Search This Blog

Monday, June 20, 2011

Creating a Access Logger Script

To track users' activities, you need to know who has made a request for what, which is why users are required to log in to the site. Without a login process, there's no way for you to identify anyone requesting a Web page.

The most convenient way of authenticating users is to specify a unique ID and associated password for each one. When a user logs in, all you need to do is to check the values (username and password) he submits against the ones you have stored.

The following script makes a query to the table user for user authentication. You start by including common_db.inc and specifying a link to the registration page:

<?php
include_once "./common_db.inc";
$register_script = "./register.php";

auth_user.php

Next, define the functions auth_user() and login_form()—more on these in a moment—but the main story begins with a session_start() call. You're going to store the user-entered values for ID and password as session variables, thereby saving the user from having to re-enter the values every time he accesses a new page.

If $userid has not been defined, call the login_form() function, which displays (surprise, surprise!) a login form, into which the user can enter ID and password:

if{!isset($userid)) {
   login_form();
   exit;

If $userid is defined (as will be the case if the script has been called from the login form), register the user-provided values userid and userpassword as session variables for later use, and use them as arguments to call the auth_user() function:

}else{
   session_start();
   session.register(''userid" , "userpassword'');
   $username = auth_user($_POST['userid'], $_POST [' userpassword']);

The value returned by auth_user() is either:
  • The user's name as stored in the user table. This is returned only if the submitted ID/password values correspond to those stored in a specific record in the table.
  • 0. This is returned when no match is found.
Store this value in $username, and use it to determine a response:

  if(!$username) {
     $PHP_SELF = $_SERVER['PHP_SELF'];
     session_unregister("userid");
     session_unregister("userpassword");
     echo "Authorization failed.".
          "You must enter a valid userid and password combo. " .
          "Click on the following link to try again.<BR>\n";
     echo "<A HREF=\"$PHP_SELF\">Login</A><BR>";
     echo "If you're not a member yet, click " .
          "on the following link to register.<BR>\n";
     echo "<A HREF=\"$register_script\">Membership</A>";
     exit;
  }else{
     echo "Welcome, $username!";
  }
}

If authentication fails, unregister the session variables to ensure that login_form() is called whenever an unauthenticated user tries to access a password-protected area. login_form() is just a table that enables the user to enter his userid and password so that you can use the values in the auth_user() function:

function login_form()
{
   global $PHP_SELF:
?>
<html>
<head>
<title>login</title>
</head>
<body>
<form method="post" action="<?php echo "$PHP_SELF"; ?>">
   <div align="center"><center>
      <h3>Please log in to access the page you requested.</h3>
   <table border="1" width="200" cellpadding="2">
      <tr>
         <th width="18%" align="right" nowrap>id</th>
         <td width="82%" nowrap>
            <input type="text" name="userid" size="8">
         </td>
      </tr>
      <tr>
         <th width="18%" align="right" nowrap>Password</th>
         <td width="82%" nowrap>
            <input type="password" name="userpassword" size="8">
         </td>
      </tr>
      <tr>
         <td width="100%" colspan="2" align="center" nowrap>
           <input type="submit" value="login" name="Submit">
         </td>
      </tr>
   </table>
   </center></div>
</form>
</body>
</html>
<?
}

The real meat of the script lies in the auth_user() function, which takes $userid and $userpassword as arguments, and validates them against the values stored in the user table:

function auth_user($userid, $userpassword)
{
   global $default_dbname, $user_tablename)

   $link_id = db_connect($default_dbname);

After you're connected to the database, query for a record whose userid and password entries correspond to the user-provided arguments, and SELECT the username value for that record:

$query = "SELECT username FROM $user_tablename WHERE userid = '$userid'
                          AND userpassword = password('$userpassword')";
$result =mysql_query($query);

If no records match both criteria, return 0; otherwise fetch and return the username value:

  if(!mysql_num_rows($result)){
     return 0;
  }else{
     $query_data =mysql_fetch_row($result);
     return $query_data[0];
  }
}

Make certain that you encrypt $userpassword before comparing it with the value in the user table so that you're comparing two encrypted values that have been derived by exactly the same process, and are there-fore identical. Not all types of encryption would enable you to do this, but MySQL's encryption algorithm.

When a user successfully logs in, he's greeted by name.

access_logger.php

You can develop the last script so that it authenticates users and logs their visits to Web pages. Call this modified version access_logger.php. You'll log user accesses by automatically attaching access_logger.php to the beginning of all your Web pages. You can do this very simply, by setting auto_prepend_file in the php.ini configuration file so that it specifies the absolute location of the script. For example:

auto_prepend_file = /home/james/access_logger.php

Another option is to include the logging script at the top of each of the Web pages that you want to password-protect. You'd need to be sure to include it at the top of the page, before sending out any HTML tags or text, otherwise the header() function won't work.

Assuming you use the blanket approach and set auto_prepend_file, you're going to attach the access logging script to every .php page on the server. If you want to exclude certain files and directories from the authentication process, you can list them respectively in a pair of arrays. When a user tries to access a Web page, the access logging script can check the page's name and path against the arrays' contents, and demand authentication only if there's no match.
Start off by including the common_db.inc file, and defining the exclusion arrays and table names:

<?pbp
require_once('common_db.inc');
$exclude_dirs = array('/info', '/contact');
$exclude_files = array('index.html', 'info.html', 'register.php');
$user_tablename = 'user';
$access_log_tablename = 'access_log';
$PHP_SELF = $_SERVER['PHP_SELF'];

