Monday, September 25, 2006

JavaScript and the DOM


Sorry folks, I’ve twisted my ankle and I’m not going to be able to make it in today. I know you’ll all miss me, but to dull the pain of separation, here’s a couple of tutorials to be going on with:

Javascript Basics Part 6 (internal link)

talking about the Document Object Model or DOM for short.

and…

Javascript Basics Part 7 (internal link)

examining the document object and the window object, both of which offer many useful functions.

When you’ve finished these you might like to try applying them to the Greening Bathurst form, so that error messages are displayed on the web page alongside the fields that they are all about (rather than in an alert box).

Want more? Have a look at error handling and AJAX:

Javascript Basics Part 11 (internal link)

how to account for errors and several different methods for general error handling.

Followed by:

Javascript Basics Part 10 (internal link)

An introduction to AJAX


Image: ‘A pint for the discerning standardista

Monday, September 04, 2006

Building a data-driven web site (reposted)


this was originally posted last month, but got lost somehow, so here it is again in all its warty glory...

It's been a while, so this is likely to be a lengthy post...

To start off, we're going to look a the topography of our data-driven book site: a page that lists all the authors, with links from each author's name to a page that lists the books written by that author. For maintenance, we'll add pages that allow author records to be added, edited and deleted.

Before we get stuck into this, we'll need to know how to communicate with our database using SQL (structured query language) statements. Have a look at the SQL CHEAT SHEET for some examples of SQL that select, update, insert and delete records from a database. You can experiement with these in myPhpAdmin by opening a SQL window and typing in commands.

Master/Detail Pages

For our first page we're just going to display a list of authors. The pseudocode for this operation would read something like:
connect to the database engineselect a database to useexecute a SQL statement to retrieve some records from the databasedisplay each record on the web pageand the php code to accomplish this might look something like:

<?php

// connect to the database engine
@ $db = mysql_pconnect('localhost','username','password');
// do some error checking
if (!$db) {
echo 'error: couldnt connect to the database';
exit;
}
else {
//echo ' all ok with connection';
}

// select a database on the database server
mysql_select_db('your_db',$db);

// execute a SQL query to select records from the authors table
$result = mysql_query('SELECT * FROM authors');

// display each record on the web page
$numresults = mysql_num_rows($result);
//echo $numresults." records found";
for ($i=0; $i<$numresults; ++$i) {
$row = mysql_fetch_assoc($result);
echo $row['firstname'].' '.$row['surname'].'<br />'';
}

?>


So far, so good. But we want more, vis: links from the author names to a page that lists all the books they've written, so we'd need to update the echo statement to look more like:
echo '<a href="titles.php?authorID='.$row['authorID'].'">'.$row['firstname'].' '.$row['surname'].'</a><br />'';Wha? I hear you ask...

Quite simple really; we've wrapped an anchor tag around our author names, linking them to (an as yet unwritten) page: titles.php, which will list all the books written by that author.

So that our new page can list just one author, we need to give it a hint about what author we're interested in, and we do this by appending the authorID to the URL: ?authorID=nnn, where nnn is grabbed from the database and pasted into the link, a unique ID for each author.

At the other end (on the titles.php page), our script will grab this ID using $_GET and use it to build an SQL statement which gets just those books written by our author. Something like:

<?php

// connect to the database engine
@ $db = mysql_pconnect('localhost','username','password');
// do some error checking
if (!$db) {
echo 'error: couldnt connect to the database';
exit;
}
else {
//echo ' all ok with connection';
}

// select a database on the database server
mysql_select_db('your_db',$db);

// execute a SQL query to select records from the authors table
$result = mysql_query('SELECT * FROM titles where authorID = '.$_GET['authorID']);

// display each title on the web page
$numresults = mysql_num_rows($result);
//echo $numresults." records found";
for ($i=0; $i<$numresults; ++$i) {
$row = mysql_fetch_assoc($result);
echo $row['title']<br />'';
}

?>

