PHP DevCenter
oreilly.comSafari Books Online.Conferences.

advertisement


Migrating Web-Based PHP Applications to Ajax

by Bill Lubanovic
05/10/2007

Web development is messy. Over the years, our toolbox has filled up with odd implements that are hard to use and don't fit well together. Web code has become a legacy problem. A typical web page is a tangle of HTML, JavaScript, and server-side scripts. User interface logic is interwoven with business rules and client-server communications. In most programming environments, we use documented APIs, so you just pass arguments to a function and get back the results. In the web environment, we've typically needed hacks like populating hidden fields in a form, and regenerating the whole page, even for a tiny change. Can we make the process more rational?

This article describes a makeover of a typical database-backed web form. We'll show some old code – a mixture of HTML, JavaScript, and PHP – and rebuild it with modern web techniques like Ajax, and modern tools like jQuery. The benefits will include:

  • Separating dynamic content from static content.
  • Separating content, style, and processing.
  • Web client-server communication via function calls.
  • Partial page updates instead of flash-bang page reloads.
  • Faster development and more maintainable code.
  • Faster load times and improved caching.

The Old Grey Web

In the beginning was HTML, shortly followed by forms, client-side JavaScript, and server-side CGI scripts. You would fill in form variables and submit the form to the CGI script, or generate a long GET-style URL in JavaScript. JavaScript was close to undebuggable. Core variables like window were not part of the language, and the Microsoft-Netscape browser wars introduced gratuitous differences that continue to plague us. Things got a little better over time, as the W3C defined the DOM and developers built cross-platform DHTML libraries.

Some dynamic pages are easy, you query the database once and dump some nicely formatted HTML, but most are harder. Database values populate pull-down menus (HTML select and option tags) and choices (radio and checkbox tags). Some forms cover multiple pages, and the logic for maintaining overall state gets trickier. Every form submission returns a fully regenerated page, maintaining all the state of the previous submissions.

