PHP Web 2.0 Mashup Projects: Your Own Video Jukebox: Part 2

Shu-Wai Chow

February 2010

Parsing With PEAR

If we were to start mashing up right now, between XSPF, YouTube's XML response, and RSS, we would have to create three different parsers to handle all three response formats. We would have to comb through the documentation and create flexible parsers for all three formats. If the XML response for any of these formats changes, we would also be responsible for changing our parser code. This isn't a difficult task, but we should be aware that someone else has already done the work for us. Someone else has already dissected the XML code. To save time, we can leverage this work for our mashup.

We used PEAR, earlier in Chapter 1 to help with XML-RPC parsing. For this project, we will once again use PEAR to save us the trouble of writing parsers for the three XML formats we will encounter.

For this project, we will take a look at three packages for our mashup. File_XSPF is a package for extracting and setting up XSPF playlists. Services_YouTube is a Web Services package that was created specifically for handling the YouTube API for us. Finally, XML_RSS is a package for working with RSS feeds.

For this project, it works out well that there are three specific packages that fits our XML and RSS formats. If you need to work with an XML format that does not have a specific PEAR package, you can use the XML_Unserializer package. This package will take a XML and return it as a string.

Is PEAR Right For You?
Before we start installing PEAR packages, we should take a look if it is even feasible to use them for a project. PEAR packages are installed with a command line package manager that is included with every core installation of PHP. In order for you to install PEAR packages, you need to have administrative access to the server. If you are in a shared hosting environment and your hosting company is stingy, or if you are in a strict corporate environment where getting a server change is more hassle than it is worth, PEAR installation may not be allowed. You could get around this by downloading the PEAR files and installing them in your web documents directory. However, you will then have to manage package dependencies and package updates by yourself. This hassle may be more trouble than it's worth, and you may be better off writing your own code to handle the functionality.
On the other hand, PEAR packages are often a great time saver. The purpose of the packages is to either simplify tedious tasks, or interface with complex systems. The PEAR developer has done the difficult work for you already. Moreover, as they are written in PHP and not C, like a PHP extension would be, a competent PHP developer should be able to read the code for documentation if it is lacking. Finally, one key benefit of many packages, including the ones we will be looking at, is that they are object-oriented representations of whatever they are interfacing. Values can be extracted by simply calling an object's properties, and complex connections can be ignited by a simple function call. This helps keep our code cleaner and modular. Whether the benefits of PEAR outweigh the potential obstacles depends on your specific situation.

Package Installation and Usage

Just like when we installed the XML-RPC package, we will use the install binary to install our three packages. If you recall, installing a package, simply type install into the command line followed by the name of the package. In this case, though, we need to set a few more flags to force the installer to grab dependencies and code in beta status.

To install File_XSPF, switch to the root user of the machine and use this command:

[Blossom:~] shuchow# /usr/local/php5/bin/pear install -f --
alldeps File_XSPF

This command will download the package. The -alldeps flag tells PEAR to also check for required dependencies and install them if necessary. The progress and outcome of the downloads will be reported.

Do a similar command for Services_YouTube:

[Blossom:~] shuchow# /usr/local/php5/bin/pear install -f --alldeps 

Usually, you will not need the –f flag. By default, PEAR downloads the latest stable release of a package. The –f flag, force, forces PEAR to download the most current version, regardless of its release state. As of this writing, File_XSPF and Services_YouTube do not have stable releases, only beta and alpha respectively. Therefore, we must use –f to grab and install this package. Otherwise, PEAR will complain that the latest version is not available. If the package you want to download is in release state, you will not need the –f flag.

This is the case of XML_RSS, which has a stable version available.

[Blossom:~] shuchow# /usr/local/php5/bin/pear install --alldeps XML_RSS

After this, sending a list-all command to PEAR will show the three new packages along with the packages you had before.

