Introduction To Computational Media on the Web (ICM-W) : Week 9

AJAX

AJAX (Aysnchronous JavaScript and XML) is a technique for dynamically altering a page by communicating with a server and without leaving the page.

Essentially it is made possible by the XMLHttpRequest object

AJAX is a bit difficult to get working in a cross platform manner but their are quite a few libraries out there that have done the hard work.

We will use this one: ajax.js

Here is an example:
A text file on the server named ajax_example.txt contains the following:
		Something...
		
The HTML (named ajax_example.html):
<html>
	<head>
		<title>AJAX Example</title>
		<!-- Load up the AJAX External JavaScript file -->
		<script type="text/javascript" src="ajax.js" ></script>

		<!-- Local Javascript Code -->
		<script type="text/javascript">

			// A variable to hold the an interval
			// Global in scope
			var interval = null;	
	
			// A function to call a text file up from the server via ajax
			function call_ajax()
			{
				makeHttpRequest('ajax_example.txt',ajax_return);
			}

			// A function that gets called when ajax returns, asynchronously
			function ajax_return(response)
			{
				// Just putting the content of the text file into the "messages" div on the page
				document.getElementById("messages").innerHTML = response;
				
				// Set the timeout again to make it keep going
				interval = setTimeout("call_ajax()",5000);				
			}
	
			// Setup AJAX function, creates a timeout so that we run something periodically
			function setup_ajax()
			{
				// Set interval of 5000 milliseconds
				// Keeps going...
				//interval = setInterval("call_ajax()",5000);

				// Only happens once..
				interval = setTimeout("call_ajax()",5000);
			}			
		
			// Register setup_ajax with the onload event of the window (when it is done loading)..	
			window.onload = setup_ajax;

		</script>
	</head>
	<body>
		<b>Looky here!</b>
		<div id="messages" style="overflow: auto; width: 500px; height: 400px;">
			Something should pop up here..
		</div>
	</body>
</html>
		
Try It

The above example is very simplistic but a illustrates many points. First of all, the browser loads the HTML and executes the JavaScript contained within ajax_example.html. At the bottom of the JavaScript there is an event "window.onload" which is assigned to run a function called "setup_ajax". This ensures that the "setup_ajax" function will run after the HTML page is rendered and the JavaScript functions are all defined. This is the same thing as using the "onload" event within the "body" tag.

The "setup_ajax" function creates an timeout that calls "call_ajax" after 5 seconds. "ajax_return" sets the timeout again after a response from the server.

The "call_ajax" function is where we call "makeHttpRequest" which is a function defined in "ajax.js". This function takes in the URL of the page to call, in this case "ajax_example.txt" and what function to send the source of this page to ("ajax_return").

Essentially, "makeHttpRequest" is functioning as if someone clicked on a link but instead of going to a different page in the browser, the source code of that page get's sent to a JavaScript function. This enables us to modify a page on the fly, perhaps even "live"..

The "ajax_return" function takes in the source of the page that was called and in this case just uses the getElementById and innerHTML methods and properties to modify the current page.

Taking this a step further, we could modify the text file that is being called repeatedly by the AJAX at any time and the change would be reflected on the user's browser.

We could also use a bit of some server side programming through PHP to do even more...

Web Services

A web service is a machine to machine interface via a web based interface. For instance, the way that we were getting the weather from the Yahoo Weather RSS feed was treating their feed as if it is a web service (which it is as RSS is a machine readable format, unlike HTML).

Web services come in a lot of different flavors, SOAP, XML-RPC, REST and so on. REST is generally the most straight forward and typically involves sending an HTTP request to a remote server and getting XML in return.

There are a ton of available web service APIs (application programming interfaces), each a bit different. For a good rundown, check: http://www.programmableweb.com/apilist.

Let's do an example using Twitter (always a favorite): Twitter's API is documented here: http://apiwiki.twitter.com/Twitter-API-Documentation

Using PHP we can make a request into Twitter's API search API in the same manner we did with getting the weather feed from Yahoo: file_get_contents.

We have to reference the Twitter search function page in order to figure out how to construct the request: http://apiwiki.twitter.com/Twitter-Search-API-Method%3A-search. In this case we want Twitter to return ATOM data (which is like RSS) so the URL will be: http://search.twitter.com/search.atom?q=somethingtosearchfor

Opening that URL in a browser (Firefox) allows us to see the format of the data returned (view source). We notice that each of the tweets is in a separate "entry" tag and is an XML format (Extensible Markup Language).
		$twitterdata = file_get_contents("http://search.twitter.com/search.atom?q=yankees");
		echo($twitterdata);
	
