21.2 Building a Web Shop


Nowadays Web shops are an essential component of every modern company's business strategy. Web shops are not built just for selling products. In many cases they are also a company's presence on the Web and will help you to present your products to a broad audience. The advantage of Web shops over other types of advertising is that people visit your Web sites to retrieve information they are not annoyed by advertisements.

In this section you will see how to build shopping carts and how to develop personalized sites. The application consists of two screens. The first one will display the products in the database. The second script will reduce the number of products that are still in the stores, and display a list of all products a customer has bought.

21.2.1 Getting Started

Let's get started by defining a simple data structure for our shop. To keep the example small and easy to understand, we start with one table. The example is designed in a simple way. It is not intended to be a complete shop because thousands of lines of code would be far too confusing for this book:

 CREATE TABLE product (         id int4,                -- unique id of a product         name text,              -- name of a product         instock int4,           -- number of products in stock         price numeric(9,2),     -- price of products         PRIMARY KEY (id) ); COPY product FROM stdin USING DELIMITERS ';'; 1;PostgreSQL Developer's Handbook;345;41.99 2;PHP and PostgreSQL;2534;41.59 3;Python Developer's Handbook;962;39.52 4;mod_perl;0;49.99 5;PostgreSQL For UNIX Programmers;1;54.69 6;Visual C++;2;29.19 \. 

As you can see, the table contains information about products. Every product has an id, a name, and a price. In addition, the database stores the number of products that are still in the store.

Our prototype consists of various files. Let's take a look at the files needed in this example, which are shown in Table 21.1.

Table 21.1. Files Needed in This Example
File Purpose
cart.php Creates new objects for shopping cart and session management.
cash.php Checkout; lists the products the customer has bought and reduces the number of products that are still in the store.
error.php Error handling.
incshop.php Helps to get around problems concerning serialization.
ss_libcart.php Library for working with shopping cart. It is an extension for the class called db defined in libdb.php.
libdb.php The database library.
libhtml.php An HTML library.
shop.php The starting screen.
temp_cash.html An HTML template.
temp_list.html An HTML template for listing the products in the database.

In this section you will see various versions of these files. You will see how to build session-driven as well as cookie-driven applications. The goal of this section is to see how to separate the layout of an application from the source code. In addition, it is important to see how to pass arrays from one screen to another. You will also see how transactions are used in everyday life.

21.2.1.1 Cookie-Driven Shopping Carts

The first thing you want to implement is a cookie-based prototype. Let's take a look at libdb.php. This file contains a library for interacting with the database.

 <?php class db {         var $conn = "host=localhost user=hs dbname=phpbook";         var $db;         var $res;         function connect()         {                 $this->db = pg_connect($this->conn);                 if      (!$this->db)                 {                         $this->ErrorMsg('Connection failed.');                 }         }         function sql($statement)         {                 if      (!$this->db)                 {                         $this->ErrorMsg('Connect First.');                 }                 $this->res = @pg_exec($this->db, $statement);                 if      (!$this->res)                 {                         return(0);                 }                 else                 {                         $num = @pg_numrows($this->res);                         return($num);                 }         }         function fetch($num, $type = 3, $param = 0, $mres = 0)         {                 ($param == 1 ? $fres = $mres : $fres = $this->res);                 switch($type)                 {                         CASE 1:                                 $row = pg_fetch_row($fres, $num);                                 break;                         CASE 2:                                 $row = pg_fetch_array($fres, $num);                                 break;                         CASE 3:                                 $row = pg_fetch_object($fres, $num);                                 break;                         default:                                 $this->ErrorMsg('Query Type does not exist');                                 break;                 }                 return ($row);         }         function disconnect()         {                 @pg_close($this->db);         }         function ErrorMsg($outstr)         {                 echo ("SEVERE ERROR<br>$outstr");                 $this->sql("ROLLBACK");                 $this->disconnect();                 die();         } } ?> 

A db object contains three variables. $conn contains the parameters defining the connection to the database. In this example these parameters have been hard-coded to reduce the amount of code and the number of files needed for this prototype. $db contains the database handle and $res the result of a SQL statement.

The connect function establishes a connection to the database and displays an error message if no connection can be established. The function called sql can be used to execute a SQL statement. In the case of an error, the error message is suppressed. The return value of the function contains the number of records returned by a SQL statement.