Traditional options on how to structure the application include:

  • Put everything in a single script. On the first call, query the database and generate HTML and form elements. On subsequent calls, the form passes a command (such as add, change, or delete) and any arguments (such as the person's ID, if change or delete). The script modifies the database and again rewrites the page's content. The form elements must reflect the database changes.
  • Use two scripts. The first queries the database and generates the HTML, with two differences from the previous example:
    • The form has an iframe for displaying dynamic contents.
    • The form's action is the second script.
    • The form's target is the name of the iframe.
    Now the form is generated once and its elements maintain their values across form submissions. The output of the second script is displayed in the iframe.

The second option sounds better, but it still has problems: if an action changed the data underlying the form elements in the enclosing page, the whole page needs to be regenerated. We need a third option.

The New Toolbox

The common restriction is the whole-page design. No matter what you do, no matter how small the change, you submit it to the server and get back a brand new page (an iframe is like a mini-page, and its size can't be changed). A variety of JavaScript remoting techniques have tried to make the web client-server connection work more like a procedure call. I think the most useful contributions are:

  • innerHTML
  • XMLHttpRequest
  • Ajax
  • JSON
  • New JavaScript libraries
innerHTML
This DOM attribute, introduced by Microsoft in IE4, is a de facto (not official W3C) standard supported by all modern browsers. With it, you get and set the contents between any HTML start and end tags, without a page refresh. This chunk of HTML:
<p id="changeme">Now you see it.</p>
can be modified by this chunk of JavaScript:
var obj = document.getElementById("changeme");
obj.innerHTML = "Now you don't";
to produce this:
<p id="changeme">Now you don't</p>
Although the DOM has functions to change page elements dynamically, innerHTML is simpler and faster. Unfortunately, innerHTML is a read-only attribute for many table elements in IE, forcing use of alternatives.
 
XMLHttpRequest
This is an API to send client requests to the server and receive the server responses. Microsoft invented it to make Outlook Web Access work more like a desktop application. It was included in IE5 and is supported by all modern browsers. Combined with innerHTML, you can call a server script and use the data returned to update any element on the page. Despite its utility, this function was hidden in plain sight for years (you wouldn't find it in JavaScript or DHTML books). Things changed when Google Mail, Maps, and Suggest demonstrated its responsiveness and introduced a new web application model.
 
Ajax
The dam burst in 2005, when Jesse James Garrett named the new model Ajax (Asynchronous JavaScript and XML), comprising XMLHttpRequest, the DOM, and other techniques. The brand and its timing were perfect, rejuvenating web development and rehabilitating JavaScript.
 
JSON
The old remoting frameworks used various formats for the client-server data stream, and XMLHttpRequest, as the name suggested, used XML. Doug Crockford designed the light and simple JSON (JavaScript Object Notation) format. It's trivial to parse JSON into JavaScript data structures (just eval(json_string)), and faster than deconstructing XML.
 
JavaScript libraries
High-quality JavaScript libraries have been developed to simplify new-model web development and bridge the inevitable cross-browser issues. I've chosen John Resig's jQuery over worthy competitors like Prototype, Dojo, or YUI for a number of reasons:
  • Compactness: About 19KB compressed
  • Chainability: Calls can be chained for more compact code
  • Support: Good documentation and development community
  • Flexibility: Its selector syntax includes CSS 1-3 and XPath phrases to select page elements
  • Architecture: Easy to extend through add-ons and plugins

The Makeover

History class is over, and beauty class begins.

To make the presentation clear and short, our code examples ignore errors and possible security issues. The purpose is to show how jQuery and Ajax techniques can improve an old script. For production use, you would check function error returns, untaint input data, and follow the other rules of good web hygiene. With the new Ajax methods, an error in the client or server code can cause a silent failure. FireBug is a very handy tool for developing and debugging Ajax applications. The full-featured version is a Firefox plugin, but a light version is available for IE and other browsers.

Let's define our form's requirements:

  1. Get data from a people table in a database. The id column is the primary key.
  2. Display the names in a pull-down menu (a form select element).
  3. Let the user select a person from the menu.
  4. Display information about that person in a table: first name, last name, favorite dance, and favorite pie.

This example assumes the number of people will fit in an HTML select element without killing the browser. Larger data would require a paged table or something similar. The page should look something like this:


People

First Name First Name Dance Pie
Alfredo de Darc tango blueberry

Version 1: Original Code

In the original version we do everything in a single PHP script: write the static HTML, create the original list of people, and fill in the lower table if a person had been selected.

people1.php:
<?php
$cmd    = @$_REQUEST["cmd"];
$id     = @$_REQUEST["id"];
mysql_connect($server, $user, $password);
mysql_select_db("test");
?>
<html>
<head><title>Old Form</title>
<script>
// Get the selected user and retrieve his/her info
function user_info(sel)
        {
        var opt    = sel.options;
        var user_id    = opt[sel.selectedIndex].value;
        // Construct a GET URL, or create a hidden field for "cmd"
        var url  =  "people1.php?cmd=info&id=" + user_id;
        window.location.href = url;
        }
</script>
</head>
<body>
<form action="people1.php" method="post">
People<br>
<select name="people" onchange="user_info(this)">
<option value="">(select a person)
<?php
// Get all users and display every time script is called
$result = mysql_query("select id, fname, lname from people");
while ($row = mysql_fetch_array($result, MYSQL_ASSOC))
        echo "<option value='$row[id]'",
                $row["id"] == $id ? " selected" : "",
                ">$row[fname] $row[lname]\n";
?>
</select>
<?php
if ($cmd == "info")
        {
    $id     = mysql_real_escape_string($id);
        $result = mysql_query("select * from people where id='$id'");
        $info = mysql_fetch_array($result, MYSQL_ASSOC);
        }
else
        $info = array("fname"=>" ", "lname"=>" ", "dance"=>" ", "pie"=>" ");
echo <<< END
<br>
<table border=1>
<tr>
<td>First Name</td><td>Last Name</td><td>Dance</td><td>Pie</td></tr>
<tr>
<td>$info[fname]</td>
<td>$info[lname]</td>
<td>$info[dance]</td>
<td>$info[pie]</td>
</tr>
</table>

END;
?>
</form>
</body>
</html>

This isn't too hard to write or understand, but it already has problems. The good news is that the code is all in the same place. The bad news is the same as the good news.

Pages: 1, 2

Next Pagearrow




Valuable Online Certification Training

Online Certification for Your Career
Earn a Certificate for Professional Development from the University of Illinois Office of Continuing Education upon completion of each online certificate program.

PHP/SQL Programming Certificate — The PHP/SQL Programming Certificate series is comprised of four courses covering beginning to advanced PHP programming, beginning to advanced database programming using the SQL language, database theory, and integrated Web 2.0 programming using PHP and SQL on the Unix/Linux mySQL platform.

Enroll today!


Sponsored by: