source-function-F_getTestIDs

It appears that you are using AdBlocking software. The cost of running this website is covered by advertisements. If you like it please feel free to a small amount of money to secure the future of this website.
Overview

Classes

Interfaces

Exceptions

Functions

   1: <?php
   2: //============================================================+
   3: // File name   : tce_functions_test_stats.php
   4: // Begin       : 2004-06-10
   5: // Last Update : 2014-01-27
   6: //
   7: // Description : Statistical functions for test results.
   8: //
   9: // Author: Nicola Asuni
  10: //
  11: // (c) Copyright:
  12: //               Nicola Asuni
  13: //               Tecnick.com LTD
  14: //               www.tecnick.com
  15: //               info@tecnick.com
  16: //
  17: // License:
  18: //    Copyright (C) 2004-2014 Nicola Asuni - Tecnick.com LTD
  19: //    See LICENSE.TXT file for more information.
  20: //============================================================+
  21: 
  22: /**
  23:  * @file
  24:  * Statistical functions for test results.
  25:  * @package com.tecnick.tcexam.shared
  26:  * @author Nicola Asuni
  27:  * @since 2004-06-10
  28:  */
  29: 
  30: /**
  31: * Returns statistic array for the test-user
  32: * @param $test_id (int) test ID.
  33: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
  34: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
  35: * return $data array containing test-user statistics.
  36: */
  37: function F_getUserTestStat($test_id, $user_id = 0, $testuser_id = 0)
  38: {
  39:     require_once('../config/tce_config.php');
  40:     require_once('../../shared/code/tce_functions_test.php');
  41:     global $db, $l;
  42:     $test_id = intval($test_id);
  43:     $user_id = intval($user_id);
  44:     $testuser_id = intval($testuser_id);
  45:     // get test data array
  46:     $data = F_getTestData($test_id);
  47:     $data += F_getUserTestTotals($test_id, $user_id, $testuser_id);
  48:     return $data;
  49: }
  50: 
  51: /**
  52: * Returns test-user totals
  53: * @param $test_id (int) test ID.
  54: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
  55: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
  56: * return $data array containing test-user statistics.
  57: */
  58: function F_getUserTestTotals($test_id, $user_id = 0, $testuser_id = 0)
  59: {
  60:     require_once('../config/tce_config.php');
  61:     require_once('../../shared/code/tce_functions_test.php');
  62:     global $db, $l;
  63:     $test_id = intval($test_id);
  64:     $user_id = intval($user_id);
  65:     $testuser_id = intval($testuser_id);
  66:     // get test data array
  67:     $data = array();
  68:     // additional info
  69:     if (($test_id > 0) and ($user_id > 0) and ($testuser_id > 0)) {
  70:         // get user totals
  71:         $sqlu = 'SELECT SUM(testlog_score) AS total_score, MAX(testlog_change_time) AS test_end_time, testuser_id, testuser_creation_time, testuser_status, testuser_comment
  72:         FROM '.K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS.'
  73:         WHERE testlog_testuser_id=testuser_id
  74:             AND testuser_id='.$testuser_id.'
  75:             AND testuser_test_id='.$test_id.'
  76:             AND testuser_user_id='.$user_id.'
  77:             AND testuser_status>0
  78:         GROUP BY testuser_id, testuser_creation_time, testuser_status, testuser_comment';
  79:         if ($ru = F_db_query($sqlu, $db)) {
  80:             if ($mu = F_db_fetch_array($ru)) {
  81:                 $data['testuser_id'] = $mu['testuser_id'];
  82:                 $data['user_score'] = $mu['total_score'];
  83:                 $data['user_test_start_time'] = $mu['testuser_creation_time'];
  84:                 $data['user_test_end_time'] = $mu['test_end_time'];
  85:                 $data['testuser_status'] = $mu['testuser_status'];
  86:                 $data['user_comment'] = $mu['testuser_comment'];
  87:             }
  88:         } else {
  89:             F_display_db_error();
  90:         }
  91:     }
  92:     return $data;
  93: }
  94: 
  95: /**
  96: * Returns statistic array for the selected test.
  97: * @param $test_id (int) test ID.
  98: * @param $group_id (int) group ID - if greater than zero, filter stats for the specified user group.
  99: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
 100: * @param $startdate (int) start date ID - if greater than zero, filter stats for the specified starting date
 101: * @param $enddate (int) end date ID - if greater than zero, filter stats for the specified ending date
 102: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
 103: * @param $pubmode (boolean) If true filter the results for the public interface.
 104: * return $data array containing test statistics.
 105: */
 106: function F_getTestStat($test_id, $group_id = 0, $user_id = 0, $startdate = 0, $enddate = 0, $testuser_id = 0, $pubmode = false)
 107: {
 108:     $data = F_getRawTestStat($test_id, $group_id, $user_id, $startdate, $enddate, $testuser_id, array(), $pubmode);
 109:     if (isset($data['qstats']['recurrence'])) {
 110:         $data = F_normalizeTestStatAverages($data);
 111:     }
 112:     return $data;
 113: }
 114: 
 115: /**
 116: * Returns raw statistic array for the selected test.
 117: * @param $test_id (int) test ID.
 118: * @param $group_id (int) group ID - if greater than zero, filter stats for the specified user group.
 119: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
 120: * @param $startdate (int) start date ID - if greater than zero, filter stats for the specified starting date
 121: * @param $enddate (int) end date ID - if greater than zero, filter stats for the specified ending date
 122: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
 123: * @param $data (array) Array of existing data to be merged with the current one.
 124: * @param $pubmode (boolean) If true filter the results for the public interface.
 125: * return $data array containing test statistics.
 126: */
 127: function F_getRawTestStat($test_id, $group_id = 0, $user_id = 0, $startdate = 0, $enddate = 0, $testuser_id = 0, $data = array(), $pubmode = false)
 128: {
 129:     require_once('../config/tce_config.php');
 130:     require_once('../../shared/code/tce_functions_authorization.php');
 131:     require_once('../../shared/code/tce_functions_test.php');
 132:     global $db, $l;
 133:     $test_id = intval($test_id);
 134:     $group_id = intval($group_id);
 135:     $user_id = intval($user_id);
 136:     $testuser_id = intval($testuser_id);
 137:     // query to calculate total number of questions
 138:     $sqltot = K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS;
 139:     $sqltb = K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS.', '.K_TABLE_ANSWERS.', '.K_TABLE_LOG_ANSWER;
 140:     $sqlm = K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS.', '.K_TABLE_QUESTIONS.', '.K_TABLE_SUBJECTS.', '.K_TABLE_MODULES.'';
 141:     // apply filters
 142:     $sqlw = 'WHERE testlog_testuser_id=testuser_id';
 143:     $sqlansw = 'WHERE logansw_answer_id=answer_id AND logansw_testlog_id=testlog_id AND testlog_testuser_id=testuser_id';
 144:     if ($test_id > 0) {
 145:         $sqlw .= ' AND testuser_test_id='.$test_id.'';
 146:         $sqlansw .= ' AND testuser_test_id='.$test_id.'';
 147:     } elseif ($pubmode) {
 148:         $test_ids_results = F_getTestIDResults($test_id, $user_id);
 149:         $sqlw .= ' AND testuser_test_id IN ('.$test_ids_results.')';
 150:         $sqlansw .= ' AND testuser_test_id IN ('.$test_ids_results.')';
 151:     }
 152:     if ($user_id > 0) {
 153:         $sqltot .= ', '.K_TABLE_USERS;
 154:         $sqltb .= ', '.K_TABLE_USERS;
 155:         $sqlm .= ', '.K_TABLE_USERS;
 156:         $sqlw .= ' AND testuser_user_id=user_id AND user_id='.$user_id.'';
 157:         $sqlansw .= ' AND testuser_user_id=user_id AND user_id='.$user_id.'';
 158:         if ($testuser_id > 0) {
 159:             $sqlw .= ' AND testuser_id='.$testuser_id.'';
 160:             $sqlansw .= ' AND testuser_id='.$testuser_id.'';
 161:         }
 162:     } elseif ($group_id > 0) {
 163:         $sqltot .= ', '.K_TABLE_USERS.', '.K_TABLE_USERGROUP;
 164:         $sqltb .= ', '.K_TABLE_USERS.', '.K_TABLE_USERGROUP;
 165:         $sqlm .= ', '.K_TABLE_USERS.', '.K_TABLE_USERGROUP;
 166:         $sqlw .= ' AND testuser_user_id=user_id AND usrgrp_user_id=user_id AND usrgrp_group_id='.$group_id.'';
 167:         $sqlansw .= ' AND testuser_user_id=user_id AND usrgrp_user_id=user_id AND usrgrp_group_id='.$group_id.'';
 168:     }
 169:     if (!empty($startdate)) {
 170:         $startdate_time = strtotime($startdate);
 171:         $startdate = date(K_TIMESTAMP_FORMAT, $startdate_time);
 172:         $sqlw .= ' AND testuser_creation_time>=\''.$startdate.'\'';
 173:         $sqlansw .= ' AND testuser_creation_time>=\''.$startdate.'\'';
 174:     }
 175:     if (!empty($enddate)) {
 176:         $enddate_time = strtotime($enddate);
 177:         $enddate = date(K_TIMESTAMP_FORMAT, $enddate_time);
 178:         $sqlw .= ' AND testuser_creation_time<=\''.$enddate.'\'';
 179:         $sqlansw .= ' AND testuser_creation_time<=\''.$enddate.'\'';
 180:     }
 181:     // check if a specific test is selected or not
 182:     if ($test_id == 0) {
 183:         $test_ids = array();
 184:         $sqlt = 'SELECT testuser_test_id FROM '.$sqltot.' '.$sqlw.' GROUP BY testuser_test_id ORDER BY testuser_test_id';
 185:         if ($rt = F_db_query($sqlt, $db)) {
 186:             while ($mt = F_db_fetch_assoc($rt)) {
 187:                 // check user's authorization
 188:                 if (F_isAuthorizedUser(K_TABLE_TESTS, 'test_id', $mt['testuser_test_id'], 'test_user_id')) {
 189:                     $test_ids[] = $mt['testuser_test_id'];
 190:                 }
 191:             }
 192:         } else {
 193:             F_display_db_error();
 194:         }
 195:         foreach ($test_ids as $tid) {
 196:             // select test IDs
 197:             $data =  F_getRawTestStat($tid, $group_id, $user_id, $startdate, $enddate, $testuser_id, $data);
 198:         }
 199:         return $data;
 200:     }
 201:     $testdata = F_getTestData($test_id);
 202:     // array to be returned
 203:     if (!isset($data['qstats'])) {
 204:         // total number of questions
 205:         $data['qstats'] = array(
 206:             'recurrence' => 0,
 207:             'recurrence_perc' => 0,
 208:             'average_score' => 0,
 209:             'average_score_perc' => 0,
 210:             'average_time' => 0,
 211:             'right' => 0,
 212:             'right_perc' => 0,
 213:             'wrong' => 0,
 214:             'wrong_perc' => 0,
 215:             'unanswered' => 0,
 216:             'unanswered_perc' => 0,
 217:             'undisplayed' => 0,
 218:             'undisplayed_perc' => 0,
 219:             'unrated' => 0,
 220:             'unrated_perc' => 0,
 221:             'qnum' => 0,
 222:             'module' => array());
 223:     }
 224:     $sql = 'SELECT
 225:         module_id,
 226:         subject_id,
 227:         question_id,
 228:         module_name,
 229:         subject_name,
 230:         subject_description,
 231:         question_description,';
 232:     if (($user_id > 0) and ($testuser_id > 0)) {
 233:         $sql .= ' testlog_score,
 234:             testlog_user_ip,
 235:             testlog_display_time,
 236:             testlog_change_time,
 237:             testlog_reaction_time,
 238:             testlog_answer_text,
 239:             question_type,
 240:             question_explanation,';
 241:     }
 242:     $sql .= ' COUNT(question_id) AS recurrence,
 243:         AVG(testlog_score) AS average_score,
 244:         AVG(testlog_change_time - testlog_display_time) AS average_time,
 245:         MIN(question_type) AS question_type,
 246:         MIN(question_difficulty) AS question_difficulty';
 247:     $sql .= ' FROM '.$sqlm;
 248:     $sql .= ' WHERE testlog_testuser_id=testuser_id AND question_id=testlog_question_id AND subject_id=question_subject_id AND module_id=subject_module_id';
 249:     if ($test_id > 0) {
 250:         $sql .= ' AND testuser_test_id='.$test_id.'';
 251:     }
 252:     if ($testuser_id > 0) {
 253:         $sql .= ' AND testuser_id='.$testuser_id.'';
 254:     }
 255:     if ($user_id > 0) {
 256:         $sql .= ' AND testuser_user_id=user_id AND user_id='.$user_id.'';
 257:     } elseif ($group_id > 0) {
 258:         $sql .= ' AND testuser_user_id=user_id AND usrgrp_user_id=user_id AND usrgrp_group_id='.$group_id.'';
 259:     }
 260:     if (!empty($startdate)) {
 261:         $sql .= ' AND testuser_creation_time>=\''.$startdate.'\'';
 262:     }
 263:     if (!empty($enddate)) {
 264:         $sql .= ' AND testuser_creation_time<=\''.$enddate.'\'';
 265:     }
 266:     $sql .= ' GROUP BY module_id, subject_id, question_id, module_name, subject_name, subject_description, question_description';
 267:     if (($user_id > 0) and ($testuser_id > 0)) {
 268:         $sql .= ', testlog_score, testlog_user_ip, testlog_display_time, testlog_change_time, testlog_reaction_time, testlog_answer_text, question_type, question_explanation';
 269:     } else {
 270:         $sql .= ' ORDER BY module_name, subject_name, question_description';
 271:     }
 272:     if ($r = F_db_query($sql, $db)) {
 273:         while ($m = F_db_fetch_array($r)) {
 274:             if (!isset($data['qstats']['module']['\''.$m['module_id'].'\''])) {
 275:                 $data['qstats']['module']['\''.$m['module_id'].'\''] = array(
 276:                     'id' => $m['module_id'],
 277:                     'name' => $m['module_name'],
 278:                     'recurrence' => 0,
 279:                     'recurrence_perc' => 0,
 280:                     'average_score' => 0,
 281:                     'average_score_perc' => 0,
 282:                     'average_time' => 0,
 283:                     'right' => 0,
 284:                     'right_perc' => 0,
 285:                     'wrong' => 0,
 286:                     'wrong_perc' => 0,
 287:                     'unanswered' => 0,
 288:                     'unanswered_perc' => 0,
 289:                     'undisplayed' => 0,
 290:                     'undisplayed_perc' => 0,
 291:                     'unrated' => 0,
 292:                     'unrated_perc' => 0,
 293:                     'qnum' => 0,
 294:                     'subject' => array());
 295:             }
 296:             if (!isset($data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\''])) {
 297:                 $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\''] = array(
 298:                     'id' => $m['subject_id'],
 299:                     'name' => $m['subject_name'],
 300:                     'description' => $m['subject_description'],
 301:                     'recurrence' => 0,
 302:                     'recurrence_perc' => 0,
 303:                     'average_score' => 0,
 304:                     'average_score_perc' => 0,
 305:                     'average_time' => 0,
 306:                     'right' => 0,
 307:                     'right_perc' => 0,
 308:                     'wrong' => 0,
 309:                     'wrong_perc' => 0,
 310:                     'unanswered' => 0,
 311:                     'unanswered_perc' => 0,
 312:                     'undisplayed' => 0,
 313:                     'undisplayed_perc' => 0,
 314:                     'unrated' => 0,
 315:                     'unrated_perc' => 0,
 316:                     'qnum' => 0,
 317:                     'question' => array());
 318:             }
 319:             $question_max_score = ($testdata['test_score_right'] * $m['question_difficulty']);
 320:             $question_half_score = ($question_max_score / 2);
 321:             $qright = F_count_rows($sqltot, $sqlw.' AND testlog_question_id='.$m['question_id'].' AND testlog_score>'.$question_half_score.'');
 322:             $qwrong = F_count_rows($sqltot, $sqlw.' AND testlog_question_id='.$m['question_id'].' AND testlog_score<='.$question_half_score.'');
 323:             $qunanswered = F_count_rows($sqltot, $sqlw.' AND testlog_question_id='.$m['question_id'].' AND testlog_change_time IS NULL');
 324:             $qundisplayed = F_count_rows($sqltot, $sqlw.' AND testlog_question_id='.$m['question_id'].' AND testlog_display_time IS NULL');
 325:             $qunrated = F_count_rows($sqltot, $sqlw.' AND testlog_question_id='.$m['question_id'].' AND testlog_score IS NULL');
 326:             if (stripos($m['average_time'], ':') !== false) {
 327:                 // PostgreSQL returns formatted time, while MySQL returns the number of seconds
 328:                 $m['average_time'] = strtotime($m['average_time']);
 329:             }
 330:             $num_all_answers = F_count_rows($sqltb, $sqlansw.' AND testlog_question_id='.$m['question_id']);
 331:             if (!isset($data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\''])) {
 332:                 $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\''] = array(
 333:                     'id' => $m['question_id'],
 334:                     'description' => $m['question_description'],
 335:                     'type' => $m['question_type'],
 336:                     'difficulty' => $m['question_difficulty'],
 337:                     'recurrence' => 0,
 338:                     'recurrence_perc' => 0,
 339:                     'average_score' => 0,
 340:                     'average_score_perc' => 0,
 341:                     'average_time' => 0,
 342:                     'right' => 0,
 343:                     'right_perc' => 0,
 344:                     'wrong' => 0,
 345:                     'wrong_perc' => 0,
 346:                     'unanswered' => 0,
 347:                     'unanswered_perc' => 0,
 348:                     'undisplayed' => 0,
 349:                     'undisplayed_perc' => 0,
 350:                     'unrated' => 0,
 351:                     'unrated_perc' => 0,
 352:                     'qnum' => 0,
 353:                     'anum' => 0,
 354:                     'answer' => array());
 355:             }
 356: 
 357:             // average score ratio
 358:             if ($question_max_score > 0) {
 359:                 $average_score_perc = ($m['average_score'] / $question_max_score);
 360:             } else {
 361:                 $average_score_perc = 0;
 362:             }
 363: 
 364:             // sum values for questions
 365:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['qnum'] += 1;
 366:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['recurrence'] += $m['recurrence'];
 367:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['average_score'] += $m['average_score'];
 368:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['average_score_perc'] += $average_score_perc;
 369:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['average_time'] += $m['average_time'];
 370:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['right'] += $qright;
 371:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['wrong'] += $qwrong;
 372:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['unanswered'] += $qunanswered;
 373:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['undisplayed'] += $qundisplayed;
 374:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['unrated'] += $qunrated;
 375:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['anum'] += $num_all_answers;
 376: 
 377:             // sum values for subject
 378:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['qnum'] += 1;
 379:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['recurrence'] += $m['recurrence'];
 380:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['average_score'] += $m['average_score'];
 381:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['average_score_perc'] += $average_score_perc;
 382:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['average_time'] += $m['average_time'];
 383:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['right'] += $qright;
 384:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['wrong'] += $qwrong;
 385:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['unanswered'] += $qunanswered;
 386:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['undisplayed'] += $qundisplayed;
 387:             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['unrated'] += $qunrated;
 388: 
 389:             // sum values for module
 390:             $data['qstats']['module']['\''.$m['module_id'].'\'']['qnum'] += 1;
 391:             $data['qstats']['module']['\''.$m['module_id'].'\'']['recurrence'] += $m['recurrence'];
 392:             $data['qstats']['module']['\''.$m['module_id'].'\'']['average_score'] += $m['average_score'];
 393:             $data['qstats']['module']['\''.$m['module_id'].'\'']['average_score_perc'] += $average_score_perc;
 394:             $data['qstats']['module']['\''.$m['module_id'].'\'']['average_time'] += $m['average_time'];
 395:             $data['qstats']['module']['\''.$m['module_id'].'\'']['right'] += $qright;
 396:             $data['qstats']['module']['\''.$m['module_id'].'\'']['wrong'] += $qwrong;
 397:             $data['qstats']['module']['\''.$m['module_id'].'\'']['unanswered'] += $qunanswered;
 398:             $data['qstats']['module']['\''.$m['module_id'].'\'']['undisplayed'] += $qundisplayed;
 399:             $data['qstats']['module']['\''.$m['module_id'].'\'']['unrated'] += $qunrated;
 400: 
 401:             // sum totals
 402:             $data['qstats']['qnum'] += 1;
 403:             $data['qstats']['recurrence'] += $m['recurrence'];
 404:             $data['qstats']['average_score'] += $m['average_score'];
 405:             $data['qstats']['average_score_perc'] += $average_score_perc;
 406:             $data['qstats']['average_time'] += $m['average_time'];
 407:             $data['qstats']['right'] += $qright;
 408:             $data['qstats']['wrong'] += $qwrong;
 409:             $data['qstats']['unanswered'] += $qunanswered;
 410:             $data['qstats']['undisplayed'] += $qundisplayed;
 411:             $data['qstats']['unrated'] += $qunrated;
 412: 
 413:             // get answer statistics
 414:             $sqlaa = 'SELECT answer_id, answer_description, COUNT(answer_id) AS recurrence';
 415:             if (($user_id > 0) and ($testuser_id > 0)) {
 416:                 $sqlaa .= ', logansw_position, logansw_selected, answer_isright, answer_position, answer_explanation';
 417:             }
 418:             $sqlaa .= ' FROM '.$sqltb.'';
 419:             $sqlaw = ' WHERE testlog_testuser_id=testuser_id
 420:                     AND logansw_testlog_id=testlog_id
 421:                     AND answer_id=logansw_answer_id
 422:                     AND answer_question_id='.$m['question_id'].'';
 423:             if ($test_id > 0) {
 424:                 $sqlaw .= ' AND testuser_test_id='.$test_id.'';
 425:             }
 426:             if ($user_id > 0) {
 427:                 $sqlaw .= ' AND testuser_user_id='.$user_id.'';
 428:             }
 429:             if ($testuser_id > 0) {
 430:                 $sqlaw .= ' AND testuser_id='.$testuser_id.'';
 431:             }
 432:             if ($user_id > 0) {
 433:                 $sqlaw .= ' AND testuser_user_id=user_id AND user_id='.$user_id.'';
 434:             } elseif ($group_id > 0) {
 435:                 $sqlaw .= ' AND testuser_user_id=user_id AND usrgrp_user_id=user_id AND usrgrp_group_id='.$group_id.'';
 436:             }
 437:             if (!empty($startdate)) {
 438:                 $sql .= ' AND testuser_creation_time>=\''.$startdate.'\'';
 439:             }
 440:             if (!empty($enddate)) {
 441:                 $sql.= ' AND testuser_creation_time<=\''.$enddate.'\'';
 442:             }
 443:             $sqlab = ' GROUP BY answer_id, answer_description';
 444: 
 445:             if (($user_id > 0) and ($testuser_id > 0)) {
 446:                 $sqlab .= ', logansw_position, logansw_selected, answer_isright, answer_position, answer_explanation';
 447:             }
 448:             $sqlab .= ' ORDER BY answer_description';
 449:             $sqla = $sqlaa.$sqlaw.$sqlab;
 450:             if ($ra = F_db_query($sqla, $db)) {
 451:                 while ($ma = F_db_fetch_array($ra)) {
 452:                     $aright = F_count_rows($sqltb, $sqlaw.' AND answer_id='.$ma['answer_id'].' AND ((answer_isright=\'0\' AND logansw_selected=0) OR (answer_isright=\'1\' AND logansw_selected=1) OR (answer_position IS NOT NULL AND logansw_position IS NOT NULL AND answer_position=logansw_position))');
 453:                     $awrong = F_count_rows($sqltb, $sqlaw.' AND answer_id='.$ma['answer_id'].' AND ((answer_isright=\'0\' AND logansw_selected=1) OR (answer_isright=\'1\' AND logansw_selected=0) OR (answer_position IS NOT NULL AND answer_position!=logansw_position))');
 454:                     $aunanswered = F_count_rows($sqltb, $sqlaw.' AND answer_id='.$ma['answer_id'].' AND logansw_selected=-1');
 455:                     if (!isset($data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\''])) {
 456:                             $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\''] = array(
 457:                             'id' => $ma['answer_id'],
 458:                             'description' => $ma['answer_description'],
 459:                             'recurrence' => 0,
 460:                             'recurrence_perc' => 0,
 461:                             'right' => 0,
 462:                             'right_perc' => 0,
 463:                             'wrong' => 0,
 464:                             'wrong_perc' => 0,
 465:                             'unanswered' => 0,
 466:                             'unanswered_perc' => 0);
 467:                     }
 468: 
 469:                     $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\'']['recurrence'] += $ma['recurrence'];
 470:                     $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\'']['right'] += $aright;
 471:                     $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\'']['wrong'] += $awrong;
 472:                     $data['qstats']['module']['\''.$m['module_id'].'\'']['subject']['\''.$m['subject_id'].'\'']['question']['\''.$m['question_id'].'\'']['answer']['\''.$ma['answer_id'].'\'']['unanswered'] += $aunanswered;
 473:                 }
 474:             } else {
 475:                 F_display_db_error();
 476:             }
 477:         }
 478:     } else {
 479:         F_display_db_error();
 480:     }
 481:     return $data;
 482: }
 483: 
 484: /**
 485:  * Calculate average values from TestStat array
 486:  * @param $data (array) Raw data array.
 487:  * return $data (array) Processed array.
 488:  */
 489: function F_normalizeTestStatAverages($data)
 490: {
 491:     if (!isset($data['qstats']['recurrence']) or ($data['qstats']['recurrence'] <= 0)) {
 492:         return $data;
 493:     }
 494:     // calculate totals and average values
 495:     $data['qstats']['recurrence_perc'] = 100;
 496:     $data['qstats']['average_score'] = ($data['qstats']['average_score'] / $data['qstats']['qnum']);
 497:     $data['qstats']['average_score_perc'] = round(100 * $data['qstats']['average_score_perc'] / $data['qstats']['recurrence']);
 498:     $data['qstats']['average_time'] = ($data['qstats']['average_time'] / $data['qstats']['qnum']);
 499:     $data['qstats']['right_perc'] = round(100 * $data['qstats']['right'] / $data['qstats']['recurrence']);
 500:     $data['qstats']['wrong_perc'] = round(100 * $data['qstats']['wrong'] / $data['qstats']['recurrence']);
 501:     $data['qstats']['unanswered_perc'] = round(100 * $data['qstats']['unanswered'] / $data['qstats']['recurrence']);
 502:     $data['qstats']['undisplayed_perc'] = round(100 * $data['qstats']['undisplayed'] / $data['qstats']['recurrence']);
 503:     $data['qstats']['unrated_perc'] = round(100 * $data['qstats']['unrated'] / $data['qstats']['recurrence']);
 504:     foreach ($data['qstats']['module'] as $mk => $mv) {
 505:         $data['qstats']['module'][$mk]['recurrence_perc'] = round(100 * $mv['recurrence'] / $data['qstats']['recurrence']);
 506:         $data['qstats']['module'][$mk]['average_score'] = ($mv['average_score'] / $mv['qnum']);
 507:         $data['qstats']['module'][$mk]['average_score_perc'] = round(100 * $mv['average_score_perc'] / $mv['recurrence']);
 508:         $data['qstats']['module'][$mk]['average_time'] = ($mv['average_time'] / $mv['qnum']);
 509:         $data['qstats']['module'][$mk]['right_perc'] = round(100 * $mv['right'] / $mv['recurrence']);
 510:         $data['qstats']['module'][$mk]['wrong_perc'] = round(100 * $mv['wrong'] / $mv['recurrence']);
 511:         $data['qstats']['module'][$mk]['unanswered_perc'] = round(100 * $mv['unanswered'] / $mv['recurrence']);
 512:         $data['qstats']['module'][$mk]['undisplayed_perc'] = round(100 * $mv['undisplayed'] / $mv['recurrence']);
 513:         $data['qstats']['module'][$mk]['unrated_perc'] = round(100 * $mv['unrated'] / $mv['recurrence']);
 514:         foreach ($mv['subject'] as $sk => $sv) {
 515:             $data['qstats']['module'][$mk]['subject'][$sk]['recurrence_perc'] = round(100 * $sv['recurrence'] / $data['qstats']['recurrence']);
 516:             $data['qstats']['module'][$mk]['subject'][$sk]['average_score'] = ($sv['average_score'] / $sv['qnum']);
 517:             $data['qstats']['module'][$mk]['subject'][$sk]['average_score_perc'] = round(100 * $sv['average_score_perc'] / $sv['recurrence']);
 518:             $data['qstats']['module'][$mk]['subject'][$sk]['average_time'] = ($sv['average_time'] / $sv['qnum']);
 519:             $data['qstats']['module'][$mk]['subject'][$sk]['right_perc'] = round(100 * $sv['right'] / $sv['recurrence']);
 520:             $data['qstats']['module'][$mk]['subject'][$sk]['wrong_perc'] = round(100 * $sv['wrong'] / $sv['recurrence']);
 521:             $data['qstats']['module'][$mk]['subject'][$sk]['unanswered_perc'] = round(100 * $sv['unanswered'] / $sv['recurrence']);
 522:             $data['qstats']['module'][$mk]['subject'][$sk]['undisplayed_perc'] = round(100 * $sv['undisplayed'] / $sv['recurrence']);
 523:             $data['qstats']['module'][$mk]['subject'][$sk]['unrated_perc'] = round(100 * $sv['unrated'] / $sv['recurrence']);
 524:             foreach ($sv['question'] as $qk => $qv) {
 525:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['recurrence_perc'] = round(100 * $qv['recurrence'] / $data['qstats']['recurrence']);
 526:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['average_score'] = ($qv['average_score'] / $qv['qnum']);
 527:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['average_score_perc'] = round(100 * $qv['average_score_perc'] / $qv['recurrence']);
 528:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['average_time'] = ($qv['average_time'] / $qv['qnum']);
 529:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['right_perc'] = round(100 * $qv['right'] / $qv['recurrence']);
 530:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['wrong_perc'] = round(100 * $qv['wrong'] / $qv['recurrence']);
 531:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['unanswered_perc'] = round(100 * $qv['unanswered'] / $qv['recurrence']);
 532:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['undisplayed_perc'] = round(100 * $qv['undisplayed'] / $qv['recurrence']);
 533:                 $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['unrated_perc'] = round(100 * $qv['unrated'] / $qv['recurrence']);
 534:                 foreach ($qv['answer'] as $ak => $av) {
 535:                     $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['answer'][$ak]['recurrence_perc'] = round(100 * $av['recurrence'] / $qv['anum']);
 536:                     $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['answer'][$ak]['right_perc'] = round(100 * $av['right'] / $av['recurrence']);
 537:                     $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['answer'][$ak]['wrong_perc'] = round(100 * $av['wrong'] / $av['recurrence']);
 538:                     $data['qstats']['module'][$mk]['subject'][$sk]['question'][$qk]['answer'][$ak]['unanswered_perc'] = round(100 * $av['unanswered'] / $av['recurrence']);
 539:                 }
 540:             }
 541:         }
 542:     }
 543:     return $data;
 544: }
 545: 
 546: /**
 547: * Returns test stats as HTML table
 548: * @param $test_id (int) test ID.
 549: * @param $group_id (int) group ID - if greater than zero, filter stats for the specified user group.
 550: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
 551: * @param $startdate (int) start date ID - if greater than zero, filter stats for the specified starting date
 552: * @param $enddate (int) end date ID - if greater than zero, filter stats for the specified ending date
 553: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
 554: * @param $ts (array) array of stats to print (leave empty to automatically generate new data).
 555: * @param $display_mode display (int) mode: 0 = disabled; 1 = minimum; 2 = module; 3 = subject; 4 = question; 5 = answer.
 556: * @param $pubmode (boolean) If true filter the results for the public interface.
 557: * return $data string containing HTML table.
 558: */
 559: function F_printTestStat($test_id, $group_id = 0, $user_id = 0, $startdate = 0, $enddate = 0, $testuser_id = 0, $ts = array(), $display_mode = 2, $pubmode = false)
 560: {
 561:     if ($display_mode < 2) {
 562:         return;
 563:     }
 564:     require_once('../config/tce_config.php');
 565:     require_once('../../shared/code/tce_functions_tcecode.php');
 566:     global $db, $l;
 567:     if (empty($ts['qstats']['recurrence'])) {
 568:         return;
 569:     }
 570:     $test_id = intval($test_id);
 571:     $user_id = intval($user_id);
 572:     $testuser_id = intval($testuser_id);
 573:     if (empty($ts)) {
 574:         // get statistics array
 575:         $ts = F_getTestStat($test_id, $group_id, $user_id, $startdate, $enddate, $testuser_id, $pubmode);
 576:     }
 577:     if ($l['a_meta_dir'] == 'rtl') {
 578:         $txtdir = 'right';
 579:     } else {
 580:         $txtdir = 'left';
 581:     }
 582:     $ret = '';
 583:     $ret .= '<table class="userselect">'.K_NEWLINE;
 584:     $ret .= '<tr><td colspan="12" style="background-color:#DDDDDD;"><strong>'.$l['w_statistics'].' ['.$l['w_all'].' + '.$l['w_module'].'';
 585:     if ($display_mode > 2) {
 586:         $ret .= ' + '.$l['w_subject'].'';
 587:         if ($display_mode > 3) {
 588:             $ret .= ' + '.$l['w_question'].'';
 589:             if ($display_mode > 4) {
 590:                 $ret .= ' + '.$l['w_answer'].'';
 591:             }
 592:         }
 593:     }
 594:     $ret .= ']</strong></td></tr>'.K_NEWLINE;
 595:     $ret .= '<tr>'.K_NEWLINE;
 596:     $ret .= '<th title="'.$l['w_module'].'">M#</th>'.K_NEWLINE;
 597:     $ret .= '<th title="'.$l['w_subject'].'">S#</th>'.K_NEWLINE;
 598:     $ret .= '<th title="'.$l['w_question'].'">Q#</th>'.K_NEWLINE;
 599:     $ret .= '<th title="'.$l['w_answer'].'">A#</th>'.K_NEWLINE;
 600:     $ret .= '<th title="'.$l['h_question_recurrence'].'">'.$l['w_recurrence'].'</th>'.K_NEWLINE;
 601:     $ret .= '<th title="'.$l['h_score_average'].'">'.$l['w_score'].'</th>'.K_NEWLINE;
 602:     $ret .= '<th title="'.$l['h_answer_time'].'">'.$l['w_answer_time'].'</th>'.K_NEWLINE;
 603:     $ret .= '<th title="'.$l['h_answers_right'].'">'.$l['w_answers_right'].'</th>'.K_NEWLINE;
 604:     $ret .= '<th title="'.$l['h_answers_wrong'].'">'.$l['w_answers_wrong'].'</th>'.K_NEWLINE;
 605:     $ret .= '<th title="'.$l['h_questions_unanswered'].'">'.$l['w_questions_unanswered'].'</th>'.K_NEWLINE;
 606:     $ret .= '<th title="'.$l['h_questions_undisplayed'].'">'.$l['w_questions_undisplayed'].'</th>'.K_NEWLINE;
 607:     $ret .= '<th title="'.$l['h_questions_unrated'].'">'.$l['w_questions_unrated'].'</th>'.K_NEWLINE;
 608:     $ret .= '</tr>'.K_NEWLINE;
 609:     $ret .= '<tr style="background-color:#FFEEEE;">';
 610:     $ret .= '<td colspan="4">'.$l['w_all'].'</td>'.K_NEWLINE;
 611:     $ret .= '<td class="numeric">'.$ts['qstats']['recurrence'].' '.F_formatPercentage($ts['qstats']['recurrence_perc'], false).'</td>'.K_NEWLINE;
 612:     $ret .= '<td class="numeric">'.($ts['qstats']['average_score_perc']).'%</td>'.K_NEWLINE;
 613:     $ret .= '<td class="numeric">&nbsp;'.date('i:s', $ts['qstats']['average_time']).'</td>'.K_NEWLINE;
 614:     $ret .= '<td class="numeric">'.$ts['qstats']['right'].' '.F_formatPercentage($ts['qstats']['right_perc'], false).'</td>'.K_NEWLINE;
 615:     $ret .= '<td class="numeric">'.$ts['qstats']['wrong'].' '.F_formatPercentage($ts['qstats']['wrong_perc'], false).'</td>'.K_NEWLINE;
 616:     $ret .= '<td class="numeric">'.$ts['qstats']['unanswered'].' '.F_formatPercentage($ts['qstats']['unanswered_perc'], false).'</td>'.K_NEWLINE;
 617:     $ret .= '<td class="numeric">'.$ts['qstats']['undisplayed'].' '.F_formatPercentage($ts['qstats']['undisplayed_perc'], false).'</td>'.K_NEWLINE;
 618:     $ret .= '<td class="numeric">'.$ts['qstats']['unrated'].' '.F_formatPercentage($ts['qstats']['unrated_perc'], false).'</td>'.K_NEWLINE;
 619:     $ret .= '</tr>'.K_NEWLINE;
 620:     $num_module = 0;
 621:     foreach ($ts['qstats']['module'] as $module) {
 622:         $num_module++;
 623:         $ret .= '<tr style="background-color:#DDEEFF;">';
 624:         if ($pubmode) {
 625:             $ret .= '<td rowspan="2" valign="middle"><strong>M'.$num_module.'</strong></td>'.K_NEWLINE;
 626:         } else {
 627:             $ret .= '<td rowspan="2" valign="middle"><a href="tce_edit_module.php?module_id='.$module['id'].'" title="'.$l['t_modules_editor'].'"><strong>M'.$num_module.'</strong></a></td>'.K_NEWLINE;
 628:         }
 629:         $ret .= '<td rowspan="2" colspan="3">&nbsp;</td>'.K_NEWLINE;
 630:         $ret .= '<td class="numeric">'.$module['recurrence'].' '.F_formatPercentage($module['recurrence_perc'], false).'</td>'.K_NEWLINE;
 631:         $ret .= '<td class="numeric">'.($module['average_score_perc']).'%</td>'.K_NEWLINE;
 632:         $ret .= '<td class="numeric">&nbsp;'.date('i:s', $module['average_time']).'</td>'.K_NEWLINE;
 633:         $ret .= '<td class="numeric">'.$module['right'].' '.F_formatPercentage($module['right_perc'], false).'</td>'.K_NEWLINE;
 634:         $ret .= '<td class="numeric">'.$module['wrong'].' '.F_formatPercentage($module['wrong_perc'], false).'</td>'.K_NEWLINE;
 635:         $ret .= '<td class="numeric">'.$module['unanswered'].' '.F_formatPercentage($module['unanswered_perc'], false).'</td>'.K_NEWLINE;
 636:         $ret .= '<td class="numeric">'.$module['undisplayed'].' '.F_formatPercentage($module['undisplayed_perc'], false).'</td>'.K_NEWLINE;
 637:         $ret .= '<td class="numeric">'.$module['unrated'].' '.F_formatPercentage($module['unrated_perc'], false).'</td>'.K_NEWLINE;
 638:         $ret .= '</tr>'.K_NEWLINE;
 639:         $ret .= '<tr>';
 640:         $ret .= '<td colspan="8" align="'.$txtdir.'" style="background-color:white;">'.F_decode_tcecode($module['name']).'</td>';
 641:         $ret .= '</tr>'.K_NEWLINE;
 642:         if ($display_mode > 2) {
 643:             $num_subject = 0;
 644:             foreach ($module['subject'] as $subject) {
 645:                 $num_subject++;
 646:                 $ret .= '<tr style="background-color:#DDFFDD;">';
 647:                 $ret .= '<td rowspan="2" style="background-color:#DDEEFF;">M'.$num_module.'</td>'.K_NEWLINE;
 648:                 if ($pubmode) {
 649:                     $ret .= '<td rowspan="2" valign="middle"><strong>S'.$num_subject.'</strong></td>'.K_NEWLINE;
 650:                 } else {
 651:                     $ret .= '<td rowspan="2" valign="middle"><a href="tce_edit_subject.php?subject_id='.$subject['id'].'" title="'.$l['t_subjects_editor'].'"><strong>S'.$num_subject.'</strong></a></td>'.K_NEWLINE;
 652:                 }
 653:                 $ret .= '<td rowspan="2" colspan="2">&nbsp;</td>'.K_NEWLINE;
 654:                 $ret .= '<td class="numeric">'.$subject['recurrence'].' '.F_formatPercentage($subject['recurrence_perc'], false).'</td>'.K_NEWLINE;
 655:                 $ret .= '<td class="numeric">'.($subject['average_score_perc']).'%</td>'.K_NEWLINE;
 656:                 $ret .= '<td class="numeric">&nbsp;'.date('i:s', $subject['average_time']).'</td>'.K_NEWLINE;
 657:                 $ret .= '<td class="numeric">'.$subject['right'].' '.F_formatPercentage($subject['right_perc'], false).'</td>'.K_NEWLINE;
 658:                 $ret .= '<td class="numeric">'.$subject['wrong'].' '.F_formatPercentage($subject['wrong_perc'], false).'</td>'.K_NEWLINE;
 659:                 $ret .= '<td class="numeric">'.$subject['unanswered'].' '.F_formatPercentage($subject['unanswered_perc'], false).'</td>'.K_NEWLINE;
 660:                 $ret .= '<td class="numeric">'.$subject['undisplayed'].' '.F_formatPercentage($subject['undisplayed_perc'], false).'</td>'.K_NEWLINE;
 661:                 $ret .= '<td class="numeric">'.$subject['unrated'].' '.F_formatPercentage($subject['unrated_perc'], false).'</td>'.K_NEWLINE;
 662:                 $ret .= '</tr>'.K_NEWLINE;
 663:                 $ret .= '<tr>';
 664:                 $ret .= '<td colspan="8" align="'.$txtdir.'" style="background-color:white;">'.F_decode_tcecode($subject['name']).'</td>';
 665:                 $ret .= '</tr>'.K_NEWLINE;
 666:                 if ($display_mode > 3) {
 667:                     $num_question = 0;
 668:                     foreach ($subject['question'] as $question) {
 669:                         $num_question++;
 670:                         $ret .= '<tr style="background-color:#FFFACD;">';
 671:                         $ret .= '<td rowspan="2" style="background-color:#DDEEFF;">M'.$num_module.'</td>'.K_NEWLINE;
 672:                         $ret .= '<td rowspan="2" style="background-color:#DDFFDD;">S'.$num_subject.'</td>'.K_NEWLINE;
 673:                         if ($pubmode) {
 674:                             $ret .= '<td rowspan="2" valign="middle"><strong>Q'.$num_question.'</strong></td>'.K_NEWLINE;
 675:                         } else {
 676:                             $ret .= '<td rowspan="2" valign="middle"><a href="tce_edit_question.php?question_id='.$question['id'].'" title="'.$l['t_questions_editor'].'"><strong>Q'.$num_question.'</strong></a></td>'.K_NEWLINE;
 677:                         }
 678:                         $ret .= '<td rowspan="2">&nbsp;</td>'.K_NEWLINE;
 679:                         $ret .= '<td class="numeric">'.$question['recurrence'].' '.F_formatPercentage($question['recurrence_perc'], false).'</td>'.K_NEWLINE;
 680:                         $ret .= '<td class="numeric">'.($question['average_score_perc']).'%</td>'.K_NEWLINE;
 681:                         $ret .= '<td class="numeric">&nbsp;'.date('i:s', $question['average_time']).'</td>'.K_NEWLINE;
 682:                         $ret .= '<td class="numeric">'.$question['right'].' '.F_formatPercentage($question['right_perc'], false).'</td>'.K_NEWLINE;
 683:                         $ret .= '<td class="numeric">'.$question['wrong'].' '.F_formatPercentage($question['wrong_perc'], false).'</td>'.K_NEWLINE;
 684:                         $ret .= '<td class="numeric">'.$question['unanswered'].' '.F_formatPercentage($question['unanswered_perc'], false).'</td>'.K_NEWLINE;
 685:                         $ret .= '<td class="numeric">'.$question['undisplayed'].' '.F_formatPercentage($question['undisplayed_perc'], false).'</td>'.K_NEWLINE;
 686:                         $ret .= '<td class="numeric">'.$question['unrated'].' '.F_formatPercentage($question['unrated_perc'], false).'</td>'.K_NEWLINE;
 687:                         $ret .= '</tr>'.K_NEWLINE;
 688:                         $ret .= '<tr>';
 689:                         $ret .= '<td colspan="8" align="'.$txtdir.'" style="background-color:white;">'.F_decode_tcecode($question['description']).'</td>';
 690:                         $ret .= '</tr>'.K_NEWLINE;
 691:                         if ($display_mode > 4) {
 692:                             $num_answer = 0;
 693:                             foreach ($question['answer'] as $answer) {
 694:                                 $num_answer++;
 695:                                 $ret .= '<tr style="">';
 696:                                 $ret .= '<td rowspan="2" style="background-color:#DDEEFF;">M'.$num_module.'</td>'.K_NEWLINE;
 697:                                 $ret .= '<td rowspan="2" style="background-color:#DDFFDD;">S'.$num_subject.'</td>'.K_NEWLINE;
 698:                                 $ret .= '<td rowspan="2" style="background-color:#FFFACD;">Q'.$num_question.'</td>'.K_NEWLINE;
 699:                                 if ($pubmode) {
 700:                                     $ret .= '<td rowspan="2" valign="middle"><strong>A'.$num_answer.'</strong></td>'.K_NEWLINE;
 701:                                 } else {
 702:                                     $ret .= '<td rowspan="2" valign="middle"><a href="tce_edit_answer.php?answer_id='.$answer['id'].'" title="'.$l['t_answers_editor'].'"><strong>A'.$num_answer.'</strong></a></td>'.K_NEWLINE;
 703:                                 }
 704:                                 $ret .= '<td class="numeric">'.$answer['recurrence'].' '.F_formatPercentage($answer['recurrence_perc'], false).'</td>'.K_NEWLINE;
 705:                                 $ret .= '<td class="numeric">&nbsp;</td>'.K_NEWLINE;
 706:                                 $ret .= '<td class="numeric">&nbsp;</td>'.K_NEWLINE;
 707:                                 $ret .= '<td class="numeric">'.$answer['right'].' '.F_formatPercentage($answer['right_perc'], false).'</td>'.K_NEWLINE;
 708:                                 $ret .= '<td class="numeric">'.$answer['wrong'].' '.F_formatPercentage($answer['wrong_perc'], false).'</td>'.K_NEWLINE;
 709:                                 $ret .= '<td class="numeric">'.$answer['unanswered'].' '.F_formatPercentage($answer['unanswered_perc'], false).'</td>'.K_NEWLINE;
 710:                                 $ret .= '<td class="numeric">&nbsp;</td>'.K_NEWLINE;
 711:                                 $ret .= '<td class="numeric">&nbsp;</td>'.K_NEWLINE;
 712:                                 $ret .= '</tr>'.K_NEWLINE;
 713:                                 $ret .= '<tr>';
 714:                                 $ret .= '<td colspan="8" align="'.$txtdir.'" style="background-color:white;">'.F_decode_tcecode($answer['description']).'</td>';
 715:                                 $ret .= '</tr>'.K_NEWLINE;
 716:                             } // end for answer
 717:                         }
 718:                     } // end for question
 719:                 }
 720:             } // end for subject
 721:         }
 722:     } // end for module
 723:     $ret .= '</table>'.K_NEWLINE;
 724:     return $ret;
 725: }
 726: 
 727: /**
 728: * Returns test stats as HTML table
 729: * @param $data (array) Array containing test statistics.
 730: * @param $nextorderdir (int) next order direction.
 731: * @param $order_field (string) order fields.
 732: * @param $filter (string) filter string for URLs.
 733: * @param $pubmode (boolean) If true filter the results for the public interface.
 734: * @param $stats (int) 2 = full stats; 1 = user stats; 0 = disabled stats;
 735: * return HTML table string.
 736: */
 737: function F_printTestResultStat($data, $nextorderdir, $order_field, $filter, $pubmode = false, $stats = 1)
 738: {
 739:     require_once('../config/tce_config.php');
 740:     global $db, $l;
 741:     if (empty($data['num_records'])) {
 742:         return;
 743:     }
 744:     if ($l['a_meta_dir'] == 'rtl') {
 745:         $tdalignr = 'left';
 746:         $tdalign = 'right';
 747:     } else {
 748:         $tdalignr = 'right';
 749:         $tdalign = 'left';
 750:     }
 751:     $ret = '';
 752:     $ret .= '<table class="userselect">'.K_NEWLINE;
 753:     $ret .= '<tr>'.K_NEWLINE;
 754:     $ret .= '<th>&nbsp;</th>'.K_NEWLINE;
 755:     $ret .= '<th>#</th>'.K_NEWLINE;
 756:     $ret .= F_select_table_header_element('testuser_creation_time', $nextorderdir, $l['h_time_begin'], $l['w_time_begin'], $order_field, $filter);
 757:     //$ret .= F_select_table_header_element('testuser_end_time', $nextorderdir, $l['h_time_end'], $l['w_time_end'], $order_field, $filter);
 758:     $ret .= '<th title="'.$l['h_test_time'].'">'.$l['w_time'].'</th>'.K_NEWLINE;
 759:     $ret .= F_select_table_header_element('testuser_test_id', $nextorderdir, $l['h_test'], $l['w_test'], $order_field, $filter);
 760:     if (!$pubmode) {
 761:         $ret .= F_select_table_header_element('user_name', $nextorderdir, $l['h_login_name'], $l['w_user'], $order_field, $filter);
 762:         $ret .= F_select_table_header_element('user_lastname', $nextorderdir, $l['h_lastname'], $l['w_lastname'], $order_field, $filter);
 763:         $ret .= F_select_table_header_element('user_firstname', $nextorderdir, $l['h_firstname'], $l['w_firstname'], $order_field, $filter);
 764:     }
 765:     $ret .= F_select_table_header_element('total_score', $nextorderdir, $l['h_score_total'], $l['w_score'], $order_field, $filter);
 766:     if ($stats > 0) {
 767:         $ret .= '<th title="'.$l['h_answers_right'].'">'.$l['w_answers_right'].'</th>'.K_NEWLINE;
 768:         $ret .= '<th title="'.$l['h_answers_wrong'].'">'.$l['w_answers_wrong'].'</th>'.K_NEWLINE;
 769:         $ret .= '<th title="'.$l['h_questions_unanswered'].'">'.$l['w_questions_unanswered'].'</th>'.K_NEWLINE;
 770:         $ret .= '<th title="'.$l['h_questions_undisplayed'].'">'.$l['w_questions_undisplayed'].'</th>'.K_NEWLINE;
 771:         $ret .= '<th title="'.$l['h_questions_unrated'].'">'.$l['w_questions_unrated'].'</th>'.K_NEWLINE;
 772:     }
 773:     $ret .= '<th title="'.$l['w_status'].' ('.$l['w_time'].' ['.$l['w_minutes'].'])">'.$l['w_status'].' ('.$l['w_time'].' ['.$l['w_minutes'].'])</th>'.K_NEWLINE;
 774:     $ret .= '<th title="'.$l['h_testcomment'].'">'.$l['w_comment'].'</th>'.K_NEWLINE;
 775:     $ret .= '</tr>'.K_NEWLINE;
 776:     foreach ($data['testuser'] as $tu) {
 777:         $ret .= '<tr>';
 778:         $ret .= '<td>';
 779:         $ret .= '<input type="checkbox" name="testuserid'.$tu['num'].'" id="testuserid'.$tu['num'].'" value="'.$tu['id'].'" title="'.$l['w_select'].'"';
 780:         if (isset($_REQUEST['checkall']) and ($_REQUEST['checkall'] == 1)) {
 781:             $ret .= ' checked="checked"';
 782:         }
 783:         $ret .= ' />';
 784:         $ret .= '</td>'.K_NEWLINE;
 785:         if (!$pubmode or F_getBoolean($tu['test']['test_report_to_users'])) {
 786:             $ret .= '<td><a href="tce_show_result_user.php?testuser_id='.$tu['id'].'&amp;test_id='.$tu['test']['test_id'].'&amp;user_id='.$tu['user_id'].'" title="'.$l['h_view_details'].'">'.$tu['num'].'</a></td>'.K_NEWLINE;
 787:         } else {
 788:             $ret .= '<td>'.$tu['num'].'</td>'.K_NEWLINE;
 789:         }
 790:         $ret .= '<td style="text-align:center;">'.$tu['testuser_creation_time'].'</td>'.K_NEWLINE;
 791:         //$ret .= '<td style="text-align:center;">'.$tu['testuser_end_time'].'</td>'.K_NEWLINE;
 792:         $ret .= '<td style="text-align:center;">'.$tu['time_diff'].'</td>'.K_NEWLINE;
 793:         $passmsg = '';
 794:         if ($tu['passmsg'] === true) {
 795:             $passmsg = ' title="'.$l['w_passed'].'" style="background-color:#BBFFBB;"';
 796:         } elseif ($tu['passmsg'] === false) {
 797:             $passmsg = ' title="'.$l['w_not_passed'].'" style="background-color:#FFBBBB;"';
 798:         }
 799:         if ($pubmode) {
 800:             $ret .= '<td style="text-align:'.$tdalign.';">'.$tu['test']['test_name'].'</td>'.K_NEWLINE;
 801:         } else {
 802:             $ret .= '<td style="text-align:'.$tdalign.';"><a href="tce_edit_test.php?test_id='.$tu['test']['test_id'].'">'.$tu['test']['test_name'].'</a></td>'.K_NEWLINE;
 803:             $ret .= '<td style="text-align:'.$tdalign.';"><a href="tce_edit_user.php?user_id='.$tu['user_id'].'">'.$tu['user_name'].'</a></td>'.K_NEWLINE;
 804:             $ret .= '<td style="text-align:'.$tdalign.';">&nbsp;'.$tu['user_lastname'].'</td>'.K_NEWLINE;
 805:             $ret .= '<td style="text-align:'.$tdalign.';">&nbsp;'.$tu['user_firstname'].'</td>'.K_NEWLINE;
 806:         }
 807:         $ret .= '<td'.$passmsg.' class="numeric">'.F_formatFloat($tu['total_score']).'&nbsp;'.F_formatPercentage($tu['total_score_perc'], false).'</td>'.K_NEWLINE;
 808:         if ($stats > 0) {
 809:             $ret .= '<td class="numeric">'.$tu['right'].'&nbsp;'.F_formatPercentage($tu['right_perc'], false).'</td>'.K_NEWLINE;
 810:             $ret .= '<td class="numeric">'.$tu['wrong'].'&nbsp;'.F_formatPercentage($tu['wrong_perc'], false).'</td>'.K_NEWLINE;
 811:             $ret .= '<td class="numeric">'.$tu['unanswered'].'&nbsp;'.F_formatPercentage($tu['unanswered_perc'], false).'</td>'.K_NEWLINE;
 812:             $ret .= '<td class="numeric">'.$tu['undisplayed'].'&nbsp;'.F_formatPercentage($tu['undisplayed_perc'], false).'</td>'.K_NEWLINE;
 813:             $ret .= '<td class="numeric">'.$tu['unrated'].'&nbsp;'.F_formatPercentage($tu['unrated_perc'], false).'</td>'.K_NEWLINE;
 814:         }
 815:         if ($tu['locked']) {
 816:             $ret .= '<td style="background-color:#FFBBBB;">'.$l['w_locked'];
 817:         } else {
 818:             $ret .= '<td style="background-color:#BBFFBB;">'.$l['w_unlocked'];
 819:         }
 820:         if ($tu['remaining_time'] < 0) {
 821:             $ret .= ' ('.$tu['remaining_time'].')';
 822:         }
 823:         $ret .= '</td>'.K_NEWLINE;
 824:         if (!empty($tu['user_comment'])) {
 825:             $ret .= '<td title="'.substr(F_compact_string(htmlspecialchars($tu['user_comment'], ENT_NOQUOTES, $l['a_meta_charset'])), 0, 255).'">'.$l['w_yes'].'</td>'.K_NEWLINE;
 826:         } else {
 827:             $ret .= '<td>&nbsp;</td>'.K_NEWLINE;
 828:         }
 829:         $ret .= '</tr>'.K_NEWLINE;
 830:     }
 831:     $ret .= '<tr>';
 832:     $colspan = 16;
 833:     if ($pubmode) {
 834:         $colspan -= 3;
 835:     }
 836:     if ($stats == 0) {
 837:         $colspan -= 5;
 838:     }
 839:     $ret .= '<td colspan="'.$colspan.'" style="text-align:'.$tdalign.';font-weight:bold;padding-right:10px;padding-left:10px;';
 840:     if ($data['passed_perc'] > 50) {
 841:         $ret .= ' background-color:#BBFFBB;"';
 842:     } else {
 843:         $ret .= ' background-color:#FFBBBB;"';
 844:     }
 845:     $ret .= '>'.$l['w_passed'].': '.$data['passed'].' '.F_formatPercentage($data['passed_perc'], false).'</td>'.K_NEWLINE;
 846:     $ret .= '</tr>';
 847:     // print statistics
 848:     $printstat = array('mean', 'median', 'mode', 'standard_deviation', 'skewness', 'kurtosi');
 849:     $noperc = array('skewness', 'kurtosi');
 850:     foreach ($data['statistics'] as $row => $col) {
 851:         if (in_array($row, $printstat)) {
 852:             $ret .= '<tr>';
 853:             $scolspan = 8;
 854:             if ($pubmode) {
 855:                 $scolspan -= 3;
 856:             }
 857:             $ret .= '<th colspan="'.$scolspan.'" style="text-align:'.$tdalignr.';">'.$l['w_'.$row].'</th>'.K_NEWLINE;
 858:             if (in_array($row, $noperc)) {
 859:                 $ret .= '<td class="numeric">'.F_formatFloat($col['score_perc']).'</td>'.K_NEWLINE;
 860:                 if ($stats > 0) {
 861:                     $ret .= '<td class="numeric">'.F_formatFloat($col['right_perc']).'</td>'.K_NEWLINE;
 862:                     $ret .= '<td class="numeric">'.F_formatFloat($col['wrong_perc']).'</td>'.K_NEWLINE;
 863:                     $ret .= '<td class="numeric">'.F_formatFloat($col['unanswered_perc']).'</td>'.K_NEWLINE;
 864:                     $ret .= '<td class="numeric">'.F_formatFloat($col['undisplayed_perc']).'</td>'.K_NEWLINE;
 865:                     $ret .= '<td class="numeric">'.F_formatFloat($col['unrated_perc']).'</td>'.K_NEWLINE;
 866:                 }
 867:             } else {
 868:                 $ret .= '<td class="numeric">'.round($col['score_perc']).'%</td>'.K_NEWLINE;
 869:                 if ($stats > 0) {
 870:                     $ret .= '<td class="numeric">'.round($col['right_perc']).'%</td>'.K_NEWLINE;
 871:                     $ret .= '<td class="numeric">'.round($col['wrong_perc']).'%</td>'.K_NEWLINE;
 872:                     $ret .= '<td class="numeric">'.round($col['unanswered_perc']).'%</td>'.K_NEWLINE;
 873:                     $ret .= '<td class="numeric">'.round($col['undisplayed_perc']).'%</td>'.K_NEWLINE;
 874:                     $ret .= '<td class="numeric">'.round($col['unrated_perc']).'%</td>'.K_NEWLINE;
 875:                 }
 876:             }
 877:             $ret .= '<td colspan="2">&nbsp;</td>'.K_NEWLINE;
 878:             $ret .= '</tr>';
 879:         }
 880:     }
 881:     $ret .= '</table>'.K_NEWLINE;
 882:     return $ret;
 883: }
 884: 
 885: /**
 886: * Returns user test stats as HTML table
 887: * @param $testuser_id (int) test-user ID - if greater than zero, filter stats for the specified test-user.
 888: * return $data string containing HTML table.
 889: */
 890: function F_printUserTestStat($testuser_id)
 891: {
 892:     require_once('../config/tce_config.php');
 893:     require_once('../../shared/code/tce_functions_tcecode.php');
 894:     global $db, $l;
 895:     $testuser_id = intval($testuser_id);
 896: 
 897:     $ret = '';
 898: 
 899:     // display user questions
 900:     $sql = 'SELECT *
 901:         FROM '.K_TABLE_QUESTIONS.', '.K_TABLE_TESTS_LOGS.', '.K_TABLE_SUBJECTS.', '.K_TABLE_MODULES.'
 902:         WHERE question_id=testlog_question_id
 903:             AND testlog_testuser_id='.$testuser_id.'
 904:             AND question_subject_id=subject_id
 905:             AND subject_module_id=module_id
 906:         ORDER BY testlog_id';
 907:     if ($r = F_db_query($sql, $db)) {
 908:         $ret .= '<ol class="question">'.K_NEWLINE;
 909:         while ($m = F_db_fetch_array($r)) {
 910:             $ret .= '<li>'.K_NEWLINE;
 911:             // display question stats
 912:             $ret .= '<strong>['.$m['testlog_score'].']'.K_NEWLINE;
 913:             $ret .= ' (';
 914:             $ret .= 'IP:'.getIpAsString($m['testlog_user_ip']).K_NEWLINE;
 915:             if (isset($m['testlog_display_time']) and (strlen($m['testlog_display_time']) > 0)) {
 916:                 $ret .= ' | '.substr($m['testlog_display_time'], 11, 8).K_NEWLINE;
 917:             } else {
 918:                 $ret .= ' | --:--:--'.K_NEWLINE;
 919:             }
 920:             if (isset($m['testlog_change_time']) and (strlen($m['testlog_change_time']) > 0)) {
 921:                 $ret .= ' | '.substr($m['testlog_change_time'], 11, 8).K_NEWLINE;
 922:             } else {
 923:                 $ret .= ' | --:--:--'.K_NEWLINE;
 924:             }
 925:             if (isset($m['testlog_display_time']) and isset($m['testlog_change_time'])) {
 926:                 $ret .= ' | '.date('i:s', (strtotime($m['testlog_change_time']) - strtotime($m['testlog_display_time']))).'';
 927:             } else {
 928:                 $ret .= ' | --:--'.K_NEWLINE;
 929:             }
 930:             if (isset($m['testlog_reaction_time']) and ($m['testlog_reaction_time'] > 0)) {
 931:                 $ret .= ' | '.($m['testlog_reaction_time']/1000).'';
 932:             } else {
 933:                 $ret .= ' | ------'.K_NEWLINE;
 934:             }
 935:             $ret .= ')</strong>'.K_NEWLINE;
 936:             $ret .= '<br />'.K_NEWLINE;
 937:             // display question description
 938:             $ret .= F_decode_tcecode($m['question_description']).K_NEWLINE;
 939:             if (K_ENABLE_QUESTION_EXPLANATION and !empty($m['question_explanation'])) {
 940:                 $ret .= '<br /><span class="explanation">'.$l['w_explanation'].':</span><br />'.F_decode_tcecode($m['question_explanation']).''.K_NEWLINE;
 941:             }
 942:             if ($m['question_type'] == 3) {
 943:                 // TEXT
 944:                 $ret .= '<ul class="answer"><li>'.K_NEWLINE;
 945:                 $ret .= F_decode_tcecode($m['testlog_answer_text']);
 946:                 $ret .= '&nbsp;</li></ul>'.K_NEWLINE;
 947:             } else {
 948:                 $ret .= '<ol class="answer">'.K_NEWLINE;
 949:                 // display each answer option
 950:                 $sqla = 'SELECT *
 951:                     FROM '.K_TABLE_LOG_ANSWER.', '.K_TABLE_ANSWERS.'
 952:                     WHERE logansw_answer_id=answer_id
 953:                         AND logansw_testlog_id=\''.$m['testlog_id'].'\'
 954:                     ORDER BY logansw_order';
 955:                 if ($ra = F_db_query($sqla, $db)) {
 956:                     while ($ma = F_db_fetch_array($ra)) {
 957:                         $ret .= '<li>';
 958:                         if ($m['question_type'] == 4) {
 959:                             // ORDER
 960:                             if ($ma['logansw_position'] > 0) {
 961:                                 if ($ma['logansw_position'] == $ma['answer_position']) {
 962:                                     $ret .= '<acronym title="'.$l['h_answer_right'].'" class="okbox">'.$ma['logansw_position'].'</acronym>';
 963:                                 } else {
 964:                                     $ret .= '<acronym title="'.$l['h_answer_wrong'].'" class="nobox">'.$ma['logansw_position'].'</acronym>';
 965:                                 }
 966:                             } else {
 967:                                 $ret .= '<acronym title="'.$l['m_unanswered'].'" class="offbox">&nbsp;</acronym>';
 968:                             }
 969:                         } elseif ($ma['logansw_selected'] > 0) {
 970:                             if (F_getBoolean($ma['answer_isright'])) {
 971:                                 $ret .= '<acronym title="'.$l['h_answer_right'].'" class="okbox">x</acronym>';
 972:                             } else {
 973:                                 $ret .= '<acronym title="'.$l['h_answer_wrong'].'" class="nobox">x</acronym>';
 974:                             }
 975:                         } elseif ($m['question_type'] == 1) {
 976:                             // MCSA
 977:                             $ret .= '<acronym title="-" class="offbox">&nbsp;</acronym>';
 978:                         } else {
 979:                             if ($ma['logansw_selected'] == 0) {
 980:                                 if (F_getBoolean($ma['answer_isright'])) {
 981:                                     $ret .= '<acronym title="'.$l['h_answer_wrong'].'" class="nobox">&nbsp;</acronym>';
 982:                                 } else {
 983:                                     $ret .= '<acronym title="'.$l['h_answer_right'].'" class="okbox">&nbsp;</acronym>';
 984:                                 }
 985:                             } else {
 986:                                 $ret .= '<acronym title="'.$l['m_unanswered'].'" class="offbox">&nbsp;</acronym>';
 987:                             }
 988:                         }
 989:                         $ret .= '&nbsp;';
 990:                         if ($m['question_type'] == 4) {
 991:                             $ret .= '<acronym title="'.$l['w_position'].'" class="onbox">'.$ma['answer_position'].'</acronym>';
 992:                         } elseif (F_getBoolean($ma['answer_isright'])) {
 993:                             $ret .= '<acronym title="'.$l['w_answers_right'].'" class="onbox">&reg;</acronym>';
 994:                         } else {
 995:                             $ret .= '<acronym title="'.$l['w_answers_wrong'].'" class="offbox">&nbsp;</acronym>';
 996:                         }
 997:                         $ret .= ' ';
 998:                         $ret .= F_decode_tcecode($ma['answer_description']);
 999:                         if (K_ENABLE_ANSWER_EXPLANATION and !empty($ma['answer_explanation'])) {
1000:                             $ret .= '<br /><span class="explanation">'.$l['w_explanation'].':</span><br />'.F_decode_tcecode($ma['answer_explanation']).''.K_NEWLINE;
1001:                         }
1002:                         $ret .= '</li>'.K_NEWLINE;
1003:                     }
1004:                 } else {
1005:                     F_display_db_error();
1006:                 }
1007:                 $ret .= '</ol>'.K_NEWLINE;
1008:             } // end multiple answers
1009:             // display teacher/supervisor comment to the question
1010:             if (isset($m['testlog_comment']) and (!empty($m['testlog_comment']))) {
1011:                 $ret .= '<ul class="answer"><li class="comment">'.K_NEWLINE;
1012:                 $ret .= F_decode_tcecode($m['testlog_comment']);
1013:                 $ret .= '&nbsp;</li></ul>'.K_NEWLINE;
1014:             }
1015:             $ret .= '<br /><br />'.K_NEWLINE;
1016:             $ret .= '</li>'.K_NEWLINE;
1017:         }
1018:         $ret .= '</ol>'.K_NEWLINE;
1019:     } else {
1020:         F_display_db_error();
1021:     }
1022:     return $ret;
1023: }
1024: 
1025: 
1026: /**
1027: * Returns users statistic array for the selected test.
1028: * @param $test_id (int) test ID.
1029: * @param $group_id (int) group ID - if greater than zero, filter stats for the specified user group.
1030: * @param $user_id (int) user ID - if greater than zero, filter stats for the specified user.
1031: * @param $startdate (string) start date ID - if greater than zero, filter stats for the specified starting date
1032: * @param $enddate (string) end date ID - if greater than zero, filter stats for the specified ending date
1033: * @param $full_order_field (string) Ordering fields for SQL query.
1034: * @param $pubmode (boolean) If true filter the results for the public interface.
1035: * @param $stats (int) 2 = full stats; 1 = user stats; 0 = disabled stats;
1036: * return $data array containing test statistics.
1037: */
1038: function F_getAllUsersTestStat($test_id, $group_id = 0, $user_id = 0, $startdate = 0, $enddate = 0, $full_order_field = 'total_score', $pubmode = false, $stats = 2)
1039: {
1040:     require_once('../config/tce_config.php');
1041:     require_once('../../shared/code/tce_functions_test.php');
1042:     require_once('../../shared/code/tce_functions_statistics.php');
1043:     global $db, $l;
1044:     $test_id = intval($test_id);
1045:     $group_id = intval($group_id);
1046:     $user_id = intval($user_id);
1047:     $data = array();
1048:     $data['svgpoints'] = '';
1049:     $data['testuser'] = array();
1050:     $sqlr = 'SELECT
1051:         testuser_id,
1052:         testuser_test_id,
1053:         testuser_creation_time,
1054:         testuser_status,
1055:         user_id,
1056:         user_lastname,
1057:         user_firstname,
1058:         user_name,
1059:         user_email,
1060:         SUM(testlog_score) AS total_score,
1061:         MAX(testlog_change_time) AS testuser_end_time
1062:         FROM '.K_TABLE_TESTS_LOGS.', '.K_TABLE_TEST_USER.', '.K_TABLE_USERS.'';
1063:     if ($group_id > 0) {
1064:         $sqlr .= ','.K_TABLE_USERGROUP.'';
1065:     }
1066:     $sqlr .= ' WHERE testlog_testuser_id=testuser_id AND testuser_user_id=user_id';
1067:     if ($test_id > 0) {
1068:         $sqlr .= ' AND testuser_test_id='.$test_id.'';
1069:     } elseif ($pubmode) {
1070:         $sqlr .= ' AND testuser_test_id IN ('.F_getTestIDResults($test_id, $user_id).')';
1071:     }
1072:     if ($group_id > 0) {
1073:         $sqlr .= ' AND usrgrp_user_id=user_id AND usrgrp_group_id='.$group_id.'';
1074:     }
1075:     if ($user_id > 0) {
1076:         $sqlr .= ' AND user_id='.$user_id.'';
1077:     }
1078:     if (!empty($startdate)) {
1079:         $startdate_time = strtotime($startdate);
1080:         $startdate = date(K_TIMESTAMP_FORMAT, $startdate_time);
1081:         $sqlr .= ' AND testuser_creation_time>=\''.$startdate.'\'';
1082:     }
1083:     if (!empty($enddate)) {
1084:         $enddate_time = strtotime($enddate);
1085:         $enddate = date(K_TIMESTAMP_FORMAT, $enddate_time);
1086:         $sqlr .= ' AND testuser_creation_time<=\''.$enddate.'\'';
1087:     }
1088:     if ($stats > 1) {
1089:         // get stats
1090:         $data += F_getTestStat($test_id, $group_id, $user_id, $startdate, $enddate);
1091:     }
1092:     $sqlr .= ' GROUP BY testuser_id, testuser_test_id, testuser_creation_time, user_id, user_lastname, user_firstname, user_name, user_email, testuser_status
1093:         ORDER BY '.$full_order_field.'';
1094:     if ($rr = F_db_query($sqlr, $db)) {
1095:         $itemcount = 0;
1096:         $passed = 0;
1097:         $statsdata = array();
1098:         $statsdata['score'] = array();
1099:         $statsdata['right'] = array();
1100:         $statsdata['wrong'] = array();
1101:         $statsdata['unanswered'] = array();
1102:         $statsdata['undisplayed'] = array();
1103:         $statsdata['unrated'] = array();
1104:         while ($mr = F_db_fetch_array($rr)) {
1105:             $itemcount++;
1106:             $usrtestdata = F_getUserTestStat($mr['testuser_test_id'], $mr['user_id'], $mr['testuser_id']);
1107:             if ($stats > 0) {
1108:                 $teststat = F_getTestStat($mr['testuser_test_id'], $group_id, $mr['user_id'], $startdate, $enddate, $mr['testuser_id']);
1109:             }
1110:             $data['testuser']['\''.$mr['testuser_id'].'\''] = array();
1111:             $data['testuser']['\''.$mr['testuser_id'].'\'']['test'] = $usrtestdata;
1112:             $data['testuser']['\''.$mr['testuser_id'].'\'']['num'] = $itemcount;
1113:             $data['testuser']['\''.$mr['testuser_id'].'\'']['id'] = $mr['testuser_id'];
1114:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_id'] = $mr['user_id'];
1115:             $halfscore = ($usrtestdata['test_max_score'] / 2);
1116:             $data['testuser']['\''.$mr['testuser_id'].'\'']['testuser_creation_time'] = $mr['testuser_creation_time'];
1117:             $data['testuser']['\''.$mr['testuser_id'].'\'']['testuser_end_time'] = $mr['testuser_end_time'];
1118:             if (($mr['testuser_end_time'] <= 0) or (strtotime($mr['testuser_end_time']) < strtotime($mr['testuser_creation_time']))) {
1119:                 $time_diff =  ($usrtestdata['test_duration_time'] * K_SECONDS_IN_MINUTE);
1120:             } else {
1121:                 $time_diff = strtotime($mr['testuser_end_time']) - strtotime($mr['testuser_creation_time']); //sec
1122:             }
1123:             $data['testuser']['\''.$mr['testuser_id'].'\'']['time_diff'] = gmdate('H:i:s', $time_diff);
1124:             $passmsg = false;
1125:             if ($usrtestdata['test_score_threshold'] > 0) {
1126:                 if ($usrtestdata['user_score'] >= $usrtestdata['test_score_threshold']) {
1127:                     $passmsg = true;
1128:                     $passed++;
1129:                 }
1130:             } elseif ($usrtestdata['user_score'] > $halfscore) {
1131:                 $passmsg = true;
1132:                 $passed++;
1133:             }
1134:             if ($usrtestdata['test_max_score'] > 0) {
1135:                 $total_score_perc = round(100 * $mr['total_score'] / $usrtestdata['test_max_score']);
1136:             } else {
1137:                 $total_score_perc = 0;
1138:             }
1139:             $data['testuser']['\''.$mr['testuser_id'].'\'']['passmsg'] = $passmsg;
1140:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_name'] = $mr['user_name'];
1141:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_email'] = $mr['user_email'];
1142:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_lastname'] = $mr['user_lastname'];
1143:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_firstname'] = $mr['user_firstname'];
1144:             $data['testuser']['\''.$mr['testuser_id'].'\'']['total_score'] = $mr['total_score'];
1145:             $data['testuser']['\''.$mr['testuser_id'].'\'']['total_score_perc'] = $total_score_perc;
1146:             if ($stats > 0) {
1147:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['right'] = $teststat['qstats']['right'];
1148:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['right_perc'] = $teststat['qstats']['right_perc'];
1149:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['wrong'] = $teststat['qstats']['wrong'];
1150:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['wrong_perc'] = $teststat['qstats']['wrong_perc'];
1151:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unanswered'] = $teststat['qstats']['unanswered'];
1152:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unanswered_perc'] = $teststat['qstats']['unanswered_perc'];
1153:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['undisplayed'] = $teststat['qstats']['undisplayed'];
1154:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['undisplayed_perc'] = $teststat['qstats']['undisplayed_perc'];
1155:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unrated'] = $teststat['qstats']['unrated'];
1156:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unrated_perc'] = $teststat['qstats']['unrated_perc'];
1157:             } else {
1158:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['right'] = '';
1159:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['right_perc'] = '';
1160:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['wrong'] = '';
1161:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['wrong_perc'] = '';
1162:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unanswered'] = '';
1163:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unanswered_perc'] = '';
1164:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['undisplayed'] = '';
1165:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['undisplayed_perc'] = '';
1166:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unrated'] = '';
1167:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['unrated_perc'] = '';
1168:             }
1169:             if ($mr['testuser_status'] > 3) {
1170:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['locked'] = true;
1171:             } else {
1172:                 $data['testuser']['\''.$mr['testuser_id'].'\'']['locked'] = false;
1173:             }
1174:             // remaining user time in minutes
1175:             $data['testuser']['\''.$mr['testuser_id'].'\'']['remaining_time'] = round(((time() - strtotime($usrtestdata['user_test_start_time']))) / K_SECONDS_IN_MINUTE) - $usrtestdata['test_duration_time'];
1176:             $data['testuser']['\''.$mr['testuser_id'].'\'']['user_comment'] = $usrtestdata['user_comment'];
1177:             // SVG points
1178:             $data['svgpoints'] .= 'x'.$data['testuser']['\''.$mr['testuser_id'].'\'']['total_score_perc'].'v'.$data['testuser']['\''.$mr['testuser_id'].'\'']['right_perc'];
1179:             // collects data for descriptive statistics
1180:             $statsdata['score'][] = $mr['total_score'];
1181:             $statsdata['score_perc'][] = $total_score_perc;
1182:             if ($stats > 0) {
1183:                 $statsdata['right'][] = $teststat['qstats']['right'];
1184:                 $statsdata['right_perc'][] = $teststat['qstats']['right_perc'];
1185:                 $statsdata['wrong'][] = $teststat['qstats']['wrong'];
1186:                 $statsdata['wrong_perc'][] = $teststat['qstats']['wrong_perc'];
1187:                 $statsdata['unanswered'][] = $teststat['qstats']['unanswered'];
1188:                 $statsdata['unanswered_perc'][] = $teststat['qstats']['unanswered_perc'];
1189:                 $statsdata['undisplayed'][] = $teststat['qstats']['undisplayed'];
1190:                 $statsdata['undisplayed_perc'][] = $teststat['qstats']['undisplayed_perc'];
1191:                 $statsdata['unrated'][] = $teststat['qstats']['unrated'];
1192:                 $statsdata['unrated_perc'][] = $teststat['qstats']['unrated_perc'];
1193:             } else {
1194:                 $statsdata['right'][] = '';
1195:                 $statsdata['right_perc'][] = '';
1196:                 $statsdata['wrong'][] = '';
1197:                 $statsdata['wrong_perc'][] = '';
1198:                 $statsdata['unanswered'][] = '';
1199:                 $statsdata['unanswered_perc'][] = '';
1200:                 $statsdata['undisplayed'][] = '';
1201:                 $statsdata['undisplayed_perc'][] = '';
1202:                 $statsdata['unrated'][] = '';
1203:                 $statsdata['unrated_perc'][] = '';
1204:             }
1205:         }
1206:     } else {
1207:         F_display_db_error();
1208:     }
1209:     $data['passed'] = $passed;
1210:     $passed_perc = 0;
1211:     if ($itemcount > 0) {
1212:         $passed_perc = round(100 * $passed / $itemcount);
1213:     }
1214:     $data['passed_perc'] = $passed_perc;
1215:     $data['num_records'] = $itemcount;
1216:     if ($itemcount > 0) {
1217:         // calculate statistics
1218:         $data['statistics'] = F_getArrayStatistics($statsdata);
1219:     }
1220:     return $data;
1221: }
1222: 
1223: /**
1224:  * Lock the user's test.<br>
1225:  * @param $test_id (int) test ID
1226:  * @param $user_id (int) user ID
1227:  */
1228: function F_lockUserTest($test_id, $user_id)
1229: {
1230:     require_once('../config/tce_config.php');
1231:     global $db, $l;
1232:     $test_id = intval($test_id);
1233:     $user_id = intval($user_id);
1234:     $sql = 'UPDATE '.K_TABLE_TEST_USER.'
1235:             SET testuser_status=4
1236:             WHERE testuser_test_id='.$test_id.'
1237:                 AND testuser_user_id='.$user_id.'
1238:                 AND testuser_status<4';
1239:     if (!$r = F_db_query($sql, $db)) {
1240:         F_display_db_error();
1241:     }
1242: }
1243: 
1244: /**
1245:  * Returns a comma separated string of test IDs with test_results_to_users enabled
1246:  * @param $test_id (int) Test ID.
1247:  * @return string
1248:  */
1249: function F_getTestIDResults($test_id, $user_id)
1250: {
1251:     return F_getTestIDs($test_id, $user_id, 'test_results_to_users');
1252: }
1253: 
1254: /**
1255:  * Returns a comma separated string of test IDs with test_results_to_users enabled
1256:  * @param $test_id (int) Test ID.
1257:  * @return string
1258:  */
1259: function F_getTestIDReports($test_id, $user_id)
1260: {
1261:     return F_getTestIDs($test_id, $user_id, 'test_report_to_users');
1262: }
1263: 
1264: /**
1265:  * Returns a comma separated string of test IDs with test_results_to_users enabled
1266:  * @param $test_id (int) Test ID.
1267:  * @return string
1268:  */
1269: function F_getTestIDs($test_id, $user_id, $filter = 'test_results_to_users')
1270: {
1271:     global $l,$db;
1272:     require_once('../config/tce_config.php');
1273:     $str = '0'; // string to return
1274:     $test_id = intval($test_id);
1275:     $user_id = intval($user_id);
1276:     $sql = 'SELECT test_id FROM '.K_TABLE_TESTS.' WHERE test_id IN (SELECT DISTINCT testuser_test_id FROM '.K_TABLE_TEST_USER.' WHERE testuser_user_id='.intval($user_id).' AND testuser_status>0) AND '.$filter.'=1';
1277:     if ($r = F_db_query($sql, $db)) {
1278:         while ($m = F_db_fetch_assoc($r)) {
1279:             $str .= ','.$m['test_id'];
1280:         }
1281:     } else {
1282:         F_display_db_error();
1283:     }
1284:     return $str;
1285: }
1286: 
1287: //============================================================+
1288: // END OF FILE
1289: //============================================================+
1290: 
 

© 2004-2018 – Nicola Asuni - Tecnick.com - All rights reserved.
about - disclaimer - privacy