Because someone is logging on to your site, you can start the session and register his userid as a session variable. You'll use the userid and password to authenticate the user in your do_authenticate() function in a moment. When you first start the session and register the userid and password, they have no values, so you check to see if the page is on your exclude list. If it isn't, you call the do_authenticate() function:

session_start();
session_register('userid', 'userpassword');
if(!$_SESSION['userid']){
   $filepath = dirname($_SERVER['SCRIPT_FILENAME']);
   $filename = basename($_SERVER['SCRIPT_FILENAME']);
   if($filepath ==''){
      $filepath ='/';
   }

   $auth_done = 0;

   for($j=0; $j < count($exclude_dirs); $j++) {
      if($exclude_dirs[$j] == $filepath){
         break;
      }else{
         for($i=0; $i< count($exclude_files); $i++) {
            if{$exclude_files[$i] == $filename){
               break;
            }
            if($i == (count($exclude_files) - 1)){
               do_authentication();
               $auth_done = 1;
               break;
            }
         }
      }
      if($auth_done) {
         break;
      }
    }
}
?>

How do you track the page accesses of a user who's already logged onto the site and submitted his userid and password information? You don't want to recall do_authenticate(), of course, but you do know that if the user is successfully logged on, then both the userid and userpassword session variables are defined, so you can say the following:

if ($_SESSION['userid'] && $_SESSION['userpassword']){
   $userid = $_SESSION['userid'];
   $filename = basename($_SERVER['SCRIPT_FILENAME]);
   $link_id = db_connect($default_dbname);
   $query = "SELECT userid FROM $access_log_tablename
   WHERE page = '$filename' AND userid = '$userid'";
   $result = mysql_query($query);

   if(!mysql_num_rows($result)){
      $query = "INSERT INTO $access_log_tablename
      VALUES('$filename', '$userid', 1, NULL)";
   }else{
      $query = "UPDATE $access_log_tablename
      SET visitcount = visitcount + 1, accessdate = NULL
      WHERE page = '$filename' AND userid = '$userid'";
   }

   mysql_query($query);

   $num_rows = mysql_affected_rows($link_id);
   if($num_rows != 1){
      die(sql_error());
   }
}

Now all of your page visits will faithfully be logged as users navigate around the site.
Declare the authentication function, checking to see if the user has sent her userid. If not, send her to the login_form() function, the same one you saw in auth_user.php (you just need to cut and paste it into this file in order for the call to workit isn't shown here again):

function do_autheritication()
{
   global $default_dbname, $user_tablename, $access_log_tablename;
   global $MYSQL_ERROR, $MYSQL_ERRNO;
   global $filename;
   global $PHP_SELF;

   if(!isset($_POST['userid'])) {
      login_form();
      exit;

If you've obtained a userid and password from the user, use the submitted values to query the database. You're also defining the session variables hereremember that these session variables persist between pages:

}else {
   $_SESSION['userpassword'] = $_POST['userpassword'];
   $_SESSION['userid'] = $_POST ['userid']; }
   $userid = $_POST['userid'];
   $userpassword = $_POST['userpassword'];
   $link_id = db_connect($default_dbname);
   $query = "SELECT username FROM $user_tablename
   WHERE userid = '$userid' AND userpassword = password('$userpassword')";
   $result = mysql_query($query);
}

If your query fails (perhaps the user tried to be sneaky and entered only his username), unregister the session and tell the user that he's failed authorization:

if(!mysql_num_rows ($result)) {
   sesssion_unregister ("userid");
   echo "Authorization failed. " .
   "You must enter a valid userid and password combo, " .
   "Click on the following link to try again.<BR>\n";
   echo "<A HREF=\"$PHP_SELF\">Login</A><BR>";
   echo "If you're not a member yet, click on the " .
   "following link to register.<BR>\n";
   echo "<A HREF= \"register.php\">Membership</A>";
   exit;

If our query is successful then check whether the user has accessed the page before, and either insert values or update the table appropriately:

   }else{
      $query = "SELECT userid FROM $access_log_tablename
      WHERE page - '$filename' AND userid = '$userid'";
      $result = mysql_query($query);
      if(!mysql_num_rows($result)) {
         $query = "INSERT INTO $access_log_tablename
         VALUES('$filename' , '$userid, 1, NULL)";
      }else{
           $query = "UPDATE $access_log_tablename
           SET visitcount = visitcount + 1, accessdate = NULL
           WHERE page = '$filename' AND userid = 'Suserid' ";
      }
      mysql_query($query);

     $num_rows = mysql_affected_rows($link_id);
     if($num_ rows != 1) die(sql_error());
   }
}

If you try running just this script, you'll see just a blank page in your browser (assuming you used a correct userid and password). However, if you take a look at the contents of the access_log table, you'll see that your activity has been logged. In the example, the site administrator browsed to access_logger.php to ensure it works:

mysql> select * from access_log;
+-------------------+--------+------------+----------------+
| page              | userid | visitcount | accessdate     |
+-------------------+--------+------------+----------------+
| stats.html        | Brian  |          1 | 20040304143102 |
| score.html        | Pads   |          2 | 20040312160114 |
| refs.html         | Nicrot |          5 | 20040124122744 |
| log.html          | Nicrot |          3 | 20040124122642 |
| log.html          | Greeny |          4 | 20040124112654 |
| access_logger.php | Dodge  |          1 | 20040314192430 |
+-------------------+--------+------------+----------------+
6 rows in set (0.00 sec)