Home > Articles > Programming > PHP

📄 Contents

  1. What is Ajax?
  2. Fundamental Ajax
  3. Adding Ajax Elements to Earlier Projects
  4. For More Information
This chapter is from the book

Adding Ajax Elements to Earlier Projects

None of the projects in Part V of this book, “Building Practical PHP and MySQL Projects,” are Ajax-enabled out of the box. Each project consists of a series of form submissions and page reloads. Although the pages contain dynamic elements, none are of the streamlined user experience we expect in the era of Web 2.0.

However, including Ajax elements in these projects would have shifted the focus away from the basics of creating web applications with PHP and MySQL. In other words, you have to learn to walk before you can run. But now that you know how to run—or at least jog a little—you can begin to think about modifying elements of these applications to include Ajax, or you can begin to think about including Ajax elements in new applications you might create.

The thought process of the Ajax developer goes something like this: What are the distinct user actions, and what page events will invoke those actions? For example, do you want your users always to press a button element to submit a form and move on to the next step, or can simply changing the focus on a form element (text field, option button, check box) invoke an asynchronous request to the web server? After you decide the types of actions you want to include, you can begin writing the JavaScript functions that invoke PHP scripts that handle the request to and result from the server.

In the following sections you’ll add some Ajax elements to existing scripts created previously in this book.

Adding Ajax Elements to PHPbookmark

In Chapter 27, “Building User Authentication and Personalization,” you created an application called PHPbookmark. This application requires user registration and login before saving bookmarks and getting recommendations for bookmarks you might like that have been saved by other users.

Because this application is already created and consists of several tightly connected PHP scripts and libraries of functions, the first step is to think of how to add additional files into the mix—whether they are style sheets, JavaScript functions, or PHP to handle actions on the server side. The answer is simple: create a separate file for styles and a separate file for all JavaScript functions. Then add a snippet of code to the existing PHP scripts from Chapter 27 to include these external files, when necessary, and the invocation of the JavaScript functions themselves. Any additional PHP scripts you create will also be kept separate from the existing application files.

After determining how to manage your new files, it’s time to determine which user functions can get the Ajax treatment. Although the user registration and login portion of the application could be a prime candidate for becoming Ajax-enabled, in the interest of space we have selected the functionality surrounding adding and editing the bookmarks stored by the user.

You will also make changes to the existing application files. It’s a good idea to copy the files from Chapter 27 into a new directory for use with this chapter; any changes you make will then be uploaded into this new directory rather than a working version of PHPbookmark you might already have installed.

Creating Additional Files

As mentioned previously, you will add new files into the existing application structure. Although you will fill in these files as you go through the sections that follow, it is a good idea to get your bearings before you continue.

Assume you will have at least two new files: a style sheet and a library of JavaScript functions. Create these two files now; call them new_ss.css and new_ajax.js. The new style sheet (new_ss.css) can be empty, because we haven’t yet defined new styles, but the new_ajax.js file should contain the getXMLHTTPRequest() function you created earlier in the chapter to create a new instance of the XMLHTTPRequest object in all browsers. Although you will be adding to these files, you can upload them as is to your web server at this time.

The next step is to add a link to both these files in one of the existing display functions for the PHPbookmark application. Doing so will ensure that the styles from the style sheet are always available, as are the functions from the JavaScript library. If you recall from Chapter 27, the function that controls the output of the head element of the HTML (among other things) is called do_html_header(), and it resides in the output_fns.php file.

A new version of this function is shown in Listing 34.4.

Listing 34.4 Amended Version of do_html_header() Containing Links to the New Style Sheet and JavaScript Function Libraries

