ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilSessionStatistics.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4
12{
13 const SLOT_SIZE = 15;
14
20 public static function isActive()
21 {
22 global $ilSetting;
23
24 return (bool) $ilSetting->get('session_statistics', 1);
25
26 /* #13566 - includes somehow won't work this late in the request - doing it directly
27 include_once "Services/Tracking/classes/class.ilObjUserTracking.php";
28 return ilObjUserTracking::_enabledSessionStatistics();
29 */
30 }
31
40 public static function createRawEntry($a_session_id, $a_session_type, $a_timestamp, $a_user_id)
41 {
42 global $ilDB;
43
44 if (!$a_user_id || !$a_session_id || !self::isActive()) {
45 return;
46 }
47
48 // #9669: if a session was destroyed and somehow the session id is still
49 // in use there will be a id-collision for the raw-entry
50
51 $ilDB->replace(
52 "usr_session_stats_raw",
53 array(
54 "session_id" => array("text", $a_session_id)
55 ),
56 array(
57 "type" => array("integer", $a_session_type),
58 "start_time" => array("integer", $a_timestamp),
59 "user_id" => array("integer", $a_user_id)
60 )
61 );
62 }
63
71 public static function closeRawEntry($a_session_id, $a_context = null, $a_expired_at = null)
72 {
73 global $ilDB;
74
75 if (!self::isActive()) {
76 return;
77 }
78
79 // single entry
80 if (!is_array($a_session_id)) {
81 if ($a_expired_at) {
82 $end_time = $a_expired_at;
83 } else {
84 $end_time = time();
85 }
86 $sql = "UPDATE usr_session_stats_raw" .
87 " SET end_time = " . $ilDB->quote($end_time, "integer");
88 if ($a_context) {
89 $sql .= ",end_context = " . $ilDB->quote($a_context, "integer");
90 }
91 $sql .= " WHERE session_id = " . $ilDB->quote($a_session_id, "text") .
92 " AND end_time IS NULL";
93 $ilDB->manipulate($sql);
94 }
95 // batch closing
96 elseif (!$a_expired_at) {
97 $sql = "UPDATE usr_session_stats_raw" .
98 " SET end_time = " . $ilDB->quote(time(), "integer");
99 if ($a_context) {
100 $sql .= ",end_context = " . $ilDB->quote($a_context, "integer");
101 }
102 $sql .= " WHERE " . $ilDB->in("session_id", $a_session_id, false, "text") .
103 " AND end_time IS NULL";
104 $ilDB->manipulate($sql);
105 }
106 // batch with individual timestamps
107 else {
108 foreach ($a_session_id as $id => $ts) {
109 $sql = "UPDATE usr_session_stats_raw" .
110 " SET end_time = " . $ilDB->quote($ts, "integer");
111 if ($a_context) {
112 $sql .= ",end_context = " . $ilDB->quote($a_context, "integer");
113 }
114 $sql .= " WHERE session_id = " . $ilDB->quote($id, "text") .
115 " AND end_time IS NULL";
116 $ilDB->manipulate($sql);
117 }
118 }
119 }
120
127 protected static function getCurrentSlot($a_now)
128 {
129 global $ilDB;
130
131 // get latest slot in db
132 $sql = "SELECT MAX(slot_end) previous_slot_end" .
133 " FROM usr_session_stats";
134 $res = $ilDB->query($sql);
135 $row = $ilDB->fetchAssoc($res);
136 $previous_slot_end = $row["previous_slot_end"];
137
138 // no previous slot? calculate last complete slot
139 // should we use minimum session raw date instead? (problem: table lock)
140 if (!$previous_slot_end) {
141 $slot = floor(date("i")/self::SLOT_SIZE);
142 // last slot of previous hour
143 if (!$slot) {
144 $current_slot_begin = mktime(date("H", $a_now)-1, 60-self::SLOT_SIZE, 0);
145 }
146 // "normalize" to slot
147 else {
148 $current_slot_begin = mktime(date("H", $a_now), ($slot-1)*self::SLOT_SIZE, 0);
149 }
150 } else {
151 $current_slot_begin = $previous_slot_end+1;
152 }
153
154 $current_slot_end = $current_slot_begin+(60*self::SLOT_SIZE)-1;
155
156 // no complete slot: nothing to do yet
157 if ($current_slot_end < $a_now) {
158 return array($current_slot_begin, $current_slot_end);
159 }
160 }
161
168 protected static function getNumberOfActiveRawSessions($a_time)
169 {
170 global $ilDB;
171
172 $sql = "SELECT COUNT(*) counter FROM usr_session_stats_raw" .
173 " WHERE (end_time IS NULL OR end_time >= " . $ilDB->quote($a_time, "integer") . ")" .
174 " AND start_time <= " . $ilDB->quote($a_time, "integer") .
175 " AND " . $ilDB->in("type", ilSessionControl::$session_types_controlled, false, "integer");
176 $res = $ilDB->query($sql);
177 $row = $ilDB->fetchAssoc($res);
178 return $row["counter"];
179 }
180
188 protected static function getRawData($a_begin, $a_end)
189 {
190 global $ilDB;
191
192 $sql = "SELECT start_time,end_time,end_context FROM usr_session_stats_raw" .
193 " WHERE start_time <= " . $ilDB->quote($a_end, "integer") .
194 " AND (end_time IS NULL OR end_time >= " . $ilDB->quote($a_begin, "integer") . ")" .
195 " AND " . $ilDB->in("type", ilSessionControl::$session_types_controlled, false, "integer") .
196 " ORDER BY start_time";
197 $res = $ilDB->query($sql);
198 $all = array();
199 while ($row = $ilDB->fetchAssoc($res)) {
200 $all[] = $row;
201 }
202 return $all;
203 }
204
211 protected static function createNewAggregationSlot($a_now)
212 {
213 global $ilDB;
214
215 $ilAtomQuery = $ilDB->buildAtomQuery();
216 $ilAtomQuery->addTableLock("usr_session_stats");
217
218 $ilAtomQuery->addQueryCallable(function (ilDBInterface $ilDB) use ($a_now, &$slot) {
219
220 // if we had to wait for the lock, no current slot should be returned here
221 $slot = self::getCurrentSlot($a_now);
222 if (!is_array($slot)) {
223 $slot = false;
224 return;
225 }
226
227 // save slot to mark as taken
228 $fields = array(
229 "slot_begin" => array("integer", $slot[0]),
230 "slot_end" => array("integer", $slot[1]),
231 );
232 $ilDB->insert("usr_session_stats", $fields);
233 });
234
235 $ilAtomQuery->run();
236
237 return $slot;
238 }
239
245 public static function aggretateRaw($a_now)
246 {
247 if (!self::isActive()) {
248 return;
249 }
250
251 $slot = self::createNewAggregationSlot($a_now);
252 while (is_array($slot)) {
253 self::aggregateRawHelper($slot[0], $slot[1]);
254 $slot = self::createNewAggregationSlot($a_now);
255 }
256
257 // #12728
259 }
260
267 public static function aggregateRawHelper($a_begin, $a_end)
268 {
269 global $ilDB, $ilSetting;
270
271 // "relevant" closing types
272 $separate_closed = array(ilSession::SESSION_CLOSE_USER,
278
279 // gather/process data (build event timeline)
280 $closed_counter = $events = array();
281 $opened_counter = 0;
282 foreach (self::getRawData($a_begin, $a_end) as $item) {
283 // open/close counters are _not_ time related
284
285 // we could filter for undefined/invalid closing contexts
286 // and ignore those items, but this would make any debugging
287 // close to impossible
288 // "closed_other" would have been a good idea...
289
290 // session opened
291 if ($item["start_time"] >= $a_begin) {
292 $opened_counter++;
293 $events[$item["start_time"]][] = 1;
294 }
295 // session closed
296 if ($item["end_time"] && $item["end_time"] <= $a_end) {
297 if (in_array($item["end_context"], $separate_closed)) {
298 $closed_counter[$item["end_context"]]++;
299 } else {
300 $closed_counter[0]++;
301 }
302 $events[$item["end_time"]][] = -1;
303 }
304 }
305
306 // initialising active statistical values
307 $active_begin = self::getNumberOfActiveRawSessions($a_begin-1);
308 $active_end = $active_min = $active_max = $active_avg = $active_begin;
309
310 // parsing events / building avergages
311 if (sizeof($events)) {
312 $last_update_avg = $a_begin-1;
313 $slot_seconds = self::SLOT_SIZE*60;
314 $active_avg = 0;
315
316 // parse all open/closing events
317 ksort($events);
318 foreach ($events as $ts => $actions) {
319 // actions which occur in the same second are "merged"
320 foreach ($actions as $action) {
321 // max
322 if ($action > 0) {
323 $active_end++;
324 }
325 // min
326 else {
327 $active_end--;
328 }
329 }
330
331 // max
332 if ($active_end > $active_max) {
333 $active_max = $active_end;
334 }
335
336 // min
337 if ($active_end < $active_min) {
338 $active_min = $active_end;
339 }
340
341 // avg
342 $diff = $ts-$last_update_avg;
343 $active_avg += $diff/$slot_seconds*$active_end;
344 $last_update_avg = $ts;
345 }
346 unset($actions);
347
348 // add up to end of slot if needed
349 if ($last_update_avg < $a_end) {
350 $diff = $a_end-$last_update_avg;
351 $active_avg += $diff/$slot_seconds*$active_end;
352 }
353
354 $active_avg = round($active_avg);
355 }
356 unset($events);
357
358
359 // do we (really) need a log here?
360 // $max_sessions = (int)$ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
361 $max_sessions = self::getLimitForSlot($a_begin);
362
363 // save aggregated data
364 $fields = array(
365 "active_min" => array("integer", $active_min),
366 "active_max" => array("integer", $active_max),
367 "active_avg" => array("integer", $active_avg),
368 "active_end" => array("integer", $active_end),
369 "opened" => array("integer", $opened_counter),
370 "closed_manual" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_USER]),
371 "closed_expire" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_EXPIRE]),
372 "closed_idle" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_IDLE]),
373 "closed_idle_first" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_FIRST]),
374 "closed_limit" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_LIMIT]),
375 "closed_login" => array("integer", (int) $closed_counter[ilSession::SESSION_CLOSE_LOGIN]),
376 "closed_misc" => array("integer", (int) $closed_counter[0]),
377 "max_sessions" => array("integer", (int) $max_sessions)
378 );
379 $ilDB->update(
380 "usr_session_stats",
381 $fields,
382 array("slot_begin" => array("integer", $a_begin),
383 "slot_end" => array("integer", $a_end))
384 );
385 }
386
392 protected static function deleteAggregatedRaw($a_now)
393 {
394 global $ilDB;
395
396 // we are rather defensive here - 7 days BEFORE current aggregation
397 $cut = $a_now-(60*60*24*7);
398
399 $ilDB->manipulate("DELETE FROM usr_session_stats_raw" .
400 " WHERE start_time <= " . $ilDB->quote($cut, "integer"));
401 }
402
408 public static function getLastMaxedOut()
409 {
410 global $ilDB;
411
412 $sql = "SELECT max(slot_end) latest FROM usr_session_stats" .
413 " WHERE active_max >= max_sessions" .
414 " AND max_sessions > " . $ilDB->quote(0, "integer");
415 $res = $ilDB->query($sql);
416 $row = $ilDB->fetchAssoc($res);
417 if ($row["latest"]) {
418 return $row["latest"];
419 }
420 }
421
429 public static function getMaxedOutDuration($a_from, $a_to)
430 {
431 global $ilDB;
432
433 $sql = "SELECT SUM(slot_end-slot_begin) dur FROM usr_session_stats" .
434 " WHERE active_max >= max_sessions" .
435 " AND max_sessions > " . $ilDB->quote(0, "integer") .
436 " AND slot_end > " . $ilDB->quote($a_from, "integer") .
437 " AND slot_begin < " . $ilDB->quote($a_to, "integer");
438 $res = $ilDB->query($sql);
439 $row = $ilDB->fetchAssoc($res);
440 if ($row["dur"]) {
441 return $row["dur"];
442 }
443 }
444
452 public static function getNumberOfSessionsByType($a_from, $a_to)
453 {
454 global $ilDB;
455
456 $sql = "SELECT SUM(opened) opened, SUM(closed_manual) closed_manual," .
457 " SUM(closed_expire) closed_expire, SUM(closed_idle) closed_idle," .
458 " SUM(closed_idle_first) closed_idle_first, SUM(closed_limit) closed_limit," .
459 " SUM(closed_login) closed_login, SUM(closed_misc) closed_misc" .
460 " FROM usr_session_stats" .
461 " WHERE slot_end > " . $ilDB->quote($a_from, "integer") .
462 " AND slot_begin < " . $ilDB->quote($a_to, "integer");
463 $res = $ilDB->query($sql);
464 return $ilDB->fetchAssoc($res);
465 }
466
474 public static function getActiveSessions($a_from, $a_to)
475 {
476 global $ilDB;
477
478 $sql = "SELECT slot_begin, slot_end, active_min, active_max, active_avg," .
479 " max_sessions" .
480 " FROM usr_session_stats" .
481 " WHERE slot_end > " . $ilDB->quote($a_from, "integer") .
482 " AND slot_begin < " . $ilDB->quote($a_to, "integer") .
483 " ORDER BY slot_begin";
484 $res = $ilDB->query($sql);
485 $all = array();
486 while ($row = $ilDB->fetchAssoc($res)) {
487 $all[] = $row;
488 }
489 return $all;
490 }
491
497 public static function getLastAggregation()
498 {
499 global $ilDB;
500
501 $sql = "SELECT max(slot_end) latest FROM usr_session_stats";
502 $res = $ilDB->query($sql);
503 $row = $ilDB->fetchAssoc($res);
504 if ($row["latest"]) {
505 return $row["latest"];
506 }
507 }
508
515 public static function getLimitForSlot($a_timestamp)
516 {
517 global $ilDB, $ilSetting;
518
519 $ilDB->setLimit(1);
520 $sql = "SELECT maxval FROM usr_session_log" .
521 " WHERE tstamp <= " . $ilDB->quote($a_timestamp, "integer") .
522 " ORDER BY tstamp DESC";
523 $res = $ilDB->query($sql);
524 $val = $ilDB->fetchAssoc($res);
525 if ($val["maxval"]) {
526 return (int) $val["maxval"];
527 } else {
528 return (int) $ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
529 }
530 }
531
537 public static function updateLimitLog($a_new_value)
538 {
539 global $ilDB, $ilSetting, $ilUser;
540
541 $new_value = (int) $a_new_value;
542 $old_value = (int) $ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
543
544 if ($new_value != $old_value) {
545 $fields = array(
546 "tstamp" => array("timestamp", time()),
547 "maxval" => array("integer", $new_value),
548 "user_id" => array("integer", $ilUser->getId())
549 );
550 $ilDB->insert("usr_session_log", $fields);
551 }
552 }
553}
date( 'd-M-Y', $objPHPExcel->getProperties() ->getCreated())
An exception for terminatinating execution or to throw for unit testing.
const DEFAULT_MAX_COUNT
default value for settings that have not been defined in setup or administration yet
static getActiveSessions($a_from, $a_to)
Get active sessions aggregated data.
static getLastAggregation()
Get timestamp of last aggregation.
static updateLimitLog($a_new_value)
Log max session setting.
static getMaxedOutDuration($a_from, $a_to)
Get maxed out duration in given timeframe.
static getLimitForSlot($a_timestamp)
Get max session setting for given timestamp.
static closeRawEntry($a_session_id, $a_context=null, $a_expired_at=null)
Close raw data entry.
static getCurrentSlot($a_now)
Get next slot to aggregate.
static getLastMaxedOut()
Get latest slot during which sessions were maxed out.
static aggregateRawHelper($a_begin, $a_end)
Aggregate statistics data for one slot.
static getRawData($a_begin, $a_end)
Read raw data for timespan.
static getNumberOfSessionsByType($a_from, $a_to)
Get session counters by type (opened, closed)
static deleteAggregatedRaw($a_now)
Remove already aggregated raw data.
static getNumberOfActiveRawSessions($a_time)
Count number of active sessions at given time.
static createNewAggregationSlot($a_now)
Create new slot (using table lock)
static isActive()
Is session statistics active at all?
static createRawEntry($a_session_id, $a_session_type, $a_timestamp, $a_user_id)
Create raw data entry.
static aggretateRaw($a_now)
Aggregate raw session data (older than given time)
const SESSION_CLOSE_USER
const SESSION_CLOSE_LOGIN
const SESSION_CLOSE_FIRST
const SESSION_CLOSE_IDLE
const SESSION_CLOSE_LIMIT
const SESSION_CLOSE_EXPIRE
$action
if(!array_key_exists('StateId', $_REQUEST)) $id
Interface ilDBInterface.
global $ilSetting
Definition: privfeed.php:17
foreach($_POST as $key=> $value) $res
global $ilDB
$ilUser
Definition: imgupload.php:18