b2evolution PHP Cross Reference Blogging Systems

Source: /inc/sessions/model/_session.class.php - 751 lines - 23125 bytes - Summary - Text - Print

Description: This file implements the Session class and holds the {@link session_unserialize_callback()} function used by it. A session can be bound to a user and provides functions to store data in its context. All Hitlogs are also bound to a Session.

   1  <?php
   2  /**
   3   * This file implements the Session class and holds the
   4   * {@link session_unserialize_callback()} function used by it.
   5   *
   6   * A session can be bound to a user and provides functions to store data in its
   7   * context.
   8   * All Hitlogs are also bound to a Session.
   9   *
  10   * This file is part of the evoCore framework - {@link http://evocore.net/}
  11   * See also {@link http://sourceforge.net/projects/evocms/}.
  12   *
  13   * @copyright (c)2003-2014 by Francois Planque - {@link http://fplanque.com/}
  14   * Parts of this file are copyright (c)2004-2006 by Daniel HAHLER - {@link http://thequod.de/contact}.
  15   *
  16   * {@internal License choice
  17   * - If you have received this file as part of a package, please find the license.txt file in
  18   *   the same folder or the closest folder above for complete license terms.
  19   * - If you have received this file individually (e-g: from http://evocms.cvs.sourceforge.net/)
  20   *   then you must choose one of the following licenses before using the file:
  21   *   - GNU General Public License 2 (GPL) - http://www.opensource.org/licenses/gpl-license.php
  22   *   - Mozilla Public License 1.1 (MPL) - http://www.opensource.org/licenses/mozilla1.1.php
  23   * }}
  24   *
  25   * {@internal Open Source relicensing agreement:
  26   * Daniel HAHLER grants Francois PLANQUE the right to license
  27   * Daniel HAHLER's contributions to this file and the b2evolution project
  28   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  29   *
  30   * Matt FOLLETT grants Francois PLANQUE the right to license
  31   * Matt FOLLETT's contributions to this file and the b2evolution project
  32   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  33   * }}
  34   *
  35   * @package evocore
  36   *
  37   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  38   * @author blueyed: Daniel HAHLER.
  39   * @author fplanque: Francois PLANQUE.
  40   * @author jeffbearer: Jeff BEARER - {@link http://www.jeffbearer.com/}.
  41   * @author mfollett:  Matt FOLLETT - {@link http://www.mfollett.com/}.
  42   *
  43   * @version $Id: _session.class.php 6136 2014-03-08 07:59:48Z manuel $
  44   */
  45  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  46  
  47  
  48  /**
  49   * A session tracks a given user (not necessarily logged in) while he's navigating the site.
  50   * A session also stores data for the length of the session.
  51   *
  52   * Sessions are tracked with a cookie containing the session ID.
  53   * The cookie also contains a random key to prevent sessions hacking.
  54   *
  55   * @package evocore
  56   */
  57  class Session
  58  {
  59      /**
  60       * The ID of the session.
  61       * @var integer
  62       */
  63      var $ID;
  64  
  65      /**
  66       * The session key (to be used in URLs).
  67       * @var string
  68       */
  69      var $key;
  70  
  71      /**
  72       * The user ID for the user of the session (NULL for anonymous (not logged in) user).
  73       *
  74       * @var integer
  75       */
  76      var $user_ID;
  77  
  78      /**
  79       * Is the session validated?
  80       * This means that it was created from a received cookie.
  81       * @var boolean
  82       */
  83      var $is_validated = false;
  84  
  85      /**
  86       * Session start timestamp
  87       * @var string
  88       */
  89      var $start_ts;
  90  
  91      /**
  92       * Session last seen timestamp which was logged
  93       * Value may be off by up to 60 seconds
  94       * @var string
  95       */
  96      var $lastseen_ts;
  97  
  98      /**
  99       * Data stored for the session.
 100       *
 101       * This holds an array( expire, value ) for each data item key.
 102       *
 103       * @access protected
 104       * @var array
 105       */
 106      var $_data;
 107  
 108      var $_session_needs_save = false;
 109  
 110      /**
 111       * The user device from where this session was created
 112       * 
 113       * @var string
 114       */
 115      var $sess_device;
 116  
 117      /**
 118       * Constructor
 119       *
 120       * If valid session cookie received: pull session from DB
 121       * Otherwise, INSERT a session into DB
 122       */
 123  	function Session()
 124      {
 125          global $DB, $Debuglog, $current_User, $localtimenow, $Messages, $Settings, $UserSettings;
 126          global $Hit;
 127          global $cookie_session, $cookie_expires, $cookie_path, $cookie_domain;
 128  
 129          $Debuglog->add( 'Session: cookie_domain='.$cookie_domain, 'request' );
 130          $Debuglog->add( 'Session: cookie_path='.$cookie_path, 'request' );
 131  
 132          $session_cookie = param_cookie( $cookie_session, 'string', '' );
 133          if( empty( $session_cookie ) )
 134          {
 135              $Debuglog->add( 'Session: No session cookie received.', 'request' );
 136          }
 137          else
 138          { // session ID sent by cookie
 139              if( ! preg_match( '~^(\d+)_(\w+)$~', $session_cookie, $match ) )
 140              {
 141                  $Debuglog->add( 'Session: Invalid session cookie format!', 'request' );
 142              }
 143              else
 144              {    // We have a valid session cookie:
 145                  $session_id_by_cookie = $match[1];
 146                  $session_key_by_cookie = $match[2];
 147  
 148                  $Debuglog->add( 'Session: Session ID received from cookie: '.$session_id_by_cookie, 'request' );
 149  
 150                  $timeout_sessions = NULL;
 151                  if( $this->user_ID != NULL )
 152                  {    // User is not anonymous, get custom session timeout (may return NULL):
 153                      $timeout_sessions = $UserSettings->get( 'timeout_sessions', $this->user_ID );
 154                  }
 155  
 156                  if( empty( $timeout_sessions ) )
 157                  {    // User is anonymous or has no custom session timeout. So, we use default session timeout:
 158                      $timeout_sessions = $Settings->get('timeout_sessions');
 159                  }
 160  
 161                  $row = $DB->get_row( '
 162                      SELECT sess_ID, sess_key, sess_data, sess_user_ID, sess_start_ts, sess_lastseen_ts, sess_device
 163                        FROM T_sessions
 164                       WHERE sess_ID  = '.$DB->quote($session_id_by_cookie).'
 165                         AND sess_key = '.$DB->quote($session_key_by_cookie).'
 166                         AND UNIX_TIMESTAMP(sess_lastseen_ts) > '.( $localtimenow - $timeout_sessions ) );
 167                  if( empty( $row ) )
 168                  {
 169                      $Debuglog->add( 'Session: Session ID/key combination is invalid!', 'request' );
 170                  }
 171                  else
 172                  { // ID + key are valid: load data
 173                      $Debuglog->add( 'Session: Session ID is valid.', 'request' );
 174                      $this->ID = $row->sess_ID;
 175                      $this->key = $row->sess_key;
 176                      $this->user_ID = $row->sess_user_ID;
 177                      $this->start_ts = mysql2timestamp( $row->sess_start_ts );
 178                      $this->lastseen_ts = mysql2timestamp( $row->sess_lastseen_ts );
 179                      $this->is_validated = true;
 180                      $this->sess_device = $row->sess_device;
 181  
 182                      $Debuglog->add( 'Session: Session user_ID: '.var_export($this->user_ID, true), 'request' );
 183  
 184                      if( empty( $row->sess_data ) )
 185                      {
 186                          $Debuglog->add( 'Session: No session data available.', 'request' );
 187                          $this->_data = array();
 188                      }
 189                      else
 190                      { // Some session data has been previsouly stored:
 191  
 192                          // Unserialize session data (using an own callback that should provide class definitions):
 193                          $old_callback = ini_set( 'unserialize_callback_func', 'session_unserialize_callback' );
 194                          if( $old_callback === false || is_null($old_callback) /* disabled, reported with PHP 5.2.5 */ )
 195                          {    // NULL if ini_set has been disabled for security reasons
 196                              // Brutally load all classes that we might need:
 197                               session_unserialize_load_all_classes();
 198                          }
 199                          // TODO: dh> This can fail, if there are special chars in sess_data:
 200                          //       It will be encoded in $evo_charset _after_ "SET NAMES", but
 201                          //       get retrieved here, _before_ any "SET NAMES" (if $db_config['connection_charset'] is not set (default))!
 202                          $this->_data = @unserialize($row->sess_data);
 203  
 204                          if( $old_callback !== false )
 205                          {    // Restore the old callback if we changed it:
 206                              ini_set( 'unserialize_callback_func', $old_callback );
 207                          }
 208  
 209                          if( ! is_array($this->_data) )
 210                          {
 211                              $Debuglog->add( 'Session: Session data corrupted!<br />
 212                                  connection_charset: '.var_export($DB->connection_charset, true).'<br />
 213                                  Serialized data was: --['.var_export($row->sess_data, true).']--', array('session','error') );
 214                              $this->_data = array();
 215                          }
 216                          else
 217                          {
 218                              $Debuglog->add( 'Session: Session data loaded.', 'request' );
 219  
 220                              // Load a Messages object from session data, if available:
 221                              if( ($sess_Messages = $this->get('Messages')) && is_a( $sess_Messages, 'Messages' ) )
 222                              {
 223                                  // dh> TODO: "old" messages should rather get prepended to any existing ones from the current request, rather than appended
 224                                  $Messages->add_messages( $sess_Messages );
 225                                  $Debuglog->add( 'Session: Added Messages from session data.', 'request' );
 226                                  $this->delete( 'Messages' );
 227                              }
 228                          }
 229                      }
 230                  }
 231              }
 232          }
 233  
 234  
 235          if( $this->ID )
 236          { // there was a valid session before
 237              if( $this->lastseen_ts < $localtimenow - 60 )
 238              { // lastseen timestamp is older then a minute, it needs to be updated at page exit
 239                  $this->session_needs_save( true );
 240              }
 241          }
 242          else
 243          { // create a new session! :
 244              $this->key = generate_random_key(32);
 245  
 246              // Detect user device
 247              global $user_devices;
 248              $this->sess_device = '';
 249  
 250              if( !empty($_SERVER['HTTP_USER_AGENT']) )
 251              {
 252                  foreach( $user_devices as $device_name => $device_regexp )
 253                  {
 254                      if( preg_match( '~'.$device_regexp.'~i', $_SERVER['HTTP_USER_AGENT'] ) )
 255                      {
 256                          $this->sess_device = $device_name;
 257                          break;
 258                      }
 259                  }
 260              }
 261  
 262              // We need to INSERT now because we need an ID now! (for the cookie)
 263              $DB->query( "
 264                  INSERT INTO T_sessions( sess_key, sess_start_ts, sess_lastseen_ts, sess_ipaddress, sess_device )
 265                  VALUES (
 266                      '".$this->key."',
 267                      '".date( 'Y-m-d H:i:s', $localtimenow )."',
 268                      '".date( 'Y-m-d H:i:s', $localtimenow )."',
 269                      ".$DB->quote( $Hit->IP ).",
 270                      ".$DB->quote( $this->sess_device )."
 271                  )" );
 272  
 273              $this->ID = $DB->insert_id;
 274  
 275              // Set a cookie valid for ~ 10 years:
 276              setcookie( $cookie_session, $this->ID.'_'.$this->key, time()+315360000, $cookie_path, $cookie_domain );
 277  
 278              $Debuglog->add( 'Session: ID (generated): '.$this->ID, 'request' );
 279              $Debuglog->add( 'Session: Cookie sent.', 'request' );
 280          }
 281      }
 282  
 283  
 284  	function session_needs_save( $session_needs_save )
 285      {
 286          // pre_dump( 'SETTING session needs save to', $session_needs_save );
 287          $this->_session_needs_save = $session_needs_save;
 288      }
 289  
 290      /**
 291       * Attach a User object to the session.
 292       *
 293       * @param User The user to attach
 294       */
 295  	function set_User( $User )
 296      {
 297          return $this->set_user_ID( $User->ID );
 298      }
 299  
 300  
 301      /**
 302       * Attach a user ID to the session.
 303       *
 304       * NOTE: ID gets saved to DB on shutdown. This may be a "problem" when querying T_sessions for sess_user_ID.
 305       *
 306       * @param integer The ID of the user to attach
 307       */
 308  	function set_user_ID( $user_ID )
 309      {
 310          if( $user_ID != $this->user_ID )
 311          {
 312              global $Settings, $UserSettings, $DB;
 313  
 314              $multiple_sessions = $Settings->get( 'multiple_sessions' );
 315  
 316              if( $multiple_sessions != 'always' && ( $multiple_sessions == 'never' || !$UserSettings->get('login_multiple_sessions', $user_ID) ) )
 317              { // The user does not want/is not allowed to have multiple sessions open at the same time:
 318                  // Invalidate previous sessions:
 319                  global $Debuglog;
 320                  $Debuglog->add( 'Session: Invalidating all previous user sessions, because login_multiple_sessions=0', 'request' );
 321                  $DB->query( '
 322                      UPDATE T_sessions
 323                         SET sess_key = NULL
 324                       WHERE sess_user_ID = '.$DB->quote($user_ID).'
 325                         AND sess_ID != '.$this->ID );
 326              }
 327  
 328              $this->user_ID = $user_ID;
 329              $this->session_needs_save( true );
 330          }
 331      }
 332  
 333  
 334      /**
 335       * Logout the user, by invalidating the session key and unsetting {@link $user_ID}.
 336       *
 337       * We want to keep the user in the session log, but we're unsetting {@link $user_ID}, which refers
 338       * to the current session.
 339       *
 340       * Because the session key is invalid/broken, on the next request a new session will be started.
 341       *
 342       * NOTE: we MIGHT want to link subsequent sessions together if we want to keep track...
 343       */
 344  	function logout()
 345      {
 346          global $Debuglog, $cookie_session, $cookie_path, $cookie_domain;
 347  
 348          // Invalidate the session key (no one will be able to use this session again)
 349          $this->key = NULL;
 350          $this->_data = array(); // We don't need to keep old data
 351          $this->session_needs_save( true );
 352          $this->dbsave();
 353  
 354          $this->user_ID = NULL; // Unset user_ID after invalidating/saving the session above, to keep the user info attached to the old session.
 355  
 356          // clean up the session cookie:
 357          setcookie( $cookie_session, '', 200000000, $cookie_path, $cookie_domain );
 358      }
 359  
 360  
 361      /**
 362       * Check if session has a user attached.
 363       *
 364       * @return boolean
 365       */
 366  	function has_User()
 367      {
 368          return !empty( $this->user_ID );
 369      }
 370  
 371  
 372      /**
 373       * Get the attached User.
 374       *
 375       * @return false|User
 376       */
 377      function & get_User()
 378      {
 379          if( !empty($this->user_ID) )
 380          {
 381              $UserCache = & get_UserCache();
 382              return $UserCache->get_by_ID( $this->user_ID );
 383          }
 384  
 385          $r = false;
 386          return $r;
 387      }
 388  
 389  
 390      /**
 391       * Get a data value for the session. This checks for the data to be expired and unsets it then.
 392       *
 393       * @param string Name of the data's key.
 394       * @param mixed Default value to use if key is not set or has expired. (since 1.10.0)
 395       * @return mixed The value, if set; otherwise $default
 396       */
 397  	function get( $param, $default = NULL )
 398      {
 399          global $Debuglog, $localtimenow;
 400  
 401          if( isset( $this->_data[$param] ) )
 402          {
 403              if( array_key_exists(1, $this->_data[$param]) // can be NULL!
 404                && ( is_null( $this->_data[$param][0] ) || $this->_data[$param][0] > $localtimenow ) ) // check for expired data
 405              {
 406                  return $this->_data[$param][1];
 407              }
 408              else
 409              { // expired or old format (without 'value' key)
 410                  unset( $this->_data[$param] );
 411                  $this->session_needs_save( true );
 412                  $Debuglog->add( 'Session: Session data['.$param.'] expired.', 'request' );
 413              }
 414          }
 415  
 416          return $default;
 417      }
 418  
 419  
 420      /**
 421       * Set a data value for the session.
 422       *
 423       * Updated values get saved to the DB automatically on shutdown, in {@link shutdown()}.
 424       *
 425       * @param string Name of the data's key.
 426       * @param mixed The value
 427       * @param integer Time in seconds for data to expire (0 to disable).
 428       */
 429  	function set( $param, $value, $expire = 0 )
 430      {
 431          global $Debuglog, $localtimenow;
 432  
 433          if( ! isset($this->_data[$param])
 434           || ! is_array($this->_data[$param]) // deprecated: check to transform 1.6 session data to 1.7
 435           || $this->_data[$param][1] != $value
 436           || $expire != 0 )
 437          {    // There is something to update:
 438              $this->_data[$param] = array( ( $expire ? ($localtimenow + $expire) : NULL ), $value );
 439  
 440              if( $param == 'Messages' )
 441              { // also set boolean to not call CachePageContent plugin event on next request:
 442                  $this->set( 'core.no_CachePageContent', 1 );
 443              }
 444  
 445              $Debuglog->add( 'Session: Session data['.$param.'] updated. Expire in: '.( $expire ? $expire.'s' : '-' ).'.', 'request' );
 446  
 447              $this->session_needs_save( true );
 448          }
 449      }
 450  
 451  
 452      /**
 453       * Delete a value from the session data.
 454       *
 455       * @param string Name of the data's key.
 456       */
 457  	function delete( $param )
 458      {
 459          global $Debuglog;
 460  
 461          if( isset($this->_data[$param]) )
 462          {
 463              unset( $this->_data[$param] );
 464  
 465              $Debuglog->add( 'Session: Session data['.$param.'] deleted!', 'request' );
 466  
 467              $this->session_needs_save( true );
 468          }
 469      }
 470  
 471  
 472      /**
 473       * Updates session data in database.
 474       *
 475       * NOTE: Debuglog additions will may not be displayed since the debuglog may alreayd have been displayed (shutdown function)
 476       */
 477  	function dbsave()
 478      {
 479          global $DB, $Debuglog, $Hit, $localtimenow;
 480  
 481          if( ! $this->_session_needs_save )
 482          {    // There have been no changes since the last save.
 483              $Debuglog->add( 'Session: Session is up to date and does not need to be saved.', 'request' );
 484              return false;
 485          }
 486  
 487          $sess_data = empty($this->_data) ? NULL : serialize($this->_data);
 488  
 489           // Note: The key actually only needs to be updated on a logout.
 490           // Note: we increase the hitcoutn every time. That assumes that there will be no 2 calls for a single hit.
 491           //       Anyway it is not a big problem if this number is approximate.
 492          $sql = "UPDATE T_sessions SET
 493                  sess_lastseen_ts = '".date( 'Y-m-d H:i:s', $localtimenow )."',
 494                  sess_data = ".$DB->quote( $sess_data ).",
 495                  sess_ipaddress = '".$Hit->IP."',
 496                  sess_key = ".$DB->quote( $this->key );
 497          if( !is_null($this->user_ID) )
 498          {    // We do NOT erase existing IDs at logout. We only want to set IDs at login:
 499                  $sql .= ", sess_user_ID = ".$this->user_ID;
 500          }
 501          $sql .= "    WHERE sess_ID = ".$this->ID;
 502  
 503          $DB->query( $sql, 'Session::dbsave()' );
 504  
 505          $Debuglog->add( 'Session: Session data saved!', 'request' );
 506  
 507          $this->session_needs_save( false );
 508      }
 509  
 510  
 511      /**
 512       * Reload session data.
 513       *
 514       * This is needed if the running process waits for a child process to write data
 515       * into the Session, e.g. the captcha plugin in test mode waiting for the Debuglog
 516       * output from the process that created the image (included through an IMG tag).
 517       */
 518  	function reload_data()
 519      {
 520          global $Debuglog, $DB;
 521  
 522          if( empty($this->ID) )
 523          {
 524              return false;
 525          }
 526  
 527          $sess_data = $DB->get_var( '
 528              SELECT SQL_NO_CACHE sess_data FROM T_sessions
 529               WHERE sess_ID = '.$this->ID );
 530  
 531          $sess_data = @unserialize( $sess_data );
 532          if( $sess_data === false )
 533          {
 534              $this->_data = array();
 535          }
 536          else
 537          {
 538              $this->_data = $sess_data;
 539          }
 540  
 541          $Debuglog->add( 'Session: Reloaded session data.' );
 542      }
 543  
 544  
 545      /**
 546       * Create a crumb that will be saved into the Session and returned to the caller for inclusion in Form or action url.
 547       *
 548       * For any action, a new crumb is generated every hour and the previous one is saved. (2 hours are valid)
 549       *
 550       * @param string crumb name
 551       * @return string crumb value
 552       */
 553  	function create_crumb( $crumb_name )
 554      {
 555          global $servertimenow, $crumb_expires;
 556  
 557          // Retrieve latest saved crumb:
 558          $crumb_recalled = $this->get( 'crumb_latest_'.$crumb_name, '-0' );
 559          list( $crumb_value, $crumb_time ) = explode( '-', $crumb_recalled );
 560  
 561          if( $servertimenow - $crumb_time > ($crumb_expires/2) )
 562          {    // The crumb we already had is older than 1 hour...
 563              // We'll need to generate a new value:
 564              $crumb_value = '';
 565              if( $servertimenow - $crumb_time < ($crumb_expires - 200) ) // Leave some margin here to make sure we do no overwrite a newer 1-2 hr crumb
 566              {    // Not too old either, save as previous crumb:
 567                  $this->set( 'crumb_prev_'.$crumb_name, $crumb_recalled );
 568              }
 569          }
 570  
 571          if( empty($crumb_value) )
 572          {    // We need to generate a new crumb:
 573              $crumb_value = generate_random_key( 32 );
 574  
 575              // Save crumb into session so we can later compare it to what get got back from the user request:
 576              $this->set( 'crumb_latest_'.$crumb_name, $crumb_value.'-'.$servertimenow );
 577          }
 578          return $crumb_value;
 579      }
 580  
 581  
 582      /**
 583       * Assert that we received a valid crumb for the object we want to act on.
 584       *
 585       * This will DIE if we have not received a valid crumb.
 586       *
 587       * The received crumb must match a crumb we previously saved less than 2 hours ago.
 588       *
 589       * @param string crumb name
 590       * @param boolean true if the script should die on error
 591       */
 592  	function assert_received_crumb( $crumb_name, $die = true )
 593      {
 594          global $servertimenow, $crumb_expires, $debug;
 595  
 596          if( ! $crumb_received = param( 'crumb_'.$crumb_name, 'string', NULL ) )
 597          { // We did not receive a crumb!
 598              if( $die )
 599              {
 600                  bad_request_die( 'Missing crumb ['.$crumb_name.'] -- It looks like this request is not legit.' );
 601              }
 602              return false;
 603          }
 604  
 605          // Retrieve latest saved crumb:
 606          $crumb_recalled = $this->get( 'crumb_latest_'.$crumb_name, '-0' );
 607          list( $crumb_value, $crumb_time ) = explode( '-', $crumb_recalled );
 608          if( $crumb_received == $crumb_value && $servertimenow - $crumb_time <= $crumb_expires )
 609          {    // Crumb is valid
 610              // echo '<p>-<p>-<p>A';
 611              return true;
 612          }
 613  
 614          $crumb_valid_latest = $crumb_value;
 615  
 616          // Retrieve previous saved crumb:
 617          $crumb_recalled = $this->get( 'crumb_prev_'.$crumb_name, '-0' );
 618          list( $crumb_value, $crumb_time ) = explode( '-', $crumb_recalled );
 619          if( $crumb_received == $crumb_value && $servertimenow - $crumb_time <= $crumb_expires )
 620          {    // Crumb is valid
 621              // echo '<p>-<p>-<p>B';
 622              return true;
 623          }
 624  
 625          if( ! $die )
 626          {
 627              return false;
 628          }
 629  
 630          // ERROR MESSAGE, with form/button to bypass and enough warning hopefully.
 631          // TODO: dh> please review carefully!
 632          echo '<div style="background-color: #fdd; padding: 1ex; margin-bottom: 1ex;">';
 633          echo '<h3 style="color:#f00;">'.T_('Incorrect crumb received!').' ['.$crumb_name.']</h3>';
 634          echo '<p>'.T_('Your request was stopped for security reasons.').'</p>';
 635          echo '<p>'.sprintf( T_('Have you waited more than %d minutes before submitting your request?'), floor($crumb_expires/60) ).'</p>';
 636          echo '<p>'.T_('Please go back to the previous page and refresh it before submitting the form again.').'</p>';
 637          echo '</div>';
 638  
 639          if( $debug > 0 )
 640          {
 641              echo '<div>';
 642              echo '<p>Received crumb:'.$crumb_received.'</p>';
 643              echo '<p>Latest saved crumb:'.$crumb_valid_latest.'</p>';
 644              echo '<p>Previous saved crumb:'.$crumb_value.'</p>';
 645              echo '</div>';
 646          }
 647  
 648          echo '<div>';
 649          echo '<p class="warning">'.T_('Alternatively, you can try to resubmit your request with a refreshed crumb:').'</p>';
 650          $Form = new Form( '', 'evo_session_crumb_resend', $_SERVER['REQUEST_METHOD'] );
 651          $Form->begin_form( 'inline' );
 652          $Form->add_crumb( $crumb_name );
 653          $Form->hiddens_by_key( remove_magic_quotes($_REQUEST) );
 654          $Form->button( array( 'submit', '', T_('Resubmit now!'), 'ActionButton' ) );
 655          $Form->end_form();
 656          echo '</div>';
 657  
 658          die();
 659      }
 660  
 661  
 662      /**
 663       * Was this session created from a mobile device
 664       */
 665  	function is_mobile_session()
 666      {
 667          global $mobile_user_devices;
 668  
 669          return array_key_exists( $this->sess_device, $mobile_user_devices );
 670      }
 671  
 672  
 673      /**
 674       * Was this session created from a mobile device
 675       */
 676  	function is_tablet_session()
 677      {
 678          global $tablet_user_devices;
 679  
 680          return array_key_exists( $this->sess_device, $tablet_user_devices );
 681      }
 682  }
 683  
 684  
 685  /**
 686   * This gets used as a {@link unserialize()} callback function, which is
 687   * responsible for loading the requested class.
 688   *
 689   * IMPORTANT: when modifying this, modify the following also:
 690   * @see session_unserialize_load_all_classes()
 691   *
 692   * @todo Once we require PHP5, we should think about using this as __autoload function.
 693   *
 694   * @return boolean True, if the required class could be loaded; false, if not
 695   */
 696  function session_unserialize_callback( $classname )
 697  {
 698      switch( strtolower($classname) )
 699      {
 700          case 'blog':
 701              load_class( 'collections/model/_blog.class.php', 'Blog' );
 702              return true;
 703  
 704          case 'collectionsettings':
 705              load_class( 'collections/model/_collsettings.class.php', 'CollectionSettings' );
 706              return true;
 707  
 708          case 'comment':
 709              load_class( 'comments/model/_comment.class.php', 'Comment' );
 710              return true;
 711  
 712          case 'item':
 713              load_class( 'items/model/_item.class.php', 'Item' );
 714              return true;
 715  
 716          case 'itemsettings':
 717              load_class( 'items/model/_itemsettings.class.php', 'ItemSettings' );
 718              return true;
 719  
 720          case 'group':
 721              load_class( 'users/model/_group.class.php', 'Group' );
 722              return true;
 723  
 724          case 'user':
 725              load_class( 'users/model/_user.class.php', 'User' );
 726              return true;
 727      }
 728  
 729      return false;
 730  }
 731  
 732  
 733  /**
 734   * When session_unserialize_callback() cannot be registered to do some smart loading,
 735   * then we fall back to this function and load everything with brute force...
 736   *
 737   * IMPORTANT: when modifying this, modify the following also:
 738   * @see session_unserialize_callback()
 739   */
 740  function session_unserialize_load_all_classes()
 741  {
 742      load_class( 'collections/model/_blog.class.php', 'Blog' );
 743      load_class( 'collections/model/_collsettings.class.php', 'CollectionSettings' );
 744      load_class( 'comments/model/_comment.class.php', 'Comment' );
 745      load_class( 'items/model/_item.class.php', 'Item' );
 746      load_class( 'items/model/_itemsettings.class.php', 'ItemSettings' );
 747      load_class( 'users/model/_group.class.php', 'Group' );
 748      load_class( 'users/model/_user.class.php', 'User' );
 749  }
 750  
 751  ?>

title

Description

title

Description

title

Description

title

title

Body