Advertisement
manchumahara

Wordpress oEmbed Class

Mar 29th, 2012
196
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 10.58 KB | None | 0 0
  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.      * Constructor
  25.      *
  26.      * @uses apply_filters() Filters a list of pre-defined oEmbed providers.
  27.      */
  28.     function __construct() {
  29.         // List out some popular sites that support oEmbed.
  30.         // The WP_Embed class disables discovery for non-unfiltered_html users, so only providers in this array will be used for them.
  31.         // Add to this list using the wp_oembed_add_provider() function (see its PHPDoc for details).
  32.         $this->providers = apply_filters( 'oembed_providers', array(
  33.             '#http://(www\.)?youtube.com/watch.*#i'         => array( 'http://www.youtube.com/oembed',            true  ),
  34.             'http://youtu.be/*'                             => array( 'http://www.youtube.com/oembed',            false ),
  35.             'http://blip.tv/*'                              => array( 'http://blip.tv/oembed/',                   false ),
  36.             '#http://(www\.)?vimeo\.com/.*#i'               => array( 'http://vimeo.com/api/oembed.{format}',     true  ),
  37.             '#http://(www\.)?dailymotion\.com/.*#i'         => array( 'http://www.dailymotion.com/api/oembed',    true  ),
  38.             '#http://(www\.)?flickr\.com/.*#i'              => array( 'http://www.flickr.com/services/oembed/',   true  ),
  39.             '#http://(.+\.)?smugmug\.com/.*#i'              => array( 'http://api.smugmug.com/services/oembed/',  true  ),
  40.             '#http://(www\.)?hulu\.com/watch/.*#i'          => array( 'http://www.hulu.com/api/oembed.{format}',  true  ),
  41.             '#http://(www\.)?viddler\.com/.*#i'             => array( 'http://lab.viddler.com/services/oembed/',  true  ),
  42.             'http://qik.com/*'                              => array( 'http://qik.com/api/oembed.{format}',       false ),
  43.             'http://revision3.com/*'                        => array( 'http://revision3.com/api/oembed/',         false ),
  44.             'http://i*.photobucket.com/albums/*'            => array( 'http://photobucket.com/oembed',            false ),
  45.             'http://gi*.photobucket.com/groups/*'           => array( 'http://photobucket.com/oembed',            false ),
  46.             '#http://(www\.)?scribd\.com/.*#i'              => array( 'http://www.scribd.com/services/oembed',    true  ),
  47.             'http://wordpress.tv/*'                         => array( 'http://wordpress.tv/oembed/',              false ),
  48.             '#http://(.+\.)?polldaddy\.com/.*#i'            => array( 'http://polldaddy.com/oembed/',             true  ),
  49.             '#http://(www\.)?funnyordie\.com/videos/.*#i'   => array( 'http://www.funnyordie.com/oembed',         true  ),
  50.         ) );
  51.  
  52.         // Fix any embeds that contain new lines in the middle of the HTML which breaks wpautop().
  53.         add_filter( 'oembed_dataparse', array(&$this, '_strip_newlines'), 10, 3 );
  54.     }
  55.  
  56.     /**
  57.      * The do-it-all function that takes a URL and attempts to return the HTML.
  58.      *
  59.      * @see WP_oEmbed::discover()
  60.      * @see WP_oEmbed::fetch()
  61.      * @see WP_oEmbed::data2html()
  62.      *
  63.      * @param string $url The URL to the content that should be attempted to be embedded.
  64.      * @param array $args Optional arguments. Usually passed from a shortcode.
  65.      * @return bool|string False on failure, otherwise the UNSANITIZED (and potentially unsafe) HTML that should be used to embed.
  66.      */
  67.     function get_html( $url, $args = '' ) {
  68.         $provider = false;
  69.  
  70.         if ( !isset($args['discover']) )
  71.             $args['discover'] = true;
  72.  
  73.         foreach ( $this->providers as $matchmask => $data ) {
  74.             list( $providerurl, $regex ) = $data;
  75.  
  76.             // Turn the asterisk-type provider URLs into regex
  77.             if ( !$regex )
  78.                 $matchmask = '#' . str_replace( '___wildcard___', '(.+)', preg_quote( str_replace( '*', '___wildcard___', $matchmask ), '#' ) ) . '#i';
  79.  
  80.             if ( preg_match( $matchmask, $url ) ) {
  81.                 $provider = str_replace( '{format}', 'json', $providerurl ); // JSON is easier to deal with than XML
  82.                 break;
  83.             }
  84.         }
  85.  
  86.         if ( !$provider && $args['discover'] )
  87.             $provider = $this->discover( $url );
  88.  
  89.         if ( !$provider || false === $data = $this->fetch( $provider, $url, $args ) )
  90.             return false;
  91.  
  92.         return apply_filters( 'oembed_result', $this->data2html( $data, $url ), $url, $args );
  93.     }
  94.  
  95.     /**
  96.      * Attempts to find oEmbed provider discovery <link> tags at the given URL.
  97.      *
  98.      * @param string $url The URL that should be inspected for discovery <link> tags.
  99.      * @return bool|string False on failure, otherwise the oEmbed provider URL.
  100.      */
  101.     function discover( $url ) {
  102.         $providers = array();
  103.  
  104.         // Fetch URL content
  105.         if ( $html = wp_remote_retrieve_body( wp_remote_get( $url ) ) ) {
  106.  
  107.             // <link> types that contain oEmbed provider URLs
  108.             $linktypes = apply_filters( 'oembed_linktypes', array(
  109.                 'application/json+oembed' => 'json',
  110.                 'text/xml+oembed' => 'xml',
  111.                 'application/xml+oembed' => 'xml', // Incorrect, but used by at least Vimeo
  112.             ) );
  113.  
  114.             // Strip <body>
  115.             $html = substr( $html, 0, stripos( $html, '</head>' ) );
  116.  
  117.             // Do a quick check
  118.             $tagfound = false;
  119.             foreach ( $linktypes as $linktype => $format ) {
  120.                 if ( stripos($html, $linktype) ) {
  121.                     $tagfound = true;
  122.                     break;
  123.                 }
  124.             }
  125.  
  126.             if ( $tagfound && preg_match_all( '/<link([^<>]+)>/i', $html, $links ) ) {
  127.                 foreach ( $links[1] as $link ) {
  128.                     $atts = shortcode_parse_atts( $link );
  129.  
  130.                     if ( !empty($atts['type']) && !empty($linktypes[$atts['type']]) && !empty($atts['href']) ) {
  131.                         $providers[$linktypes[$atts['type']]] = $atts['href'];
  132.  
  133.                         // Stop here if it's JSON (that's all we need)
  134.                         if ( 'json' == $linktypes[$atts['type']] )
  135.                             break;
  136.                     }
  137.                 }
  138.             }
  139.         }
  140.  
  141.         // JSON is preferred to XML
  142.         if ( !empty($providers['json']) )
  143.             return $providers['json'];
  144.         elseif ( !empty($providers['xml']) )
  145.             return $providers['xml'];
  146.         else
  147.             return false;
  148.     }
  149.  
  150.     /**
  151.      * Connects to a oEmbed provider and returns the result.
  152.      *
  153.      * @param string $provider The URL to the oEmbed provider.
  154.      * @param string $url The URL to the content that is desired to be embedded.
  155.      * @param array $args Optional arguments. Usually passed from a shortcode.
  156.      * @return bool|object False on failure, otherwise the result in the form of an object.
  157.      */
  158.     function fetch( $provider, $url, $args = '' ) {
  159.         $args = wp_parse_args( $args, wp_embed_defaults() );
  160.  
  161.         $provider = add_query_arg( 'maxwidth', (int) $args['width'], $provider );
  162.         $provider = add_query_arg( 'maxheight', (int) $args['height'], $provider );
  163.         $provider = add_query_arg( 'url', urlencode($url), $provider );
  164.  
  165.         foreach( array( 'json', 'xml' ) as $format ) {
  166.             $result = $this->_fetch_with_format( $provider, $format );
  167.             if ( is_wp_error( $result ) && 'not-implemented' == $result->get_error_code() )
  168.                 continue;
  169.             return ( $result && ! is_wp_error( $result ) ) ? $result : false;
  170.         }
  171.         return false;
  172.     }
  173.  
  174.     /**
  175.      * Fetches result from an oEmbed provider for a specific format and complete provider URL
  176.      *
  177.      * @since 3.0.0
  178.      * @access private
  179.      * @param string $provider_url_with_args URL to the provider with full arguments list (url, maxheight, etc.)
  180.      * @param string $format Format to use
  181.      * @return bool|object False on failure, otherwise the result in the form of an object.
  182.      */
  183.     function _fetch_with_format( $provider_url_with_args, $format ) {
  184.         $provider_url_with_args = add_query_arg( 'format', $format, $provider_url_with_args );
  185.         $response = wp_remote_get( $provider_url_with_args );
  186.         if ( 501 == wp_remote_retrieve_response_code( $response ) )
  187.             return new WP_Error( 'not-implemented' );
  188.         if ( ! $body = wp_remote_retrieve_body( $response ) )
  189.             return false;
  190.         $parse_method = "_parse_$format";
  191.         return $this->$parse_method( $body );
  192.     }
  193.  
  194.     /**
  195.      * Parses a json response body.
  196.      *
  197.      * @since 3.0.0
  198.      * @access private
  199.      */
  200.     function _parse_json( $response_body ) {
  201.         return ( ( $data = json_decode( trim( $response_body ) ) ) && is_object( $data ) ) ? $data : false;
  202.     }
  203.  
  204.     /**
  205.      * Parses an XML response body.
  206.      *
  207.      * @since 3.0.0
  208.      * @access private
  209.      */
  210.     function _parse_xml( $response_body ) {
  211.         if ( function_exists('simplexml_load_string') ) {
  212.             $errors = libxml_use_internal_errors( 'true' );
  213.             $data = simplexml_load_string( $response_body );
  214.             libxml_use_internal_errors( $errors );
  215.             if ( is_object( $data ) )
  216.                 return $data;
  217.         }
  218.         return false;
  219.     }
  220.  
  221.     /**
  222.      * Converts a data object from {@link WP_oEmbed::fetch()} and returns the HTML.
  223.      *
  224.      * @param object $data A data object result from an oEmbed provider.
  225.      * @param string $url The URL to the content that is desired to be embedded.
  226.      * @return bool|string False on error, otherwise the HTML needed to embed.
  227.      */
  228.     function data2html( $data, $url ) {
  229.         if ( !is_object($data) || empty($data->type) )
  230.             return false;
  231.  
  232.         switch ( $data->type ) {
  233.             case 'photo':
  234.                 if ( empty($data->url) || empty($data->width) || empty($data->height) )
  235.                     return false;
  236.  
  237.                 $title = ( !empty($data->title) ) ? $data->title : '';
  238.                 $return = '<a href="' . esc_url( $url ) . '"><img src="' . esc_url( $data->url ) . '" alt="' . esc_attr($title) . '" width="' . esc_attr($data->width) . '" height="' . esc_attr($data->height) . '" /></a>';
  239.                 break;
  240.  
  241.             case 'video':
  242.             case 'rich':
  243.                 $return = ( !empty($data->html) ) ? $data->html : false;
  244.                 break;
  245.  
  246.             case 'link':
  247.                 $return = ( !empty($data->title) ) ? '<a href="' . esc_url($url) . '">' . esc_html($data->title) . '</a>' : false;
  248.                 break;
  249.  
  250.             default;
  251.                 $return = false;
  252.         }
  253.  
  254.         // You can use this filter to add support for custom data types or to filter the result
  255.         return apply_filters( 'oembed_dataparse', $return, $data, $url );
  256.     }
  257.  
  258.     /**
  259.      * Strip any new lines from the HTML.
  260.      *
  261.      * @access private
  262.      * @param string $html Existing HTML.
  263.      * @param object $data Data object from WP_oEmbed::data2html()
  264.      * @param string $url The original URL passed to oEmbed.
  265.      * @return string Possibly modified $html
  266.      */
  267.     function _strip_newlines( $html, $data, $url ) {
  268.         if ( false !== strpos( $html, "\n" ) )
  269.             $html = str_replace( array( "\r\n", "\n" ), '', $html );
  270.  
  271.         return $html;
  272.     }
  273. }
  274.  
  275. /**
  276.  * Returns the initialized {@link WP_oEmbed} object
  277.  *
  278.  * @since 2.9.0
  279.  * @access private
  280.  *
  281.  * @see WP_oEmbed
  282.  * @uses WP_oEmbed
  283.  *
  284.  * @return WP_oEmbed object.
  285.  */
  286. function &_wp_oembed_get_object() {
  287.     static $wp_oembed;
  288.  
  289.     if ( is_null($wp_oembed) )
  290.         $wp_oembed = new WP_oEmbed();
  291.  
  292.     return $wp_oembed;
  293. }
  294.  
  295. ?>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement