Introduction
This is the final project for the semester. It is open–ended: there is not enough time for you to complete the entire application, but it is structured as a sequence of steps that will take you as close to the complete project as you have time for. At each step, you will add a feature to your project. You will not receive credit for partially completing a feature, but after the first few mandatory components are working, you may implement additional features in any sequence that works for you. Just be sure each feature is completely tested and working before moving on to another feature.
Each time you complete work on a feature, make a backup copy of your complete web site. At the end, discard any work you did on an incomplete feature, and restore your last backup to your My Website directory.
Project Description
The overall goal of the project is to provide a mechanism for people to submit applications to serve on Academic Senate Committees at Queens College. You have already seen that your database has a table for people, containing their QC email address, first name, and last name. This table also has columns for information about the person: how to contact them, whether they are a student, faculty member, or graduate student, and what department they are affiliated with. For faculty, the departmental affiliation is the academic department they are a member of; for students, the department depends on their major.
The purpose of this assignment is to provide a means for people to enter or update the information about themselves in preparation for filling out an application for membership on Senate committees. The project uses the "login or register" model: to use the site, users must either login using their QC email and password or register with the site so they can then log in. The site must work with JavaScript disabled, but if JavaScript is available, the site is to use AJAX techniques to increase the responsiveness of the user interactions. Since this is a scripting course, we will develop the AJAX functionality first, while making sure our implementation will not interfere with implementation of a non–JavaScript version at some unidentified time in the future.
The user will see only one web page: the index.xhtml file in the project directory, but there will actually be other PHP files in the project directory that will handle various aspects of the AJAX interactions for the assignment. These files will be described in the development steps below.
Development Steps
-
Set up the project directory.
Create a directory named Final_Project, capitalized and spelled just like that, for this project. Copy the index.xhtml and loginOrRegister.xhtml files from Assignment 7 into this directory. Edit the index page so that it loads a new script file, named final_project.js (in your scripts directory) instead of the one you used for Assignment 7. Remove the “You need JavaScript” message from the index page, and remove the “have JavaScript validate the address” checkbox from the form. Copy your script file from Assignment 7 to final_project.js, and edit it so that the submit event listener always calls Core.preventDefault() and does nothing else.
At this point, if you disable JavaScript, your project should have essentially the same functionality as Assignment 7 did. Use the Web Developer’s toolbar to disable all JavaScript, fill in an email address in the form, and click the submit button: the form data should be submitted to loginOrRegister.xhtml, which should show the proper message, depending on whether the user’s email address is valid and in the database or not.
If you enable JavaScript, submitting the form should cause nothing to happen, because Core.preventDefault() is always called when the form is submitted.
When you have this step completed and tested, make a copy of the entire project into a directory named Final_Project.1; this is your first backup copy for the assignment.
-
Establish an XMLHttpRequest Framework
Add a new file to the project, named ajax.php. Put <php? … ?> tags in the file, and an echo statement in it that displays some useful information, such as the word “hello.”
In your index page, add either a paragraph or a div under the form with no content. (The validator will give a warning about this, which you can eliminate by putting a non-breaking space — — inside the paragraph or div. Use an id on this element so it will be easy to locate using JavaScript; I used the id of placeholder in the code below.
For the XMLHttpRequest, you will need an event handler (not listener) to process the information that comes back after you send the request. For this step, set up a function that locates the paragraph or div you just set up, and writes some text to it:
var request = null; var stateChangeHandler = function() { if (request.readyState == 4 && request.status == 200) { document.getElementById('placeholder').firstChild.nodeValue = "Not Hello"; } else { console.log("Request not complete yet: " + request.readyState); } }
The above code would go inside the “Anonymous self-executing function that returns an object that contains an init() method.” The request variable will be initialized using a call to XMLHttpRequest(). How to do this is described starting on page 306 in the textbook.
For this assignment, you may assume the user will be using a browser that supports the XMLHttpRequest() function rather the old proprietary Microsoft versions. Testing suggests that the code in the book does not work because of the sequence of operations given on page 311. Here is code that will successfully initiate an XMLHttpRequest transaction using the POST method, using your ajax.php file as the target:
request = new XMLHttpRequest(); request.onreadystatechange = stateChangeHandler; request.open('POST', './ajax.php', true); request.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); request.send('request=anything');
The string sent using the send() function is arbitrary at this point, but the example shows how to mimic sending some form data with the name equal to request and the value of that variable being the string “anything.”
The XMLHttpRequest code should be executed when the user submits the form on the index page: it goes inside your submit listener function, after the call to Core.preventDefault() has been executed.
If you have everything set up right, submitting the form should cause some text to appear under the form (“Not Hello” in the code given above) when the user clicks the Login or Register button. If you open the Firebug console, you might (or might not) see some “Request not complete” messages as the request goes through the various states up to readyState 4.
Test and edit your code until it works. At this point you have established that you can do a round–trip exchange with ajax.php, but you haven’t actually exchanged any data between the JavaScript and PHP code yet. That comes next. First, make a complete copy of your project in a directory named Final_Project.2 for backup.
Verify Data Transfer to JavaScript from PHP
This step is trivial, but important: verify that what is echoed by ajax.php is in fact passed back to the JavaScript XMLHttpRequest handler. Change just one line of code:
document.getElementById('placeholder').firstChild.nodeValue = "Not Hello";
becomes:
document.getElementById('placeholder').firstChild.nodeValue = request.responseText;
If the index page now displays “Hello” instead of “Not Hello” when you submit the form, you have verified that the JavaScript code can successfully receive data from ajax.php. It’s a small but critical step. When it works, make a copy of your entire project in a directory named Final_Project.3 for backup.
Send data from JavaScript to PHP
The mechanism for sending data using XMLHttpRequest mimics the mechanism already used by the browser to submit form data. In our case, the code is set up to submit the form data using the POST method. So far, the code sends just one name–value pair: “request=anything”. Modify ajax.php so it echoes the value of $_POST['request'] instead of “Hello”. If submitting the form causes the word “anything” to appear below the form, this step works.
But this code is very fragile: it will “break” if anything out of the ordinary happens. You need to add some checks and fix-ups to ajax.php and verify that they work:
-
Use the isset() PHP function to verify that the value of $_POST is actually available before echoing it. If it is not set, echo an error message instead. (Note: appearance of this error message either means there is a bug in your code or that a hacker is trying to subvert your system. Try to word the error message to help you locate the bug but not to help the hacker figure out how the system works!)
You can test this code by changing the first argument to the XMLHttpRequest open() function from POST to GET, which will cause the data to be appear in the $_GET array instead of the $_POST array, so the test to see if $_POST[request] is set will fail and you will get to see your error message.
-
The other fragility has to do with quotation marks in the data you send/receive. These are especially critical in the JSON processing you will be doing below, so it’s best to get them taken care of now. The solution is quite simple: add this line to the beginning of your ajax.php file:
require_once('strip_quotes.php');
The problem addressed by the code in this file is that the PHP processor might or might not insert backslash characters before quotation marks in the $_GET, $_POST, and $_COOKIE super global variables. (The first two are used for passing form data to the script, and the last one (surprise) is used for cookies.) The code tests whether backslashes have been inserted or not by testing a PHP configuration parameter named “magic quotes”, and then removing them if it is set. If magic quotes is not set on the computer you are using, the script does nothing. Thus, it is possible that your code will work without this code — but it might fail when run on another computer, such as when I grade your project!
First you need to get a copy of the strip_quotes.php file. I put it into a Zip file that you can download: strip_quotes.zip — just download it, unzip it, and put strip_quotes.php in your project directory along with the index file and ajax.php. (Thought Question: strip_quotes.php is a very small file; why did I need to put it in a Zip file?)
You can test this feature by adding some quotation characters to the text following the equal sign in the send() function call, and verifying that they come through unchanged in the data returned when the form is submitted.
Test your code carefully to be sure everything works, then make a copy of your entire project in a directory named Final_Project.4 for backup.
-
Exchange Objects using JSON
Before starting work on this step, download the JSON parser for JavaScript: json2.js. Add it to your scripts directory, and add a script tag to your index page to include this file before your final_project.js file. JSON processing is built into PHP, so you do not need to download anything for that. Use the PHP documentation and the web to learn about JSON.
For this step, you are going to use JSON encoding to transfer a JavaScript Object to PHP, and then to transfer a PHP object back to JavaScript. You have already established that you can exchange text strings between the two sides of your code in previous steps. The idea of JSON is that it can convert objects into strings and vice-versa, so the model for this step is:
-
In JavaScript, create an object, and add the user’s email address to it:
var anObject = {}; anObject.email = qcEmailElement.value;
Of course, your variable names might be different.
- Convert the JavaScript to a string using JSON.stringify().
- Send the string created in the previous step to ajax.php using XMLHttpRequest.
-
In ajax.php, convert the string received from JavaScript into a PHP object
using the built-in json_decode() function, add a field to the object, and
use json_encode() to convert it back into a string, which gets sent back
to JavaScript:
$obj = json_decode($_POST['request']); $obj->password = 'secret'; echo json_encode($obj);
- Back in the JavaScript readyState change handler, you need to convert the received string back into an object using JSON.parse(), and then extract the email and password values from the resulting object.
When this step works, your index page should show the email address entered by the user and the secret password generated by ajax.php under the form when it is submitted. Test your code carefully to be sure everything works, then make a copy of your entire project in a directory named Final_Project.5 for backup.
-
In JavaScript, create an object, and add the user’s email address to it:
Implement the Business Logic
The remainder of the project is to use the framework established in the first 5 steps as a basis for implementing the “business logic” of the application: letting existing users log into the system and letting new users register for the system so they can log in.
We will use the following protocol for exchanging information between the JavaScript and PHP sides of the application: Each side will send an object to the other side that consists of one code field and one or more data fields. The JavaScript side will send “request objects” to the PHP side, and the PHP side will return “reply objects” to the JavaScript side. The name of the code field of a request object will be requestCode and the name of the code field of a reply object will be replyCode. All the other fields of both types of object will match the names of various columns in the database people table. (This last statement will have to be modified some if you actually do the entire application.)
There are just two possible values of requestCode:
requestCode Meaning Other Information Sent 0 Lookup User qc_email and password 1 Register User qc_email, password, last_name, first_name, … The situation is a bit richer for responseCode:
responseCode Meaning Other Information Returned 0 Email and Password OK Return user information from database in other fields. 1 Email Syntax Error Should not occur: email was checked by JavaScript. 2 Not in Database Nothing 3 Missing Password Nothing 4 Wrong Password Nothing As usual, this part of the project will be implemented as a sequence of development steps, each of which adds functionality to those that went before:
-
The first step is to modify the code from the previous step so the two sides communicate with each other using our object-based protocol. The previous step corresponded (roughly) to a “Lookup User” request (requestCode = 0) and a “Email and Password OK” (responseCode = 0)reply.
JavaScript should create the object that it sends like this:
$obj = {}; $obj.requestCode = 0; $obj.qc_email = emailElement.value; $obj.password = passwdElement.value;
Have the PHP side copy information from the request into a new object that it returns. The following code illustrates creating the equivalent of JavaScript’s $obj = {}; by using PHP’s stdClass() “constructor” function:
$request = json_decode($_POST['request']); $reply = new stdClass(); $reply->responseCode = 0; $reply->qc_email = $request->qc_email; $reply->last_name = 'Student'; $reply->first_name = 'Perfect'; echo json_encode($reply);
With this code in place and working, the user should see the qc_email, responseCode, last_name, and first_name values displayed under the login or register form when he or she submits it.
When you have this step working, save the entire project in a directory named Final_Project.6a as backup before proceeding to the next step.
Sending the user’s password over the network as plain text is a security risk. In the real world, you would encrypt the password on the JavaScript side before sending it to the PHP side. But for this assignment, implementing proper security management will be “left for a later step.” Doing authentication securely involves setting up a secure socket layer (SSL) certificate on the server, which is beyond the scope of this course.
-
More to come …
-
Submit the Assignment
When you have tested your web pages, send me an email message to me saying your assignment is ready; I will get a copy from your account on the server and check it out. Send your email to:
Christopher.VickeryATqc.cuny.eduBe sure the Subject Line of your email says CS-90.3 Assignment 8, just like that, to be sure your message does not get trapped by my spam filters.
Be sure to sign your email so I can tell who sent it!