Note the php which grabs our authorID from the URL and sticks it onto the end of our SQL statement:
'SELECT * FROM titles where authorID = '.$_GET['authorID']
Nice and easy, yes? On to...

Adding New Records

To add a new record we need to write a form with text inputs for each field in the table, and link to this new page from our original authors list. So, to start we'd add a little line of HTML to our authors.php page:
<a href="admin/authoradd.php">Add a new author</a>(note, we're putting our administration pages in a new sub-directory called admin. More on why later)

The form itself is rather simple, just asking for the firstname and lastname of our new author (we don't need to get an authorID because this is an autonumber field and the database will do this for us). Something like this should do the trick:

<h1>Add a New Author</h1>
<form method="post" action="authoradd2.php">
<table border="0" cellpadding="3" >
<tr>
<td>First Name:</td>
<td><input type="text" name="firstname" /></td>
</tr><tr>
<td>Surname:</td>
<td><input type="text" name="surname" /></td>
</tr><tr>
<td></td>
<td><input type="submit" value="Add Author" /></td>
</tr>
</table>
</form>

For simplicity the form will submit (POST) to a second php page: authoradd2.php which will do the actual work of creating the new record. The pseudocode for this operation would be:
Get the form elements into variablesConstruct an SQL statement from these to insert a new recordConnect to the database engineSelect a databaseExecute the SQL statementRedirect back to the authors list (authors.php) to display the new authorand the code might look something like:

<?php
// get the firstname and surname from the form
$firstname = $_POST['firstname'];
$surname = $_POST['surname'];

// build the SQL statement which will insert a record
$sql = "INSERT INTO authors (firstname, surname) VALUES (' ".$firstname." ', ' ".$surname." ') ";

// connect to the database engine
@ $db = mysql_pconnect('localhost','username','password');
// do some error checking
if (!$db) {
echo 'error: couldnt connect to the database';
exit;
}
else {
//echo ' all ok with connection';
}

// select a database on the database server
mysql_select_db('your_db',$db);

// execute the SQL statement
$result = mysql_query($sql);
// check that it ran correctly
if (!$result) {
die('Invalid query: ' . mysql_error());
}

// redirect to the authors list to show the results
header("location: ../authors.php");

?>

let's move on now to...

Editing a Record

This is really a combination of things we've already done. Firstly, we need to add an 'Edit' link next to each author's name (which must include the authorID in the URL). This would mean changing our authors.php file so that each author would be displayed as:

echo '<a href="titles.php?authorID='.$row['authorID'].'">'.$row['firstname'].' '.$row['surname'].'</a><a href="admin/authoredit.php?authorID='.$row['authorID'].'">edit</a><br />'';

The important new part being:

<a href="admin/authoredit.php?authorID='.$row[authorID].'">edit</a>

And the new authoredit.php page? It would take the authorID, select the author record from the database, and populate a form with these values, allowing the user to edit them. Someting like:

<?php

// connect to the database engine
@ $db = mysql_pconnect('localhost','username','password');
// do some error checking
if (!$db) {
echo 'error: couldnt connect to the database';
exit;
}
else {
//echo ' all ok with connection';
}

// select a database on the database server
mysql_select_db('your_db',$db);

// execute a SQL query to select the author record from the authors table
$result = mysql_query('SELECT * FROM authors where authorID = '.$_GET['authorID']);

?>

<h1>Edit Author</h1>
<form method="post" action="authoredit2.php">
<table border="0" cellpadding="3" >
<tr>
<td>First Name:</td>
<td><input type="text" name="firstname" value="<?php echo $row['firstname'] ?>" /></td>
</tr><tr>
<td>Surname:</td>
<td><input type="text" name="surname" value="<?php echo $row['surname'] ?>"/></td>
</tr><tr>
<td><input type="hidden" name="authorID" value="<?php echo $row['authorID'] ?>" /></td>
<td><input type="submit" value="Add Author" /></td>
</tr>
</table>
</form>

One trick to note: the authorID is being passed to authoredit2.php as a hidden field:

<input type="hidden" name="authorID" value="<?php echo $row['authorID'] ?>" />

We don't want the end user to edit this value, but need to send it through so it can be used when updating the record. Once submitted the form calls authoredit2.php, which performs the following operations:
Retrive the form valuesBuild an SQL statement from them to update the recordConnect to the database engineSelect a databaseExecute the SQL statementRedirect the user to the authors list to display the resultsI won't bore you with a full listing, just the first 2 steps:

// get the firstname, surname and authorID from the form
$firstname = $_POST['firstname'];
$surname = $_POST['surname'];
$authorID = $_POST['authorID'];

// build the SQL statement which will insert a record
$sql = "UPDATE authors SET firstname = '".$firstname."', surname = '".$surname."' WHERE authorID = ".$authorID;

The biggest trick here is to remember to wrap any text strings inside single quotes for the SQL statement. This can call for some tricky double quote stuff in the php. Perhaps a view of the final SQL will give you an idea of what we're aiming at here. If, for example, I wanted to author number 1 in the database to assume my name the SQL would look like this:
UPDATE authors SET firstname = 'Peter', surname = 'Shanks' WHERE authorID = 1
Nearly done now, just one more thing:

Deleting Records

Lucky for us, this is really the easiest operation so far. All we need do is add a little code right next to our edit links on the authors.php page:


<a href="admin/authordelete.php?authorID='.$row['authorID'].'">del</a>

As with the edit link, we're passing each author's ID in with the URL. This time we don't need a form, just the php to build the SQL and execute it before redirecting us back to the author list page:

<?php
$authorID = $_GET['authorID'];
$sql = "DELETE FROM authors WHERE authorID = ".$authorID;
require("../connection.php");

$result = mysql_query($sql);
if (!$result) {
die('Invalid query: ' . mysql_error());
}

header("location: ../authors.php");
?>

Of note here: I got sick of writing the database connection and selection code over and over. Instead I put it in a seperate file: connection.php, which I included in this one with the php function: require("../connection.php");

And that's it - we've built a fully functional, data-driven set of web pages. If you want to practice your skills further, add some pages which allow you to view book details when you click on titles, and add, edit and delete titles from the database.

Sessions


So, we've been looking a bit at session variables. The scenario:

we're displaying a screenful of data to our web site visitors (like a list of authors), and we want to give authorised users the option to edit, delete and add new records - but we want to hide these pages from the average viewer. First, we need a login screen.

A simple form asking for a user's email and password should do. When the form's submitted, these fields would be checked against a database of users. Then the magic occurs...

If the user's email and password match, we'll be setting a session variable, that will let us know that they're authorised to see the administrative pages and links.

Sessions are like server-side files that store variables that can be read from, or written to, by PHP scripts. Each session file is unique to the user that created it and can only be accessed by subsequent requests from the same user.

For our login, we'll be setting a session variable called loggedin. The first piece of code on the page, and all other pages that need to access the variables, will be:

<?php session_start(); ?>

This piece of code does one of two things. If the user does not already have a session, it creates a new session - or - if the user does already have a session it connects to the existing session file. When a new session is created, PHP session management generates a session identifier.

After calling the session_start function, we're ready to do the email/password comparison with the user details in the database (you can do that), if they match we'd set the session variable:

$_SESSION['loggedin'] = 'true';

Subsequenly we can check for this value on any page. To selectively display bits of html (links to edit and delete functions, for example) we might add:

<?php
session_start();
if ($_SESSION['loggedin'] == 'true') {
echo 'Edit>';
}
?>

If we were restricting access to a whole page (say the add, edit or delete pages), we might add some code like this:

<?php
session_start();
if ($_SESSION['loggedin'] != 'true') {
header("location:login.php");
}
?>

This code checks to see if the session variable loggedin is set to true. If not, it redirects the user to the login page.



Thanks to iconjon for the pic