session.php

Go to the documentation of this file.
00001 <?php
00002 /* SVN FILE: $Id: session_8php-source.html 580 2008-07-01 14:45:49Z gwoo $ */
00003 /**
00004  * Session class for Cake.
00005  *
00006  * Cake abstracts the handling of sessions.
00007  * There are several convenient methods to access session information.
00008  * This class is the implementation of those methods.
00009  * They are mostly used by the Session Component.
00010  *
00011  * PHP versions 4 and 5
00012  *
00013  * CakePHP(tm) :  Rapid Development Framework <http://www.cakephp.org/>
00014  * Copyright 2005-2008, Cake Software Foundation, Inc.
00015  *                              1785 E. Sahara Avenue, Suite 490-204
00016  *                              Las Vegas, Nevada 89104
00017  *
00018  * Licensed under The MIT License
00019  * Redistributions of files must retain the above copyright notice.
00020  *
00021  * @filesource
00022  * @copyright       Copyright 2005-2008, Cake Software Foundation, Inc.
00023  * @link                http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
00024  * @package         cake
00025  * @subpackage      cake.cake.libs
00026  * @since           CakePHP(tm) v .0.10.0.1222
00027  * @version         $Revision: 580 $
00028  * @modifiedby      $LastChangedBy: gwoo $
00029  * @lastmodified    $Date: 2008-07-01 09:45:49 -0500 (Tue, 01 Jul 2008) $
00030  * @license         http://www.opensource.org/licenses/mit-license.php The MIT License
00031  */
00032 /**
00033  * Database name for cake sessions.
00034  *
00035  */
00036 if (!class_exists('Set')) {
00037     uses('set');
00038 }
00039 /**
00040  * Session class for Cake.
00041  *
00042  * Cake abstracts the handling of sessions. There are several convenient methods to access session information.
00043  * This class is the implementation of those methods. They are mostly used by the Session Component.
00044  *
00045  * @package     cake
00046  * @subpackage  cake.cake.libs
00047  */
00048 class CakeSession extends Object {
00049 /**
00050  * True if the Session is still valid
00051  *
00052  * @var boolean
00053  * @access public
00054  */
00055     var $valid = false;
00056 /**
00057  * Error messages for this session
00058  *
00059  * @var array
00060  * @access public
00061  */
00062     var $error = false;
00063 /**
00064  * User agent string
00065  *
00066  * @var string
00067  * @access protected
00068  */
00069     var $_userAgent = '';
00070 /**
00071  * Path to where the session is active.
00072  *
00073  * @var string
00074  * @access public
00075  */
00076     var $path = '/';
00077 /**
00078  * Error number of last occurred error
00079  *
00080  * @var integer
00081  * @access public
00082  */
00083     var $lastError = null;
00084 /**
00085  * 'Security.level' setting, "high", "medium", or "low".
00086  *
00087  * @var string
00088  * @access public
00089  */
00090     var $security = null;
00091 /**
00092  * Start time for this session.
00093  *
00094  * @var integer
00095  * @access public
00096  */
00097     var $time = false;
00098 /**
00099  * Time when this session becomes invalid.
00100  *
00101  * @var integer
00102  * @access public
00103  */
00104     var $sessionTime = false;
00105 /**
00106  * Keeps track of keys to watch for writes on
00107  *
00108  * @var array
00109  * @access public
00110  */
00111     var $watchKeys = array();
00112 /**
00113  * Current Session id
00114  *
00115  * @var string
00116  * @access public
00117  */
00118     var $id = null;
00119 /**
00120  * Constructor.
00121  *
00122  * @param string $base The base path for the Session
00123  * @param boolean $start Should session be started right now
00124  * @access public
00125  */
00126     function __construct($base = null, $start = true) {
00127         if (Configure::read('Session.save') === 'database' && !class_exists('ConnectionManager')) {
00128             App::import('Core', 'ConnectionManager');
00129         }
00130 
00131         if (Configure::read('Session.checkAgent') === true || Configure::read('Session.checkAgent') === null) {
00132             if (env('HTTP_USER_AGENT') != null) {
00133                 $this->_userAgent = md5(env('HTTP_USER_AGENT') . Configure::read('Security.salt'));
00134             }
00135         }
00136         $this->time = time();
00137 
00138         if ($start === true) {
00139             $this->host = env('HTTP_HOST');
00140 
00141             if (empty($base) || strpos($base, '?') === 0 || strpos($base, 'index.php') === 0) {
00142                 $this->path = '/';
00143             } else {
00144                 $this->path = $base;
00145             }
00146 
00147             if (strpos($this->host, ':') !== false) {
00148                 $this->host = substr($this->host, 0, strpos($this->host, ':'));
00149             }
00150 
00151             if (!class_exists('Security')) {
00152                 App::import('Core', 'Security');
00153             }
00154 
00155             $this->sessionTime = $this->time + (Security::inactiveMins() * Configure::read('Session.timeout'));
00156             $this->security = Configure::read('Security.level');
00157         }
00158         parent::__construct();
00159     }
00160 /**
00161  * Starts the Session.
00162  *
00163  * @param string $name Variable name to check for
00164  * @return boolean True if variable is there
00165  * @access public
00166  */
00167     function start() {
00168         if (function_exists('session_write_close')) {
00169             session_write_close();
00170         }
00171         $this->__initSession();
00172         return $this->__startSession();
00173     }
00174 /**
00175  * Determine if Session has been started.
00176  *
00177  * @access public
00178  */
00179     function started() {
00180         if (isset($_SESSION)) {
00181             return true;
00182         }
00183         return false;
00184     }
00185 /**
00186  * Returns true if given variable is set in session.
00187  *
00188  * @param string $name Variable name to check for
00189  * @return boolean True if variable is there
00190  * @access public
00191  */
00192     function check($name) {
00193         $var = $this->__validateKeys($name);
00194         if (empty($var)) {
00195             return false;
00196         }
00197         $result = Set::extract($_SESSION, $var);
00198         return isset($result);
00199     }
00200 /**
00201  *
00202  * @param id $name string
00203  * @return string Session id
00204  * @access public
00205  */
00206     function id($id = null) {
00207         if ($id) {
00208             $this->id = $id;
00209             session_id($this->id);
00210         }
00211         if (isset($_SESSION)) {
00212             return session_id();
00213         } else {
00214             return $this->id;
00215         }
00216     }
00217 /**
00218  * Removes a variable from session.
00219  *
00220  * @param string $name Session variable to remove
00221  * @return boolean Success
00222  * @access public
00223  */
00224     function del($name) {
00225         if ($this->check($name)) {
00226             if ($var = $this->__validateKeys($name)) {
00227                 if (in_array($var, $this->watchKeys)) {
00228                     trigger_error('Deleting session key {' . $var . '}', E_USER_NOTICE);
00229                 }
00230                 $this->__overwrite($_SESSION, Set::remove($_SESSION, $var));
00231                 return ($this->check($var) == false);
00232             }
00233         }
00234         $this->__setError(2, "$name doesn't exist");
00235         return false;
00236     }
00237 /**
00238  * Used to write new data to _SESSION, since PHP doesn't like us setting the _SESSION var itself
00239  *
00240  * @param array $old Set of old variables => values
00241  * @param array $new New set of variable => value
00242  * @access private
00243  */
00244     function __overwrite(&$old, $new) {
00245         if(!empty($old)) {
00246             foreach ($old as $key => $var) {
00247                 if (!isset($new[$key])) {
00248                     unset($old[$key]);
00249                 }
00250             }
00251         }
00252         foreach ($new as $key => $var) {
00253             $old[$key] = $var;
00254         }
00255     }
00256 /**
00257  * Return error description for given error number.
00258  *
00259  * @param integer $errorNumber Error to set
00260  * @return string Error as string
00261  * @access private
00262  */
00263     function __error($errorNumber) {
00264         if (!is_array($this->error) || !array_key_exists($errorNumber, $this->error)) {
00265             return false;
00266         } else {
00267             return $this->error[$errorNumber];
00268         }
00269     }
00270 /**
00271  * Returns last occurred error as a string, if any.
00272  *
00273  * @return mixed Error description as a string, or false.
00274  * @access public
00275  */
00276     function error() {
00277         if ($this->lastError) {
00278             return $this->__error($this->lastError);
00279         } else {
00280             return false;
00281         }
00282     }
00283 /**
00284  * Returns true if session is valid.
00285  *
00286  * @return boolean Success
00287  * @access public
00288  */
00289     function valid() {
00290         if ($this->read('Config')) {
00291             if (Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read("Config.userAgent") && $this->time <= $this->read("Config.time")) {
00292                 if ($this->error === false) {
00293                     $this->valid = true;
00294                 }
00295             } else {
00296                 $this->valid = false;
00297                 $this->__setError(1, "Session Highjacking Attempted !!!");
00298             }
00299         }
00300         return $this->valid;
00301     }
00302 /**
00303  * Returns given session variable, or all of them, if no parameters given.
00304  *
00305  * @param mixed $name The name of the session variable (or a path as sent to Set.extract)
00306  * @return mixed The value of the session variable
00307  * @access public
00308  */
00309     function read($name = null) {
00310         if (is_null($name)) {
00311             return $this->__returnSessionVars();
00312         }
00313         if (empty($name)) {
00314             return false;
00315         }
00316         $result = Set::extract($_SESSION, $name);
00317 
00318         if (!is_null($result)) {
00319             return $result;
00320         }
00321         $this->__setError(2, "$name doesn't exist");
00322         return null;
00323     }
00324 /**
00325  * Returns all session variables.
00326  *
00327  * @return mixed Full $_SESSION array, or false on error.
00328  * @access private
00329  */
00330     function __returnSessionVars() {
00331         if (!empty($_SESSION)) {
00332             return $_SESSION;
00333         }
00334         $this->__setError(2, "No Session vars set");
00335         return false;
00336     }
00337 /**
00338  * Tells Session to write a notification when a certain session path or subpath is written to
00339  *
00340  * @param mixed $var The variable path to watch
00341  * @access public
00342  */
00343     function watch($var) {
00344         $var = $this->__validateKeys($var);
00345         if (empty($var)) {
00346             return false;
00347         }
00348         $this->watchKeys[] = $var;
00349     }
00350 /**
00351  * Tells Session to stop watching a given key path
00352  *
00353  * @param mixed $var The variable path to watch
00354  * @access public
00355  */
00356     function ignore($var) {
00357         $var = $this->__validateKeys($var);
00358         if (!in_array($var, $this->watchKeys)) {
00359             return;
00360         }
00361         foreach ($this->watchKeys as $i => $key) {
00362             if ($key == $var) {
00363                 unset($this->watchKeys[$i]);
00364                 $this->watchKeys = array_values($this->watchKeys);
00365                 return;
00366             }
00367         }
00368     }
00369 /**
00370  * Writes value to given session variable name.
00371  *
00372  * @param mixed $name Name of variable
00373  * @param string $value Value to write
00374  * @return boolean True if the write was successful, false if the write failed
00375  * @access public
00376  */
00377     function write($name, $value) {
00378         $var = $this->__validateKeys($name);
00379 
00380         if (empty($var)) {
00381             return false;
00382         }
00383         if (in_array($var, $this->watchKeys)) {
00384             trigger_error('Writing session key {' . $var . '}: ' . Debugger::exportVar($value), E_USER_NOTICE);
00385         }
00386         $this->__overwrite($_SESSION, Set::insert($_SESSION, $var, $value));
00387         return (Set::extract($_SESSION, $var) === $value);
00388     }
00389 /**
00390  * Helper method to destroy invalid sessions.
00391  *
00392  * @access public
00393  */
00394     function destroy() {
00395         $sessionpath = session_save_path();
00396         if (empty($sessionpath)) {
00397             $sessionpath = "/tmp";
00398         }
00399 
00400         if (isset($_COOKIE[session_name()])) {
00401             setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
00402         }
00403 
00404         $_SESSION = array();
00405         $file = $sessionpath . DS . "sess_" . session_id();
00406         @session_destroy();
00407         @unlink ($file);
00408         $this->__construct($this->path);
00409         $this->renew();
00410     }
00411 /**
00412  * Helper method to initialize a session, based on Cake core settings.
00413  *
00414  * @access private
00415  */
00416     function __initSession() {
00417         switch($this->security) {
00418             case 'high':
00419                 $this->cookieLifeTime = 0;
00420                 if (function_exists('ini_set')) {
00421                     ini_set('session.referer_check', $this->host);
00422                 }
00423             break;
00424             case 'medium':
00425                 $this->cookieLifeTime = 7 * 86400;
00426                 if (function_exists('ini_set')) {
00427                     ini_set('session.referer_check', $this->host);
00428                 }
00429             break;
00430             case 'low':
00431             default:
00432                 $this->cookieLifeTime = 788940000;
00433             break;
00434         }
00435 
00436         switch(Configure::read('Session.save')) {
00437             case 'cake':
00438                 if (!isset($_SESSION)) {
00439                     if (function_exists('ini_set')) {
00440                         ini_set('session.use_trans_sid', 0);
00441                         ini_set('url_rewriter.tags', '');
00442                         ini_set('session.serialize_handler', 'php');
00443                         ini_set('session.use_cookies', 1);
00444                         ini_set('session.name', Configure::read('Session.cookie'));
00445                         ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00446                         ini_set('session.cookie_path', $this->path);
00447                         ini_set('session.auto_start', 0);
00448                         ini_set('session.save_path', TMP . 'sessions');
00449                     }
00450                 }
00451             break;
00452             case 'database':
00453                 if (!isset($_SESSION)) {
00454                     if (Configure::read('Session.table') === null) {
00455                         trigger_error(__("You must set the all Configure::write('Session.*') in core.php to use database storage"), E_USER_WARNING);
00456                         exit();
00457                     } elseif (Configure::read('Session.database') === null) {
00458                         Configure::write('Session.database', 'default');
00459                     }
00460                     if (function_exists('ini_set')) {
00461                         ini_set('session.use_trans_sid', 0);
00462                         ini_set('url_rewriter.tags', '');
00463                         ini_set('session.save_handler', 'user');
00464                         ini_set('session.serialize_handler', 'php');
00465                         ini_set('session.use_cookies', 1);
00466                         ini_set('session.name', Configure::read('Session.cookie'));
00467                         ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00468                         ini_set('session.cookie_path', $this->path);
00469                         ini_set('session.auto_start', 0);
00470                     }
00471                 }
00472                 session_set_save_handler(array('CakeSession','__open'),
00473                                                     array('CakeSession', '__close'),
00474                                                     array('CakeSession', '__read'),
00475                                                     array('CakeSession', '__write'),
00476                                                     array('CakeSession', '__destroy'),
00477                                                     array('CakeSession', '__gc'));
00478             break;
00479             case 'php':
00480                 if (!isset($_SESSION)) {
00481                     if (function_exists('ini_set')) {
00482                         ini_set('session.use_trans_sid', 0);
00483                         ini_set('session.name', Configure::read('Session.cookie'));
00484                         ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00485                         ini_set('session.cookie_path', $this->path);
00486                     }
00487                 }
00488             break;
00489             case 'cache':
00490                 if (!isset($_SESSION)) {
00491                     if (!class_exists('Cache')) {
00492                         uses('Cache');
00493                     }
00494                     if (function_exists('ini_set')) {
00495                         ini_set('session.use_trans_sid', 0);
00496                         ini_set('url_rewriter.tags', '');
00497                         ini_set('session.save_handler', 'user');
00498                         ini_set('session.use_cookies', 1);
00499                         ini_set('session.name', Configure::read('Session.cookie'));
00500                         ini_set('session.cookie_lifetime', $this->cookieLifeTime);
00501                         ini_set('session.cookie_path', $this->path);
00502                     }
00503                 }
00504                 session_set_save_handler(array('CakeSession','__open'),
00505                                                     array('CakeSession', '__close'),
00506                                                     array('Cache', 'read'),
00507                                                     array('Cache', 'write'),
00508                                                     array('Cache', 'delete'),
00509                                                     array('CakeSession', '__gc'));
00510             break;
00511             default:
00512                 if (!isset($_SESSION)) {
00513                     $config = CONFIGS . Configure::read('Session.save') . '.php';
00514 
00515                     if (is_file($config)) {
00516                         require_once ($config);
00517                     }
00518                 }
00519             break;
00520         }
00521     }
00522 /**
00523  * Helper method to start a session
00524  *
00525  * @access private
00526  */
00527     function __startSession() {
00528         if (headers_sent()) {
00529             if (!isset($_SESSION)) {
00530                 $_SESSION = array();
00531             }
00532             return false;
00533         } elseif (!isset($_SESSION)) {
00534             session_cache_limiter ("must-revalidate");
00535             session_start();
00536             header ('P3P: CP="NOI ADM DEV PSAi COM NAV OUR OTRo STP IND DEM"');
00537             return true;
00538         } else {
00539             session_start();
00540             return true;
00541         }
00542     }
00543 /**
00544  * Helper method to create a new session.
00545  *
00546  * @access protected
00547  */
00548     function _checkValid() {
00549         if ($this->read('Config')) {
00550             if (Configure::read('Session.checkAgent') === false || $this->_userAgent == $this->read("Config.userAgent") && $this->time <= $this->read("Config.time")) {
00551                 $time = $this->read("Config.time");
00552                 $this->write("Config.time", $this->sessionTime);
00553 
00554                 if (Configure::read('Security.level') === 'high') {
00555                     $check = $this->read("Config.timeout");
00556                     $check = $check - 1;
00557                     $this->write("Config.timeout", $check);
00558 
00559                     if (time() > ($time - (Security::inactiveMins() * Configure::read('Session.timeout')) + 2) || $check < 1) {
00560                         $this->renew();
00561                         $this->write('Config.timeout', 10);
00562                     }
00563                 }
00564                 $this->valid = true;
00565             } else {
00566                 $this->destroy();
00567                 $this->valid = false;
00568                 $this->__setError(1, "Session Highjacking Attempted !!!");
00569             }
00570         } else {
00571             srand ((double)microtime() * 1000000);
00572             $this->write("Config.userAgent", $this->_userAgent);
00573             $this->write("Config.time", $this->sessionTime);
00574             $this->write('Config.rand', rand());
00575             $this->write('Config.timeout', 10);
00576             $this->valid = true;
00577             $this->__setError(1, "Session is valid");
00578         }
00579     }
00580 /**
00581  * Helper method to restart a session.
00582  *
00583  * @access private
00584  */
00585     function __regenerateId() {
00586         $oldSessionId = session_id();
00587         if ($oldSessionId) {
00588             $sessionpath = session_save_path();
00589             if (empty($sessionpath)) {
00590                 $sessionpath = "/tmp";
00591             }
00592             if (isset($_COOKIE[session_name()])) {
00593                 setcookie(Configure::read('Session.cookie'), '', time() - 42000, $this->path);
00594             }
00595             session_regenerate_id();
00596             $newSessid = session_id();
00597 
00598             if (function_exists('session_write_close')) {
00599                 session_write_close();
00600             }
00601             $this->__initSession();
00602             session_id($oldSessionId);
00603             session_start();
00604             session_destroy();
00605             $file = $sessionpath . DS . "sess_$oldSessionId";
00606             @unlink($file);
00607             $this->__initSession();
00608             session_id($newSessid);
00609             session_start();
00610         }
00611     }
00612 /**
00613  * Restarts this session.
00614  *
00615  * @access public
00616  */
00617     function renew() {
00618         $this->__regenerateId();
00619     }
00620 /**
00621  * Validate that the $name is in correct dot notation
00622  * example: $name = 'ControllerName.key';
00623  *
00624  * @param string $name Session key names as string.
00625  * @return mixed false is $name is not correct format, or $name if it is correct
00626  * @access private
00627  */
00628     function __validateKeys($name) {
00629         if (is_string($name) && preg_match("/^[ 0-9a-zA-Z._-]*$/", $name)) {
00630             return $name;
00631         }
00632         $this->__setError(3, "$name is not a string");
00633         return false;
00634     }
00635 /**
00636  * Helper method to set an internal error message.
00637  *
00638  * @param integer $errorNumber Number of the error
00639  * @param string $errorMessage Description of the error
00640  * @access private
00641  */
00642     function __setError($errorNumber, $errorMessage) {
00643         if ($this->error === false) {
00644             $this->error = array();
00645         }
00646         $this->error[$errorNumber] = $errorMessage;
00647         $this->lastError = $errorNumber;
00648     }
00649 /**
00650  * Method called on open of a database session.
00651  *
00652  * @return boolean Success
00653  * @access private
00654  */
00655     function __open() {
00656         return true;
00657     }
00658 /**
00659  * Method called on close of a database session.
00660  *
00661  * @return boolean Success
00662  * @access private
00663  */
00664     function __close() {
00665         $probability = mt_rand(1, 150);
00666         if ($probability <= 3) {
00667             switch(Configure::read('Session.save')) {
00668                 case 'cache':
00669                     Cache::gc();
00670                 break;
00671                 default:
00672                     CakeSession::__gc();
00673                 break;
00674             }
00675         }
00676         return true;
00677     }
00678 /**
00679  * Method used to read from a database session.
00680  *
00681  * @param mixed $key The key of the value to read
00682  * @return mixed The value of the key or false if it does not exist
00683  * @access private
00684  */
00685     function __read($key) {
00686         $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00687         $table = $db->fullTableName(Configure::read('Session.table'), false);
00688         $row = $db->query("SELECT " . $db->name($table.'.data') . " FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key), false);
00689 
00690         if ($row && !isset($row[0][$table]) && isset($row[0][0])) {
00691             $table = 0;
00692         }
00693 
00694         if ($row && $row[0][$table]['data']) {
00695             return $row[0][$table]['data'];
00696         } else {
00697             return false;
00698         }
00699     }
00700 /**
00701  * Helper function called on write for database sessions.
00702  *
00703  * @param mixed $key The name of the var
00704  * @param mixed $value The value of the var
00705  * @return boolean Success
00706  * @access private
00707  */
00708     function __write($key, $value) {
00709         $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00710         $table = $db->fullTableName(Configure::read('Session.table'));
00711 
00712         switch(Configure::read('Security.level')) {
00713             case 'high':
00714                 $factor = 10;
00715             break;
00716             case 'medium':
00717                 $factor = 100;
00718             break;
00719             case 'low':
00720                 $factor = 300;
00721             break;
00722             default:
00723                 $factor = 10;
00724             break;
00725         }
00726         $expires = time() +  Configure::read('Session.timeout') * $factor;
00727         $row = $db->query("SELECT COUNT(id) AS count FROM " . $db->name($table) . " WHERE "
00728                                  . $db->name('id') . " = "
00729                                  . $db->value($key), false);
00730 
00731         if ($row[0][0]['count'] > 0) {
00732             $db->execute("UPDATE " . $db->name($table) . " SET " . $db->name('data') . " = "
00733                                 . $db->value($value) . ", " . $db->name('expires') . " = "
00734                                 . $db->value($expires) . " WHERE " . $db->name('id') . " = "
00735                                 . $db->value($key));
00736         } else {
00737             $db->execute("INSERT INTO " . $db->name($table) . " (" . $db->name('data') . ","
00738                                 . $db->name('expires') . "," . $db->name('id')
00739                                 . ") VALUES (" . $db->value($value) . ", " . $db->value($expires) . ", "
00740                                 . $db->value($key) . ")");
00741         }
00742         return true;
00743     }
00744 /**
00745  * Method called on the destruction of a database session.
00746  *
00747  * @param integer $key Key that uniquely identifies session in database
00748  * @return boolean Success
00749  * @access private
00750  */
00751     function __destroy($key) {
00752         $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00753         $table = $db->fullTableName(Configure::read('Session.table'));
00754         $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.id') . " = " . $db->value($key));
00755         return true;
00756     }
00757 /**
00758  * Helper function called on gc for database sessions.
00759  *
00760  * @param integer $expires Timestamp (defaults to current time)
00761  * @return boolean Success
00762  * @access private
00763  */
00764     function __gc($expires = null) {
00765         $db =& ConnectionManager::getDataSource(Configure::read('Session.database'));
00766         $table = $db->fullTableName(Configure::read('Session.table'));
00767         $db->execute("DELETE FROM " . $db->name($table) . " WHERE " . $db->name($table.'.expires') . " < ". $db->value(time()));
00768         return true;
00769      }
00770 }
00771 ?>