outputs:
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns:google="http://base.google.com/ns/1.0" xml:lang="en-US" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns="http://www.w3.org/2005/Atom" xmlns:twitter="http://api.twitter.com/">
  <id>tag:search.twitter.com,2005:search/yankees</id>
  <link type="text/html" href="http://search.twitter.com/search?q=yankees" rel="alternate"/>
  <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=yankees" rel="self"/>
  <title>yankees - Twitter Search</title>
  <link type="application/opensearchdescription+xml" href="http://search.twitter.com/opensearch.xml" rel="search"/>
  <link type="application/atom+xml" href="http://search.twitter.com/search.atom?q=yankees&since_id=5354203798" rel="refresh"/>
  <twitter:warning>since_id removed for pagination.</twitter:warning>
  <updated>2009-11-02T03:19:30Z</updated>
  <openSearch:itemsPerPage>15</openSearch:itemsPerPage>
  <link type="application/atom+xml" href="http://search.twitter.com/search.atom?max_id=5354203798&page=2&q=yankees" rel="next"/>
  <entry>
    <id>tag:search.twitter.com,2005:5354203798</id>
    <published>2009-11-02T03:19:30Z</published>
    <link type="text/html" href="http://twitter.com/beachboi757/statuses/5354203798" rel="alternate"/>
    <title>let's. Go Yankees</title>
    <content type="html">let&apos;s. Go <b>Yankees</b></content>
    <updated>2009-11-02T03:19:30Z</updated>
    <link type="image/png" href="http://a1.twimg.com/profile_images/488154818/me_again_normal.jpg" rel="image"/>
    <twitter:geo>
    </twitter:geo>
    <twitter:source><a href="http://twidroid.com" rel="nofollow">twidroid</a></twitter:source>
    <twitter:lang>da</twitter:lang>
    <author>
      <name>beachboi757 (Mark Murphy)</name>
      <uri>http://twitter.com/beachboi757</uri>
    </author>
  </entry>
  <entry>
    <id>tag:search.twitter.com,2005:5354203559</id>
    <published>2009-11-02T03:19:29Z</published>
    <link type="text/html" href="http://twitter.com/MelvinJames/statuses/5354203559" rel="alternate"/>
    <title>Just getting in from the Obama rally in Newark.. what an awesome day, what an awesome President. Now watching the rest of the Yankees game.</title>
    <content type="html">Just getting in from the Obama rally in Newark.. what an awesome day, what an awesome President. Now watching the rest of the <b>Yankees</b> game.</content>
    <updated>2009-11-02T03:19:29Z</updated>
    <link type="image/png" href="http://a3.twimg.com/profile_images/455298953/twitterProfilePhoto_normal.jpg" rel="image"/>
    <twitter:geo>
    </twitter:geo>
    <twitter:source><a href="http://twitter.com/">web</a></twitter:source>
    <twitter:lang>en</twitter:lang>
    <author>
      <name>MelvinJames (MelvinJames)</name>
      <uri>http://twitter.com/MelvinJames</uri>
    </author>
  </entry>
	
We could use the same methods we used with Yahoo's Weather API and find specific things using substring and so on but there is an easier way.

XML

.... Using SimpleXML we can have PHP automatically parse the XML file for us and put it into a "data structure". This data structure stuff can be a bit confusing and difficult to figure out so the first thing we want to do is output it using print_r
        $twitterdata = file_get_contents("http://search.twitter.com/search.atom?q=yankees");
        $twitterxml = simplexml_load_string($twitterdata);
        print_r($twitterxml);	
	
