1
|
1 |
<?php |
|
2 |
/** |
|
3 |
* API for fetching the HTML to embed remote content based on a provided URL. |
|
4 |
* Used internally by the {@link WP_Embed} class, but is designed to be generic. |
|
5 |
* |
|
6 |
* @link http://codex.wordpress.org/oEmbed oEmbed Codex Article |
|
7 |
* @link http://oembed.com/ oEmbed Homepage |
|
8 |
* |
|
9 |
* @package WordPress |
|
10 |
* @subpackage oEmbed |
|
11 |
*/ |
|
12 |
|
|
13 |
/** |
|
14 |
* oEmbed class. |
|
15 |
* |
|
16 |
* @package WordPress |
|
17 |
* @subpackage oEmbed |
|
18 |
* @since 2.9.0 |
|
19 |
*/ |
|
20 |
class WP_oEmbed { |
|
21 |
var $providers = array(); |
|
22 |
|
|
23 |
/** |
|
24 |
* PHP4 constructor |
|
25 |
*/ |
|
26 |
function WP_oEmbed() { |
|
27 |
return $this->__construct(); |
|
28 |
} |
|
29 |
|
|
30 |
/** |
|
31 |
* PHP5 constructor |
|
32 |
* |
|
33 |
* @uses apply_filters() Filters a list of pre-defined oEmbed providers. |
|
34 |
*/ |
|
35 |
function __construct() { |
|
36 |
// List out some popular sites that support oEmbed. |
|
37 |
// The WP_Embed class disables discovery for non-unfiltered_html users, so only providers in this array will be used for them. |
|
38 |
// Add to this list using the wp_oembed_add_provider() function (see it's PHPDoc for details). |
|
39 |
$this->providers = apply_filters( 'oembed_providers', array( |
|
40 |
'#http://(www\.)?youtube.com/watch.*#i' => array( 'http://www.youtube.com/oembed', true ), |
|
41 |
'http://blip.tv/file/*' => array( 'http://blip.tv/oembed/', false ), |
|
42 |
'#http://(www\.)?vimeo\.com/.*#i' => array( 'http://www.vimeo.com/api/oembed.{format}', true ), |
|
43 |
'#http://(www\.)?dailymotion\.com/.*#i' => array( 'http://www.dailymotion.com/api/oembed', true ), |
|
44 |
'#http://(www\.)?flickr\.com/.*#i' => array( 'http://www.flickr.com/services/oembed/', true ), |
|
45 |
'#http://(www\.)?hulu\.com/watch/.*#i' => array( 'http://www.hulu.com/api/oembed.{format}', true ), |
|
46 |
'#http://(www\.)?viddler\.com/.*#i' => array( 'http://lab.viddler.com/services/oembed/', true ), |
|
47 |
'http://qik.com/*' => array( 'http://qik.com/api/oembed.{format}', false ), |
|
48 |
'http://revision3.com/*' => array( 'http://revision3.com/api/oembed/', false ), |
|
49 |
'http://i*.photobucket.com/albums/*' => array( 'http://photobucket.com/oembed', false ), |
|
50 |
'http://gi*.photobucket.com/groups/*' => array( 'http://photobucket.com/oembed', false ), |
|
51 |
'#http://(www\.)?scribd\.com/.*#i' => array( 'http://www.scribd.com/services/oembed', true ), |
|
52 |
'http://wordpress.tv/*' => array( 'http://wordpress.tv/oembed/', false ), |
|
53 |
) ); |
|
54 |
|
|
55 |
// Fix Scribd embeds. They contain new lines in the middle of the HTML which breaks wpautop(). |
|
56 |
add_filter( 'oembed_dataparse', array(&$this, 'strip_scribd_newlines'), 10, 3 ); |
|
57 |
} |
|
58 |
|
|
59 |
/** |
|
60 |
* The do-it-all function that takes a URL and attempts to return the HTML. |
|
61 |
* |
|
62 |
* @see WP_oEmbed::discover() |
|
63 |
* @see WP_oEmbed::fetch() |
|
64 |
* @see WP_oEmbed::data2html() |
|
65 |
* |
|
66 |
* @param string $url The URL to the content that should be attempted to be embedded. |
|
67 |
* @param array $args Optional arguments. Usually passed from a shortcode. |
|
68 |
* @return bool|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed. |
|
69 |
*/ |
|
70 |
function get_html( $url, $args = '' ) { |
|
71 |
$provider = false; |
|
72 |
|
|
73 |
if ( !isset($args['discover']) ) |
|
74 |
$args['discover'] = true; |
|
75 |
|
|
76 |
foreach ( $this->providers as $matchmask => $data ) { |
|
77 |
list( $providerurl, $regex ) = $data; |
|
78 |
|
|
79 |
// Turn the asterisk-type provider URLs into regex |
|
80 |
if ( !$regex ) |
|
81 |
$matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i'; |
|
82 |
|
|
83 |
if ( preg_match( $matchmask, $url ) ) { |
|
84 |
$provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML |
|
85 |
break; |
|
86 |
} |
|
87 |
} |
|
88 |
|
|
89 |
if ( !$provider && $args['discover'] ) |
|
90 |
$provider = $this->discover( $url ); |
|
91 |
|
|
92 |
if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) ) |
|
93 |
return false; |
|
94 |
|
|
95 |
return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args ); |
|
96 |
} |
|
97 |
|
|
98 |
/** |
|
99 |
* Attempts to find oEmbed provider discovery <link> tags at the given URL. |
|
100 |
* |
|
101 |
* @param string $url The URL that should be inspected for discovery <link> tags. |
|
102 |
* @return bool|string False on failure, otherwise the oEmbed provider URL. |
|
103 |
*/ |
|
104 |
function discover( $url ) { |
|
105 |
$providers = array(); |
|
106 |
|
|
107 |
// Fetch URL content |
|
108 |
if ( $html = wp_remote_retrieve_body( wp_remote_get( $url ) ) ) { |
|
109 |
|
|
110 |
// <link> types that contain oEmbed provider URLs |
|
111 |
$linktypes = apply_filters( 'oembed_linktypes', array( |
|
112 |
'application/json+oembed' => 'json', |
|
113 |
'text/xml+oembed' => 'xml', |
|
114 |
'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo |
|
115 |
) ); |
|
116 |
|
|
117 |
// Strip <body> |
|
118 |
$html = substr( $html, 0, stripos( $html, '</head>' ) ); |
|
119 |
|
|
120 |
// Do a quick check |
|
121 |
$tagfound = false; |
|
122 |
foreach ( $linktypes as $linktype => $format ) { |
|
123 |
if ( stripos($html, $linktype) ) { |
|
124 |
$tagfound = true; |
|
125 |
break; |
|
126 |
} |
|
127 |
} |
|
128 |
|
|
129 |
if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) { |
|
130 |
foreach ( $links[1] as $link ) { |
|
131 |
$atts = shortcode_parse_atts( $link ); |
|
132 |
|
|
133 |
if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) { |
|
134 |
$providers[$linktypes[$atts['type']]] = $atts['href']; |
|
135 |
|
|
136 |
// Stop here if it's JSON (that's all we need) |
|
137 |
if ( 'json' == $linktypes[$atts['type']] ) |
|
138 |
break; |
|
139 |
} |
|
140 |
} |
|
141 |
} |
|
142 |
} |
|
143 |
|
|
144 |
// JSON is preferred to XML |
|
145 |
if ( !empty($providers['json']) ) |
|
146 |
return $providers['json']; |
|
147 |
elseif ( !empty($providers['xml']) ) |
|
148 |
return $providers['xml']; |
|
149 |
else |
|
150 |
return false; |
|
151 |
} |
|
152 |
|
|
153 |
/** |
|
154 |
* Connects to a oEmbed provider and returns the result. |
|
155 |
* |
|
156 |
* @param string $provider The URL to the oEmbed provider. |
|
157 |
* @param string $url The URL to the content that is desired to be embedded. |
|
158 |
* @param array $args Optional arguments. Usually passed from a shortcode. |
|
159 |
* @return bool|object False on failure, otherwise the result in the form of an object. |
|
160 |
*/ |
|
161 |
function fetch( $provider, $url, $args = '' ) { |
|
162 |
$args = wp_parse_args( $args, wp_embed_defaults() ); |
|
163 |
|
|
164 |
$provider = add_query_arg( 'format', 'json', $provider ); // JSON is easier to deal with than XML |
|
165 |
|
|
166 |
$provider = add_query_arg( 'maxwidth', $args['width'], $provider ); |
|
167 |
$provider = add_query_arg( 'maxheight', $args['height'], $provider ); |
|
168 |
$provider = add_query_arg( 'url', urlencode($url), $provider ); |
|
169 |
|
|
170 |
if ( !$result = wp_remote_retrieve_body( wp_remote_get( $provider ) ) ) |
|
171 |
return false; |
|
172 |
|
|
173 |
$result = trim( $result ); |
|
174 |
|
|
175 |
// JSON? |
|
176 |
// Example content: http://vimeo.com/api/oembed.json?url=http%3A%2F%2Fvimeo.com%2F240975 |
|
177 |
if ( $data = json_decode($result) ) { |
|
178 |
return $data; |
|
179 |
} |
|
180 |
|
|
181 |
// Must be XML. Only parse it if PHP5 is installed. (PHP4 isn't worth the trouble.) |
|
182 |
// Example content: http://vimeo.com/api/oembed.xml?url=http%3A%2F%2Fvimeo.com%2F240975 |
|
183 |
elseif ( function_exists('simplexml_load_string') ) { |
|
184 |
$errors = libxml_use_internal_errors( 'true' ); |
|
185 |
|
|
186 |
$data = simplexml_load_string( $result ); |
|
187 |
|
|
188 |
libxml_use_internal_errors( $errors ); |
|
189 |
|
|
190 |
if ( is_object($data) ) |
|
191 |
return $data; |
|
192 |
} |
|
193 |
|
|
194 |
return false; |
|
195 |
} |
|
196 |
|
|
197 |
/** |
|
198 |
* Converts a data object from {@link WP_oEmbed::fetch()} and returns the HTML. |
|
199 |
* |
|
200 |
* @param object $data A data object result from an oEmbed provider. |
|
201 |
* @param string $url The URL to the content that is desired to be embedded. |
|
202 |
* @return bool|string False on error, otherwise the HTML needed to embed. |
|
203 |
*/ |
|
204 |
function data2html( $data, $url ) { |
|
205 |
if ( !is_object($data) || empty($data->type) ) |
|
206 |
return false; |
|
207 |
|
|
208 |
switch ( $data->type ) { |
|
209 |
case 'photo': |
|
210 |
if ( empty($data->url) || empty($data->width) || empty($data->height) ) |
|
211 |
return false; |
|
212 |
|
|
213 |
$title = ( !empty($data->title) ) ? $data->title : ''; |
|
214 |
$return = '<img src="' . esc_attr( clean_url( $data->url ) ) . '" alt="' . esc_attr($title) . '" width="' . esc_attr($data->width) . '" height="' . esc_attr($data->height) . '" />'; |
|
215 |
break; |
|
216 |
|
|
217 |
case 'video': |
|
218 |
case 'rich': |
|
219 |
$return = ( !empty($data->html) ) ? $data->html : false; |
|
220 |
break; |
|
221 |
|
|
222 |
case 'link': |
|
223 |
$return = ( !empty($data->title) ) ? '<a href="' . clean_url($url) . '">' . esc_html($data->title) . '</a>' : false; |
|
224 |
break; |
|
225 |
|
|
226 |
default; |
|
227 |
$return = false; |
|
228 |
} |
|
229 |
|
|
230 |
// You can use this filter to add support for custom data types or to filter the result |
|
231 |
return apply_filters( 'oembed_dataparse', $return, $data, $url ); |
|
232 |
} |
|
233 |
|
|
234 |
/** |
|
235 |
* Strip new lines from the HTML if it's a Scribd embed. |
|
236 |
* |
|
237 |
* @param string $html Existing HTML. |
|
238 |
* @param object $data Data object from WP_oEmbed::data2html() |
|
239 |
* @param string $url The original URL passed to oEmbed. |
|
240 |
* @return string Possibly modified $html |
|
241 |
*/ |
|
242 |
function strip_scribd_newlines( $html, $data, $url ) { |
|
243 |
if ( preg_match( '#http://(www\.)?scribd.com/.*#i', $url ) ) |
|
244 |
$html = str_replace( array( "\r\n", "\n" ), '', $html ); |
|
245 |
|
|
246 |
return $html; |
|
247 |
} |
|
248 |
} |
|
249 |
|
|
250 |
/** |
|
251 |
* Returns the initialized {@link WP_oEmbed} object |
|
252 |
* |
|
253 |
* @since 2.9.0 |
|
254 |
* @access private |
|
255 |
* |
|
256 |
* @see WP_oEmbed |
|
257 |
* @uses WP_oEmbed |
|
258 |
* |
|
259 |
* @return WP_oEmbed object. |
|
260 |
*/ |
|
261 |
function &_wp_oembed_get_object() { |
|
262 |
static $wp_oembed; |
|
263 |
|
|
264 |
if ( is_null($wp_oembed) ) |
|
265 |
$wp_oembed = new WP_oEmbed(); |
|
266 |
|
|
267 |
return $wp_oembed; |
|
268 |
} |
|
269 |
|
|
270 |
?> |