Storing and Retrieving Data
Key topics you will learn about in this tutorial include- Saving data for later
- Opening a file
- Creating and writing to a file
- Closing a file
- Reading from a file
- File locking
- Deleting files
- Other useful file functions
- Doing it a better way: database management systems
Saving Data for Later
There are basically two ways you can store data: in flat files or in a database.
A flat file can have many formats but, in general, when we refer to a flat file, we mean a simple text file. In this example, we’ll write customer orders to a text file, one order per line. This is very simple to do, but also pretty limiting, as we’ll see later in this chapter. If you’re dealing with information of any reasonable volume, you’ll probably want to use a database instead. However, flat files have their uses and there are some situations when you’ll need to know how to use them. Writing to and reading from files in PHP is virtually identical to the way it’s done in C. If you’ve done any C programming or UNIX shell scripting, this will all seem pretty
familiar to you.
Overview of File Processing
There are three steps to writing data to a file:
1. Open the file. If the file doesn’t already exist, it will need to be created.
2. Write the data to the file.
3. Close the file.
Similarly, there are three steps to reading data from a file:
1. Open the file. If the file can’t be opened (for example, if it doesn’t exist), we need
to recognize this and exit gracefully.
2. Read data from the file.
3. Close the file.
When you want to read data from a file, you have choices about how much of the file to
read at a time.We’ll look at each of those choices in detail.
For now, we’ll start at the beginning by opening a file.
Opening a File
To open a file in PHP, we use the fopen() function.When we open the file, we need to
specify how we intend to use it.This is known as the file mode.
File Modes
The operating system on the server needs to know what you want to do with a file that you are opening. It needs to know if the file can be opened by another script while you have it open, and to work out if you (the owner of the script) have permission to use it in that way. Essentially, file modes give the operating system a mechanism to determine how to handle access requests from other people or scripts and a method to check that you have access and permission to this particular file.
There are three choices you need to make when opening a file:
1. You might want to open a file for reading only, for writing only, or for both reading
and writing.
2. If writing to a file, you might want to overwrite any existing contents of a file or
to append new data to the end of the file.
3. If you are trying to write to a file on a system that differentiates between binary
and text files, you might want to specify this.
The fopen() function supports combinations of these three options.
Using fopen() to Open a File
Let’s assume that we want to write a customer order to Bob’s order file.You can open
this file for writing with the following:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", "w");
When fopen is called, it expects two or three parameters. Usually you’ll use two, as
shown in this code line. The first parameter should be the file you want to open.You can specify a path to this file as we’ve done in the previous code—our orders.txt file is in the orders directory. We’ve used the PHP built-in variable $HTTP_SERVER_VARS['DOCUMENT_ROOT'] but, as with the cumbersome full names for form variables, we have assigned it a shorter name. This variable points at the base of the document tree on your Web server.We’ve used the ".." to mean “the parent directory of the document root directory.”This directory is outside the document tree, for security reasons.We do not want this file to be Web accessible except through the interface that we provide.This path is called a relative path
as it describes a position in the file system relative to the document root.
As with the short names we are giving form variables, unless register_globals is turned on, we need the following line at the start of our script
$DOCUMENT_ROOT = $HTTP_SERVER_VARS['DOCUMENT_ROOT'];
to copy the contents of the long style variable to the short style name. In the same way as there are different ways to access form data, there are different ways to access the predefined server variables. Depending on your server setup you can get at the document root through: - $DOCUMENT_ROOT- $_SERVER['DOCUMENT_ROOT'] - $HTTP_SERVER_VARS['DOCUMENT_ROOT']
As with form data, the first style, which we have been calling short style, is only automatically available if you have register_globals turned on.The second style (medium style) cannot be turned off, but is only available in PHP 4.1 and later versions.The long style is available on all systems, but this style is deprecated, so may not be around forever. You could also specify an absolute path to the file.This is the path from the root directory (/ on a UNIX system and typically C:\ on a Windows system). On our UNIX server, this would be /home/book/orders.The problem with doing this is that, particularly if you are hosting your site on somebody else’s server, the absolute path might change.We once learned this the hard way after having to change absolute paths in a large number of scripts when the systems administrators decided to change the directory structure without notice.
If no path is specified, the file will be created or looked for in the same directory as the script itself.This will be different if you are running PHP through some kind of CGI wrapper and will depend on your server configuration. In a UNIX environment, the slashes in directories will be forward slashes (/). If you are using a Windows platform, you can use forward or backslashes. If you use back slashes, they must be escaped (marked as a special character) for fopen to understand them properly.To escape a character, you simply add an additional backslash in front of it, as shown in the following:
$fp = fopen("$DOCUMENT_ROOT\\..\\orders\\orders.txt", 'w');
Very few people use backslashes in paths within PHP as it means your code will only
work on Windows. If you use forward slashes you can often move your code between Windows and UNIX machines without alteration. The second parameter of fopen() is the file mode, which should be a string.This specifies what you want to do with the file. In this case, we are passing 'w' to fopen()—this means open the file for writing.
Summary of File Modes for fopen
Mode Meaning
r Read mode—Open the file for reading, beginning from the start of the
file.
r+ Read mode—Open the file for reading and writing, beginning from the
start of the file.
w Write mode—Open the file for writing, beginning from the start of the
file. If the file already exists, delete the existing contents. If it does not
exist, try and create it.
w+ Write mode—Open the file for writing and reading, beginning from
the start of the file. If the file already exists, delete the existing contents.
If it does not exist, try and create it.
a Append mode—Open the file for appending (writing) only, starting
from the end of the existing contents, if any. If it does not exist, try and
create it.
a+ Append mode—Open the file for appending (writing) and reading,
starting from the end of the existing contents, if any. If it does not exist,
try and create it.
b Binary mode—Used in conjunction with one of the other modes.You might want to use this if your file system differentiates between binary and text files. Windows systems differentiate; UNIX systems do not.
The file mode to use in our example depends on how the system will be used.We have used 'w', which will only allow one order to be stored in the file. Each time a new order is taken, it will overwrite the previous order.This is probably not very sensible, so we are better off specifying append mode: $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'a');
The fopen() function has an optional third parameter.You can use it if you want to search the include_path (set in your PHP configuration—see Appendix A,“Installing PHP 4 and MySQL”) for a file. If you want to do this, set this parameter to 1. If you tell PHP to search the include_path, you do not need to provide a directory name or path: $fp = fopen('orders.txt', 'a', 1);
If fopen() opens the file successfully, a pointer to the file is returned and should be stored in a variable, in this case $fp.You will use this variable to access the file when you actually want to read from or write to it.
Opening Files Through FTP or HTTP
As well as opening local files for reading and writing, you can open files via FTP and HTTP using fopen(). If the filename you use begins with ftp://, a passive mode FTP connection will be opened to the server you specify and a pointer to the start of the file will be returned. If the filename you use begins with http://, an HTTP connection will be opened to the server you specify and a pointer to the response will be returned.When using HTTP mode, you must specify trailing slashes on directory names, as shown in the following:
http://www.server.com/ not http://www.server.com When you specify the latter form of address (without the slash), a Web server will normally use an HTTP redirect to send you to the first address (with the slash).Try it in your browser. Prior to PHP 4.0.5, the fopen() function did not support HTTP redirects, so you must specify URLs that refer to directories with a trailing slash.
As of PHP 4.3.0 you can also open files over SSL as long as you have compiled or enabled support for OpenSSL and you begin the name of the file with https://. Remember that the domain names in your URL are not case sensitive, but the path and filename might be.
Problems Opening Files
A common error you might make while trying to open a file is trying to open a file you don’t have permission to read or write to. PHP will specifically warn you when a file can’t be opened. If you get this error, you need to make sure that the user that the script runs as has permission to access the file you are trying to use. Depending on how your server is set up, the script might be running as the Web server user or as the owner of the directory that the script is in.
On most systems, the script will run as the Web server user. If your script was on a
UNIX system in the ~/public_html/chapter2/ directory, you would create a world
writeable directory in which to store the order by typing the following:
mkdir ~/orders
chmod 777 ~/orders
Bear in mind that directories and files that anybody can write to are dangerous.You
should not have directories that are accessible directly from the Web as writeable. For this reason, our orders directory is two subdirectories back, above the public_html directory.
Incorrect permission settings is probably the most common thing that can go wrong
when opening a file, but it’s not the only thing. If the file can’t be opened, you really
need to know this so that you don’t try to read data from or write data to it.
If the call to fopen() fails, the function will return false.You can deal with
the error in a more user-friendly way by suppressing PHP’s error message and giving
your own:
@ $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'a', 1);
if (!$fp)
{
echo '<p><strong> Your order could not be processed at this time. '
.'Please try again later.</strong></p></body></html>';
exit;
}
The @ symbol in front of the call to fopen() tells PHP to suppress any errors resulting
from the function call. Usually it’s a good idea to know when things go wrong, but in
this case we’re going to deal with that elsewhere. This line can also be written as follows
$fp = @fopen("$DOCUMENT_ROOT/../orders/orders.txt", "a", 1);
but this does tend to make it less obvious that you are using the error suppression
operator.
The if statement tests the variable $fp to see if a valid file pointer was returned from
the fopen call; if not, it prints an error message and ends script execution. Because the page will finish here, notice that we have closed the HTML tags to give valid HTML. Using your own error messages instead of PHP’s can be more user friendly.
Writing to a File
Writing to a file in PHP is relatively simple.You can use either of the functions
fwrite() (file write) or fputs() (file put string); fputs() is an alias to fwrite().We
call fwrite() in the following:
fwrite($fp, $outputstring);
This tells PHP to write the string stored in $outputstring to the file pointed to by
$fp.We’ll discuss fwrite() in more detail before we talk about the contents of $outputstring.
Parameters for fwrite()
The function fwrite() actually takes three parameters but the third one is optional.The prototype for fwrite() is int fwrite ( int fp, string string [, int length])
The third parameter, length, is the maximum number of bytes to write. If this parameter is supplied, fwrite() will write string to the file pointed to by fp until it reaches the end of string or has written length bytes, whichever comes first.
File Formats
When you are creating a data file like the one in our example, the format in which you store the data is completely up to you. (However, if you are planning to use the data file in another application, you may have to follow that application’s rules.)
Let’s construct a string that represents one record in our data file.We can do this as
follows:
$outputstring = $date."\t".$tireqty." tires \t".$oilqty." oil\t"
.$sparkqty." spark plugs\t\$".$total
."\t". $address."\n";
In our simple example, we are storing each order record on a separate line in the file.We choose to write one record per line because this gives us a simple record separator in the newline character. Because newlines are invisible, we represent them with the control sequence "\n".
We will write the data fields in the same order every time and separate fields with a
tab character.Again, because a tab character is invisible, it is represented by the control sequence "\t".You may choose any sensible delimiter that is easy to read back. The separator or delimiter character should either be something that will certainly not occur in the input, or we should process the input to remove or escape out any instances of the delimiter. We will assume that nobody will place a tab into our order form. It is difficult, but not impossible, for a user to put a tab or newline into a single line HTML input field.
Using a special field separator will allow us to split the data back into separate variables more easily when we read the data back. For the time being, we’ll treat each order as a single string.
Example of What the Orders File Might Contain
(THESE ARE MAKE BELIEVE)
15:42, 20th April 4 tires 1 oil 6 spark plugs $434.00 22 Short St, Smalltown
15:43, 20th April 1 tires 0 oil 0 spark plugs $100.00 33 Main Rd, Newtown
15:43, 20th April 0 tires 1 oil 4 spark plugs $26.00 127 Acacia St, Springfield
Closing a File
When you’ve finished using a file, you need to close it.You should do this with the fclose() function as follows:
fclose($fp);
This function will return true if the file was successfully closed, or false if it wasn’t. This is generally much less likely to go wrong than opening a file in the first place, so in this case we’ve chosen not to test it.
Reading from a File
Right now, Bob’s(make believe name) customers can leave their orders via the Web, but if Bob’s staff wants to look at the orders, they’ll have to open the files themselves. Let’s create an example Web interface to let Bob’s staff read the files easily.
Staff Interface to the Orders File
<?php
//create short variable name
$DOCUMENT_ROOT = $HTTP_SERVER_VARS['DOCUMENT_ROOT'];
?>
<html>
<head>
<title>Bob's Auto Parts - Customer Orders</title>
</head>
<body>
<h1>Bob's Auto Parts</h1>
<h2>Customer Orders</h2>
<?php
Reading from a File 61
@ $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'r');
if (!$fp)
{
echo '<p><strong>No orders pending.'
.'Please try again later.</strong></p>';
exit;
}
while (!feof($fp))
{
$order= fgets($fp, 999);
echo $order.'<br />';
}
fclose($fp);
?>
</body>
</html>
This script follows the sequence we talked about earlier: open the file, read from the file, close the file. Let’s look at the functions in this script in detail.
Opening a File for Reading: fopen()
Again, we open the file using fopen(). In this case we are opening the file for reading
only, so we use the file mode 'r':
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'r');
Knowing When to Stop: feof()
In this example, we use a while loop to read from the file until the end of the file is
reached.The while loop tests for the end of the file using the feof() function:
while (!feof($fp))
The feof() function takes a file pointer as its single parameter. It will return true if the
file pointer is at the end of the file. Although the name might seem strange, it is easy to remember if you know that feof stands for File End Of File.
In this case (and generally when reading from a file), we read from the file until EOF is reached. Reading a Line at a Time: fgets(), fgetss(), and fgetcsv() In our example, we use the fgets() function to read from the file: $order= fgets($fp, 999);
This function is used to read one line at a time from a file. In this case, it will read until it encounters a newline character (\n), encounters an EOF, or has read 998 bytes from the file.The maximum length read is the length specified minus one byte.
There are many different functions that can be used to read from files.The fgets()
function is useful when dealing with files that contain plain text that we want to deal
with in chunks.
An interesting variation on fgets() is fgetss(), which has the following prototype:
string fgetss(int fp, int length, string [allowable_tags]);
This is very similar to fgets() except that it will strip out any PHP and HTML tags
found in the string. If you want to leave any particular tags in, you can include them in the allowable_tags string.You would use fgetss() for safety when reading a file written by somebody else or containing user input. Allowing unrestricted HTML code in the file could mess up your carefully planned formatting. Allowing unrestricted PHP could give a malicious user almost free rein on your server.
The function fgetcsv() is another variation on fgets(). It has the following prototype:
array fgetcsv ( int fp, int length [, string delimiter [, string enclosure]])
It is used for breaking up lines of files when you have used a delimiting character,
such as the tab character as we suggested earlier or a comma as commonly used by
spreadsheets and other applications. If we want to reconstruct the variables from the order separately rather than as a line of text, fgetcsv() allows us to do this simply.You call it in much the same way as you would call fgets(), but you pass it the delimiter you used to separate fields. For example, $order = fgetcsv($fp, 100, "\t");would retrieve a line from the file and break it up wherever a tab (\t) was encountered. The results are returned in an array ($order in this code example).
The length parameter should be greater than the length in characters of the longest
line in the file you are trying to read. The enclosure parameter is used to specify what each field in a line is surrounded by. If not specified, it defaults to " (double quote).
Reading the Whole File: readfile(), fpassthru(), file()
Instead of reading from a file a line at a time, we can read the whole file in one go.
There are four different ways we can do this. The first uses readfile().We can replace the entire script we wrote previously with one line:
readfile("$DOCUMENT_ROOT/../orders/orders.txt");
A call to the readfile() function opens the file, echoes the content to standard output
(the browser), and then closes the file.The prototype for readfile() is
int readfile(string filename, int [use_include_path]); The optional second parameter specifies whether PHP should look for the file in the include_path and operates the same way as in fopen().The function returns the total number of bytes read from the file.
Secondly, you can use fpassthru().You need to open the file using fopen() first.
You can then pass the file pointer as argument to fpassthru(), which will dump the
contents of the file from the pointer’s position onward to standard output. It closes the file when it is finished.
You can replace the previous script with fpassthru() as follows:
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'r');
fpassthru($fp);
The function fpassthru() returns true if the read is successful and false otherwise.
The third option for reading the whole file is using the file() function.This function
is identical to readfile() except that instead of echoing the file to standard output,
it turns it into an array. Just for reference, you would call it using
$filearray = file($fp);
This will read the entire file into the array called $filearray. Each line of the file is
stored in a separate element of the array. Note that this function is not binary-safe.
Finally, as of PHP 4.3.0 you can use the file_get_contents() function.This function
is identical to readfile() except that it returns the content of the file as a string
instead of outputting it to the browser.The advantage of this new function is that it is
binary-safe, unlike the file() function.
Reading a Character: fgetc()
Another option for file processing is to read a single character at a time from a file. You can do this using the fgetc() function. It takes a file pointer as its only parameter and returns the next character in the file.We can replace the while loop in our original script with one that uses fgetc():
while (!feof($fp))
{
$char = fgetc($fp);
if (!feof($fp))
echo ($char=="\n" ? '<br />': $char);
}
This code reads a single character from the file at a time using fgetc() and stores it in
$char, until the end of the file is reached.We then do a little processing to replace the text end-of-line characters, \n, with HTML line breaks, <br />.This is just to clean up the formatting. Because browsers don’t render a newline in HTML as a newline without this code, the whole file would be printed on a single line. (Try it and see.) We use the ternary operator to do this neatly.
A minor side effect of using fgetc() instead of fgets() is that it will return the EOF
character whereas fgets() will not.We need to test feof() again after we’ve read the
character because we don’t want to echo the EOF to the browser.
It is not generally sensible to read a file character-by-character unless for some reason we want to process it character-by-character.Reading an Arbitrary Length: fread() The final way we can read from a file is using the fread() function to read an arbitrary number of bytes from the file.This function has the following prototype:
string fread(int fp, int length); The way it works is to read up to length bytes or to the end of file, whichever comes first.
Other Useful File Functions
There are a number of other file functions we can use that are useful from time-to-time. Checking Whether a File Is There: file_exists()
If you want to check if a file exists without actually opening it, you can use
file_exists(), as follows:
if (file_exists("$DOCUMENT_ROOT/../orders/orders.txt"))
echo 'There are orders waiting to be processed.';
else
echo 'There are currently no orders.';
Knowing How Big a File Is: filesize()
You can check the size of a file with the filesize() function. It returns the size of a
file in bytes:
echo filesize("$DOCUMENT_ROOT/../orders/orders.txt");
It can be used in conjunction with fread() to read a whole file (or some fraction of the
file) at a time.We can replace our entire original script with
$fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'r');
echo fread( $fp, filesize("$DOCUMENT_ROOT/../orders/orders.txt" ));
fclose( $fp );
Deleting a File: unlink()
If you want to delete the order file after the orders have been processed, you can do it using unlink(). (There is no function called delete.) For example,
unlink("$DOCUMENT_ROOT/../orders/orders.txt");
This function returns false if the file could not be deleted.This will typically occur if
the permissions on the file are insufficient or if the file does not exist.
Navigating Inside a File: rewind(), fseek(), and ftell() You can manipulate and discover the position of the file pointer inside a file using rewind(), fseek(), and ftell().
The rewind() function resets the file pointer to the beginning of the file.The
ftell() function reports how far into the file the pointer is in bytes. For example, we
can add the following lines to the bottom of our original script (before the fclose()
command): echo 'Final position of the file pointer is '.(ftell($fp));
echo '<br />';
rewind($fp);
echo 'After rewind, the position is '.(ftell($fp));
echo '<br />';
After reading the orders, the file pointer points to the end of the file, an offset of 234 bytes.The call to rewind sets it back to position 0, the start of the file.
The function fseek() can be used to set the file pointer to some point within the file.
Its prototype is int fseek ( int fp, int offset [, int whence])
A call to fseek() sets the file pointer fp at a point starting from whence and moving offset bytes into the file.The optional whence parameter was added in PHP 4.0.0. It defaults to the value SEEK_SET which is effectively the start of the file.The other possible values are SEEK_CUR (the current location of the file pointer) and SEEK_END (the end of the file). The rewind() function is equivalent to calling the fseek() function with an offset of zero. For example, you can use fseek() to find the middle record in a file or to perform a binary search. Often if you reach the level of complexity in a data file where you need to do these kinds of things, your life will be much easier if you use a database.
File Locking
Imagine a situation where two customers are trying to order a product at the same time. (Not uncommon, especially when you start to get any kind of volume of traffic on a Web site.) What if one customer calls fopen() and begins writing, and then the other customer calls fopen() and also begins writing? What will be the final contents of the file? Will it be the first order followed by the second order or vice versa? Will it be one order or the other? Or will it be something less useful, like the two orders interleaved somehow? The answer depends on your operating system, but is often impossible to know. To avoid problems like this, you can use file locking.This is implemented in PHP using the flock() function.This function should be called after a file has been opened, but before any data is read from or written to the file.
The prototype for flock() is bool flock(int fp, int operation [, int &wouldblock])
You need to pass it a pointer to an open file and a number representing the kind of
lock you require. It returns true if the lock was successfully acquired, and false if it was not. The possible values of operation are shown in Table 2.2.The possible values
changed at PHP 4.0.1. Both sets of values are shown in the table.
Operation Values
Value of operation Meaning
LOCK_SH (formerly 1) Reading lock.This means the file can be shared with other
readers.
LOCK_EX (formerly 2) Writing lock.This is exclusive.The file cannot be shared.
LOCK_UN (formerly 3) Release existing lock.
LOCK_NB (formerly 4) Adding 4 to the operation prevents blocking while trying to
acquire a lock. If you are going to use flock(), you will need to add it to all the scripts that use the file; otherwise, it is worthless. Note that flock() does not work with NFS or other networked file systems. It also does not work with older file systems that do not support locking such as FAT. On some operating systems it is implemented at the process level and will not work correctly if you are using a multithreaded server API.
To use it with this example, you can alter processorder.php as follows: $fp = fopen("$DOCUMENT_ROOT/../orders/orders.txt", 'a');
flock($fp, LOCK_EX); // lock the file for writing
fwrite($fp, $outputstring);
flock($fp, LOCK_UN); // release write lock
fclose($fp);
You should also add locks to this:
$fp = fopen("$DOCUMENT_ROOT /../orders/orders.txt", 'r');
flock($fp, LOCK_SH); // lock file for reading
68 Chapter 2 Storing and Retrieving Data
// read from the file
flock($fp, LOCK_UN); // release read lock
fclose($fp);
Our code is now more robust, but still not perfect.What if two scripts tried to acquire a lock at the same time? This would result in a race condition, where the processes compete for locks but it is uncertain which will succeed, that could cause more problems. We can do better by using a DBMS.
Doing It a Better Way: Database Management Systems
So far all the examples we have looked at use flat files. In the next section of this book we’ll look at how you can use MySQL, a relational database management system, instead.You might ask,“Why would I bother?”
Problems with Using Flat Files There are a number of problems in working with flat files:
- When a file gets large, it can be very slow to work with.
- Searching for a particular record or group of records in a flat file is difficult. If the
records are in order, you can use some kind of binary search in conjunction with a
fixed-width record to search on a key field. If you want to find patterns of information (for example, you want to find all the customers who live in Smalltown), you would have to read in each record and check it individually. n Dealing with concurrent access can become problematic.We have seen how you can lock files, but this can cause a race condition as we discussed earlier. It can also cause a bottleneck.With enough traffic on the site, a large group of users may be
waiting for the file to be unlocked before they can place their order. If the wait is
too long, people will go elsewhere to buy.- All the file processing we have seen so far deals with a file using sequential processing— that is, we start from the start of the file and read through to the end. If we want to insert records into or delete records from the middle of the file (random access), this can be difficult—you end up reading the whole file into memory,
making the changes, and writing the whole file out again.With a large data file,
this becomes a significant overhead. n Beyond the limits offered by file permissions, there is no easy way of enforcing different levels of access to data.
How RDBMSs Solve These Problems
Relational database management systems address all of these issues:
- RDBMSs can provide faster access to data than flat files.And MySQL, the database
system we use in this book, has some of the fastest benchmarks of any RDBMS.
- RDBMSs can be easily queried to extract sets of data that fit certain criteria.
- RDBMSs have built-in mechanisms for dealing with concurrent access so that you
as a programmer don’t have to worry about it.
- RDBMSs provide random access to your data.
- RDBMSs have built-in privilege systems. MySQL has particular strengths in this
area. Probably the main reason for using an RDBMS is that all (or at least most) of the functionality that you want in a data storage system has already been implemented. Sure, you could write your own library of PHP functions, but why reinvent the wheel?
In Part 2 of this book,“Using MySQL,” we’ll discuss how relational databases work generally, and specifically how you can set up and use MySQL to create database-backed Web sites.





