List /View
Many web applications are all about data. We store our data in a database management system, and build the web application to allow access to that data. Our first step towards building a web application starts with the concept of the list and the view.
Displaying Data: When we view data on the web, we need a way to present a reasonable amount of data, even if there are thousands of things we could show. When I go to amazon.com, I don't see all of the millions of books at once. I might see a select list of books, and when I select one of them, I can then view the details of a single book. The terms list & view are borrowed from the Rails web development platform. Until Rails came along, I called the these category & item, respectively.
The List: We address the list first, because this is the way we present the user with choices. An easy way to imagine a list is to think of what is returned when we do a search on a search engine. We see a list of items, with a description that gives us enough detail to determine if we are interested. To view details, we click on a link which will take us to view the page.
Loaded Querystring: The list/view application is based upon the concept of a loaded querystring. When we looked at forms, we may have noticed that using the GET method appends the data submitted via the form to the end of the formhandler page:
formhandler.php?id=5
The data following the question mark above is called the querystring, because it starts with the question mark. What follows it is a series of name/value pairs. Above we see the name "id" is assigned to the value "5".
The id of 5 potentially refers to the 5th item entered in a database table. It is this relationship, wherein we tag an id to a page that allows us to vary the item to the page. We can pass in any id number to the page in this way, and accommodate any number of items on a single page!
When we pass data into a page via the querystring in this way we call it a loaded querystring.
When we build a list page out of a single table from the database, we loop through our records, and can create links to each individual item. These links are called loaded links because the id number of individual records are thus loaded to be activated when the link is clicked:
<a href="view.php?id=5">My PHP Book</a>
In the above example, My PHP Book is the title of the page. Both the ID number and the title of the book are retrieved from the database. While retrieving the records (in the retrieval loop) the line of PHP code could look like this:
print '<a href="view.php?id=' . row['BookID'] . '">' . row['BookTitle'] . '</a>';
Above the fields BookID and BookTitle are retrieved from the database while we build the HTML to support loading the querystring. If we called up 10 book records, we would then have 10 loaded querystring links, and each one would activate a different book via the view page.
The View: While the list page displays records from a single database table, the view page displays data for a single record only. The view page (as described above) uses a loaded querystring to display a single record:
view.php?id=5
As the data passed to the view page varies (different id number being sent) the data on the page varies. If there is no data currently being passed via the querystring (meaning for example id=5 is not present) or the data sent is improper, the user is redirected back to the list page because the view page requires proper querystring data to be present.
List as Entry Point of the Application: The list and view pages together make a simple web application. We'll call the list page the entry point of the application, because the view pages are loaded by visiting the list page first. How can you view a single item on the view page, without loading the querystring? The list page loads the querystring for us. This is why the list is the entry point.
Demo Context: To give this demo a specific context, we’ll use muffins as our type of data. This demo could apply to any other sort of item, such as books, CDs, photos or clothing. It's usually easier to work with the list/view in an inventory related context.
Database Table Schema: In order to store our muffins, we'll need to build a database table to hold the proper data types and then enter some test data. In our case, we'll create a table named test_Muffins, and insert 6 muffins:
create table test_Muffins
( MuffinID int unsigned not null auto_increment primary key,
MuffinName varchar(60),
Description text,
Price decimal(5,2)
);
insert into test_Muffins values (NULL,"Apple","An apple muffin a day keeps the doctor away!",.99);
insert into test_Muffins values (NULL,"Banana Nut","Bananas and walnuts combine in a rich and rewarding muffin!",1.50);
insert into test_Muffins values (NULL,"Blueberry","Our wildly popular traditional blueberry muffin.",1.25);
insert into test_Muffins values (NULL,"Chocolate","The chocoholics love us for this one!",1.50);
insert into test_Muffins values (NULL,"Bran","Our bran muffins are a favorite among our regular customers!",.99);
insert into test_Muffins values (NULL,"Raspberry","A truly decadent raspberry streusel muffin!",1.99);
You can copy the SQL script above and paste it into the command line on MySQL, or you can install a program like
phpMinAdmin. which can make your MySQL configuration life easier!
demo_list.php/demo_view.php: The following example shows how 2 visible pages interact to create a fundamental web application. It is an application because the pages work together with data to present a dynamic set of data. The application consists of more than one file, so it is a multi-file web application.
Properly named List/View Applications: We've named our sample pages demo instead of muffins to highlight the reason for the pages is really to create a place to start from to make your list/view application. If we made a list/view application to feature test_Muffins, for example, we could use cd_list.php & cd_view.php. With CDs being the reason for the application, the word "CDs" would be the name/label that a user sees when clicking on the link to our cd_list.php page:
<a href="cd_list.php>My CDs</a>
Remember the view page is linked from the list page and therefore requires no link created by a developer!
Natural Names for List/View: While the terms list & view keep developers straight as to what is going on, what are the natural names for these pages? If we were using muffins as our context, the list page would be muffins.php (plural) and the view page would be muffin.php (singular). How confusing would that be to talk about, or to keep straight?
Contingency: The demo_list.php example relies upon correct installation of nmCommon, a set of functional include files to handle errors and database credentials. If you are still working on your theme from A7, you can switch to one of the installed themes to proceed with the demo.
Redirection: During the course of building web applications we run into the issue of passing the users browser back and forth between pages. This could be due to a successful login, or even due to an unsuccessful login attempt! The concept of redirection exists in nearly every server side language. In our case, if invalid data is sent to our view page, we'll elect to redirect the user back to a safe page, in this case our list page.
myRedirect(): The function used in demo_view.php to handle redirection is named myRedirect() and it's inside our common_inc.php include file of utility functions. We use this function to forcibly redirect a user who overtypes the querystring data being passed into demo_view.php. PHP has a function named header() which can be used to redirect a user, but our version incorporates header() and can accept an absolute or relative URL, and also keeps either the HTTP or HTTPS protocol of the sending page intact.
Sanitizing Data: Our include file common_inc.php also includes dbOut(), which is designed to ‘clean’ (sanitize) the string of data as it leaves the database, and enters our page. This function is called a wrapper function because it ‘wraps’ other functions that we can now change, as our site develops, or if we need special handling. Placing all the ‘cleaning’ code in a wrapper allows us to change this capability site wide.
dbOut() implements some built in PHP functions such as stripslashes(), which along with its opposite addslashes() render harmless single quotes, which trip up an insertion of data into a database. In SQL, single quotes are used to designate a string, but must be escaped (by adding a slash in front of the literal quote) to be entered into the database.
dbOut() has an opposite related function named dbIn() which employs mysql_real_escape_string() and other connection specific cleaning methods to clean data entering the database. We need to use part of our querystring in a SQL call, so we need to santize our data, however in this case we'll use a different technique, casting the input.
Casting The Querystring Input: When we use a loaded querystring we use data that can be edited by the user against the database connection, merely by typing in the address bar of the browser. This allows the possibility of SQL injection in which a hacker tries to crash our server or insert contaminated data to destroy or force a login to our application.
Since we're using integers on our querystring, we can defend ourselves against improper data on the querystring by forcibly casting any data to an integer:
$myID = (int)$_GET['id'];
In the above example we identify the data type we wish to cast our data to in parens and set it beside to the data entering via the querystring. The value on the querystring is forcibly cast to an integer. Upon failure, the data is cast harmlessly to zero! This means that if the user types any 'hacker bits', what they have typed is converted to zero.
The Happy Accident of Zero: Since zero is both an invalid number in a database table (autonumber starts at one) we can then redirect the user who overtypes any improper data on the querystring of the view page harmlessly back to the list page!