statistics.lib.php 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945
  1. <?php
  2. /* For licensing terms, see /license.txt */
  3. /**
  4. * This class provides some functions for statistics
  5. * @package chamilo.statistics
  6. */
  7. class Statistics
  8. {
  9. /**
  10. * Converts a number of bytes in a formatted string
  11. * @param int $size
  12. * @return string Formatted file size
  13. */
  14. public static function makeSizeString($size)
  15. {
  16. if ($size < pow(2, 10)) {
  17. return $size." bytes";
  18. }
  19. if ($size >= pow(2, 10) && $size < pow(2, 20)) {
  20. return round($size / pow(2, 10), 0)." KB";
  21. }
  22. if ($size >= pow(2, 20) && $size < pow(2, 30)) {
  23. return round($size / pow(2, 20), 1)." MB";
  24. }
  25. if ($size > pow(2, 30)) {
  26. return round($size / pow(2, 30), 2)." GB";
  27. }
  28. }
  29. /**
  30. * Count courses
  31. * @param string $categoryCode Code of a course category. Default: count all courses.
  32. * @return int Number of courses counted
  33. */
  34. public static function countCourses($categoryCode = null)
  35. {
  36. $course_table = Database :: get_main_table(TABLE_MAIN_COURSE);
  37. $access_url_rel_course_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  38. $current_url_id = api_get_current_access_url_id();
  39. if (api_is_multiple_url_enabled()) {
  40. $sql = "SELECT COUNT(*) AS number
  41. FROM ".$course_table." as c, ".$access_url_rel_course_table." as u
  42. WHERE u.c_id = c.id AND access_url_id='".$current_url_id."'";
  43. if (isset ($categoryCode)) {
  44. $sql .= " AND category_code = '".Database::escape_string($categoryCode)."'";
  45. }
  46. } else {
  47. $sql = "SELECT COUNT(*) AS number
  48. FROM ".$course_table." ";
  49. if (isset ($categoryCode)) {
  50. $sql .= " WHERE category_code = '".Database::escape_string($categoryCode)."'";
  51. }
  52. }
  53. $res = Database::query($sql);
  54. $obj = Database::fetch_object($res);
  55. return $obj->number;
  56. }
  57. /**
  58. * Count courses by visibility
  59. * @param int $visibility Visibility (0 = closed, 1 = private, 2 = open, 3 = public) all courses.
  60. * @return int Number of courses counted
  61. */
  62. public static function countCoursesByVisibility($visibility = null)
  63. {
  64. if (!isset($visibility)) {
  65. return 0;
  66. }
  67. $course_table = Database :: get_main_table(TABLE_MAIN_COURSE);
  68. $access_url_rel_course_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  69. $current_url_id = api_get_current_access_url_id();
  70. if (api_is_multiple_url_enabled()) {
  71. $sql = "SELECT COUNT(*) AS number
  72. FROM ".$course_table." as c, ".$access_url_rel_course_table." as u
  73. WHERE u.c_id = c.id AND access_url_id='".$current_url_id."'";
  74. if (isset ($visibility)) {
  75. $sql .= " AND visibility = ".intval($visibility);
  76. }
  77. } else {
  78. $sql = "SELECT COUNT(*) AS number FROM ".$course_table." ";
  79. if (isset ($visibility)) {
  80. $sql .= " WHERE visibility = ".intval($visibility);
  81. }
  82. }
  83. $res = Database::query($sql);
  84. $obj = Database::fetch_object($res);
  85. return $obj->number;
  86. }
  87. /**
  88. * Count users
  89. * @param int $status Optional user status (COURSEMANAGER or STUDENT), if it's not setted it'll count all users.
  90. * @param string $categoryCode Optional, code of a course category. Default: count only users without filtering category
  91. * @param bool $countInvisibleCourses Count invisible courses (todo)
  92. * @param bool $onlyActive Count only active users (false to only return currently active users)
  93. * @return int Number of users counted
  94. */
  95. public static function countUsers($status = null, $categoryCode = null, $countInvisibleCourses = true, $onlyActive = false)
  96. {
  97. // Database table definitions
  98. $course_user_table = Database:: get_main_table(TABLE_MAIN_COURSE_USER);
  99. $course_table = Database:: get_main_table(TABLE_MAIN_COURSE);
  100. $user_table = Database:: get_main_table(TABLE_MAIN_USER);
  101. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  102. $current_url_id = api_get_current_access_url_id();
  103. $active_filter = $onlyActive?' AND active=1':'';
  104. $status_filter = isset($status)?' AND status = '.intval($status):'';
  105. if (api_is_multiple_url_enabled()) {
  106. $sql = "SELECT COUNT(DISTINCT(u.user_id)) AS number
  107. FROM $user_table as u, $access_url_rel_user_table as url
  108. WHERE
  109. u.user_id = url.user_id AND
  110. access_url_id = '".$current_url_id."'
  111. $status_filter $active_filter";
  112. if (isset ($categoryCode)) {
  113. $sql = "SELECT COUNT(DISTINCT(cu.user_id)) AS number
  114. FROM $course_user_table cu, $course_table c, $access_url_rel_user_table as url
  115. WHERE
  116. c.id = cu.c_id AND
  117. c.category_code = '".Database::escape_string($categoryCode)."' AND
  118. cu.user_id = url.user_id AND
  119. access_url_id='".$current_url_id."'
  120. $status_filter $active_filter";
  121. }
  122. } else {
  123. $sql = "SELECT COUNT(DISTINCT(user_id)) AS number
  124. FROM $user_table
  125. WHERE 1=1 $status_filter $active_filter";
  126. if (isset ($categoryCode)) {
  127. $status_filter = isset($status)?' AND status = '.intval($status):'';
  128. $sql = "SELECT COUNT(DISTINCT(cu.user_id)) AS number
  129. FROM $course_user_table cu, $course_table c
  130. WHERE
  131. c.id = cu.c_id AND
  132. c.category_code = '".Database::escape_string($categoryCode)."'
  133. $status_filter
  134. $active_filter
  135. ";
  136. }
  137. }
  138. $res = Database::query($sql);
  139. $obj = Database::fetch_object($res);
  140. return $obj->number;
  141. }
  142. /**
  143. * Count sessions
  144. * @return int Number of sessions counted
  145. */
  146. public static function countSessions()
  147. {
  148. $session_table = Database :: get_main_table(TABLE_MAIN_SESSION);
  149. $access_url_rel_session_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_SESSION);
  150. if (api_is_multiple_url_enabled()) {
  151. $current_url_id = api_get_current_access_url_id();
  152. $sql = "SELECT COUNT(id) AS number
  153. FROM ".$session_table." as s, ".$access_url_rel_session_table." as u
  154. WHERE u.session_id=s.id AND access_url_id='".$current_url_id."'";
  155. } else {
  156. $sql = "SELECT COUNT(id) AS number
  157. FROM ".$session_table." ";
  158. }
  159. $res = Database::query($sql);
  160. $obj = Database::fetch_object($res);
  161. return $obj->number;
  162. }
  163. /**
  164. * Count activities from track_e_default_table
  165. * @return int Number of activities counted
  166. */
  167. public static function getNumberOfActivities()
  168. {
  169. // Database table definitions
  170. $track_e_default = Database :: get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
  171. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  172. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  173. $current_url_id = api_get_current_access_url_id();
  174. if (api_is_multiple_url_enabled()) {
  175. $sql = "SELECT count(default_id) AS total_number_of_items
  176. FROM $track_e_default, $table_user user, $access_url_rel_user_table url
  177. WHERE
  178. default_user_id = user.user_id AND
  179. user.user_id=url.user_id AND
  180. access_url_id='".$current_url_id."'";
  181. } else {
  182. $sql = "SELECT count(default_id) AS total_number_of_items
  183. FROM $track_e_default, $table_user user
  184. WHERE default_user_id = user.user_id ";
  185. }
  186. if (isset($_GET['keyword'])) {
  187. $keyword = Database::escape_string(trim($_GET['keyword']));
  188. $sql .= " AND (user.username LIKE '%".$keyword."%' OR default_event_type LIKE '%".$keyword."%' OR default_value_type LIKE '%".$keyword."%' OR default_value LIKE '%".$keyword."%') ";
  189. }
  190. $res = Database::query($sql);
  191. $obj = Database::fetch_object($res);
  192. return $obj->total_number_of_items;
  193. }
  194. /**
  195. * Get activities data to display
  196. * @param int $from
  197. * @param int $numberOfItems
  198. * @param int $column
  199. * @param string $direction
  200. * @return array
  201. */
  202. public static function getActivitiesData($from, $numberOfItems, $column, $direction)
  203. {
  204. $track_e_default = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
  205. $table_user = Database::get_main_table(TABLE_MAIN_USER);
  206. $access_url_rel_user_table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  207. $current_url_id = api_get_current_access_url_id();
  208. $column = intval($column);
  209. $from = intval($from);
  210. $numberOfItems = intval($numberOfItems);
  211. if (!in_array($direction, array('ASC','DESC'))) {
  212. $direction = 'DESC';
  213. }
  214. if (api_is_multiple_url_enabled()) {
  215. $sql = "SELECT
  216. default_event_type as col0,
  217. default_value_type as col1,
  218. default_value as col2,
  219. c_id as col3,
  220. session_id as col4,
  221. user.username as col5,
  222. user.user_id as col6,
  223. default_date as col7
  224. FROM $track_e_default as track_default,
  225. $table_user as user,
  226. $access_url_rel_user_table as url
  227. WHERE
  228. track_default.default_user_id = user.user_id AND
  229. url.user_id = user.user_id AND
  230. access_url_id='".$current_url_id."'";
  231. } else {
  232. $sql = "SELECT
  233. default_event_type as col0,
  234. default_value_type as col1,
  235. default_value as col2,
  236. c_id as col3,
  237. session_id as col4,
  238. user.username as col5,
  239. user.user_id as col6,
  240. default_date as col7
  241. FROM $track_e_default track_default, $table_user user
  242. WHERE track_default.default_user_id = user.user_id ";
  243. }
  244. if (isset($_GET['keyword'])) {
  245. $keyword = Database::escape_string(trim($_GET['keyword']));
  246. $sql .= " AND (user.username LIKE '%".$keyword."%' OR
  247. default_event_type LIKE '%".$keyword."%' OR
  248. default_value_type LIKE '%".$keyword."%' OR
  249. default_value LIKE '%".$keyword."%') ";
  250. }
  251. if (!empty($column) && !empty($direction)) {
  252. $sql .= " ORDER BY col$column $direction";
  253. } else {
  254. $sql .= " ORDER BY col5 DESC ";
  255. }
  256. $sql .= " LIMIT $from,$numberOfItems ";
  257. $res = Database::query($sql);
  258. $activities = array ();
  259. while ($row = Database::fetch_row($res)) {
  260. if (strpos($row[1], '_object') === false && strpos($row[1], '_array') === false) {
  261. $row[2] = $row[2];
  262. } else {
  263. if (!empty($row[2])) {
  264. $originalData = str_replace('\\', '', $row[2]);
  265. $row[2] = unserialize($originalData);
  266. if (is_array($row[2]) && !empty($row[2])) {
  267. $row[2] = implode_with_key(', ', $row[2]);
  268. } else {
  269. $row[2] = $originalData;
  270. }
  271. }
  272. }
  273. if (!empty($row['default_date']) && $row['default_date'] != '0000-00-00 00:00:00') {
  274. $row['default_date'] = api_get_local_time($row['default_date']);
  275. } else {
  276. $row['default_date'] = '-';
  277. }
  278. if (!empty($row[5])) {
  279. //course
  280. if (!empty($row[3])) {
  281. $row[3] = Display::url($row[3], api_get_path(WEB_CODE_PATH).'admin/course_edit.php?id='.$row[3]);
  282. } else {
  283. $row[3] = '-';
  284. }
  285. // session
  286. if (!empty($row[4])) {
  287. $row[4] = Display::url($row[4], api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.$row[4]);
  288. } else {
  289. $row[4] = '-';
  290. }
  291. // User id.
  292. $row[5] = Display::url(
  293. $row[5],
  294. api_get_path(WEB_CODE_PATH).'admin/user_information.php?user_id='.$row[6],
  295. array('title' => get_lang('UserInfo'))
  296. );
  297. $row[6] = TrackingUserLog::get_ip_from_user_event($row[6], $row[7], true);
  298. if (empty($row[6])) {
  299. $row[6] = get_lang('Unknown');
  300. }
  301. }
  302. $activities[] = $row;
  303. }
  304. return $activities;
  305. }
  306. /**
  307. * Get all course categories
  308. * @return array All course categories (code => name)
  309. */
  310. public static function getCourseCategories()
  311. {
  312. $categoryTable = Database :: get_main_table(TABLE_MAIN_CATEGORY);
  313. $sql = "SELECT code, name FROM $categoryTable
  314. ORDER BY tree_pos";
  315. $res = Database::query($sql);
  316. $categories = array ();
  317. while ($category = Database::fetch_object($res)) {
  318. $categories[$category->code] = $category->name;
  319. }
  320. return $categories;
  321. }
  322. /**
  323. * Rescale data
  324. * @param array $data The data that should be rescaled
  325. * @param int $max The maximum value in the rescaled data (default = 500);
  326. * @return array The rescaled data, same key as $data
  327. */
  328. public static function rescale($data, $max = 500)
  329. {
  330. $data_max = 1;
  331. foreach ($data as $index => $value) {
  332. $data_max = ($data_max < $value ? $value : $data_max);
  333. }
  334. reset($data);
  335. $result = array ();
  336. $delta = $max / $data_max;
  337. foreach ($data as $index => $value) {
  338. $result[$index] = (int) round($value * $delta);
  339. }
  340. return $result;
  341. }
  342. /**
  343. * Show statistics
  344. * @param string $title The title
  345. * @param array $stats
  346. * @param bool $showTotal
  347. * @param bool $isFileSize
  348. */
  349. public static function printStats($title, $stats, $showTotal = true, $isFileSize = false)
  350. {
  351. $total = 0;
  352. $data = Statistics::rescale($stats);
  353. echo '<table class="data_table" cellspacing="0" cellpadding="3">
  354. <tr><th colspan="'.($showTotal ? '4' : '3').'">'.$title.'</th></tr>';
  355. $i = 0;
  356. foreach ($stats as $subtitle => $number) {
  357. $total += $number;
  358. }
  359. foreach ($stats as $subtitle => $number) {
  360. if (!$isFileSize) {
  361. $number_label = number_format($number, 0, ',', '.');
  362. } else {
  363. $number_label = Statistics::makeSizeString($number);
  364. }
  365. $percentage = ($total>0?number_format(100*$number/$total, 1, ',', '.'):'0');
  366. echo '<tr class="row_'.($i%2 == 0 ? 'odd' : 'even').'">
  367. <td width="150">'.$subtitle.'</td>
  368. <td width="550">'.Display::bar_progress($percentage, false).'</td>
  369. <td align="right">'.$number_label.'</td>';
  370. if ($showTotal) {
  371. echo '<td align="right"> '.$percentage.'%</td>';
  372. }
  373. echo '</tr>';
  374. $i ++;
  375. }
  376. if ($showTotal) {
  377. if (!$isFileSize) {
  378. $total_label = number_format($total, 0, ',', '.');
  379. } else {
  380. $total_label = Statistics::makeSizeString($total);
  381. }
  382. echo '<tr><th colspan="4" align="right">'.get_lang('Total').': '.$total_label.'</td></tr>';
  383. }
  384. echo '</table>';
  385. }
  386. /**
  387. * Show some stats about the number of logins
  388. * @param string $type month, hour or day
  389. */
  390. public static function printLoginStats($type)
  391. {
  392. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  393. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  394. $current_url_id = api_get_current_access_url_id();
  395. $table_url = null;
  396. $where_url = null;
  397. $now = api_get_utc_datetime();
  398. $where_url_last = ' WHERE login_date > DATE_SUB("' . $now . '",INTERVAL 1 %s)';
  399. if (api_is_multiple_url_enabled()) {
  400. $table_url = ", $access_url_rel_user_table";
  401. $where_url = " WHERE login_user_id=user_id AND access_url_id='".$current_url_id."'";
  402. $where_url_last = ' AND login_date > DATE_SUB("' . $now . '",INTERVAL 1 %s)';
  403. }
  404. $period = get_lang('PeriodMonth');
  405. $periodCollection = api_get_months_long();
  406. $sql = "SELECT DATE_FORMAT( login_date, '%Y-%m' ) AS stat_date , count( login_id ) AS number_of_logins
  407. FROM ".$table.$table_url.$where_url."
  408. GROUP BY stat_date
  409. ORDER BY login_date DESC";
  410. $sql_last_x = null;
  411. switch ($type) {
  412. case 'hour':
  413. $period = get_lang('PeriodHour');
  414. $sql = "SELECT DATE_FORMAT( login_date, '%H' ) AS stat_date , count( login_id ) AS number_of_logins FROM ".$table.$table_url.$where_url." GROUP BY stat_date ORDER BY stat_date ";
  415. $sql_last_x = "SELECT DATE_FORMAT( login_date, '%H' ) AS stat_date , count( login_id ) AS number_of_logins FROM ".$table.$table_url.$where_url.sprintf($where_url_last,'DAY')." GROUP BY stat_date ORDER BY stat_date ";
  416. break;
  417. case 'day':
  418. $periodCollection = api_get_week_days_long();
  419. $period = get_lang('PeriodDay');
  420. $sql = "SELECT DATE_FORMAT( login_date, '%w' ) AS stat_date , count( login_id ) AS number_of_logins FROM ".$table.$table_url.$where_url." GROUP BY stat_date ORDER BY DATE_FORMAT( login_date, '%w' ) ";
  421. $sql_last_x = "SELECT DATE_FORMAT( login_date, '%w' ) AS stat_date , count( login_id ) AS number_of_logins FROM ".$table.$table_url.$where_url.sprintf($where_url_last,'WEEK')." GROUP BY stat_date ORDER BY DATE_FORMAT( login_date, '%w' ) ";
  422. break;
  423. }
  424. if ($sql_last_x) {
  425. $res_last_x = Database::query($sql_last_x);
  426. $result_last_x = array();
  427. while ($obj = Database::fetch_object($res_last_x)) {
  428. $stat_date = ($type === 'day') ? $periodCollection[$obj->stat_date] : $obj->stat_date;
  429. $result_last_x[$stat_date] = $obj->number_of_logins;
  430. }
  431. Statistics::printStats(get_lang('LastLogins').' ('.$period.')', $result_last_x, true);
  432. flush(); //flush web request at this point to see something already while the full data set is loading
  433. echo '<br />';
  434. }
  435. $res = Database::query($sql);
  436. $result = array();
  437. while ($obj = Database::fetch_object($res)) {
  438. $stat_date = $obj->stat_date;
  439. switch ($type) {
  440. case 'month':
  441. $stat_date = explode('-', $stat_date);
  442. $stat_date[1] = $periodCollection[$stat_date[1] - 1];
  443. $stat_date = implode(' ', $stat_date);
  444. break;
  445. case 'day':
  446. $stat_date = $periodCollection[$stat_date];
  447. break;
  448. }
  449. $result[$stat_date] = $obj->number_of_logins;
  450. }
  451. Statistics::printStats(get_lang('AllLogins').' ('.$period.')', $result, true);
  452. }
  453. /**
  454. * Print the number of recent logins
  455. * @param bool $distinct Whether to only give distinct users stats, or *all* logins
  456. * @return void
  457. */
  458. public static function printRecentLoginStats($distinct = false)
  459. {
  460. $totalLogin = array();
  461. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  462. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  463. $current_url_id = api_get_current_access_url_id();
  464. if (api_is_multiple_url_enabled()) {
  465. $table_url = ", $access_url_rel_user_table";
  466. $where_url = " AND login_user_id=user_id AND access_url_id='".$current_url_id."'";
  467. } else {
  468. $table_url = '';
  469. $where_url='';
  470. }
  471. $now = api_get_utc_datetime();
  472. $field = 'login_user_id';
  473. if ($distinct) {
  474. $field = 'DISTINCT(login_user_id)';
  475. }
  476. $sql[get_lang('ThisDay')] = "SELECT count($field) AS number FROM $table $table_url WHERE DATE_ADD(login_date, INTERVAL 1 DAY) >= '$now' $where_url";
  477. $sql[get_lang('Last7days')] = "SELECT count($field) AS number FROM $table $table_url WHERE DATE_ADD(login_date, INTERVAL 7 DAY) >= '$now' $where_url";
  478. $sql[get_lang('Last31days')] = "SELECT count($field) AS number FROM $table $table_url WHERE DATE_ADD(login_date, INTERVAL 31 DAY) >= '$now' $where_url";
  479. $sql[get_lang('Total')] = "SELECT count($field) AS number FROM $table $table_url WHERE 1=1 $where_url";
  480. foreach ($sql as $index => $query) {
  481. $res = Database::query($query);
  482. $obj = Database::fetch_object($res);
  483. $totalLogin[$index] = $obj->number;
  484. }
  485. if ($distinct) {
  486. Statistics::printStats(get_lang('DistinctUsersLogins'), $totalLogin, false);
  487. } else {
  488. Statistics::printStats(get_lang('Logins'), $totalLogin, false);
  489. }
  490. }
  491. /**
  492. * get the number of recent logins
  493. * @param bool $distinct Whether to only give distinct users stats, or *all* logins
  494. * @return array
  495. */
  496. public static function getRecentLoginStats($distinct = false)
  497. {
  498. $totalLogin = [];
  499. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  500. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  501. $current_url_id = api_get_current_access_url_id();
  502. if (api_is_multiple_url_enabled()) {
  503. $table_url = ", $access_url_rel_user_table";
  504. $where_url = " AND login_user_id=user_id AND access_url_id='".$current_url_id."'";
  505. } else {
  506. $table_url = '';
  507. $where_url='';
  508. }
  509. $now = api_get_utc_datetime();
  510. $field = 'login_user_id';
  511. if ($distinct) {
  512. $field = 'DISTINCT(login_user_id)';
  513. }
  514. $sql = "SELECT count($field) AS number, date(login_date) as login_date FROM $table $table_url WHERE DATE_ADD(login_date, INTERVAL 15 DAY) >= '$now' $where_url GROUP BY date(login_date)";
  515. $res = Database::query($sql);
  516. while($row = Database::fetch_array($res,'ASSOC')){
  517. $totalLogin[$row['login_date']] = $row['number'];
  518. }
  519. return $totalLogin;
  520. }
  521. /**
  522. * Show some stats about the accesses to the different course tools
  523. */
  524. public static function printToolStats()
  525. {
  526. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
  527. $access_url_rel_course_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  528. $current_url_id = api_get_current_access_url_id();
  529. $tools = array(
  530. 'announcement',
  531. 'assignment',
  532. 'calendar_event',
  533. 'chat',
  534. 'conference',
  535. 'course_description',
  536. 'document',
  537. 'dropbox',
  538. 'group',
  539. 'learnpath',
  540. 'link',
  541. 'quiz',
  542. 'student_publication',
  543. 'user',
  544. 'forum'
  545. );
  546. $tool_names = array();
  547. foreach ($tools as $tool) {
  548. $tool_names[$tool] = get_lang(ucfirst($tool), '');
  549. }
  550. if (api_is_multiple_url_enabled()) {
  551. $sql = "SELECT access_tool, count( access_id ) AS number_of_logins
  552. FROM $table t , $access_url_rel_course_table a
  553. WHERE
  554. access_tool IN ('".implode("','", $tools)."') AND
  555. t.c_id = a.c_id AND
  556. access_url_id='".$current_url_id."'
  557. GROUP BY access_tool
  558. ";
  559. } else {
  560. $sql = "SELECT access_tool, count( access_id ) AS number_of_logins
  561. FROM $table
  562. WHERE access_tool IN ('".implode("','", $tools)."')
  563. GROUP BY access_tool ";
  564. }
  565. $res = Database::query($sql);
  566. $result = array();
  567. while ($obj = Database::fetch_object($res)) {
  568. $result[$tool_names[$obj->access_tool]] = $obj->number_of_logins;
  569. }
  570. Statistics::printStats(get_lang('PlatformToolAccess'), $result, true);
  571. }
  572. /**
  573. * Show some stats about the number of courses per language
  574. */
  575. public static function printCourseByLanguageStats()
  576. {
  577. $table = Database :: get_main_table(TABLE_MAIN_COURSE);
  578. $access_url_rel_course_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  579. $current_url_id = api_get_current_access_url_id();
  580. if (api_is_multiple_url_enabled()) {
  581. $sql = "SELECT course_language, count( c.code ) AS number_of_courses
  582. FROM $table as c, $access_url_rel_course_table as u
  583. WHERE u.c_id = c.id AND access_url_id='".$current_url_id."'
  584. GROUP BY course_language
  585. ORDER BY number_of_courses DESC";
  586. } else {
  587. $sql = "SELECT course_language, count( code ) AS number_of_courses
  588. FROM $table GROUP BY course_language
  589. ORDER BY number_of_courses DESC";
  590. }
  591. $res = Database::query($sql);
  592. $result = array();
  593. while ($obj = Database::fetch_object($res)) {
  594. $result[$obj->course_language] = $obj->number_of_courses;
  595. }
  596. Statistics::printStats(get_lang('CountCourseByLanguage'), $result, true);
  597. }
  598. /**
  599. * Shows the number of users having their picture uploaded in Dokeos.
  600. */
  601. public static function printUserPicturesStats()
  602. {
  603. $user_table = Database :: get_main_table(TABLE_MAIN_USER);
  604. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  605. $current_url_id = api_get_current_access_url_id();
  606. $url_condition = null;
  607. $url_condition2 = null;
  608. $table = null;
  609. if (api_is_multiple_url_enabled()) {
  610. $url_condition = ", $access_url_rel_user_table as url WHERE url.user_id=u.user_id AND access_url_id='".$current_url_id."'";
  611. $url_condition2 = " AND url.user_id=u.user_id AND access_url_id='".$current_url_id."'";
  612. $table = ", $access_url_rel_user_table as url ";
  613. }
  614. $sql = "SELECT COUNT(*) AS n FROM $user_table as u ".$url_condition;
  615. $res = Database::query($sql);
  616. $count1 = Database::fetch_object($res);
  617. $sql = "SELECT COUNT(*) AS n FROM $user_table as u $table ".
  618. "WHERE LENGTH(picture_uri) > 0 $url_condition2";
  619. $res = Database::query($sql);
  620. $count2 = Database::fetch_object($res);
  621. // #users without picture
  622. $result[get_lang('No')] = $count1->n - $count2->n;
  623. $result[get_lang('Yes')] = $count2->n; // #users with picture
  624. Statistics::printStats(get_lang('CountUsers').' ('.get_lang('UserPicture').')', $result, true);
  625. }
  626. /**
  627. * Important activities
  628. */
  629. public static function printActivitiesStats()
  630. {
  631. echo '<h4>'.get_lang('ImportantActivities').'</h4>';
  632. // Create a search-box
  633. $form = new FormValidator(
  634. 'search_simple',
  635. 'get',
  636. api_get_path(WEB_CODE_PATH).'admin/statistics/index.php',
  637. '',
  638. 'width=200px',
  639. false
  640. );
  641. $renderer =& $form->defaultRenderer();
  642. $renderer->setCustomElementTemplate('<span>{element}</span> ');
  643. $form->addElement('hidden', 'report', 'activities');
  644. $form->addElement('hidden', 'activities_direction', 'DESC');
  645. $form->addElement('hidden', 'activities_column', '4');
  646. $form->addElement('text', 'keyword', get_lang('Keyword'));
  647. $form->addButtonSearch(get_lang('Search'), 'submit');
  648. echo '<div class="actions">';
  649. $form->display();
  650. echo '</div>';
  651. $table = new SortableTable(
  652. 'activities',
  653. array('Statistics', 'getNumberOfActivities'),
  654. array('Statistics', 'getActivitiesData'),
  655. 5,
  656. 50,
  657. 'DESC'
  658. );
  659. $parameters = array();
  660. $parameters['report'] = 'activities';
  661. if (isset($_GET['keyword'])) {
  662. $parameters['keyword'] = Security::remove_XSS($_GET['keyword']);
  663. }
  664. $table->set_additional_parameters($parameters);
  665. $table->set_header(0, get_lang('EventType'));
  666. $table->set_header(1, get_lang('DataType'));
  667. $table->set_header(2, get_lang('Value'));
  668. $table->set_header(3, get_lang('Course'));
  669. $table->set_header(4, get_lang('Session'));
  670. $table->set_header(5, get_lang('UserName'));
  671. $table->set_header(6, get_lang('IPAddress'));
  672. $table->set_header(7, get_lang('Date'));
  673. $table->display();
  674. }
  675. /**
  676. * Shows statistics about the time of last visit to each course.
  677. */
  678. public static function printCourseLastVisit()
  679. {
  680. $access_url_rel_course_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
  681. $current_url_id = api_get_current_access_url_id();
  682. $columns[0] = 'c_id';
  683. $columns[1] = 'access_date';
  684. $sql_order[SORT_ASC] = 'ASC';
  685. $sql_order[SORT_DESC] = 'DESC';
  686. $per_page = isset($_GET['per_page'])?intval($_GET['per_page']) : 10;
  687. $page_nr = isset($_GET['page_nr'])?intval($_GET['page_nr']) : 1;
  688. $column = isset($_GET['column'])?intval($_GET['column']) : 0;
  689. $date_diff = isset($_GET['date_diff'])?intval($_GET['date_diff']) : 60;
  690. $direction = isset($_GET['direction']) ? $_GET['direction'] : SORT_ASC;
  691. if (!in_array($direction, array(SORT_ASC, SORT_DESC))) {
  692. $direction = SORT_ASC;
  693. }
  694. $form = new FormValidator('courselastvisit', 'get');
  695. $form->addElement('hidden', 'report', 'courselastvisit');
  696. $form->addText('date_diff', get_lang('Days'), true);
  697. $form->addRule('date_diff', 'InvalidNumber', 'numeric');
  698. $form->addButtonSearch(get_lang('Search'), 'submit');
  699. if (!isset($_GET['date_diff'])) {
  700. $defaults['date_diff'] = 60;
  701. } else {
  702. $defaults['date_diff'] = Security::remove_XSS($_GET['date_diff']);
  703. }
  704. $form->setDefaults($defaults);
  705. $form->display();
  706. $values = $form->exportValues();
  707. $date_diff = $values['date_diff'];
  708. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
  709. if (api_is_multiple_url_enabled()) {
  710. $sql = "SELECT * FROM $table t , $access_url_rel_course_table a
  711. WHERE
  712. t.c_id = a.c_id AND
  713. access_url_id='".$current_url_id."'
  714. GROUP BY c_id
  715. HAVING c_id <> ''
  716. AND DATEDIFF( '".date('Y-m-d h:i:s')."' , access_date ) <= ". $date_diff;
  717. } else {
  718. $sql = "SELECT * FROM $table
  719. GROUP BY c_id
  720. HAVING c_id <> ''
  721. AND DATEDIFF( '".date('Y-m-d h:i:s')."' , access_date ) <= ". $date_diff;
  722. }
  723. $sql .= ' ORDER BY '.$columns[$column].' '.$sql_order[$direction];
  724. $from = ($page_nr -1) * $per_page;
  725. $sql .= ' LIMIT '.$from.','.$per_page;
  726. echo '<p>'.get_lang('LastAccess').' &gt;= '.$date_diff.' '.get_lang('Days').'</p>';
  727. $res = Database::query($sql);
  728. if (Database::num_rows($res) > 0) {
  729. $courses = array ();
  730. while ($obj = Database::fetch_object($res)) {
  731. $courseInfo = api_get_course_info_by_id($obj->c_id);
  732. if (empty($courseInfo)) {
  733. continue;
  734. }
  735. $course = array ();
  736. $course[]= '<a href="'.api_get_path(WEB_COURSE_PATH).$courseInfo['code'].'">'.$courseInfo['code'].' <a>';
  737. // Allow sort by date hiding the numerical date
  738. $course[] = '<span style="display:none;">'.$obj->access_date.'</span>'.api_convert_and_format_date($obj->access_date);
  739. $courses[] = $course;
  740. }
  741. $parameters['date_diff'] = $date_diff;
  742. $parameters['report'] = 'courselastvisit';
  743. $table_header[] = array(get_lang("CourseCode"), true);
  744. $table_header[] = array(get_lang("LastAccess"), true);
  745. Display:: display_sortable_table(
  746. $table_header,
  747. $courses,
  748. array('column' => $column, 'direction' => $direction),
  749. array(),
  750. $parameters
  751. );
  752. } else {
  753. echo get_lang('NoSearchResults');
  754. }
  755. }
  756. /**
  757. * Displays the statistics of the messages sent and received by each user in the social network
  758. * @param string Type of message: 'sent' or 'received'
  759. * @return array Message list
  760. */
  761. public static function getMessages($messageType)
  762. {
  763. $message_table = Database::get_main_table(TABLE_MESSAGE);
  764. $user_table = Database::get_main_table(TABLE_MAIN_USER);
  765. $access_url_rel_user_table = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  766. $current_url_id = api_get_current_access_url_id();
  767. switch ($messageType) {
  768. case 'sent':
  769. $field = 'user_sender_id';
  770. break;
  771. case 'received':
  772. $field = 'user_receiver_id';
  773. break;
  774. }
  775. if (api_is_multiple_url_enabled()) {
  776. $sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message ".
  777. "FROM ".$access_url_rel_user_table." as url, ".$message_table." m ".
  778. "LEFT JOIN ".$user_table." u ON m.$field = u.user_id ".
  779. "WHERE url.user_id = m.$field AND access_url_id='".$current_url_id."' ".
  780. "GROUP BY m.$field ORDER BY count_message DESC ";
  781. } else {
  782. $sql = "SELECT lastname, firstname, username, COUNT($field) AS count_message ".
  783. "FROM ".$message_table." m ".
  784. "LEFT JOIN ".$user_table." u ON m.$field = u.user_id ".
  785. "GROUP BY m.$field ORDER BY count_message DESC ";
  786. }
  787. $res = Database::query($sql);
  788. $messages_sent = array();
  789. while ($messages = Database::fetch_array($res)) {
  790. if (empty($messages['username'])) {
  791. $messages['username'] = get_lang('Unknown');
  792. }
  793. $users = api_get_person_name($messages['firstname'], $messages['lastname']).'<br />('.$messages['username'].')';
  794. $messages_sent[$users] = $messages['count_message'];
  795. }
  796. return $messages_sent;
  797. }
  798. /**
  799. * Count the number of friends for social network users
  800. */
  801. public static function getFriends()
  802. {
  803. $user_friend_table = Database::get_main_table(TABLE_MAIN_USER_REL_USER);
  804. $user_table = Database::get_main_table(TABLE_MAIN_USER);
  805. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  806. $current_url_id = api_get_current_access_url_id();
  807. if (api_is_multiple_url_enabled()) {
  808. $sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend ".
  809. "FROM ".$access_url_rel_user_table." as url, ".$user_friend_table." uf ".
  810. "LEFT JOIN ".$user_table." u ON uf.user_id = u.user_id ".
  811. "WHERE uf.relation_type <> '".USER_RELATION_TYPE_RRHH."' AND uf.user_id = url.user_id AND access_url_id='".$current_url_id."' ".
  812. "GROUP BY uf.user_id ORDER BY count_friend DESC ";
  813. } else {
  814. $sql = "SELECT lastname, firstname, username, COUNT(friend_user_id) AS count_friend ".
  815. "FROM ".$user_friend_table." uf ".
  816. "LEFT JOIN ".$user_table." u ON uf.user_id = u.user_id ".
  817. "WHERE uf.relation_type <> '".USER_RELATION_TYPE_RRHH."' ".
  818. "GROUP BY uf.user_id ORDER BY count_friend DESC ";
  819. }
  820. $res = Database::query($sql);
  821. $list_friends = array();
  822. while ($friends = Database::fetch_array($res)) {
  823. $users = api_get_person_name($friends['firstname'], $friends['lastname']).'<br />('.$friends['username'].')';
  824. $list_friends[$users] = $friends['count_friend'];
  825. }
  826. return $list_friends;
  827. }
  828. /**
  829. * Print the number of users that didn't login for a certain period of time
  830. */
  831. public static function printUsersNotLoggedInStats()
  832. {
  833. $totalLogin = array();
  834. $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LOGIN);
  835. $access_url_rel_user_table= Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
  836. $current_url_id = api_get_current_access_url_id();
  837. $total = self::countUsers();
  838. if (api_is_multiple_url_enabled()) {
  839. $table_url = ", $access_url_rel_user_table";
  840. $where_url = " AND login_user_id=user_id AND access_url_id='".$current_url_id."'";
  841. } else {
  842. $table_url = '';
  843. $where_url='';
  844. }
  845. $now = api_get_utc_datetime();
  846. $sql[get_lang('ThisDay')] =
  847. "SELECT count(distinct(login_user_id)) AS number ".
  848. " FROM $table $table_url ".
  849. " WHERE DATE_ADD(login_date, INTERVAL 1 DAY) >= '$now' $where_url";
  850. $sql[get_lang('Last7days')] =
  851. "SELECT count(distinct(login_user_id)) AS number ".
  852. " FROM $table $table_url ".
  853. " WHERE DATE_ADD(login_date, INTERVAL 7 DAY) >= '$now' $where_url";
  854. $sql[get_lang('Last31days')] =
  855. "SELECT count(distinct(login_user_id)) AS number ".
  856. " FROM $table $table_url ".
  857. " WHERE DATE_ADD(login_date, INTERVAL 31 DAY) >= '$now' $where_url";
  858. $sql[sprintf(get_lang('LastXMonths'), 6)] =
  859. "SELECT count(distinct(login_user_id)) AS number ".
  860. " FROM $table $table_url ".
  861. " WHERE DATE_ADD(login_date, INTERVAL 6 MONTH) >= '$now' $where_url";
  862. $sql[get_lang('NeverConnected')] =
  863. "SELECT count(distinct(login_user_id)) AS number ".
  864. " FROM $table $table_url WHERE 1=1 $where_url";
  865. foreach ($sql as $index => $query) {
  866. $res = Database::query($query);
  867. $obj = Database::fetch_object($res);
  868. $r = $total - $obj->number;
  869. $totalLogin[$index] = $r < 0 ? 0 : $r;
  870. }
  871. Statistics::printStats(
  872. get_lang('StatsUsersDidNotLoginInLastPeriods'),
  873. $totalLogin,
  874. false
  875. );
  876. }
  877. }