Accessing third-party content with oEmbed and PHP

Add rich content and data from popular apps and websites to your web pages

The story of Web 2.0 is the story of user-generated content. Sites like Flickr, Facebook, MySpace, and YouTube allow users to upload their original photos or video footage to the cloud and share it with the wider community using simple online tools. The easy availability of cloud-based content creation and sharing tools, coupled with web services that allow developers programmatic access to user-generated content, has made it possible to combine content from different sources to enable new, content-driven applications (mashups).

Frequently used acronyms API: Application program interface

HTML: HyperText Markup Language

JSON: JavaScript Object Notation

OOP: Object-oriented programming

SQL: Structured Query Language

URL: Uniform Resource Locator

UTF-8: UCS Transformation Format-8-bit

XML: Extensible Markup Language

XSS: Cross-site scripting

There is, however, one small problem. If you have your photos in Flickr, your videos in YouTube, and your TV shows in Hulu, how do you bring them all into your blog posts on Blogger? Of course, you can do this by hyperlinking to the appropriate content, but wouldn't it be nicer if you could just embed them into your post at the appropriate place?

Enter oEmbed. As the name suggests, oEmbed offers a solution to this problem by allowing users to turn URLs to rich content, such as photos and videos, on external sites, such as Flickr and YouTube, into embedded representations of that content. In this article, I introduce you to oEmbed and show you how to use it with PHP to embed third-party content in your web pages.

Understanding oEmbed