To retrieve values from the result of a SQL statement, the fetch function has been implemented. Depending on what kind of result you want to retrieve, you can choose. With the help of the third parameter passed to the function, you can decide whether you want to work with arrays, objects, or rows. This is a comfortable feature because it helps you to reduce the functions in your database library without reducing the flexibility of the programmer using the library.

The disconnect function is used to destroy a connection to the database. The ErrorMsg function displays a message on the screen and makes the application quit its work.

This library will be used by the entire shop package.

The next package you will need is called ss_libcart.php. It is used to work with the shopping cart.

 <?php require ("libdb.php"); class cart extends db {         function cartwork($id, $number, $ser_cart)         {                 $ar_cart = unserialize($ser_cart);                 if ($number < 0)                 {                         header("Location: shop.php?msg=2");                         exit;                 }                 $chk = $this->checkstock($id,$number);                 if (!$chk)                 {                         header("Location: shop.php?msg=1");                         exit;                 }                 if ( $number < 1)                 {                         unset ($ar_cart[$id]);                 }                 else                 {                         $ar_cart[$id] = $number;                 }                 $ser_cart = serialize($ar_cart);                 return($ser_cart);         }         function checkstock($id, $number)         {                 $chksel = "SELECT instock FROM product WHERE id=$id";                 $this->connect();                 $this->sql($chksel);                 $row = $this->fetch(0,3);                 if ($number > $row->instock)                 {                         return(0);                 }                 return(1);         } } ?> 

The first function defined in this part is called cartwork. It is needed for checking the data transmitted from one script to another. Let's have a few words on how scripts can interact with each other: To transmit data that cannot be stored in a string from one script to another, the data must be serialized. For things such as arrays or objects, this is necessary because an array or an object consists of more than just one component. Serialization makes sure that a string containing the same information as the original objects is built. This way the data can be stored in a cookie or in a session, or it can be used inside an URL.

The checkstock function is used to find out if the number of units of a certain product a customer wants to buy is available or not. If the number of products the customer wants to buy is higher than the products that are in the stores, 0 is returned. Otherwise the function will return 1. The only two parameters needed by this function are the object id and the number of products the user wants to buy. The number of units available is taken from the database.

The next file you will look at is cart.php. It is used to process the parameters passed to the payment script.

 <? include ("ss_libcart.php"); @session_start(); $sid = session_id(); $keys = array_keys($HTTP_POST_VARS); $anz = count($keys); for ($x = 0; $x < count($keys); $x++) {         if ($HTTP_POST_VARS[$keys[$x]])         {                 $id = $keys[$x];                 $number = $HTTP_POST_VARS[$keys[$x]];                 $sc = new cart();                 $ser_cart = $sc->cartwork($id, $number , $ser_cart);         } } $t = time() + 50000; setcookie("ser_cart",$ser_cart,$t,"/"); header("Location: shop.php"); ?> 

At the beginning of the script a session is started. In addition, a session id is created. After that the keys in $HTTP_POST_VARS are extracted. $HTTP_POST_VARS contains all parameters passed to the function with the help of a POST request. For every key in this array, the number of products is computed. A new cart object is created and cartwork is called. You have already seen cartwork earlier in this section.

At the end of a script a cookie is set. This cookie is needed to store the information about the shopping cart. The data is serialized, so you don't have to worry about the way the data is stored inside the cookie.

The next file in the list is called error.php. It contains a code fragment for displaying error information:

 <?php if      ($msg) {         switch  ($msg)         {                 CASE 1:                         $page->add_data("MSG", "<b>Not enough products                                          in stock!</b>");                         break;                 case 2:                         $page->add_data("MSG", "<b>You cannot order                                  negative numbers!</b>");                         break;         } } ?> 

As you can see, the script checks whether $msg is defined. If it is, one $page->add_data is called and <b>Not enough products in stock!</b> will be added to the object containing the HTML code of the page. The object containing the code is called $page, as you will see in the next file. Let's take a look at shop.php. This file is used to display the first screen containing a list of all products a user can buy. Here is the code of the file:

 <?php include("ss_libcart.php"); include("libhtml.php"); include("incshop.php"); $page = new libhtml('temp_list.html'); include("error.php"); $psel = "SELECT id,name,instock,price FROM product ORDER BY name"; $con = new db(); $con->connect(); $num = $con->sql($psel); $content = ""; for ($i = 0; $i<$num; $i++) {         $row = $con->fetch($i, 3);         $content .= $page->line($row->id,                         $row->name, $row->price, $ar_cart[$row->id]); } $page->add_data('CONTENT',$content); echo $page->output(); ?> 