PEAR packages are basically self-contained PHP files that PEAR installs into your PHP includes directory. The includes directory is a directive in your php.ini file. Navigate to this directory to see the PEAR packages' source files. To use a PEAR package, you will need to include the package's source file in the top of your code. Consult the package's documentation on how to include the main package file. For example, File_XSPF is activated by including a file named XSPF.php. PEAR places XSPF.php in a directory named File, and that directory is inside your includes directory.

require_once 'File/XSPF.php';
//File_XSPF is now available.


The documentation to the latest version of XSPF is located at

The package is simple to use. The heart of the package is an object called XSPF. You instantiate and use this object to interact with a playlist. It has methods to retrieve and modify values from a playlist, as well as utility methods to load a playlist into memory, write a playlist from memory to a file, and convert an XSPF file to other formats.

Getting information from a playlist consists of two straightforward steps. First, the location of the XSPF file is passed to the XSPF object's parse method. This loads the file into memory. After the file is loaded, you can use the object's various getter methods to extract values from the list. Most of the XSPF getter methods are related to getting metadata about the playlist itself. To get information about the tracks in the playlist, use the getTracks method. This method will return an array of XSPF_Track objects. Each track in the playlist is represented as an XSPF_Track object in this array. You can then use the XSPF_Track object's methods to grab information about the individual tracks.

We can grab a playlist from to illustrate how this works. The web service has a playlist of a member's most played songs. Named Top Tracks, the playlist is located at, where USERNAME is the name of the user that you want to query.

This page is named XSPFPEARTest.php in the examples. It uses File_XSPF to display my top tracks playlist from

require_once 'File/XSPF.php';
$xspfObj =& new File_XSPF();
//Load the playlist into the XSPF object.
//Get all tracks in the playlist.
$tracks = $xspfObj->getTracks();

This first section creates the XSPF object and loads the playlist. First, we bring in the File_XSPF package into the script. Then, we instantiate the object. The parseFile method is used to load an XSPF file list across a network. This ties the playlist to the XSPF object. We then use the getTracks method to transform the songs on the playlist into XSPF_Track objects.

<title>Shu Chow's Top Tracks</title>
Title: <?= $xspfObj->getTitle() ?><br />
Created By: <?= $xspfObj->getCreator() ?>

Next, we prepare to display the playlist. Before we do that, we extract some information about the playlist. The XSPF object's getTitle method returns the XSPF file's title element. getCreator returns the creator element of the file.

<?php foreach ($tracks as $track) { ?>
Title: <?= $track->getTitle() ?><br />
Artist: <?= $track->getCreator() ?><br />
<?php } ?>

Finally, we loop through the tracks array. We assign the array's elements, which are XSPF_Track objects, into the $track variable. XSPF_Track also has getTitle and getCreator methods. Unlike XSPF's methods of the same names, getTitle returns the title of the track, and getCreator returns the track's artist.

Running this file in your web browser will return a list populated with data from


Services_YouTube works in a manner very similar to File_XSPF. Like File_XSPF, it is an object-oriented abstraction layer on top of a more complicated system. In this case, the system is the YouTube API.

Using Services_YouTube is a lot like using File_XSPF. Include the package in your code, instantiate a Services_YouTube object, and use this object's methods to interact with the service. The official documentation for the latest release of Services_YouTube is located at The package also contains online working examples at

Many of the methods deal with getting members' information like their profile and videos they've uploaded. A smaller, but very important subset is used to query YouTube for videos. We will use this subset in our mashup. To get a list of videos that have been tagged with a specific tag, use the object's listByTag method.

listByTag will query the YouTube service and store the XML response in memory. It is does not return an array of video objects we can directly manage, but with one additional function call, we can achieve this. From there, we can loop through an array of videos similar to what we did for XSPF tracks.

The example file YouTubePearTest.php illustrates this process.

require_once 'Services/YouTube.php';
$dev_id = 'Your YouTube DeveloperID';
$tag = 'Social Distortion';
$youtube = new Services_YouTube($dev_id, array('usesCache' => true));
$videos = $youtube->listByTag($tag);