First, here is a quick introduction to oEmbed. According to its official website (http://www.oembed.com), oEmbed is:

...a format for allowing an embedded representation of a URL on third party sites...[it] allows a website to display embedded content (such as photos or videos) when a user posts a link to that resource, without having to parse the resource directly."

There are two parties to an oEmbed transaction: a provider and a consumer. A consumer requests specific content items by making requests to the provider's API endpoint. A provider services these requests by returning XML- or JSON-encoded representations of the requested content items.

How does this approach work in practice? Well, suppose that you write a blog post and you want to display one of your uploaded videos from YouTube. You can do this a couple of ways:

You can hyperlink to it; when users click the link, they are directed to YouTube to view the video.

You can use YouTube's embedded media player to directly embed the video into your blog post.

The first approach is simple, but it results in users being transferred from your site to YouTube, with its infinite distractions. The second approach keeps visitors on your site but requires you to do some research to learn how YouTube's embedded player works.

oEmbed offers a third, simpler solution. Because YouTube is an oEmbed provider, you can send a request to its oEmbed API endpoint for the video in question. The response to this request is an XML or JSON document that contains the HTML code for an embedded video player, and that code can be directly used in your blog post to display the video, without any further manual intervention.

Listing 1 shows what an oEmbed request and response for a YouTube video look like:

Listing 1. An oEmbed request

GET http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=hI-BDR2UcmU &format=xml <?xml version="1.0" encoding="utf-8"?> <oembed> <provider_url>http://www.youtube.com/</provider_url> <title>NORAD Tracks Santa - US Region</title> <html><object width="425" height="344"><param name="movie" value="http://www.youtube.com/v/hI-BDR2UcmU?fs=1"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="//www.youtube.com/v/hI-BDR2UcmU?fs=1" type="application/x-shockwave-flash" width="425" height="344" allowscriptaccess="always" allowfullscreen="true"></embed></object></html> <author_name>NORADTracksSanta</author_name> <height>344</height> <thumbnail_width>480</thumbnail_width> <width>425</width> <version>1.0</version> <author_url>http://www.youtube.com/user/NORADTracksSanta</author_url> <provider_name>YouTube</provider_name> <thumbnail_url>http://i1.ytimg.com/vi/hI-BDR2UcmU/hqdefault.jpg</thumbnail_url> <type>video</type> <thumbnail_height>360</thumbnail_height> </oembed>

Notice that the request is being sent to http://www.youtube.com/oembed, which is the YouTube API endpoint for oEmbed requests. The API is passed the URL of the video being requested in the "url" request parameter. The response to the request contains some video metadata, such as the video's author and title and the appropriate HTML embed code.

oEmbed providers can return responses in either XML or JSON. All responses are encoded in UTF-8. The response format can be specified in the request as an additional "format" parameter. Listing 2 shows an example.

Listing 2. Using the YouTube oEmbed API

GET http://www.youtube.com/oembed?url=http://www.youtube.com/watch?v=hI-BDR2UcmU &format=json { "provider_url": "http:\/\/www.youtube.com\/", "title": "NORAD Tracks Santa - US Region", "html": "<object width=\"425\" height=\"344\"><param name=\"movie\" value=\"http:\/\/www.youtube.com\/v\/hI-BDR2UcmU?fs=1\"><\/param> <param name=\"allowFullScreen\" value=\"true\"><\/param> <param name=\"allowscriptaccess\" value=\"always\"><\/param> <embed src=\"http:\/\/www.youtube.com\/v\/hI-BDR2UcmU?fs=1\" type=\"application\/x-shockwave-flash\" width=\"425\" height=\"344\" allowscriptaccess=\"always\" allowfullscreen=\"true\"><\/embed><\/object>", "author_name": "NORADTracksSanta", "height": 344, "thumbnail_width": 480, "width": 425, "version": "1.0", "author_url": "http:\/\/www.youtube.com\/user\/NORADTracksSanta", "provider_name": "YouTube", "thumbnail_url": "http:\/\/i1.ytimg.com\/vi\/hI-BDR2UcmU\/hqdefault.jpg", "type": "video", "thumbnail_height": 360 }

Embedding content with oEmbed

Now that you understand how oEmbed works, let's look at some code. I assume throughout this article that you are familiar with HTML, SQL, and XML and that you have a working Apache or PHP development environment. I also assume that you know the basics of working with classes and objects in PHP, as the PHP components used in this article are written in compliance with OOP principles.

To use oEmbed with a PHP application, you have a choice of two libraries: PEAR Services_oEmbed or php-oembed. Most of the examples in this article use PEAR Services_oEmbed (although I've also includes some examples of using php-oembed for reference), so install that. You can either manually download and install it from the PEAR website (see Related topics for a link) or have it installed automatically using the PEAR installer, as shown here.

shell> pear install Services_oEmbed-0.2.0

After you install it, try a simple example, as in Listing 3:

Listing 3. Using the YouTube oEmbed API

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://www.youtube.com/watch?v=hI-BDR2UcmU'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://www.youtube.com/oembed' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $video = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $video; ?> </div> </body> </html>

Listing 3 begins by loading the Services_oEmbed class and then defining the URL to the content to be embedded—in this case, a YouTube video. Next, an instance of the Services_oEmbed class is initialized, with the class constructor passed two arguments: the YouTube URL and an array of options.

The key element of the options array is the oEmbed API endpoint to use; in this case, it's YouTube's oEmbed endpoint, which is http://www.youtube.com/oembed. Finally, a call to the service object's getObject() method takes care of performing the oEmbed request and returning an object representation of the specified video.

This object representation contains details of the video being requested, such as its URL, author, provider, and title. It can also include size information for the thumbnail and the video object. Figure 1 illustrates what the object looks like.

Figure 1. The oEmbed object returned by PEAR Services_oEmbed

And Figure 2 illustrates the output of Listing 3. In this instance, the video is about NORAD tracking Santa Claus in the US Region.

Figure 2. An embedded YouTube video

Working with content metadata

You can add in some metadata for your embedded media, as in Listing 4.

Listing 4. Using oEmbed metadata

<?ph4 // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://www.youtube.com/watch?v=hI-BDR2UcmU'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://www.youtube.com/oembed' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $video = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $video; ?> </div> <div> Type: <?php echo $video->type;?> <br/> Title: <?php echo $video->title;?> <br/> Author: <a href="<?php echo $video->author_url;?>"> <?php echo $video->author_name;?></a> <br/> Provider: <a href="<?php echo $video->provider_url;?>"> <?php echo $video->provider_name;?></a> <br/> </div> </body> </html>

Figure 3 displays the output of Listing 4 with video and additional details such as type (video), title (NORAD Tracks Santa - US Region), author (NORADTracksSanta), and provider (YouTube).

Figure 3: An embedded YouTube video with additional metadata

It's important to note that the oEmbed specification defines four types of media: photo, video, link, and rich. The metadata returned for each type can differ; for example, a video has an html parameter containing the embed code for the video player, while a photo has a url parameter specifying the URL to the photo. Look in the specification (see Related topics for a link) for a complete list of request and response parameters.

Note also that you can include an additional parameter in the call to getObject() : an array containing maxheight and maxwidth parameters, which specify the height and width of the returned representation.

Using content from multiple sources

The nice thing about oEmbed is that it's supported by a number of different, popular web services: Flickr, Facebook, YouTube, Vimeo, Viddler, Revision3, just to name a few. Consider Listing 5, which demonstrates the process of embedding a video from Revision3.

Listing 5. Using the Revision3 oEmbed API

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://revision3.com/foundation/jackdorsey'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://revision3.com/api/oembed/' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $object = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $object; ?> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Figure 4 displays the output with video and additional details such as type (video), title (Jack Dorsey), author (Foundation), and provider (Revision3).

Figure 4. An embedded Revision3 video

Listing 6 has another example, this one embedding a fractal from the deviantART website.

Listing 6. Using the deviantART oEmbed API

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://undead-academy.deviantart.com/art/Spool-192326055'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://backend.deviantart.com/oembed' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $object = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $object; ?> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Figure 5 displays the output with the photo and additional details such as type (photo), title (Spool), author (Undead_Academy), and provider (DeviantART).

Figure 5. An embedded deviantART image

Using the oohEmbed service

Although many web applications already provide their own oEmbed API endpoint, there are some that don't. It's still possible, though, to access these applications through the oohEmbed service, which bills itself as "an oEmbed compatible provider of HTML embed codes for various websites." Additional applications and services that you can access through oohEmbed include amazon.com product images, Twitter status updates, Google Video, Metacafe, Slideshare, TwitPic, Wikipedia, Wordpress, and others. Note, however, that oohEmbed supports only JSON output and often ignores the maxwidth and maxheight parameters.

Listing 7 has an example of embedding Wikipedia content into a web page using oohEmbed.

Listing 7. Using oohEmbed and Wikipedia

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://en.wikipedia.org/wiki/Drupal'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://oohembed.com/oohembed/' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $object = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $object->html; ?> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Notice that in Listing 7, the API endpoint specified belongs to oohEmbed and not to Wikipedia. oohEmbed works like a proxy, receiving the oEmbed request and looking up the corresponding link, and returns an oEmbed-compliant response containing the required data to the caller.

Figure 6 illustrates the output of Listing 7 with video and additional details such as type (link), title (Drupal), author (the item is blank with no specific author named), and provider (Wikipedia):

Figure 6. An embedded Wikipedia page

Listing 8 has an example of embedding a Slideshare presentation into a web page (a rich media type) using oohEmbed.

Listing 8. Using oohEmbed and Slideshare

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://www.slideshare.net/weierophinney/best-practices-of-php-development-presentation'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://oohembed.com/oohembed/' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $object = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $object; ?> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Figure 7 illustrates the output of Listing 8 with a presentation and additional details such as type (rich), title (Best Practices of PHP Development), author (weierophinney, a working link), and provider (SlideShare, a working link to ).

Figure 7. An embedded Slideshare presentation

Listing 9 uses oohEmbed to retrieve and embed an amazon.com product image from the product URL.

Listing 9. Using oohEmbed and amazon.com

<?php // include class include 'Services/oEmbed.php'; // define content URL $url = 'http://www.amazon.com/Framework-Beginners-Guide-Vikram-Vaswani/dp/007163939X'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://oohembed.com/oohembed/' ); // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); $object = $oEmbed->getObject(); ?> <html> <head></head> <body> <div> <?php echo $object; ?> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Figure 8 illustrates the output of Listing 9 with a photo of a book cover and additional details such as type (photo), title (Zend Framework, A Beginner's Guide), author (Vikram Vaswani, a working link), and provider (Amazon Product Image, a working link).

Figure 8. An embedded Amazon product image

Using alternative PHP libraries

An alternative to the PEAR Services_oEmbed library is the php-oembed library, which can also be used to embed content into a web page. Installing the library is simple; download it (see Related topics for a link) and copy it to a location in your PHP include path. Configuration is, however, a little more complex than that for Services_oEmbed.

The php-oembed library maintains its own list of oEmbed providers and API endpoints in an XML file named providers.xml in its installation directory. Therefore, before you can begin using a particular oEmbed provider, you must first add it to this file. To illustrate, if you'd like to use the deviantART oEmbed API, you must first edit the providers.xml file and add an entry to it, as in Listing 10.

Listing 10. Editing the providers.xml file and adding an entry to it

<?xml version="1.0"?> <providers> <provider> <url>http://*.flickr.com/*</url> <endpoint>http://www.flickr.com/services/oembed/</endpoint> </provider> <provider> <url>http://*.pownce.com/*</url> <endpoint>http://api.pownce.com/2.1/oembed.{format}</endpoint> </provider> <provider> <url>http://*.deviantart.com/*</url> <endpoint>http://backend.deviantart.com/oembed</endpoint> </provider> <provider> <url>http://*.youtube.*/*</url> <endpoint>http://www.youtube.com/oembed</endpoint> </provider> </providers>

After the provider is added, you can proceed to use php-oembed in a PHP script, as in Listing 11.

Listing 11. Using oohEmbed and deviantART with the php-oembed library

<?php // define provider configuration define('PROVIDER_XML', 'providers.xml'); // include classes include 'ProviderManager.class.php'; include 'EmbedProvider.class.php'; include 'OEmbedProvider.class.php'; include 'LazyTemplateEngine.class.php'; include 'OEmbed.class.php'; include 'PhotoEmbed.class.php'; // create provider manager $manager = ProviderManager::getInstance(); // define content URL $url = 'http://undead-academy.deviantart.com/art/Spool-192326055'; // get oEmbed representation $object = $manager->provide($url, 'object'); ?> <html> <head></head> <body> <div> <img src="<?php echo $object->url; ?>" /> </div> <div> Type: <?php echo $object->type;?> <br/> Title: <?php echo $object->title;?> <br/> Author: <a href="<?php echo $object->author_url;?>"> <?php echo $object->author_name;?></a> <br/> Provider: <a href="<?php echo $object->provider_url;?>"> <?php echo $object->provider_name;?></a> <br/> </div> </body> </html>

Listing 11 begins by defining the location of the providers.xml file and including all the relevant classes needed by php-oembed. It then generates a ProviderManager service object and uses that object's provide() method to retrieve the oEmbed representation of a content URL. This representation can be returned in a variety of formats: XML, JSON, PHP object, PHP array, or serialized string.

Figure 9 illustrates what the returned object looks like. (View a text-only version of Figure 9.)

Figure 9. The oEmbed object returned by php-oembed

It's now quite easy to use the properties of this object and include the embedded representation inside a web page with the photo and additional details such as type (photo), title (Spool), author (Undead_Academy), and provider (DeviantART), as in Figure 10.

Figure 10. An embedded deviantART image

Example application: Inline content embedding

Now that you understand the basics of using PHP with oEmbed, let's see how it all works in the context of a sample application. Because oEmbed is all about embedding content into web pages, the example application offers users a form to input content (such as a blog post) and automatically turn hyperlinks within that content into embedded representations using oEmbed.

Listing 12 has the complete code.

Listing 12. An example application for inline content embedding

<html> <head></head> <body> <?php if (isset($_POST['submit'])): ?> <?php // include class include 'Services/oEmbed.php'; // define API endpoint $options = array( Services_oEmbed::OPTION_API => 'http://oohembed.com/oohembed/' ); // get post body // extract all URLs into array $oBody = $_POST['body']; $title = $_POST['title']; preg_match_all('!https?://[\S]+!', $oBody, $matches); $urls = $matches[0]; $embeds = array(); // for each URL // get embed code from oohembed if available // else convert to simple hyperlink foreach ($urls as $url) { // get oEmbed representation $oEmbed = new Services_oEmbed($url, $options); try { $object = $oEmbed->getObject(array('maxheight' => '100', 'maxwidth' => '100')); $embeds[] = (string)$object; } catch (Exception $e) { $embeds[] = "<a href=\"" . $url . "\">" . $url . "</a>"; } } // replace URLs in body with code // print revised output $nBody = str_replace($urls, $embeds, $oBody); ?> <h1>Preview New Post</h1> <h2><?php echo $title; ?></h2> <p> <?php echo nl2br($nBody); ?> </p> <?php else: ?> <h1>Add New Post</h1> <form method="post" action="<?php echo htmlentities($_SERVER['PHP_SELF']); ?>"> <p> Title: <br/> <input type="text" name="title" size="40" /> </p> <p> Body: <br/> <textarea name="body" rows="10" cols="50"></textarea> </p> <input type="submit" name="submit" /> </form> <?php endif; ?> </body> </html>

Listing 12 is divided into two sections, separated by an if-else() conditional test. The test checks for a form submission; if it is not found, it displays a simple web form that asks the user to enter a page title and body content. A user can enter text into both these fields, including hyperlinks as needed. Figure 11 illustrates the web form generated by Listing 12, with some sample input. (View a text-only version of Figure 11.)

Figure 11. A web form that supports inline content embedding

After the form is submitted, the script initializes a new Services_oEmbed object, passing it the oohEmbed API endpoint. It then parses the content submitted by the user, extracting all the URLs found within the body by means of a simple regular expression. (Note: This regular expression should not be used in production environments as it is not secure against XSS attacks.) The URLs identified in this manner are stored in a PHP array named $urls .

Next, a foreach() loop and try-catch{} block are used to iterate over the URL array, passing each one to the Services_oEmbed object's getObject() method. This step results in a request to the oohEmbed API for the corresponding remote content. If the content is on a supported service, the getObject() method returns the corresponding HTML embed code, which is saved to a separate array named $embeds . If the content isn't supported, the code throws an exception, which is caught by the try-catch{} block. This exception implies that an embedded representation of the URL was not available; therefore, the URL is simply converted to an HTML anchor tag and saved to the $embeds array.

The final step is to perform a search-and-replace operation on the original body content submitted by the user, replacing each URL with either the corresponding HTML embed code or HTML hyperlink. The revised body is then printed to the web page.

Figure 12 illustrates the resulting output, with embedded content displayed inline.

Figure 12. A web page with inline embedded content

Conclusion

This article gave you a crash course in how to embed rich content, such as photos, videos, and slides, stored on third-party web services into a web page using the oEmbed specification. This specification provides an efficient and intuitive way to embed data from multiple popular applications and websites into a web page. The examples in this article made use of two PHP client libraries for oEmbed and discussed using oEmbed with a number of popular websites, including Flickr, YouTube, SlideShare, Wikipedia, and amazon.com.

As these examples illustrate, oEmbed is a simple purpose-built API that is designed for just one thing—embedding content —and it performs this task extremely well. It offers a flexible tool for developers looking to build creative new applications around content aggregation and search. Play with it sometime, and see what you think.

Downloadable resources

Related topics