First the libraries needed to display the pages are included. In the next step, a new object called $page is created. This object is based on a template called temp_list.html. The code of this template is shown in the next listing:

temp_list.html:

 <h1>Productlist</h1> {MSG} <form action="cart.php" method=post> <table>   <tr>     <td>ID</td>     <td>Productname  </td>     <td>Price</td>     <td>Quantity</td>    </tr> {CONTENT} </table> </form> <a href="cash.php">Proceed to Checkout</a> 

As you can see, the HTML template is fairly simple. It contains some HTML code and some keywords.

After including the libraries and creating the $page object, error.php is included. This library must be included here and not before generating the $page object because error.php relies on the existence of $page. The entire HTML code generated by this application is stored in $page before displaying it, so $page must already exist before adding code to it. Now a connection to the database is established by creating a db object. In addition, a query is executed. This query is necessary for retrieving the desired products from the database. The return value of the function called sql contains the number of rows in the result. This value is used by the loop processing every record returned by PostgreSQL. Inside the loop a function named line is called. Just like all other functions called in this block, the function has been implemented in libhtml.php:

 <?php class libhtml {         var $page;         var $msg;         function libhtml($file)         {                 $this->page = implode('', @file($file));         }         function add_data($field, $value)         {                 $this->page = str_replace('{'.$field.'}', $value,$this->page);         }         function line($id, $name, $price, $value)         {                 $tableline = "<tr><td>$id</td><td>$name</td><td>$price</td>";                 $tableline .= '<td>';                 $tableline .= '<input type="text" name="'.$id.'"';                 $tableline .= ' value="'.$value.'">';                 $tableline .= '</td><td>';                 $tableline .= '<input type=submit value="Buy"></td></tr>';                 return ($tableline);         }         function cashline($id = "", $name = "", $price = "", $value = "",                                  $sum = "")         {                 $tableline = "<tr><td>$id</td><td>$name</td><td>$price</td>";                 $tableline .= "<td>$value</td><td>$sum</td><tr>";                 return ($tableline);         }         function output()         {                 $this->page = str_replace("{MSG}", $msg, $this->page);                 return($this->page);         } } ?> 

The class implemented in libhtml.php contains two variables. $page contains the entire HTML code of the page being generated. $msg contains important messages.

Let's take a closer look at the constructor of the object. A filename is passed to the method. This file is read and assigned to $page. Now the data in the file can be modified easily. To replace the variables in the files for the data you want to see, you can use add_data. It parses the files and performs simple substitutions. add_data replaces entire strings for data. However, in the case of tables this is not what you want. Therefore you need a function called line. This function is needed to display one line of a table. No matter which data you need, line will build the table for you.

The next function in the listing is called cashline. It is used to display data in the final sheet, which contains a list of all products a user has bought. Finally, the output function has been implemented. It performs a substitution and returns the code of the page.

As you have seen in the HTML template used by shop.php, the link on the bottom of the screen leads to cash.php. Cash.php is the file responsible for checking out. After the user has selected all the products he wants, he can buy these products, and that's exactly what he can do with the help of cash.php. Just like the rest of the application, the HTML code is based on templates. This time the file is called temp_cash.html. Let's take a look at the content of the file:

 <h1>Payment</h1> {MSG} <table>   <tr>     <td>ID</td>     <td>Productname  </td>     <td>Price   </td>     <td>Quantity</td>     <td>Sum</td>    </tr> {CONTENT} </table> </form> 

