Article

The PHP Anthology Volume 2, Chapter 1 - Access Control

Page: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Next

Next, we have some accessor methods that are used simply to fetch the values from the object's variables:

Example 1.50. AccessControl/User.php (in SPLIB) (excerpt)              
             
 /**              
  * Returns the user's id              
  * @return int              
  * @access public              
  */              
 function id()              
 {              
   return $this->userId;              
 }              
 /**              
  * Returns the users email              
  * @return int              
  * @access public              
  */              
 function email()              
 {              
   return $this->email;              
 }              
 /**              
  * Returns the users first name              
  * @return string              
  * @access public              
  */              
 function firstName()              
 {              
   return $this->firstName;              
 }              
 /**              
  * Returns the users last name              
  * @return string              
  * @access public              
  */              
 function lastName()              
 {              
   return $this->lastName;              
 }              
 /**              
  * Returns the users signature              
  * @return string              
  * @access public              
  */              
 function signature()              
 {              
   return $this->signature;              
 }

The checkPermission method determines whether a user has a named permission. It returns TRUE if it finds the permission named in the local permissions array:

Example 1.51. AccessControl/User.php (in SPLIB) (excerpt)              
             
 /**              
  * Checks to see if the user has the named permission              
  * @param string name of a permission              
  * @return boolean TRUE is user has permission              
  * @access public              
  */              
 function checkPermission($permission)              
 {              
   // If I don't have any permissions, fetch them              
   if (!isset($this->permissions)) {              
     $this->permissions = array();              
     $sql = "SELECT              
               p." . PERM_TABLE_NAME . " as permission              
             FROM              
               " . USER2COLL_TABLE . " uc,              
               " . COLL2PERM_TABLE . " cp,              
               " . PERM_TABLE . " p              
             WHERE              
               uc." . USER2COLL_TABLE_USER_ID . "='" .              
                 $this->userId . "' AND              
               uc." . USER2COLL_TABLE_COLL_ID . "=              
                 cp." . COLL2PERM_TABLE_COLL_ID . " AND              
               cp." . COLL2PERM_TABLE_PERM_ID . "=              
                 p." . PERM_TABLE_ID;              
     $result = $this->db->query($sql);              
     while ($row = $result->fetch()) {              
       $this->permissions[] = $row['permission'];              
     }              
   }              
   if (in_array($permission, $this->permissions)) {              
     return TRUE;              
   } else {              
     return FALSE;              
   }              
 }              
}

We've set it up so that if there are no permissions currently stored in the class's $this->permissions array, checkPermissions fetches all of them. This means that if we need to check permissions more than once on a page, it will only be at the cost of a single query. You may take the alternative view that it's better to use the name of the permission in the query as well, and then count the number of rows returned. This reduces the amount of memory required by PHP, but will generate one query for each permission you check. The SQL statement for this alternative approach (showing the real table and column names, rather than the constants) could be:

$sql = 'SELECT              
         COUNT(*) AS num_rows              
       FROM              
         user2collect uc, collection2permission cp, permission p              
       WHERE              
         uc.user_id = "' . $this->userId . '" AND              
         uc.collection_id = cp.collection_id AND              
         cp.permission_id = p.permission_id AND              
         p.name = "' . $permission . '"';

The User class fetches data on a "need to know" basis. That is, it's fairly safe to assume that the basic, available user information will be required shortly after instantiation; hence, the use of the populate method—otherwise, we wouldn't have created the object in the first place. The data pertaining to permissions, however, may not be needed every time the User class is instantiated. It's likely that we'll only check permissions on a restricted number of pages, so we can save ourselves a query when the user views public pages, leaving the checkPermission method to be called explicitly as needed. This approach is known as lazy fetching, and can be a useful approach to reducing unnecessary queries and performance overhead.

Having seen the class, let's consider a demonstration. This login form script (13.php) is the same as 11.php, but it sends the post data to a different URL. Let's look at a simple example of the permissions in action: first, we'll include and set up the classes as usual, and put the new User class into action:

Example 1.52. 14.php (excerpt)              
             
<?php              
// Include MySQL class              
require_once 'Database/MySQL.php';              
             
// Include Session class              
require_once 'Session/Session.php';              
             
// Include Auth class              
require_once 'AccessControl/Auth.php';              
             
// Include User class              
require_once 'AccessControl/User.php';              
             
$host   = 'localhost'; // Hostname of MySQL server              
$dbUser = 'harryf';    // Username for MySQL              
$dbPass = 'secret';    // Password for user              
$dbName = 'sitepoint'; // Database name              
             
// Instantiate MySQL connection              
$db = &new MySQL($host, $dbUser, $dbPass, $dbName);              
             
// Instantiate the Authentication class              
$auth = &new Auth($db, '13.php', 'secret');              
             
// Instantiate the User class              
$user = &new User($db);

Now, we have code that will change the page based on the value of $_GET['view']. Each view has a different permission, which we can then look up with the User object:

Example 1.53. 14.php (excerpt)              
             
// Switch on the view GET variable              
switch (@$_GET['view']) {              
 case 'create':              
   // Define permission (a name in permissions table)              
   $permission = 'create';              
   // Create a message for users with access to this area              
   $msg = 'From here you can create new content';              
   break;              
 case 'edit':              
   $permission = 'edit';              
   $msg = 'From here you can edit existing content';              
   break;              
 case 'delete':              
   $permission = 'delete';              
   $msg = 'From here you can delete existing content';              
   break;              
 default:              
   $permission = 'view';              
   $msg = 'From here you can read existing content';              
}              
             
// Check the user's permission. If inadequate, change the msg              
if (!$user->checkPermission($permission)) {              
 $msg = 'You do not have permission to do this';              
}
             
?>              
<p><?php echo $msg; ?></p>              
<p>              
 <a href="<?php echo $_SERVER['PHP_SELF']; ?>">Main</a> |              
 <a href="<?php echo $_SERVER['PHP_SELF'];              
   ?>?view=create">Create</a> |              
 <a href="<?php echo $_SERVER['PHP_SELF'];              
   ?>?view=edit">Edit</a> |              
 <a href="<?php echo $_SERVER['PHP_SELF'];              
   ?>?view=delete">Delete</a>              
</p>

This is a simple example, of course, but you could use the checkPermission method any way you like—perhaps simply to use if/else statements to decide what a user is allowed to do and see. Another approach would be to use a variable, such as the $msg variable we've used here, to store the name of a PHP script for use with an include statement.

Otherwise, that's all there is to it. Now, all you need to do is build an administration interface to control Users, Groups and Permissions!

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links