First, we load the Services_YouTube file into our script. As YouTube's web service requires a Developer ID, we store that information into a local variable. After that, we place the tag we want to search for in another local variable named $tag. In this example, we are going to check out which videos YouTube has for the one of the greatest bands of all time, Social Distortion. Service_YouTube's constructor takes this Developer ID and uses it whenever it queries the YouTube web service. The constructor can take an array of options as a parameter. One of the options is to use a local cache of the queries. It is considered good practice to use a cache, as to not slam the YouTube server and run up your requests quota.

Another option is to specify either REST or XML-RPC as the protocol via the driver key in the options array. By default, Services_YouTube uses REST. Unless you have a burning requirement to use XML-RPC, you can leave it as is.

Once instantiated, you can call listByTag to get the response from YouTube. listByTag takes only one parameter—the tag of our desire.

Services_YouTube now has the results from YouTube. We can begin the display of the results.

<title>Social Distortion Videos</title>
<h1>YouTube Query Results for Social Distortion</h1>

Next, we will loop through the videos. In order to get an array of video objects, we first need to parse the XML response. We do that using Services_YouTube's xpath method, which will use the powerful XPATH query language to go through the XML and convert it into PHP objects. We pass the XPATH query into the method, which will give us an array of useful objects. We will take a closer look at XPATH and XPATH queries later in another project. For now, trust that the query //video will return an array of video objects that we can examine.

Within the loop, we display each video's title, a thumbnail image of the video, and a hyperlink to the video itself.

<?php foreach ($videos->xpath('//video') as $i => $video) { ?>
Title: <?= $video->title ?><br />
<img src='<?= $video->thumbnail_url ?>' alt='<?= $video->title ?>'
/><br />
<a href='<?= $video->url ?>'>URL</a>
<?php } ?>

Running this query in our web browser will give us a results page of videos that match the search term we submitted.


Like the other PEAR extensions, XML_RSS changes something very complex, RSS, into something very simple and easy to use, PHP objects. The complete documentation for this package is at

There is a small difference to the basic philosophy of XML_RSS compared to Services_YouTube and File_XSPF. The latter two packages take information from whatever we're interested in, and place them into PHP object properties.

For example, File_XSPF takes track names into a Track object, and you use a getTitle() getter method to get the title of the track. In Services_YouTube, it's the same principle, but the properties are public, and so there are no getter methods. You access the video's properties directly in the video object.

In XML_RSS, the values we're interested in are stored in associative arrays. The available methods in this package get the arrays, then you manipulate them directly. It's a small difference, but you should be aware of it in case you want to look at the code. It also means that you will have to check the documentation of the package to see which array keys are available to you.

Let's take a look at how this works in an example. The file is named RSSPEARTest.php in the example code. One of Audioscrobbler's feeds gives us an RSS file of songs that a user recently played. The feed isn't always populated because after a few hours, songs that are played aren't considered recent. In other words, songs will eventually drop off the feed simply because they are too old. Therefore, it's best to use this feed on a heavy user of

RJ is a good example to use. He seems to always be listening to something. We'll grab his feed from Audioscrobbler:

include ("XML/RSS.php");
$rss =& new XML_RSS("

We start off by including the module and creating an XML_RSS object. XML_RSS is where all of the array get methods reside, and is the heart of this package. It's constructor method takes one variable—the path to the RSS file. At instantiation, the package loads the RSS file into memory.

parse() is the method that actually does the RSS parsing. After this, the get methods will return data about the feed. Needless to say, parse() must be called before you do anything constructive with the file.

 $channelInfo = $rss->getChannelInfo();

The package's getChannelInfo() method returns an array that holds information about the metadata, the channel, of the file. This array holds the title, description, and link elements of the RSS file. Each of these elements is stored in the array with the same key name as the element.

<?= "<?xml version="1.0" encoding="UTF-8" ?>" ?>

The data that comes back will be UTF-8 encoded. Therefore, we need to force the page into UTF-8 encoding mode. This line outputs the XML declaration into the top of the web page in order to insure proper rendering. Putting a regular <?xml declaration will trigger the PHP engine to parse the declaration. However, PHP will not recognize the code and halt the page with an error.

<title><?= $channelInfo['title'] ?></title>
<h1><?= $channelInfo['description'] ?></h1>

Here we begin the actual output of the page. We start by using the array returned from getChannelInfo() to output the title and description elements of the feed.

<?php foreach ($rss->getItems() as $item { ?>
<?= $item['title'] ?>:
<a href="<?= $item ['link'] ?>"><?= $item ['link'] ?></a>
<?php } ?>

Next, we start outputting the items in the RSS file. We use getItems() to grab information about the items in the RSS. The return is an array that we loop through with a foreach statement. Here, we are extracting the item's title and link elements. We show the title, and then create a hyperlink to the song's page on The description and pubDate elements in the RSS are also available to us in getItems's returned array.

 Link to User:
<a href="<?= $channelInfo['link'] ?>"><?=
$channelInfo['link'] ?></a>

Finally, we use the channel's link property to create a hyperlink to the user's page before we close off the page's body and html tags.

Using More Elements
In this example, the available elements in the channel and item arrays are a bit limited. getChannelInfo() returns an array that only has the title, description, and link properties. The array from getItems() only has title, description, link, and pubDate properties. This is because we are using the latest release version of XML_RSS. At the time of writing this book, it is version 0.9.2. The later versions of XML_RSS, currently in beta, handle many more elements. Elements in RSS 2.0 like category and authors are available. To upgrade to a beta version of XML_RSS, use the command PEAR upgrade –f XML_RSS in the command line. The –f flag is the same flag we used to force the beta and alpha installations of Service_YouTube and File_XSPF. Alternatively, you can install the beta version of XML_RSS at the beginning using the same –f flag.

If we run this page on our web browser, we can see the successful results of our hit.

At this point, we know how to use the Audioscrobbler feeds to get information. The majority of the feeds are either XSPF or RSS format. We know generally how the YouTube API works. Most importantly, we know how to use the respective PEAR packages to extract information from each web service. It's time to start coding our application.

Mashing Up

If you haven't already, you should, at the very least, create a YouTube account and sign up for a developer key. You should also create a account, install the client software, and start listening to some music on your computer. This will personalize the video jukebox to your music tastes. All examples here will assume that you are using your own YouTube key. I will use my own account for the examples. As the feeds are open and free, you can use the same feeds if you choose not to create a account.

Mashup Architecture

There are obviously many ways in which we can set up our application. However, we're going to keep functionality fairly simple.

The interface will be a framed web page. The top pane is the navigation pane. It will be for the song selection. The bottom section is the content pane and will display and play the video.

In the navigation pane, we will create a select menu with all of our songs. The value, and label, for each option will be the artist name followed by a dash, followed by the name of the song (For example, "April Smith—Bright White Jackets"). Providing both pieces of information will help YouTube narrow down the selection.

When the user selects a song and pushes a "Go" button, the application will load the content page into the content pane. This form will pass the artist and song information to the content page via a GET parameter. The content page will use this GET parameter to query YouTube. The page will pull up the first, most relevant result from its list of videos and display it.

PHP Web 2.0 Mashup Projects

Main Page

The main page is named jukebox.html in the example code. This is our frameset page. It will be quite simple. All it will do is define the frameset that we will use.

<title>My Video Jukebox</title>
<frameset rows="10%,90%">
<frame src="navigation.php" name="Navigation" />
<frame src="" name="Content" />

This code defines our page. It is two frame rows. The navigation section, named Navigation, is 10% of the height, and the content, named Content, is the remaining 90%. When first loaded, the mashup will load the list of songs in the navigation page and nothing else.

Navigation Page

The navigation page is named navigation.php. This page will use File_XSPF and XML_RSS to load the songs from's Top Tracks and Recent Tracks feeds for the user, and merge them together to create a select menu.

require_once ('File/XSPF.php');
require_once ('XML/RSS.php');

In the beginning, the File_XSPF and XML_RSS PEAR packages are loaded.

$songsArray = array();

An array to hold all the songs is initialized. We need this because we are dealing with two feeds—Top Tracks and Recent Tracks. Also, both feeds return different things. File_XSPF returns an array of song objects. RSS_XML returns an associative array of values where the property names are the key in the array.

//Top Tracks
$xspfObj =& new File_XSPF();
$topTracks = $xspfObj->getTracks();

First, we create an array of song objects from the Top Tracks XSPF feed.

//Recent Tracks
$rss =& new XML_RSS('
$recentTracks = $rss->getItems();

We extract the second, associative array from XML_RSS:

foreach ($topTracks as $trackObj) {
$songsArray[] =
$trackObj->getCreator() . " - " . $trackObj->getTitle();

We use the getCreator() and getTitle() methods on the Top Track objects to create a string in the Artist—Song format, and we place it in $songsArray.

foreach ($recentTracks as $tracksArray) {
$tempSong =
htmlentities($tracksArray['title'], ENT_COMPAT, 'UTF-8');
$songsArray[] = str_replace('&ndash;', "-", $tempSong);

By default, the "Artist—Song" format is what the RSS feed returns. Therefore, we can just extract it and place it into the $songsArray. However, we have to do a little massaging first. As the data is coming from an XML-based file, certain characters are encoded. This includes the dash mark inbetween the artist and song. The first line uses the PHP htmlentities() function and converts the value from XML encoding to the equivalent HTML entity. In this case, the dash in the RSS file becomes "–" This new value is placed inside a variable named $tempSong. The next line replaces ; with a regular dash character, and pushes it into $songsArray.

$songsArray = array_unique($songsArray);

Finally, we make the list presentable. array_unique() will eliminate duplicate songs between the Top Tracks feed and the Recent Tracks feed. sort() will sort the list for us alphabetically. This ends the preliminary required PHP code. We can start with the HTML next:.

<?= '<?xml version="1.0" encoding="UTF-8" ?>' ?>
<form method="GET" action="content.php" target="Content">
<select name="query">
<?php foreach ($songsArray as $key => $value) { ?>
<option value="<?= $value ?>"><?= $value ?></option>
<?php } ?>
<input type="submit" value="Go" />

Again, before we start with the actual HTML, we use a PHP echo to declare the encoding on this page. In the HTML, we create the form. The form will use a GET method to pass the selected option value to the content.php page targeted for the Content frame. We use $songsArray, which we previously populated to create the select menu.

Finally, an input button is added to trigger the load. The form and html tags are then closed.

Content Page

Our content page, named content.php, is loaded when the form on the navigation page is submitted. The form sends the artist and song title to content.php via a query parameter named query. content.php will have to take this parameter, pass it to YouTube's Web API, and display the results.

require_once ('Services/YouTube.php');
//YouTube parameters
$tag = $_GET['query'];
//YouTube Result Parameters
$videosArray = array();
$firstVideo = null;

We start off with some basic initialization. We pull in the Services_YouTube package, set up the $dev_id variable, which holds our YouTube Developer ID, and set up a variable named $tag which holds the GET parameter received when the page is called.

Next, an array is set up to hold the video return results. A variable named $firstVideo is declared. A query can, and often does, return multiple results, with the most relevant result returned at the top. $firstVideo will hold this most relevant hit.

$youtube = new Services_YouTube($devID, array('usesCache' => true));
$videos = $youtube->listByTag($tag);
$videosArray = $videos->xpath('//video');
$firstVideo = $videosArray[0];

The first three lines of this block operate just like the Services_YouTube example: a Services_YouTube object is declared, the service is called, and the results are queried through XPATH.

We now have an array of all results. As we're only interested in the most relevant, we capture the one at index position 0 and place it into the $firstVideo array. Our setup PHP code is now completed, and we can begin the HTML.

<?= '<?xml version="1.0" encoding="UTF-8" ?>' ?>
<h1>YouTube Query Results for <?= $_GET['query'] ?></h1>
<?php if ($firstVideo) { ?>

In the HTML, we encounter a PHP if statement. This if statement checks to see if the $firstVideo array actually has anything in it. We check to see if the object exists.

Title: <?= $firstVideo->title ?><br />
<object width="425" height="350">
<param name="movie" value="<?=
$firstVideo->id ?>"></param>
<param name="wmode" value="transparent"></param>
<embed src="<?= $firstVideo->id ?>"
type="application/x-shockwave-flash" wmode="transparent"
width="425" height="350"></embed>
<a href="<?= $firstVideo->url ?>"><?=
$firstVideo->title ?>'s YouTube Page</a>

If the object exists, we use it to create the display page. The video object has three properties that we use in this section:

  • title is the YouTube title.
  • id is the YouTube unique identifier.
  • url is the URL to the YouTube page.

The id is particularly important. Each video's page on YouTube has sample code you can use to copy and paste into your own web page. This will embed the video into the page and play it within the page. The sample code involves an object, two param tags, and an embed tag. We have copied this code into our application. However, we substitute the hard-coded example ids with our object's id property.

<?php } else { ?>
No Results Found
<?php } ?>

We add an else block to display a, "No Results Found", message if YouTube returns nothing from the query. Finally, we close the body and html tags.

Place these three files into the same, web-server accessible directory on a web server. You can start using the mashup by launching jukebox.php in your web browser.

Using the Mashup

When you load jukebox.php, you will see a page similar to the one shown on the previous page. navigation.php will load, and the select menu will be created from our feeds.

Click on the menu. You will see a list of the songs from the two feeds. Select one and press the Go button.

My first selection, a song by Tangerine, yielded no results. We see the error message in the content pane. This isn't surprising because they are a small, up and coming local band based in Pittsburgh, Pennsylvania. Once they become more popular, their legions of fans will grow and hopefully someone will put something up on YouTube.

Let's select a more well-known band and song.

Our next selection, Atmosphere by Joy Division, was more successful. In this case, someone upload Atmosphere's music video. Pressing on the Play button will start playing the video without leaving our mashup.

The great thing about this mashup is the user-driven nature of YouTube. You can't be sure of what will be returned In Atmosphere's case, we saw the official music video that someone uploaded. In many other cases, we get to see rare live performances that someone recorded with a camcorder and uploaded. Sometimes we'll see some creative minds who made their own music video and set it to the music that we queried. Other times, the video may have nothing to do with the song at all, except that it plays in the background. For example, when I submitted The Clash's classic Death or Glory, the only video that was returned was a tribute slideshow of, of all people, Harry Potter star Daniel Radcliffe that someone created.


In this mashup, we used two different web APIs—one from video repository site YouTube, and the XML feeds from social music site We took a look at three different XML-based file formats from those two sites: XSPF for song playlists, RSS for publishing frequently updated information, and YouTube's custom XML format. We created a mashup that took the songs in two feeds and queried YouTube to retrieve videos based on the song.

If we were to create our own XML-based parsers to parse the three formats, this would have taken much more time than it actually did. We found that the PHP Extension and Application Repository, PEAR, already had parsers we could use; one for each of the three formats. Using these PEAR packages, we were able to create an object-oriented abstraction of these formats, which allowed us to easily finish our application.


If you have read this article you may be interested to view :

You've been reading an excerpt of:

PHP Web 2.0 Mashup Projects: Practical PHP Mashups with Google Maps, Flickr, Amazon, YouTube, MSN Search, Yahoo!

Explore Title