function do_html_header($title) { 
 // print an HTML header
?>
 <html>
 <head>
  <title><?php echo $title;?></title>
  <style>
   body { font-family: Arial, Helvetica, sans-serif; font-size: 13px; } 
   li, td { font-family: Arial, Helvetica, sans-serif; font-size: 13px; } 
   hr { color: #3333cc; } 
   a { color: #000000; } 
  </style>

  <link rel="stylesheet" type="text/css" href="new_ss.css"/>
  <script src="new_ajax.js" type="text/javascript"></script>

 </head>
 <body>
 <img src="bookmark.gif" alt="PHPbookmark logo" border="0"
    align="left" valign="bottom" height="55" width="57" />
 <h1>PHPbookmark</h1>
 <hr />
<?php
 if($title) { 
  do_html_heading($title);
 } 
} 

If you upload the new style sheet, the JavaScript functions library, the output_fns.php file, and open any page in the PHPbookmark system, the new files should be included without error. Next, you’ll actually put additional styles and scripts into these files and create some Ajax functionality.

Adding Bookmarks the Ajax Way

Currently, adding a bookmark occurs when a user enters the bookmark URL and presses the form submission button. The act of pressing the form submission button invokes another PHP script, which adds the bookmark, returns the user to the list of bookmarks, and shows that the new bookmark has been added. In other words, pages are reloaded.

The Ajax way is to present the form for adding a bookmark, but instead of the form submission button requiring more page loads, it invokes a JavaScript function in the background that calls a PHP script to add the item to the database and return the response to the user—all without leaving the page that has already been loaded. This new functionality first requires a change to the display_add_bm_form() function in output_fns.php.

Listing 34.5 shows the amended function. We have removed the form action, added an id value to the input field, and changed the attributes of the button element. We have also added a call to the getXMLHTTPRequest() JavaScript function.

Listing 34.5 Amended Version of display_add_bm_form()

function display_add_bm_form() { 
 // display the form for people to enter a new bookmark in
?>
<script type="text/javascript">
var myReq = getXMLHTTPRequest();
</script>
<form>
<table width="250" cellpadding="2" cellspacing="0" bgcolor="#cccccc">
<tr><td>New BM:</td>
<td><input type="text" name="new_url" name="new_url" value="http://"
   size="30" maxlength="255"/></td></tr>
<tr><td colspan="2" align="center">
  <input type="button" value="Add bookmark" 
      onClick=" javascript:addNewBookmark();"/></td></tr>
</table>
</form>
<?php
} 

Take a closer look at the button element:

<input type="button" value="Add bookmark" 
     onClick=" javascript:addNewBookmark();"/>

When the button is clicked, the onClick event handler invokes the addNewBookmark() JavaScript function. This function makes a request to the server, specifically to a PHP script that attempts to insert the record into the database. The code for this function is found in Listing 34.6.

Listing 34.6 The JavaScript Function addNewBookmark()

function addNewBookmark() { 
 var url = "add_bms.php";
 var params = "new_url=" + encodeURI(document.getElementById('new_url').value);
 myReq.open("POST", url, true);
 myReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
 myReq.setRequestHeader("Content-length", params.length);
 myReq.setRequestHeader("Connection", "close");
 myReq.onreadystatechange = addBMResponse;
 myReq.send(params);
} 

This function should look similar to the getServerTime() function used earlier in this chapter. The process is quite similar: create variables, send the data to a PHP script, and invoke a function to handle the response from the server.

The following line creates a name/value pair from the name of the form field and the value entered by the user:

var params = "new_url=" + encodeURI(document.getElementById('new_url').value);

The value of params is then sent to the back-end PHP script in the last line of the function:

myReq.send(params);

Before the values are sent, three request headers are also sent so that the server knows how to handle the data sent in the POST request:

myReq.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
myReq.setRequestHeader("Content-length", params.length);
myReq.setRequestHeader("Connection", "close");

The next step in this process is to create the JavaScript function to handle the server response; we have called this addBMResponse:

myReq.onreadystatechange = addBMResponse;

Again, this code is similar to the theHTTPResponse function created earlier in the chapter. The code for addBMResponse is seen in Listing 34.7.

Listing 34.7 The JavaScript Function addBMResponse()

function addBMResponse() { 
 if (myReq.readyState == 4) { 
  if(myReq.status == 200) { 
    result = myReq.responseText;
    document.getElementById('displayresult').innerHTML = result;
  } else { 
   alert('There was a problem with the request.');
  } 
 } 
} 

This JavaScript function first checks the state of the object; if it has completed its process, it next checks that the response code from the server was 200 (OK). If the response code is not 200, an alert is shown with the words “There was a problem with the request.” Any other responses will come from the execution of the add_bms.php script and will be displayed in a div with an id value of displayresult. For the moment, the displayresult id is defined in the new_ss.css style sheet as follows (a white background):

#displayresult { 
  background: #fff;
} 

The following line of code has been added after the closing form tag in the PHP function display_add_bm_form(); this is the div in which the result from the server will be displayed to the user.

<div id="displayresult"></div>

Next, you will have to make modifications to the existing add_bms.php code.

Additional Modifications to Existing Code

If you were to attempt to add a bookmark without modifying anything in the add_bms.php script, the actual process of checking user permissions and adding a bookmark would work just fine. However, the result would be the monstrosity seen in Figure 34.4, which includes the duplication of the title, logo, and footer links, as well as other issues with the application display.

Figure 34.4

Figure 34.4 Adding a bookmark before editing the add_bms.php script.

In the non-Ajax version of the PHPbookmark application, remember that the form is one page, the submission result is another, and all page elements are reloaded at all times. However, in this Ajax-enabled environment, you want to add a new bookmark, get the result from the server, and continue on to add more bookmarks (or not) without reloading any page elements. This new functionality necessitates some changes to the add_bms.php code. The original code is shown in Listing 34.8.

Listing 34.8 The Original PHP Code in add_bms.php

<?php
 require_once('bookmark_fns.php');
 session_start();

 //create short variable name
 $new_url = $_POST['new_url'];

 do_html_header('Adding bookmarks');

 try { 
  check_valid_user();
  if (!filled_out($_POST)) { 
   throw new Exception('Form not completely filled out.');
  } 
  // check URL format
  if (strstr($new_url, 'http://') === false) { 
    $new_url = 'http://'.$new_url;
  } 

  // check URL is valid
  if (!(@fopen($new_url, 'r'))) { 
   throw new Exception('Not a valid URL.');
  } 

  // try to add bm
  add_bm($new_url);
  echo 'Bookmark added.';

  // get the bookmarks this user has saved
  if ($url_array = get_user_urls($_SESSION['valid_user'])) { 
   display_user_urls($url_array);
  } 
 } 
 catch (Exception $e) { 
  echo $e->getMessage();
 } 
 display_user_menu();
 do_html_footer();
?>

The first line of the script brings all the items of the bookmark_fns.php file into play. If you look at the contents of bookmark_fns.php you will notice that it calls yet another series of files:

<?php
 // We can include this file in all our files
 // this way, every file will contain all our functions and exceptions
 require_once('data_valid_fns.php'); 
 require_once('db_fns.php');
 require_once('user_auth_fns.php');
 require_once('output_fns.php');
 require_once('url_fns.php');
?>

Although you may or may not need all the items in these files in the Ajax-enabled version of the bookmark addition sequence, the comment at the beginning says it all—every file will contain all our functions and exceptions. In this situation, as you are moving from a series of dynamic pages to all-in-one Ajax-enabled functionality, it is better to have a few extra elements than to remove core functionality before you are sure you don’t need it. Keep the first line of add_bms.php as is.

The second line, which begins or continues a user session, should also remain as is; even in the Ajax-enabled version of this action you will want some sense of security intact. Similarly, the third line can remain as well. This line gives the shortname $new_url to the POST value sent through the request:

$new_url = $_POST['new_url'];

Finally, you are at the point in which you can remove something, namely this line:

do_html_header('Adding bookmarks');

Because you are already on a page (add_bm_form.php) that contains HTML header information, there is no need to repeat it again—you’re not moving to a different page. This repetition produces the two sets of header graphics and titles that you see in Figure 34.4. For similar reasons, you can eliminate two lines at the end of add_bms.php as well:

display_user_menu();
do_html_footer();

If you remove these elements, upload the file to the server, and attempt to add another bookmark, the results will be closer to what you expect, although there are still some changes to be made. Figure 34.5 shows the application display with changes made in the code to this point.

We still have a duplicate message regarding the status of the user as “logged in,” but the issues are not nearly as unappealing as before. The next step is to remove the duplicate messages and to change some of the other exceptions-related functionality so that it makes sense in an Ajax-environment.

Figure 34.5

Figure 34.5 Adding a bookmark after the first pass of editing the add_bms.php script.

To remove the duplicate message regarding the user’s login name, delete this line from add_bms.php:

check_valid_user();

The check for valid user will have already been done when the add_bms_form.php page was loaded; you wouldn’t be on the page that invokes Ajax functionality if you weren’t found to be a valid user.

The next step is to remove the outer try block and the exception handling. The reason for this is because you want the script to get to the end in which the list of URLs already stored is displayed for the user. This means some adjustments will be made along the way to reintroduce error text as necessary. Listing 34.9 shows an amended version of add_bms.php.

Listing 34.9 An Amended Version of add_bms.php

<?php
 require_once('bookmark_fns.php');
 session_start();

 //create short variable name
 $new_url = $_POST['new_url'];

 //check that form has been completed
 if (!filled_out($_POST)) { 
  //has not
  echo "<p class=\ "warn\ ">Form not completely filled out.</p>";
 } else { 
  // has; check and fix URL format if necessary
  if (strstr($new_url, 'http://') === false) { 
    $new_url = 'http://'.$new_url;
  } 

  // continue on to check URL is valid
  if (!(@fopen($new_url, 'r'))) { 
   echo "<p class=\ "warn\ ">Not a valid URL.</p>";
  } else { 
   //it is valid, so continue to add it
   add_bm($new_url);
   echo "<p>Bookmark added.</p>";
  } 
 } 
 // regardless of the status of the current request
 // get the bookmarks this user has already saved
 if ($url_array = get_user_urls($_SESSION['valid_user'])) { 
  display_user_urls($url_array);
 } 
?>

This version of the script still follows a logical path through possible events, but displays an appropriate error message without duplicating any other page elements.

The first check is whether the form itself has been filled out. If it has not, an error message is displayed between the addition form and the user’s current list of stored bookmarks. You can see this response in Figure 34.6.

The second check is whether the URL is properly formed; if it is not, the string is transformed into a proper URL and moves on to the next step. In the next step, a socket is opened and the URL is tested for validity. If it fails, an error message is displayed between the addition form and the user’s current list of stored bookmarks. However, if the URL is valid, it is added to the user’s existing list of stored URLs. In Figure 34.7 you can see the response when attempting to add an invalid URL.

Figure 34.6

Figure 34.6 Attempting to add a blank value.

Figure 34.7

Figure 34.7 Attempting to add an invalid URL.

Finally, and regardless of the errors in attempting to add a URL, the user’s existing bookmarks are displayed. You can see this result in Figure 34.8.

Figure 34.8

Figure 34.8 Success—a valid URL has been added.

Although the core functionality around adding a bookmark has been successfully Ajax-enabled, a few elements still need some work. For instance, the add_bm() function in the url_fns.php file contains some exceptions that could be handled differently to produce an error message in this new system. Listing 34.10 shows the existing add_bm() function.

Listing 34.10 Existing add_bm() Function in url_fns.php

function add_bm($new_url) { 
 // Add new bookmark to the database

 echo "Attempting to add ".htmlspecialchars($new_url)."<br />";
 $valid_user = $_SESSION['valid_user'];

 $conn = db_connect();

 // check not a repeat bookmark
 $result = $conn->query("select * from bookmark
             where username='$valid_user'
             and bm_URL='".$new_url."'");
 if ($result && ($result->num_rows>0)) { 
  throw new Exception('Bookmark already exists.');
 } 

 // insert the new bookmark
 if (!$conn->query("insert into bookmark values
   ('".$valid_user."', '".$new_url."')")) { 
  throw new Exception('Bookmark could not be inserted.');
 } 

 return true;
} 

In this situation, all we want to do is change the exceptions to produce error messages and continue the processing (display). This can be done by changing the two distinct if blocks to the following:

if ($result && ($result->num_rows>0)) { 
 echo "<p class=\ "warn\ ">Bookmark already exists.</p>";
} else { 
 //attempt to add
 if (!$conn->query("insert into bookmark values
  ('".$valid_user."', '".$new_url."')")) { 
  echo "<p class=\ "warn\ ">Bookmark could not be inserted.</p>";
 } else { 
  echo "<p>Bookmark added.</p>";
 } 
} 

This version of the script still follows a logical path through possible events and displays appropriate error messages. After checking to see whether the bookmark already exists for the user, either an error message is displayed between the addition form and the user’s current list of stored bookmarks, or the script attempts to add the bookmark.

If the bookmark cannot be added, again an error message is displayed between the addition form and the user’s current list of stored bookmarks. However, if the bookmark is successfully added, the message “Bookmark added” is displayed. This echo statement has been removed from the add_bm.php script and put in this position in the add_bm() function because otherwise the user could have seen an error message such as “Bookmark could not be inserted” followed by a success message of “Bookmark added,” even though the outcome was not successful.

Figure 34.9 shows the result of these changes.

Figure 34.9

Figure 34.9 Attempting to add a bookmark that already exists.

Additional Changes to PHPbookmark

Changing the bookmark addition functionality to an Ajax-enabled user interface is just the first of many changes you could make to this application. The next logical choice might be the bookmark deletion functionality. The process might go something like this:

  • Remove the Delete BM link from the page footer.
  • Invoke a new JavaScript function when the user checks the Delete? check box next to a bookmark.
  • Modify the delete_bm.php script so that it can be invoked by the new JavaScript function, complete the deletion process, and return a message to the user.
  • Make any additional modifications to the functionality to ensure that actions occur and messages are displayed appropriately within the new user interface.

With the structure already in place for these changes, you should be able to make them just with the information provided in this chapter. However, the following sections provide links to resources containing much more information on creating Ajax-enabled sites.

Remember, Ajax is a set of technologies that work together to create a more fluid user experience; this often necessitates rethinking an application from the ground up now that you know what you can do when all the puzzle pieces fall into place.

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020