} } } return request } Let’s go through this document and look at what it does, starting with the first three lines, which simply set up an HTML document and display a heading.. After
Trang 1Example 18-2 urlpost.html
<html><head><title>Ajax Example</title>
</head><body><center />
<h1>Loading a web page into a DIV</h1>
<div id='info'>This sentence will be replaced</div>
<script>
params = "url=oreilly.com"
request = new ajaxRequest()
request.open("POST", "urlpost.php", true)
request.setRequestHeader("Content-type",
"application/x-www-form-urlencoded")
request.setRequestHeader("Content-length", params.length)
request.setRequestHeader("Connection", "close")
request.onreadystatechange = function()
{
if (this.readyState == 4)
{
if (this.status == 200)
{
if (this.responseText != null)
{
document.getElementById('info').innerHTML =
this.responseText
}
else alert("Ajax error: No data received")
}
else alert( "Ajax error: " + this.statusText)
}
}
request.send(params)
function ajaxRequest()
{
try
{
var request = new XMLHttpRequest()
}
catch(e1)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP")
}
catch(e2)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP")
}
catch(e3)
{
request = false
Trang 2}
}
}
return request
}
</script></body></html>
Let’s go through this document and look at what it does, starting with the first three lines, which simply set up an HTML document and display a heading The next line creates an HTML DIV tag with the ID “info”, containing the text “This sentence will
be replaced” by default Later on, the text returned from the Ajax call will be inserted here
The next six lines are required for making an HTTP POST Ajax request The first sets the variable params to a parameter=value pair, which is what we’ll send to the server Then the Ajax object request is created After this, the open method is called to set the object to make a POST request to geturl.php in asynchronous mode The last three lines
in this group set up headers that are required for the receiving server to know that a POST request is coming
The readyState property
Now we get to the nitty-gritty of an Ajax call, which all hangs on the readyState prop-erty The “asynchronous” aspect of Ajax allows the browser to keep accepting user input and changing the screen, while our program sets the onreadystatechange property
to call a function of our choice each time readyState changes In this case, a nameless (or anonymous) inline function has been used, as opposed to a separate, named
func-tion This type of function is known as a callback function, as it is called back each time
readyState changes
The syntax to set up the callback function using an inline, anonymous function is as follows:
request.onreadystatechange = function()
{
if (this.readyState == 4)
{
// do something
}
}
If you wish to use a separate, named function, the syntax is slightly different:
request.onreadystatechange = ajaxCallback
function ajaxCallback()
{
if (this.readyState == 4)
{
// do something
}
}
Trang 3Looking at Table 18-1, you’ll see that readyState can have five different values But only one of them concerns us: value 4, which represents a completed Ajax call There-fore, each time the new function gets called, it returns without doing anything until readyState has a value of 4 When our function detects that value, it next inspects the status of the call to ensure it has a value of 200, which means that the call succeeded
If it’s not 200, an alert pop up is displayed containing the error message contained in statusText
You will notice that all of these object properties are referenced using
this.readyState , this.status, and so on, rather than the object’s
cur-rent name, request , as in request.readyState or request.status This is
so that you can easily copy and paste the code and it will work with any
object name, because the this keyword always refers to the current
object.
So, having ascertained that the readyState is 4 and the status is 200, the responseText value is tested to see whether it contains a value If not, an error message is displayed
in an alert box Otherwise, the inner HTML of the DIV is assigned the value of responseText, like this:
document.getElementById('info').innerHTML = this.responseText
What happens in this line is that the element “info” is referenced using the getElementByID method and then its innerHTML property is assigned the value that was returned by the Ajax call
After all this setting up and preparation, the Ajax request is finally sent to the server using the following command, which passes the parameters already defined in the var-iable params:
request.send(params)
After that, all the preceding code is activated each time readyState changes
The remainder of the document is the ajaxRequest method from Example 18-1, and the closing script and HTML tags
The server half of the Ajax process
Now we get to the PHP half of the equation, which you can see in Example 18-3 Type
it in and save it as urlpost.php.
Example 18-3 urlpost.php
<?php // urlpost.php
if (isset($_POST['url'])) {
echo file_get_contents("http://".SanitizeString($_POST['url']));
}
function SanitizeString($var) {
Trang 4$var = strip_tags($var);
$var = htmlentities($var);
return stripslashes($var);
}
?>
As you can see, this is short and sweet, and also makes use of the ever-important SanitizeString function, as should always be done with all posted data
What the program does is use the file_get_contents PHP function to load in the web page at the URL supplied to it in the POST variable $_POST['url'] The file_get_contents function is versatile, in that it loads in the entire contents of a file
or web page from either a local or a remote server—it even takes into account moved pages and other redirects
Once you have typed the program in, you are ready to call up urlpost.html into your web browser and, after a few seconds, you should see the contents of the oreilly.com
front page loaded into the DIV that we created for that purpose It won’t be as fast as directly loading the web page, because it is transferred twice: once to the server and again from the server to your browser The result should look like Figure 18-2
Figure 18-2 The oreilly.com front page has been loaded into a DIV
Trang 5Not only have we succeeded in making an Ajax call and having a response returned back to JavaScript, we also harnessed the power of PHP to enable the merging in of a totally unrelated web object Incidentally, if we had tried to find a way to fetch the
oreilly.com web page directly via Ajax (without recourse to the PHP server-side
mod-ule), we wouldn’t have succeeded, because there are security blocks preventing cross-domain Ajax So this little example also illustrates a handy solution to a very practical problem
Using GET Instead of POST
As with submitting any form data, you have the option of submitting your data in the form of GET requests, and you will save a few lines of code if you do so However, there
is a downside: some browsers may cache GET requests, whereas POST requests will never
be cached You don’t want to cache a request because the browser will just redisplay what it got last time instead of going to the server for fresh input The solution to this
is to use a workaround that adds a random parameter to each request, ensuring that each URL requested is unique
Example 18-4 shows how you would achieve the same result as with Example 18-2, but using an Ajax GET request instead of POST
Example 18-4 urlget.html
<html><head><title>Ajax GET Example</title>
</head><body><center />
<h1>Loading a web page into a DIV</h1>
<div id='info'>This sentence will be replaced</div>
<script>
nocache = "&nocache=" + Math.random() * 1000000
request = new ajaxRequest()
request.open("GET", "urlget.php?url=oreilly.com" + nocache, true)
request.onreadystatechange = function()
{
if (this.readyState == 4)
{
if (this.status == 200)
{
if (this.responseText != null)
{
document.getElementById('info').innerHTML =
this.responseText
}
else alert("Ajax error: No data received")
}
else alert( "Ajax error: " + this.statusText)
}
}
request.send(null)
Trang 6function ajaxRequest()
{
try
{
var request = new XMLHttpRequest()
}
catch(e1)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP")
}
catch(e2)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP")
}
catch(e3)
{
request = false
}
}
}
return request
}
</script></body></html>
The differences to note between the two documents are highlighted in bold, and are as follows:
• It is not necessary to send headers for a GET request
• The open method is called using a GET request, supplying a URL with a string comprising a ? symbol followed by the parameter/value pair url=oreilly.com
• A second parameter/value pair is started using an & symbol, followed by setting the value of the parameter nocache to a random value between 0 and a million This is used to ensure that each URL requested is different, and therefore that no requests will be cached
• The call to send now contains only a parameter of null as no parameters are being passed via a POST request Note that leaving the parameter out is not an option, as
it would result in an error
To accompany this new document, it is necessary to modify the PHP program to re-spond to a GET request, as in Example 18-5, urlget.php.
Example 18-5 urlget.php
<?php
if (isset($_GET['url'])) {
echo file_get_contents("http://".sanitizeString($_GET['url']));
}
Trang 7function sanitizeString($var) {
$var = strip_tags($var);
$var = htmlentities($var);
return stripslashes($var);
}
?>
All that’s different between this and Example 18-3 is that the references to $_POST have been replaced with $_GET The end result of calling up urlget.html in your browser is identical to loading in urlpost.html.
Sending XML Requests
Although the objects we’ve been creating are called XMLHttpRequest objects, so far we have made absolutely no use of XML This is where the Ajax term is a bit of a misnomer, because the technology actually allows you to request any type of textual data, only one of which is XML As you have seen, we have requested an entire HTML document via Ajax, but we could equally have asked for a text page, a string or number, or even spreadsheet data
So let’s modify the previous example document and PHP program to fetch some XML
data To do this, take a look at the PHP program first, xmlget.php, shown in Exam-ple 18-6
Example 18-6 xmlget.php
<?php
if (isset($_GET['url'])) {
header('Content-Type: text/xml');
echo file_get_contents("http://".sanitizeString($_GET['url']));
}
function sanitizeString($var) {
$var = strip_tags($var);
$var = htmlentities($var);
return stripslashes($var);
}
?>
This program has been very slightly modified (shown in bold highlighting) to first out-put the correct XML header before returning a fetched document No checking is made here, as it is assumed the calling Ajax will request an actual XML document
Now on to the HTML document, xmlget.html, shown in Example 18-7
Example 18-7 xmlget.html
<html><head><title>Ajax XML Example</title>
</head><body>
<h2>Loading XML content into a DIV</h2>
<div id='info'>This sentence will be replaced</div>
Trang 8nocache = "&nocache=" + Math.random() * 1000000
url = "rss.news.yahoo.com/rss/topstories"
request = new ajaxRequest()
request.open("GET", "xmlget.php?url=" + url + nocache, true)
out = "";
request.onreadystatechange = function()
{
if (this.readyState == 4)
{
if (this.status == 200)
{
if (this.responseXML != null)
{
titles = this.responseXML.getElementsByTagName('title') for (j = 0 ; j < titles.length ; ++j)
{
out += titles[j].childNodes[0].nodeValue + '<br />' }
document.getElementById('info').innerHTML = out
}
else alert("Ajax error: No data received")
}
else alert( "Ajax error: " + this.statusText)
}
}
request.send(null)
function ajaxRequest() {
try
{
var request = new XMLHttpRequest()
}
catch(e1)
{
try
{
request = new ActiveXObject("Msxml2.XMLHTTP")
}
catch(e2)
{
try
{
request = new ActiveXObject("Microsoft.XMLHTTP") }
catch(e3)
{
request = false
}
}
}
Trang 9return request
}
</script></body></html>
Again, the differences have been highlighted in bold, so you can see that this code is substantially similar to previous versions, except that the URL now being requested,
rss.news.yahoo.com/rss/topstories, contains an XML document, the Yahoo! News Top
Stories feed
The other big change is the use of the responseXML property, which replaces the responseText property Whenever a server returns XML data, responseText will return
a null value, and responseXML will contain the XML returned instead
However, responseXML doesn’t simply contain a string of XML text: it is actually a complete XML document object that can be examined and parsed using DOM tree methods and properties This means it is accessible, for example, by the JavaScript getElementsByTagName method
About XML
An XML document will generally take the form of the RSS feed shown in Exam-ple 18-8 However, the beauty of XML is that this type of structure can be stored in-ternally in a DOM tree (see Figure 18-3) to make it quickly searchable
Figure 18-3 The DOM tree of Example 18-8
Example 18-8 An XML document
<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
<channel>
<title>RSS Feed</title>
Trang 10<link>http://website.com</link>
<description>website.com's RSS Feed</description>
<pubDate>Mon, 16 May 2011 00:00:00 GMT</pubDate>
<item>
<title>Headline</title>
<guid>http://website.com/headline</guid>
<description>This is a headline</description>
</item>
<item>
<title>Headline 2</title>
<guid>http://website.com/headline2</guid>
<description>The 2nd headline</description>
</item>
</channel>
</rss>
Therefore, using the getElementsByTagName method, you can quickly extract the values associated with various tags without a lot of string searching This is exactly what we
do in Example 18-7, where the following command is issued:
titles = this.responseXML.getElementsByTagName('title')
This single command has the effect of placing all the values of the “title” elements into the array titles From there, it is a simple matter to extract them with the following expression (where j is the title to access):
titles[j].childNodes[0].nodeValue
All the titles are then appended to the string variable out and, once all have been pro-cessed, the result is inserted into the empty DIV at the document start When you call
up xmlget.html in your browser, the result will be something like Figure 18-4
Figure 18-4 Fetching a Yahoo! XML news feed via Ajax