Two parameters are in the file. The first one is {MSG} and the second one is {CONTENT}. These two strings will be substituted for the content. This is done by cash.php; let's take a look at this file:

 <? include ("libhtml.php"); include ("libdb.php"); include ("incshop.php"); $page = new libhtml('temp_cash.html'); $con = new db(); $con->connect(); $con->sql("BEGIN TRANSACTION"); $allsum = 0; $keys = array_keys($ar_cart); foreach ($keys as $element) {         $selcart = "SELECT id,price,name,instock                           FROM product WHERE id=$element";         $con->sql($selcart);         $row = $con->fetch(0);         if ($ar_cart[$row->id])         {                 $sum = round($ar_cart[$row->id] * $row->price, 2);                 $allsum = $allsum + $sum;                 $content .= $page->cashline($row->id, $row->name,                                 $row->price, $ar_cart[$row->id], $sum);                 $upd = "UPDATE product SET instock =                         instock-".$ar_cart[$row->id]." WHERE id=$row->id";                 $con->sql($upd);         } } $con->sql("COMMIT"); $content .= $page->cashline("", "", "", "", $allsum); $page->add_data('CONTENT',$content); $t = time() - 50000; setcookie("ser_cart", "", $t, "/"); echo $page->output(); ?> 

At the beginning of the file an object containing the HTML code is created. Just as in shop.php, the object is called $page. In the next step a connection to the database is established. In addition, a transaction is started. This is important because when removing the products from the stores, something bad must not happen in the middle of the process. If just one query fails, the number of products in the stores won't be correct any more and there is no way to solve problems like that.

In the next step the user's shopping cart is processed. For every product the user buys, a SELECT statement is performed. The data returned by the SELECT statement is used to build the final overview of the products. In addition, an UPDATE query is performed. This query reduces the products that are still in the stores.

After processing the data, the transaction is committed and additional HTML code is added to the $page object. Finally, the content of the object is displayed onscreen and the cookie is set to a negative timestamp. This means that the cookie is deleted and therefore the user's shopping cart is empty.

As you can see, it is an easy task to build a fragment of a shop. In this example the shop is based on cookies and parsing. Templates are read and strings inside these templates are substituted for the data retrieved from the database. This way it is easy to split layout and source code. It is an easy task to change the way the shop looks by changing the templates. In most cases it is not necessary to change the libraries for performing slight modifications. By splitting the code from the layout, you can save a lot of time and gain flexibility.

Now that you have seen how the application was implemented, you can take a look at the screen generated by shop.php, which is shown in Figure 21.6.

Figure 21.6. The main screen.

graphics/21fig06.jpg

Finally, let's take a look at incshop.php:

 <? @session_start(); $sid = session_id(); $sel = "SELECT value FROM cart WHERE sid='$sid'"; $condb = new db(); $condb->connect(); $num = $condb->sql($sel); if ($num) {         $erg = $condb->fetch(0);         $ar_cart = unserialize($erg->value); } $condb->disconnect(); ?> 
21.2.1.2 Session-Driven Shopping Carts

You have already learned that cookies can have several disadvantages. Especially when working with a mixture of secure and insecure areas, cookies can be fatal because a cookie that has been set in the secure area is not valid in the insecure area. This can cause trouble and lead to a lot of work and high costs. In this section you will see how the application you have seen before can be implemented with the help of sessions. Several files have to be changed:

  • cart.php Added functions for starting sessions

  • incshop.php Added functions for starting sessions

  • ss_libcart.php Insert and update session information

The purpose of the original files is the same, but modifications have been made in order to work with sessions.

Before going to the files briefly, you can create a table:

 CREATE TABLE "cart" (         "sid" text,         "value" text ); 

This table is used for storing the information collected by the session subsystem. The first column contains the session id. The second column is used to store the values of the session.

After creating the table, you can take a look at the file we have changed for working with session information. Let's start with cart.php:

 <?php include ("ss_libcart.php"); @session_start(); $sid = session_id(); $keys = array_keys($HTTP_POST_VARS); for ($x = 0; $x < count($keys); $x++) {         if      ($HTTP_POST_VARS[$keys[$x]])         {                 $id = $keys[$x];                 $number = $HTTP_POST_VARS[$keys[$x]];                 $sc = new cart();                 $sc->cartwork($id, $number);         } } header("Location: shop.php"); ?> 

As you can see at the beginning of the script, a session is started. You have already seen in Chapter 15, "Session Management," how sessions can be started and how sessions can be treated. In the next step a session id is created. This id is assigned to $sid. The rest of the script works just like the cookie version of the file. The only thing you have to remove is the setcookie function and the lines related to it.

