Your Federal Quarterly Tax Payments are due April 15th Get Help Now >>

Guide to PHP by Ade_Robianto

VIEWS: 110 PAGES: 184

this is a tutorial about PHP

More Info
									A guide to PHP
Part 1:
The Only Acronym You'll Ever Need
If you're new to Web development, you could be forgiven for thinking that it
consists of no more than a mass of acronyms, each one more indecipherable
than the last. ASP, CGI, SOAP, XML, HTTP - the list seems never-ending, and
the sheer volume of information on each of these can discourage the most
avid programmer. But before you put on your running shoes and flee, there's
a little secret you should know. To put together a cutting-edge Web site,
chock full of all the latest bells and whistles, there's only one acronym you
really need to know:


PHP


Now, while you have almost certainly heard of PHP, you may not be aware of
just how powerful the language is, and how much it can do for you. Today,
PHP has the enviable position of being the only open-source server-side
scripting language that's both fun and easy to learn. This is not just
advertising: recent surveys show that more than 16,000,000 Web sites use
PHP as a server side scripting language, and the language also tops the list
of most popular Apache modules.


Why, you ask? The short answer: it's powerful, it's easy to use, and it's free.
Extremely robust and scalable, PHP can be used for the most demanding of
applications, and delivers excellent performance even at high loads. Built-in
database support means that you can begin creating data-driven
applications immediately, XML support makes it suitable for the new
generation of XML-enabled applications, and the extensible architecture
makes it easy for developers to use it as a framework to build their own
custom modules. Toss in a great manual, a knowledgeable developer
community and a really low price (can you spell f-r-e-e?) and you've got the
makings of a winner!


My goal in this series of tutorials is very simple: I'll be teaching you the
basics of using PHP, and showing you why I think it's the best possible tool
for Web application development today. I'll be making no assumptions about
your level of knowledge, other than that you can understand basic HTML and
have a sense of humor. And before you ask... Yes, this series covers both
PHP 4 and PHP 5, with new PHP 5 features flagged for easy reference.


Let's get going!


The Right Environment
PHP is typically used in combination with a Web server like Apache. Requests
for PHP scripts are received by the Web server, and are handled by the PHP
interpreter. The results obtained after execution are returned to the Web
server, which takes care of transmitting them to the client browser. Within
the PHP script itself, the sky's the limit - your script can perform calculations,
process user input, interact with a database, read and write files... Basically,
anything you can do with a regular programming language, you can do
inside your PHP scripts.


From the above, it is clear that in order to begin using PHP, you need to have
a proper development environment set up.


This series will focus on using PHP with the Apache Web server on Linux, but
you can just as easily use PHP with Apache on Windows, UNIX and Mac OS.
Detailed instructions on how to set up this development environment on
each platform are available in the online manual, at http://www.php.net/
manual/en/installation.php - or you can just download a copy of PHP 5 from
http://www.php.net and read the installation instructions.


Go do that now, and come back when you've successfully installed and
tested PHP.


Start Me Up
There's one essential concept that you need to get your mind around before
we proceed further. Unlike CGI scripts, which require you to write code to
output HTML, PHP lets you embed PHP code in regular HTML pages, and
execute the embedded PHP code when the page is requested.


These embedded PHP commands are enclosed within special start and end
tags, like this:

<?php

... PHP code ...

?>

Here's a simple example that demonstrates how PHP and HTML can be
combined:

<html>
<head></head>
<body>

Agent: So who do you think you are, anyhow?
<br />

<?php
// print output
echo 'Neo: I am Neo, but my people call me The One.';
?>
</body>
</html>

Not quite your traditional "Hello, World" program... but then again, I always
thought tradition was over-rated.


Save the above script to a location under your Web server document root,
with a .php extension, and browse to it. You'll see something like this:




Look at the HTML source:

<html>
<head></head>
<body>
Agent: So who do you think you are, anyhow?
<br />
Neo: I am Neo, but my people call me The One.
</body>
</html>

What just happened? When you requested the script above, Apache
intercepted your request and handed it off to PHP. PHP then parsed the
script, executing the code between the <?php...?> marks and replacing it
with the output of the code run. The result was then handed back to the
server and transmitted to the client. Since the output contained valid HTML,
the browser was able to render it for display to the user.


A close look at the script will reveal the basic syntactical rules of PHP. Every
PHP statement ends in a semi-colon. This convention is identical to that used
in Perl, and omitting the semi-colon is one of the most common mistakes
newbies make. That said, it is interesting to note that a semi-colon is not
needed to terminate the last line of a PHP block. The PHP closing tag
includes a semi-colon, therefore the following is perfectly valid PHP code:

<?php

// print output
echo 'Neo: I am Neo, but my people call me The One.'

?>



It's also possible to add comments to your PHP code, as I've done in the
example above. PHP supports both single-line and multi-line comment
blocks:

<?php

// this is a single-line comment
/* and this is a
multi-line
comment */

?>

Blank lines within the PHP tags are ignored by the parser. Everything outside
the tags is also ignored by the parser, and returned as-is. Only the code
between the tags is read and executed.


A Case of Identity
Variables are the bread and butter of every programming language... and
PHP has them too. A variable can be thought of as a programming construct
used to store both numeric and non-numeric data; the contents of a variable
can be altered during program execution. Finally, variables can be compared
with each other, and you - the programmer - can write code that performs
specific actions on the basis of this comparison.


PHP supports a number of different variable types: integers, floating point
numbers, strings and arrays. In many languages, it's essential to specify the
variable type before using it: for example, a variable may need to be
specified as type integer or type array. Give PHP credit for a little
intelligence, though: it automagically determines variable type by the
context in which it is being used!


Every variable has a name. In PHP, a variable name is preceded by a dollar
($) symbol and must begin with a letter or underscore, optionally followed
by more letters, numbers and/or underscores. For example, $popeye, $one
and $INCOME are all valid PHP variable names, while $123 and $48hrs are
invalid.


Note that variable names in PHP are case sensitive, so $me is different from
$Me or $ME.

Here's a simple example that demonstrates PHP's variables:
<html>
<head></head>
<body>

Agent: So who do you think you are, anyhow?
<br />

<?php
// define variables
$name = 'Neo';
$rank = 'Anomaly';
$serialNumber = 1;

// print output
echo "Neo: I am <b>$name</b>, the <b>$rank</b>. You can
call me by my serial number, <b>$serialNumber</b>.";
?>

</body>
</html>

Here, the variables $name, $rank and $serialNumber are first defined with
string and numeric values, and then substituted in the echo() function call.
The echo() function, along with the print() function, is commonly used to
print data to the standard output device (here, the browser). Notice that I've
included HTML tags within the call to echo(), and those have been rendered
by the browser in its output. You can do this too. Really.


An Equal Music
To assign a value to a variable, you use the assignment operator: the =
symbol. This is used to assign a value (the right side of the equation) to a
variable (the left side). The value being assigned need not always be fixed; it
could also be another variable, an expression, or even an expression
involving other variables, as below:
<?php

$age = $dob + 15;

?>

Interestingly, you can also perform more than one assignment at a time.
Consider the following example, which assigns three variables the same
value simultaneously:

<?php

$angle1 = $angle2 = $angle3 = 60;

?>


Not My Type
Every language has different types of variable - and PHP is no exception. The
language supports a wide variety of data types, including simple numeric,
character, string and Boolean types, and more complex arrays and objects.
Here's a quick list of the basic ones, with examples:


     Boolean: The simplest variable type in PHP, a Boolean variable, simply
     specifies a true or false value. <?php

     $auth = true;

     ?>
     Integer: An integer is a plain-vanilla whole number like 75, -95, 2000
     or 1. <?php

     $age = 99;

     ?>
      Floating-point: A floating-point number is typically a fractional
      number such as 12.5 or 3.141592653589. Floating point numbers may
      be specified using either decimal or scientific notation. <?php

      $temperature = 56.89;

      ?>
      String: A string is a sequence of characters, like "hello" or
      "abracadabra". String values may be enclosed in either double quotes
      ("") or single quotes(''). (Quotation marks within the string itself can
      be "escaped" with a backslash (\) character.) String values enclosed in
      double quotes are automatically parsed for special characters and
      variable names; if these are found, they are replaced with the
      appropriate value. Here's an example: <?php

      $identity = 'James Bond';
      $car = 'BMW';

      // this would contain the string "James Bond drives a
      BMW"
      $sentence = "$identity drives a $car";
      echo $sentence;

      ?>
To learn more about PHP's data types, visit http://www.php.net/manual/en/
language.types.php.


Market Value
If variables are the building blocks of a programming language, operators
are the glue that let you build something useful with them. You've already
seen one example of an operator - the assignment operator -, which lets you
assign a value to a variable. Since PHP believes in spoiling you, it also comes
with operators for arithmetic, string, comparison and logical operations.
A good way to get familiar with operators is to use them to perform
arithmetic operations on variables, as in the following example:

<html>
<head>
</head>
<body>

<?php

// set quantity
$quantity = 1000;

// set original and current unit price
$origPrice = 100;
$currPrice = 25;

// calculate difference in price
$diffPrice = $currPrice - $origPrice;

// calculate percentage change in price
$diffPricePercent = (($currPrice - $origPrice) * 100)/
$origPrice

?>

<table border="1" cellpadding="5" cellspacing="0">
<tr>
<td>Quantity</td>
<td>Cost price</td>
<td>Current price</td>
<td>Absolute change in price</td>
<td>Percent change in price</td>
</tr>
<tr>
<td><?php echo $quantity ?></td>
<td><?php    echo   $origPrice ?></td>
<td><?php    echo   $currPrice ?></td>
<td><?php    echo   $diffPrice ?></td>
<td><?php    echo   $diffPricePercent ?>%</td>
</tr>
</table>

</body>
</html>

Looks complex? Don't be afraid - it's actually pretty simple. The meat of the
script is at the top, where I've set up variables for the unit cost and the
quantity. Next, I've performed a bunch of calculations using PHP's various
mathematical operators, and stored the results of those calculations in
different variables. The rest of the script is related to the display of the
resulting calculations in a neat table.


If you'd like, you can even perform an arithmetic operation simultaneously
with an assignment, by using the two operators together. The two code
snippets below are equivalent:

<?php

// this...
$a = 5;
$a = $a + 10;

// ... is the same as this
$a = 5;
$a += 10;

?>

If you don't believe me, try echoing them both.


Stringing Things Along
Why stop with numbers? PHP also allows you to add strings with the string
concatenation operator, represented by a period (.). Take a look:

<?php

//   set up some string variables
$a   = 'the';
$b   = 'games';
$c   = 'begin';
$d   = 'now';

// combine them using the concatenation operator
// this returns 'the games begin now<br />'
$statement = $a.' '.$b.' '.$c.' '.$d.'<br />';
print $statement;

// and this returns 'begin the games now!'
$command = $c.' '.$a.' '.$b.' '.$d.'!';
print $command;

?>

As before, you can concatenate and assign simultaneously, as below:

<?php

// define string
$str = 'the';

// add and assign
$str .= 'n';

// str now contains "then"
echo $str;

?>
To learn more about PHP's arithmetic and string operators, visit http://
www.php.net/manual/en/language.operators.arithmetic.php and http://
www.php.net/manual/en/language.operators.string.php.


That's about it for this tutorial. You now know all about the basic building
blocks and glue of PHP - its variables and operators. In Part Two of this
series, I'll be using these fundamental concepts to demonstrate PHP's
powerful form processing capabilities.




Part 2:
Not What You Expected
In Part One of this series, I gave you a brief introduction to PHP, and how it
fits into your Web application development environment. I also taught you
the basics of PHP variables, and showed you how to add, multiply and
concatenate them together.


Now that you know the basics, it's time to focus in on one of PHP's nicer
features - its ability to automatically receive user input from a Web form and
convert it into PHP variables. If you're used to writing Perl code to retrieve
form values in your CGI scripts, PHP's simpler approach is going to make
you weep with joy. So get that handkerchief out, and scroll on down.


Form...
Forms have always been one of quickest and easiest ways to add
interactivity to your Web site. A form allows you to ask customers if they like
your products, casual visitors for comments on your site, and pretty girls for
their phone numbers. And PHP can simplify the task of processing the data
generated from a Web-based form substantially, as this first example
demonstrates. This example contains two scripts, one containing an HTML
form (named form.htm) and the other containing the form processing logic
(message.php). Here's form.htm:
<html>
<head></head>
<body>
<form action="message.php" method="post">
Enter your message: <input type="text" name="msg"
size="30">
<input type="submit" value="Send">
</form>
</body>
</html>

The critical line in this page is the <form> tag



<form action="message.php" method="post">
...
</form>

As you probably already know, the "action" attribute of the <form> tag
specifies the name of the server-side script (message.php in this case) that
will process the information entered into the form. The "method" attribute
specifies how the information will be passed.


...And Function
Now for the other half of the puzzle: the message.php script. This script
reads the data submitted by the user and "does something with it". Here is
message.php:



<html>
<head></head>
<body>

<?php
// retrieve form data
$input = $_POST['msg'];
// use it
echo "You said: <i>$input</i>";
?>

</body>
</html>

