ILIAS  release_8 Revision v8.24
class.ilSession.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
27{
35 public const SESSION_HANDLING_FIXED = 0;
36
45
51 public const SESSION_CLOSE_USER = 1; // manual logout
52 public const SESSION_CLOSE_EXPIRE = 2; // has expired
53 public const SESSION_CLOSE_FIRST = 3; // kicked by session control (first abidencer)
54 public const SESSION_CLOSE_IDLE = 4; // kickey by session control (ilde time)
55 public const SESSION_CLOSE_LIMIT = 5; // kicked by session control (limit reached)
56 public const SESSION_CLOSE_LOGIN = 6; // anonymous => login
57 public const SESSION_CLOSE_PUBLIC = 7; // => anonymous
58 public const SESSION_CLOSE_TIME = 8; // account time limit reached
59 public const SESSION_CLOSE_IP = 9; // wrong ip
60 public const SESSION_CLOSE_SIMUL = 10; // simultaneous login
61 public const SESSION_CLOSE_INACTIVE = 11; // inactive account
62
63 private static ?int $closing_context = null;
64
65 protected static bool $enable_web_access_without_session = false;
66
76 public static function _getData(string $a_session_id): string
77 {
78 if (!$a_session_id) {
79 // fix for php #70520
80 return '';
81 }
82 global $DIC;
83
84 $ilDB = $DIC['ilDB'];
85
86 $q = "SELECT data FROM usr_session WHERE session_id = " .
87 $ilDB->quote($a_session_id, "text");
88 $set = $ilDB->query($q);
89 $rec = $ilDB->fetchAssoc($set);
90 if (!is_array($rec)) {
91 return '';
92 }
93
94 // fix for php #70520
95 return (string) $rec["data"];
96 }
97
103 public static function lookupExpireTime(string $a_session_id): int
104 {
105 global $DIC;
106
107 $ilDB = $DIC['ilDB'];
108
109 $query = 'SELECT expires FROM usr_session WHERE session_id = ' .
110 $ilDB->quote($a_session_id, 'text');
111 $res = $ilDB->query($query);
112 if ($row = $res->fetchRow(ilDBConstants::FETCHMODE_OBJECT)) {
113 return (int) $row->expires;
114 }
115 return 0;
116 }
117
118 public static function _writeData(string $a_session_id, string $a_data): bool
119 {
120 global $DIC;
121
123 $ilDB = $DIC['ilDB'];
125 $ilClientIniFile = $DIC['ilClientIniFile'];
126
127 if (self::isWebAccessWithoutSessionEnabled()) {
128 // Prevent session data written for web access checker
129 // when no cookie was sent (e.g. for pdf files linking others).
130 // This would result in new session records for each request.
131 return true;
132 }
133
134 if (!$a_session_id) {
135 return true;
136 }
137
138 $now = time();
139
140 // prepare session data
141 $fields = [
142 'user_id' => [ilDBConstants::T_INTEGER, (int) (self::get('_authsession_user_id') ?? 0)],
143 'expires' => [ilDBConstants::T_INTEGER, self::getExpireValue()],
144 'data' => [ilDBConstants::T_CLOB, $a_data],
145 'ctime' => [ilDBConstants::T_INTEGER, $now],
146 'type' => [ilDBConstants::T_INTEGER, (int) (self::get('SessionType') ?? 0)]
147 ];
148 if ($ilClientIniFile->readVariable('session', 'save_ip')) {
149 $fields['remote_addr'] = [ilDBConstants::T_TEXT, $_SERVER['REMOTE_ADDR'] ?? ''];
150 }
151
152 if (self::_exists($a_session_id)) {
153 // note that we do this only when inserting the new record
154 // updating may get us other contexts for the same session, especially ilContextWAC, which we do not want
155 if (class_exists('ilContext') && ilContext::isSessionMainContext()) {
156 $fields['context'] = [ilDBConstants::T_TEXT, ilContext::getType()];
157 }
158 $ilDB->update(
159 'usr_session',
160 $fields,
161 ['session_id' => [ilDBConstants::T_TEXT, $a_session_id]]
162 );
163 } else {
164 $fields['session_id'] = [ilDBConstants::T_TEXT, $a_session_id];
165 $fields['createtime'] = [ilDBConstants::T_INTEGER, $now];
166
167 // note that we do this only when inserting the new record
168 // updating may get us other contexts for the same session, especially ilContextWAC, which we do not want
169 if (class_exists('ilContext')) {
170 $fields['context'] = [ilDBConstants::T_TEXT, ilContext::getType()];
171 }
172
173 $insert_fields = implode(', ', array_keys($fields));
174 $insert_values = implode(
175 ', ',
176 array_map(
177 static fn (string $type, $value): string => $ilDB->quote($value, $type),
178 array_column($fields, 0),
179 array_column($fields, 1)
180 )
181 );
182
183 $update_fields = array_filter(
184 $fields,
185 static fn (string $field): bool => !in_array($field, ['session_id', 'user_id', 'createtime'], true),
186 ARRAY_FILTER_USE_KEY
187 );
188 $update_values = implode(
189 ', ',
190 array_map(
191 static fn (string $field, string $type, $value): string => $field . ' = ' . $ilDB->quote(
192 $value,
193 $type
194 ),
195 array_keys($update_fields),
196 array_column($update_fields, 0),
197 array_column($update_fields, 1)
198 )
199 );
200
201 $ilDB->manipulate(
202 'INSERT INTO usr_session (' . $insert_fields . ') '
203 . 'VALUES (' . $insert_values . ') '
204 . 'ON DUPLICATE KEY UPDATE ' . $update_values
205 );
206
207 // check type against session control
208 $type = (int) $fields['type'][1];
211 $fields['session_id'][1],
212 $type,
213 $fields['createtime'][1],
214 $fields['user_id'][1]
215 );
216 }
217 }
218
219 // finally delete deprecated sessions
220 $random = new ilRandom();
221 if ($random->int(0, 50) === 2) {
222 // get time _before_ destroying expired sessions
225 }
226
227 return true;
228 }
229
230
231
238 public static function _exists(string $a_session_id): bool
239 {
240 if (!$a_session_id) {
241 return false;
242 }
243 global $DIC;
244
245 $ilDB = $DIC['ilDB'];
246
247 $q = "SELECT 1 FROM usr_session WHERE session_id = " . $ilDB->quote($a_session_id, "text");
248 $set = $ilDB->query($q);
249
250 return $ilDB->numRows($set) > 0;
251 }
252
260 public static function _destroy($a_session_id, ?int $a_closing_context = null, $a_expired_at = null): bool
261 {
262 global $DIC;
263
264 $ilDB = $DIC['ilDB'];
265
266 if (!$a_closing_context) {
267 $a_closing_context = self::$closing_context;
268 }
269
270 ilSessionStatistics::closeRawEntry($a_session_id, $a_closing_context, $a_expired_at);
271
272 if (!is_array($a_session_id)) {
273 $q = "DELETE FROM usr_session WHERE session_id = " .
274 $ilDB->quote($a_session_id, "text");
275 } else {
276 // array: id => timestamp - so we get rid of timestamps
277 if ($a_expired_at) {
278 $a_session_id = array_keys($a_session_id);
279 }
280 $q = "DELETE FROM usr_session WHERE " .
281 $ilDB->in("session_id", $a_session_id, false, "text");
282 }
283
285
286 $ilDB->manipulate($q);
287
288 try {
289 // only delete session cookie if it is set in the current request
290 if ($DIC->http()->wrapper()->cookie()->has(session_name()) &&
291 $DIC->http()->wrapper()->cookie()->retrieve(session_name(), $DIC->refinery()->kindlyTo()->string()) === $a_session_id) {
292 $cookieJar = $DIC->http()->cookieJar()->without(session_name());
293 $cookieJar->renderIntoResponseHeader($DIC->http()->response());
294 }
295 } catch (\Throwable $e) {
296 // ignore
297 // this is needed for "header already" sent errors when the random cleanup of expired sessions is triggered
298 }
299
300 return true;
301 }
302
308 public static function _destroyByUserId(int $a_user_id): bool
309 {
310 global $DIC;
311
312 $ilDB = $DIC['ilDB'];
313
314 $q = "DELETE FROM usr_session WHERE user_id = " .
315 $ilDB->quote($a_user_id, "integer");
316 $ilDB->manipulate($q);
317
318 return true;
319 }
320
325 public static function _destroyExpiredSessions(): int
326 {
327 global $DIC;
328
329 $ilDB = $DIC['ilDB'];
330
331 $q = "SELECT session_id,expires FROM usr_session WHERE expires < " .
332 $ilDB->quote(time(), "integer");
333 $res = $ilDB->query($q);
334 $ids = [];
335 while ($row = $ilDB->fetchAssoc($res)) {
336 $ids[$row["session_id"]] = $row["expires"];
337 }
338 if ($ids !== []) {
339 self::_destroy($ids, self::SESSION_CLOSE_EXPIRE, true);
340 }
341
342 return count($ids);
343 }
344
351 public static function _duplicate(string $a_session_id): string
352 {
353 global $DIC;
354
355 $ilDB = $DIC['ilDB'];
356
357 // Create new session id
358 $new_session = $a_session_id;
359 do {
360 $new_session = md5($new_session);
361 $q = "SELECT * FROM usr_session WHERE " .
362 "session_id = " . $ilDB->quote($new_session, "text");
363 $res = $ilDB->query($q);
364 } while ($ilDB->fetchAssoc($res));
365
366 $query = "SELECT * FROM usr_session " .
367 "WHERE session_id = " . $ilDB->quote($a_session_id, "text");
368 $res = $ilDB->query($query);
369
370 if ($row = $ilDB->fetchObject($res)) {
371 self::_writeData($new_session, $row->data);
372 return $new_session;
373 }
374 //TODO check if throwing an excpetion might be a better choice
375 return "";
376 }
377
387 public static function getExpireValue(bool $fixedMode = false): int
388 {
389 global $DIC;
390
391 if ($fixedMode) {
392 // fixed session
393 return time() + self::getIdleValue($fixedMode);
394 }
395
397 $ilSetting = $DIC['ilSetting'];
398 if ($ilSetting->get('session_handling_type', (string) self::SESSION_HANDLING_FIXED) === (string) self::SESSION_HANDLING_FIXED) {
399 return time() + self::getIdleValue($fixedMode);
400 }
401
402 if ($ilSetting->get('session_handling_type', (string) self::SESSION_HANDLING_FIXED) === (string) self::SESSION_HANDLING_LOAD_DEPENDENT) {
403 // load dependent session settings
404 $max_idle = (int) ($ilSetting->get('session_max_idle') ?? ilSessionControl::DEFAULT_MAX_IDLE);
405 return time() + $max_idle * 60;
406 }
407 return time() + ilSessionControl::DEFAULT_MAX_IDLE * 60;
408 }
409
417 public static function getIdleValue(bool $fixedMode = false): int
418 {
419 global $DIC;
420
421 $ilSetting = $DIC['ilSetting'];
422 $ilClientIniFile = $DIC['ilClientIniFile'];
423
424 if ($fixedMode || $ilSetting->get('session_handling_type', (string) self::SESSION_HANDLING_FIXED) === (string) self::SESSION_HANDLING_FIXED) {
425 // fixed session
426 return (int) $ilClientIniFile->readVariable('session', 'expire');
427 }
428
429 if ($ilSetting->get('session_handling_type', (string) self::SESSION_HANDLING_FIXED) === (string) self::SESSION_HANDLING_LOAD_DEPENDENT) {
430 // load dependent session settings
431 return (int) ($ilSetting->get('session_max_idle', (string) (ilSessionControl::DEFAULT_MAX_IDLE * 60)));
432 }
434 }
435
443 public static function getSessionExpireValue(): int
444 {
445 return self::getIdleValue(true);
446 }
447
451 public static function set(string $a_var, $a_val): void
452 {
453 $_SESSION[$a_var] = $a_val;
454 }
455
459 public static function get(string $a_var)
460 {
461 return $_SESSION[$a_var] ?? null;
462 }
463
464 public static function has($a_var): bool
465 {
466 return isset($_SESSION[$a_var]);
467 }
468
472 public static function clear(string $a_var): void
473 {
474 if (isset($_SESSION[$a_var])) {
475 unset($_SESSION[$a_var]);
476 }
477 }
478
479 public static function dumpToString(): string
480 {
481 return print_r($_SESSION, true);
482 }
483
487 public static function setClosingContext(int $a_context): void
488 {
489 self::$closing_context = $a_context;
490 }
491
495 public static function getClosingContext(): int
496 {
498 }
499
500
501
505 public static function isWebAccessWithoutSessionEnabled(): bool
506 {
508 }
509
514 {
515 self::$enable_web_access_without_session = $enable_web_access_without_session;
516 }
517}
static isSessionMainContext()
Context that are not only temporary in a session (e.g.
static getType()
Get context type.
Wrapper for generation of random numbers, strings, bytes.
static array $session_types_controlled
static destroySession($a_session_id)
Destroy session(s).
static closeRawEntry($a_session_id, ?int $a_context=null, $a_expired_at=null)
Close raw data entry.
static aggretateRaw(int $a_now)
Aggregate raw session data (older than given time)
static createRawEntry(string $a_session_id, int $a_session_type, int $a_timestamp, int $a_user_id)
Create raw data entry.
static _destroyByUserId(int $a_user_id)
Destroy session.
static _exists(string $a_session_id)
Check whether session exists.
static dumpToString()
const SESSION_HANDLING_LOAD_DEPENDENT
static _duplicate(string $a_session_id)
Duplicate session.
const SESSION_CLOSE_USER
const SESSION_CLOSE_IP
static int $closing_context
const SESSION_HANDLING_FIXED
static getClosingContext()
get closing context (for statistics)
static isWebAccessWithoutSessionEnabled()
static clear(string $a_var)
const SESSION_CLOSE_LOGIN
const SESSION_CLOSE_TIME
static _destroyExpiredSessions()
Destroy expired sessions.
static bool $enable_web_access_without_session
const SESSION_CLOSE_SIMUL
static setClosingContext(int $a_context)
set closing context (for statistics)
const SESSION_CLOSE_FIRST
static _destroy($a_session_id, ?int $a_closing_context=null, $a_expired_at=null)
Destroy session.
static getIdleValue(bool $fixedMode=false)
Returns the idle time in seconds.
const SESSION_CLOSE_INACTIVE
const SESSION_CLOSE_IDLE
const SESSION_CLOSE_PUBLIC
static getSessionExpireValue()
Returns the session expiration value.
static enableWebAccessWithoutSession(bool $enable_web_access_without_session)
const SESSION_CLOSE_LIMIT
static _getData(string $a_session_id)
Get session data from table.
static has($a_var)
static lookupExpireTime(string $a_session_id)
Lookup expire time for a specific session.
const SESSION_CLOSE_EXPIRE
global $DIC
Definition: feed.php:28
$res
Definition: ltiservices.php:69
get(string $key, Refinery\Transformation $t)
Get passed parameter, if not data passed, get key from http request.
global $ilSetting
Definition: privfeed.php:17
$query
$type
$_SERVER['HTTP_HOST']
Definition: raiseError.php:10