Let's go on to incshop.php:

 <? @session_start(); $sid = session_id(); $sel = "SELECT value FROM cart WHERE sid='$sid'"; $condb = new db(); $condb->connect(); $num = $condb->sql($sel); if ($num) {         $erg = $condb->fetch(0);         $ar_cart = unserialize($erg->value); } $condb->disconnect(); ?> 

After starting a session and generating a session id, the current session id is retrieved from the database. If data is returned, the value in the second column is retrieved and unserialize is called. This way the session information is retrieved from the database.

Finally, take a look at the modified version of ss_libcart.php.

 <? require ("libdb.php"); class cart extends db {         function cartwork($id, $number)         {                 @session_start();                 $sid=session_id();                 if ($number < 0)                 {                         header("Location: shop.php?msg=2");                         exit;                 }                 $con = new db();                 $con->connect();                 $chk = $this->checkstock($id,$number);                 if (!$chk)                 {                         header("Location: shop.php?msg=1");                         exit;                 }                 $selc = "SELECT value FROM cart WHERE sid='$sid'";                 $num=$con->sql($selc);                 if (!$num)                 {                         $ar_cart[$id] = $number;                         $ser_cart = serialize($ar_cart);                         $ins = "INSERT INTO cart(sid,value)                                 VALUES('$sid','$ser_cart')";                         $con->sql($ins);                 }                 else                 {                         $erg = $con->fetch(0);                         $ar_cart = unserialize($erg->value);                         if ($number < 1)                         {                                 unset ($ar_cart[$id]);                         }                         else                         {                                 $ar_cart[$id] = $number;                         }                         $ser_cart = serialize($ar_cart);                         $upd = "UPDATE cart SET value='$ser_cart' WHERE                                sid='$sid'";                         $con->sql($upd);                 }         }         function checkstock($id,$number)         {                 $chksel = "SELECT instock FROM product WHERE id=$id";                 $this->connect();                 $this->sql($chksel);                 $row = $this->fetch(0,3);                 if ($number > $row->instock)                 {                         return(0);                 }                 return(1);         } } ?> 

Let's start with the function called cartwork. Just as you have seen in the cookie version, the function checks whether enough products are in the stores. This is done with the help of the checkstock function that can be found at the end of this file. This function works just like the one you have already seen in the cookie version of this script. In order to work with the session database, a connection to the database must be established, which is done by creating a db object.

In the next step the records containing the session id are retrieved from the database. The content of the second field in the column is unserialized and modified before it is serialized again. Finally, the content of the database is modified.

After the application has run, some records can be found in the table called cart:

 phpbook=# SELECT * FROM cart;                sid                |                   value ----------------------------------+--------------------------------------------  1d94d8e82a893618bcfddde8b06fcf17 | a:2:{i:2;s:2:"24";i:1;s:1:"3";}  ef495e885964545b61c10bfc6f1853fd | a:3:{i:1;s:1:"2";i:5;s:1:"1";i:2;s:1:"5";}  9646a5abc72d26ce1975f8c389990358 | a:3:{i:1;s:1:"3";i:2;s:1:"1";i:3;s:1:"2";} (3 rows) 

In the first column you can see what a session id looks like; it is a 32-character long, alphanumeric string. The second column contains the serialized version of the data passed to the script called cash.php.

As you have seen in this section, working with sessions is an easy task and if an application has been implemented properly, it is an easy task to change the way sessions are managed. If all components used for working with sessions are managed by modules, you just have to change the modules you are using. In most cases this will not affect your entire application.

Finally it is time to see what the screen for the checkout looks like. Let's take a look at Figure 21.7.

Figure 21.7. The checkout.

graphics/21fig07.jpg

The layout of the screen has been generated according to the HTML template accessed by cash.php. To change the layout, you just have to edit this template. This can be done by a designer who does not need to be able to write PHP programs. This is important because it will save costs and help you to make programmers and designers work more independently.

21.2.2 Collecting User Data

Collecting user data is one of the most important things when implementing business applications. The behavior of a user can be analyzed, and with the help of this data it is possible to optimize your Web site. You can find out which components are not interesting for a user and which links are used often. For marketing purposes, this is essential and it can help you to improve your business. Nearly all big players in modern e-commerce business use user tracking systems to optimize their sites. In this section we will try to implement a simple system you can use to find out what a user does inside your application. Modules like the one you will see in this section are optimized for shopping applications, but you can also use a module like this for analyzing any kind of Web site.

