-
-
Save joshhartman/5380593 to your computer and use it in GitHub Desktop.
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>AutoEmbed Examples</title> | |
</head> | |
<body> | |
<h1>AutoEmbed Examples</h1> | |
<?php | |
$content = " | |
<p>Have a laugh...</p> | |
http://youtu.be/dMH0bHeiRNg | |
<p>Hahahaha, awesome!</p> | |
<p>Want to learn something interesting?</p> | |
http://blip.tv/bushcraft/m-for-morocco-azbushcraft-com-1738329 | |
<p>Something else perhaps?</p> | |
http://vimeo.com/62571137 | |
<p>Maybe music is more your style?</p> | |
https://soundcloud.com/nanaperadze/f-chopin-dernier-nocturne | |
<p>A stylized photo could be just the ticket.</p> | |
http://instagram.com/p/BUG/ | |
<p>Now that's easy.</p> | |
"; | |
echo '<h2>Before</h2>'; | |
echo '<pre>'.htmlspecialchars($content, ENT_QUOTES, 'UTF-8').'</pre>'; | |
echo '<h2>After</h2>'; | |
require 'autoembed.php'; | |
$autoembed = new AutoEmbed(); | |
$content = $autoembed->parse($content); | |
echo $content; | |
?> | |
</body> | |
</html> |
<?php | |
/** | |
* Class to parse a string for URLs on their own line and use oEmbed to embed remote content based on the URL. | |
* Ripped from WordPress 3.5 for use in other PHP projects. | |
* | |
* Usage: | |
* $autoembed = new AutoEmbed(); | |
* $content = $autoembed->parse($content); | |
* echo $content; | |
* | |
* @link http://oembed.com/ oEmbed Homepage | |
* | |
* @package AutoEmbed | |
*/ | |
class AutoEmbed { | |
// List out some popular sites that support oEmbed. | |
var $providers = array( | |
'#https?://(www\.)?youtube.com/watch.*#i' => array( 'http://www.youtube.com/oembed', true ), | |
'http://youtu.be/*' => array( 'http://www.youtube.com/oembed', false ), | |
'http://blip.tv/*' => array( 'http://blip.tv/oembed/', false ), | |
'#https?://(www\.)?vimeo\.com/.*#i' => array( 'http://vimeo.com/api/oembed.{format}', true ), | |
'#https?://(www\.)?dailymotion\.com/.*#i' => array( 'http://www.dailymotion.com/services/oembed', true ), | |
'#https?://(www\.)?flickr\.com/.*#i' => array( 'http://www.flickr.com/services/oembed/', true ), | |
'#https?://(.+\.)?smugmug\.com/.*#i' => array( 'http://api.smugmug.com/services/oembed/', true ), | |
'#https?://(www\.)?hulu\.com/watch/.*#i' => array( 'http://www.hulu.com/api/oembed.{format}', true ), | |
'#https?://(www\.)?viddler\.com/.*#i' => array( 'http://lab.viddler.com/services/oembed/', true ), | |
'http://qik.com/*' => array( 'http://qik.com/api/oembed.{format}', false ), | |
'http://revision3.com/*' => array( 'http://revision3.com/api/oembed/', false ), | |
'http://i*.photobucket.com/albums/*' => array( 'http://photobucket.com/oembed', false ), | |
'http://gi*.photobucket.com/groups/*' => array( 'http://photobucket.com/oembed', false ), | |
'#https?://(www\.)?scribd\.com/.*#i' => array( 'http://www.scribd.com/services/oembed', true ), | |
'http://wordpress.tv/*' => array( 'http://wordpress.tv/oembed/', false ), | |
'#https?://(.+\.)?polldaddy\.com/.*#i' => array( 'http://polldaddy.com/oembed/', true ), | |
'#https?://(www\.)?funnyordie\.com/videos/.*#i' => array( 'http://www.funnyordie.com/oembed', true ), | |
'#https?://(www\.)?twitter.com/.+?/status(es)?/.*#i' => array( 'http://api.twitter.com/1/statuses/oembed.{format}', true ), | |
'#https?://(www\.)?soundcloud\.com/.*#i' => array( 'http://soundcloud.com/oembed', true ), | |
'#https?://(www\.)?slideshare.net/*#' => array( 'http://www.slideshare.net/api/oembed/2', true ), | |
'#http://instagr(\.am|am\.com)/p/.*#i' => array( 'http://api.instagram.com/oembed', true ), | |
); | |
/** | |
* Passes on any unlinked URLs that are on their own line for potential embedding. | |
* @param string $content The content to be searched. | |
* @return string Potentially modified $content. | |
*/ | |
function parse( $content ) { | |
return preg_replace_callback( '|^\s*(https?://[^\s"]+)\s*$|im', array( $this, 'autoembed_callback' ), $content ); | |
} | |
/** | |
* Callback function for {@link AutoEmbed::parse()}. | |
* @param array $match A regex match array. | |
* @return string The embed HTML on success, otherwise the original URL. | |
*/ | |
function autoembed_callback( $match ) { | |
$attr['discover'] = true; | |
$return = $this->get_html( $match[1], $attr ) or $return = '<p>'.$match[1].'</p>'; | |
return "\n$return\n"; | |
} | |
/** | |
* The do-it-all function that takes a URL and attempts to return the HTML. | |
* @param string $url The URL to the content that should be attempted to be embedded. | |
* @param array $args Optional arguments. | |
* @return bool|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed. | |
*/ | |
function get_html( $url, $args = '' ) { | |
$provider = false; | |
if ( !isset($args['discover']) ) | |
$args['discover'] = true; | |
foreach ( $this->providers as $matchmask => $data ) { | |
list( $providerurl, $regex ) = $data; | |
// Turn the asterisk-type provider URLs into regex | |
if ( !$regex ) { | |
$matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i'; | |
$matchmask = preg_replace( '|^#http\\\://|', '#https?\://', $matchmask ); | |
} | |
if ( preg_match( $matchmask, $url ) ) { | |
$provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML | |
break; | |
} | |
} | |
if ( !$provider && $args['discover'] ) | |
$provider = $this->discover( $url ); | |
if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) ) | |
return false; | |
return $this->data2html( $data, $url ); | |
} | |
/** | |
* Attempts to find oEmbed provider discovery <link> tags at the given URL. | |
* | |
* @param string $url The URL that should be inspected for discovery <link> tags. | |
* @return bool|string False on failure, otherwise the oEmbed provider URL. | |
*/ | |
function discover( $url ) { | |
$providers = array(); | |
// Fetch URL content | |
if ( $html = $this->my_remote_get( $url ) ) { | |
// <link> types that contain oEmbed provider URLs | |
$linktypes = array( | |
'application/json+oembed' => 'json', | |
'text/xml+oembed' => 'xml', | |
'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo | |
); | |
// Strip <body> | |
$html = substr( $html, 0, stripos( $html, '</head>' ) ); | |
// Do a quick check | |
$tagfound = false; | |
foreach ( $linktypes as $linktype => $format ) { | |
if ( stripos($html, $linktype) ) { | |
$tagfound = true; | |
break; | |
} | |
} | |
if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) { | |
foreach ( $links[1] as $link ) { | |
$atts = $this->parse_atts( $link ); | |
if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) { | |
$providers[$linktypes[$atts['type']]] = $atts['href']; | |
// Stop here if it's JSON (that's all we need) | |
if ( 'json' == $linktypes[$atts['type']] ) | |
break; | |
} | |
} | |
} | |
} | |
// JSON is preferred to XML | |
if ( !empty($providers['json']) ) | |
return $providers['json']; | |
elseif ( !empty($providers['xml']) ) | |
return $providers['xml']; | |
else | |
return false; | |
} | |
/** | |
* Connects to a oEmbed provider and returns the result. | |
* | |
* @param string $provider The URL to the oEmbed provider. | |
* @param string $url The URL to the content that is desired to be embedded. | |
* @param array $args Optional arguments. | |
* @return bool|object False on failure, otherwise the result in the form of an object. | |
*/ | |
function fetch( $provider, $url, $args = '' ) { | |
$width = 500; | |
$height = min( ceil( $width * 1.5 ), 1000 ); | |
$args = array_merge( compact('width', 'height'), $args ); | |
$provider = $this->add_query_arg( 'maxwidth', (int) $args['width'], $provider ); | |
$provider = $this->add_query_arg( 'maxheight', (int) $args['height'], $provider ); | |
$provider = $this->add_query_arg( 'url', $url, $provider ); | |
foreach( array( 'json', 'xml' ) as $format ) { | |
$result = $this->_fetch_with_format( $provider, $format ); | |
return $result; | |
} | |
return false; | |
} | |
/** | |
* Fetches result from an oEmbed provider for a specific format and complete provider URL | |
* @access private | |
* @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.) | |
* @param string $format Format to use | |
* @return bool|object False on failure, otherwise the result in the form of an object. | |
*/ | |
private function _fetch_with_format( $provider_url_with_args, $format ) { | |
$provider_url_with_args = $this->add_query_arg( 'format', $format, $provider_url_with_args ); | |
if ( ! $body = $this->my_remote_get( $provider_url_with_args ) ) | |
return false; | |
$parse_method = "_parse_$format"; | |
return $this->$parse_method( $body ); | |
} | |
/** | |
* Parses a json response body. | |
* @access private | |
*/ | |
private function _parse_json( $response_body ) { | |
return ( ( $data = json_decode( trim( $response_body ) ) ) && is_object( $data ) ) ? $data : false; | |
} | |
/** | |
* Parses an XML response body. | |
* @access private | |
*/ | |
private function _parse_xml( $response_body ) { | |
if ( !function_exists('simplexml_load_string') ) { | |
return false; | |
} | |
if ( ! class_exists( 'DOMDocument' ) ) | |
return false; | |
$errors = libxml_use_internal_errors( true ); | |
$old_value = null; | |
if ( function_exists( 'libxml_disable_entity_loader' ) ) { | |
$old_value = libxml_disable_entity_loader( true ); | |
} | |
$dom = new DOMDocument; | |
$success = $dom->loadXML( $response_body ); | |
if ( ! is_null( $old_value ) ) { | |
libxml_disable_entity_loader( $old_value ); | |
} | |
libxml_use_internal_errors( $errors ); | |
if ( ! $success || isset( $dom->doctype ) ) { | |
return false; | |
} | |
$data = simplexml_import_dom( $dom ); | |
if ( ! is_object( $data ) ) | |
return false; | |
$return = new stdClass; | |
foreach ( $data as $key => $value ) | |
$return->$key = (string) $value; | |
return $return; | |
} | |
/** | |
* Converts a data object and returns the HTML. | |
* | |
* @param object $data A data object result from an oEmbed provider. | |
* @param string $url The URL to the content that is desired to be embedded. | |
* @return bool|string False on error, otherwise the HTML needed to embed. | |
*/ | |
function data2html( $data, $url ) { | |
if ( ! is_object( $data ) || empty( $data->type ) ) | |
return false; | |
$return = false; | |
switch ( $data->type ) { | |
case 'photo': | |
if ( empty( $data->url ) || empty( $data->width ) || empty( $data->height ) ) | |
break; | |
if ( ! is_string( $data->url ) || ! is_numeric( $data->width ) || ! is_numeric( $data->height ) ) | |
break; | |
$title = ! empty( $data->title ) && is_string( $data->title ) ? $data->title : ''; | |
$return = '<a href="' . $this->esc_url( $url ) . '"><img src="' . htmlspecialchars( $data->url, ENT_QUOTES, 'UTF-8' ) . '" alt="' . htmlspecialchars($title, ENT_QUOTES, 'UTF-8') . '" width="' . htmlspecialchars($data->width, ENT_QUOTES, 'UTF-8') . '" height="' . htmlspecialchars($data->height, ENT_QUOTES, 'UTF-8') . '" /></a>'; | |
break; | |
case 'video': | |
case 'rich': | |
if ( ! empty( $data->html ) && is_string( $data->html ) ) | |
$return = $data->html; | |
break; | |
case 'link': | |
if ( ! empty( $data->title ) && is_string( $data->title ) ) | |
$return = '<a href="' . $this->esc_url( $url ) . '">' . htmlspecialchars( $data->title, ENT_QUOTES, 'UTF-8') . '</a>'; | |
break; | |
default: | |
$return = false; | |
} | |
// Strip any new lines from the HTML. | |
if ( false !== strpos( $return, "\n" ) ) | |
$return = str_replace( array( "\r\n", "\n" ), '', $return ); | |
return $return; | |
} | |
/** | |
* Grabs the response from a remote URL. | |
* | |
* @param string $url The remote URL. | |
* @return bool|string False on error, otherwise the response body. | |
*/ | |
function my_remote_get( $url ) { | |
$handle = curl_init(); | |
curl_setopt( $handle, CURLOPT_CONNECTTIMEOUT, 5 ); | |
curl_setopt( $handle, CURLOPT_TIMEOUT, 5 ); | |
curl_setopt( $handle, CURLOPT_URL, $url); | |
curl_setopt( $handle, CURLOPT_RETURNTRANSFER, true ); | |
curl_setopt( $handle, CURLOPT_SSL_VERIFYHOST, false ); | |
curl_setopt( $handle, CURLOPT_SSL_VERIFYPEER, false ); | |
curl_setopt( $handle, CURLOPT_FOLLOWLOCATION, false ); | |
curl_setopt( $handle, CURLOPT_HEADER, false ); | |
curl_setopt( $handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0 ); | |
$response = curl_exec( $handle ); | |
curl_close( $handle ); | |
return $response; | |
} | |
/** | |
* Add HTTP query arguments. | |
*/ | |
function add_query_arg() { | |
$ret = ''; | |
$args = func_get_args(); | |
if ( is_array( $args[0] ) ) { | |
if ( count( $args ) < 2 || false === $args[1] ) | |
$uri = $_SERVER['REQUEST_URI']; | |
else | |
$uri = $args[1]; | |
} else { | |
if ( count( $args ) < 3 || false === $args[2] ) | |
$uri = $_SERVER['REQUEST_URI']; | |
else | |
$uri = $args[2]; | |
} | |
if ( $frag = strstr( $uri, '#' ) ) | |
$uri = substr( $uri, 0, -strlen( $frag ) ); | |
else | |
$frag = ''; | |
if ( 0 === stripos( 'http://', $uri ) ) { | |
$protocol = 'http://'; | |
$uri = substr( $uri, 7 ); | |
} elseif ( 0 === stripos( 'https://', $uri ) ) { | |
$protocol = 'https://'; | |
$uri = substr( $uri, 8 ); | |
} else { | |
$protocol = ''; | |
} | |
if ( strpos( $uri, '?' ) !== false ) { | |
$parts = explode( '?', $uri, 2 ); | |
if ( 1 == count( $parts ) ) { | |
$base = '?'; | |
$query = $parts[0]; | |
} else { | |
$base = $parts[0] . '?'; | |
$query = $parts[1]; | |
} | |
} elseif ( $protocol || strpos( $uri, '=' ) === false ) { | |
$base = $uri . '?'; | |
$query = ''; | |
} else { | |
$base = ''; | |
$query = $uri; | |
} | |
parse_str( $query, $qs ); | |
if ( is_array( $args[0] ) ) { | |
$kayvees = $args[0]; | |
$qs = array_merge( $qs, $kayvees ); | |
} else { | |
$qs[ $args[0] ] = $args[1]; | |
} | |
foreach ( $qs as $k => $v ) { | |
if ( $v === false ) | |
unset( $qs[$k] ); | |
} | |
$ret = http_build_query( $qs, null, '&' ); | |
$ret = trim( $ret, '?' ); | |
$ret = preg_replace( '#=(&|$)#', '$1', $ret ); | |
$ret = $protocol . $base . $ret . $frag; | |
$ret = rtrim( $ret, '?' ); | |
return $ret; | |
} | |
/** | |
* Checks and cleans a URL. | |
* | |
* @param string $url The URL to be cleaned. | |
* @return string The cleaned $url. | |
*/ | |
function esc_url( $url ) { | |
if ( '' == $url ) | |
return $url; | |
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\\x80-\\xff]|i', '', $url); | |
$strip = array('%0d', '%0a', '%0D', '%0A'); | |
$url = $this->_deep_replace($strip, $url); | |
$url = str_replace(';//', '://', $url); | |
/* If the URL doesn't appear to contain a scheme, we | |
* presume it needs http:// appended (unless a relative | |
* link starting with /, # or ? or a php file). | |
*/ | |
if ( strpos($url, ':') === false && ! in_array( $url[0], array( '/', '#', '?' ) ) && | |
! preg_match('/^[a-z0-9-]+?\.php/i', $url) ) | |
$url = 'http://' . $url; | |
$url = str_replace( '&', '&', $url ); | |
$url = str_replace( "'", ''', $url ); | |
return $url; | |
} | |
/** | |
* Perform a deep string replace operation to ensure the values in $search are no longer present | |
* | |
* Repeats the replacement operation until it no longer replaces anything so as to remove "nested" values | |
* e.g. $subject = '%0%0%0DDD', $search ='%0D', $result ='' rather than the '%0%0DD' that | |
* str_replace would return | |
* | |
* @access private | |
* | |
* @param string|array $search | |
* @param string $subject | |
* @return string The processed string | |
*/ | |
private function _deep_replace( $search, $subject ) { | |
$found = true; | |
$subject = (string) $subject; | |
while ( $found ) { | |
$found = false; | |
foreach ( (array) $search as $val ) { | |
while ( strpos( $subject, $val ) !== false ) { | |
$found = true; | |
$subject = str_replace( $val, '', $subject ); | |
} | |
} | |
} | |
return $subject; | |
} | |
/** | |
* Retrieve all attributes from the tag. | |
* | |
* @param string $text | |
* @return array List of attributes and their value. | |
*/ | |
function shortcode_parse_atts($text) { | |
$atts = array(); | |
$pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; | |
$text = preg_replace("/[\x{00a0}\x{200b}]+/u", " ", $text); | |
if ( preg_match_all($pattern, $text, $match, PREG_SET_ORDER) ) { | |
foreach ($match as $m) { | |
if (!empty($m[1])) | |
$atts[strtolower($m[1])] = stripcslashes($m[2]); | |
elseif (!empty($m[3])) | |
$atts[strtolower($m[3])] = stripcslashes($m[4]); | |
elseif (!empty($m[5])) | |
$atts[strtolower($m[5])] = stripcslashes($m[6]); | |
elseif (isset($m[7]) and strlen($m[7])) | |
$atts[] = stripcslashes($m[7]); | |
elseif (isset($m[8])) | |
$atts[] = stripcslashes($m[8]); | |
} | |
} else { | |
$atts = ltrim($text); | |
} | |
return $atts; | |
} | |
} |
I created a repo on GitHub to properly maintain the code: https://github.com/MarQuisKnox/AutoEmbed
Hello, my wysiwyg editor comes with html tag. And this cause the autoembed not work. What should I do?
<a target="_blank" rel="nofollow">https://youtu.be/HB3K5HY5RnE</a>
Well, I changed the editor. So I can edit the content from link into 'pure text'. But still not work.
Instagram api is old. I updated new api but its not working. Can you upguarde Joshhartman. Thanks. I updated twitter api and working.
Any others urls while crash.
http://fr.novopress.info/203003/sortir-de-la-cour-europeenne-des-droits-de-lhomme-qui-en-aura-le-courage/
http://wearechange.org/chinese-nukes-prepared-response-inauguration-donald-trump/
Fatal error: Call to undefined method AutoEmbed::parse_atts() in /home1/username/public_html/example.com/oembed/AutoEmbed/autoembed.php on line 130
I updated the $providers array: https://gist.github.com/MarQuisKnox/888df92d8a91557e2332/revisions
Thanks for sharing!