When you enter some data into form.htm (let's say "Boo"), and submit it,
the form processor message.php will read it and display it to you ("You
said: Boo"). Thus, whenever a form is submitted to a PHP script, all variable-
value pairs within that form automatically become available for use within
the script, through a special PHP container variable: $_POST. You can then
access the value of the form variable by using its "name" inside the $_POST
container, as I did in the script above.


Obviously, PHP also supports the GET method of form submission. All you
need to do is change the "method" attribute to "get", and retrieve values
from $_GET instead of $_POST. The $_GET and $_POST variables are
actually a special type of PHP animal called an array, which I'll be teaching
you about shortly. Don't worry too much about it at the moment, just make
sure you're comfortable with retrieving simple values from a form with PHP,
and then scroll on down to learn about some more operators that are useful
in this context.


Operating With Extreme Caution
Thus far, the scripts we've discussed have been pretty dumb. All they've
done is add numbers and strings, and read back to you the data you typed
in yourself - not exactly overwhelming. In order to add some intelligence to
your scripts, you need to know how to construct what geeks call a
"conditional statement" - a statement which lets your script perform one of a
series of possible actions based on the result of a comparison test. And since
the basis of a conditional statement is comparison, you first need to know
how to compare two variables and determine whether they're identical or
different.


You've already seen some of PHP's arithmetic and string operators. However,
the language also comes with operators designed specifically to compare two
values: the so-called "comparison operators". Here's an example that
demonstrates them in action:



<?php

/* define some variables */
$mean = 9;
$median = 10;
$mode = 9;

// less-than operator
// returns true if left side is less than right
// returns true here
$result = ($mean < $median);
print "result is $result<br />";

// greater-than operator
// returns true if left side is greater than right
// returns false here
$result = ($mean > $median);
print "result is $result<br />";

// less-than-or-equal-to operator
// returns true if left side is less than or equal to right
// returns false here
$result = ($median <= $mode);
print "result is $result<br />";

// greater-than-or-equal-to operator
// returns true if left side is greater than or equal to
right
// returns true here
$result = ($median >= $mode);
print "result is $result<br />";

// equality operator
// returns true if left side is equal to right
// returns true here
$result = ($mean == $mode);
print "result is $result<br />";

// not-equal-to operator
// returns true if left side is not equal to right
// returns false here
$result = ($mean != $mode);
print "result is $result<br />";

// inequality operator
// returns true if left side is not equal to right
// returns false here
$result = ($mean <> $mode);
print "result is $result";

?>

The result of a comparison test is always Boolean: either true (1) or false (0
- which doesn't print anything). This makes comparison operators an
indispensable part of your toolkit, as you can use them in combination with a
conditional statement to send a script down any of its multiple action paths.


PHP 4.0 also introduced a new comparison operator, which allows you to test
both for equality and type: the === operator. The following example
demonstrates it:



<?php
/* define two variables */
$str = '10';
$int = 10;

/* returns true, since both variables contain the same
value */
$result = ($str == $int);
print "result is $result<br />";

/* returns false, since the variables are not of the same
type even though they have the same value */
$result = ($str === $int);
print "result is $result<br />";

/* returns true, since the variables are the same type and
value */
$anotherInt = 10;
$result = ($anotherInt === $int);
print "result is $result";

?>

Read more about PHP's comparison operators at http://www.php.net/
manual/en/language.operators.comparison.php.


A Question of Logic
In addition to the comparison operators I used so liberally above, PHP also
provides four logical operators, which are designed to group conditional
expressions together. These four operators - logical AND, logical OR, logical
XOR and logical NOT - are illustrated in the following example:



<?php
/* define some variables */
$auth = 1;
$status = 1;
$role = 4;

/* logical AND returns true if all conditions are true */
// returns true
$result = (($auth == 1) && ($status != 0));
print "result is $result<br />";

/* logical OR returns true if any condition is true */
// returns true
$result = (($status == 1) || ($role <= 2));
print "result is $result<br />";

/* logical NOT returns true if the condition is false and
vice-versa */
// returns false
$result = !($status == 1);
print "result is $result<br />";

/* logical XOR returns true if either of two conditions are
true, or returns false if both conditions are true */
// returns false
$result = (($status == 1) xor ($auth == 1));
print "result is $result<br />";

?>

Logical operators play an important role in building conditional statements,
as they can be used to link together related conditions simply and elegantly.
View more examples of how they can be used at http://www.php.net/
manual/en/language.operators.logical.php.


Older But Not Wiser
Now that you've learnt all about comparison and logical operators, I can
teach you about conditional statements. As noted earlier, a conditional
statement allows you to test whether a specific condition is true or false, and
perform different actions on the basis of the result. In PHP, the simplest form
of conditional statement is the if() statement, which looks something like
this:



if (condition) {
    do this!
}

The argument to if()is a conditional expression, which evaluates to either
true or false. If the statement evaluates to true, all PHP code within the curly
braces is executed; if it does not, the code within the curly braces is skipped
and the lines following the if() construct are executed.


Let me show you how the if() statement works by combining it with a
form. In this example, the user is asked to enter his or her age.



<html>
<head></head>
<body>
<form action="ageist.php" method="post">
Enter your age: <input name="age" size="2">
</form>
</body>
</html>

Depending on whether the entered age is above or below 21, a different
message is displayed by the ageist.php script:



<html>
<head></head>
<body>

<?php
// retrieve form data
$age = $_POST['age'];
// check entered value and branch
if ($age >= 21) {
      echo 'Come on in, we have alcohol and music awaiting
you!';
}
if ($age < 21) {
      echo "You're too young for this club, come back when
you're a little older";
}
?>

</body>
</html>


If Not This, Then What?
In addition to the if() statement, PHP also offers the if-else construct,
used to define a block of code that gets executed when the conditional
expression in the if() statement evaluates as false.


The if-else construct looks like this:



if (condition) {
    do this!
    }
else {
    do this!
}
This construct can be used to great effect in the last example: we can
combine the two separate if()statements into a single if-else statement.



<html>
<head></head>
<body>

<?php
// retrieve form data
$age = $_POST['age'];
// check entered value and branch
if ($age >= 21) {
    echo 'Come on in, we have alcohol and music awaiting
you!';
    }
else {
    echo "You're too young for this club, come back when
you're a little older";
}
?>

</body>
</html>


Spreading Confusion
If the thought of confusing people who read your code makes you feel warm
and tingly, you're going to love the ternary operator, represented by a
question mark (?). This operator, which lets you make your conditional
statements almost unintelligible, provides shortcut syntax for creating a
single-statement if-else block. So, while you could do this:



<?php
if ($numTries > 10) {
      $msg = 'Blocking your account...';
    }
else {
    $msg = 'Welcome!';
}

?>

You could also do this, which is equivalent (and a lot more fun):



<?php

$msg = $numTries > 10 ? 'Blocking your account...' :
'Welcome!';

?>

PHP also lets you "nest" conditional statements inside each other. For
example, this is perfectly valid PHP code:



<?php

if ($day == 'Thursday') {
    if ($time == '0800') {
        if ($country == 'UK') {
            $meal = 'bacon and eggs';
        }
    }
}

?>
Another, more elegant way to write the above is with a series of logical
operators:



<?php

if ($day == 'Thursday' && $time == '0800' && $country ==
'UK') {
    $meal = 'bacon and eggs';
}

?>


The Daily Special
PHP also provides you with a way of handling multiple possibilities: the if-
elseif-else construct. A typical if-elseif-else statement block would
look like this:



if (first condition is true) {
    do this!
    }
elseif (second condition is true) {
    do this!
    }
elseif (third condition is true) {
    do this!
    }
  ... and so on ...
else {
      do this!
}

And here's an example that demonstrates how to use it:
<html>
<head></head>
<body>
<h2>Today's Special</h2>
<p>
<form method="get" action="cooking.php">
<select name="day">
<option value="1">Monday/Wednesday
<option value="2">Tuesday/Thursday
<option value="3">Friday/Sunday
<option value="4">Saturday
</select>
<input type="submit" value="Send">
</form>
</body>
</html>

As you can see, this is simply a form which allows you to pick a day of the
week. The real work is done by the PHP script cooking.php:



<html>
<head></head>
<body>

<?php
// get form selection
$day = $_GET['day'];
// check value and select appropriate item
if ($day == 1) {
    $special = 'Chicken in oyster sauce';
    }
elseif ($day == 2) {
    $special = 'French onion soup';
    }
elseif ($day == 3) {
    $special = 'Pork chops with mashed potatoes and green
salad';
    }
else {
    $special = 'Fish and chips';
}
?>

<h2>Today's special is:</h2>
<?php echo $special; ?>
</body>
</html>

In this case, I've used the if-elseif-else control structure to assign a
different menu special to each combination of days. Note that as soon as
one of the if() branches within the block is found to be true, PHP will
execute the corresponding code, skip the remaining if() statements in the
block, and jump immediately to the lines following the entire if-elseif-
else block.

And that's it for now. To view more examples of conditional statements in
action, visit http://www.php.net/manual/en/language.control-
structures.php. In Part Three, I'll be bringing you more control structures,
more operators and more strange and wacky scripts - so make sure you
don't miss it!




Part 3:
Going Deeper
If you've been paying attention, you remember that in Part Two I gave you a
quick crash course in PHP's basic control structures and operators. I also
showed you how PHP can be used to process the data entered into a Web
form. In this tutorial, I'm going to delve deeper into PHP's operators and
control structures, showing you two new operators, an alternative to the if-
else() family of conditional statements, and some of PHP's more
interesting loops. So keep reading... this is just about to get interesting!


Switching Things Around
An alternative to the if-else() family of control structures is PHP's
switch-case() statement, which does almost the same thing. It looks like
this:

switch (decision-variable) {
    case first condition is true:
        do this!
    case second condition is true:
        do this!
      ... and so on...
}

Depending on the value of the decision variable, the appropriate case()
block is executed. A default block can also be created, to handle all those
occasions when the value of the decision variable does not match any of the
listed case() conditions.


I'll make this a little clearer by re-writing one of my earlier examples in
terms of the switch() statement:

<html>
<head></head>
<body>

<?php

// get form selection
$day = $_GET['day'];
// check value and select appropriate item
switch ($day) {
    case 1:
        $special     = 'Chicken in oyster sauce';
        break;
    case 2:
        $special     = 'French onion soup';
        break;
    case 3:
        $special     = 'Pork chops with mashed potatoes and
green salad';
        break;
    default:
        $special     = 'Fish and chips';
        break;
}

?>

<h2>Today's special is:</h2>
<?php echo $special ?>
</body>
</html>

There are a couple of important keywords here:


     The break keyword is used to break out of the switch() statement
     block and move immediately to the lines following it.
     The default keyword is used to execute a default set of statements
     when the variable passed to switch() does not satisfy any of the
     conditions listed within the block.
A common newbie mistake here is to forget the break at the end of every
case() block. Remember that if you forget to break out of a case() block,
PHP will continue executing the code in all the subsequent case() blocks it
encounters.


For more on the switch() statement, see http://www.php.net/manual/en/
control-structures.switch.php.
Creative Conditionals
Normally, when creating and processing forms in PHP, you would place the
HTML form in one file, and handle form processing through a separate PHP
script. However, with the power of conditional statements at your disposal,
you can combine both pages into one.


How do you do this? Simple. All you need to do is assign a name to the form
submit control, and then check whether the special $_POST container
variable contains that name when the script first loads up. If it does, the
form has already been submitted, and you can process the data; if it does
not, that the user has not submitted the form and you therefore need to
generate the initial, unfilled form. Thus, by testing for the presence or
absence of this submit variable, a clever PHP programmer can use a single
PHP script to generate both the initial form, and the output after it has been
submitted, as appropriate.


Here's a simple example:

<html>
<head></head>
<body>

<?php
/* if the "submit" variable does not exist, the form has
not been submitted - display initial page */
if (!isset($_POST['submit'])) {
?>

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
    Enter your age: <input name="age" size="2">
    <input type="submit" name="submit" value="Go">
    </form>

<?php
     }
else {
/* if the "submit" variable exists, the form has been
submitted - look for and process form data */
    // display result
    $age = $_POST['age'];
    if ($age >= 21) {
        echo 'Come on in, we have alcohol and music
awaiting you!';
        }
    else {
        echo 'You're too young for this club, come back
when you're a little older';
    }
}
?>

</body>
</html>

As you can see, the script contains two pages: the initial, empty form and
the result page generated after hitting the submit button. In order to decide
which page to display, the script first tests for the presence of the
$_POST['submit'] variable. If it doesn't find it, it assumes that the form
has yet to be submitted, and displays the initial list of days. Once the form
has been submitted, the same script will be called to process the form input.
This time, however, the $_POST['submit'] variable will be set, and so PHP
will not display the initial page, but rather the page containing the result
message.


Note that for this to work, your submit button must have a value assigned
to its "name" attribute, and you must check for that value in the primary
conditional statement. And in case you were wondering, the $_SERVER array
is a special PHP variable which always holds server information, including the
path and name of the currently executing script.
Next up, loops.


One by One
For those of you unfamiliar with the term, a loop is a control structure that
enables you to repeat the same set of php
statements or commands over and over again (the actual number of
repetitions can be a number you specify, or depend on the fulfillment of one
or more conditions).


Now, last time out you saw a few comparison and logical operators, which
help in building conditional statements. Since this segment of the tutorial is
going to focus on loops, this is an appropriate time to introduce you to PHP's
auto-increment and auto-decrement operators, which see a lot of use in this
context.


The auto-increment operator is a PHP operator designed to automatically
increment the value of the variable it is attached to by 1. It is represented
by two "plus" signs (++). This snippet of code should explain it:

<?php

// define $total as 10
$total = 10;
// increment it
$total++;
// $total is now 11
echo $total;

?>

Thus, $total++ is functionally equivalent to $total = $total + 1.


There's a corresponding auto-decrement operator (--), which does exactly
the opposite:
<?php

// define $total as 10
$total = 10;
// decrement it
$total--;
// $total is now 9
echo $total;

?>

These operators are frequently used in loops, to update the value of the loop
counter, speaking of which...


Being Square
The first - and simplest - loop to learn in PHP is the so-called while() loop,
which looks like this:

while (condition is true) {
    do this!
}

In this case, so long as the condition specified evaluates as true - remember
what you learned in Part Two? - the PHP statements within the curly braces
will continue to execute. As soon as the condition becomes false, the loop
will be broken and the statements following it will be executed.


Here's a quick example which demonstrates the while() loop:

<html>
<head></head>
<body>
<form action="squares.php" method="POST">
Print all the squares between 1 and <input type="text"
name="limit" size="4" maxlength="4">
<input type="submit" name="submit" value="Go">
</form>
</body>
</html>

This is a simple form which asks the user to enter a number. When the form
is submitted, the PHP script that is invoked should take this number and
print the squares of all the numbers between 1 and the entered value. With
a while() loop, this is simplicity itself:

<html>
<head></head>
<body>

<?php

// set variables from form input
$upperLimit = $_POST['limit'];
$lowerLimit = 1;
// keep printing squares until lower limit = upper limit
while ($lowerLimit <= $upperLimit) {
    echo ($lowerLimit * $lowerLimit).'&nbsp;';
    $lowerLimit++;
}
// print end marker
echo 'END';

?>

</body>
</html>

This script uses a while() loop to count forwards from 1 until the values of
$lowerLimit and $upperLimit are equal.

Loop First, Ask Questions Later
The while() loop executes a set of statements while a specified condition is
true. But what happens if the condition is true on the first iteration of the
loop itself? In the previous example, if you were to enter the value 0in the
form, the while() loop would not execute even once. Try it yourself and
you'll see what I mean.


If you're in a situation where you need to execute a set of statements *at
least* once, PHP offers you the do-while() loop. Here's what it looks like:

do {
    do this!
} while (condition is true)

Let's take a quick example to better understand the difference between
while() and do-while():

<?php

$x = 100;
// while loop
while ($x == 700) {
    echo "Running...";
    break;
}

?>

In this case, no matter how many times you run this PHP script, you will get
no output at all, since the value of $x is not equal to 700. But, if you ran this
version of the script:

<?php

$x = 100;
// do-while loop
do {
    echo "Running...";
    break;
} while ($x == 700);

?>

you would see one line of output, as the code within the do() block would
run once.


Let's now revise the previous PHP script so that it runs at least once,
regardless of what value is entered into the form:

<html>
<head></head>
<body>

<?php

// set variables from form input
$upperLimit = $_POST['limit'];
$lowerLimit = 1;
// keep printing squares until lower limit = upper limit
do {
     echo ($lowerLimit * $lowerLimit).'&nbsp;';
     $lowerLimit++;
} while ($lowerLimit <= $upperLimit);
// print end marker
echo ' END';

?>

</body>
</html>

Thus, the construction of the do-while() loop is such that the statements
within the loop are executed first, and the condition to be tested is checked
afterwards. This implies that the statements within the curly braces would be
executed at least once.


Read more about the while() and do-while() loops at http://
www.php.net/manual/en/control-structures.while.php and http://
www.php.net/manual/en/control-structures.do.while.php.


Doing it by Numbers
Both the while() and do-while() loops continue to iterate for as long as
the specified conditional expression remains true. But what if you need to
execute a certain set of statements a specific number of times - for example,
printing a series of thirteen sequential numbers, or repeating a particular set
of <td> cells five times? In such cases, clever programmers reach for the
for() loop...

The for() loop typically looks like this:



for (initial value of counter; condition; new value of
counter) {
    do this!
}

Looks like gibberish? Well, hang in there for a minute...the "counter" here is
a PHP variable that is initialized to a numeric value, and keeps track of the
number of times the loop is executed. Before each execution of the loop, the
"condition" is tested. If it evaluates to true, the loop will execute once more
and the counter will be appropriately incremented; if it evaluates to false,
the loop will be broken and the lines following it will be executed instead.


Here's a simple example that demonstrates how this loop can be used:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// define the number
$number = 13;
// use a for loop to calculate tables for that number
for ($x = 1; $x <= 10; $x++) {
    echo "$number x $x = ".($number * $x)."<br />";
}

?>

</body>
</html>

The first thing I've done here is define the number to be used for the
multiplication table. I've used 13 here - for no reason other than that it
rhymes with "green".


Next, I've constructed a for() loop with $x as the counter variable,
initialized it to 1. and specified that the loop should run no more than 10
times. The auto-increment operator (discussed earlier) automatically
increments the counter by 1 every time the loop is executed. Within the
loop, the counter is multiplied by the number, to create the multiplication
table, and echo() is used to display the result on the page.


Turning the Tables
As you just saw, a for() loop is a very interesting - and useful -
programming construct. The next example illustrates its usefulness in a
manner that should endear it to any HTML programmer.

<html>
<head></head>
<body>
<form method="post" action="<?php echo
$_SERVER['PHP_SELF']; ?>">
Enter number of rows <input name="rows" type="text"
size="4"> and columns <input name="columns" type="text"
size="4"> <input type="submit" name="submit" value="Draw
Table">
</form>

<?php

if (isset($_POST['submit'])) {
    echo "<table width = 90% border = '1' cellspacing = '5'
cellpadding = '0'>";
    // set variables from form input
    $rows = $_POST['rows'];
    $columns = $_POST['columns'];
    // loop to create rows
    for ($r = 1; $r <= $rows; $r++) {
        echo "<tr>";
        // loop to create columns
        for ($c = 1; $c <= $columns;$c++) {
            echo "<td>&nbsp;</td> ";
        }     echo "</tr> ";
    }
    echo "</table> ";
}

?>

</body>
</html>

As you'll see if you try coding the same thing by hand, PHP's for() loop just
saved you a whole lot of work! And it looks good too - take a look at the
source code of the dynamically generated table, and you'll see that it's nicely
formatted, with line breaks at the end of every table cell and row. This magic
is accomplished by forcing a carriage return with in every call to echo().


For more examples of the for() loop in action, visit http://www.php.net/
manual/en/control-structures.for.php.


Loops are frequently used in combination with one of PHP's more complex
data types, the animal known as the array. That's a whole topic in itself, and
in fact I'm going to discuss it in detail in the next segment of this tutorial.
Then I'm going to show you how arrays, loops and forms all work together
to make the creation of complex Web forms as easy as eating pie. All that
and more in Part Four!




Part 4:
A Big Mistake
Having spent lots of time travelling around the outer landscape of PHP -
learning all about control structures, operators and variables - you're
probably bored. You might even be thinking of dropping out right now, and
instead spending your time more constructively (or so you think) in front of
the idiot box.


That would be a big mistake. And when I say big, I mean humongous.


You see, if you forego this segment of the tutorial for the dubious charms of
Ally McBeal, you're going to miss out on one of PHP's coolest variable types.
It's a little thing called an array, and I'm not exaggerating when I tell you
that once you're on speaking terms with it, you're never going to look at a
PHP script the same way again. But hey, don't take my word for it... toss
that remote aside and come see for yourself!


Fruity Pizza
Thus far, the variables we've discussed contained only a single value, such
as:
<?php

$i = 5;

?>

However, array variables are a different kettle of fish altogether. An array is
a complex variable that allows you to store multiple values in a single
variable (which is handy when you need to store and represent related
information). Think of the array variable as a "container" variable, which can
contain one or more values. For example:



<?php

// define an array
$pizzaToppings = array('onion', 'tomato', 'cheese',
'anchovies', 'ham', 'pepperoni');
print_r($pizzaToppings);

?>

Here, $pizzaToppings is an array variable, which contains the values
'onion', 'tomato', 'cheese', 'anchovies', 'ham' and 'pepperoni'.
(Array variables are particularly useful for grouping related values together.)


print_r() is a special function that allows you to take a sneak peek inside
an array. It's more useful for debugging (finding out why your script doesn't
work) than it is for display purposes, but I'll use it here so you can see
what's going on under the surface. You do have your server running and
your browser open, right?


The various elements of the array are accessed via an index number, with
the first element starting at zero. So, to access the element 'onion', you
would use the notation $pizzaToppings[0], while 'anchovies' would be
$pizzaToppings[3] - essentially, the array variable name followed by the
index number enclosed within square braces.


PHP also allows you to replace indices with user-defined "keys", in order to
create a slightly different type of array. Each key is unique, and corresponds
to a single value within the array.



<?php

// define an array
$fruits = array('red' => 'apple', 'yellow' => 'banana',
'purple' => 'plum', 'green' => 'grape');
print_r($fruits);

?>

In this case, $fruits is an array variable containing four key-value pairs.
(The => symbol is used to indicate the association between a key and its
value.) In order to access the value 'banana', you would use the notation
$fruits['yellow'], while the value 'grape' would be accessible via the
notation $fruits['green'].


This type of array is sometimes referred to as a "hash" or "associative
array". If you've ever used Perl, you'll see the similarities to the Perl hash
variable.


Eating Italian
The simplest was to define an array variable is the array() function. Here's
how:



<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

?>

The rules for choosing an array variable name are the same as those for any
other PHP variable: it must begin with a letter or underscore, and can
optionally be followed by more letters, numbers and underscores.


Alternatively, you can define an array by specifying values for each element
in the index notation, like this:



<?php

// define   an array
$pasta[0]   = 'spaghetti';
$pasta[1]   = 'penne';
$pasta[2]   = 'macaroni';

?>

If you're someone who prefers to use keys rather than default numeric
indices, you might prefer the following example:



<?php

// define an array
$menu['breakfast'] = 'bacon and eggs';
$menu['lunch'] = 'roast beef';
$menu['dinner'] = 'lasagna';

?>
You can add elements to the array in a similar manner. For example, if you
wanted to add the element 'green olives' to the $pizzaToppings array,
you would use something like this:



<?php

// add an element to an array
$pizzaToppings[3] = 'green olives';

?>

In order to modify an element of an array, simply assign a new value to the
corresponding scalar variable. If you wanted to replace 'ham' with
'chicken', you'd use:



<?php

// modify an array
$pizzaToppings[4] = 'chicken';

?>

You can do the same using keys. The following statement modifies the
element with the key 'lunch' to a different value:



<?php

// modify an array
$menu['lunch'] = 'steak with mashed potatoes';

?>


Push And Pull
You can also add an element to the end of an existing array with the
array_push() function:



<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

// add an element to the end
array_push($pasta, 'tagliatelle');

print_r($pasta);

?>

And you can remove an element from the end of an array using the
interestingly-named array_pop() function.



<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

// remove an element from the end
array_pop($pasta);

print_r($pasta);

?>

If you need to pop an element off the top of the array, you can use the
array_shift() function:
<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

// take an element off the top
array_shift($pasta);

print_r($pasta);

?>

And the array_unshift() function takes care of adding elements to the
beginning of the array.



<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

// add an element to the beginning
array_unshift($pasta, 'tagliatelle');

print_r($pasta);

?>

The array_push() and array_unshift() functions don't work with
associative arrays; to add elements to these arrays, it's better to use the
$arr[$key] = $value notation to add new values to the array.


The explode() function splits a string into smaller components, based on a
user-specified delimiter, and returns the pieces as elements as an array.
<?php

// define CSV string
$str = 'red, blue, green, yellow';

// split into individual words
$colors = explode(', ', $str);

print_r($colors);

?>

To do the reverse, you can use the implode() function, which creates a
single string from all the elements of an array by joining them together with
a user-defined delimiter. Reversing the example above, we have:



<?php

// define array
$colors = array ('red', 'blue', 'green', 'yellow');

// join into single string with 'and'
// returns 'red and blue and green and yellow'
$str = implode(' and ', $colors);

print $str;

?>

Finally, the two examples below show how the sort() and
rsort()functions can be used to sort an array alphabetically (or
numerically), in ascending and descending order respectively:
<?php

// define an array
$pasta = array('spaghetti', 'penne', 'macaroni');

// returns the array sorted alphabetically
sort($pasta);
print_r($pasta);
print "<br />";

// returns the array sorted alphabetically in reverse
rsort($pasta);
print_r($pasta);

?>


Looping the Loop
So that takes care of putting data inside an array. Now, how about getting it
out?


Retrieving data from an array is pretty simple: all you need to do is access
the appropriate element of the array using its index number. To read an
entire array you simply loop over it, using any of the loop constructs you
learned about in Part Three of this tutorial.


How about a quick example?



<html>
<head></head>
<body>
My favourite bands are:
<ul>
<?php

// define array
$artists = array('Metallica', 'Evanescence', 'Linkin Park',
'Guns n Roses');
// loop over it and print array elements
for ($x = 0; $x < sizeof($artists); $x++) {
    echo '<li>'.$artists[$x];
}

?>

</ul>
</body>
</html>

When you run this script, here's what you'll see:




My favourite bands are:
      Metallica
      Evanescence
      Linkin Park
      Guns n Roses




In this case, I've defined an array, and then used the for() loop to: run
through it, extract the elements using the index notation, and display them
one after the other.


I'll draw your attention here to the sizeof() function. This function is one
of the most important and commonly used array functions. It returns the
size of (read: number of elements within) the array. It is mostly used in loop
counters to ensure that the loop iterates as many times as there are
elements in the array.
If you're using an associative array, the array_keys() and
array_values()functions come in handy, to get a list of all the keys and
values within the array.



<?php

// define an array
$menu = array('breakfast' => 'bacon and eggs', 'lunch' =>
'roast beef', 'dinner' => 'lasagna');

/* returns the array ('breakfast', 'lunch', 'dinner') with
numeric indices */
$result = array_keys($menu);
print_r($result);
print "<br />";

/* returns the array ('bacon and eggs', 'roast beef',
'lasagna') with numeric indices */
$result = array_values($menu);
print_r($result);

?>


What's That Noise?
There is, however, a simpler way of extracting all the elements of an array.
PHP 4.0 introduced a spanking-new loop type designed specifically for the
purpose of iterating over an array: the foreach() loop. (It is similar in
syntax to the Perl construct of the same name.) Here's what it looks like:



foreach ($array as $temp) {
    do this!
}
A foreach() loop runs once for each element of the array passed to it as
argument, moving forward through the array on each iteration. Unlike a
for() loop, it doesn't need a counter or a call to sizeof(), because it
keeps track of its position in the array automatically. On each run, the
statements within the curly braces are executed, and the currently-selected
array element is made available through a temporary loop variable.


To better understand how this works, consider this rewrite of the previous
example, using the foreach() loop:



<html>
<head></head>
<body>
My favourite bands are:
<ul>

<?php

// define array
$artists = array('Metallica', 'Evanescence', 'Linkin Park',
'Guns n Roses');
// loop over it
// print array elements
foreach ($artists as $a) {
    echo '<li>'.$a;
}

?>

</ul>
</body>
</html>

Each time the loop executes, it places the currently-selected array element
in the temporary variable $a. This variable can then be used by the
statements inside the loop block. Since a foreach() loop doesn't need a
counter to keep track of where it is in the array, it is lower-maintenance and
also much easier to read than a standard for() loop. Oh yeah... and it also
works with associative arrays, with no extra programming needed.


Music for the Masses
In addition to their obvious uses, arrays and loops also come in handy when
processing forms in PHP. For example, if you have a group of related
checkboxes or a multi-select list, you can use an array to capture all the
selected form values in a single variable, to simplify processing. Consider the
following example, which illustrates this:



<html>
<head></head>
<body>

<?php
// check for submit
if (!isset($_POST['submit'])) {
    // and display form
    ?>

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="POST">
    <input type="checkbox" name="artist[]" value="Bon
Jovi">Bon Jovi
    <input type="checkbox" name="artist[]"
value="N'Sync">N'Sync
    <input type="checkbox" name="artist[]"
value="Boyzone">Boyzone
    <input type="checkbox" name="artist[]" value="Britney
Spears">Britney Spears
    <input type="checkbox" name="artist[]" value="Jethro
Tull">Jethro Tull
    <input type="checkbox" name="artist[]" value="Crosby,
Stills & Nash">Crosby, Stills & Nash
    <input type="submit" name="submit" value="Select">
    </form>

<?php
    }
else {
    // or display the selected artists
    // use a foreach loop to read and display array
elements
    if (is_array($_POST['artist'])) {
         echo 'You selected: <br />';
         foreach ($_POST['artist'] as $a) {
            echo "<i>$a</i><br />";
             }
         }
    else {
         echo 'Nothing selected';
    }
}
?>

</body>
</html>

When the above form is submitted, PHP will automatically create an array
variable, and populate it with the items selected. This array can then be
processed with a foreach() loop, and the selected items retrieved from it.


You can do this with a multi-select list also, simply by using array notation in
the select control's "name" attribute. Try it out for yourself and see... and
make sure you tune in for the next PHP 101 tutorial, same time, same
channel.
Part 5:
Back to School
When you first started reading this series, I promised you that you'd have a
whole lot of fun. If you're the cynical type, you may be feeling that I didn't
keep my promise. After all, how much fun have you really had so far? All
you've done is learn a bunch of theoretical rules, added and subtracted
numbers from each other, learnt primitive decision-making and gone round
and round in the circular funhouse of loops. Heck, if this wasn't a PHP
tutorial, it would be kindergarten...


I hear you.


In this segment of our ongoing saga, I'm going to teach you how to do
something that's definitely not for kids. It involves getting down and dirty
with files on the disk: meeting them (shock!), reading their contents
(shriek!) and (horror of horrors!) writing data to them. All of these exciting
activities will take place under the aegis of PHP's very cool file manipulation
API, which allows you to view and modify file attributes, read and list
directory contents, alter file permissions, retrieve file contents into a variety
of native data structures, and search for files based on specific patterns.


Let's get started!


Handle With Care
I'll begin with something simple: opening a file and reading its contents.
Let's assume that somewhere on your disk, hidden under /usr/local/stuff/
that/should/be/elsewhere/recipes/, you have a text file containing the recipe
for the perfect Spanish omelette. You now wish to read the contents of this
file into a PHP script.


In order to do this, there are three distinct steps to be followed:


      Open the file and assign it a file handle.
      Interact with the file, via its handle, and extract its contents into a PHP
      variable.
      Close the file.
Here's a PHP script that does just that:



<?php

// set file to read
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/
omelette.txt' or die('Could not open file!');
// open file
$fh = fopen($file, 'r') or die('Could not open file!');
// read file contents
$data = fread($fh, filesize($file)) or die('Could not read
file!');
// close file
fclose($fh);
// print file contents
echo $data;

?>

Run this script through your Web browser, and PHP should return the
contents of the file.


Now let me explain each of the three steps above in detail:


Open the file and assign it a file handle
PHP needs a file handle to read data from a file. This file handle can be
created with the fopen() function, which accepts two arguments: the name
and path to the file, and a string indicating the "mode" in which the file is to
be opened ('r' for read).


Three different modes are available for use with the fopen() function.
Here's the list:
'r' - opens a file in read mode

'w' - opens a file in write mode, destroying existing file contents

'a' - opens a file in append mode, preserving existing file contents

Interact with the file via its handle and extract its contents into a
PHP variable
If the fopen() function is successful, it returns a file handle, $fh, which can
be used for further interaction with the file. This file handle is used by the
fread() function, which reads the file and places its contents into a
variable.


The second argument to fread() is the number of bytes to be read. You
can usually obtain this information through the filesize() function, which
- who'd have guessed it?!- returns the size of the file in bytes.


Close the file
This last step is not strictly necessary as PHP closes the file automatically
once it reaches the end of the script, but it's a good habit to develop.
Explicitly closing the file with fclose() has two advantages: it ties up loose
ends in your script, and it wins you lots of good karma from the PHP
community.


You probably haven't see the die() function before, either. This function is
mostly used as a primitive error-handling mechanism. In the event of a fatal
error, such as the file path being invalid or the file permissions being such
that PHP cannot read it, die() terminates script processing and optionally
displays a user-specified error message indicating why it committed suicide.


Different Strokes
An alternative method of reading data from a file is the very cool file()
function, which reads the entire file into an array (remember them?) with
one line of code. Each element of the array then contains one line from the
file. To display the contents of the file, simply iterate over the array in a
foreach() loop and print each element.

The following example demonstrates:



<?php

// set file to read
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/
omelette.txt' or die('Could not read file!');
// read file into array
$data = file($file) or die('Could not read file!');
// loop through array and print each line
foreach ($data as $line) {
     echo $line;
}

?>

In this example, the file() command opens the file, reads it into an array
and closes the file - all in one, single, elegant movement. Each element of
the array now corresponds to a line from the file. It's easy to print the file's
contents now - just reach for that mainstay of array processing, the
foreach() loop.

Don't want the data in an array? Try the file_get_contents() function,
new in PHP 4.3.0 and PHP 5.0, which reads the entire file into a string:



<?php

// set file to read
$file = '/usr/local/stuff/that/should/be/elsewhere/recipes/
omelette.txt' ;
// read file into string
$data = file_get_contents($file) or die('Could not read
file!');
// print contents
echo $data;

?>

Who am I kidding? I always use the one-line functions noted above instead
of the three-line sequence of fopen(), fread() and fclose(). Laziness
conquers all.


When Laziness is a Virtue
PHP also offers two very useful functions to import files into a PHP script: the
include() and require()functions. These functions can be used to suck
external files lock, stock and barrel into a PHP script, which is very handy if,
for example, you have a modular application which has its code broken down
across files in separate locations.


The best way to understand the utility of the include() and require()
functions is with an example. Assume that on your Web site you have a
standard menu bar at the top of every page, and a standard copyright notice
in the bottom. Instead of copying and pasting the header and footer code on
each individual page, PHP gurus simply create separate files for the header
and footer, and import them at the top and bottom of each script. This also
makes a change to the site design easier to implement: instead of manually
editing a gazillion files, you simply edit two, and the changes are reflected
across your entire site instantaneously.


Let's see a real live example of this in action. Create the header in one file,
called header.php:



<html>
<head>
<title><?php echo $page['title'];?></title>
</head>
<body>
<!-- top menu bar -->
<table width="90%" border="0" cellspacing="5"
cellpadding="5">
<tr>
<td><a href="#">Home</a></td>
<td><a href="#">Site Map</a></td>
<td><a href="#">Search</a></td>
<td><a href="#">Help</a></td>
</tr>
</table>
<!-- header ends -->

Next, create the footer with the copyright notice in a second file,
footer.php:



<!-- footer begins -->
<br />
<center>Your usage of this site is subject to its published
<a href="tac.html">terms and conditions</a>. Data is
copyright Big Company Inc, 1995-<?php echo date("Y",
mktime()); ?></center>
</body>
</html>

Finally, create a script to display the main content of your site, and
include() the header and footer at appropriate places:



<?php

// create an array to set page-level variables
$page = array();
$page['title'] = 'Product Catalog';
/* once the file is imported, the variables set above will
become available to it */

// include the page header
include('header.php');

?>

<!-- HTML content here -->

<?php

// include the page footer
include('footer.php');

?>

Now, when you run the script above, PHP will automatically read in the
header and footer files, merge them with the HTML content, and display the
complete page to you. Simple, isn't it?


Notice that you can even write PHP code inside the files being imported.
When the file is first read in, the parser will look for <?php...?> tags, and
automatically execute the code inside it. (If you're familiar with JavaScript,
you can use this feature to replicate functionality similar to that of the
onLoad() page event handler in JavaScript.)

PHP also offers the require_once() and include_once()functions, which
ensure that a file which has already been read is not read again. This can
come in handy if you have a situation in which you want to eliminate
multiple reads of the same include file, either for performance reasons or to
avoid corruption of the variable space.


A quick note on the difference between the include() and
require()functions: the require()function returns a fatal error if the
named file cannot be found and halts script processing, while the
include() function returns a warning but allows script processing to
continue.


Writing to Ma
After everything you've just read, you've probably realized that reading a file
is not exactly brain surgery. So let's proceed to something slightly more
difficult - writing to a file.


The steps involved in writing data to a file are almost identical to those
involved in reading it: open the file and obtain a file handle, use the file
handle to write data to it, and close the file. There are two differences: first,
you must fopen() the file in write mode ('w' for write), and second,
instead of using the fread() function to read from the file handle, use the
fwrite() function to write to it. Take a look:



<?php

// set file to write
$file = '/tmp/dump.txt';
// open file
$fh = fopen($file, 'w') or die('Could not open file!');
// write to file
fwrite($fh, "Look, Ma, I wrote a file! ") or die('Could not
write to file');
// close file
fclose($fh);

?>

When you run this script, it should create a file named dump.txt in /tmp,
and write a line of text to it, with a carriage return at the end. Notice that
double quotes are needed to convert into a carriage return.
The fopen(), fwrite() and fread() functions are all binary-safe, which
means you can use them on binary files without worrying about damage to
the file contents. Read more about many of the issues related to binary-safe
file manipulation on different platforms at http://www.php.net/manual/en/
function.fopen.php.


If I've spoiled you by showing you the one-line shortcut functions for file
reads, let me damage you further by introducing you to the
file_put_contents() function, new in PHP 5.0, which takes a string and
writes it to a file in a single line of code.



<?php

// set file to write
$filename = '/tmp/dump.txt';
// write to file
file_put_contents($filename, "Look, Ma, I wrote a file! ")
or die('Could not write to file');

?>

Bear in mind that the directory in which you're trying to create the file must
exist before you can write to it. Forgetting this important step is a common
cause of script errors.


Information is Power
PHP also comes with a bunch of functions that allow you to test the status of
a file - for example to find out whether it exists, whether it's empty, whether
it's readable or writable, and whether it's a binary or text file. Of these, the
most commonly used operator is the file_exists() function, which is
used to test for the existence of a specific file.


Here's an example which asks the user to enter the path to a file in a Web
form, and then returns a message displaying whether or not the file exists:
<html>
<head>
</head>
<body>

<?php
// if form has not yet been submitted
// display input box
if (!isset($_POST['file'])) {
?>

    <form action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
    Enter file path <input type="text" name="file">
    </form>

<?php
}
// else process form input
else {
    // check if file exists
    // display appropriate message
    if (file_exists($_POST['file'])) {
        echo 'File exists!';
        }
    else {
        echo 'File does not exist!';
    }
}
?>

</body>
</html>
There are many more such functions. Here's a brief list, followed by an
example that builds on the previous one to provide more information on the
file specified by the user.


     is_dir() - returns a Boolean indicating whether the specified path is
     a directory
     is_file() - returns a Boolean indicating whether the specified file is
      a regular file
      is_link() - returns a Boolean indicating whether the specified file is
      a symbolic link
      is_executable() - returns a Boolean indicating whether the
      specified file is executable
      is_readable()- returns a Boolean indicating whether the specified
      file is readable
      is_writable()- returns a Boolean indicating whether the specified
      file is writable
      filesize() - gets size of file
      filemtime() - gets last modification time of file
      filamtime() - gets last access time of file
      fileowner() - gets file owner
      filegroup() - gets file group
      fileperms() - gets file permissions
      filetype() - gets file type
This script asks for a file name as input and uses the functions above to
return information on it.

<html>
<head>
</head>
<body>

<?php
/* if form has not yet been submitted, display input box */
if (!isset($_POST['file'])) {
?>
    <form action="<?php echo $_SERVER['PHP_SELF']; ?>"
method="post">
    Enter file path <input type="text" name="file">
    </form>

<?php
}
// else process form input
else {
    echo 'File name: <b>'.$_POST['file'] .'</b><br />';
    /* check if file exists and display appropriate message
*/
    if (file_exists($_POST['file'])) {
        // print file size
        echo 'File size: '.filesize($_POST['file']).'
bytes<br />';
        // print file owner
        echo 'File owner:
'.fileowner($_POST['file']).'<br />';
        // print file group
        echo 'File group:
'.filegroup($_POST['file']).'<br />';
        // print file permissions
        echo 'File permissions:
'.fileperms($_POST['file']).'<br />';
        // print file type
        echo 'File type: '.filetype($_POST['file']).'<br /
>';
        // print file last access time
        echo 'File last accessed on: '.date('Y-m-d',
fileatime($_POST['file'])).'<br />';
        // print file last modification time
        echo 'File last modified on: '.date('Y-m-d',
filemtime($_POST['file'])).'<br />';
        // is it a directory?
        if (is_dir($_POST['file'])) {
               echo 'File is a directory <br />';
          }
          // is it a file?
          if (is_file($_POST['file'])) {
              echo 'File is a regular file <br />';
          }
          // is it a link?
          if (is_link($_POST['file'])) {
              echo 'File is a symbolic link <br />';
          }
          // is it executable?
          if (is_executable($_POST['file'])) {
              echo 'File is executable <br />';
          }
          // is it readable?
          if (is_readable($_POST['file'])) {
              echo 'File is readable <br />';
          }
          // is it writable?
          if (is_writable($_POST['file'])) {
              echo 'File is writable <br />';
          }
     }
     else {
         echo 'File does not exist! <br />';
     }
}
?>

</body>
</html>

And here's what the output might look like:

File name: /usr/local/apache/logs/error_log
File size: 53898 bytes
File   owner: 0
File   group: 0
File   permissions: 33188
File   type: file
File   last accessed on: 2004-05-26
File   last modified on: 2004-06-20
File   is a regular file
File   is readable



Breaking Eggs
So now you know how to read a file, write to it, and test its status. Let's look
at some examples of what you can do with this new-found power.


Let's go back to my Spanish omelette recipe. Let's suppose I'm feeling
generous, and I decide that I'd like to hear what people really think about
my culinary skills. Since I have a bunch of recipes that I'd like to share with
people, and since they all look something like this:

SPANISH OMELETTE
INGREDIENTS:
- 1 chopped onion
- 1 chopped tomato
- 1/2 chopped green pepper
- 4 beaten eggs
- Salt and pepper to taste
METHOD:
1. Fry onions in a pan
2. Pour beaten eggs over onions and fry gently
3. Add tomatoes, green pepper, salt and pepper to taste
4. Serve with toast or bread



I need a quick way to convert them all into HTML so that they look
presentable on my Web site. We've already established that I'm lazy, so
fuggedaboutme re-creating the recipes in HTML. Instead, I'll have PHP do
the heavy lifting for me:

<html>
<head></head>
<body>

<?php
// read recipe file into array
$data = file('/usr/local/stuff/that/should/be/elsewhere/
omelette.txt') or die('Could not read file!');
/* first line contains title: read it into variable */
$title = $data[0];
// remove first line from array
array_shift($data);
?>

<h2><?php echo $title; ?></h2>

<?php
/* iterate over content and print it */
foreach ($data as $line) {
    echo nl2br($line);
}
?>

</body>
</html>

I've used the file() function to read the recipe into an array, and assign
the first line (the title) to a variable. That title is then printed at the top of
the page. Since the rest of the data is fairly presentable as is, I can simply
print the lines to the screen one after the other. Line breaks are
automatically handled for me by the extremely cool nl2br() function, which
converts regular text linebreaks into the HTML equivalent, the <br /> tag.
The end result: an HTML-ized version of my recipe that the world can marvel
at. Take a look:

<html>
<head></head><body>

<h2>SPANISH OMELETTE
</h2>
INGREDIENTS:<br />
- 1 chopped onion<br />
- 1 chopped tomato<br />
- 1/2 chopped green pepper<br />
- 4 beaten eggs<br />

- Salt and pepper to taste<br />
METHOD:<br />
1. Fry onions in a pan<br />
2. Pour beaten eggs over onions and fry gently<br />
3. Add tomatoes, green pepper, salt and pepper to
taste<br />
4. Serve with toast or bread<br />

</body>
</html>



If the elegance and creative simplicity of my Spanish omelette recipe has left
you speechless, I'm not surprised - many people feel that way. Until you get
your voice back: Ciao... and make sure you come back to work through Part
Six of PHP 101, which discusses creating your own reusable functions.




Part 6:
A Little Knowledge
If you've been taking your regular dose of PHP 101, you know now enough
about PHP to write simple programs of your own. However, these programs
will be "procedural" or linear - the statements in them will be executed
sequentially, one after another - simply because that's the only programming
style I've used so far.


You know what they say about a little knowledge being a dangerous thing...
as your PHP scripts become more and more complex, it's only a matter of
time before you bump your head against the constraints of the procedural
method, and begin looking for a more efficient way of structuring your PHP
programs.


That's where Part Six of PHP 101 comes in. In this tutorial I'm going to
introduce you to a new way of doing things, where code doesn't run in a
straight line, but twists, leaps and bounds across the landscape of your
script. Most of this activity is accomplished through a programming construct
called a "function", and this tutorial teaches you how to build them (once),
use them (many times), pass them arguments and have them return values,
and generally make your scripts more compact, efficient and maintainable.


In Plain English
Ask a geek to define the term "function", and he'll probably mumble
something about a function being "a block of statements that can be
grouped together as a named entity." Since this is a tutorial on PHP, not an
introductory course in Greek, I'll translate that for you: a function is simply a
set of program statements which perform a specific task, and which can be
"called", or executed, from anywhere in your program.


Every programming language comes with its own built-in functions, and
typically also allows developers to define their own functions. For example, if
I had a profit statement for the year on my desk, and I wanted to inflate
each number by 35%, I could call my neighborhood accounting firm and get
them to do it for me... or I could write a simple PHP function called
cheatTheShareholders() and have it do the work for me (it's faster, plus
PHP doesn't bill by the hour).


There are three important reasons why functions are a Good Thing™. First:
user-defined functions allow you to separate your code into easily
identifiable subsections - which are easier to understand and debug. Second:
functions make your program modular, allowing you to write a piece of code
once and then re-use it multiple times within the same program. And third:
functions simplify code updates or changes, because the change needs only
to be implemented in a single place (the function definition). Functions thus
save time, money and electrons... and I know the electrons at least will
thank you!


Monday Morning Blues
To see how a function works, look at the following example:

<?php

// define a function
function myStandardResponse() {
    echo "Get lost, jerk!<br /><br />";
}

// on the bus
echo "Hey lady, can you spare a dime? <br />";
myStandardResponse();

// at the office
echo "Can you handle Joe's workload, in addition to your
own, while he's in Tahiti for a month? You'll probably need
to come in early and work till midnight, but we are
confident you can handle it. Oh, and we can't pay you extra
because of budgetary constraints...<br />";
myStandardResponse();
// at the party
echo "Hi, haven't I seen you somewhere before?<br />";
myStandardResponse();

?>



Here's what the output might look like:

Hey lady, can you spare a dime?
Get lost, jerk!

Can you handle Joe's workload, in addition to your own,
while he's in Tahiti for a month?
You'll probably need to come in early and work till
midnight, but we are confident you can
handle it. Oh, and we can't pay you extra because of
budgetary constraints...
Get lost, jerk!

Hi, haven't I seen you somewhere before?
Get lost, jerk!
(Sure it's rude, but it does demonstrate how a function allows you to reuse
pieces of code.)


The first thing I've done in the script above is define a new function, with the
function keyword. This keyword is followed by the name of the function,
which in this case is myStandardResponse(). All the program code
attached to that function is then placed within a pair of curly braces - and
this program code can contain loops, conditional statements, calls to other
user-defined functions, or calls to other PHP functions.
Of course, defining a function is only half of the puzzle; for it to be of any
use at all, you need to "invoke" it. In PHP, as in a million other languages,
this is accomplished by calling the function by its name, as I've done in the
example above. Calling a user-defined function is identical to calling a built-
in PHP function like echo() or explode().
Here's the typical format for a function:
function function_name (optional function arguments) {
    statement 1...
    statement 2...
    .
    .
    .
    statement n...
}


Having an Argument... or Two
Functions like the one you saw in the previous section print the same value
every time you invoke them. While this is interesting the first six times, it
can get boring on the seventh. What we need to do, to make these boring,
unintelligent functions a little more exciting, is get them to return a different
value each time they are invoked.


Enter arguments.


Arguments work by using a placeholder to represent a certain variable within
a function. Values for this variable are provided to the function at run-time
from the main program. Since the input to the function will differ at each
invocation, so will the output.


To see how this works, look at the following function, which accepts a single
argument and then prints it back after a calculation:

<?php

// define a function
function getCircumference($radius) {
    echo "Circumference of a circle with radius $radius is
".sprintf("%4.2f", (2 * $radius * pi()))."<br />";
}
// call a function with an argument
getCircumference(10);

// call the same function with another argument
getCircumference(20);

?>

In this example, when the getCircumference() function is called with an
argument, the argument is assigned to the placeholder variable $radius
within the function, and then acted upon by the code within the function
definition.


It's also possible to pass more than one argument to a function. This is done
using a comma-separated list, as the following example shows:

<?php

// define a function
function changeCase($str, $flag) {
    /* check the flag variable and branch the code */
    switch($flag) {
        case 'U':
            print strtoupper($str)."<br />";
            break;
        case 'L':
            print strtolower($str)."<br />";
            break;
        default:
            print $str."<br />";
            break;
    }
}

// call the function
changeCase("The cow jumped over the moon", "U");
changeCase("Hello Sam", "L");

?>

Here, depending on the value of the second argument, program flow within
the function moves to the appropriate branch and manipulates the first
argument.


Note that there is no requirement to specify the data type of the argument
being passed to a function. Since PHP is a dynamically-typed language, it
automatically identifies the variable type and acts on it appropriately.


Circles in the Sand
The functions on the previous page simply printed their output to the screen.
But what if you want the function to do something else with the result? Well,
in PHP, you can have a function return a value, such as the result of a
calculation, to the statement that called it. This is done using a return
statement within the function, as shown below:

<?php

// define a function
function getCircumference($radius) {
    // return value
    return (2 * $radius * pi());
}

/* call a function with an argument and store the result in
a variable */
$result = getCircumference(10);

/* call the same function with another argument and print
the return value */
print getCircumference(20);
?>

Here, the argument passed to the getCircumference() function is
processed, and the result is returned to the main program, where it may be
captured in a variable, printed, or dealt with in other ways.


You can even use the result of a function inside another function, as
illustrated in this minor revision of the example above:

<?php

// define a function
function getCircumference($radius) {
// return value
    return (2 * $radius * pi());
}

// print the return value after formatting it
print "The answer is ".sprintf("%4.2f",
getCircumference(20));

?>

Return values need not be numbers or strings alone: a function can just as
easily return an array (remember them?), as demonstrated in the following
example:

<?php

/* define a function that can accept a list of email
addresses */
function getUniqueDomains($list) {
    /* iterate over the list, split addresses and add
domain part to another array */
    $domains = array();
     foreach ($list as $l) {
         $arr = explode("@", $l);
         $domains[] = trim($arr[1]);
     }
     // remove duplicates and return
     return array_unique($domains);
}

// read email addresses from a file into an array
$fileContents = file("data.txt");

/* pass the file contents to the function and retrieve the
result array */
$returnArray = getUniqueDomains($fileContents);

// process the return array
foreach ($returnArray as $d) {
    print "$d, ";
}

?>

Assuming the file looked like this,

test@test.com
a@x.com
zooman@deeply.bored.org
b@x.com
guess.me@where.ami.net
testmore@test.com
the output of the script above would look like this:
test.com, x.com, deeply.bored.org, where.ami.net,
Note that the return statement terminates program execution inside a
function.


Marching Order
The order in which arguments are passed to a function can be important.
The following example requires that the name is passed as the first
argument, and the place as the second.

<?php

// define a function
function introduce($name, $place) {
    print "Hello, I am $name from $place";
}

// call function
introduce("Moonface", "The Faraway Tree");

?>

This is the output:

Hello, I am Moonface from The Faraway Tree
In this example, if you reversed the order in which arguments were passed
to the function, this is what you'd see:
Hello, I am The Faraway Tree from Moonface
And look what happens if you forget to pass a required argument altogether:
Warning: Missing argument 2 for introduce() in xx.php on
line 3
Hello, I am Moonface from
In order to avoid such errors, PHP allows you to specify default values for all
the arguments in a user-defined function. These default values are used if
the function invocation is missing some arguments. Here's an example:

<?php

// define a function
function introduce($name="John Doe", $place="London") {
    print "Hello, I am $name from $place";
}
// call function
introduce("Moonface");

?>

In this case the output would be:

Hello, I am Moonface from London

Notice that the function has been called with only a single argument, even
though the function definition requires two. However, since default values
are present for each argument in the function, the missing argument is
replaced by the default value for that argument, and no error is generated.


The Amazing Shrinking Argument List
All the examples on the previous page have one thing in common: the
number of arguments in the function definition is fixed. However, PHP 4.x
also supports variable-length argument lists, by using the
func_num_args() and func_get_args() commands. For want of a better
name, these functions are called "function functions". Try wrapping your
tongue around that while you look at the next example, which demonstrates
how they can be used:

<?php

// define a function
function someFunc() {
    // get the arguments
    $args = func_get_args();

     // print the arguments
     print "You sent me the following arguments:";
     foreach ($args as $arg) {
         print " $arg ";
     }
     print "<br />";
}

// call a function with different arguments
someFunc("red", "green", "blue");
someFunc(1, "soap");

?>

Hmmm... if you're sneaky, you might have tried to pass someFunc() an
array, and found that instead of displaying the elements of the array, it
simply said "Array". You can fix this by adding a quick test for array
arguments inside the function, as in this rewrite:

<?php

// define a function
function someFunc() {
    // get the number of arguments passed
    $numArgs = func_num_args();

// get the arguments
    $args = func_get_args();

    // print the arguments
    print "You sent me the following arguments: ";
    for ($x = 0; $x < $numArgs; $x++) {
        print "<br />Argument $x: ";
        /* check if an array was passed and, if so, iterate
and print contents */
        if (is_array($args[$x])) {
            print " ARRAY ";
            foreach ($args[$x] as $index => $element) {
                print " $index => $element ";
            }
          }
          else {
              print " $args[$x] ";
          }
     }
}

// call a function with different arguments
someFunc("red", "green", "blue", array(4,5), "yellow");

?>


Going Global
Let's now talk a little bit about the variables used within a function, and their
relationship with variables in the outside world. Usually, the variables used
within a function are "local" - meaning that the values assigned to them, and
the changes made to them, are restricted to the function space alone.


Consider this simple example:

<?php

// define a variable in the main program
$today = "Tuesday";

// define a function
function getDay() {
    // define a variable inside the function
    $today = "Saturday";
    // print the variable
    print "It is $today inside the function<br />";
}

// call the function
getDay();
// print the variable
print "It is $today outside the function";

?>

When you run this script, here is what you will see:

It is Saturday inside the function
It is Tuesday outside the function
In other words, the variable inside the function is insulated from the
identically-named variable in the main program. Variables inside a function
are thus aptly called "local" variables because they only exist within the
function in which they are defined.


The reverse is also true: variables defined inside a function cannot be "seen"
outside it. To illustrate, take a look at the next example and its output (or
the lack of it):
<?php

// define a function
function getDay() {
    // define a variable inside the function
    $today = "Saturday";
}

getDay();
print "Today is $today";

?>

Here is the output:

Today is
Depending on the error_reporting you have set up in php.ini, you might also
see an error message:
Notice: Undefined variable: today in x1.php on line 10



However, I didn't say this can't be overcome. To have variables within a
function accessible from outside it (and vice-versa), all you need to do is
first declare them "global" with the - you guessed it! - global keyword.




Here is a rewrite of the earlier example, this time declaring the $today
variable global:

<?php

// define a variable in the main program
$today = "Tuesday";

// define a function
function getDay() {
    // make the variable global
    global $today;

     // define a variable inside the function
     $today = "Saturday";
     // print the variable
     print "It is $today inside the function<br />";
}

// print the variable
print "It is $today before running the function<br />";

// call the function
getDay();

// print the variable
print "It is $today after running the function";
?>

And here is the output:

It is Tuesday before running the function
It is Saturday inside the function
It is Saturday after running the function
Thus, once a variable is declared global, it is available at the global level,
and can be manipulated both inside and outside a function.


PHP also comes with so-called superglobal variables - variables that are
always available, regardless of whether you're inside a function or outside it.
You've already seen some of these special variables in action: the
$_SERVER, $_POST and $_GET variables are all superglobals, which is why
you can access things like the currently-executing script's name or form
values even inside a function.
Superglobals are a Good Thing™, because they're always there when you
need them, and you don't need to jump through any hoops to use the data
stored inside them. Read more about superglobals and variable scope at
http://www.php.net/manual/en/language.variables.predefined.php and
http://www.php.net/manual/en/language.variables.scope.php.
Checking References
Any discussion about variables in and out of functions would be incomplete
without some mention of the difference between "passing by reference" and
"passing by value". So far, all the examples you've seen have involved
passing arguments to a function "by value" - meaning that a copy of the
variable was passed to the function, while the original variable remained
untouched. However, PHP also allows you to pass "by reference" - meaning
that instead of passing a value to a function, you pass a reference to the
original variable, and have the function act on that instead of a copy.


Confusing? Well, this is probably easier to understand with an example. Let's
start with this:
<?php

// create a variable
$today = "Saturday";

// function to print the value of the variable
function setDay($day) {
    $day = "Tuesday";
    print "It is $day inside the function<br />";
}

// call function
setDay($today);

// print the value of the variable
print "It is $today outside the function";

?>

You've already seen this before, and you already know what the output is
going to say:

It is Tuesday inside the function
It is Saturday outside the function
This is because when the getDay() function is invoked, it passes the value
"Saturday" to the function ("passing by value"). The original variable
remains untouched; only its content is sent to the function. The function
then acts on the content, modifying and displaying it.


Now, look at how "passing by reference" works:
<?php

// create a variable
$today = "Saturday";

// function to print the value of the variable
function setDay(&$day) {
    $day = "Tuesday";
    print "It is $day inside the function<br />";
}

// call function
setDay($today);

// print the value of the variable
print "It is $today outside the function";

?>

Notice the ampersand (&) before the argument in the function definition.
This tells PHP to use the variable reference instead of the variable value.
When such a reference is passed to a function, the code inside the function
acts on the reference, and modifies the content of the original variable
(which the reference is pointing to) rather than a copy. If you then try
retrieving the value of the original variable outside the function, it returns
the modified value:

.
It is Tuesday inside the function
It is Tuesday outside the function
Now you understand why I said no discussion about variables would be
complete without mentioning the two ways of passing variables. This, of
course, is what the global keyword does inside a function: use a reference
to ensure that changes to the variable inside the function also reflect outside
it. The PHP manual puts it best when it says "...when you declare a variable
as global $var you are in fact creating a reference to a global variable".
For more examples, read all about references at http://www.zend.com/
manual/language.references.php.


And that just about concludes this tutorial. This time you've taken a big step
towards better software design by learning how to abstract parts of your PHP
code into reusable functions. You now know how to add flexibility to your
functions by allowing them to accept different arguments, and how to obtain
one (or more) return values from them. Finally, you've learned a little bit
about how PHP treats variables inside and outside functions.
In Part Seven, I'll be showing you how to group related functions together
into classes, and also telling you all about the cool new features in the PHP 5
object model. You definitely don't want to miss that one!




Part 7.1:
Alphabet Soup
So now you know how to create your own functions in PHP, and you've spent
the last few days busily inspecting your applications and turning repeated
code fragments into functions. But functions are just the tip of the software
abstraction iceberg. Lurking underneath is a three-letter acronym that
strikes fear into the hearts of most newbie programmers.


OOP.


If you've been programming for a while, you've probably heard the term
OOP before - it stands for Object Oriented Programming, and refers to a
technique whereby you create program "objects" and then use these objects
to build the functionality you need into your program. PHP 5 is very big on
OOP - it comes with a brand-spanking-new object model which finally brings
PHP objects into conformance with standard OOP principles and offers OO
programmers a whole bunch of new goodies to play with.


Wondering how you can get in on this? Well, wonder no more. Your prayers
have been answered.


Over the course of this tutorial, I'm going to take a brief look at PHP's OO
capabilities (both PHP 4 and PHP 5), together with examples and
explanations to demonstrate just how powerful it really is. I'll be covering
most of the basics - classes, objects, attributes and methods - and a couple
of more advanced concepts - constructors, destructors, private methods and
properties, and inheritance. And if you're new to object-oriented
programming, or just apprehensive about what lies ahead, don't worry - I
promise this will be a lot less painful than you think. And unlike dentists, I
don't lie.


Back To Class
Before beginning, though, let's make sure that you have a clear idea of the
concepts involved here.


In PHP, a class is simply a set of program statements which perform a
specific task. A typical class definition contains both variables and functions,
and serves as the template from which to spawn specific instances of that
class.


These specific instances of a class are referred to as objects. Every object
has certain characteristics, or properties, and certain pre-defined functions,
or methods. These properties and methods of the object correspond directly
with the variables and functions within the class definition.


Once a class has been defined, PHP allows you to spawn as many instances
of the class as you like. Each of these instances is a completely independent
object, with its own properties and methods, and can therefore be
manipulated independently of other objects. This comes in handy in
situations where you need to spawn more than one instance of an object -
for example, two simultaneous database links for two simultaneous queries,
or two shopping carts.


Classes also help you keep your code modular - you can define a class in a
separate file, and include that file only in the scripts where you plan to use
the class - and simplify code changes, since you only need to edit a single
file to add new functionality to all your spawned objects.


Animal Antics
To understand this better, pick an animal, any animal. I pick the bear,
because I like bears. Now ask yourself, can you consider this bear, within the
framework of OOP, as an "object"?


Why not? After all, every bear has certain characteristics - age, weight, sex -
which are equivalent to object properties. And every bear can perform
certain activities - eat, sleep, walk, run, mate - all of which are equivalent to
object methods.


Let's take it a little further. Since all bears share certain characteristics, it is
possible to conceive of a template Bear(), which defines the basic
characteristics and abilities of every bear on the planet. Once this Bear()
("class") is used to create a new $bear ("object"), the individual
characteristics of the newly-created Bear can be manipulated independently
of other Bears that may be created from the template.


Now, if you sat down to code this class in PHP 5, it would probably look
something like this:

<?php
// PHP 5

// class definition
class Bear {
    // define properties
    public $name;
    public $weight;
    public $age;
    public $sex;
    public $colour;

     // define methods
     public function eat() {
         echo $this->name." is eating... ";
     }
     public function run() {
         echo $this->name." is running... ";
     }

     public function kill() {
         echo $this->name." is killing prey... ";
     }

     public function sleep() {
         echo $this->name." is sleeping... ";
     }
}

?>

Given this class, it's now simple to spawn as many Bears as you like, and
adjust the individual properties of each. Take a look:

<?php

// my first bear
$daddy = new Bear;
// give him a name
$daddy->name = "Daddy Bear";
// how old is he
$daddy->age = 8;
// what sex is he
$daddy->sex = "male";
// what colour is his coat
$daddy->colour = "black";
// how much does he weigh
$daddy->weight = 300;

// give daddy a wife
$mommy = new Bear;
$mommy->name = "Mommy Bear";
$mommy->age = 7;
$mommy->sex = "female";
$mommy->colour = "black";
$mommy->weight = 310;

// and a baby to complete the family
$baby = new Bear;
$baby->name = "Baby Bear";
$baby->age = 1;
$baby->sex = "male";
$baby->colour = "black";
$baby->weight = 180;

// a nice evening in the Bear family
// daddy kills prey and brings it home
$daddy->kill();

// mommy eats it
$mommy->eat();
// and so does baby
$baby->eat();

// mommy sleeps
$mommy->sleep();
// and so does daddy
$daddy->sleep();

// baby eats some more
$baby->eat();

?>

As the illustration above shows, once new objects are defined, their
individual methods and variables can be accessed and modified independent
of each other. This comes in very handy, as the rest of this tutorial will show.
Going Deeper
Now that you've got the concepts straight, let's take a look at the nitty-gritty
of a class definition.

<?php
// PHP 5

// class definition
class Bear {

     // define public properties
     public $name;
     public $age;

     // more properties

     // define public methods
     public function eat() {
         echo $this->name." is eating... ";
         // more code
     }

     // more methods
}

?>

Every class definition begins with the keyword class, followed by a class
name. You can give your class any name that strikes your fancy, so long as it
doesn't collide with a reserved PHP word. A pair of curly braces encloses all
class variables and functions, which are written as you would normally code
them.


PHP 5 also introduces the concept of visibility to the object model. Visibility
controls the extent to which object properties and methods can be
manipulated by the caller, and plays an important role in defining how open
or closed your class is. Three levels of visibility exist, ranging from most
visible to least visible: public, private and protected. Within the class
definition, you can mark the visibility of a property or method by preceding it
with one of the keywords - public, private, or protected .


By default, class methods and properties are public; this allows the calling
script to reach inside your object instances and manipulate them directly. If
you don't like the thought of this intrusion, you can mark a particular
property or method as private or protected, depending on how much
control you want to cede over the object's internals (more on this shortly).


Since the PHP 4 object model does not include support for visibility, the class
definition above would not work in PHP 4. Instead, you would need to use
the following:

<?php
// PHP 4

// class definition
class Bear {
    // define properties
    var $name;
    var $weight;
    var $age;
    var $sex;
    var $colour;

     // define methods
     function eat() {
         echo $this->name." is eating... ";
     }

     function run() {
         echo $this->name." is running... ";
     }
     function kill() {
         echo $this->name." is killing prey... ";
     }

     function sleep() {
         echo $this->name." is sleeping... ";
     }
}

?>

From the above, it should be clear that class properties and methods in PHP
4 are always public ...and there ain't nuttin' you can do about that!


In order to create a new instance of a class, you use the new keyword to
assign the newly created object to a PHP variable.

<?php

$daddy = new Bear;

?>

In English, the above would mean "create a new object of class Bear() and
assign it to the variable $daddy ".


You can now access all the methods and properties of the class via this
variable. For example, the code

<?php

$daddy->name = "Daddy Bear";

?>
would mean "assign the value Daddy Bear to the variable $name of this
specific instance of the class Bear()", while the statement

<?php

$daddy->sleep();

?>

would mean "execute the function sleep() for this specific instance of the
class Bear()".


Note the -> symbol used to connect objects to their properties or methods,
and the fact that the $ symbol is omitted when accessing properties of a
class instance.


This And That
In case you need to access functions or variables within the class definition
itself, both PHP 4 and PHP 5 offer the $this keyword, which is used to refer
to "this" class. To see how this works, let's alter the eat() method to accept
a number of food units and then add that to the bear's weight.

<?php
// PHP 5

// class definition
class Bear {
    // define properties
    public $name;
    public $weight;

    // define methods
    public function eat($units) {
        echo $this->name." is eating ".$units." units of
food... ";
          $this->weight += $units;
     }
}

?>

In this case, the $this prefix indicates that the variable to be modified
exists within the class - or, in English, "add the argument provided to eat()
to the variable $weight within this object". The $this prefix thus provides
a convenient way to access variables and functions which are "local" to the
class.


Here's an example of how it works:

<?php

// create instance
$baby = new Bear;
$baby->name = "Baby Bear";
$baby->weight = 1000;

// now create another instance
// this one has independent values for each property
$brother = new Bear;
$brother->name = "Brother Bear";
$brother->weight = 1000;

// retrieve properties
echo $baby->name." weighs ".$baby->weight." units ";
echo $brother->name." weighs ".$brother->weight." units ";

// call eat()
$baby->eat(100);
$baby->eat(50);
$brother->eat(11);
// retrieve new values
echo $baby->name." now weighs ".$baby->weight." units ";
echo $brother->name." now weighs ".$brother->weight." units
";

?>

The output of this will read:

Baby Bear weighs 1000 units
Brother Bear weighs 1000 units
Baby Bear is eating 100 units of food...
Baby Bear is eating 50 units of food...
Brother Bear is eating 11 units of food...
Baby Bear now weighs 1150 units
Brother Bear now weighs 1011 units



Under Construction
It's also possible to automatically execute a function when the class is called
to create a new object. This is referred to in geek lingo as a constructor
and, in order to use it, your PHP 5 class definition must contain a special
function, __construct().


For example, if you'd like all newly born bears to be brown and weigh 100
units, you could add this to your class definition:

<?php
// PHP 5

// class definition
class Bear {
    // define properties
    public $name;
    public $weight;
     public $age;
     public $colour;

     // constructor
     public function __construct() {
         $this->age = 0;
         $this->weight = 100;
         $this->colour = "brown";
     }

     // define methods
}

?>

In PHP 4, your constructor must have the same name as the class. Here's
the equivalent code for PHP 4:

<?php
// PHP 4

// class definition
class Bear {
    // define properties
    var $name;
    var $weight;
    var $age;
    var $colour;

     // constructor
     function Bear() {
         $this->age = 0;
         $this->weight = 100;
         $this->colour = "brown";
     }
     // define methods
}

?>

Now, try creating and using an instance of the class:

<?php

// create instance
$baby = new Bear;
$baby->name = "Baby Bear";
echo $baby->name." is ".$baby->colour." and weighs ".$baby-
>weight." units at birth";

?>

Here, the constructor automatically sets default properties every time an
object of the class is instantiated. Therefore, when you run the script above,
you will see this:

Baby Bear is brown and weighs 100 units at birth



Hands Off
As noted previously, PHP 5 makes it possible to mark class properties and
methods as private, which means that they cannot be manipulated or
viewed outside the class definition. This is useful to protect the inner
workings of your class from manipulation by object instances. Consider the
following example, which illustrates this by adding a new private variable,
$_lastUnitsConsumed, to the Bear() class:

<?php
// PHP 5
// class definition
class Bear {
    // define properties
    public $name;
    public $age;
    public $weight;
    private $_lastUnitsConsumed;

     // constructor
     public function __construct() {
         $this->age = 0;
         $this->weight = 100;
         $this->_lastUnitsConsumed = 0;
     }

    // define methods
    public function eat($units) {
        echo $this->name." is eating ".$units." units of
food... ";
        $this->weight += $units;
        $this->_lastUnitsConsumed = $units;
    }

    public function getLastMeal() {
        echo "Units consumed in last meal were ".$this-
>_lastUnitsConsumed." ";
    }
}

?>

Now, since the $_lastUnitsConsumed variable is declared as private,
any attempt to modify it from an object instance will fail. Here is an
example:
<?php

$bob = new Bear;
$bob->name = "Bobby Bear";
$bob->eat(100);
$bob->eat(200);
echo $bob->getLastMeal();
// the next line will generate a fatal error
$bob->_lastUnitsConsumed = 1000;

?>

In a similar way, class methods can also be marked as private - try it out
for yourself and see.


Extending Yourself
Two of the best things about OOP, whether in PHP 4 or in PHP 5, are
extensibility and inheritance. Very simply, this means that you can create a
new class based on an existing class, add new features (read: properties and
methods) to it, and then create objects based on this new class. These
objects will contain all the features of the original parent class, together with
the new features of the child class.


As an illustration, consider the following PolarBear() class, which extends
the Bear() class with a new method.

<?php
// PHP 5

// class definition
class Bear {
    // define properties
    public $name;
    public $weight;
    public $age;
    public $sex;
    public $colour;

    // constructor
    public function __construct() {
        $this->age = 0;
        $this->weight = 100;
    }

    // define methods
    public function eat($units) {
        echo $this->name." is eating ".$units." units of
food... ";
        $this->weight += $units;
    }

    public function run() {
        echo $this->name." is running... ";
    }

    public function kill() {
        echo $this->name." is killing prey... ";
    }

    public function sleep() {
        echo $this->name." is sleeping... ";
    }
}

// extended class definition
class PolarBear extends Bear {

    // constructor
    public function __construct() {
        parent::__construct();
        $this->colour = "white";
          $this->weight = 600;
     }

     // define methods
     public function swim() {
         echo $this->name." is swimming... ";
     }
}

?>

The extends keyword is used to extend a parent class to a child class. All
the functions and variables of the parent class immediately become available
to the child class. This is clearly visible in the following code snippet:

<?php

// create instance of Bear()
$tom = new Bear;
$tom->name = "Tommy Bear";

// create instance of PolarBear()
$bob = new PolarBear;
$bob->name = "Bobby Bear";

// $bob can use all the methods of Bear() and PolarBear()
$bob->run();
$bob->kill();
$bob->swim();

// $tom can use all the methods of Bear() but not
PolarBear()
$tom->run();
$tom->kill();
$tom->swim();
?>

In this case, the final call to $tom->swim() will fail and cause an error,
because the Bear() class does not contain a swim() method. However,
none of the calls to $bob->run() or $bob->kill() will fail, because as a
child of the Bear() class, PolarBear() inherits all the methods and
properties of its parent.


Note how the parent class constructor has been called in the PolarBear()
child class constructor - it's a good idea to do this so that all necessary
initialization of the parent class is carried out when a child class is
instantiated. Child-specific initialization can then be done in the child class
constructor. Only if a child class does not have a constructor, is the parent
class constructor automatically called.


You can do this in PHP 4, too. Here's a PHP 4 version of the PolarBear class
definition:

<?php
// PHP 4

// extended class definition
class PolarBear extends Bear {

     // constructor
     function PolarBear() {
         parent::Bear();
         $this->colour = "white";
         $this->weight = 600;
     }

     // define methods
     function swim() {
         echo $this->name." is swimming... ";
     }
}

?>

To prevent a class or its methods from being inherited, use the final
keyword before the class or method name (this is new in PHP 5 and will not
work in older versions of PHP). Here's an example, which renders the
Bear() class un-inheritable (if that's actually a word):

<?php
// PHP 5

// class definition
final class Bear {
    // define properties

     // define methods
}

// extended class definition
// this will fail because Bear() cannot be extended
class PolarBear extends Bear {
        // define methods
}

// create instance of PolarBear()
// this will fail because Bear() could not be extended
$bob = new PolarBear;
$bob->name = "Bobby Bear";
echo $bob->weight;

?>

PHP 101 (part 7): The Bear Necessities - Part 2
Part 7.2:
Ending On A High Note
Just as there are constructors, so also are there destructors. Destructors
are object methods which are called when the last reference to an object in
memory is destroyed, and they are usually tasked with clean-up work - for
example, closing database connections or files, destroying a session and so
on. Destructors are only available in PHP 5, and must be named
__destruct(). Here's an example:

<?php
// PHP 5

// class definition
class Bear {
    // define properties
    public $name;
    public $weight;
    public $age;
    public $sex;
    public $colour;

     // constructor
     public function __construct() {
         $this->age = 0;
         $this->weight = 100;
         $this->colour = "brown";
     }

    // destructor
    public function __destruct() {
        echo $this->name." is dead. He was ".$this->age."
years old and ".$this->weight." units heavy. Rest in peace!
";
     }

    // define methods
    public function eat($units) {
        echo $this->name." is eating ".$units." units of
food... ";
        $this->weight += $units;
    }

     public function run() {
         echo $this->name." is running... ";
     }

     public function kill() {
         echo $this->name." is killing prey... ";
     }
}

// create instance of Bear()
$daddy = new Bear;
$daddy->name = "Daddy Bear";
$daddy->age = 10;
$daddy->kill();
$daddy->eat(2000);
$daddy->run();
$daddy->eat(100);

?>

Here, once the script ends, no reference will exist for $daddy, and so the
destructor will be called automatically. The output would look like this:

Daddy    Bear   is   killing prey...
Daddy    Bear   is   eating 2000 units of food...
Daddy    Bear   is   running...
Daddy    Bear   is   eating 100 units of food...
Daddy Bear is dead. He was 10 years old and 2200 units
heavy. Rest in peace!



Discovering New Things
PHP 4 and PHP 5 come with a bunch of functions designed to let you
discover object properties and methods, and find out which class an object
belongs to. The first two of these are the get_class() and
get_parent_class() functions, which tell you the name of the classes
which spawned a particular object. Consider the following class definition:

<?php
// PHP 5

// base class
class Bear {
    public $name;
    public $weight;

     // constructor
     public function __construct() {
     }

     // define methods
     public function eat() {
     }

     public function run() {
     }

     public function sleep() {
     }
}

// derived class
class GrizzlyBear extends Bear {
    public function kill() {
    }
}

?>

And now consider the following script, which uses get_class() and
get_parent_class() to retrieve the class name from an instance:

<?php

$joe = new GrizzlyBear;
$joe->name = "Joe Bear";
$joe->weight = 1000;
echo "Class: " . get_class($joe);
echo "Parent class: " . get_parent_class(get_class($joe));

?>

You can view all the properties exposed by a class with get_class_vars(),
and all its methods with get_class_methods() function. To view
properties of the specific object instance, use get_object_vars() instead
of get_class_vars(). Here is an example:

<?php

// create instance
$joe = new GrizzlyBear;
$joe->name = "Joe Bear";
$joe->weight = 1000;

// get class name
$className = get_class($joe);

// get class properties
echo "Class properties: ";
print_r(get_class_vars($className));

// get class methods
echo " Class methods: ";
print_r(get_class_methods($className));

// get this instance's properties
echo " Instance properties: ";
print_r(get_object_vars($joe));

?>

and here is some sample output:

Class properties:
Array
(
    [name] =>
    [weight] =>
)

Class methods:
Array
(
    [0] => kill
    [1] => __construct
    [2] => eat
    [3] => run
    [4] => sleep
)

Instance properties:
Array
(
    [name] => Joe Bear
     [weight] => 1000
)



As noted in one of the previous segments of this tutorial, the print_r()
function allows you to look inside any PHP variable, including an object. It's
extremely useful, so note it down for future reference.


Access Denied
And now that you know the basics of how objects work in PHP, let's wrap this
up with a real-world example. Consider the following userAuth() class, which
exposes methods to validate a user login using an encrypted password file
such as /etc/passwd or .htaccess, both of which are used on Unix systems
(i.e. most of the Internet). I'll assume here that the passwords in the
password file are encrypted with MD5, and use a 12-character salt beginning
with $1$:

<?php
// PHP 5

// class definition
class userAuth {
    // define properties
    public $username;
    private $passwd;
    private $passwdFile;
    private $_resultCode;

     // constructor
     // must be passed username and password
     public function __construct($username, $password) {
             $this->username = $username;
             $this->passwd = $password;
             $this->_resultCode = -1;
     }
    // used to set file to read for password data
    public function setPasswdFile($file) {
        $this->passwdFile = $file;
    }

    // returns: -1 if user does not exist
    //           0 if user exists but password is incorrect
    //           1 if username and password are correct
    public function getResultCode() {
        return $this->_resultCode;
    }

    public function authenticateUser() {
        // make sure that the script has permission to read
this file!
        $data = file($this->passwdFile);

          // iterate through file
          foreach ($data as $line) {
              $arr = explode(":", $line);
              // if username matches
              // test password
              if ($arr[0] == $this->username) {

                  // if match, user/pass combination is
correct
                 // return 1
                 if ($arr[1] == crypt($this->passwd,
$arr[1])) {
                     $this->_resultCode = 1;
                     break;
                 }
                 // otherwise return 0
                 else {
                     $this->_resultCode = 0;
                         break;
                    }
               }
          }
    }
// end class definition
}

?>

Most of this should be clear to you from the examples in previous pages. In
case it isn't, the following script should help you understand what's
happening:

<?php

// create instance
$ua = new userAuth("joe", "secret");
// set password file
$ua->setPasswdFile("passwd.txt");
// perform authentication
$ua->authenticateUser();
// check result code and display message
switch ($ua->getResultCode()) {
    case -1:
        echo "Could not find your user account";
        break;

     case 0:
         echo "Your password was incorrect";
         break;

     case 1:
         echo "Welcome, ".$ua->username;
         break;
}
?>

Here, the username and password is passed to the object constructor, as is
the name and path of the file containing authentication credentials. The
authenticateUser() method takes care of parsing the password file and
checking if the user exists and the password is correct. Depending on what it
finds, a result code is generated and stored in the private variable
$_resultCode. This variable can be read through the getResultCode()
method, and an appropriate message displayed. And since this entire thing
is neatly encapsulated in a class, I can take it anywhere, use it in any script
- even inside another application - and extend it to support different types of
authentication schemes and containers.


There's a lot more you can do with objects, especially in PHP 5; I've
restrained myself here because I didn't want to confuse you too much with
talk of overloading, abstract classes and static methods. If you're interested,
however, drop by http://www.php.net/manual/en/language.oop.php for
more. And make sure you come back for Part Eight of PHP 101, because I'm
going to show you how to hook your scripts up to a MySQL database.




Part 8.1:
Mix and Match
One of the most compelling things PHP has going for it is its support for a
variety of database management systems, including MySQL, PostgreSQL,
Oracle and Microsoft Access. By virtue of this support, PHP developers can
create sophisticated data-driven Web applications at a fraction of the time
and cost required by competing alternatives. And nowhere is this more clear
than in PHP's longtime support of MySQL, the very fast, very reliable and
very feature-rich open-source RDBMS.


By using PHP and MySQL together, developers can benefit from huge savings
on the licensing costs of commercial alternatives, and also leverage off the
tremendous amount of thought PHP and MySQL developers have put into
making sure that the two packages work together seamlessly and smoothly.
And since both PHP and MySQL are open-source projects, when you use the
two of them together you know you're getting the most up-to-date
technology available. And that's always a good thought to go to bed with.


OK. Enough of the marketing talk. Let's get down to business.


In this issue of PHP 101, I'm going to show you how to use PHP to extract
data from a database, and use that data to dynamically build a Web page. In
order to try out the examples in this tutorial, you'll need a working MySQL
installation, which you can obtain from the MySQL Web site at http://
www.mysql.com/. If you have some knowledge of SQL (Structured Query
Language, the language used to interact with a database server) you'll find it
helpful, but it's not essential.


Building Blocks
In order to use MySQL and PHP together, your PHP build must include
support for MySQL. On UNIX, this is accomplished by adding the --with-
mysql option to the configure script when building PHP on UNIX, and
pointing PHP to the MySQL client libraries. On Windows, the MySQL client
libraries are built in to PHP 4 and activated by default. In PHP 5, pre-built .dll
files are included with the Windows distribution. Read more about this at
http://www.php.net/manual/en/ref.mysql.php.


Unix users should note that PHP 4 ships with a set of MySQL client libraries,
which are activated by default; however, PHP 5 no longer bundles these
libraries due to licensing issues, so you need to obtain, install and activate
them yourself. They're included with the MySQL distribution, and are
installed automatically when you install MySQL. To activate the MySQL
extension, ext/mysql, add the --with-mysql option to PHP's configure
script. For more information on this change, read http://www.php.net/
manual/en/faq.databases.php#faq.databases.mysql.php5.
And finally (as if all that wasn't quite confusing enough) PHP 5 also comes
with a new MySQL extension, called ext/mysqli (MySQL Improved). You
can use this new extension to access the new features in MySQL 4.1.2 or
better, and to gain the benefits of improved speed and security. To activate
this extension on UNIX, add the --with-mysqli option to PHP's
configure script, and point PHP to the mysql_config program that comes
with MySQL 4.1 and above. For Windows users, a pre-built version of ext/
mysqli is included in the win32 PHP distribution. Read more about this at
http://www.php.net/manual/en/ref.mysqli.php.


To figure out which extension you need, use the following rule of thumb:


      If you need the new features in MySQL 4.1.2 or better, or if you're
      using an older version of MySQL but still want to benefit from the
      speed/security improvements in the new extension, use ext/mysqli.
      If you don't fall into either of the categories above, or don't know what
      I'm talking about, use regular ext/mysql.



In case you were wondering, this tutorial covers both ext/mysql and ext/
mysqli, so you actually get two for the price of one. Keep reading, and let
me introduce you to MySQL.


Animal Magnetism
Every MySQL database is composed of one or more tables. These tables,
which structure data into rows and columns, are what lend organization to
the data.


Here's an example of what a typical table looks like:

+----+-----------+----------+
| id | country   | animal   |
+----+-----------+----------+
| 1 | America    | eagle    |
| 2 | China      | dragon   |
| 3 | England    | lion     |
| 4 | India      | tiger    |
| 5 | Australia | kangaroo |
| 6 | Norway     | elk      |
+----+-----------+----------+
As you can see, a table divides data into rows, with a new entry (or record)
on every row. The data in each row is further broken down into cells (or
fields), each of which contains a value for a particular attribute of the data.
For example, if you consider the record for the country "India", you'll see
that the record is clearly divided into separate fields for record number,
country name and national animal.


The rows within a table are not arranged in any particular order - they can
be sorted alphabetically, by number, by name, or by any other criteria you
choose to specify. It is therefore necessary to have some method of
identifying a specific record in a table. In the example above, each record is
identified by a unique number; this unique field is referred to as the primary
key for that table.
You use the Structured Query Language, SQL, to interact with the MySQL
server and tell it to create a table, mark a field as primary, insert records,
edit records, retrieve records... basically, anything that involves
manipulating the data or the database. To see how this works, examine the
following SQL, which creates the table above:
CREATE DATABASE testdb;

CREATE TABLE `symbols` (
    `id` int(11) NOT NULL auto_increment,
    `country` varchar(255) NOT NULL default '',
    `animal` varchar(255) NOT NULL default '',
    PRIMARY KEY (`id`)
) TYPE=MyISAM;

INSERT   INTO   `symbols`    VALUES    (1,   'America', 'eagle');
INSERT   INTO   `symbols`    VALUES    (2,   'China', 'dragon');
INSERT   INTO   `symbols`    VALUES    (3,   'England', 'lion');
INSERT   INTO   `symbols`    VALUES    (4,   'India', 'tiger');
INSERT INTO `symbols` VALUES (5, 'Australia', 'kangaroo');
INSERT INTO `symbols` VALUES (6, 'Norway', 'elk');

You can enter these commands either interactively or non-interactively
through the MySQL commandline client program, which you run by
navigating to the mysql/bin directory from your shell or DOS box and
typing - with no ; because this is a shell command - either mysql, or mysql
db_name if you want to choose an existing database to work with. Read
http://dev.mysql.com/doc/mysql/en/mysql.html for more information on
how to use the MySQL commandline client, and the tutorial at http://
www.melonfire.com/community/columns/trog/article.php?id=39 to
understand what each of the SQL commands above does. SQL is a lot like
spoken English, so it won't take you very long to pick it up. Just don't try to
turn those backticks into single quotation marks.


Once the data has been imported, run a quick SELECT query to check that
everything is working as it should be:

mysql> SELECT * FROM `symbols`;
+----+-----------+----------+
| id | country   | animal   |
+----+-----------+----------+
| 1 | America    | eagle    |
| 2 | China      | dragon   |
| 3 | England    | lion     |
| 4 | India      | tiger    |
| 5 | Australia | kangaroo |
| 6 | Norway     | elk      |
+----+-----------+----------+
6 rows in set (0.06 sec)
In English, the query above means "show me all the records from the table
named symbols". If you saw the same output as above, you're good to go!


Hello Database!
Now, let's use PHP to do exactly the same thing. You could use PHP to set up
the database from the start, but as ours already exists we'll simply fire a
SELECT query at the database 'testdb', and display the results in an HTML
page:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set database server access variables:
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// open connection
$connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

// select database
mysql_select_db($db) or die ("Unable to select database!");

// create query
$query = "SELECT * FROM symbols";

// execute query
$result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());

// see if any rows were returned
if (mysql_num_rows($result) > 0) {
    // yes
     // print them one after another
     echo "<table cellpadding=10 border=1>";
     while($row = mysql_fetch_row($result)) {
         echo "<tr>";
         echo "<td>".$row[0]."</td>";
         echo "<td>" . $row[1]."</td>";
         echo "<td>".$row[2]."</td>";
         echo "</tr>";
     }
     echo "</table>";
}
else {
    // no
    // print status message
    echo "No rows found!";
}

// free result set memory
mysql_free_result($result);

// close connection
mysql_close($connection);

?>

</body>
</html>

Here's what the result looks like:
As you can see, using PHP to get data from a database involves several
steps, each of which is actually a pre-defined PHP function. Let's dissect
each step:


 1.   The first thing to do is specify some important information needed to
      establish a connection to the database server. This information
      includes the server name, the username and password required to
      gain access to it, and the name of the database to query. These values
      are all set up in regular PHP variables. <?php

      $host   = "localhost";
      $user   = "test";
      $pass   = "test";
      $db =   "testdb";

      ?>
 2.   To begin communication with a MySQL database server, you need to
      open a connection to that server. All communication between PHP and
      the database server takes place through this connection. In order to
      initialize this connection, PHP offers the mysql_connect() function:
      <?php

      $connection = mysql_connect($server, $user, $pass);
     ?>
     All the parameters in mysql_connect()are optional, but there are
     three you will generally need to use anywhere beyond your own
     machine: the database server name, username and password. If the
     database server and the Web server are running on the same physical
     machine, you can use localhost as the database server name this is
     in fact the default value supplied by PHP.
     mysql_connect() returns a "link identifier", which is stored in the
     variable $connection. This identifier is used when communicating
     with the database.
3.   Once you have a connection to the database, you must select a
     database for use with the mysql_select_db() function: <?php

     mysql_select_db($db) or die ("Unable to select
     database!");

     ?>
     This function must be passed the name of the database to be used for
     all subsequent queries. An optional second argument here is the link
     identifier; if no identifier is specified, the last opened link is assumed.
     If you have two or more database connections open simultaneously,
     it's a good idea to specify the link identifier as the second argument to
     mysql_select_db() - and indeed to all other mysql_* functions in
     the script, so that PHP doesn't get confused about which connection to
     use where.
4.   The next step is to create the query and execute it. This is
     accomplished with the mysql_query() function. <?php

     $query = "SELECT * FROM symbols";
     $result = mysql_query($query) or die ("Error in query:
     $query. ".mysql_error());

     ?>
     This function also needs two parameters: the query string and the link
     identifier for the connection. Again, if no link identifier is specified, the
     last opened link is used. Depending on whether or not the query was
     successful, the function returns true or false; a failure can be caught
     via the ...or die() clause of the statement, and the
     mysql_error() function can be used to display the corresponding
     error message.
5.   If mysql_query() is successful, the result set returned by the query
     is stored in the variable $result. This result set may contain one or
     more rows or columns of data, depending on your query. You can
     retrieve specific subsets of the result set with different PHP functions,
     including the one used here - the mysql_fetch_row() function -
     which fetches a single row of data as an array called $row. Fields in
     that row can then be accessed using standard PHP array notation.
     Each time you call mysql_fetch_row(), the next record in the result
     set is returned. This makes mysql_fetch_row() very suitable for use
     in a while() or for() loop.
     <?php

     if (mysql_num_rows($result) > 0) {
         while($row = mysql_fetch_row($result)) {
             echo "<td>".$row[0]."</td>";
             echo "<td>".$row[1]."</td>";
             echo "<td>".$row[2]."</td>";
         }
     }

     ?>
     Notice that the call to mysql_fetch_row() is wrapped in a
     conditional test, which first checks to see if any rows were returned at
     all. This information is provided by the mysql_num_rows() function,
     which contains the number of rows returned by the query. Obviously,
     you can only use this function with queries that return data, like
     SELECT or SHOW.It is not appropriate for use with INSERT, UPDATE,
     DELETE or similar queries.
     There are several other alternatives to mysql_fetch_row(), which
     will be explained a little later.
 6.   Finally, since each result set returned after a query occupies memory,
      it's a good idea to use the mysql_free_result() function to free up
      the used memory. After the result set is freed, if no further queries are
      to be run, you can close the connection to the MySQL server with
      mysql_close(). <?php

      mysql_free_result($result);
      mysql_close($connection);

      ?>
Different Strokes...
You can also use PHP's mysql_fetch_row() and list() functions to
obtain a simple array of values, and then assign these values to different
variables - a variation of the technique in the previous section. Take a look
(only the while() loop changes):

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// open connection
$connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

// select database
mysql_select_db($db) or die ("Unable to select database!");

// create query
$query = "SELECT * FROM symbols";

// execute query
$result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());

// see if any rows were returned
if (mysql_num_rows($result) > 0) {
     // yes
     // print them one after another
     echo "<table cellpadding=10 border=1>";
     while(list($id, $country, $animal) =
mysql_fetch_row($result)) {
          echo "<tr>";
          echo "<td>$id</td>";
          echo "<td>$country</td>";
          echo "<td>$animal</td>";
          echo "</tr>";
     }
     echo "</table>";
}
else {
     // no
     // print status message
     echo "No rows found!";
}

// free result set memory
mysql_free_result($result);

// close connection
mysql_close($connection);
?>

</body>
</html>

In this case, the list() function is used to assign different elements of the
result set to PHP variables, which are then used when rendering the page.


You can use PHP's mysql_fetch_assoc() function to represent each row
as an associative array of field-value pairs - a minor variation of the
technique used above:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// open connection
$connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

// select database
mysql_select_db($db) or die ("Unable to select database!");

// create query
$query = "SELECT * FROM symbols";
// execute query
$result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());

// see if any rows were returned
if (mysql_num_rows($result) > 0) {
    // yes
    // print them one after another
    echo "<table cellpadding=10 border=1>";
    while($row = mysql_fetch_assoc($result)) {
        echo "<tr>";
        echo "<td>".$row['id']."</td>";
        echo "<td>".$row['country']."</td>";
        echo "<td>".$row['animal']."</td>";
        echo "</tr>";
    }
    echo "</table>";
}
else {
    // no
    // print status message
    echo "No rows found!";
}

// free result set memory
mysql_free_result($result);

// close connection
mysql_close($connection);

?>

</body>
</html>
Notice that in this case, field values are accessed using the field name
instead of the index.


Of all the alternatives, however, the function I like the most is the
mysql_fetch_object() function, which returns each row as an object
(remember them from Part Seven?) with properties corresponding to the
field names:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// open connection
$connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

// select database
mysql_select_db($db) or die ("Unable to select database!");

// create query
$query = "SELECT * FROM symbols";

// execute query
$result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());
// see if any rows were returned
if (mysql_num_rows($result) > 0) {
    // yes
    // print them one after another
    echo "<table cellpadding=10 border=1>";
    while($row = mysql_fetch_object($result)) {
        echo "<tr>";
        echo "<td>".$row->id."</td>";
        echo "<td>".$row->country."</td>";
        echo "<td>".$row->animal."</td>";
        echo "</tr>";
    }
    echo "</table>";
}
else {
    // no
    // print status message
    echo "No rows found!";
}

// free result set memory
mysql_free_result($result);

// close connection
mysql_close($connection);

?>

</body>
</html>

Here, each $row object is created with properties corresponding to the field
names in that row. Row values can thus be accessed using standard
object->property notation.
If you're the type that likes to have your cake and eat it too, you will
probably enjoy the mysql_fetch_array() function, which returns both an
associative array and a numerically-indexed array, a combination of the
mysql_fetch_row() and mysql_fetch_assoc() functions. Read about it
at http://www.php.net/manual/en/function.mysql-fetch-array.php.


...for Different Folks
If you're using PHP 5, you can do the same thing using the new ext/mysqli
extension, which offers a number of new features. This extension can be
used in two ways: procedural (using functions), and object-oriented (using
class methods and properties). Consider the next script, which uses ext/
mysqli in a procedural manner:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// open connection
$connection = mysqli_connect($host, $user, $pass, $db) or
die ("Unable to connect!");

// create query
$query = "SELECT * FROM symbols";

// execute query
$result = mysqli_query($connection, $query) or die ("Error
in query: $query. ".mysqli_error());

// see if any rows were returned
if (mysqli_num_rows($result) > 0) {
    // yes
    // print them one after another
    echo "<table cellpadding=10 border=1>";
    while($row = mysqli_fetch_row($result)) {
        echo "<tr>";
        echo "<td>".$row[0]."</td>";
        echo "<td>".$row[1]."</td>";
        echo "<td>".$row[2]."</td>";
        echo "</tr>";
    }
    echo "</table>";
}
else {
    // no
    // print status message
    echo "No rows found!";
}

// free result set memory
mysqli_free_result($result);

// close connection
mysqli_close($connection);

?>

</body>
</html>

As you can see, this looks a lot like the code written for ext/mysql. The
only real difference - at least to the naked eye - is the fact that function
names now begin with mysqli_* instead of mysql_*. Of course, there are a
whole bunch of differences under the hood: ext/mysqli is faster, more
secure and more powerful than regular ext/mysql, and also includes
support for prepared statements, bound result sets, multiple simultaneous
queries, transactions and a whole bunch of other cool stuff.


You can also use ext/mysqli in an object-oriented way, where each task -
connecting, querying, fetching - is actually a method of the mysqli()
object:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// create mysqli object
// open connection
$mysqli = new mysqli($host, $user, $pass, $db);

// check for connection errors
if (mysqli_connect_errno()) {
    die("Unable to connect!");
}

// create query
$query = "SELECT * FROM symbols";
// execute query
if ($result = $mysqli->query($query)) {
    // see if any rows were returned
    if ($result->num_rows > 0) {
        // yes
        // print them one after another
        echo "<table cellpadding=10 border=1>";
        while($row = $result->fetch_array()) {
            echo "<tr>";
            echo "<td>".$row[0]."</td>";
            echo "<td>".$row[1]."</td>";
            echo "<td>".$row[2]."</td>";
            echo "</tr>";
        }
        echo "</table>";
    }
    else {
        // no
        // print status message
        echo "No rows found!";
    }

     // free result set memory
     $result->close();
}
else {
    // print error message
    echo "Error in query: $query. ".$mysqli->error;
}
// close connection
$mysqli->close();

?>

</body>
</html>
Here, the new keyword is used to instantiate an object of class mysqli, and
pass the object constructor connection information (including the database
name). The resulting object, stored in the variable $mysqli, then exposes
methods and properties to perform the tasks of querying, fetching and
processing rows, and handling errors.


If you look closely at the two scripts above, you'll notice the numerous
similarities between the function and method names, and the structure of
the script. Of the two, though, the object-oriented method is recommended,
especially in light of the new object model in PHP 5.


A couple of other important differences to keep in mind:


     With ext/mysqli, you can include the database name in the
     arguments passed to the mysqli_connect() function or to the
     mysqli()constructor.
     When calling mysqli_query() or the mysqli object's query()
     method, the link identifier is mandatory, not optional.



PHP 101 (part 8): Databases and Other Animals - Part 2




Part 8.2:
Surgical Insertion
So now you know how to execute a SELECT query to retrieve a result set
from the database. However, you can also use PHP's MySQL API for queries
that don't return a result set - for example, an INSERT or UPDATE query.
Consider the following example, which demonstrates this by asking for user
input through a form and then INSERT-ing that data into the database:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

if (!isset($_POST['submit'])) {
// form not submitted
?>

    <form action="<?=$_SERVER['PHP_SELF']?>" method="post">
    Country: <input type="text" name="country">
    National animal: <input type="text" name="animal">
    <input type="submit" name="submit">
    </form>

<?php
}
else {
// form submitted
// set server access variables
    $host = "localhost";
    $user = "test";
    $pass = "test";
    $db = "testdb";

// get form input
    // check to make sure it's all there
    // escape input values for greater safety
    $country = empty($_POST['country']) ? die ("ERROR:
Enter a country") : mysql_escape_string($_POST['country']);
    $animal = empty($_POST['animal']) ? die ("ERROR: Enter
an animal") : mysql_escape_string($_POST['animal']);

    // open connection
    $connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");
    // select database
    mysql_select_db($db) or die ("Unable to select
database!");

    // create query
    $query = "INSERT INTO symbols (country, animal) VALUES
('$country', '$animal')";

    // execute query
    $result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());

     // print message with ID of inserted record
     echo "New record inserted with ID ".mysql_insert_id();

     // close connection
     mysql_close($connection);
}
?>

</body>
</html>

Here, the user is first presented with a form asking for a country and its
national animal.




Once the form is submitted, the form input is used inside to create an
INSERT query, which is then sent to the database with the mysql_query()
method. Since mysql_query() returns a Boolean value indicating whether
the query was successful or not, it is possible to check whether the INSERT
took place and return an appropriate message:
There are two new functions in the example above. The
mysql_escape_string() function escapes special characters (like quotes)
in the user input so that it can be safely entered into the database; while the
mysql_insert_id() returns the ID generated by the previous INSERT
query (useful only if the table into which the INSERT occurs contains an
AUTO_INCREMENT field). Both these functions are also available in ext/
mysqli.

Wiping Out
Obviously, you can also do the same thing with other data manipulation
statements. This next example demonstrates how to use a DELETE
statement with PHP to selectively delete items from the table. For variety,
I'm going to use ext/mysqli this time around:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "test";
$pass = "test";
$db = "testdb";

// create mysqli object
// open connection
$mysqli = new mysqli($host, $user, $pass, $db);
// check for connection errors
if (mysqli_connect_errno()) {
    die("Unable to connect!");
}

// if id provided, then delete that record
if (isset($_GET['id'])) {
// create query to delete record
    $query = "DELETE FROM symbols WHERE id = ".$_GET['id'];

// execute query
    if ($mysqli->query($query)) {
    // print number of affected rows
    echo $mysqli->affected_rows." row(s) affected";
    }
    else {
    // print error message
    echo "Error in query: $query. ".$mysqli->error;
    }
}
// query to get records
$query = "SELECT * FROM symbols";

// execute query
if ($result = $mysqli->query($query)) {
    // see if any rows were returned
    if ($result->num_rows > 0) {
        // yes
        // print them one after another
        echo "<table cellpadding=10 border=1>";
        while($row = $result->fetch_array()) {
            echo "<tr>";
            echo "<td>".$row[0]."</td>";
            echo "<td>".$row[1]."</td>";
            echo "<td>".$row[2]."</td>";
            echo "<td><a href=".$_SERVER['PHP_SELF']."?
id=".$row[0].">Delete</a></td>";
            echo "</tr>";
        }
    }
    // free result set memory
    $result->close();
}
else {
    // print error message
    echo "Error in query: $query. ".$mysqli->error;
}
// close connection
$mysqli->close();

?>

</body>
</html>

Here's what it looks like:
Notice my usage of the affected_rows property of the mysqli object here
- this returns the total number of rows affected by the last operation. It's
available in ext/mysql as well, as the function mysql_affected_rows().


Looking Inside
PHP comes with a bunch of functions designed to tell you everything you
would ever want to know about the MySQL client and server, their version
numbers, the total number of databases available, the tables inside each
database, the processes running... you name it, and it's probably there.
Here's an example which uses them to give you a big-picture view of what's
going on inside your MySQL RDBMS:

<html>
<head>
<basefont face="Arial">
</head>
<body>

<?php

// set server access variables
$host = "localhost";
$user = "root";
$pass = "guessme";
$db = "testdb";

// open connection
$connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

// get database list
$query = "SHOW DATABASES";
$result = mysql_query($query) or die ("Error in query:
$query. ".mysql_error());
echo "<ul>";
while ($row = mysql_fetch_array($result)) {
    echo "<li>".$row[0];

    // for each database, get table list and print
    $query2 = "SHOW TABLES FROM ".$row[0];
    $result2 = mysql_query($query2) or die ("Error in
query: $query2. ".mysql_error());
    echo "<ul>";
    while ($row2 = mysql_fetch_array($result2)) {
        echo "<li>".$row2[0];
    }
    echo "</ul>";
}
echo "</ul>";

// get version and host information
echo "Client version: ".mysql_get_client_info()."<br />";
echo "Server version: ".mysql_get_server_info()."<br />";
echo "Protocol version: ".mysql_get_proto_info()."<br />";
echo "Host: ".mysql_get_host_info()."<br />";

// get server status
$status = mysql_stat();
echo $status;

// close connection
mysql_close($connection);
?>

</body>
</html>

Here's what the output might look like:
The first part of this script is fairly simple: it runs the SHOW DATABASES
query to get a list of databases, then iterates over the list and runs the SHOW
TABLES command to retrieve the list of tables inside each. Next, the
mysql_get_*_info() functions provide the client version number, the
MySQL version number, the version number of the special MySQL client-
server protocol used for communication between the two, the current host
name, and how it is connected to the MySQL server. Finally, new in PHP
4.3.0 is the mysql_stat() function, which returns a string containing
status information on the MySQL server (including information on server
uptime, open tables, queries per second and other statistical information).


Oops!
All done? Nope, not quite yet - before you go out there and start building
cool data-driven Web sites, you should be aware that both MySQL extensions
come with powerful error-tracking functions which can speed up
development time. Take a look at the following example, which contains a
deliberate error in the SELECT query string:

<?php
// connect
$connection = mysql_connect("localhost", "test", "test") or
die("Invalid server or user");
mysql_select_db("testdb", $connection) or die("Invalid
database");

// query
$query = "SELECT FROM symbols";

// result
$result = mysql_query($query,$connection);

// look for errors and print
if(!$result) {
    $error_number = mysql_errno();
    $error_msg = mysql_error();
    echo "MySQL error $error_number: $error_msg";
}

// disconnect
mysql_close($connection);

?>

Here's an example of the output:




The mysql_errno() function displays the error code returned by MySQL if
there's an error in your SQL statement, while the mysql_error() function
returns the actual error message. Turn these both on, and you'll find that
they can significantly reduce the time you spend fixing bugs.
The ext/mysqli code tree includes two additional functions for connection
errors, mysqli_connect_errno() and mysqli_connect_error(), which
contain information on connection (not query) errors only. Use these to
debug errors in your MySQL connections, as in the example below:

<?php

// create mysqli object
// open connection
$mysqli = new mysqli("localhost", "test", "test",
"testdb");

// check for connection errors
if (mysqli_connect_errno()) {
    die("Unable to connect: ".mysqli_connect_error());
}

// query
$query = "SELECT FROM symbols";

// execute query
$result = $mysqli->query($query);

// look for errors and print
if(!$result) {
    $error_number = $mysqli->errno;
    $error_msg = $mysqli->error;
    echo "MySQL error $error_number: $error_msg";
}

// disconnect
$mysqli->close();

?>
And in case you were wondering why I haven't used object syntax for these
two functions in the script above, it's actually very simple: I can't. You see, if
there is an error in connecting to the server, the mysqli() object will not be
created, and so methods and properties related to that object will not exist.
For this reason, to debug connection errors in ext/mysqli, you must
always use the procedural, rather than the object, notation.


And that's about all I have for this issue of PHP 101. In Part Nine I'm going
to tell you all about PHP 5's built-in DBMS alternative, the very cool SQLite
database engine. Don't miss it!




Part 9.1:
Hard Choices
If you've been paying attention, you now know how to use PHP's MySQL API
to perform queries and process result sets. You might even have started
thinking about how to re-program your site to run off a MySQL database. All
of this is a Good Thing - it means you're getting comfortable with using
PHP's database support to power your applications - but there's still a little
further to go.


As you saw in Part Eight, enabling MySQL support in PHP 5.0 is not as simple
as it used to be. Instead of supporting MySQL out of the box, PHP now
requires you to make all kinds of decisions about versions and libraries
before allowing you to hook your scripts up to a MySQL database. If you're
lazy (and deep down, we both know you are), you might instead prefer to
try a simpler option: the SQLite database engine.


Built-in SQLite support is new to PHP 5.0, and offers users a lightweight
database system that is fast, efficient and gets the job done. Since it's
enabled by default in PHP 5.0, it provides a viable alternative to MySQL; you
can use it out of the box, without spending time on version checks and
library downloads; just install PHP 5 and start typing. That's why I'm
devoting a whole tutorial to it - so get out of bed, make yourself some coffee
and let's get started!


Making New Friends
Before getting into the code, let's make sure that you have a clear idea of
what SQLite is (and isn't). Unlike MySQL, which operates on a client-server
paradigm, SQLite is a file-based database engine and uses file I/O (input/
output) functions to store and read databases from files on disk. It's also
much, much smaller than MySQL - the command-line version of SQLite
weighs in at under 200 KB - and supports most of the SQL commands you're
used to.


This small size shouldn't deceive you, however - according to the official
SQLite Web site, SQLite supports databases up to 2 terabytes in size and is
actually faster than MySQL in certain situations. SQLite database files are
easily portable, and SQLite databases created on Windows work fine on *NIX
platforms and vice-versa.


One of SQLite's more interesting aspects is that it is completely typeless.
Fields in an SQLite database need not be associated with a specific type, and
even if they are, you can still insert values of different types into them
(there is one exception to this rule, but I'll get to that later). This is
important, because it means that if you're concerned about values of the
wrong type getting into your tables, you need to write code to implement
type checking in your application.


Another important difference between MySQL and SQLite lies in their
licensing policies: unlike MySQL, SQLite source code is completely public-
domain, which means that you can use and distribute it however you choose
in both commercial and non-commercial products. Take a look at http://
sqlite.org/copyright.html for more on this.


In order to use SQLite and PHP together, your PHP build must include
SQLite. This is enabled by default in both the UNIX and Windows versions of
PHP 5. Read more about this at http://www.php.net/manual/en/
ref.sqlite.php. If you're a PHP 4.x user, though, don't lose heart - you can
still use SQLite, by manually downloading and installing php_sqlite.dll from
http://snaps.php.net (Windows) or the latest tarball from http://
pecl.php.net/package/SQLite (UNIX). You don't need to download anything
else; the SQLite 'client' is its own engine.


The Bookworm Turns
As with MySQL, you use regular SQL commands to interact with an SQLite
database. The exact SQL syntax used by SQLite is listed at http://sqlite.org/
lang.html, but for most operations SQL commands are standard.


Here's an example, which sets up the table I'll be using in this tutorial:

C:\WINDOWS\Desktop\sqlite>sqlite library.db
SQLite version 2.8.15
Enter ".help" for instructions
sqlite> create table books (
   ...> id integer primary key,
   ...> title varchar(255) not null,
   ...> author varchar(255) not null
   ...>);
sqlite> insert into books (title, author) values                 ('The Lord
Of The Rings', 'J.R.R. Tolkien');
sqlite> insert into books (title, author) values                 ('The
Murders In The Rue Morgue', 'Edgar Allen Poe');
sqlite> insert into books (title, author) values                 ('Three
Men In A Boat', 'Jerome K. Jerome');
sqlite> insert into books (title, author) values                 ('A Study
In Scarlet', 'Arthur Conan Doyle');
sqlite> insert into books (title, author) values                 ('Alice In
Wonderland', 'Lewis Carroll');
sqlite> .exit

You can enter these commands either interactively or non-interactively
through the SQLite commandline program, which is available at http://
sqlite.org/download.html as a precompiled binary for Windows and Linux.
SQLite 2.* is the version currently used in both branches of PHP, with SQLite
3.* support anticipated for PDO and later PHP 5.* releases.


Extract the downloaded files to a directory of your choice, cd into it from
your shell or DOS box and type 'sqlite'. You should see the SQLite version
information and the line:

Enter ".help" for instructions
Read http://sqlite.org/sqlite.html for more information on how to use the
commandline program.


Once the data has been imported into the database file library.db, run a
quick SELECT query to check if everything is working as it should:
sqlite> select * from books;

1|The Lord Of The Rings|J.R.R. Tolkien
2|The Murders In The Rue Morgue|Edgar Allen Poe
3|Three Men In A Boat|Jerome K. Jerome
4|A Study In Scarlet|Arthur Conan Doyle
5|Alice In Wonderland|Lewis Carroll
If you saw the same output as above, you're good to go!


Anatomy Class
Now, use PHP to communicate with SQLite, generate the same result set and
format it as an HTML page. Here's the code:

<html>
<head></head>
<body>
<?php
// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
$query = "SELECT * FROM books";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// if rows exist
if (sqlite_num_rows($result) > 0) {
    // get each row as an array
    // print values
    echo "<table cellpadding=10 border=1>";
    while($row = sqlite_fetch_array($result)) {
        echo "<tr>";
        echo "<td>".$row[0]."</td>";
        echo "<td>".$row[1]."</td>";
        echo "<td>".$row[2]."</td>";
        echo "</tr>";
    }
    echo "</table>";
}

// all done
// close database file
sqlite_close($handle);
?>
</body>
</html>

If all goes well, you should see something like this:
If you remember what you learned in Part Eight, the PHP script above should
be easy to decipher. In case you don't, here's a fast rundown:


 1.   The ball starts rolling with the sqlite_open() function, which
      accepts the name of the database file as argument and attempts to
      open it. If this database file cannot be found, an empty database file
      will be created with the supplied name (assuming the script has write
      access to the directory). <?php

      $db = $_SERVER['DOCUMENT_ROOT']."/../library.db";
      $handle = sqlite_open($db) or die("Could not open
      database");

      ?>

      The database file library.db needs to be kept somewhere it can't be
      accessed through the browser by visitors to your site. That means that
      you need to create it outside your public_html, www or htdocs
      directory, in a directory that allows your scripts read/write
      permissions. Web hosting companies generally will offer a space above
      your web-visible directory where you can do this.
      $_SERVER['DOCUMENT_ROOT']."/.." is the directory directly above
      your web-visible directory.
     If successful, the sqlite_open() function returns a handle to the file,
     which is stored in the variable $handle and is used for all subsequent
     communication with the database.
2.   The next step is to create and execute the query, with the
     sqlite_query() function. <?php

     $query = "SELECT * FROM books";
     $result = sqlite_query($handle, $query) or die("Error
     in query:
     ".sqlite_error_string(sqlite_last_error($handle)));

     ?>

     This function also needs two parameters: the database handle and the
     query string. Depending on whether or not the query was successful,
     the function returns true or false; in the event of a failure, the
     sqlite_error_string() and sqlite_last_error() functions can
     be used to display the error that took place.
3.   If sqlite_query() is successful, the result set returned by the query
     is stored in the variable $result. You can retrieve the records in the
     result set with the sqlite_fetch_array() function, which fetches a
     single row of data as an array called $row. Fields in that record are
     represented as array elements, and can be accessed using standard
     index notation. Each time you call sqlite_fetch_array(), the next
     record in the result set is returned. This makes
     sqlite_fetch_array() very suitable for use in a while() loop, in
     much the same way as mysql_fetch_row() was used earlier.
     <?php

     if (sqlite_num_rows($result) > 0) {
         echo "<table cellpadding=10 border=1>";
         while($row = sqlite_fetch_array($result)) {
             echo "<tr>";
             echo "<td>".$row[0]."</td>";
             echo "<td>".$row[1]."</td>";
             echo "<td>".$row[2]."</td>";
                echo "</tr>";
           }
           echo "</table>";
      }

      ?>
      The number of records returned by the query can be retrieved with the
      sqlite_num_rows() function. Or, if what you're really interested in is
      the number of fields in the result set, use the sqlite_num_fields()
      function instead. Of course, these are only applicable with queries that
      actually return records; it doesn't really make sense to use them with
      INSERT, UPDATE or DELETE queries.
 4.   Once you're done, it's a good idea to close the database handle and
      return the used memory to the system, with a call to
      sqlite_close(): <?php

      sqlite_close($handle);

      ?>
In PHP 5 you can also use the SQLite API in an object-oriented way, wherein
each of the functions above becomes a method of the SQLiteDatabase()
object. Take a look at this next listing, which is equivalent to the one above:

<html>
<head></head>
<body>
<?php
// set path of database file
$file = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// create database object
$db = new SQLiteDatabase($file) or die("Could not open
database");

// generate query string
$query = "SELECT * FROM books";
// execute query
// return result object
$result = $db->query($query) or die("Error in query");

// if rows exist
if ($result->numRows() > 0) {
    // get each row as an array
    // print values
    echo "<table cellpadding=10 border=1>";
    while($row = $result->fetch()) {
        echo "<tr>";
        echo "<td>".$row[0]."</td>";
        echo "<td>".$row[1]."</td>";
        echo "<td>".$row[2]."</td>";
        echo "</tr>";
    }
    echo "</table>";
}

// all done
// destroy database object
unset($db);
?>
</body>
</html>

Here, the new keyword is used to instantiate an object of the class
SQLiteDatabase() by passing the object constructor the name of the
database file. If the database file does not already exist, a new database file
is created. The resulting object, stored in $db, then exposes methods and
properties to perform queries. Every query returns an instance of the class
SQLiteResult(), which in turn exposes methods for fetching and
processing records.
If you look closely at the two scripts above, you'll see the numerous
similarities between the procedural function names and the object method
names. While the correspondence between the two is not perfect, it's usually
close enough to make it possible to guess the one if you know the other.


Different Strokes
As with the MySQL API, PHP's SQLite API offers you more than one way to
skin a cat. For example, you can retrieve each row as an object with the
sqlite_fetch_object() method, and access field values by using the
field names as object properties. Here's an example:

<html>
<head></head>
<body>
<?php
// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
$query = "SELECT * FROM books";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// if rows exist
if (sqlite_num_rows($result) > 0) {
    // get each row as an object
    // print field values as object properties
    echo "<table cellpadding=10 border=1>";
    while($obj = sqlite_fetch_object($result)) {
          echo   "<tr>";
          echo   "<td>".$obj->id."</td>";
          echo   "<td>".$obj->title."</td>";
          echo   "<td>".$obj->author."</td>";
          echo   "</tr>";
     }
     echo "</table>";
}

// all done
// close database file
sqlite_close($handle);
?>
</body>
</html>

Another option is to retrieve the complete result set in one fell swoop with
the sqlite_fetch_all() function. This function retrieves the complete set
of records as an array of arrays; each element of the outer array represents
a record, and is itself structured as an array whose elements represent fields
in that record.


Here's an example, which might make this clearer:

<html>
<head></head>
<body>
<?php
// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
$query = "SELECT * FROM books";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// get the complete result set as a series of nested arrays
$data = sqlite_fetch_all($result);

// all done
// close database file
sqlite_close($handle);

// check the array to see if it contains at least one
record
if (sizeof($data) > 0) {
    echo "<table cellpadding=10 border=1>";
    // iterate over outer array (rows)
    // print values for each element of inner array
(columns)
    foreach ($data as $row) {
        echo "<tr>";
        echo "<td>".$row[0]."</td>";
        echo "<td>".$row[1]."</td>";
        echo "<td>".$row[2]."</td>";
        echo "</tr>";
    }
    echo "</table>";
}
?>
</body>
</html>

In all the previous examples, the database remained open while the result
set was processed, because records were retrieved one after another with
the sqlite_fetch_array() or sqlite_fetch_object() functions. The
example above is unique in that the database can be closed before the result
set array is processed. This is because the entire result set is retrieved at
once and stored in the $data array, so there really isn't any need to leave
the database open while processing it.


If your result set contains only a single field, use the
sqlite_fetch_single()function, which retrieves the value of the first
field of a row. The PHP manual puts it best when it says "this is the most
optimal way to retrieve data when you are only interested in the values from
a single column of data." Take a look:

<html>
<head></head>
<body>
<?php
// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
// this query returns only a single record with a single
field
$query = "SELECT author FROM books WHERE title = 'A Study
In Scarlet'";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// if a row exists
if (sqlite_num_rows($result) > 0) {
    // get the value of the first field of the first row
    echo sqlite_fetch_single($result);
}

// all done
// close database file
sqlite_close($handle);
?>
</body>
</html>

You can even use the sqlite_fetch_single() function in combination
with a while() loop to iterate over a result set containing many records but
a single field. Notice also my usage of the sqlite_has_more() function, to
check if the next row exists or not.

<html>
<head></head>
<body>
<?php
// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
$query = "SELECT DISTINCT author FROM books";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// if rows exist
if (sqlite_num_rows($result) > 0) {
    echo "<table cellpadding=10 border=1>";
    // check for more rows
     while (sqlite_has_more($result)) {
         // get first field from each row
         // print values
         $row = sqlite_fetch_single($result);
         echo "<tr>";
         echo "<td>".$row."</td>";
         echo "</tr>";
     }
     echo "</table>";
}

// all done
// close database file
sqlite_close($handle);
?>
</body>
</html>

You can, of course, do the same thing using object notation in PHP 5.
However, you need to know that sqlite_has_more() is one function that
really doesn't translate to its object method name; in an OO script, you
would need to call $result->valid();.


This script is the OO equivalent of the one above:
<html>
<head></head>
<body>
<?php
// set path of database file
$file = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// create database object
$db = new SQLiteDatabase($file) or die("Could not open
database");

// generate query string
$query = "SELECT DISTINCT author FROM books";

// execute query
$result = $db->query($query) or die("Error in query");

// if rows exist
if ($result->numRows() > 0) {
    echo "<table cellpadding=10 border=1>";
    // check for more rows
    while ($result->valid()) {
        // get first field from each row
        // print values
        $row = $result->fetchSingle();
        echo "<tr>";
        echo "<td>".$row."</td>";
        echo "</tr>";
    }
    echo "</table>";
}

// all done
// destroy database object
unset($db);
?>
</body>
</html>

PHP 101 (part 9): SQLite My Fire! - Part 2




Part 9.2:
Not My Type
Whilst on the topic of INSERT, remember my statement a couple pages back
about how SQLite is typeless and so you can insert values of any type into
any field? There is one important exception to this rule: a field marked as
INTEGER PRIMARY KEY. In SQLite, fields marked as INTEGER PRIMARY
KEY do two important things: they provide a unique numeric identifier for
each record in the table, and if you insert a NULL value into them, SQLite
automatically inserts a value that is 1 greater than the largest value already
present in that field.


INTEGER PRIMARY KEY fields in SQLite thus perform the equivalent of
AUTO_INCREMENT fields in MySQL, and are a convenient way of
automatically numbering your records. Obviously, you can't insert non-
numeric values into such a field, which is why I said they were an exception
to the typeless rule. Read more about this at http://www.sqlite.org/
datatypes.html.


Since the books table used in the previous example already contains such a
field (the id field), it's clear that every INSERT into it with a NULL value for
that field generates a new record number. If you'd like to retrieve this
number, PHP has a way to do that too - just use the
sqlite_last_insert_rowid() function, which returns the ID of the last
inserted row (equivalent to the mysql_insert_id() function in PHP's
MySQL API).


To see this in action, update the if() loop in the middle of the previous
script to include a call to sqlite_last_insert_rowid(), as follows:

<?php

// check to see if the form was submitted with a new record
if (isset($_POST['submit'])) {
    // make sure both title and author are present
if (!empty($_POST['title']) && !empty($_POST['author'])) {
        // generate INSERT query
        $insQuery = "INSERT INTO books (title, author)
VALUES (\"".sqlite_escape_string($_POST['title'])."\",
\"".sqlite_escape_string($_POST['author'])."\")";
        // execute query
        $insResult = sqlite_query($handle, $insQuery) or
die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));
        // print success message
        echo "<i>Record successfully inserted with ID
".sqlite_last_insert_rowid($handle)."!</i><p />";
    }
    else {
        // missing data
        // display error message
        echo "<i>Incomplete form input. Record not
inserted!</i><p />";
    }
}

?>

If you need to, you can also find out how many rows were affected using the
sqlite_changes() function - try it for yourself and see!

Starting From Scratch
You'll remember, from the beginning of this tutorial, that I suggested you
initialize the library.db database using the SQLite commandline program.
Well, that isn't the only way to create a fresh SQLite database - you can use
PHP itself to do this, by issuing the necessary CREATE TABLE and INSERT
commands through the sqlite_query() function. Here's how:

<?php

// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library2.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");
// create database
sqlite_query($handle, "CREATE TABLE books (id INTEGER
PRIMARY KEY, title VARCHAR(255) NOT NULL, author
VARCHAR(255) NOT NULL)") or die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

// insert records
sqlite_query($handle, "INSERT INTO books (title, author)
VALUES ('The Lord Of The Rings', 'J.R.R. Tolkien')") or
die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

sqlite_query($handle, "INSERT INTO books (title, author)
VALUES ('The Murders In The Rue Morgue', 'Edgar Allan
Poe')") or die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

sqlite_query($handle, "INSERT INTO books (title, author)
VALUES ('Three Men In A Boat', 'Jerome K. Jerome')") or
die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

sqlite_query($handle, "INSERT INTO books (title, author)
VALUES ('A Study In Scarlet', 'Arthur Conan Doyle')") or
die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

sqlite_query($handle, "INSERT INTO books (title, author)
VALUES ('Alice In Wonderland', 'Lewis Carroll')") or
die("Error in query:
".sqlite_error_string(sqlite_last_error($handle)));

// print success message
echo "<i>Database successfully initialized!";
// all done
// close database file
sqlite_close($handle);

?>

Or, in PHP 5, you can use the object-oriented approach:

<?php

// set path of database file
$file = $_SERVER['DOCUMENT_ROOT']."/../library3.db";

// create database object
$db = new SQLiteDatabase($file) or die("Could not open
database");

// create database
$db->query("CREATE TABLE books (id INTEGER PRIMARY KEY,
title VARCHAR(255) NOT NULL, author VARCHAR(255) NOT
NULL)") or die("Error in query");

// insert records
$db->query("INSERT INTO books (title, author) VALUES ('The
Lord Of The Rings', 'J.R.R. Tolkien')") or die("Error in
query");

$db->query("INSERT INTO books (title, author) VALUES ('The
Murders In The Rue Morgue', 'Edgar Allan Poe')") or
die("Error in query");

$db->query("INSERT INTO books (title, author) VALUES
('Three Men In A Boat', 'Jerome K. Jerome')") or die("Error
in query");

$db->query("INSERT INTO books (title, author) VALUES ('A
Study In Scarlet', 'Arthur Conan Doyle')") or die("Error in
query");

$db->query("INSERT INTO books (title, author) VALUES
('Alice In Wonderland', 'Lewis Carroll')") or die("Error in
query");

// print success message
echo "<i>Database successfully initialized!";

// all done
// destroy database object
unset($db);

?>


A Few Extra Tools
Finally, the SQLite API also includes some ancillary functions, to provide you
with information on the SQLite version and encoding, and on the error code
and message generated by the last failed operation. The following example
demonstrates the sqlite_libversion() and sqlite_libencoding()
functions, which return the version number and encoding of the linked
SQLite library respectively:

<?php

// version
echo "SQLite version: ".sqlite_libversion()."<br />";
// encoding
echo "SQLite encoding: ".sqlite_libencoding()."<br />";

?>

When things go wrong, reach for the sqlite_last_error() function,
which returns the last error code returned by SQLite. Of course, this error
code - a numeric value - is not very useful in itself; to convert it to a human-
readable message, couple it with the sqlite_error_string() function.
Consider the following example, which illustrates by attempting to run a
query with a deliberate error in it:

<?php

// set path of database file
$db = $_SERVER['DOCUMENT_ROOT']."/../library.db";

// open database file
$handle = sqlite_open($db) or die("Could not open
database");

// generate query string
// query contains a deliberate error
$query = "DELETE books WHERE id = 1";

// execute query
$result = sqlite_query($handle, $query) or die("Error in
query: ".sqlite_error_string(sqlite_last_error($handle)));

// all done
// close database file
sqlite_close($handle);

?>

Here's what the output looks like:
Note that although they might appear similar, the sqlite_last_error()
and sqlite_error_string() functions don't work in exactly the same way
as the mysql_errno() and mysql_error() functions. The
mysql_errno() and mysql_error() functions can be used independently
of each other to retrieve the last error code and message respectively, but
the sqlite_error_string() is dependent on the error code returned by
sqlite_last_error().

If your appetite has been whetted, you can read more about the things PHP
can do with SQLite in Zend's PHP 5 In Depth section.
And that's about all I have for you in this tutorial. More secrets await you in
Part 10 of PHP 101, so make sure you come back for that one!




Part 10:
Patience Pays
Now that you've used PHP with MySQL and SQLite, you probably think you
know everything you need to get started with PHP programming. In fact, you
might even be thinking of cutting down your visits to Zend.com altogether,
giving up this series for something flashier and cooler...


Uh-uh. Big mistake.


You see, while built-in database support makes programming with PHP easy,
it isn't the only thing that makes PHP so popular. An easy-to-use XML API
and new exception handling mechanism (in PHP 5), support for pluggable
modules, and built-in session management are just some of the many other
features that make PHP rock. And all these capabilities are going to be
explored, in depth, right here in this very series, if you can just find it in
yourself to hang around a little longer. So close your eyes, take a deep
breath, and read on to find out all about this tutorial's topic: sessions and
cookies.


Party Time
Maybe you heard this at the last party you went to: "HTTP is a stateless
protocol, and the Internet is a stateless development environment".


No? Hmmm. Obviously, you don't go to the right parties.


In simple language, all this means is that HTTP, the HyperText Transfer
Protocol that is the backbone of the Web, is unable to retain a memory of
the identity of each client that connects to a Web site, and therefore treats
each request for a Web page as a unique and independent connection, with
no relationship whatsoever to the connections that preceded it. This
"stateless environment" works great so long as you're aimlessly surfing the
Web, but it can cause a serious headache for sites that actually depend on
the data accumulated in previous requests. The most common example is
that of an online shopping cart - in a stateless environment, it becomes
difficult to keep track of all the items you've shortlisted for purchase as you
jump from one catalog page to another.


Obviously, then, what is required is a method that makes it possible to
"maintain state", allowing client connections to be tracked and connection-
specific data to be maintained. And thus came about cookies, which allow
Web sites to store client-specific information on the client system, and
access the information whenever required. A cookie is simply a file,
containing a series of variable-value pairs and linked to a domain. When a
client requests a particular domain, the values in the cookie file are read and
imported into the server environment, where a developer can read, modify
and use them for different purposes. A cookie is a convenient way to carry
forward data from one client visit to the next.


Another common approach is to use a session to store connection-specific
data; this session data is preserved on the server for the duration of the
visit, and is destroyed on its conclusion. Sessions work by associating every
session with a session ID (a unique identifier for the session) that is
automatically generated by PHP. This session ID is stored in two places: on
the client using a temporary cookie, and on the server in a flat file or a
database. By using the session ID to put a name to every request received,
a developer can identify which client initiated which request, and track and
maintain client-specific information in session variables (variable-value pairs
which remain alive for the duration of the session and which can store
textual or numeric information).


Sessions and cookies thus provide an elegant way to bypass the stateless
nature of the HTTP protocol, and are used on many of today's largest sites to
track and maintain information for personal and commercial transactions.
Typically, you use a session to store values that are required over the course
of a single visit, and a cookie to store more persistent data that is used over
multiple visits.


PHP has included support for cookies since PHP 3.0, and built-in session
management since PHP 4.0. Both these features are enabled by default, so
you don't have to do anything special to activate them. Instead, scroll down
and take a look at your first session.


The First Session
One of the standard examples used to demonstrate how a session works is
the hit counter application. This is a simple counter that initializes a variable
the first time you visit a Web page, and increments it each time you reload
the page. The counter variable is stored in a session, which means that if
you browse to another site and then return, the last saved value of the
counter will be restored (so long as you didn't destroy the session by
shutting down the browser in the interim).


Take a look at the code:

<?php

// initialize a session
session_start();

// increment a session counter
$_SESSION['counter']++;

// print value
echo "You have viewed this page " . $_SESSION['counter'] .
" times";

?>

To see how this works, request the script above through your browser a few
times. You will notice that the counter increases by 1 on each subsequent
page load. If you open up two browser windows and request the same page
in each one, PHP will maintain and increment individual session counters for
each browser instance. The session ID is used to identify which client made
which request, and recreate the prior saved environment for each individual
session. This also means that if you visit one (or more) other Web sites
during the same session and then return to the script above without shutting
down your browser in the interim, your previous session will be retrieved
and recreated for you.


Every session in PHP begins with a call to the session_start() function.
This function checks to see whether a session already exists, and either
restores it (if it does) or creates a new one (if it doesn't). Session variables
can then be registered by adding keys and values to the special $_SESSION
superglobal array, and can be accessed at any time during the session using
standard array notation. In the example above, a key named counter has
been added to the $_SESSION array. The first time a session is created, this
key will have the value 0. On every subsequent request for the page during
the same session, the previous value of the counter will be retrieved and
incremented by 1.


If the example above doesn't work as advertised, check to make sure that
the session.save_path variable in your php.ini file points to a valid
temporary directory for your system. This value is hard-wired to /tmp by
default, so if you're trying the example on a Windows system, you will need
to edit it to C:\Windows\temp (or your system's temporary directory).


Remember Me
Here's another example, this one asking you to log in and then storing your
login name and session start time as two session variables. This information
is then used to display the total number of minutes the session has been
active.

<?php

// initialize a session
session_start();
?>
<html>
<head></head>
<body>

<?php
if (!isset($_SESSION['name']) && !isset($_POST['name'])) {
    // if no data, print the form
?>
    <form action="<?php echo $_SERVER['PHP_SELF']?>"
method="post">
        <input type="text" name="name">
        <input type="submit" name="submit" value="Enter
your name">
    </form>
<?php
}
else if (!isset($_SESSION['name']) &&
isset($_POST['name'])) {
    // if a session does not exist but the form has been
submitted
    // check to see if the form has all required values
    // create a new session
    if (!empty($_POST['name'])) {
        $_SESSION['name'] = $_POST['name'];
        $_SESSION['start'] = time();
        echo "Welcome, " . $_POST['name'] . ". A new
session has been activated for you. Click <a href=" .
$_SERVER['PHP_SELF'] . ">here</a> to refresh the page.";
    }
    else {
        echo "ERROR: Please enter your name!";
    }
}
else if (isset($_SESSION['name'])) {
    // if a previous session exists
    // calculate elapsed time since session start and now
    echo "Welcome back, " . $_SESSION['name'] . ". This
session was activated " . round((time() -
$_SESSION['start']) / 60) . " minute(s) ago. Click <a
href=" . $_SERVER['PHP_SELF'] . ">here</a> to refresh the
page.";
}
?>
</body>
</html>

In this example, the presence or absence of a session variable is used to
decide which of the three possible screens to display. The session start time
is also recorded in $_SESSION['start'] with the time() function, which
returns the total number of seconds between January 1 1970 and the
current time. At a later stage, the value stored in $_SESSION['start'] is
compared with the most current value of time() to calculate and display an
(approximate) display of elapsed time.


It's important to note that the call to session_start() must appear first,
before any output is generated by the script (assuming you're not using
PHP's output buffering feature, which you can read about at http://
www.php.net/manual/en/ref.outcontrol.php). This is because the PHP
session handler internally uses in-memory cookies to store session data, and
the cookie creation headers must be transmitted to the client browser before
any output. If you ever see an error like this in one of your session-enabled
pages:

Warning: Cannot send session cache limiter - headers already
sent (output started at ...)



it's usually because somewhere, somehow, some output has found its way to
the browser before session_start() was called. Even a carriage return or
a blank space outside the PHP tags surrounding session_start() can
cause this error, so watch out for them.


As noted previously, every session has a unique session ID, which PHP uses
to keep track of different clients. This session ID is a long alphanumeric
string, which is automatically passed by PHP from page to page so that the
continuity of the session is maintained. To see what it looks like, use the
session_id() function, as in this simple example:

<?php

// initialize a session
session_start();

// print session ID
echo "I'm tracking you with session ID " . session_id();

?>

When the user shuts down the client browser and destroys the session, the
$_SESSION array will be flushed of all session variables. You can also
explicitly destroy a session - for example, when a user logs out - by calling
the session_destroy() function, as in the following example:
<?php

// initialize a session
session_start();

// then destroy it
session_destroy();

?>

In case you were wondering if you read that right - yes, before you can call
session_destroy() to destroy a session, you must first call
session_start() to recreate it.

Remember that $_SESSION is a superglobal, so you can use it inside and
outside functions without needing to declare it as global first. The following
simple example illustrates this:

<?php

// initialize a session
session_start();

// this function checks the value of a session variable
// and returns true or false
function isAdmin() {
    if ($_SESSION['name'] == 'admin') {
        return true;
    }
    else {
        return false;
    }
}

// set a value for $_SESSION['name']
$_SESSION['name'] = "guessme";
// call a function which uses a session variable
// returns false here
echo isAdmin()."<br />";

// set a new value for $_SESSION['name']
$_SESSION['name'] = "admin";
// call a function which uses a session variable
// returns true here
echo isAdmin()."<br />";

?>

You can read more about sessions and session handling functions at http://
www.php.net/manual/en/ref.session.php.


Rules Of The Game
A session works by using an in-memory cookie, which explains why it's only
active while the browser instance that created it is active; once the browser
instance is terminated, the memory allocated to that instance is flushed and
returned to the system, destroying the session cookie in the process. If you
want longer-lasting cookies, you can use PHP's built-in cookie functions to
write data to the user's disk as a cookie file, and read this data back as and
when needed.


Before you start using cookies, there are a few things you should be aware
of:


 1.   Since cookies are used to record information about your activities on a
      particular domain, they can only be read by the domain that created
      them
 2.   A single domain cannot set more than twenty cookies, and each cookie
      is limited to a maximum size of 4 KB
 3.   A cookie usually possesses six attributes, of which only the first is
      mandatory. Here they are:
             name: the name of the cookie
           value: the value of the cookie
           expires: the date and time at which the cookie expires
           path: the top-level directory on the domain from which cookie
           data can be accessed
           domain: the domain for which the cookie is valid
           secure: a Boolean flag indicating whether the cookie should be
           transmitted only over a secure HTTP connection



More information on cookies can be obtained from Netscape, the people who
originally invented them. Visit http://www.netscape.com/newsref/std/
cookie_spec.html for the Netscape cookie specification.


It's important to remember that, since cookies are stored on the user's hard
drive, you as the developer have very little control over them. If a user
decides to turn off cookie support in his or her browser, your cookies will
simply not be saved. Therefore, avoid writing code that depends heavily on
cookies; and have a backup plan ready in case cookie data cannot be
retrieved from the client.


With that caveat out of the way, let's look at some simple cookie-handling
code in PHP.


Meeting Old Friends
PHP offers a single function for cookie manipulation: setcookie(). This
function allows you to read and write cookie files, as demonstrated in the
following example:

<?php

if (!isset($_COOKIE['visited'])) {
    // if a cookie does not exist
    // set it
    setcookie("visited", "1", mktime()+86400, "/") or
die("Could not set cookie");
     echo "This is your first visit here today.";
}
else {
    // if a cookie already exists
    echo "Nice to see you again, old friend!";
}

?>

To see how this works, request the page above through your browser a
couple of times. The first time around, because no cookie has yet been set,
the first message will be displayed. On all subsequent attempts, because the
cookie has already been set, the client will be recognized and the second
message will be displayed. Note that this works even if you terminate the
browser instance, restart it and visit the page again - a marked difference
from what happened in the session examples you saw earlier.


The setcookie() function accepts six arguments: the name of the cookie,
its value, its expiry date, the domain, the path for which it is valid, and a
Boolean value indicating its security state. As noted previously, only the
name and value are mandatory, although the example above specifies both a
top-level directory and an expiry date for the cookie (1 day) with the
mktime() function, which works like the time() function described
previously.


Cookie values are automatically sent to PHP from the client, and converted
to key-value pairs in the $_COOKIE variable, a superglobal array similar to
$_SESSION. Values can then be retrieved using standard associative array
notation, as in the example above. Note that, as with sessions, calls to
setcookie() must take place before any output is generated by the script,
or else you'll see an error like this:

Warning: Cannot add header information - headers already sent by
(output started at ... )
Form And Function
Here's another, slightly more complex example:

<?php

if (!isset($_POST['email'])) {
    // if form has not been submitted
    // display form
    // if cookie already exists, pre-fill form field with
cookie value
?>
    <html>
    <head></head>
    <body>

    <form action="<?php echo $_SERVER['PHP_SELF']?>"
method="post">
        Enter your email address: <input type="text"
name="email" value="<?php echo $_COOKIE['email']; ?>">
        <input type="submit" name="submit">
        <?php
        // also calculate the time since the last
submission
        if ($_COOKIE['lastsave']) {
             $days = round((time() - $_COOKIE['lastsave']) /
86400);
            echo "<br /> $days day(s) since last
submission";
        }
        ?>
    </form>

    </body>
    </html>
<?php
}
else {
    //  if form has been submitted
    //  set cookies with form value and timestamp
    //  both cookies expire after 30 days
    if  (!empty($_POST['email'])) {
         setcookie("email", $_POST['email'], mktime()
+(86400*30), "/");
         setcookie("lastsave", time(), mktime()+(86400*30),
"/");
         echo "Your email address has been recorded.";
    }
    else {
         echo "ERROR: Please enter your email address!";
    }
}
?>
</body>
</html>

In this case, the value entered into the form is stored as a cookie called
email, and automatically retrieved to pre-fill the form field on all subsequent
requests. This technique is frequently used by Web sites that require the
user to enter a login name and password; by automatically pre-filling the
username field in the login box with the value used in the last successful
attempt, they save the user a few keystrokes.


This example also demonstrates how you can set more than one cookie for a
domain, by calling setcookie() multiple times. In the example above, the
time at which the data was entered is stored as a second cookie, and used to
calculate the time elapsed between successive entries.


To remove a cookie from the client, simply call setcookie() with the same
syntax you used to originally set the cookie, but an expiry date in the past.
This will cause the cookie to be removed from the client system. Here's an
example:
<?php

// delete cookie
setcookie("lastsave", NULL, mktime() - 3600, "/");

?>

Read more about cookies and the setcookie() function at http://
www.php.net/manual/en/features.cookies.php and http://www.php.net/
manual/en/function.setcookie.php.


Access Granted
As I said at the beginning of this tutorial, cookies and sessions are two
different ways of making data "persistent" on the client. A session retains
data for the duration of the session, while a cookie retains values for as long
as you need it to. With that in mind, let's now look at an example that uses
them both.


The application here is a simple user authentication system, where certain
pages can only be viewed by users who successfully log in to the system.
Users who have not been authenticated with a valid password are denied
access to these "special" pages. The list of valid usernames and passwords is
stored in a MySQL database, and PHP is used to verify a user's credentials
and decide whether or not to grant access.


Assuming the MySQL database table looks like this

+-------+-----------------------------------------------+
| name | pass                                           |
+-------+-----------------------------------------------+
| sue   | 9565d44fd0fe4db59f073eea1db70f3ea258e10b      |
| harry | 6e74234b8b552685113b53c7bff0f386c8cef8cf      |
| louis | 6817dda51b64b8190029490d2811a4d9cb9cd432      |
| sam   | bd17f8243e771a57cfbb06aa9a82bbf09fd2d90b      |
| james | 792ec9b44d432c947ac6775b2b52326e9d08512f      |
+-------+-----------------------------------------------+



with a unique username field and a password field created with the SHA1()
function, here's the PHP script that does all the hard work:

<?php

if (isset($_POST['name']) || isset($_POST['pass'])) {
    // form submitted
    // check for required values
    if (empty($_POST['name'])) {
        die ("ERROR: Please enter username!");
    }
    if (empty($_POST['pass'])) {
        die ("ERROR: Please enter password!");
    }

    // set server access variables
    $host = "localhost";
    $user = "test";
    $pass = "test";
    $db = "db2";

    // open connection
    $connection = mysql_connect($host, $user, $pass) or die
("Unable to connect!");

    // select database
    mysql_select_db($db) or die ("Unable to select
database!");

    // create query
    $query = "SELECT * FROM users WHERE name = '" .
$_POST['name'] . "' AND pass = SHA1('" . $_POST['pass'] .
"')";
    // execute query
    $result = mysql_query($query) or die ("Error in query:
$query. " . mysql_error());

    // see if any rows were returned
    if (mysql_num_rows($result) == 1) {
        // if a row was returned
        // authentication was successful
        // create session and set cookie with username
        session_start();
        $_SESSION['auth'] = 1;
        setcookie("username", $_POST['name'], time()
+(84600*30));
        echo "Access granted!";
    }
    else {
        // no result
        // authentication failed
        echo "ERROR: Incorrect username or password!";
    }

    // free result set memory
    mysql_free_result($result);

    // close connection
    mysql_close($connection);
}
else {
    // no submission
    // display login form
?>
    <html>
    <head></head>
    <body>
    <center>
    <form method="post" action="<?php echo
$_SERVER['PHP_SELF']; ?>">
    Username <input type="text" name="name" value="<?php
echo $_COOKIE['username']; ?>">
    <p />
    Password <input type="password" name="pass">
    <p />
    <input type="submit" name="submit" value="Log In">
    </center>
    </body>
    </html>
<?php
}

?>

Here, the values entered into the login box are integrated into a MySQL
SELECT query, which is executed on the user table. If both username and
password match, a single record will be returned, indicating that
authentication succeeded; if they don't, no records will be returned,
indicating that authentication failed.


Assuming authentication succeeds, a session is initialized, the
$_SESSION['auth'] key is created and assigned a value of Boolean true,
and the username is stored in a cookie for next time. The cookie will remain
valid for 30 days, and will be used to pre-fill the username field in the login
box on the next login attempt.


Of course, this isn't enough by itself. While the script above performs
authentication and initializes both a session and a cookie if the user's
credentials are validated, a security check must also be carried out on each
of the restricted pages. Without this check, any user could bypass the login
screen and simply type in the exact URL to each page to view it.


Since it is clear from the previous script that the session variable
$_SESSION['auth'] can only exist if the user's credentials have been
validated, it suffices to check for the presence of the $_SESSION['auth']
variable at the top of each restricted page, and grant access if that check
returns true. Here's how:

<?php

// start session
session_start();
if (!$_SESSION['auth'] == 1) {
    // check if authentication was performed
    // else die with error
    die ("ERROR: Unauthorized access!");
}
else {
?>
    <html>
    <head></head>
    <body>
    This is a secure page. You can only see this if
$_SESSION['auth'] = 1
    </body>
    </html>
<?php
}

?>

Pretty neat, huh? Only authenticated users will be able to see this page,
because only their clients will have a session with the $_SESSION['auth']
variable in it. Everyone else will simply see an error message.


That's about it for this tutorial. In Part Eleven, I'll be telling you all about
SimpleXML, the new XML processing toolkit that comes bundled with PHP 5.
Make sure you come back for that!

								
To top