The key to user tracking is logging. The best thing to do is to write an object that is solely used for logging. All data collected by this object can be analyzed easily. In this section you will take a look at an object and you will see how data generated by this object can be analyzed.

Before implementing the object, you can create a table that will contain the logging information. In this example the table is called logging:

 CREATE TABLE logging (         id serial8,                     -- unique id of an entry         tstamp timestamp with time zone                 DEFAULT now(),          -- timestamp         sid varchar(32),                -- session id         http_referer text,              -- where does the user come from         script_filename text,           -- the name of the current script         remote_addr inet,               -- ip address of viewer         http_host text,                 -- name of the current (virtual) host         http_user_agent text,           -- the browser the user is using         message text                    -- logging message ); 

As you can see, the table contains many columns. The first one contains a unique id that will be assigned to every piece of logging information automatically. In the second column you will see when the logging information was added to the table. In addition, the table will contain the session id, the site the user comes from, the name of the script generating the logging information, the IP address of the person visiting the Web site, the name of the domain running on the machine the user is accessing, the version of the browser the user is utilizing, and a logging message. With the help of this information it is possible to track the user and to gain important information about the behavior of a user. After the table is created, the objects used for logging are implemented. In this example three objects will be shown. The object called filelog can be used to send logging information to a file. The dblog object is a database-driven logging utility. It is based on the table you have just seen. If you want to use files and a PostgreSQL database, the log object will be the right thing for you. It is a combination of both the filelog and the dblog object. It sends logging information to a file as well as to the database.

Let's take a look at the implementation of these three objects:

 <?php # logging into a file class filelog {         var $filename;         var $fp;         function filelog($file)         {                 $this->filename = $file;                 $this->fp = fopen($this->filename, "a+");         }         function add_log($message)         {                 setlocale("LC_TIME","en_US");                 $data = strftime("[%d/%b/%Y:%T %Z]");                 fwrite($this->fp, "$data -- $message\n");         }         function logclose()         {                 fclose($this->fp);         } }; # using a logging database class dblog {         var $dbhost = 'localhost';         var $dbname = 'phpbook';         var $dbuser = 'hs';         var $conn;         # creating a logging object         function dblog()         {                 $this->conn = pg_connect("dbname=".$this->dbname.                         " host=".$this->dbhost." user=".$this->dbuser);                 if      (!$this->conn)                 {                         echo 'Connection failed.';                         die;                 }         }         # add an entry to the logging database         function add_log($sid, $message)         {                 $message = str_replace("'", "''", $message);                 $message = str_replace("\\", "\\\\", $message);                 $sql = "INSERT INTO logging (sid, http_referer,                         script_filename, remote_addr, http_host,                         http_user_agent, message) VALUES ('$sid', '".                         getenv('HTTP_REFERER')."', '".                         getenv('SCRIPT_FILENAME')."', '".                         getenv('REMOTE_ADDR')."', '".                         getenv('HTTP_HOST')."', '".                         getenv('HTTP_USER_AGENT')."', ".                         "'$message')";                 if      (pg_exec($this->conn, $sql))                 {                         # everything seems to work well ...                 }                 else                 {                         echo "an error in the logging library has occurred.";                         die;                 }         }         function logclose()         {                 pg_close($this->conn);         } }; class log {         var $filelog;         var $dblog;         function log($file)         {                 $this->filelog = new filelog($file) or                         die ("cannot create logging object (filelog,                              $file)\n");                 $this->dblog = new dblog() or                         die ("cannot create logging object (dblog)\n");         }         function add_log($sid, $message)         {                 $this->filelog->add_log($message);                 $this->dblog->add_log($sid, $message);         }         function logclose()         {                 $this->filelog->logclose();                 $this->dblog->logclose();         } }; ?> 

The firstobject that has been implemented in logging.php is called filelog. It contains two variables. $filename contains the name of the file the logging information is sent to. $fp contains the file handle. The constructor of the objects opens a file having the name passed to the function. The next function in the list is the add_log function. One parameter containing the message must be passed to the function. A timestamp is compiled and the string is sent to the logfile. The last function in the code of the object is logclose. It does nothing but close the file containing the logging information.

