eZ Publish  [4.0]
ezsession.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // Definition of eZSession class
00004 //
00005 // Created on: <19-Aug-2002 12:49:18 bf>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   Re-implementation of PHP session management using database.
00033 
00034   The session system has a hook system which allows external code to perform
00035   extra tasks before and after a certain action is executed. For instance to
00036   cleanup a table when sessions are removed.
00037   To create a hook function the global variable \c eZSessionFunctions must be
00038   filled in. This contains an associative array with hook points, e.g.
00039   \c destroy_pre which is checked by the session system.
00040   Each hook point must contain an array with function names to execute, if the
00041   hook point does not exist the session handler will not handle the hooks.
00042 
00043   \code
00044   function cleanupStuff( $db, $key, $escKey )
00045   {
00046       // Do cleanup here
00047   }
00048   if ( !isset( $GLOBALS['eZSessionFunctions']['destroy_pre'] ) )
00049       $GLOBALS['eZSessionFunctions']['destroy_pre'] = array();
00050   $GLOBALS['eZSessionFunctions']['destroy_pre'][] = 'cleanupstuff';
00051   \endcode
00052 
00053   When new data is inserted to the database it will call the \c update_pre and
00054   \c update_post hooks. The signature of the function is
00055   function insert( $db, $key, $escapedKey, $expirationTime, $userID, $value )
00056 
00057   When existing data is updated in the databbase it will call the \c insert_pre
00058   and \c insert_post hook. The signature of the function is
00059   function update( $db, $key, $escapedKey, $expirationTime, $userID, $value )
00060 
00061   When a specific session is destroyed in the database it will call the
00062   \c destroy_pre and \c destroy_post hooks. The signature of the function is
00063   function destroy( $db, $key, $escapedKey )
00064 
00065   When multiple sessions are expired (garbage collector) in the database it
00066   will call the \c gc_pre and \c gc_post hooks. The signature of the function is
00067   function gcollect( $db, $expiredTime )
00068 
00069   When all sessionss are removed from the database it will call the
00070   \c empty_pre and \c empty_post hooks. The signature of the function is
00071   function empty( $db )
00072 
00073   \param $db The database object used by the session manager.
00074   \param $key The session key which are being worked on, see also \a $escapedKey
00075   \param $escapedKey The same key as \a $key but is escaped correctly for the database.
00076                      Use this to save a call to eZDBInterface::escapeString()
00077   \param $expirationTime An integer specifying the timestamp of when the session
00078                          will expire.
00079   \param $expiredTime Similar to \a $expirationTime but is the time used to figure
00080                       if a session is expired in the database. ie. all sessions with
00081                       lower expiration times will be removed.
00082 */
00083 
00084 function eZSessionOpen( )
00085 {
00086     // do nothing eZDB will open connection when needed.
00087 }
00088 
00089 function eZSessionClose( )
00090 {
00091     // eZDB will handle closing the database
00092 }
00093 
00094 function eZSessionRead( $key )
00095 {
00096     //include_once( 'lib/ezdb/classes/ezdb.php' );
00097     $db = eZDB::instance();
00098 
00099     $key = $db->escapeString( $key );
00100 
00101     $sessionRes = $db->arrayQuery( "SELECT data, user_id, expiration_time FROM ezsession WHERE session_key='$key'" );
00102 
00103     if ( $sessionRes !== false and count( $sessionRes ) == 1 )
00104     {
00105         $ini = eZINI::instance();
00106 
00107         $sessionUpdatesTime = $sessionRes[0]['expiration_time'] - $ini->variable( 'Session', 'SessionTimeout' );
00108         $sessionIdle = time() - $sessionUpdatesTime;
00109 
00110         $GLOBALS['eZSessionUserID'] = $sessionRes[0]['user_id'];
00111         $GLOBALS['eZSessionIdleTime'] = $sessionIdle;
00112 
00113         /*
00114          * The line below is needed to correctly load list of content classes saved
00115          * in the CanInstantiateClassList session variable.
00116          * Without this we get incomplete classes loaded (__PHP_Incomplete_Class).
00117          */
00118         require_once( 'kernel/classes/ezcontentclass.php' );
00119 
00120         return $sessionRes[0]['data'];
00121     }
00122     else
00123     {
00124         return false;
00125     }
00126 }
00127 
00128 /*!
00129   Will write the session information to database.
00130 */
00131 function eZSessionWrite( $key, $value )
00132 {
00133 //    //include_once( 'lib/ezdb/classes/ezdb.php' );
00134 
00135     if ( isset( $GLOBALS["eZRequestError"] ) && $GLOBALS["eZRequestError"] )
00136     {
00137         return;
00138     }
00139 
00140     $db = eZDB::instance();
00141     $ini = eZINI::instance();
00142     $expirationTime = time() + $ini->variable( 'Session', 'SessionTimeout' );
00143 
00144     if ( $db->bindingType() != eZDBInterface::BINDING_NO )
00145     {
00146         $value = $db->bindVariable( $value, array( 'name' => 'data' ) );
00147     }
00148     else
00149     {
00150         $value = '\'' . $db->escapeString( $value ) . '\'';
00151 
00152     }
00153 //    $value = $db->escapeString( $value );
00154     $escKey = $db->escapeString( $key );
00155     // check if session already exists
00156 
00157     $userID = 0;
00158     if ( isset( $GLOBALS['eZSessionUserID'] ) )
00159         $userID = $GLOBALS['eZSessionUserID'];
00160     $userID = $db->escapeString( $userID );
00161 
00162     $sessionRes = $db->arrayQuery( "SELECT session_key FROM ezsession WHERE session_key='$escKey'" );
00163 
00164     if ( count( $sessionRes ) == 1 )
00165     {
00166         if ( isset( $GLOBALS['eZSessionFunctions']['update_pre'] ) )
00167         {
00168             foreach ( $GLOBALS['eZSessionFunctions']['update_pre'] as $func )
00169             {
00170                 $func( $db, $key, $escKey, $expirationTime, $userID, $value );
00171             }
00172         }
00173 
00174         $updateQuery = "UPDATE ezsession
00175                     SET expiration_time='$expirationTime', data=$value, user_id='$userID'
00176                     WHERE session_key='$escKey'";
00177 
00178         $ret = $db->query( $updateQuery );
00179 
00180         if ( isset( $GLOBALS['eZSessionFunctions']['update_post'] ) )
00181         {
00182             foreach ( $GLOBALS['eZSessionFunctions']['update_post'] as $func )
00183             {
00184                 $func( $db, $key, $escKey, $expirationTime, $userID, $value );
00185             }
00186         }
00187     }
00188     else
00189     {
00190         if ( isset( $GLOBALS['eZSessionFunctions']['insert_pre'] ) )
00191         {
00192             foreach ( $GLOBALS['eZSessionFunctions']['insert_pre'] as $func )
00193             {
00194                 $func( $db, $key, $escKey, $expirationTime, $userID, $value );
00195             }
00196         }
00197 
00198         $insertQuery = "INSERT INTO ezsession
00199                     ( session_key, expiration_time, data, user_id )
00200                     VALUES ( '$escKey', '$expirationTime', $value, '$userID' )";
00201 
00202         $ret = $db->query( $insertQuery );
00203 
00204         if ( isset( $GLOBALS['eZSessionFunctions']['insert_post'] ) )
00205         {
00206             foreach ( $GLOBALS['eZSessionFunctions']['insert_post'] as $func )
00207             {
00208                 $func( $db, $key, $escKey, $expirationTime, $userID, $value );
00209             }
00210         }
00211     }
00212 }
00213 
00214 /*!
00215   Will remove a session from the database.
00216 */
00217 function eZSessionDestroy( $key )
00218 {
00219     //include_once( 'lib/ezdb/classes/ezdb.php' );
00220     $db = eZDB::instance();
00221 
00222     $escKey = $db->escapeString( $key );
00223     if ( isset( $GLOBALS['eZSessionFunctions']['destroy_pre'] ) )
00224     {
00225         foreach ( $GLOBALS['eZSessionFunctions']['destroy_pre'] as $func )
00226         {
00227             $func( $db, $key, $escKey );
00228         }
00229     }
00230 
00231     $query = "DELETE FROM ezsession WHERE session_key='$escKey'";
00232     $db->query( $query );
00233 
00234     if ( isset( $GLOBALS['eZSessionFunctions']['destroy_post'] ) )
00235     {
00236         foreach ( $GLOBALS['eZSessionFunctions']['destroy_post'] as $func )
00237         {
00238             $func( $db, $key, $escKey );
00239         }
00240     }
00241 }
00242 
00243 /*!
00244   Handles session cleanup. Will delete timed out sessions from the database.
00245 */
00246 function eZSessionGarbageCollector()
00247 {
00248     //include_once( 'lib/ezdb/classes/ezdb.php' );
00249     $db = eZDB::instance();
00250     $time = time();
00251 
00252     if ( isset( $GLOBALS['eZSessionFunctions']['gc_pre'] ) )
00253     {
00254         foreach ( $GLOBALS['eZSessionFunctions']['gc_pre'] as $func )
00255         {
00256             $func( $db, $time );
00257         }
00258     }
00259 
00260     $query = "DELETE FROM ezsession WHERE expiration_time < " . $time;
00261 
00262     $db->query( $query );
00263 
00264     if ( isset( $GLOBALS['eZSessionFunctions']['gc_post'] ) )
00265     {
00266         foreach ( $GLOBALS['eZSessionFunctions']['gc_post'] as $func )
00267         {
00268             $func( $db, $time );
00269         }
00270     }
00271 }
00272 
00273 /*!
00274   Removes all entries from session.
00275 */
00276 function eZSessionEmpty()
00277 {
00278     //include_once( 'lib/ezdb/classes/ezdb.php' );
00279     $db = eZDB::instance();
00280 
00281     if ( isset( $GLOBALS['eZSessionFunctions']['empty_pre'] ) )
00282     {
00283         foreach ( $GLOBALS['eZSessionFunctions']['empty_pre'] as $func )
00284         {
00285             $func( $db );
00286         }
00287     }
00288 
00289     $query = "TRUNCATE TABLE ezsession";
00290 
00291     $db->query( $query );
00292 
00293     if ( isset( $GLOBALS['eZSessionFunctions']['empty_post'] ) )
00294     {
00295         foreach ( $GLOBALS['eZSessionFunctions']['empty_post'] as $func )
00296         {
00297             $func( $db );
00298         }
00299     }
00300 }
00301 
00302 /*!
00303   Counts the number of active session and returns it.
00304 */
00305 function eZSessionCountActive()
00306 {
00307     //include_once( 'lib/ezdb/classes/ezdb.php' );
00308     $db = eZDB::instance();
00309     $query = "SELECT count( * ) AS count FROM ezsession";
00310 
00311     $rows = $db->arrayQuery( $query );
00312     return $rows[0]['count'];
00313 }
00314 
00315 /*!
00316  Register the needed session functions.
00317  Call this only once.
00318 */
00319 function eZRegisterSessionFunctions()
00320 {
00321     session_module_name( 'user' );
00322     $ini = eZINI::instance();
00323     if ( $ini->variable( 'Session', 'SessionNameHandler' ) == 'custom' )
00324     {
00325         $sessionName = $ini->variable( 'Session', 'SessionNamePrefix' );
00326         if ( $ini->variable( 'Session', 'SessionNamePerSiteAccess' ) == 'enabled' )
00327         {
00328             $access = $GLOBALS['eZCurrentAccess'];
00329             $sessionName .=  $access['name'];
00330         }
00331         session_name( $sessionName );
00332     }
00333     session_set_save_handler(
00334         'ezsessionopen',
00335         'ezsessionclose',
00336         'ezsessionread',
00337         'ezsessionwrite',
00338         'ezsessiondestroy',
00339         'ezsessiongarbagecollector' );
00340 }
00341 
00342 /*!
00343  Makes sure that the session is started properly.
00344  Multiple calls will just be ignored.
00345 */
00346 function eZSessionStart()
00347 {
00348     // Check if we are allowed to use sessions
00349     if ( isset( $GLOBALS['eZSiteBasics'] ) &&
00350          isset( $GLOBALS['eZSiteBasics']['session-required'] ) &&
00351          !$GLOBALS['eZSiteBasics']['session-required'] )
00352     {
00353         return false;
00354     }
00355     if ( isset( $GLOBALS['eZSessionIsStarted'] ) &&
00356          $GLOBALS['eZSessionIsStarted'] )
00357     {
00358          return false;
00359     }
00360     //include_once( 'lib/ezdb/classes/ezdb.php' );
00361     $db = eZDB::instance();
00362     if ( !$db->isConnected() )
00363     {
00364         return false;
00365     }
00366     eZRegisterSessionFunctions();
00367     $ini = eZINI::instance();
00368     $cookieTimeout = isset( $GLOBALS['RememberMeTimeout'] ) ? $GLOBALS['RememberMeTimeout'] : $ini->variable( 'Session', 'CookieTimeout' );
00369 
00370     if ( is_numeric( $cookieTimeout ) )
00371     {
00372         session_set_cookie_params( (int)$cookieTimeout );
00373     }
00374     session_start();
00375     return $GLOBALS['eZSessionIsStarted'] = true;
00376 }
00377 
00378 /*!
00379  Makes sure session data is stored in the session and stops the session.
00380 */
00381 function eZSessionStop()
00382 {
00383     if ( isset( $GLOBALS['eZSessionIsStarted'] ) &&
00384          !$GLOBALS['eZSessionIsStarted'] )
00385     {
00386          return false;
00387     }
00388     //include_once( 'lib/ezdb/classes/ezdb.php' );
00389     $db = eZDB::instance();
00390     if ( !$db->isConnected() )
00391     {
00392         return false;
00393     }
00394     session_write_close();
00395     $GLOBALS['eZSessionIsStarted'] = false;
00396     return true;
00397 }
00398 
00399 /*!
00400  Will make sure the user gets a new session ID while keepin the session data.
00401  This is useful to call on logins, to avoid sessions theft from users.
00402  \note This requires PHP 4.3.2 and higher which has the session_regenerate_id
00403  \return \c true if succesful
00404 */
00405 function eZSessionRegenerate()
00406 {
00407     if ( isset( $GLOBALS['eZSessionIsStarted'] ) &&
00408          !$GLOBALS['eZSessionIsStarted'] )
00409     {
00410          return false;
00411     }
00412     if ( !function_exists( 'session_regenerate_id' ) )
00413     {
00414         return false;
00415     }
00416     // This doesn't seem to work as expected
00417 //     session_regenerate_id();
00418     return true;
00419 }
00420 
00421 /*!
00422  Removes the current session and resets session variables.
00423 */
00424 function eZSessionRemove()
00425 {
00426     if ( isset( $GLOBALS['eZSessionIsStarted'] ) &&
00427          !$GLOBALS['eZSessionIsStarted'] )
00428     {
00429          return false;
00430     }
00431     //include_once( 'lib/ezdb/classes/ezdb.php' );
00432     $db = eZDB::instance();
00433     if ( !$db->isConnected() )
00434     {
00435         return false;
00436     }
00437     $_SESSION = array();
00438     session_destroy();
00439     $GLOBALS['eZSessionIsStarted'] = false;
00440     return true;
00441 }
00442 
00443 /*!
00444  Sets the current user ID to \a $userID,
00445  this ID will be written to the session table field user_id
00446  when the page is done.
00447  \sa eZSessionUserID
00448 */
00449 function eZSessionSetUserID( $userID )
00450 {
00451     $GLOBALS['eZSessionUserID'] = $userID;
00452 }
00453 
00454 /*!
00455  Returns the current session ID.
00456  The session handler will not care about value of the ID,
00457  it's entirely up to the clients of the session handler to use and update this value.
00458 */
00459 function eZSessionUserID()
00460 {
00461     if ( isset( $GLOBALS['eZSessionUserID'] ) )
00462         return $GLOBALS['eZSessionUserID'];
00463     return 0;
00464 }
00465 
00466 ?>