ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 {
46 return;
47 }
48
49 // #9669: if a session was destroyed and somehow the session id is still
50 // in use there will be a id-collision for the raw-entry
51
52 $ilDB->replace(
53 "usr_session_stats_raw",
54 array(
55 "session_id" => array("text", $a_session_id)
56 ),
57 array(
58 "type" => array("integer", $a_session_type),
59 "start_time" => array("integer", $a_timestamp),
60 "user_id" => array("integer", $a_user_id)
61 )
62 );
63 }
64
72 public static function closeRawEntry($a_session_id, $a_context = null, $a_expired_at = null)
73 {
74 global $ilDB;
75
76 if(!self::isActive())
77 {
78 return;
79 }
80
81 // single entry
82 if(!is_array($a_session_id))
83 {
84 if($a_expired_at)
85 {
86 $end_time = $a_expired_at;
87 }
88 else
89 {
90 $end_time = time();
91 }
92 $sql = "UPDATE usr_session_stats_raw".
93 " SET end_time = ".$ilDB->quote($end_time, "integer");
94 if($a_context)
95 {
96 $sql .= ",end_context = ".$ilDB->quote($a_context, "integer");
97 }
98 $sql .= " WHERE session_id = ".$ilDB->quote($a_session_id, "text").
99 " AND end_time IS NULL";
100 $ilDB->manipulate($sql);
101 }
102 // batch closing
103 else if(!$a_expired_at)
104 {
105 $sql = "UPDATE usr_session_stats_raw".
106 " SET end_time = ".$ilDB->quote(time(), "integer");
107 if($a_context)
108 {
109 $sql .= ",end_context = ".$ilDB->quote($a_context, "integer");
110 }
111 $sql .= " WHERE ".$ilDB->in("session_id", $a_session_id, false, "text").
112 " AND end_time IS NULL";
113 $ilDB->manipulate($sql);
114 }
115 // batch with individual timestamps
116 else
117 {
118 foreach($a_session_id as $id => $ts)
119 {
120 $sql = "UPDATE usr_session_stats_raw".
121 " SET end_time = ".$ilDB->quote($ts, "integer");
122 if($a_context)
123 {
124 $sql .= ",end_context = ".$ilDB->quote($a_context, "integer");
125 }
126 $sql .= " WHERE session_id = ".$ilDB->quote($id, "text").
127 " AND end_time IS NULL";
128 $ilDB->manipulate($sql);
129 }
130 }
131 }
132
139 protected static function getCurrentSlot($a_now)
140 {
141 global $ilDB;
142
143 // get latest slot in db
144 $sql = "SELECT MAX(slot_end) previous_slot_end".
145 " FROM usr_session_stats";
146 $res = $ilDB->query($sql);
147 $row = $ilDB->fetchAssoc($res);
148 $previous_slot_end = $row["previous_slot_end"];
149
150 // no previous slot? calculate last complete slot
151 // should we use minimum session raw date instead? (problem: table lock)
152 if(!$previous_slot_end)
153 {
154 $slot = floor(date("i")/self::SLOT_SIZE);
155 // last slot of previous hour
156 if(!$slot)
157 {
158 $current_slot_begin = mktime(date("H", $a_now)-1, 60-self::SLOT_SIZE, 0);
159 }
160 // "normalize" to slot
161 else
162 {
163 $current_slot_begin = mktime(date("H", $a_now), ($slot-1)*self::SLOT_SIZE, 0);
164 }
165 }
166 else
167 {
168 $current_slot_begin = $previous_slot_end+1;
169 }
170
171 $current_slot_end = $current_slot_begin+(60*self::SLOT_SIZE)-1;
172
173 // no complete slot: nothing to do yet
174 if($current_slot_end < $a_now)
175 {
176 return array($current_slot_begin, $current_slot_end);
177 }
178 }
179
186 protected static function getNumberOfActiveRawSessions($a_time)
187 {
188 global $ilDB;
189
190 $sql = "SELECT COUNT(*) counter FROM usr_session_stats_raw".
191 " WHERE (end_time IS NULL OR end_time >= ".$ilDB->quote($a_time, "integer").")".
192 " AND start_time <= ".$ilDB->quote($a_time, "integer").
193 " AND ".$ilDB->in("type", ilSessionControl::$session_types_controlled, false, "integer");
194 $res = $ilDB->query($sql);
195 $row = $ilDB->fetchAssoc($res);
196 return $row["counter"];
197 }
198
206 protected static function getRawData($a_begin, $a_end)
207 {
208 global $ilDB;
209
210 $sql = "SELECT start_time,end_time,end_context FROM usr_session_stats_raw".
211 " WHERE start_time <= ".$ilDB->quote($a_end, "integer").
212 " AND (end_time IS NULL OR end_time >= ".$ilDB->quote($a_begin, "integer").")".
213 " AND ".$ilDB->in("type", ilSessionControl::$session_types_controlled, false, "integer").
214 " ORDER BY start_time";
215 $res = $ilDB->query($sql);
216 $all = array();
217 while($row = $ilDB->fetchAssoc($res))
218 {
219 $all[] = $row;
220 }
221 return $all;
222 }
223
230 protected static function createNewAggregationSlot($a_now)
231 {
232 global $ilDB;
233
234 $ilAtomQuery = $ilDB->buildAtomQuery();
235 $ilAtomQuery->addTableLock("usr_session_stats");
236
237 $ilAtomQuery->addQueryCallable(function(ilDBInterface $ilDB) use ($a_now, &$slot){
238
239 // if we had to wait for the lock, no current slot should be returned here
240 $slot = self::getCurrentSlot($a_now);
241 if(!is_array($slot))
242 {
243 $slot = false;
244 return;
245 }
246
247 // save slot to mark as taken
248 $fields = array(
249 "slot_begin" => array("integer", $slot[0]),
250 "slot_end" => array("integer", $slot[1]),
251 );
252 $ilDB->insert("usr_session_stats", $fields);
253
254 });
255
256 $ilAtomQuery->run();
257
258 return $slot;
259 }
260
266 public static function aggretateRaw($a_now)
267 {
268 if(!self::isActive())
269 {
270 return;
271 }
272
273 $slot = self::createNewAggregationSlot($a_now);
274 while(is_array($slot))
275 {
276 self::aggregateRawHelper($slot[0], $slot[1]);
277 $slot = self::createNewAggregationSlot($a_now);
278 }
279
280 // #12728
282 }
283
290 public static function aggregateRawHelper($a_begin, $a_end)
291 {
292 global $ilDB, $ilSetting;
293
294 // "relevant" closing types
295 $separate_closed = array(ilSession::SESSION_CLOSE_USER,
301
302 // gather/process data (build event timeline)
303 $closed_counter = $events = array();
304 $opened_counter = 0;
305 foreach(self::getRawData($a_begin, $a_end) as $item)
306 {
307 // open/close counters are _not_ time related
308
309 // we could filter for undefined/invalid closing contexts
310 // and ignore those items, but this would make any debugging
311 // close to impossible
312 // "closed_other" would have been a good idea...
313
314 // session opened
315 if($item["start_time"] >= $a_begin)
316 {
317 $opened_counter++;
318 $events[$item["start_time"]][] = 1;
319 }
320 // session closed
321 if($item["end_time"] && $item["end_time"] <= $a_end)
322 {
323 if(in_array($item["end_context"], $separate_closed))
324 {
325 $closed_counter[$item["end_context"]]++;
326 }
327 else
328 {
329 $closed_counter[0]++;
330 }
331 $events[$item["end_time"]][] = -1;
332 }
333 }
334
335 // initialising active statistical values
336 $active_begin = self::getNumberOfActiveRawSessions($a_begin-1);
337 $active_end = $active_min = $active_max = $active_avg = $active_begin;
338
339 // parsing events / building avergages
340 if(sizeof($events))
341 {
342 $last_update_avg = $a_begin-1;
343 $slot_seconds = self::SLOT_SIZE*60;
344 $active_avg = 0;
345
346 // parse all open/closing events
347 ksort($events);
348 foreach($events as $ts => $actions)
349 {
350 // actions which occur in the same second are "merged"
351 foreach($actions as $action)
352 {
353 // max
354 if($action > 0)
355 {
356 $active_end++;
357 }
358 // min
359 else
360 {
361 $active_end--;
362 }
363 }
364
365 // max
366 if($active_end > $active_max)
367 {
368 $active_max = $active_end;
369 }
370
371 // min
372 if($active_end < $active_min)
373 {
374 $active_min = $active_end;
375 }
376
377 // avg
378 $diff = $ts-$last_update_avg;
379 $active_avg += $diff/$slot_seconds*$active_end;
380 $last_update_avg = $ts;
381 }
382 unset($actions);
383
384 // add up to end of slot if needed
385 if($last_update_avg < $a_end)
386 {
387 $diff = $a_end-$last_update_avg;
388 $active_avg += $diff/$slot_seconds*$active_end;
389 }
390
391 $active_avg = round($active_avg);
392 }
393 unset($events);
394
395
396 // do we (really) need a log here?
397 // $max_sessions = (int)$ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
398 $max_sessions = self::getLimitForSlot($a_begin);
399
400 // save aggregated data
401 $fields = array(
402 "active_min" => array("integer", $active_min),
403 "active_max" => array("integer", $active_max),
404 "active_avg" => array("integer", $active_avg),
405 "active_end" => array("integer", $active_end),
406 "opened" => array("integer", $opened_counter),
407 "closed_manual" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_USER]),
408 "closed_expire" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_EXPIRE]),
409 "closed_idle" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_IDLE]),
410 "closed_idle_first" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_FIRST]),
411 "closed_limit" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_LIMIT]),
412 "closed_login" => array("integer", (int)$closed_counter[ilSession::SESSION_CLOSE_LOGIN]),
413 "closed_misc" => array("integer", (int)$closed_counter[0]),
414 "max_sessions" => array("integer", (int)$max_sessions)
415 );
416 $ilDB->update("usr_session_stats", $fields,
417 array("slot_begin" => array("integer", $a_begin),
418 "slot_end" => array("integer", $a_end)));
419 }
420
426 protected static function deleteAggregatedRaw($a_now)
427 {
428 global $ilDB;
429
430 // we are rather defensive here - 7 days BEFORE current aggregation
431 $cut = $a_now-(60*60*24*7);
432
433 $ilDB->manipulate("DELETE FROM usr_session_stats_raw".
434 " WHERE start_time <= ".$ilDB->quote($cut, "integer"));
435 }
436
442 public static function getLastMaxedOut()
443 {
444 global $ilDB;
445
446 $sql = "SELECT max(slot_end) latest FROM usr_session_stats".
447 " WHERE active_max >= max_sessions".
448 " AND max_sessions > ".$ilDB->quote(0, "integer");
449 $res = $ilDB->query($sql);
450 $row = $ilDB->fetchAssoc($res);
451 if($row["latest"])
452 {
453 return $row["latest"];
454 }
455 }
456
464 public static function getMaxedOutDuration($a_from, $a_to)
465 {
466 global $ilDB;
467
468 $sql = "SELECT SUM(slot_end-slot_begin) dur FROM usr_session_stats".
469 " WHERE active_max >= max_sessions".
470 " AND max_sessions > ".$ilDB->quote(0, "integer").
471 " AND slot_end > ".$ilDB->quote($a_from, "integer").
472 " AND slot_begin < ".$ilDB->quote($a_to, "integer");
473 $res = $ilDB->query($sql);
474 $row = $ilDB->fetchAssoc($res);
475 if($row["dur"])
476 {
477 return $row["dur"];
478 }
479 }
480
488 public static function getNumberOfSessionsByType($a_from, $a_to)
489 {
490 global $ilDB;
491
492 $sql = "SELECT SUM(opened) opened, SUM(closed_manual) closed_manual,".
493 " SUM(closed_expire) closed_expire, SUM(closed_idle) closed_idle,".
494 " SUM(closed_idle_first) closed_idle_first, SUM(closed_limit) closed_limit,".
495 " SUM(closed_login) closed_login, SUM(closed_misc) closed_misc".
496 " FROM usr_session_stats".
497 " WHERE slot_end > ".$ilDB->quote($a_from, "integer").
498 " AND slot_begin < ".$ilDB->quote($a_to, "integer");
499 $res = $ilDB->query($sql);
500 return $ilDB->fetchAssoc($res);
501 }
502
510 public static function getActiveSessions($a_from, $a_to)
511 {
512 global $ilDB;
513
514 $sql = "SELECT slot_begin, slot_end, active_min, active_max, active_avg,".
515 " max_sessions".
516 " FROM usr_session_stats".
517 " WHERE slot_end > ".$ilDB->quote($a_from, "integer").
518 " AND slot_begin < ".$ilDB->quote($a_to, "integer").
519 " ORDER BY slot_begin";
520 $res = $ilDB->query($sql);
521 $all = array();
522 while($row = $ilDB->fetchAssoc($res))
523 {
524 $all[] = $row;
525 }
526 return $all;
527 }
528
534 public static function getLastAggregation()
535 {
536 global $ilDB;
537
538 $sql = "SELECT max(slot_end) latest FROM usr_session_stats";
539 $res = $ilDB->query($sql);
540 $row = $ilDB->fetchAssoc($res);
541 if($row["latest"])
542 {
543 return $row["latest"];
544 }
545 }
546
553 public static function getLimitForSlot($a_timestamp)
554 {
555 global $ilDB, $ilSetting;
556
557 $ilDB->setLimit(1);
558 $sql = "SELECT maxval FROM usr_session_log".
559 " WHERE tstamp <= ".$ilDB->quote($a_timestamp, "integer").
560 " ORDER BY tstamp DESC";
561 $res = $ilDB->query($sql);
562 $val = $ilDB->fetchAssoc($res);
563 if($val["maxval"])
564 {
565 return (int)$val["maxval"];
566 }
567 else
568 {
569 return (int)$ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
570 }
571 }
572
578 public static function updateLimitLog($a_new_value)
579 {
580 global $ilDB, $ilSetting, $ilUser;
581
582 $new_value = (int)$a_new_value;
583 $old_value = (int)$ilSetting->get("session_max_count", ilSessionControl::DEFAULT_MAX_COUNT);
584
585 if($new_value != $old_value)
586 {
587 $fields = array(
588 "tstamp" => array("timestamp", time()),
589 "maxval" => array("integer", $new_value),
590 "user_id" => array("integer", $ilUser->getId())
591 );
592 $ilDB->insert("usr_session_log", $fields);
593 }
594 }
595}
596
597?>
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.
const SESSION_CLOSE_USER
const SESSION_CLOSE_LOGIN
const SESSION_CLOSE_FIRST
const SESSION_CLOSE_IDLE
const SESSION_CLOSE_LIMIT
const SESSION_CLOSE_EXPIRE
Interface ilDBInterface.
global $ilSetting
Definition: privfeed.php:17
global $ilDB
$ilUser
Definition: imgupload.php:18