Let's take a look at the dblog object. At the beginning of the object, three variables are initialized. The fourth variable called $conn will contain the database handle. As you can see, the constructor of the function opens a connection to the database. In this scenario the parameters taken from the header of the object are used. The add_log function is slightly more complex than the add_log function of the object you have seen before. The first thing is that special characters are escaped. This is done with the help of two regular expressions. In the next step a SQL command is built. The data is taken from the input parameters of the function as well as from predefined environment variables. These variables have been set by Apache and can be accessed using the getenv function. After the SQL code has been compiled, it is sent to the server.

In the case of the dblog function, logclose does nothing but close the connection to the database.

After discussing the first two objects, you can take a look at the log object, which combines the features of the first two objects. The constructor of the object generates two objects. These objects are assigned to the internal variables. Let's take a look at the add_log function. In this example it calls the add_log function of the two objects we have just discussed.

Now that you have seen how the objects have been implemented, it is time to take a look at an example that shows how the functions can be used:

 <?php         include("logging.php");         # starting sessions         @session_start();         $sid=session_id();         echo "starting sessions ...<br>\n";         # creating new objects (filelog and dblog)         $filelog = new filelog ("/tmp/logfile.txt") or                 die ("cannot create logging object (1)");         $dblog = new dblog ();         echo "creating objects ...<br>\n";         # sending logging information to objects         $filelog->add_log("welcome from filelog");         $dblog->add_log($sid, "welcome from dblog");         echo "sending logging information to objects ...<br>\n";         # closing objects         $filelog->logclose();         $dblog->logclose();         echo "closing objects ...\n"; ?> 

After including the library, session information is computed. In the next step a filelog and a dblog object are created. To see if the objects work correctly, add_log is called.

Let's run the script and see what comes out:

 starting sessions ... creating objects ... sending logging information to objects ... closing objects ... 

If the script has been executed successfully, you can take a look at the content of the logfile:

 [hs@duron shop]$ tail -n1 /tmp/logfile.txt [11/Feb/2002:22:05:37 CET] -- welcome from filelog 

In addition to the logfile, data has been added to the database. In this example, more than one query is performed to display the result because otherwise the result would not fit on one page. Let's take a look:

 phpbook=# SELECT id, tstamp, sid FROM logging;  id |            tstamp             |               sid ----+-------------------------------+----------------------------------   1 | 2002-02-11 22:05:37.373493+01 | 9646a5abc72d26ce1975f8c389990358 (1 row) phpbook=# SELECT http_referer, script_filename, remote_addr, http_host FROM logging;  http_referer |        script_filename         | remote_addr | http_host --------------+--------------------------------+-------------+-----------               | /var/www/html/shop/makelog.php | 127.0.0.1   | localhost (1 row) phpbook=# SELECT http_user_agent FROM logging;                          http_user_agent ------------------------------------------------------------------  Mozilla/5.0 (X11; U; Linux i686; en-US; rv:0.9.7) Gecko/20011226 (1 row) phpbook=# SELECT id, message FROM logging;  id |      message ----+--------------------   1 | welcome from dblog (1 row) 

As you can see, all information has been added to the table.

In the previous example you have seen two objects being used. In the next example you can see how almost the same goal can be reached using the log object instead of the two objects log is based on:

 <?php         include("logging.php");         # starting sessions         @session_start();         $sid=session_id();         echo "starting sessions ...<br>\n";         # creating new object         $log = new log ("/tmp/logfile.txt") or                 die ("cannot create logging object (1)");         $log->add_log($sid, "welcome from filelog");         $log->logclose(); ?> 

When using this module extensively, tracking users is an easy task. Just query the table containing the logging information and with the help of the object id, you will find out who has done what inside your applications.

When implementing online shops, you can find out which products are viewed more often than others. You can try to figure out how price reductions of certain products affect the behavior of your customers and approximately how long a customer stays on one site. As an exercise, just try to add some logging information to the shop fragment you have seen in the previous section. You will see that it is easily possible to find out whether a user has removed products from the shopping cart again. You will also find out how long it takes to finish shopping.



PHP and PostgreSQL. Advanced Web Programming2002
PHP and PostgreSQL. Advanced Web Programming2002
ISBN: N/A
EAN: N/A
Year: 2004
Pages: 201

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net