|
Moodle
2.2.1
http://www.collinsharper.com
|
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 }