this outputs:
SimpleXMLElement Object
(
    [id] => tag:search.twitter.com,2005:search/yankees
    [link] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [type] => text/html
                            [href] => http://search.twitter.com/search?q=yankees
                            [rel] => alternate
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [type] => application/atom+xml
                            [href] => http://search.twitter.com/search.atom?q=yankees
                            [rel] => self
                        )

                )

            [2] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [type] => application/opensearchdescription+xml
                            [href] => http://search.twitter.com/opensearch.xml
                            [rel] => search
                        )

                )

            [3] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [type] => application/atom+xml
                            [href] => http://search.twitter.com/search.atom?q=yankees&since_id=5354595897
                            [rel] => refresh
                        )

                )

            [4] => SimpleXMLElement Object
                (
                    [@attributes] => Array
                        (
                            [type] => application/atom+xml
                            [href] => http://search.twitter.com/search.atom?max_id=5354595897&page=2&q=yankees
                            [rel] => next
                        )

                )

        )

    [title] => yankees - Twitter Search
    [updated] => 2009-11-02T03:37:37Z
    [entry] => Array
        (
            [0] => SimpleXMLElement Object
                (
                    [id] => tag:search.twitter.com,2005:5354595897
                    [published] => 2009-11-02T03:37:37Z
                    [link] => Array
                        (
                            [0] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => text/html
                                            [href] => http://twitter.com/Phil_AkA_wAcKo/statuses/5354595897
                                            [rel] => alternate
                                        )

                                )

                            [1] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => image/png
                                            [href] => http://a3.twimg.com/profile_images/495079725/aaaassssssssssss_normal.jpg
                                            [rel] => image
                                        )

                                )

                        )

                    [title] => Let's go Yankees :) we can win this
                    [content] => Let's go <b>Yankees</b> :) we can win this
                    [updated] => 2009-11-02T03:37:37Z
                    [author] => SimpleXMLElement Object
                        (
                            [name] => Phil_AkA_wAcKo (Phil)
                            [uri] => http://twitter.com/Phil_AkA_wAcKo
                        )

                )

            [1] => SimpleXMLElement Object
                (
                    [id] => tag:search.twitter.com,2005:5354595896
                    [published] => 2009-11-02T03:37:37Z
                    [link] => Array
                        (
                            [0] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => text/html
                                            [href] => http://twitter.com/sathomas/statuses/5354595896
                                            [rel] => alternate
                                        )

                                )

                            [1] => SimpleXMLElement Object
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => image/png
                                            [href] => http://a1.twimg.com/profile_images/343666442/My-ID-PB_normal.jpg
                                            [rel] => image
                                        )

                                )

                        )

                    [title] => Thousands of Phillies fans cannot drown out dozens or hundreds of Yankee / Jeter fans. #FAIL

#YANKEES #MLB #Phillies
                    [content] => Thousands of Phillies fans cannot drown out dozens or hundreds of Yankee / Jeter fans. <a href="http://search.twitter.com/search?q=%23FAIL">#FAIL</a>

<a href="http://search.twitter.com/search?q=%23YANKEES">#<b>YANKEES</b></a> <a href="http://search.twitter.com/search?q=%23MLB">#MLB</a> <a href="http://search.twitter.com/search?q=%23Phillies">#Phillies</a>
                    [updated] => 2009-11-02T03:37:37Z
                    [author] => SimpleXMLElement Object
                        (
                            [name] => sathomas (GreatÉ ScottÉ.)
                            [uri] => http://twitter.com/sathomas
                        )

                )	
	
This output might seem a bit overwhelming at first so let's go through it.. At the very first level, we have a "SimpleXML Object" which is what "simplexml_load_string" and it is saved in $twitterxml. This object has several attributes, defined by "[xxxx]", such as id, link, title and so on. As we learned by looking at the source code of the page we got back from Twitter, we know that we want the "entry" attribute. Looking through the data structure, we see that it is an array and each of the index numbers is a distinct entry. We can pull out and display all of the entry titles like this:
        $twitterdata = file_get_contents("http://search.twitter.com/search.atom?q=yankees");
        $twitterxml = simplexml_load_string($twitterdata);
        //print_r($twitterxml);

        $titles = array();

        for ($i = 0; $i < sizeof($twitterxml->entry); $i++)
        {
                //print_r($twitterxml->entry[$i]);
                $current_entry = $twitterxml->entry[$i];
                echo($current_entry->title . "<br />\n");

                // Put it in our array
                $titles[$i] = $current_entry->title;
        }
	
