Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/sessionlib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00025 defined('MOODLE_INTERNAL') || die();
00026 
00027 if (!defined('SESSION_ACQUIRE_LOCK_TIMEOUT')) {
00032     define('SESSION_ACQUIRE_LOCK_TIMEOUT', 60*2);
00033 }
00034 
00039 function session_get_instance() {
00040     global $CFG, $DB;
00041 
00042     static $session = null;
00043 
00044     if (is_null($session)) {
00045         if (empty($CFG->sessiontimeout)) {
00046             $CFG->sessiontimeout = 7200;
00047         }
00048 
00049         try {
00050             if (defined('SESSION_CUSTOM_CLASS')) {
00051                 // this is a hook for webservices, key based login, etc.
00052                 if (defined('SESSION_CUSTOM_FILE')) {
00053                     require_once($CFG->dirroot.SESSION_CUSTOM_FILE);
00054                 }
00055                 $session_class = SESSION_CUSTOM_CLASS;
00056                 $session = new $session_class();
00057 
00058             } else if ((!isset($CFG->dbsessions) or $CFG->dbsessions) and $DB->session_lock_supported()) {
00059                 // default recommended session type
00060                 $session = new database_session();
00061 
00062             } else {
00063                 // legacy limited file based storage - some features and auth plugins will not work, sorry
00064                 $session = new legacy_file_session();
00065             }
00066         } catch (Exception $ex) {
00067             // prevent repeated inits
00068             $session = new emergency_session();
00069             throw $ex;
00070         }
00071     }
00072 
00073     return $session;
00074 }
00075 
00076 
00085 interface moodle_session {
00090     public function terminate_current();
00091 
00097     public function write_close();
00098 
00104     public function session_exists($sid);
00105 }
00106 
00107 
00117 class emergency_session implements moodle_session {
00118 
00119     public function __construct() {
00120         // session not used at all
00121         $_SESSION = array();
00122         $_SESSION['SESSION'] = new stdClass();
00123         $_SESSION['USER']    = new stdClass();
00124     }
00125 
00130     public function terminate_current() {
00131         return;
00132     }
00133 
00139     public function write_close() {
00140         return;
00141     }
00142 
00148     public function session_exists($sid) {
00149         return false;
00150     }
00151 }
00152 
00153 
00162 abstract class session_stub implements moodle_session {
00163     protected $justloggedout;
00164 
00165     public function __construct() {
00166         global $CFG;
00167 
00168         if (NO_MOODLE_COOKIES) {
00169             // session not used at all
00170             $_SESSION = array();
00171             $_SESSION['SESSION'] = new stdClass();
00172             $_SESSION['USER']    = new stdClass();
00173 
00174         } else {
00175             $this->prepare_cookies();
00176             $this->init_session_storage();
00177 
00178             $newsession = empty($_COOKIE['MoodleSession'.$CFG->sessioncookie]);
00179 
00180             ini_set('session.use_trans_sid', '0');
00181 
00182             session_name('MoodleSession'.$CFG->sessioncookie);
00183             session_set_cookie_params(0, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure, $CFG->cookiehttponly);
00184             session_start();
00185             if (!isset($_SESSION['SESSION'])) {
00186                 $_SESSION['SESSION'] = new stdClass();
00187                 if (!$newsession and !$this->justloggedout) {
00188                     $_SESSION['SESSION']->has_timed_out = true;
00189                 }
00190             }
00191             if (!isset($_SESSION['USER'])) {
00192                 $_SESSION['USER'] = new stdClass();
00193             }
00194         }
00195 
00196         $this->check_user_initialised();
00197 
00198         $this->check_security();
00199     }
00200 
00205     public function terminate_current() {
00206         global $CFG, $SESSION, $USER, $DB;
00207 
00208         try {
00209             $DB->delete_records('external_tokens', array('sid'=>session_id(), 'tokentype'=>EXTERNAL_TOKEN_EMBEDDED));
00210         } catch (Exception $ignored) {
00211             // probably install/upgrade - ignore this problem
00212         }
00213 
00214         if (NO_MOODLE_COOKIES) {
00215             return;
00216         }
00217 
00218         // Initialize variable to pass-by-reference to headers_sent(&$file, &$line)
00219         $_SESSION = array();
00220         $_SESSION['SESSION'] = new stdClass();
00221         $_SESSION['USER']    = new stdClass();
00222         $_SESSION['USER']->id = 0;
00223         if (isset($CFG->mnet_localhost_id)) {
00224             $_SESSION['USER']->mnethostid = $CFG->mnet_localhost_id;
00225         }
00226         $SESSION = $_SESSION['SESSION']; // this may not work properly
00227         $USER    = $_SESSION['USER'];    // this may not work properly
00228 
00229         $file = null;
00230         $line = null;
00231         if (headers_sent($file, $line)) {
00232             error_log('Can not terminate session properly - headers were already sent in file: '.$file.' on line '.$line);
00233         }
00234 
00235         // now let's try to get a new session id and delete the old one
00236         $this->justloggedout = true;
00237         session_regenerate_id(true);
00238         $this->justloggedout = false;
00239 
00240         // write the new session
00241         session_write_close();
00242     }
00243 
00249     public function write_close() {
00250         if (NO_MOODLE_COOKIES) {
00251             return;
00252         }
00253 
00254         session_write_close();
00255     }
00256 
00263     protected function check_user_initialised() {
00264         global $CFG;
00265 
00266         if (isset($_SESSION['USER']->id)) {
00267             // already set up $USER
00268             return;
00269         }
00270 
00271         $user = null;
00272 
00273         if (!empty($CFG->opentogoogle) and !NO_MOODLE_COOKIES) {
00274             if (is_web_crawler()) {
00275                 $user = guest_user();
00276             }
00277             if (!empty($CFG->guestloginbutton) and !$user and !empty($_SERVER['HTTP_REFERER'])) {
00278                 // automaticaly log in users coming from search engine results
00279                 if (strpos($_SERVER['HTTP_REFERER'], 'google') !== false ) {
00280                     $user = guest_user();
00281                 } else if (strpos($_SERVER['HTTP_REFERER'], 'altavista') !== false ) {
00282                     $user = guest_user();
00283                 }
00284             }
00285         }
00286 
00287         if (!$user) {
00288             $user = new stdClass();
00289             $user->id = 0; // to enable proper function of $CFG->notloggedinroleid hack
00290             if (isset($CFG->mnet_localhost_id)) {
00291                 $user->mnethostid = $CFG->mnet_localhost_id;
00292             } else {
00293                 $user->mnethostid = 1;
00294             }
00295         }
00296         session_set_user($user);
00297     }
00298 
00303     protected function check_security() {
00304         global $CFG;
00305 
00306         if (NO_MOODLE_COOKIES) {
00307             return;
00308         }
00309 
00310         if (!empty($_SESSION['USER']->id) and !empty($CFG->tracksessionip)) {
00312             $remoteaddr = getremoteaddr();
00313 
00314             if (empty($_SESSION['USER']->sessionip)) {
00315                 $_SESSION['USER']->sessionip = $remoteaddr;
00316             }
00317 
00318             if ($_SESSION['USER']->sessionip != $remoteaddr) {
00319                 // this is a security feature - terminate the session in case of any doubt
00320                 $this->terminate_current();
00321                 print_error('sessionipnomatch2', 'error');
00322             }
00323         }
00324     }
00325 
00329     protected function prepare_cookies() {
00330         global $CFG;
00331 
00332         if (!isset($CFG->cookiesecure) or (strpos($CFG->wwwroot, 'https://') !== 0 and empty($CFG->sslproxy))) {
00333             $CFG->cookiesecure = 0;
00334         }
00335 
00336         if (!isset($CFG->cookiehttponly)) {
00337             $CFG->cookiehttponly = 0;
00338         }
00339 
00341         if (!isset($CFG->sessioncookie)) {
00342             $CFG->sessioncookie = '';
00343         }
00344 
00345         // make sure cookie domain makes sense for this wwwroot
00346         if (!isset($CFG->sessioncookiedomain)) {
00347             $CFG->sessioncookiedomain = '';
00348         } else if ($CFG->sessioncookiedomain !== '') {
00349             $host = parse_url($CFG->wwwroot, PHP_URL_HOST);
00350             if ($CFG->sessioncookiedomain !== $host) {
00351                 if (substr($CFG->sessioncookiedomain, 0, 1) === '.') {
00352                     if (!preg_match('|^.*'.preg_quote($CFG->sessioncookiedomain, '|').'$|', $host)) {
00353                         // invalid domain - it must be end part of host
00354                         $CFG->sessioncookiedomain = '';
00355                     }
00356                 } else {
00357                     if (!preg_match('|^.*\.'.preg_quote($CFG->sessioncookiedomain, '|').'$|', $host)) {
00358                         // invalid domain - it must be end part of host
00359                         $CFG->sessioncookiedomain = '';
00360                     }
00361                 }
00362             }
00363         }
00364 
00365         // make sure the cookiepath is valid for this wwwroot or autodetect if not specified
00366         if (!isset($CFG->sessioncookiepath)) {
00367             $CFG->sessioncookiepath = '';
00368         }
00369         if ($CFG->sessioncookiepath !== '/') {
00370             $path = parse_url($CFG->wwwroot, PHP_URL_PATH).'/';
00371             if ($CFG->sessioncookiepath === '') {
00372                 $CFG->sessioncookiepath = $path;
00373             } else {
00374                 if (strpos($path, $CFG->sessioncookiepath) !== 0 or substr($CFG->sessioncookiepath, -1) !== '/') {
00375                     $CFG->sessioncookiepath = $path;
00376                 }
00377             }
00378         }
00379 
00380         //discard session ID from POST, GET and globals to tighten security,
00381         //this is session fixation prevention
00382         unset(${'MoodleSession'.$CFG->sessioncookie});
00383         unset($_GET['MoodleSession'.$CFG->sessioncookie]);
00384         unset($_POST['MoodleSession'.$CFG->sessioncookie]);
00385         unset($_REQUEST['MoodleSession'.$CFG->sessioncookie]);
00386 
00387         //compatibility hack for Moodle Cron, cookies not deleted, but set to "deleted" - should not be needed with NO_MOODLE_COOKIES in cron.php now
00388         if (!empty($_COOKIE['MoodleSession'.$CFG->sessioncookie]) && $_COOKIE['MoodleSession'.$CFG->sessioncookie] == "deleted") {
00389             unset($_COOKIE['MoodleSession'.$CFG->sessioncookie]);
00390         }
00391     }
00392 
00396     protected abstract function init_session_storage();
00397 }
00398 
00399 
00408 class legacy_file_session extends session_stub {
00412     protected function init_session_storage() {
00413         global $CFG;
00414 
00415         ini_set('session.save_handler', 'files');
00416 
00417         // Some distros disable GC by setting probability to 0
00418         // overriding the PHP default of 1
00419         // (gc_probability is divided by gc_divisor, which defaults to 1000)
00420         if (ini_get('session.gc_probability') == 0) {
00421             ini_set('session.gc_probability', 1);
00422         }
00423 
00424         ini_set('session.gc_maxlifetime', $CFG->sessiontimeout);
00425 
00426         // make sure sessions dir exists and is writable, throws exception if not
00427         make_upload_directory('sessions');
00428 
00429         // Need to disable debugging since disk_free_space()
00430         // will fail on very large partitions (see MDL-19222)
00431         $freespace = @disk_free_space($CFG->dataroot.'/sessions');
00432         if (!($freespace > 2048) and $freespace !== false) {
00433             print_error('sessiondiskfull', 'error');
00434         }
00435         ini_set('session.save_path', $CFG->dataroot .'/sessions');
00436     }
00442     public function session_exists($sid){
00443         global $CFG;
00444 
00445         $sid = clean_param($sid, PARAM_FILE);
00446         $sessionfile = "$CFG->dataroot/sessions/sess_$sid";
00447         return file_exists($sessionfile);
00448     }
00449 }
00450 
00451 
00460 class database_session extends session_stub {
00462     protected $record   = null;
00463 
00465     protected $database = null;
00466 
00468     protected $failed   = false;
00469 
00470     public function __construct() {
00471         global $DB;
00472         $this->database = $DB;
00473         parent::__construct();
00474 
00475         if (!empty($this->record->state)) {
00476             // something is very wrong
00477             session_kill($this->record->sid);
00478 
00479             if ($this->record->state == 9) {
00480                 print_error('dbsessionmysqlpacketsize', 'error');
00481             }
00482         }
00483     }
00484 
00490     public function session_exists($sid){
00491         global $CFG;
00492         try {
00493             $sql = "SELECT * FROM {sessions} WHERE timemodified < ? AND sid=? AND state=?";
00494             $params = array(time() + $CFG->sessiontimeout, $sid, 0);
00495 
00496             return $this->database->record_exists_sql($sql, $params);
00497         } catch (dml_exception $ex) {
00498             error_log('Error checking existance of database session');
00499             return false;
00500         }
00501     }
00502 
00506     protected function init_session_storage() {
00507         global $CFG;
00508 
00509         // gc only from CRON - individual user timeouts now checked during each access
00510         ini_set('session.gc_probability', 0);
00511 
00512         ini_set('session.gc_maxlifetime', $CFG->sessiontimeout);
00513 
00514         $result = session_set_save_handler(array($this, 'handler_open'),
00515                                            array($this, 'handler_close'),
00516                                            array($this, 'handler_read'),
00517                                            array($this, 'handler_write'),
00518                                            array($this, 'handler_destroy'),
00519                                            array($this, 'handler_gc'));
00520         if (!$result) {
00521             print_error('dbsessionhandlerproblem', 'error');
00522         }
00523     }
00524 
00534     public function handler_open($save_path, $session_name) {
00535         return true;
00536     }
00537 
00545     public function handler_close() {
00546         if (isset($this->record->id)) {
00547             try {
00548                 $this->database->release_session_lock($this->record->id);
00549             } catch (Exception $ex) {
00550                 // ignore any problems
00551             }
00552         }
00553         $this->record = null;
00554         return true;
00555     }
00556 
00565     public function handler_read($sid) {
00566         global $CFG;
00567 
00568         if ($this->record and $this->record->sid != $sid) {
00569             error_log('Weird error reading database session - mismatched sid');
00570             $this->failed = true;
00571             return '';
00572         }
00573 
00574         try {
00575             if (!$record = $this->database->get_record('sessions', array('sid'=>$sid))) {
00576                 $record = new stdClass();
00577                 $record->state        = 0;
00578                 $record->sid          = $sid;
00579                 $record->sessdata     = null;
00580                 $record->userid       = 0;
00581                 $record->timecreated  = $record->timemodified = time();
00582                 $record->firstip      = $record->lastip = getremoteaddr();
00583                 $record->id           = $this->database->insert_record_raw('sessions', $record);
00584             }
00585         } catch (Exception $ex) {
00586             // do not rethrow exceptions here, we need this to work somehow before 1.9.x upgrade and during install
00587             error_log('Can not read or insert database sessions');
00588             $this->failed = true;
00589             return '';
00590         }
00591 
00592         try {
00593             $this->database->get_session_lock($record->id, SESSION_ACQUIRE_LOCK_TIMEOUT);
00594         } catch (Exception $ex) {
00595             // This is a fatal error, better inform users.
00596             // It should not happen very often - all pages that need long time to execute
00597             // should close session soon after access control checks
00598             error_log('Can not obtain session lock');
00599             $this->failed = true;
00600             throw $ex;
00601         }
00602 
00603         // verify timeout
00604         if ($record->timemodified + $CFG->sessiontimeout < time()) {
00605             $ignoretimeout = false;
00606             if (!empty($record->userid)) { // skips not logged in
00607                 if ($user = $this->database->get_record('user', array('id'=>$record->userid))) {
00608                     if (!isguestuser($user)) {
00609                         $authsequence = get_enabled_auth_plugins(); // auths, in sequence
00610                         foreach($authsequence as $authname) {
00611                             $authplugin = get_auth_plugin($authname);
00612                             if ($authplugin->ignore_timeout_hook($user, $record->sid, $record->timecreated, $record->timemodified)) {
00613                                 $ignoretimeout = true;
00614                                 break;
00615                             }
00616                         }
00617                     }
00618                 }
00619             }
00620             if ($ignoretimeout) {
00621                 //refresh session
00622                 $record->timemodified = time();
00623                 try {
00624                     $this->database->update_record('sessions', $record);
00625                 } catch (Exception $ex) {
00626                     // very unlikely error
00627                     error_log('Can not refresh database session');
00628                     $this->failed = true;
00629                     throw $ex;
00630                 }
00631             } else {
00632                 //time out session
00633                 $record->state        = 0;
00634                 $record->sessdata     = null;
00635                 $record->userid       = 0;
00636                 $record->timecreated  = $record->timemodified = time();
00637                 $record->firstip      = $record->lastip = getremoteaddr();
00638                 try {
00639                     $this->database->update_record('sessions', $record);
00640                 } catch (Exception $ex) {
00641                     // very unlikely error
00642                     error_log('Can not time out database session');
00643                     $this->failed = true;
00644                     throw $ex;
00645                 }
00646             }
00647         }
00648 
00649         $data = is_null($record->sessdata) ? '' : base64_decode($record->sessdata);
00650 
00651         unset($record->sessdata); // conserve memory
00652         $this->record = $record;
00653 
00654         return $data;
00655     }
00656 
00669     public function handler_write($sid, $session_data) {
00670         global $USER;
00671 
00672         // TODO: MDL-20625 we need to rollback all active transactions and log error if any open needed
00673 
00674         if ($this->failed) {
00675             // do not write anything back - we failed to start the session properly
00676             return false;
00677         }
00678 
00679         $userid = 0;
00680         if (!empty($USER->realuser)) {
00681             $userid = $USER->realuser;
00682         } else if (!empty($USER->id)) {
00683             $userid = $USER->id;
00684         }
00685 
00686         if (isset($this->record->id)) {
00687             $record = new stdClass();
00688             $record->state              = 0;
00689             $record->sid                = $sid;                         // might be regenerating sid
00690             $this->record->sessdata     = base64_encode($session_data); // there might be some binary mess :-(
00691             $this->record->userid       = $userid;
00692             $this->record->timemodified = time();
00693             $this->record->lastip       = getremoteaddr();
00694 
00695             // TODO: verify session changed before doing update,
00696             //       also make sure the timemodified field is changed only every 10s if nothing else changes  MDL-20462
00697 
00698             try {
00699                 $this->database->update_record_raw('sessions', $this->record);
00700             } catch (dml_exception $ex) {
00701                 if ($this->database->get_dbfamily() === 'mysql') {
00702                     try {
00703                         $this->database->set_field('sessions', 'state', 9, array('id'=>$this->record->id));
00704                     } catch (Exception $ignored) {
00705                     }
00706                     error_log('Can not write database session - please verify max_allowed_packet is at least 4M!');
00707                 } else {
00708                     error_log('Can not write database session');
00709                 }
00710                 return false;
00711             } catch (Exception $ex) {
00712                 error_log('Can not write database session');
00713                 return false;
00714             }
00715 
00716         } else {
00717             // fresh new session
00718             try {
00719                 $record = new stdClass();
00720                 $record->state        = 0;
00721                 $record->sid          = $sid;
00722                 $record->sessdata     = base64_encode($session_data); // there might be some binary mess :-(
00723                 $record->userid       = $userid;
00724                 $record->timecreated  = $record->timemodified = time();
00725                 $record->firstip      = $record->lastip = getremoteaddr();
00726                 $record->id           = $this->database->insert_record_raw('sessions', $record);
00727                 $this->record = $record;
00728 
00729                 $this->database->get_session_lock($this->record->id, SESSION_ACQUIRE_LOCK_TIMEOUT);
00730             } catch (Exception $ex) {
00731                 // this should not happen
00732                 error_log('Can not write new database session or acquire session lock');
00733                 $this->failed = true;
00734                 return false;
00735             }
00736         }
00737 
00738         return true;
00739     }
00740 
00749     public function handler_destroy($sid) {
00750         session_kill($sid);
00751 
00752         if (isset($this->record->id) and $this->record->sid === $sid) {
00753             try {
00754                 $this->database->release_session_lock($this->record->id);
00755             } catch (Exception $ex) {
00756                 // ignore problems
00757             }
00758             $this->record = null;
00759         }
00760 
00761         return true;
00762     }
00763 
00772     public function handler_gc($ignored_maxlifetime) {
00773         session_gc();
00774         return true;
00775     }
00776 }
00777 
00778 
00783 function session_is_legacy() {
00784     global $CFG, $DB;
00785     return ((isset($CFG->dbsessions) and !$CFG->dbsessions) or !$DB->session_lock_supported());
00786 }
00787 
00792 function session_kill_all() {
00793     global $CFG, $DB;
00794 
00795     // always check db table - custom session classes use sessions table
00796     try {
00797         $DB->delete_records('sessions');
00798     } catch (dml_exception $ignored) {
00799         // do not show any warnings - might be during upgrade/installation
00800     }
00801 
00802     if (session_is_legacy()) {
00803         $sessiondir = "$CFG->dataroot/sessions";
00804         if (is_dir($sessiondir)) {
00805             foreach (glob("$sessiondir/sess_*") as $filename) {
00806                 @unlink($filename);
00807             }
00808         }
00809     }
00810 }
00811 
00816 function session_touch($sid) {
00817     global $CFG, $DB;
00818 
00819     // always check db table - custom session classes use sessions table
00820     try {
00821         $sql = "UPDATE {sessions} SET timemodified=? WHERE sid=?";
00822         $params = array(time(), $sid);
00823         $DB->execute($sql, $params);
00824     } catch (dml_exception $ignored) {
00825         // do not show any warnings - might be during upgrade/installation
00826     }
00827 
00828     if (session_is_legacy()) {
00829         $sid = clean_param($sid, PARAM_FILE);
00830         $sessionfile = clean_param("$CFG->dataroot/sessions/sess_$sid", PARAM_FILE);
00831         if (file_exists($sessionfile)) {
00832             // if the file is locked it means that it will be updated anyway
00833             @touch($sessionfile);
00834         }
00835     }
00836 }
00837 
00843 function session_kill($sid) {
00844     global $CFG, $DB;
00845 
00846     // always check db table - custom session classes use sessions table
00847     try {
00848         $DB->delete_records('sessions', array('sid'=>$sid));
00849     } catch (dml_exception $ignored) {
00850         // do not show any warnings - might be during upgrade/installation
00851     }
00852 
00853     if (session_is_legacy()) {
00854         $sid = clean_param($sid, PARAM_FILE);
00855         $sessionfile = "$CFG->dataroot/sessions/sess_$sid";
00856         if (file_exists($sessionfile)) {
00857             @unlink($sessionfile);
00858         }
00859     }
00860 }
00861 
00868 function session_kill_user($userid) {
00869     global $CFG, $DB;
00870 
00871     // always check db table - custom session classes use sessions table
00872     try {
00873         $DB->delete_records('sessions', array('userid'=>$userid));
00874     } catch (dml_exception $ignored) {
00875         // do not show any warnings - might be during upgrade/installation
00876     }
00877 
00878     if (session_is_legacy()) {
00879         // log error?
00880     }
00881 }
00882 
00891 function session_gc() {
00892     global $CFG, $DB;
00893 
00894     $maxlifetime = $CFG->sessiontimeout;
00895 
00896     try {
00898         $DB->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE deleted <> 0)");
00899 
00901         $auth_sequence = get_enabled_auth_plugins(true);
00902         $auth_sequence = array_flip($auth_sequence);
00903         unset($auth_sequence['nologin']); // no login allowed
00904         $auth_sequence = array_flip($auth_sequence);
00905         $notplugins = null;
00906         list($notplugins, $params) = $DB->get_in_or_equal($auth_sequence, SQL_PARAMS_QM, '', false);
00907         $DB->delete_records_select('sessions', "userid IN (SELECT id FROM {user} WHERE auth $notplugins)", $params);
00908 
00910         $sql = "SELECT u.*, s.sid, s.timecreated AS s_timecreated, s.timemodified AS s_timemodified
00911                   FROM {user} u
00912                   JOIN {sessions} s ON s.userid = u.id
00913                  WHERE s.timemodified + ? < ? AND u.id <> ?";
00914         $params = array($maxlifetime, time(), $CFG->siteguest);
00915 
00916         $authplugins = array();
00917         foreach($auth_sequence as $authname) {
00918             $authplugins[$authname] = get_auth_plugin($authname);
00919         }
00920         $rs = $DB->get_recordset_sql($sql, $params);
00921         foreach ($rs as $user) {
00922             foreach ($authplugins as $authplugin) {
00923                 if ($authplugin->ignore_timeout_hook($user, $user->sid, $user->s_timecreated, $user->s_timemodified)) {
00924                     continue;
00925                 }
00926             }
00927             $DB->delete_records('sessions', array('sid'=>$user->sid));
00928         }
00929         $rs->close();
00930 
00931         $purgebefore = time() - $maxlifetime;
00932         // delete expired sessions for guest user account
00933         $DB->delete_records_select('sessions', 'userid = ? AND timemodified < ?', array($CFG->siteguest, $purgebefore));
00934         // delete expired sessions for userid = 0 (not logged in)
00935         $DB->delete_records_select('sessions', 'userid = 0 AND timemodified < ?', array($purgebefore));
00936     } catch (dml_exception $ex) {
00937         error_log('Error gc-ing sessions');
00938     }
00939 }
00940 
00949 function sesskey() {
00950     // note: do not use $USER because it may not be initialised yet
00951     if (empty($_SESSION['USER']->sesskey)) {
00952         $_SESSION['USER']->sesskey = random_string(10);
00953     }
00954 
00955     return $_SESSION['USER']->sesskey;
00956 }
00957 
00958 
00972 function confirm_sesskey($sesskey=NULL) {
00973     global $USER;
00974 
00975     if (!empty($USER->ignoresesskey)) {
00976         return true;
00977     }
00978 
00979     if (empty($sesskey)) {
00980         $sesskey = required_param('sesskey', PARAM_RAW);  // Check script parameters
00981     }
00982 
00983     return (sesskey() === $sesskey);
00984 }
00985 
00990 function require_sesskey() {
00991     if (!confirm_sesskey()) {
00992         print_error('invalidsesskey');
00993     }
00994 }
00995 
01002 function set_moodle_cookie($username) {
01003     global $CFG;
01004 
01005     if (NO_MOODLE_COOKIES) {
01006         return;
01007     }
01008 
01009     if (empty($CFG->rememberusername)) {
01010         // erase current and do not store permanent cookies
01011         $username = '';
01012     }
01013 
01014     if ($username === 'guest') {
01015         // keep previous cookie in case of guest account login
01016         return;
01017     }
01018 
01019     $cookiename = 'MOODLEID_'.$CFG->sessioncookie;
01020 
01021     // delete old cookie
01022     setcookie($cookiename, '', time() - HOURSECS, $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure, $CFG->cookiehttponly);
01023 
01024     if ($username !== '') {
01025         // set username cookie for 60 days
01026         setcookie($cookiename, rc4encrypt($username), time()+(DAYSECS*60), $CFG->sessioncookiepath, $CFG->sessioncookiedomain, $CFG->cookiesecure, $CFG->cookiehttponly);
01027     }
01028 }
01029 
01035 function get_moodle_cookie() {
01036     global $CFG;
01037 
01038     if (NO_MOODLE_COOKIES) {
01039         return '';
01040     }
01041 
01042     if (empty($CFG->rememberusername)) {
01043         return '';
01044     }
01045 
01046     $cookiename = 'MOODLEID_'.$CFG->sessioncookie;
01047 
01048     if (empty($_COOKIE[$cookiename])) {
01049         return '';
01050     } else {
01051         $username = rc4decrypt($_COOKIE[$cookiename]);
01052         if ($username === 'guest' or $username === 'nobody') {
01053             // backwards compatibility - we do not set these cookies any more
01054             return '';
01055         }
01056         return $username;
01057     }
01058 }
01059 
01060 
01069 function session_set_user($user) {
01070     $_SESSION['USER'] = $user;
01071     unset($_SESSION['USER']->description); // conserve memory
01072     sesskey(); // init session key
01073 }
01074 
01079 function session_is_loggedinas() {
01080     return !empty($_SESSION['USER']->realuser);
01081 }
01082 
01087 function session_get_realuser() {
01088     if (session_is_loggedinas()) {
01089         return $_SESSION['REALUSER'];
01090     } else {
01091         return $_SESSION['USER'];
01092     }
01093 }
01094 
01101 function session_loginas($userid, $context) {
01102     if (session_is_loggedinas()) {
01103         return;
01104     }
01105 
01106     // switch to fresh new $SESSION
01107     $_SESSION['REALSESSION'] = $_SESSION['SESSION'];
01108     $_SESSION['SESSION']     = new stdClass();
01109 
01111     $_SESSION['REALUSER'] = $_SESSION['USER'];
01112     $user = get_complete_user_data('id', $userid);
01113     $user->realuser       = $_SESSION['REALUSER']->id;
01114     $user->loginascontext = $context;
01115 
01116     // let enrol plugins deal with new enrolments if necessary
01117     enrol_check_plugins($user);
01118     // set up global $USER
01119     session_set_user($user);
01120 }
01121 
01130 function cron_setup_user($user = NULL, $course = NULL) {
01131     global $CFG, $SITE, $PAGE;
01132 
01133     static $cronuser    = NULL;
01134     static $cronsession = NULL;
01135 
01136     if (empty($cronuser)) {
01138         $cronuser = get_admin();
01139         $cronuser->timezone = $CFG->timezone;
01140         $cronuser->lang     = '';
01141         $cronuser->theme    = '';
01142         unset($cronuser->description);
01143 
01144         $cronsession = new stdClass();
01145     }
01146 
01147     if (!$user) {
01148         // cached default cron user (==modified admin for now)
01149         session_set_user($cronuser);
01150         $_SESSION['SESSION'] = $cronsession;
01151 
01152     } else {
01153         // emulate real user session - needed for caps in cron
01154         if ($_SESSION['USER']->id != $user->id) {
01155             session_set_user($user);
01156             $_SESSION['SESSION'] = new stdClass();
01157         }
01158     }
01159 
01160     // TODO MDL-19774 relying on global $PAGE in cron is a bad idea.
01161     // Temporary hack so that cron does not give fatal errors.
01162     $PAGE = new moodle_page();
01163     if ($course) {
01164         $PAGE->set_course($course);
01165     } else {
01166         $PAGE->set_course($SITE);
01167     }
01168 
01169     // TODO: it should be possible to improve perf by caching some limited number of users here ;-)
01170 
01171 }
 All Data Structures Namespaces Files Functions Variables Enumerations