which outputs:
starts chant LETS GO YANKEES *CLAP, CLAP,CLAP*<br />
RT @philliesnation A-Rod, Teixeira, Posada, Cano, Cabrera are 7-for-62. .113 BA. And the Yankees are 9 outs away from being up 3-1 // now 6<br />
Let's go Bombers, put up a crooked number. GO YANKEES!<br />
Can the Yankees bullpen hold of the phillies.. They better!<br />
If the Yankees win tonight, that's it.  End of series.  #MercyRule<br />
#Yankees sure could use an insurance run (or 5)...<br />
I want the yankees to lose more than anything right now.<br />
goo yankees!!!!!!!!!!! world series<br />
Hey @djprostyle YANKEES HOMIEEE! ( #followDjProstyle live Ý http://ustre.am/5zBV)<br />
Let's Go Yankees!!!<br />
watching the World Series! Goooooo YANKEES!<br />
Yankees take 4-2 lead after 6 innings in Game 4 
 (AP) http://bit.ly/4FAvf<br />
watching the yankees hold onto the lead. Should be 4-2 but I guess a bad call doesn't get challenged in this game.<br />
@sexymimi23 CC did good, Yankees are almost there<br />
Utley would do his team well to share whatever magic he has against CC.  Probably can't formulate a sentence though.  #Yankees>#Phillies<br />
Combining this with our AJAX example above yields a page which always displays the latest from twitter for a particular keyword:
<html>
	<head>
		<title>AJAX Example</title>
		<!-- Load up the AJAX External JavaScript file -->
		<script language="JavaScript" src="ajax.js" />

		<!-- Local Javascript Code -->
		<script language="JavaScript">

			// A variable to hold the an interval
			// Global in scope
			var interval = null;	
	
			// A function to call a text file up from the server via ajax
			function call_ajax()
			{
				makeHttpRequest('twitter.php',ajax_return);
			}

			// A function that gets called when ajax returns, asynchronously
			function ajax_return(response)
			{
				// Just putting the content of the text file into the "messages" div on the page
				document.getElementById("messages").innerHTML = response;
				
				// Set the timeout again to make it keep going
				interval = setTimeout("call_ajax()",5000);				
			}
	
			// Setup AJAX function, creates a timeout so that we run something periodically
			function setup_ajax()
			{
				// Set interval of 5000 milliseconds
				// Keeps going...
				//interval = setInterval("call_ajax()",5000);

				// Only happens once..
				interval = setTimeout("call_ajax()",5000);
			}			
		
			// Register setup_ajax with the onload event of the window (when it is done loading)..	
			window.onload = setup_ajax;

		</script>
	</head>
	<body>
		<b>Looky here!</b>
		<div id="messages" style="overflow: auto; width: 500px; height: 400px;">
			Something should pop up here..
		</div>
	</body>
</html>	
Try it

Flickr

Flickr is a bit more difficult than Twitter but it's worthwhile!

First of all, you need to apply for an API key so that your requests are unique to you: http://www.flickr.com/services/api/keys/

Here are a couple of pages for your reference:

Overview: http://www.flickr.com/services/api/misc.overview.html
API: http://www.flickr.com/services/api/
REST: http://www.flickr.com/services/api/request.rest.html
Example requests:
http://api.flickr.com/services/rest/?method=flickr.test.echo&name=value
http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=0b1af17a814c2e2bb33436b52b6cca31&tags=yankees

Response:
	<rsp stat="ok">
<photos page="1" pages="1262" perpage="100" total="126128">
<photo id="4062990559" owner="22288367@N03" secret="0f435d5412" server="2644" farm="3" title="IMG_4318" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="4062994973" owner="22288367@N03" secret="f6a04f7593" server="3521" farm="4" title="IMG_4366" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="4062995163" owner="22288367@N03" secret="f038e43662" server="2504" farm="3" title="IMG_4370" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="4062987207" owner="22288367@N03" secret="f8338c86bf" server="2802" farm="3" title="IMG_4280" ispublic="1" isfriend="0" isfamily="0"/>
<photo id="4062986357" owner="22288367@N03" secret="ca35024350" server="3490" farm="4" title="IMG_4369" ispublic="1" isfriend="0" isfamily="0"/>
</photos>
</rsp>
	
Parsing this is pretty straight forward:
        $flickr_key = "xxxxxxx";
        $flickr_data = file_get_contents("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=" . $flickr_key . "&tags=yankees");
        $flickr_xml = simplexml_load_string($flickr_data);
        //print_r($flickr_xml);

        $pictures = array();

        for ($i = 0; $i < sizeof($flickr_xml->photos->photo); $i++)
        {
                //print_r($twitterxml->entry[$i]);
                $current_photo = $flickr_xml->photos->photo[$i];
                if ($i == 0)
                {
                        print_r($current_photo);
                }
		}
Unfortunately, Flickr doesn't give us the actual URL for the photos. We have to construct it: http://www.flickr.com/services/api/misc.urls.html like this: http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}.jpg

So this:
	<photo id="4062990559" owner="22288367@N03" secret="0f435d5412" server="2644" farm="3" title="IMG_4318" ispublic="1" isfriend="0" isfamily="0"/>
Becomes this:
	http://farm3.static.flickr.com/2644/4062990559_0f435d5412.jpg
Here is a full example:
        $flickr_key = "xxxxxxx";
        $flickr_data = file_get_contents("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=" . $flickr_key . "&tags=yankees");
        $flickr_xml = simplexml_load_string($flickr_data);
        //print_r($flickr_xml);

        $pictures = array();

        for ($i = 0; $i < sizeof($flickr_xml->photos->photo); $i++)
        {
                //print_r($twitterxml->entry[$i]);
                $current_photo = $flickr_xml->photos->photo[$i];
                if ($i == 0)
                {
                        print_r($current_photo);
                }
                //echo($current_photo . "<br />\n");

                // Sub in the appropriate values and construct the url
                echo("<img src=\"http://farm" . $current_photo['farm'] . ".static.flickr.com/" . $current_photo['server'] . "/" . $current_photo['id'] . "_" . $current_photo['secret'] . ".jpg\" />");
        }
Try it