source-function-F_getTestData

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.php
   4: // Begin       : 2004-05-28
   5: // Last Update : 2016-03-15
   6: //
   7: // Description : Functions to handle test generation, status
   8: //               and user access.
   9: //
  10: // Author: Nicola Asuni
  11: //
  12: // (c) Copyright:
  13: //               Nicola Asuni
  14: //               Tecnick.com LTD
  15: //               www.tecnick.com
  16: //               info@tecnick.com
  17: //
  18: // License:
  19: //    Copyright (C) 2004-2013 Nicola Asuni - Tecnick.com LTD
  20: //    See LICENSE.TXT file for more information.
  21: //============================================================+
  22: 
  23: /**
  24:  * @file
  25:  * Functions to handle test generation, status and user access.
  26:  * @package com.tecnick.tcexam.shared
  27:  * @author Nicola Asuni
  28:  * @since 2004-05-28
  29:  */
  30: 
  31: /**
  32:  * Returns an XHTML table of user's tests.
  33:  * @return string containing an XHTML table of user's tests.
  34:  */
  35: function F_getUserTests()
  36: {
  37:     require_once('../config/tce_config.php');
  38:     require_once('../../shared/code/tce_functions_tcecode.php');
  39:     require_once('../../shared/code/tce_functions_test_stats.php');
  40:     global $db, $l;
  41:     $user_id = intval($_SESSION['session_user_id']);
  42:     $str = ''; // temp string
  43:     // get current date-time
  44:     $current_time = date(K_TIMESTAMP_FORMAT);
  45:     // select tests hiding old repeated tests
  46:     $sql = 'SELECT * FROM '.K_TABLE_TESTS.' WHERE (test_id IN (SELECT tsubset_test_id FROM '.K_TABLE_TEST_SUBJSET.') AND (test_begin_time < \''.$current_time.'\')';
  47:     if (K_HIDE_EXPIRED_TESTS) {
  48:         $sql .= ' AND (test_end_time > \''.$current_time.'\')';
  49:     }
  50:     $sql .= ') ORDER BY test_begin_time DESC';
  51:     if ($r = F_db_query($sql, $db)) {
  52:         while ($m = F_db_fetch_array($r)) { // for each active test
  53:             $expired = false;
  54:             // check user's authorization
  55:             if (F_isValidTestUser($m['test_id'], $_SESSION['session_user_ip'], $m['test_ip_range'])) {
  56:                 // the user's IP is valid, check test status
  57:                 list ($test_status, $testuser_id) = F_checkTestStatus($user_id, $m['test_id'], $m['test_duration_time']);
  58:                 if (strtotime($current_time) >= strtotime($m['test_end_time'])) {
  59:                     // the test is expired.
  60:                     $expired = true;
  61:                     $datestyle = ' style="color:#666666;"';
  62:                 } else {
  63:                     $datestyle = '';
  64:                 }
  65:                 $str .= '<tr>'.K_NEWLINE;
  66:                 if (strlen($m['test_password']) > 0) {
  67:                     $str .= '<td style="background-color:#ffffcc;">';
  68:                 } else {
  69:                     $str .= '<td>';
  70:                 }
  71:                 $str .= '<strong>'.F_testInfoLink($m['test_id'], $m['test_name']).'</strong></td>'.K_NEWLINE;
  72:                 $str .= '<td'.$datestyle.'>'.$m['test_begin_time'].'</td>'.K_NEWLINE;
  73:                 $str .= '<td'.$datestyle.'>'.$m['test_end_time'].'</td>'.K_NEWLINE;
  74:                 // status
  75:                 $str .= '<td';
  76:                 if (($test_status >= 4) and F_getBoolean($m['test_results_to_users'])) {
  77:                     $usrtestdata = F_getUserTestStat($m['test_id'], $user_id, $testuser_id);
  78:                     $passmsg = '';
  79:                     if (isset($usrtestdata['user_score']) and isset($usrtestdata['test_score_threshold']) and ($usrtestdata['test_score_threshold'] > 0)) {
  80:                         if ($usrtestdata['user_score'] >= $usrtestdata['test_score_threshold']) {
  81:                             $str .= ' style="background-color:#ddffdd;"';
  82:                             $passmsg = ' - '.$l['w_passed'];
  83:                         } else {
  84:                             $str .= ' style="background-color:#ffdddd;"';
  85:                             $passmsg = ' - '.$l['w_not_passed'];
  86:                         }
  87:                     }
  88:                     $str .= '>';
  89:                     if (isset($usrtestdata['user_score']) and (strlen(''.$usrtestdata['user_score']) > 0)) {
  90:                         if ($usrtestdata['test_max_score'] > 0) {
  91:                             $str .= '<a href="tce_show_result_user.php?testuser_id='.$testuser_id.'&amp;test_id='.$m['test_id'].'" title="'.$l['h_result'].'">'.$usrtestdata['user_score'].' / '.$usrtestdata['test_max_score'].' ('.round(100 * $usrtestdata['user_score'] / $usrtestdata['test_max_score']).'%)'.$passmsg.'</a>';
  92:                         } else {
  93:                             $str .= '<a href="tce_show_result_user.php?testuser_id='.$testuser_id.'&amp;test_id='.$m['test_id'].'" title="'.$l['h_result'].'">'.$usrtestdata['user_score'].$passmsg.'</a>';
  94:                         }
  95:                     } else {
  96:                         $str .= '&nbsp;';
  97:                     }
  98:                 } else {
  99:                     $str .= '>&nbsp;';
 100:                 }
 101:                 $str .= '</td>'.K_NEWLINE;
 102:                 // display various action links by status case
 103:                 $str .= '<td style="text-align:center;">';
 104:                 if (!$expired) {
 105:                     switch ($test_status) {
 106:                         case 0: { // 0 = the test generation process is started but not completed
 107:                             // print execute test link
 108:                             $str .= '<a href="';
 109:                             if (K_DISPLAY_TEST_DESCRIPTION or !empty($m['test_password'])) {
 110:                                 // display test description before starting
 111:                                 $str .= 'tce_test_start.php';
 112:                             } else {
 113:                                 // directly execute test
 114:                                 $str .= 'tce_test_execute.php';
 115:                             }
 116:                             $str .= '?testid='.$m['test_id'].'" title="'.$l['h_execute'].'" class="buttongreen">'.$l['w_execute'].'</a>';
 117:                             break;
 118:                         }
 119:                         case 1: // 1 = the test has been successfully created
 120:                         case 2: // 2 = all questions have been displayed to the user
 121:                         case 3: { // 3 = all questions have been answered
 122:                             // continue test
 123:                             $str .= '<a href="tce_test_execute.php?testid='.$m['test_id'].'" title="'.$l['h_continue'].'" class="xmlbutton">'.$l['w_continue'].'</a>';
 124:                             break;
 125:                         }
 126:                         default: { // 4 or greater = test can be repeated
 127:                             if (F_getBoolean($m['test_repeatable'])) {
 128:                                 // print execute test link
 129:                                 $str .= '<a href="';
 130:                                 if (K_DISPLAY_TEST_DESCRIPTION or !empty($m['test_password'])) {
 131:                                     // display test description before starting
 132:                                     $str .= 'tce_test_start.php';
 133:                                 } else {
 134:                                     // directly execute test
 135:                                     $str .= 'tce_test_execute.php';
 136:                                 }
 137:                                 $str .= '?testid='.$m['test_id'].'&amp;repeat=1" title="'.$l['h_repeat_test'].'" class="buttonblue">'.$l['w_repeat'].'</a>';
 138:                             }
 139:                             break;
 140:                         }
 141:                     }
 142:                 }
 143:                 $str .= '</td>'.K_NEWLINE;
 144:                 $str .= '</tr>'.K_NEWLINE;
 145:             }
 146:         }
 147:     } else {
 148:         F_display_db_error();
 149:     }
 150:     if (strlen($str) > 0) {
 151:         $out = '<table class="testlist">'.K_NEWLINE;
 152:         $out .= '<tr>'.K_NEWLINE;
 153:         $out .= '<th>'.$l['w_test'].'</th>'.K_NEWLINE;
 154:         $out .= '<th>'.$l['w_from'].'</th>'.K_NEWLINE;
 155:         $out .= '<th>'.$l['w_to'].'</th>'.K_NEWLINE;
 156:         $out .= '<th>'.$l['w_status'].'</th>'.K_NEWLINE;
 157:         $out .= '<th>'.$l['w_action'].'</th>'.K_NEWLINE;
 158:         $out .= '</tr>'.K_NEWLINE;
 159:         $out .= $str;
 160:         $out .= '</table>'.K_NEWLINE;
 161:     } else {
 162:         $out = $l['m_no_test_available'];
 163:     }
 164:     return $out;
 165: }
 166: 
 167: /**
 168:  * Mark previous test attempts as repeated.
 169:  * @param $test_id (int) Test ID
 170:  */
 171: function F_repeatTest($test_id)
 172: {
 173:     require_once('../config/tce_config.php');
 174:     global $db, $l;
 175:     $test_id = intval($test_id);
 176:     $user_id = intval($_SESSION['session_user_id']);
 177:     $sql = 'SELECT test_id FROM '.K_TABLE_TESTS.' WHERE test_id='.$test_id.' AND test_repeatable=\'1\' LIMIT 1';
 178:     if ($r = F_db_query($sql, $db)) {
 179:         if ($m = F_db_fetch_array($r)) {
 180:             $sqls = 'SELECT testuser_id FROM '.K_TABLE_TEST_USER.' WHERE testuser_test_id='.$test_id.' AND testuser_user_id='.$user_id.' AND testuser_status>3 ORDER BY testuser_status DESC';
 181:             if ($rs = F_db_query($sqls, $db)) {
 182:                 while ($ms = F_db_fetch_array($rs)) {
 183:                     $sqld = 'UPDATE '.K_TABLE_TEST_USER.' SET testuser_status=testuser_status+1 WHERE testuser_id='.$ms['testuser_id'].'';
 184:                     if (!$rd = F_db_query($sqld, $db)) {
 185:                         F_display_db_error();
 186:                     }
 187:                 }
 188:             } else {
 189:                 F_display_db_error();
 190:             }
 191:         }
 192:     } else {
 193:         F_display_db_error();
 194:     }
 195: }
 196: 
 197: /**
 198:  * Check if user's IP is valid over test IP range
 199:  * @param $user_ip (int) user's IP address in expanded IPv6 format.
 200:  * @param $test_ips (int) comma separated list of valid test IP addresses. The '*' character may be used to indicate any number in IPv4 addresses. Intervals must be specified using the '-' character.
 201:  * @return true if IP is valid, false otherwise
 202:  */
 203: function F_isValidIP($user_ip, $test_ips)
 204: {
 205:     if (empty($user_ip) or empty($test_ips)) {
 206:         return false;
 207:     }
 208:     // convert user IP to number
 209:     $usrip = getIpAsInt($user_ip);
 210:     // build array of valid IP masks
 211:     $test_ip = explode(',', $test_ips);
 212:     // check user IP against test IP masks
 213:     while (list($key, $ipmask) = each($test_ip)) {
 214:         if (strrpos($ipmask, '*') !== false) {
 215:             // old range notation using IPv4 addresses and '*' character.
 216:             $ipv4 = explode('.', $ipmask);
 217:             $ipv4_start = array();
 218:             $ipv4_end = array();
 219:             foreach ($ipv4 as $num) {
 220:                 if ($num == '*') {
 221:                     $ipv4_start[] = 0;
 222:                     $ipv4_end[] = 255;
 223:                 } else {
 224:                     $num = intval($num);
 225:                     if (($num >= 0) and ($num <= 255)) {
 226:                         $ipv4_start[] = $num;
 227:                         $ipv4_end[] = $num;
 228:                     } else {
 229:                         $ipv4_start[] = 0;
 230:                         $ipv4_end[] = 255;
 231:                     }
 232:                 }
 233:             }
 234:             // convert to IPv6 address range
 235:             $ipmask = getNormalizedIP(implode('.', $ipv4_start)).'-'.getNormalizedIP(implode('.', $ipv4_end));
 236:         }
 237:         if (strrpos($ipmask, '-') !== false) {
 238:             // address range
 239:             $ip_range = explode('-', $ipmask);
 240:             if (count($ip_range) !== 2) {
 241:                 return false;
 242:             }
 243:             $ip_start = getIpAsInt($ip_range[0]);
 244:             $ip_end = getIpAsInt($ip_range[1]);
 245:             if (($usrip >= $ip_start) and ($usrip <= $ip_end)) {
 246:                 return true;
 247:             }
 248:         } elseif ($usrip == getIpAsInt($ipmask)) {
 249:             // exact address comparison
 250:             return true;
 251:         }
 252:     }
 253:     return false;
 254: }
 255: 
 256: 
 257: /**
 258:  * Check if user's IP is valid over test IP range
 259:  * @param $test_id (int) Test ID
 260:  * @return true if the client certifiate is valid, false otherwise
 261:  */
 262: function F_isValidSSLCert($test_id)
 263: {
 264:     require_once('../config/tce_config.php');
 265:     require_once('../../shared/code/tce_functions_authorization.php');
 266:     global $db, $l;
 267:     $test_id = intval($test_id);
 268:     if (F_count_rows(K_TABLE_TEST_SSLCERTS, 'WHERE tstssl_test_id='.$test_id) == 0) {
 269:         // no certificates were selected for this test
 270:         return true;
 271:     }
 272:     // get the hash code for the client SSl certificate
 273:     $client_ssl_hash = F_getSSLClientHash();
 274:     // check if the client certificate is enabled for this test
 275:     if (F_count_rows(
 276:         K_TABLE_TEST_SSLCERTS.', '.K_TABLE_SSLCERTS,
 277:         'WHERE tstssl_ssl_id=ssl_id
 278:             AND tstssl_test_id='.$test_id.'
 279:             AND ssl_hash=\''.$client_ssl_hash.'\'
 280:             LIMIT 1'
 281:     ) > 0) {
 282:         return true;
 283:     }
 284:     return false;
 285: }
 286: 
 287: /**
 288:  * Check if user is authorized to execute the specified test
 289:  * @param $test_id (int) ID of the selected test
 290:  * @param $user_ip (int) user's IP address.
 291:  * @param $test_ip (int) test IP valid addresses. Various IP addresses may be separated using comma character. The asterisk character may be used to indicate "any number".
 292:  * @return true if is user is authorized, false otherwise
 293:  */
 294: function F_isValidTestUser($test_id, $user_ip, $test_ip)
 295: {
 296:     require_once('../config/tce_config.php');
 297:     global $db, $l;
 298:     $test_id = intval($test_id);
 299:     $user_id = intval($_SESSION['session_user_id']);
 300:     // check user's IP
 301:     if (!F_isValidIP($user_ip, $test_ip)) {
 302:         return false;
 303:     }
 304:     // check user's SSL certificate
 305:     if (!F_isValidSSLCert($test_id)) {
 306:         return false;
 307:     }
 308:     // check user's group
 309:     if (F_count_rows(
 310:         K_TABLE_USERGROUP.', '.K_TABLE_TEST_GROUPS,
 311:         'WHERE usrgrp_group_id=tstgrp_group_id
 312:             AND tstgrp_test_id='.$test_id.'
 313:             AND usrgrp_user_id='.$user_id.'
 314:             LIMIT 1'
 315:     ) > 0) {
 316:         return true;
 317:     }
 318:     return false;
 319: }
 320: 
 321: /**
 322:  * Terminate user's test<br>
 323:  * @param $test_id (int) test ID
 324:  * @since 4.0.000 (2006-09-27)
 325:  */
 326: function F_terminateUserTest($test_id)
 327: {
 328:     require_once('../config/tce_config.php');
 329:     global $db, $l;
 330:     $test_id = intval($test_id);
 331:     $user_id = intval($_SESSION['session_user_id']);
 332:     $sql = 'UPDATE '.K_TABLE_TEST_USER.'
 333:         SET testuser_status=4
 334:         WHERE testuser_test_id='.$test_id.'
 335:             AND testuser_user_id='.$user_id.'
 336:             AND testuser_status<4';
 337:     if (!$r = F_db_query($sql, $db)) {
 338:         F_display_db_error();
 339:     }
 340: }
 341: 
 342: /**
 343:  * Check and returns specific test status for the specified user.<br>
 344:  * @param $user_id (int) user ID
 345:  * @param $test_id (int) test ID
 346:  * @param $duration (int) test duration in seconds
 347:  * @return array of (test_status_code, testuser_id). test_status_code: <ul><li>0 = the test generation process is started but not completed;</li><li>1 = the test has been successfully created;</li><li>2 = all questions have been displayed to the user;</li><li>3 = all questions have been answered;</li><li>4 = test locked (for timeout);</li><li>5 or more = old version of repeated test;</li></ul>
 348:  */
 349: function F_checkTestStatus($user_id, $test_id, $duration)
 350: {
 351:     require_once('../config/tce_config.php');
 352:     global $db, $l;
 353:     // get current date-time
 354:     $current_time = date(K_TIMESTAMP_FORMAT);
 355:     $test_status = 0;
 356:     $user_id = intval($user_id);
 357:     $test_id = intval($test_id);
 358:     $duration = intval($duration);
 359:     $testuser_id = 0;
 360:     // get current test status for the selected user
 361:     $sql = 'SELECT testuser_id, testuser_status, testuser_creation_time
 362:         FROM '.K_TABLE_TEST_USER.'
 363:         WHERE testuser_test_id='.$test_id.'
 364:             AND testuser_user_id='.$user_id.'
 365:         ORDER BY testuser_status
 366:         LIMIT 1';
 367:     if ($r = F_db_query($sql, $db)) {
 368:         if ($m = F_db_fetch_array($r)) {
 369:             $testuser_id = $m['testuser_id'];
 370:             $test_status = $m['testuser_status'];
 371:             $endtime = date(K_TIMESTAMP_FORMAT, strtotime($m['testuser_creation_time']) + ($duration * K_SECONDS_IN_MINUTE));
 372:             if (($test_status > 0) and ($test_status < 4) and ($current_time > $endtime)) {
 373:                 // update test mode to 4 = test locked (for timeout)
 374:                 $sqlu = 'UPDATE '.K_TABLE_TEST_USER.'
 375:                     SET testuser_status=4
 376:                     WHERE testuser_id='.$testuser_id.'';
 377:                 if (!$ru = F_db_query($sqlu, $db)) {
 378:                     F_display_db_error();
 379:                 } else {
 380:                     // test locked
 381:                     $test_status = 4;
 382:                 }
 383:             } else {
 384:                 switch ($test_status) {
 385:                     case 0: { // 0 = the test generation process is started but not completed
 386:                         // delete incomplete test (also deletes test logs using database referential integrity)
 387:                         $sqld = 'DELETE FROM '.K_TABLE_TEST_USER.'
 388:                             WHERE testuser_id='.$testuser_id.'';
 389:                         if (!$rd = F_db_query($sqld, $db)) {
 390:                             F_display_db_error();
 391:                         }
 392:                         break;
 393:                     }
 394:                     case 1: { // 1 = the test has been successfully created
 395:                         // check if all questions were displayed
 396:                         if (F_count_rows(K_TABLE_TESTS_LOGS, 'WHERE testlog_testuser_id='.$testuser_id.' AND testlog_display_time IS NULL') == 0) {
 397:                             // update test status to 2 = all questions have been displayed to the user
 398:                             $sqlu = 'UPDATE '.K_TABLE_TEST_USER.'
 399:                                 SET testuser_status=2
 400:                                 WHERE testuser_id='.$testuser_id.'';
 401:                             if (!$ru = F_db_query($sqlu, $db)) {
 402:                                 F_display_db_error();
 403:                             } else {
 404:                                 $test_status = 2;
 405:                             }
 406:                         }
 407:                         break;
 408:                     }
 409:                     case 2: { // 2 = all questions have been displayed to the user
 410:                         // check if test has been completed in time
 411:                         if (F_count_rows(K_TABLE_TESTS_LOGS, 'WHERE testlog_testuser_id='.$testuser_id.' AND testlog_change_time IS NULL') == 0) {
 412:                             // update test mode to 3 = all questions have been answered
 413:                             $sqlu = 'UPDATE '.K_TABLE_TEST_USER.'
 414:                                 SET testuser_status=3
 415:                                 WHERE testuser_id='.$testuser_id.'';
 416:                             if (!$ru = F_db_query($sqlu, $db)) {
 417:                                 F_display_db_error();
 418:                             } else {
 419:                                 $test_status = 3;
 420:                             }
 421:                         }
 422:                         break;
 423:                     }
 424:                 } //end switch
 425:             } //end else
 426:         }
 427:     } else {
 428:         F_display_db_error();
 429:     }
 430:     return array($test_status, $testuser_id);
 431: }
 432: 
 433: /**
 434:  * Returns XHTML link to open test info popup.
 435:  * @param $test_id (int) test ID
 436:  * @param $link_name (string) link caption
 437:  * return XHTML code
 438:  */
 439: function F_testInfoLink($test_id, $link_name = '')
 440: {
 441:     require_once('../config/tce_config.php');
 442:     global $db, $l;
 443:     $str = '';
 444:     $onclickinfo = 'infoTestWindow=window.open(\'tce_popup_test_info.php?testid='.$test_id.'\'';
 445:     $onclickinfo .= ',\'infoTestWindow\',\'dependent';
 446:     $onclickinfo .= ',height='.K_TEST_INFO_HEIGHT;
 447:     $onclickinfo .= ',width='.K_TEST_INFO_WIDTH;
 448:     $onclickinfo .= ',menubar=no,resizable=yes,scrollbars=yes,status=no,toolbar=no\');';
 449:     $onclickinfo .= 'return false;';
 450:     $str .= '<a href="tce_popup_test_info.php?testid='.$test_id.'" onclick="'.$onclickinfo.'" title="'.$l['m_new_window_link'].'">';
 451:     if (strlen($link_name) > 0) {
 452:         $str .= $link_name;
 453:     } else {
 454:         $str .= $l['w_info'];
 455:     }
 456:     $str .= '</a>';
 457:     return $str;
 458: }
 459: 
 460: /**
 461:  * Returns an XHTML string containing specified test information.
 462:  * @param $test_id (int) test ID
 463:  * @param $showip (boolean) if true display enabled users' IP range
 464:  * @return string containing an XHTML code
 465:  */
 466: function F_printTestInfo($test_id, $showip = false)
 467: {
 468:     require_once('../config/tce_config.php');
 469:     require_once('../../shared/code/tce_functions_tcecode.php');
 470:     global $db, $l;
 471:     $str = ''; //string to return
 472:     $boolval = array($l['w_no'], $l['w_yes']);
 473:     //$ordmode = Array($l['w_position'], $l['w_alphabetic'], $l['w_id']);
 474:     $sql = 'SELECT * FROM '.K_TABLE_TESTS.' WHERE test_id='.$test_id.'';
 475:     if ($r = F_db_query($sql, $db)) {
 476:         if ($m = F_db_fetch_array($r)) {
 477:             $str .= '<h1>'.htmlspecialchars($m['test_name'], ENT_NOQUOTES, $l['a_meta_charset']).'</h1>'.K_NEWLINE;
 478:             $str .= '<div class="tcecontentbox">'.F_decode_tcecode($m['test_description']).'<br /><br /></div>'.K_NEWLINE;
 479:             $str .= '<div class="tceformbox">'.K_NEWLINE;
 480:             $str .= F_twoColRow($l['w_time_begin'], $l['h_time_begin'], $m['test_begin_time']);
 481:             $str .= F_twoColRow($l['w_time_end'], $l['h_time_end'], $m['test_end_time']);
 482:             $str .= F_twoColRow($l['w_test_time'], $l['h_test_time'], $m['test_duration_time'].' '.$l['w_minutes']);
 483:             $str .= F_twoColRow($l['w_score_right'], $l['h_score_right'], $m['test_score_right']);
 484:             $str .= F_twoColRow($l['w_score_wrong'], $l['h_score_wrong'], $m['test_score_wrong']);
 485:             $str .= F_twoColRow($l['w_score_unanswered'], $l['h_score_unanswered'], $m['test_score_unanswered']);
 486:             $str .= F_twoColRow($l['w_max_score'], $l['w_max_score'], $m['test_max_score']);
 487:             $str .= F_twoColRow($l['w_test_score_threshold'], $l['h_test_score_threshold'], $m['test_score_threshold']);
 488:             $str .= F_twoColRow($l['w_results_to_users'], $l['h_results_to_users'], $boolval[intval(F_getBoolean($m['test_results_to_users']))]);
 489:             $str .= F_twoColRow($l['w_report_to_users'], $l['h_report_to_users'], $boolval[intval(F_getBoolean($m['test_report_to_users']))]);
 490:             $str .= F_twoColRow($l['w_repeatable'], $l['h_repeatable_test'], $boolval[intval(F_getBoolean($m['test_repeatable']))]);
 491:             // Additional information hidden by default
 492:             //$str .= F_twoColRow($l['w_random_questions_select'], $l['h_random_questions_select'], $boolval[intval(F_getBoolean($m['test_random_questions_select']))]);
 493:             //$str .= F_twoColRow($l['w_random_questions_order'], $l['h_random_questions_order'], $boolval[intval(F_getBoolean($m['test_random_questions_order']))]);
 494:             //$str .= F_twoColRow($l['w_questions_order_mode'], $l['h_questions_order_mode'], $ordmode[intval(F_getBoolean($m['test_questions_order_mode']))]);
 495:             //$str .= F_twoColRow($l['w_random_answers_select'], $l['h_random_answers_select'], $boolval[intval(F_getBoolean($m['test_random_answers_select']))]);
 496:             //$str .= F_twoColRow($l['w_random_answers_order'], $l['h_random_answers_order'], $boolval[intval(F_getBoolean($m['test_random_answers_order']))]);
 497:             //$str .= F_twoColRow($l['w_answers_order_mode'], $l['h_answers_order_mode'], $ordmode[intval(F_getBoolean($m['test_answers_order_mode']))]);
 498:             //$str .= F_twoColRow($l['w_comment_enabled'], $l['h_comment_enabled'], $boolval[intval(F_getBoolean($m['test_comment_enabled']))]);
 499:             //$str .= F_twoColRow($l['w_menu_enabled'], $l['h_menu_enabled'], $boolval[intval(F_getBoolean($m['test_menu_enabled']))]);
 500:             //$str .= F_twoColRow($l['w_noanswer_enabled'], $l['h_noanswer_enabled'], $boolval[intval(F_getBoolean($m['test_noanswer_enabled']))]);
 501:             //$str .= F_twoColRow($l['w_mcma_radio'], $l['h_mcma_radio'], $boolval[intval(F_getBoolean($m['test_mcma_radio']))]);
 502:             if ($showip) {
 503:                 $str .= F_twoColRow($l['w_ip_range'], $l['h_ip_range'], $m['test_ip_range']);
 504:             }
 505:             $str .= '<br/>';
 506:         }
 507:     } else {
 508:         F_display_db_error();
 509:     }
 510:     $str .= '</div>';
 511:     return $str;
 512: }
 513: 
 514: /**
 515:  * Returns the test data.
 516:  * @param $test_id (int) test ID.
 517:  * @return array containing test data.
 518:  */
 519: function F_getTestData($test_id)
 520: {
 521:     require_once('../config/tce_config.php');
 522:     global $db, $l;
 523:     $test_id = intval($test_id);
 524:     $td = array();
 525:     $sql = 'SELECT *
 526:         FROM '.K_TABLE_TESTS.'
 527:         WHERE test_id='.$test_id.'
 528:         LIMIT 1';
 529:     if ($r = F_db_query($sql, $db)) {
 530:         $td = F_db_fetch_assoc($r);
 531:     } else {
 532:         F_display_db_error();
 533:     }
 534:     return $td;
 535: }
 536: 
 537: /**
 538:  * Returns user data.
 539:  * @param $user_id (int) User ID.
 540:  * @return array containing test data.
 541:  */
 542: function F_getUserData($user_id)
 543: {
 544:     require_once('../config/tce_config.php');
 545:     global $db, $l;
 546:     $user_id = intval($user_id);
 547:     $ud = array();
 548:     $sql = 'SELECT *
 549:         FROM '.K_TABLE_USERS.'
 550:         WHERE user_id='.$user_id.'
 551:         LIMIT 1';
 552:     if ($r = F_db_query($sql, $db)) {
 553:         $ud = F_db_fetch_assoc($r);
 554:     } else {
 555:         F_display_db_error();
 556:     }
 557:     return $ud;
 558: }
 559: 
 560: /**
 561:  * Returns the test password.
 562:  * @param $test_id (int) test ID.
 563:  * @return string test password or empty string in case of error.
 564:  */
 565: function F_getTestPassword($test_id)
 566: {
 567:     $test_id = intval($test_id);
 568:     $td = F_getTestData($test_id);
 569:     return $td['test_password'];
 570: }
 571: 
 572: /**
 573:  * Returns the test name.
 574:  * @param $test_id (int) test ID.
 575:  * @return string test name or empty string in case of error.
 576:  */
 577: function F_getTestName($test_id)
 578: {
 579:     $test_id = intval($test_id);
 580:     $td = F_getTestData($test_id);
 581:     return $td['test_name'];
 582: }
 583: 
 584: /**
 585:  * Returns the test duration time in seconds.
 586:  * @param $test_id (int) test ID
 587:  * @return int test duration time in seconds
 588:  */
 589: function F_getTestDuration($test_id)
 590: {
 591:     require_once('../config/tce_config.php');
 592:     $test_id = intval($test_id);
 593:     $td = F_getTestData($test_id);
 594:     return ($td['test_duration_time'] * K_SECONDS_IN_MINUTE);
 595: }
 596: 
 597: /**
 598:  * Returns the user's test start time in seconds since UNIX epoch (1970-01-01 00:00:00).
 599:  * @param $testuser_id (int) user's test ID
 600:  * @return int start time in seconds
 601:  */
 602: function F_getTestStartTime($testuser_id)
 603: {
 604:     require_once('../config/tce_config.php');
 605:     global $db, $l;
 606:     $testuser_id = intval($testuser_id);
 607:     $starttime = 0;
 608:     // select test control row (if any)
 609:     $sql = 'SELECT testuser_creation_time
 610:         FROM '.K_TABLE_TEST_USER.'
 611:         WHERE testuser_id='.$testuser_id.'';
 612:     if ($r = F_db_query($sql, $db)) {
 613:         if ($m = F_db_fetch_array($r)) {
 614:             $starttime = strtotime($m['testuser_creation_time']);
 615:         }
 616:     } else {
 617:         F_display_db_error();
 618:     }
 619:     return $starttime;
 620: }
 621: 
 622: /**
 623:  * Return a formatted XHTML row to display 2 columns data.<br>
 624:  * See CSS classes:<ul>
 625:  * <li>div.row span.label</li>
 626:  * <li>div.row span.formw</li>
 627:  * </ul>
 628:  * @param $label (string) string to display on the left column
 629:  * @param $description (string) string to display on the title attribute of the left column field
 630:  * @param $value (string) string to display on the right column
 631:  * @return string XHTML code
 632:  */
 633: function F_twoColRow($label = "", $description = "", $value = "")
 634: {
 635:     $str = '';
 636:     $str .= '<div class="row">';
 637:     $str .= '<span class="label">';
 638:     $str .= '<span title="'.$description.'">';
 639:     $str .= $label.': ';
 640:     $str .= '</span>';
 641:     $str .= '</span>';
 642:     $str .= '<span class="value">';
 643:     $str .= $value;
 644:     $str .= '</span>';
 645:     $str .= '</div>'.K_NEWLINE;
 646:     return $str;
 647: }
 648: 
 649: /**
 650:  * Returns true if the current user is authorized to execute the selected test.<br>
 651:  * Generates the test if it's not already generated.
 652:  * @param $test_id (int) test ID.
 653:  * @return true if user is authorized, false otherwise.
 654:  */
 655: function F_executeTest($test_id)
 656: {
 657:     require_once('../config/tce_config.php');
 658:     global $db, $l;
 659:     // get current date-time
 660:     $current_time = date(K_TIMESTAMP_FORMAT);
 661:     $test_id = intval($test_id);
 662:     // select the specified test checking if it's valid for the current time
 663:     $sql = 'SELECT test_id, test_ip_range, test_duration_time, test_repeatable
 664:         FROM '.K_TABLE_TESTS.'
 665:         WHERE test_id='.$test_id.'
 666:             AND test_begin_time < \''.$current_time.'\'
 667:             AND test_end_time > \''.$current_time.'\'';
 668:     if ($r = F_db_query($sql, $db)) {
 669:         if ($m = F_db_fetch_array($r)) {
 670:             // check user's authorization
 671:             if (F_isValidTestUser($m['test_id'], $_SESSION['session_user_ip'], $m['test_ip_range'])) {
 672:                 // the user's IP is valid, check test status
 673:                 list ($test_status, $testuser_id) = F_checkTestStatus($_SESSION['session_user_id'], $m['test_id'], $m['test_duration_time']);
 674:                 if (($test_status > 4) and F_getBoolean($m['test_repeatable'])) {
 675:                     // this test can be repeated - create new test session for the current user
 676:                     return F_createTest($test_id, $_SESSION['session_user_id']);
 677:                 }
 678:                 switch ($test_status) {
 679:                     case 0: { // 0 = test is not yet created
 680:                         // create new test session for the current user
 681:                         return F_createTest($test_id, $_SESSION['session_user_id']);
 682:                         break;
 683:                     }
 684:                     case 1: // 1 = the test has been successfully created
 685:                     case 2: // 2 = all questions have been displayed to the user
 686:                     case 3: { // 3 = all questions have been answered
 687:                         return true;
 688:                         break;
 689:                     }
 690:                     case 4: { // 4 = test locked (for timeout)
 691:                         return false;
 692:                         break;
 693:                     }
 694:                 }
 695:             }
 696:         }
 697:     } else {
 698:         F_display_db_error();
 699:     }
 700:     return false;
 701: }
 702: 
 703: /**
 704:  * Checks if the current user is the right testlog_id owner.<br>
 705:  * This function is used for security reasons.
 706:  * @param $test_id (int) test ID
 707:  * @param $testlog_id (int) test log ID
 708:  * @return boolean TRUE in case of success, FALSE otherwise
 709:  */
 710: function F_isRightTestlogUser($test_id, $testlog_id)
 711: {
 712:     require_once('../config/tce_config.php');
 713:     global $db, $l;
 714:     $test_id = intval($test_id);
 715:     $testlog_id = intval($testlog_id);
 716:     // check if the current user is the right testlog_id owner
 717:     $sql = 'SELECT testuser_user_id, testuser_test_id
 718:         FROM '.K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS.'
 719:         WHERE testuser_id=testlog_testuser_id
 720:             AND testlog_id='.$testlog_id.'';
 721:     if ($r = F_db_query($sql, $db)) {
 722:         if ($m = F_db_fetch_array($r)) {
 723:             if (($m['testuser_user_id'] != $_SESSION['session_user_id']) or ($m['testuser_test_id'] != $test_id)) {
 724:                 return false;
 725:             }
 726:         } else {
 727:             return false;
 728:         }
 729:     } else {
 730:         F_display_db_error();
 731:     }
 732:     return true;
 733: }
 734: 
 735: /**
 736:  * Return an array containing answer_id field of selected answers.<br>
 737:  * @param $question_id (int) Question ID.
 738:  * @param $isright (int) Value (0 = false, 1 = true), if non-empty checks for answer_isright value on WHERE clause.
 739:  * @param $ordering (int) Ordering type question (0 = false, 1 = true).
 740:  * @param $limit (int) Maximum number of IDs to return.
 741:  * @param $startindex (int) Array starting index (default = 0).
 742:  * @param $randorder (boolean) If true user random order.
 743:  * @param $ordmode (int) Ordering mode: 0=position; 1=alphabetical; 2=ID.
 744:  * @return array id of selected answers
 745:  */
 746: function F_selectAnswers($question_id, $isright = '', $ordering = false, $limit = 0, $startindex = 0, $randorder = true, $ordmode = 0)
 747: {
 748:     require_once('../config/tce_config.php');
 749:     global $db, $l;
 750:     $question_id = intval($question_id);
 751:     $isright = F_escape_sql($db, $isright);
 752:     $limit = intval($limit);
 753:     $answers_ids = array(); // stores answers IDs
 754:     if ($ordering) {
 755:         $randorder = true;
 756:     }
 757:     $sql_order_by = '';
 758:     switch ($ordmode) {
 759:         case 0: {
 760:             $sql_order_by = ' AND answer_position>0 ORDER BY answer_position';
 761:             break;
 762:         }
 763:         case 1: {
 764:             $sql_order_by = ' ORDER BY answer_description';
 765:             break;
 766:         }
 767:         case 2: {
 768:             $sql_order_by = ' ORDER BY answer_id';
 769:             break;
 770:         }
 771:     }
 772:     $sql = 'SELECT answer_id, answer_position
 773:         FROM '.K_TABLE_ANSWERS.'
 774:         WHERE answer_question_id='.$question_id.'
 775:         AND answer_enabled=\'1\'';
 776:     if ($ordering) {
 777:         $sql .= ' AND answer_position>0';
 778:     } elseif (strlen($isright) > 0) {
 779:         // MCSA
 780:         $sql .= ' AND answer_isright=\''.$isright.'\'';
 781:     }
 782:     if ($randorder) {
 783:         $sql .= ' ORDER BY RAND()';
 784:     } else {
 785:         $sql .= $sql_order_by;
 786:     }
 787:     if ($limit > 0) {
 788:         if (K_DATABASE_TYPE == 'ORACLE') {
 789:             $sql = 'SELECT * FROM ('.$sql.') WHERE rownum <= '.$limit.'';
 790:         } else {
 791:             $sql .= ' LIMIT '.$limit.'';
 792:         }
 793:     }
 794:     if ($r = F_db_query($sql, $db)) {
 795:         while ($m = F_db_fetch_array($r)) {
 796:             if ($randorder or ($ordmode != 0)) {
 797:                 if ($ordmode == 2) {
 798:                     // order by ID
 799:                     $answers_ids[$m['answer_id']] = $m['answer_id'];
 800:                 } else {
 801:                     // default
 802:                     $answers_ids[$startindex++] = $m['answer_id'];
 803:                 }
 804:             } else {
 805:                 $answers_ids[$m['answer_position']] = $m['answer_id'];
 806:             }
 807:         }
 808:     } else {
 809:         F_display_db_error(false);
 810:         return false;
 811:     }
 812:     return $answers_ids;
 813: }
 814: 
 815: /**
 816:  * Add specified answers on tce_tests_logs_answer table.
 817:  * @param $testlog_id (int) testlog ID
 818:  * @param $answers_ids (array) array of answer IDs to add
 819:  * @return boolean true in case of success, false otherwise
 820:  */
 821: function F_addLogAnswers($testlog_id, $answers_ids)
 822: {
 823:     require_once('../config/tce_config.php');
 824:     global $db, $l;
 825:     $testlog_id = intval($testlog_id);
 826:     $i = 0;
 827:     while (list($key, $answid) = each($answers_ids)) {
 828:         $i++;
 829:         $sqli = 'INSERT INTO '.K_TABLE_LOG_ANSWER.' (
 830:             logansw_testlog_id,
 831:             logansw_answer_id,
 832:             logansw_selected,
 833:             logansw_order
 834:             ) VALUES (
 835:             '.$testlog_id.',
 836:             '.$answid.',
 837:             -1,
 838:             '.$i.'
 839:             )';
 840:         if (!$ri = F_db_query($sqli, $db)) {
 841:             F_display_db_error(false);
 842:             return false;
 843:         }
 844:     }
 845:     return true;
 846: }
 847: 
 848: /**
 849:  * Returns the ID of the tce_tests_users table corresponding to a complete test of $test_id type.
 850:  * @param $test_id (int) test ID
 851:  * @return int testuser ID
 852:  */
 853: function F_getFirstTestUser($test_id)
 854: {
 855:     require_once('../config/tce_config.php');
 856:     global $db, $l;
 857:     $test_id = intval($test_id);
 858:     // check if this is the first test creation
 859:     $firsttest = 0;
 860:     $sql = 'SELECT testuser_id
 861:         FROM '.K_TABLE_TEST_USER.'
 862:         WHERE testuser_test_id='.$test_id.'
 863:             AND testuser_status>0
 864:         LIMIT 1';
 865:     if ($r = F_db_query($sql, $db)) {
 866:         if ($m = F_db_fetch_array($r)) {
 867:             $firsttest = $m['testuser_id'];
 868:         }
 869:     } else {
 870:         F_display_db_error(false);
 871:     }
 872:     return $firsttest;
 873: }
 874: 
 875: /**
 876:  * Creates a new tce_tests_logs table entry and returns inserted ID.
 877:  * @param $testuser_id (int) ID of tce_tests_users
 878:  * @param $question_id (int) question ID
 879:  * @param $score (int) score for unanswered questions
 880:  * @param $order (int) question display order
 881:  * @param $num_answers (int) number of alternative answers
 882:  * @return int testlog ID
 883:  */
 884: function F_newTestLog($testuser_id, $question_id, $score, $order, $num_answers = 0)
 885: {
 886:     require_once('../config/tce_config.php');
 887:     global $db, $l;
 888:     $testuser_id = intval($testuser_id);
 889:     $question_id = intval($question_id);
 890:     $score = floatval($score);
 891:     $sqll = 'INSERT INTO '.K_TABLE_TESTS_LOGS.' (
 892:         testlog_testuser_id,
 893:         testlog_question_id,
 894:         testlog_score,
 895:         testlog_creation_time,
 896:         testlog_reaction_time,
 897:         testlog_order,
 898:         testlog_num_answers
 899:         ) VALUES (
 900:         '.$testuser_id.',
 901:         '.$question_id.',
 902:         '.$score.',
 903:         \''.date(K_TIMESTAMP_FORMAT).'\',
 904:         0,
 905:         '.$order.',
 906:         '.$num_answers.'
 907:         )';
 908:     if (!$rl = F_db_query($sqll, $db)) {
 909:         F_display_db_error(false);
 910:         return false;
 911:     }
 912:     // get inserted ID
 913:     return F_db_insert_id($db, K_TABLE_TESTS_LOGS, 'testlog_id');
 914: }
 915: 
 916: /**
 917:  * Returns false if the number of executed tests is under the limits, true otherwise.
 918:  * @return boolean true/false.
 919:  */
 920: function F_isTestOverLimits()
 921: {
 922:     require_once('../config/tce_config.php');
 923:     if ((K_REMAINING_TESTS !== false) and (K_REMAINING_TESTS <= 0)) {
 924:         return true;
 925:     }
 926:     $now = time();
 927:     $enddate = date(K_TIMESTAMP_FORMAT, $now);
 928:     if (K_MAX_TESTS_DAY !== false) {
 929:         // check day limit (last 24 hours)
 930:         $startdate = date(K_TIMESTAMP_FORMAT, ($now - K_SECONDS_IN_DAY));
 931:         $numtests = F_count_rows(K_TABLE_TESTUSER_STAT, 'WHERE tus_date>=\''.$startdate.'\' AND tus_date<=\''.$enddate.'\'');
 932:         if ($numtests >= K_MAX_TESTS_DAY) {
 933:             return true;
 934:         }
 935:     }
 936:     if (K_MAX_TESTS_MONTH !== false) {
 937:         // check month limit (last 30 days)
 938:         $startdate = date(K_TIMESTAMP_FORMAT, ($now - K_SECONDS_IN_MONTH));
 939:         $numtests = F_count_rows(K_TABLE_TESTUSER_STAT, 'WHERE tus_date>=\''.$startdate.'\' AND tus_date<=\''.$enddate.'\'');
 940:         if ($numtests >= K_MAX_TESTS_MONTH) {
 941:             return true;
 942:         }
 943:     }
 944:     if (K_MAX_TESTS_YEAR !== false) {
 945:         // check year limit (last 365 days)
 946:         $startdate = date(K_TIMESTAMP_FORMAT, ($now - K_SECONDS_IN_YEAR));
 947:         $numtests = F_count_rows(K_TABLE_TESTUSER_STAT, 'WHERE tus_date>=\''.$startdate.'\' AND tus_date<=\''.$enddate.'\'');
 948:         if ($numtests >= K_MAX_TESTS_YEAR) {
 949:             return true;
 950:         }
 951:     }
 952:     return false;
 953: }
 954: 
 955: /**
 956:  * Returns the number of executed tests on the specified time interval.
 957:  * @param $startdate (string) Star date-time interval.
 958:  * @param $enddate (string) End  date-time interval.
 959:  * @return int number of executed tests.
 960:  */
 961: function F_count_executed_tests($startdate, $enddate)
 962: {
 963:     require_once('../config/tce_config.php');
 964:     if (!empty($startdate)) {
 965:         $startdate_time = strtotime($startdate);
 966:         $startdate = date(K_TIMESTAMP_FORMAT, $startdate_time);
 967:     } else {
 968:         $startdate = date('Y').'-01-01 00:00:00';
 969:     }
 970:     if (!empty($enddate)) {
 971:         $enddate_time = strtotime($enddate);
 972:         $enddate = date(K_TIMESTAMP_FORMAT, $enddate_time);
 973:     } else {
 974:         $enddate = date('Y').'-12-31 23:59:59';
 975:     }
 976:     return F_count_rows(K_TABLE_TESTUSER_STAT, 'WHERE tus_date>=\''.$startdate.'\' AND tus_date<=\''.$enddate.'\'');
 977: }
 978: 
 979: /**
 980:  * Track generated tests.
 981:  * @param $date (string) date-time when the test was generated.
 982:  */
 983: function F_updateTestuserStat($date)
 984: {
 985:     require_once('../config/tce_config.php');
 986:     global $db;
 987:     $sql = 'INSERT INTO '.K_TABLE_TESTUSER_STAT.' (tus_date) VALUES (\''.$date.'\')';
 988:     if (!$r = F_db_query($sql, $db)) {
 989:         F_display_db_error();
 990:     }
 991: }
 992: 
 993: /**
 994:  * Create user's test and returns TRUE on success.
 995:  * @param $test_id (int) test ID.
 996:  * @param $user_id (int) user ID.
 997:  * @return boolean TRUE in case of success, FALSE otherwise.
 998:  */
 999: function F_createTest($test_id, $user_id)
1000: {
1001:     require_once('../config/tce_config.php');
1002:     require_once('../../shared/code/tce_functions_tcecode.php');
1003:     global $db, $l;
1004:     if (F_isTestOverLimits()) {
1005:         return false;
1006:     }
1007:     $test_id = intval($test_id);
1008:     $user_id = intval($user_id);
1009:     $firsttest = 0; // id of the firts test of this type
1010:     // get test data
1011:     $testdata = F_getTestData($test_id);
1012:     $test_random_questions_select = F_getBoolean($testdata['test_random_questions_select']);
1013:     $test_random_questions_order = F_getBoolean($testdata['test_random_questions_order']);
1014:     $test_questions_order_mode = intval($testdata['test_questions_order_mode']);
1015:     $test_random_answers_select = F_getBoolean($testdata['test_random_answers_select']);
1016:     $test_random_answers_order = F_getBoolean($testdata['test_random_answers_order']);
1017:     $test_answers_order_mode = intval($testdata['test_answers_order_mode']);
1018:     $random_questions = ($test_random_questions_select or $test_random_questions_order);
1019:     $sql_answer_position = '';
1020:     if (!$test_random_answers_order and ($test_answers_order_mode == 0)) {
1021:         $sql_answer_position = ' AND answer_position>0';
1022:     }
1023:     $sql_questions_order_by = '';
1024:     switch ($test_questions_order_mode) {
1025:         case 0: { // position
1026:             $sql_questions_order_by = ' AND question_position>0 ORDER BY question_position';
1027:             break;
1028:         }
1029:         case 1: { // alphabetic
1030:             $sql_questions_order_by = ' ORDER BY question_description';
1031:             break;
1032:         }
1033:         case 2: { // ID
1034:             $sql_questions_order_by = ' ORDER BY question_id';
1035:             break;
1036:         }
1037:         case 3: { // type
1038:             $sql_questions_order_by = ' ORDER BY question_type';
1039:             break;
1040:         }
1041:         case 4: { // subject ID
1042:             $sql_questions_order_by = ' ORDER BY question_subject_id';
1043:             break;
1044:         }
1045:     }
1046:     // IDs of MCSA questions with more than one correct answer
1047:     $right_answers_mcsa_questions_ids = '';
1048:     // IDs of MCSA questions with more than one wrong answer
1049:     $wrong_answers_mcsa_questions_ids = array();
1050:     // IDs of MCMA questions with more than one answer
1051:     $answers_mcma_questions_ids = array();
1052:     // IDs of ORDER questions with more than one ordering answer
1053:     $answers_order_questions_ids = '';
1054:     // 1. create user's test entry
1055:     // ------------------------------
1056:     $date = date(K_TIMESTAMP_FORMAT);
1057:     $sql = 'INSERT INTO '.K_TABLE_TEST_USER.' (
1058:         testuser_test_id,
1059:         testuser_user_id,
1060:         testuser_status,
1061:         testuser_creation_time
1062:         ) VALUES (
1063:         '.$test_id.',
1064:         '.$user_id.',
1065:         0,
1066:         \''.$date.'\'
1067:         )';
1068:     if (!$r = F_db_query($sql, $db)) {
1069:         F_display_db_error(false);
1070:         return false;
1071:     } else {
1072:         // get inserted ID
1073:         $testuser_id = F_db_insert_id($db, K_TABLE_TEST_USER, 'testuser_id');
1074:         F_updateTestuserStat($date);
1075:     }
1076:     // get ID of first user's test (if exist)
1077:     $firsttest = F_getFirstTestUser($test_id);
1078:     // select questions
1079:     if ($test_random_questions_select or ($firsttest == 0)) {
1080:         // selected questions IDs
1081:         $selected_questions = '0';
1082:         // 2. for each set of subjects
1083:         // ------------------------------
1084:         $sql = 'SELECT *
1085:             FROM '.K_TABLE_TEST_SUBJSET.'
1086:             WHERE tsubset_test_id='.$test_id.'
1087:             ORDER BY tsubset_type, tsubset_difficulty, tsubset_answers DESC';
1088:         if ($r = F_db_query($sql, $db)) {
1089:             $questions_data = array();
1090:             while ($m = F_db_fetch_array($r)) {
1091:                 // 3. select the subjects IDs
1092:                 $selected_subjects = '0';
1093:                 $sqlt = 'SELECT subjset_subject_id FROM '.K_TABLE_SUBJECT_SET.' WHERE subjset_tsubset_id='.$m['tsubset_id'];
1094:                 if ($rt = F_db_query($sqlt, $db)) {
1095:                     while ($mt = F_db_fetch_array($rt)) {
1096:                         $selected_subjects .= ','.$mt['subjset_subject_id'];
1097:                     }
1098:                 }
1099:                 // 4. select questions
1100:                 // ------------------------------
1101:                 $sqlq = 'SELECT question_id, question_type, question_difficulty, question_position
1102:                     FROM '.K_TABLE_QUESTIONS.'';
1103:                 $sqlq .= ' WHERE question_subject_id IN ('.$selected_subjects.')
1104:                     AND question_difficulty='.$m['tsubset_difficulty'].'
1105:                     AND question_enabled=\'1\'
1106:                     AND question_id NOT IN ('.$selected_questions.')';
1107:                 if ($m['tsubset_type'] > 0) {
1108:                     $sqlq .= ' AND question_type='.$m['tsubset_type'];
1109:                 }
1110:                 if ($m['tsubset_type'] == 1) {
1111:                     // (MCSA : Multiple Choice Single Answer) ----------
1112:                     // get questions with the right number of answers
1113:                     if (empty($right_answers_mcsa_questions_ids)) {
1114:                         $right_answers_mcsa_questions_ids = '0';
1115:                         $sqlt = 'SELECT DISTINCT answer_question_id FROM '.K_TABLE_ANSWERS.' WHERE answer_enabled=\'1\' AND answer_isright=\'1\''.$sql_answer_position.'';
1116:                         if ($rt = F_db_query($sqlt, $db)) {
1117:                             while ($mt = F_db_fetch_array($rt)) {
1118:                                 $right_answers_mcsa_questions_ids .= ','.$mt['answer_question_id'];
1119:                             }
1120:                         }
1121:                     }
1122:                     $sqlq .= ' AND question_id IN ('.$right_answers_mcsa_questions_ids.')';
1123:                     if ($m['tsubset_answers'] > 0) {
1124:                         if (!isset($wrong_answers_mcsa_questions_ids['\''.$m['tsubset_answers'].'\''])) {
1125:                             $wrong_answers_mcsa_questions_ids['\''.$m['tsubset_answers'].'\''] = '0';
1126:                             $sqlt = 'SELECT answer_question_id FROM '.K_TABLE_ANSWERS.' WHERE answer_enabled=\'1\' AND answer_isright=\'0\''.$sql_answer_position.' GROUP BY answer_question_id HAVING (COUNT(answer_id)>='.($m['tsubset_answers']-1).')';
1127:                             if ($rt = F_db_query($sqlt, $db)) {
1128:                                 while ($mt = F_db_fetch_array($rt)) {
1129:                                     $wrong_answers_mcsa_questions_ids['\''.$m['tsubset_answers'].'\''] .= ','.$mt['answer_question_id'];
1130:                                 }
1131:                             }
1132:                         }
1133:                         $sqlq .= ' AND question_id IN ('.$wrong_answers_mcsa_questions_ids['\''.$m['tsubset_answers'].'\''].')';
1134:                     }
1135:                 } elseif ($m['tsubset_type'] == 2) {
1136:                     // (MCMA : Multiple Choice Multiple Answers) -------
1137:                     // get questions with the right number of answers
1138:                     if ($m['tsubset_answers'] > 0) {
1139:                         if (!isset($answers_mcma_questions_ids['\''.$m['tsubset_answers'].'\''])) {
1140:                             $answers_mcma_questions_ids['\''.$m['tsubset_answers'].'\''] = '0';
1141:                             $sqlt = 'SELECT answer_question_id FROM '.K_TABLE_ANSWERS.' WHERE answer_enabled=\'1\''.$sql_answer_position.' GROUP BY answer_question_id HAVING (COUNT(answer_id)>='.$m['tsubset_answers'].')';
1142:                             if ($rt = F_db_query($sqlt, $db)) {
1143:                                 while ($mt = F_db_fetch_array($rt)) {
1144:                                     $answers_mcma_questions_ids['\''.$m['tsubset_answers'].'\''] .= ','.$mt['answer_question_id'];
1145:                                 }
1146:                             }
1147:                         }
1148:                         $sqlq .= ' AND question_id IN ('.$answers_mcma_questions_ids['\''.$m['tsubset_answers'].'\''].')';
1149:                     }
1150:                 } elseif ($m['tsubset_type'] == 4) {
1151:                     // ORDERING ----------------------------------------
1152:                     if (empty($answers_order_questions_ids)) {
1153:                         $answers_order_questions_ids = '0';
1154:                         $sqlt = 'SELECT answer_question_id FROM '.K_TABLE_ANSWERS.' WHERE answer_enabled=\'1\' AND answer_position>0 GROUP BY answer_question_id HAVING (COUNT(answer_id)>1)';
1155:                         if ($rt = F_db_query($sqlt, $db)) {
1156:                             while ($mt = F_db_fetch_array($rt)) {
1157:                                 $answers_order_questions_ids .= ','.$mt['answer_question_id'];
1158:                             }
1159:                         }
1160:                     }
1161:                     $sqlq .= ' AND question_id IN ('.$answers_order_questions_ids.')';
1162:                 }
1163:                 if ($random_questions) {
1164:                     $sqlq .= ' ORDER BY RAND()';
1165:                 } else {
1166:                     $sqlq .= $sql_questions_order_by;
1167:                 }
1168:                 if (K_DATABASE_TYPE == 'ORACLE') {
1169:                     $sqlq = 'SELECT * FROM ('.$sqlq.') WHERE rownum <= '.$m['tsubset_quantity'].'';
1170:                 } else {
1171:                     $sqlq .= ' LIMIT '.$m['tsubset_quantity'].'';
1172:                 }
1173:                 if ($rq = F_db_query($sqlq, $db)) {
1174:                     while ($mq = F_db_fetch_array($rq)) {
1175:                         // store questions data
1176:                         $tmp_data = array(
1177:                             'id' => $mq['question_id'],
1178:                             'type' => $mq['question_type'],
1179:                             'answers' => $m['tsubset_answers'],
1180:                             'score' => ($testdata['test_score_unanswered'] * $mq['question_difficulty'])
1181:                             );
1182:                         if ($random_questions or ($test_questions_order_mode != 0)) {
1183:                             $questions_data[] = $tmp_data;
1184:                         } else {
1185:                             $questions_data[$mq['question_position']] = $tmp_data;
1186:                         }
1187:                         $selected_questions .= ','.$mq['question_id'].'';
1188:                     } // end while select questions
1189:                 } else {
1190:                     F_display_db_error(false);
1191:                     return false;
1192:                 } // --- end 3
1193:             } // end while for each set of subjects
1194:             // 5. STORE QUESTIONS AND ANSWERS
1195:             // ------------------------------
1196:             if ($random_questions) {
1197:                 shuffle($questions_data);
1198:             } else {
1199:                 ksort($questions_data);
1200:             }
1201:             // add questions to database
1202:             $question_order = 0;
1203:             foreach ($questions_data as $key => $q) {
1204:                 $question_order++;
1205:                 $testlog_id = F_newTestLog($testuser_id, $q['id'], $q['score'], $question_order, $q['answers']);
1206:                 // Add answers
1207:                 if (!F_addQuestionAnswers($testlog_id, $q['id'], $q['type'], $q['answers'], $firsttest, $testdata)) {
1208:                     return false;
1209:                 }
1210:             }
1211:         } else {
1212:             F_display_db_error(false);
1213:             return false;
1214:         } // --- end 2
1215:     } else {
1216:         // same questions for all test-takers
1217:         // ---------------------------------------
1218:         $sql = 'SELECT *
1219:             FROM '.K_TABLE_TESTS_LOGS.', '.K_TABLE_QUESTIONS.'
1220:             WHERE question_id=testlog_question_id
1221:                 AND testlog_testuser_id='.$firsttest.'';
1222:         if (F_getBoolean($testdata['test_random_questions_order'])) {
1223:             $sql .= ' ORDER BY RAND()';
1224:         } else {
1225:             $sql .= ' ORDER BY testlog_order';
1226:         }
1227:         if ($r = F_db_query($sql, $db)) {
1228:             $question_order = 0;
1229:             while ($m = F_db_fetch_array($r)) {
1230:                 $question_order++;
1231:                 // copy values to new user test
1232:                 $question_unanswered_score = $testdata['test_score_unanswered'] * $m['question_difficulty'];
1233:                 $testlog_id = F_newTestLog($testuser_id, $m['testlog_question_id'], $question_unanswered_score, $question_order, $m['testlog_num_answers']);
1234:                 // Add answers
1235:                 if (!F_addQuestionAnswers($testlog_id, $m['question_id'], $m['question_type'], $m['testlog_num_answers'], $firsttest, $testdata)) {
1236:                     return false;
1237:                 }
1238:             }
1239:         } else {
1240:             F_display_db_error(false);
1241:             return false;
1242:         }
1243:     }
1244:     // 6. update user's test status as 1 = the test has been successfully created
1245:     // ------------------------------
1246:     $sql = 'UPDATE '.K_TABLE_TEST_USER.' SET
1247:         testuser_status=1,
1248:         testuser_creation_time=\''.date(K_TIMESTAMP_FORMAT).'\'
1249:         WHERE testuser_id='.$testuser_id.'';
1250:     if (!$r = F_db_query($sql, $db)) {
1251:         F_display_db_error(false);
1252:         return false;
1253:     }
1254:     return true;
1255: }
1256: 
1257: /**
1258:  * Add answers to selected question.
1259:  * @param $testlog_id (int) testlog ID.
1260:  * @param $question_id (int) question ID.
1261:  * @param $question_type (int) type of question.
1262:  * @param $num_answers (int) number of alternative answers to display.
1263:  * @param $firsttest (int) ID of first test testuser_id.
1264:  * @param $testdata (array) array of test data.
1265:  * @return boolean TRUE in case of success, FALSE otherwise.
1266:  */
1267: function F_addQuestionAnswers($testlog_id, $question_id, $question_type, $num_answers, $firsttest, $testdata)
1268: {
1269:     require_once('../config/tce_config.php');
1270:     global $db, $l;
1271:     if ($question_type == 3) {
1272:         // free text question
1273:         return true;
1274:     }
1275:     $randorder = F_getBoolean($testdata['test_random_answers_order']);
1276:     $ordmode = intval($testdata['test_answers_order_mode']);
1277:     // for each question
1278:     if (F_getBoolean($testdata['test_random_questions_select']) or F_getBoolean($testdata['test_random_answers_select']) or ($firsttest == 0)) {
1279:             $answers_ids = array(); // array used to store answers IDs
1280:         switch ($question_type) {
1281:             case 1: { // MCSA
1282:                 // select first right answer
1283:                 $answers_ids += F_selectAnswers($question_id, 1, false, 1, 0, $randorder, $ordmode);
1284:                 // select remaining answers
1285:                 $answers_ids += F_selectAnswers($question_id, 0, false, ($num_answers - 1), 1, $randorder, $ordmode);
1286:                 if ($ordmode == 1) {
1287:                     // reorder answers alphabetically
1288:                     $sql = 'SELECT answer_id FROM '.K_TABLE_ANSWERS.' WHERE answer_id IN ('.implode(',', $answers_ids).') ORDER BY answer_description';
1289:                     $answers_ids = array();
1290:                     if ($r = F_db_query($sql, $db)) {
1291:                         while ($m = F_db_fetch_array($r)) {
1292:                             $answers_ids[] = $m['answer_id'];
1293:                         }
1294:                     } else {
1295:                         F_display_db_error(false);
1296:                         return false;
1297:                     }
1298:                 }
1299:                 break;
1300:             }
1301:             case 2: { // MCMA
1302:                 // select answers
1303:                 $answers_ids += F_selectAnswers($question_id, '', false, $num_answers, 0, $randorder, $ordmode);
1304:                 break;
1305:             }
1306:             case 4: { // ORDERING
1307:                 // select answers
1308:                 $randorder = true;
1309:                 $answers_ids += F_selectAnswers($question_id, '', true, 0, 0, $randorder, $ordmode);
1310:                 break;
1311:             }
1312:         }
1313:             // randomizes the order of the answers
1314:         if ($randorder) {
1315:             shuffle($answers_ids);
1316:         } else {
1317:             ksort($answers_ids);
1318:         }
1319:             // add answers
1320:             F_addLogAnswers($testlog_id, $answers_ids);
1321:     } else {
1322:         // same answers for all test-takers
1323:         // --------------------------------
1324:         $sql = 'SELECT logansw_answer_id
1325:             FROM '.K_TABLE_LOG_ANSWER.', '.K_TABLE_TESTS_LOGS.'
1326:             WHERE logansw_testlog_id=testlog_id
1327:                 AND testlog_testuser_id='.$firsttest.'
1328:                 AND testlog_question_id='.$question_id.'';
1329:         if ($randorder) {
1330:             $sql .= ' ORDER BY RAND()';
1331:         } else {
1332:             $sql .= ' ORDER BY logansw_order';
1333:         }
1334:         if ($r = F_db_query($sql, $db)) {
1335:             $answers_ids = array();
1336:             while ($m = F_db_fetch_array($r)) {
1337:                 $answers_ids[] = $m['logansw_answer_id'];
1338:             }
1339:             F_addLogAnswers($testlog_id, $answers_ids);
1340:         } else {
1341:             F_display_db_error(false);
1342:             return false;
1343:         }
1344:     }
1345:     return true;
1346: }
1347: 
1348: /**
1349:  * Updates question log data (register user's answers and calculate scores).
1350:  * @param $test_id (int) test ID
1351:  * @param $testlog_id (int) test log ID
1352:  * @param $answpos (array) Array of answer positions
1353:  * @param $answer_text (string) answer text
1354:  * @param $reaction_time (int) reaction time in milliseconds
1355:  * @return boolean TRUE in case of success, FALSE otherwise
1356:  */
1357: function F_updateQuestionLog($test_id, $testlog_id, $answpos = array(), $answer_text = '', $reaction_time = 0)
1358: {
1359:     require_once('../config/tce_config.php');
1360:     global $db, $l;
1361:     $question_id = 0; // question ID
1362:     $question_type = 3; // question type
1363:     $question_difficulty = 1; // question difficulty
1364:     $oldtext = ''; // old text answer
1365:     $answer_changed = false; // true when answer change
1366:     $answer_score = 0; // answer total score
1367:     $num_answers = 0; // counts alternative answers
1368:     $test_id = intval($test_id);
1369:     $testlog_id = intval($testlog_id);
1370:     $unanswered = true;
1371:     $answer_id = F_getAnswerIdFromPosition($testlog_id, $answpos);
1372:     // get test data
1373:     $testdata = F_getTestData($test_id);
1374:     // get question information
1375:     $sql = 'SELECT *
1376:         FROM '.K_TABLE_TESTS_LOGS.', '.K_TABLE_QUESTIONS.'
1377:         WHERE testlog_question_id=question_id
1378:             AND testlog_id='.$testlog_id.'
1379:         LIMIT 1';
1380:     if ($r = F_db_query($sql, $db)) {
1381:         if ($m = F_db_fetch_array($r)) {
1382:             // get previous answer text
1383:             $oldtext = $m['testlog_answer_text'];
1384:             $question_id = $m['question_id'];
1385:             $question_type = $m['question_type'];
1386:             $question_difficulty = $m['question_difficulty'];
1387:         }
1388:     } else {
1389:         F_display_db_error();
1390:         return false;
1391:     }
1392:     // calculate question score
1393:     $question_right_score = $testdata['test_score_right'] * $question_difficulty;
1394:     $question_wrong_score = $testdata['test_score_wrong'] * $question_difficulty;
1395:     $question_unanswered_score = $testdata['test_score_unanswered'] * $question_difficulty;
1396:     if ($question_type != 3) {
1397:         $sql = 'SELECT *
1398:             FROM '.K_TABLE_LOG_ANSWER.', '.K_TABLE_ANSWERS.'
1399:             WHERE logansw_answer_id=answer_id
1400:                 AND logansw_testlog_id='.$testlog_id.'
1401:             ORDER BY logansw_order';
1402:         if ($r = F_db_query($sql, $db)) {
1403:             while (($m = F_db_fetch_array($r))) {
1404:                 $num_answers++;
1405:                 // update each answer
1406:                 $sqlu = 'UPDATE '.K_TABLE_LOG_ANSWER.' SET';
1407:                 switch ($question_type) {
1408:                     case 1: {
1409:                         // MCSA - Multiple Choice Single Answer
1410:                         if (empty($answer_id)) {
1411:                             // unanswered
1412:                             $answer_score = $question_unanswered_score;
1413:                             if ($m['logansw_selected'] != -1) {
1414:                                 $answer_changed = true;
1415:                             }
1416:                             $sqlu .= ' logansw_selected=-1';
1417:                         } elseif (!empty($answer_id[$m['logansw_answer_id']])) {
1418:                             $unanswered = false;
1419:                             // selected
1420:                             if (F_getBoolean($m['answer_isright'])) {
1421:                                 $answer_score = $question_right_score;
1422:                             } else {
1423:                                 $answer_score = $question_wrong_score;
1424:                             }
1425:                             if ($m['logansw_selected'] != 1) {
1426:                                 $answer_changed = true;
1427:                             }
1428:                             $sqlu .= ' logansw_selected=1';
1429:                         } else {
1430:                             $unanswered = false;
1431:                             // unselected
1432:                             if ($m['logansw_selected'] == 1) {
1433:                                 $answer_changed = true;
1434:                             }
1435:                             $sqlu .= ' logansw_selected=0';
1436:                         }
1437:                         break;
1438:                     }
1439:                     case 2: {
1440:                         // MCMA - Multiple Choice Multiple Answer
1441:                         if (isset($answer_id[$m['logansw_answer_id']])) {
1442:                             // radiobutton or selected checkbox
1443:                             $answer_id[$m['logansw_answer_id']] = intval($answer_id[$m['logansw_answer_id']]);
1444:                             if ($answer_id[$m['logansw_answer_id']] == -1) {
1445:                                 // unanswered
1446:                                 $answer_score += $question_unanswered_score;
1447:                             } elseif (F_getBoolean($m['answer_isright']) and ($answer_id[$m['logansw_answer_id']] == 1)) {
1448:                                 // right (selected)
1449:                                 $unanswered = false;
1450:                                 $answer_score += $question_right_score;
1451:                             } elseif (!F_getBoolean($m['answer_isright']) and ($answer_id[$m['logansw_answer_id']] == 0)) {
1452:                                 // right (unselected)
1453:                                 $unanswered = false;
1454:                                 $answer_score += $question_right_score;
1455:                             } else {
1456:                                 // wrong
1457:                                 $unanswered = false;
1458:                                 $answer_score += $question_wrong_score;
1459:                             }
1460:                             if ($m['logansw_selected'] != $answer_id[$m['logansw_answer_id']]) {
1461:                                 $answer_changed = true;
1462:                             }
1463:                             $sqlu .= ' logansw_selected='.$answer_id[$m['logansw_answer_id']].'';
1464:                         } else {
1465:                             // unselected checkbox
1466:                             $unanswered = false;
1467:                             if (F_getBoolean($m['answer_isright'])) {
1468:                                 $answer_score += $question_wrong_score;
1469:                             } else {
1470:                                 $answer_score += $question_right_score;
1471:                             }
1472:                             if ($m['logansw_selected'] != 0) {
1473:                                 $answer_changed = true;
1474:                             }
1475:                             $sqlu .= ' logansw_selected=0';
1476:                         }
1477:                         break;
1478:                     }
1479:                     case 4: {
1480:                         // ORDER
1481:                         if (!empty($answer_id[$m['logansw_answer_id']])) {
1482:                             // selected
1483:                             $unanswered = false;
1484:                             $answer_id[$m['logansw_answer_id']] = intval($answer_id[$m['logansw_answer_id']]);
1485:                             if ($answer_id[$m['logansw_answer_id']] == $m['answer_position']) {
1486:                                 $answer_score += $question_right_score;
1487:                             } else {
1488:                                 $answer_score += $question_wrong_score;
1489:                             }
1490:                             if ($answer_id[$m['logansw_answer_id']] != $m['logansw_position']) {
1491:                                 $answer_changed = true;
1492:                             }
1493:                             $sqlu .= ' logansw_position='.$answer_id[$m['logansw_answer_id']].', logansw_selected=1';
1494:                         } else {
1495:                             // unanswered
1496:                             $answer_score += $question_unanswered_score;
1497:                             if ($m['logansw_position'] > 0) {
1498:                                 $answer_changed = true;
1499:                             }
1500:                             $sqlu .= ' logansw_selected=-1, logansw_position=0';
1501:                         }
1502:                         break;
1503:                     }
1504:                 } // end of switch
1505:                 $sqlu .= ' WHERE logansw_testlog_id='.$testlog_id.' AND logansw_answer_id='.$m['logansw_answer_id'].'';
1506:                 if (!$ru = F_db_query($sqlu, $db)) {
1507:                     F_display_db_error();
1508:                     return false;
1509:                 }
1510:             }
1511:             if ($question_type > 1) {
1512:                 // normalize score
1513:                 if (F_getBoolean($testdata['test_mcma_partial_score'])) {
1514:                     // use partial scoring for MCMA and ORDER questions
1515:                     $answer_score = round(($answer_score / $num_answers), 3);
1516:                 } else {
1517:                     // all-or-nothing points
1518:                     if ($answer_score >= ($question_right_score * $num_answers)) {
1519:                         // right
1520:                         $answer_score = $question_right_score;
1521:                     } elseif ($answer_score == ($question_unanswered_score * $num_answers)) {
1522:                         // unanswered
1523:                         $answer_score = $question_unanswered_score;
1524:                     } else {
1525:                         // wrong
1526:                         $answer_score = $question_wrong_score;
1527:                     }
1528:                 }
1529:             }
1530:         } else {
1531:             F_display_db_error();
1532:             return false;
1533:         }
1534:     }
1535:     // update log if answer is changed
1536:     if ($answer_changed or ($oldtext != $answer_text)) {
1537:         if (strlen($answer_text) > 0) {
1538:             $unanswered = false;
1539:             $answer_score = 'NULL';
1540:             // check exact answers score
1541:             $sql = 'SELECT *
1542:                 FROM '.K_TABLE_ANSWERS.'
1543:                 WHERE answer_question_id='.$question_id.'
1544:                     AND answer_enabled=\'1\'
1545:                     AND answer_isright=\'1\'';
1546:             if ($r = F_db_query($sql, $db)) {
1547:                 while ($m = F_db_fetch_array($r)) {
1548:                     if ((K_SHORT_ANSWERS_BINARY and (strcmp(trim($answer_text), $m['answer_description']) == 0))
1549:                         or (!K_SHORT_ANSWERS_BINARY and (strcasecmp(trim($answer_text), $m['answer_description']) == 0))) {
1550:                         $answer_score += $question_right_score;
1551:                         break;
1552:                     }
1553:                 }
1554:             } else {
1555:                 F_display_db_error();
1556:                 return false;
1557:             }
1558:         }
1559:         if ($unanswered) {
1560:             $change_time = '';
1561:         } else {
1562:             $change_time = date(K_TIMESTAMP_FORMAT);
1563:         }
1564:         $sqlu = 'UPDATE '.K_TABLE_TESTS_LOGS.' SET';
1565:         $sqlu .= ' testlog_answer_text='.F_empty_to_null($answer_text).',';
1566:         $sqlu .= ' testlog_score='.$answer_score.',';
1567:         $sqlu .= ' testlog_change_time='.F_empty_to_null($change_time).',';
1568:         $sqlu .= ' testlog_reaction_time='.intval($reaction_time).',';
1569:         $sqlu .= ' testlog_user_ip=\''.getNormalizedIP($_SERVER['REMOTE_ADDR']).'\'';
1570:         $sqlu .= ' WHERE testlog_id='.$testlog_id.'';
1571:         if (!$ru = F_db_query($sqlu, $db)) {
1572:             F_display_db_error();
1573:             return false;
1574:         }
1575:     }
1576:     return true;
1577: }
1578: 
1579: /**
1580:  * Returns the answer ID from position
1581:  * @param $testlog_id (int) Test Log ID
1582:  * @param $answpos (array) Answer positions (order in wich they are displayed)
1583:  * @return int answer ID
1584:  */
1585: function F_getAnswerIdFromPosition($testlog_id, $answpos)
1586: {
1587:     require_once('../config/tce_config.php');
1588:     global $db, $l;
1589:     $answer_id = array();
1590:     foreach ($answpos as $pos => $val) {
1591:         $sql = 'SELECT logansw_answer_id'
1592:             .' FROM '.K_TABLE_LOG_ANSWER
1593:             .' WHERE logansw_testlog_id='.intval($testlog_id)
1594:             .' AND logansw_order='.intval($pos)
1595:             .' LIMIT 1';
1596:         if ($r = F_db_query($sql, $db)) {
1597:             if ($m = F_db_fetch_array($r)) {
1598:                 $answer_id[intval($m['logansw_answer_id'])] = $val;
1599:             }
1600:         } else {
1601:             F_display_db_error();
1602:         }
1603:     }
1604:     return $answer_id;
1605: }
1606: 
1607: /**
1608:  * Returns a formatted XHTML form code to handle the specified question.<br>
1609:  * Form fields names are: answer_text, answer_id<br>
1610:  * CSS classes:<ul>
1611:  * <li>div.tcecontentbox</li>
1612:  * <li>div.rowl</li>
1613:  * <li>textarea.answertext</li>
1614:  * </ul>
1615:  * @param $test_id (int) test ID
1616:  * @param $testlog_id (int) test log ID
1617:  * @param $formname (string) form name (form ID)
1618:  * @return string XHTML code
1619:  */
1620: function F_questionForm($test_id, $testlog_id, $formname)
1621: {
1622:     require_once('../config/tce_config.php');
1623:     require_once('../../shared/code/tce_functions_tcecode.php');
1624:     global $db, $l, $examtime, $timeout_logout;
1625:     $test_id = intval($test_id);
1626:     $testlog_id = intval($testlog_id);
1627:     $user_id = intval($_SESSION['session_user_id']);
1628:     $aswkeys = array();
1629:     $str = '';
1630:     if (!isset($test_id) or ($test_id == 0)) {
1631:         return;
1632:     }
1633:     $testdata = F_getTestData($test_id);
1634:     $noanswer_hidden = '';
1635:     $noanswer_disabled = '';
1636:     if (!F_getBoolean($testdata['test_noanswer_enabled'])) {
1637:         $noanswer_hidden = ' style="visibility:hidden;display:none;"';
1638:         $noanswer_disabled = ' readonly="readonly" disabled="disabled"';
1639:     }
1640:     // select question for the first time
1641:     if (!isset($testlog_id) or ($testlog_id == 0)) {
1642:         //select first question
1643:         $sql = 'SELECT testlog_id
1644:             FROM '.K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS.'
1645:             WHERE testlog_testuser_id=testuser_id
1646:                 AND testuser_test_id='.$test_id.'
1647:                 AND testuser_user_id='.$user_id.'
1648:                 AND testuser_status<5
1649:             ORDER BY testlog_id
1650:             LIMIT 1';
1651:         if ($r = F_db_query($sql, $db)) {
1652:             if ($m = F_db_fetch_array($r)) {
1653:                 $testlog_id = $m['testlog_id'];
1654:             } else {
1655:                 return;
1656:             }
1657:         } else {
1658:             F_display_db_error();
1659:         }
1660:     }
1661:     // build selection query for question to display
1662:     $sql = 'SELECT *
1663:             FROM '.K_TABLE_QUESTIONS.', '.K_TABLE_TESTS_LOGS.'
1664:             WHERE question_id=testlog_question_id
1665:                 AND testlog_id='.$testlog_id.'
1666:             LIMIT 1';
1667:     if ($r = F_db_query($sql, $db)) {
1668:         if ($m = F_db_fetch_array($r)) {
1669:             if (F_getBoolean($m['question_fullscreen'])) {
1670:                 // hide some section for fullscreen mode
1671:                 $str .= '<style>'.K_NEWLINE;
1672:                 $str .= '.header{visibility:hidden;display:none;}'.K_NEWLINE;
1673:                 $str .= '.infolink{visibility:hidden;display:none;}'.K_NEWLINE;
1674:                 $str .= 'h1{visibility:hidden;display:none;}'.K_NEWLINE;
1675:                 $str .= '.pagehelp{visibility:hidden;display:none;}'.K_NEWLINE;
1676:                 $str .= '.userbar{visibility:hidden;display:none;}'.K_NEWLINE;
1677:                 $str .= '.minibutton{visibility:hidden;display:none;}'.K_NEWLINE;
1678:                 $str .= '.navlink{visibility:hidden;display:none;}'.K_NEWLINE;
1679:                 $str .= '.testcomment{visibility:hidden;display:none;}'.K_NEWLINE;
1680:                 $str .= '#terminatetest{visibility:hidden;display:none;}'.K_NEWLINE;
1681:                 $str .= '</style>'.K_NEWLINE;
1682:             }
1683:             $str .= '<input type="hidden" name="testid" id="testid" value="'.$test_id.'" />'.K_NEWLINE;
1684:             $str .= '<input type="hidden" name="testlogid" id="testlogid" value="'.$testlog_id.'" />'.K_NEWLINE;
1685:             $str .= '<input type="hidden" name="testuser_id" id="testuser_id" value="'.$m['testlog_testuser_id'].'" />'.K_NEWLINE;
1686:             // get test data
1687:             $test_data = F_getTestData($test_id);
1688:             // store time information for interactive timer
1689:             $examtime = F_getTestStartTime($m['testlog_testuser_id']) + ($test_data['test_duration_time'] * K_SECONDS_IN_MINUTE);
1690:             $str .= '<input type="hidden" name="examtime" id="examtime" value="'.$examtime.'" />'.K_NEWLINE;
1691:             if (F_getBoolean($test_data['test_logout_on_timeout'])) {
1692:                 $str .= '<input type="hidden" name="timeout_logout" id="timeout_logout" value="1" />'.K_NEWLINE;
1693:             }
1694:             $str .= '<a name="questionsection" id="questionsection"></a>'.K_NEWLINE;
1695:             $str .= '<div class="tcecontentbox">'.K_NEWLINE;
1696:             //fieldset
1697:             //$str .= '<legend>';
1698:             //$str .= $l['w_question'];
1699:             //$str .= '</legend>'.K_NEWLINE;
1700:             // display question description
1701:             if ($m['question_type'] == 3) {
1702:                 $str .= '<label for="answertext">';
1703:             }
1704:             $str .= F_decode_tcecode($m['question_description']).K_NEWLINE;
1705:             if ($m['question_type'] == 3) {
1706:                 $str .= '</label>';
1707:             }
1708:             $str .= '<div class="row">'.K_NEWLINE;
1709:             $str .= '<hr/>'.K_NEWLINE;
1710:             $str .= '</div>'.K_NEWLINE;
1711:             $str .= '<div class="rowl">'.K_NEWLINE;
1712:             if ($m['question_type'] == 3) {
1713:                 // TEXT - free text question
1714:                 if (K_ENABLE_VIRTUAL_KEYBOARD) {
1715:                     $str .= '<script src="'.K_PATH_SHARED_JSCRIPTS.'vk/vk_easy.js?vk_skin=default" type="text/javascript"></script>'.K_NEWLINE;
1716:                 }
1717:                 $str .= '<textarea cols="'.K_ANSWER_TEXTAREA_COLS.'" rows="'.K_ANSWER_TEXTAREA_ROWS.'" name="answertext" id="answertext" onchange="saveAnswer()"';
1718:                 if (K_ENABLE_VIRTUAL_KEYBOARD) {
1719:                     $str .= 'keyboardInput ';
1720:                 }
1721:                 $str .= 'answertext">';
1722:                 $str .= $m['testlog_answer_text'];
1723:                 $str .= '</textarea>'.K_NEWLINE;
1724:             } else {
1725:                 // multiple-choice question
1726:                 $checked = false;
1727:                 if (F_getBoolean($m['question_inline_answers'])) {
1728:                     // inline display
1729:                     $str .= '<ol class="answer_inline">'.K_NEWLINE;
1730:                 } else {
1731:                     $str .= '<ol class="answer">'.K_NEWLINE;
1732:                 }
1733:                 if ($m['question_type'] == 4) {
1734:                     // get max positions for odering questions
1735:                     $max_position = F_count_rows(K_TABLE_LOG_ANSWER, 'WHERE logansw_testlog_id='.$testlog_id.'');
1736:                 }
1737:                 // display answer options
1738:                 $sqla = 'SELECT *
1739:                     FROM '.K_TABLE_ANSWERS.', '.K_TABLE_LOG_ANSWER.'
1740:                     WHERE logansw_answer_id=answer_id
1741:                         AND logansw_testlog_id='.$testlog_id.'
1742:                     ORDER BY logansw_order';
1743:                 if ($ra = F_db_query($sqla, $db)) {
1744:                     while ($ma = F_db_fetch_array($ra)) {
1745:                         $anspos = $ma['logansw_order'];
1746:                         $str .= '<li>';
1747:                         switch ($m['question_type']) {
1748:                             case 1: {
1749:                                 // MCSA - single-answer question
1750:                                 $str .= '<input type="radio" name="answpos" id="answpos_'.$anspos.'" value="'.$anspos.'"';
1751:                                 if (intval($ma['logansw_selected']) == 1) {
1752:                                     $str .= ' checked="checked"';
1753:                                     $checked = true;
1754:                                 }
1755:                                 if (F_getBoolean($m['question_auto_next'])) {
1756:                                     $str .= " onclick=\"var submittime=new Date();document.getElementById('reaction_time').value=submittime.getTime()-document.getElementById('display_time').value;document.getElementById('autonext').value=1;document.getElementById('".$formname."').submit();\"";
1757:                                 }
1758:                                 $str .= ' />&nbsp;';
1759:                                 $str .= '<label for="answpos_'.$anspos.'">';
1760:                                 $str .= F_decode_tcecode($ma['answer_description']);
1761:                                 $str .= '</label>';
1762:                                 if ($ma['answer_keyboard_key'] > 0) {
1763:                                     $aswkeys[$ma['answer_keyboard_key']] = 'answpos_'.$anspos;
1764:                                 }
1765:                                 break;
1766:                             }
1767:                             case 2: {
1768:                                 // MCMA - multiple-answer question
1769:                                 if (F_getBoolean($testdata['test_mcma_radio'])) {
1770:                                     // radiobuttons
1771: 
1772:                                     // no-answer option
1773:                                     $str .= '<span style="background-color:#DDDDDD;"'.$noanswer_hidden.'>&nbsp;';
1774:                                     $str .= '<label for="answpos_'.$anspos.'u" title="'.$l['m_unanswered'].'">'.$l['w_unanswered_acronym'].'</label>';
1775:                                     $str .= '<input type="radio"'.$noanswer_disabled.' name="answpos['.$anspos.']" id="answpos_'.$anspos.'u" value="-1" title="'.$l['m_unanswered'].'"';
1776:                                     if (intval($ma['logansw_selected']) == -1) {
1777:                                         $str .= ' checked="checked"';
1778:                                     }
1779:                                     $str .= ' />';
1780:                                     $str .= '</span>&nbsp;';
1781: 
1782:                                     // false option
1783:                                     $str .= '<span style="background-color:#FFBBBB;">&nbsp;';
1784:                                     $str .= '<label for="answpos_'.$anspos.'f" title="'.$l['w_false'].'">'.$l['w_false_acronym'].'</label>';
1785:                                     $str .= '<input type="radio" name="answpos['.$anspos.']" id="answpos_'.$anspos.'f" value="0"';
1786:                                     if (intval($ma['logansw_selected']) == 0) {
1787:                                         $str .= ' checked="checked"';
1788:                                     }
1789:                                     $str .= ' />';
1790:                                     $str .= '</span>&nbsp;';
1791: 
1792:                                     // true option
1793:                                     $str .= '<span style="background-color:#BBFFBB;">&nbsp;';
1794:                                     $str .= '<label for="answpos_'.$anspos.'t" title="'.$l['w_true'].'">'.$l['w_true_acronym'].'</label>';
1795:                                     $str .= '<input type="radio" name="answpos['.$anspos.']" id="answpos_'.$anspos.'t" value="1"';
1796:                                     if (intval($ma['logansw_selected']) == 1) {
1797:                                         $str .= ' checked="checked"';
1798:                                     }
1799:                                     $str .= ' />';
1800:                                     $str .= '</span>&nbsp;';
1801:                                     if ($ma['answer_keyboard_key'] > 0) {
1802:                                         $aswkeys[] = array($ma['answer_keyboard_key'] => 'answpos_'.$anspos.'t');
1803:                                     }
1804: 
1805:                                     $str .= F_decode_tcecode($ma['answer_description']);
1806:                                 } else {
1807:                                     // checkbox
1808:                                     $str .= '<input type="checkbox" name="answpos['.$anspos.']" id="answpos_'.$anspos.'" value="1"';
1809:                                     if (intval($ma['logansw_selected']) == 1) {
1810:                                         $str .= ' checked="checked"';
1811:                                         $checked = true;
1812:                                     }
1813:                                     $str .= ' />&nbsp;';
1814:                                     $str .= '<label for="answpos_'.$anspos.'">';
1815:                                     $str .= F_decode_tcecode($ma['answer_description']);
1816:                                     $str .= '</label>';
1817:                                 }
1818:                                 break;
1819:                             }
1820:                             case 4: {
1821:                                 // ORDER - ordering questions
1822:                                 $str .= '<select name="answpos['.$anspos.']" id="answpos_'.$anspos.'" size="0">'.K_NEWLINE;
1823:                                 if (F_getBoolean($testdata['test_noanswer_enabled'])) {
1824:                                     $str .= '<option value="0">&nbsp;</option>'.K_NEWLINE;
1825:                                 }
1826:                                 for ($pos=1; $pos <= $max_position; $pos++) {
1827:                                     $str .= '<option value="'.$pos.'"';
1828:                                     if ($pos == $ma['logansw_position']) {
1829:                                         $str .= ' selected="selected"';
1830:                                     }
1831:                                     $str .= '>'.$pos.'</option>'.K_NEWLINE;
1832:                                 }
1833:                                 $str .= '</select>'.K_NEWLINE;
1834:                                 $str .= '<label for="answpos_'.$anspos.'">';
1835:                                 $str .= F_decode_tcecode($ma['answer_description']);
1836:                                 $str .= '</label>';
1837:                                 break;
1838:                             }
1839:                         } // end of switch
1840:                         $str .= '</li>'.K_NEWLINE;
1841:                     } // end of while
1842:                 } else {
1843:                     F_display_db_error();
1844:                 }
1845:                 if ($m['question_type'] == 1) {
1846:                     // display default "unanswered" option for MCSA
1847:                     $str .= '<li'.$noanswer_hidden.'>';
1848:                     $str .= '<input type="radio"'.$noanswer_disabled.' name="answpos" id="answpos_0" value="0"';
1849:                     if (!$checked) {
1850:                         $str .= ' checked="checked"';
1851:                     }
1852:                     $str .= ' />&nbsp;';
1853:                     $str .= '<label for="answpos_0">';
1854:                     $str .= $l['m_unanswered'];
1855:                     $str .= '</label>';
1856:                     $str .= '</li>'.K_NEWLINE;
1857:                 }
1858: 
1859:                 $str .= '</ol>'.K_NEWLINE;
1860:             } // end multiple answers
1861:             $str .= '</div>'.K_NEWLINE;
1862:             $str .= '</div>'.K_NEWLINE; //fieldset
1863:             // javascript code
1864:             $str .= '<script type="text/javascript">'.K_NEWLINE;
1865:             $str .= '//<![CDATA['.K_NEWLINE;
1866:             // script to handle keyboard events
1867:             $str .= 'function actionByChar(e){e=(e)?e:window.event;keynum=(e.keyCode)?e.keyCode:e.which;switch(keynum){'.K_NEWLINE;
1868:             foreach ($aswkeys as $key => $fieldid) {
1869:                 $str .= 'case '.$key.':{document.getElementById(\''.$fieldid.'\').checked=true;var submittime=new Date();document.getElementById(\'reaction_time\').value=submittime.getTime()-document.getElementById(\'display_time\').value;document.getElementById(\'autonext\').value=1;document.getElementById(\''.$formname.'\').submit();break;}'.K_NEWLINE;
1870:             }
1871:             $str .= '}}'.K_NEWLINE;
1872:             $str .= 'if (!document.all) {document.captureEvents(Event.KEYPRESS);}';
1873:             $str .= 'document.onkeypress=actionByChar;'.K_NEWLINE;
1874:             // script for autosaving text answers
1875:             if ($m['question_type'] == 3) {
1876:                 // check if local storage is enabled (HTML5)
1877:                 $str .= 'var enable_storage=(typeof(Storage)!=="undefined");'.K_NEWLINE;
1878:                 // function to save the text answer locally
1879:                 $str .= 'function saveAnswer(){if(enable_storage){localStorage.answertext'.$testlog_id.'=document.getElementById("answertext").value;}}'.K_NEWLINE;
1880:                 // initialize the text answer with the saved value
1881:                 $str .= 'if(enable_storage && localStorage.answertext'.$testlog_id.'){document.getElementById("answertext").value=localStorage.answertext'.$testlog_id.';}'.K_NEWLINE;
1882:             }
1883:             // script for autonext
1884:             if ($m['question_timer'] > 0) {
1885:                 // automatic submit form after specified amount of time
1886:                 $str .= "setTimeout('document.getElementById(\'autonext\').value=1;document.getElementById(\'".$formname."\').submit();', ".($m['question_timer'] * 1000).");".K_NEWLINE;
1887:             }
1888:             $str .= '//]]>'.K_NEWLINE;
1889:             $str .= '</script>'.K_NEWLINE;
1890:             // display questions menu
1891:             $str .= F_questionsMenu($testdata, $m['testlog_testuser_id'], $testlog_id, F_getBoolean($m['question_fullscreen']));
1892:         }
1893:         if (empty($m['testlog_display_time'])) {
1894:             // mark test as displayed:
1895:             $sqlu = 'UPDATE '.K_TABLE_TESTS_LOGS.'
1896:                 SET testlog_display_time=\''.date(K_TIMESTAMP_FORMAT).'\'
1897:                 WHERE testlog_id='.$testlog_id.'';
1898:             if (!$ru = F_db_query($sqlu, $db)) {
1899:                 F_display_db_error();
1900:             }
1901:         }
1902:     } else {
1903:         F_display_db_error();
1904:     }
1905:     return $str;
1906: }
1907: 
1908: /**
1909:  * Returns a questions menu and navigator buttons.
1910:  * @param $testdata (array) test data
1911:  * @param $testuser_id (int) user's test ID
1912:  * @param $testlog_id (int) test log ID
1913:  * @param $disable (boolean) if TRUE disable the questions list.
1914:  * @return string XHTML code
1915:  */
1916: function F_questionsMenu($testdata, $testuser_id, $testlog_id = 0, $disable = false)
1917: {
1918:     require_once('../config/tce_config.php');
1919:     require_once('../../shared/code/tce_functions_tcecode.php');
1920:     global $db, $l;
1921:     $testuser_id = intval($testuser_id);
1922:     $testlog_id = intval($testlog_id);
1923:     $str = '';
1924:     $testlog_id_prev = 0; // previous question ID
1925:     $testlog_id_next = 0; // next question ID
1926:     $testlog_id_last = 0; // temp variable
1927:     $sql = 'SELECT question_description, question_difficulty, question_timer, testlog_id, testlog_answer_text, testlog_display_time, testlog_change_time
1928:         FROM '.K_TABLE_QUESTIONS.', '.K_TABLE_TESTS_LOGS.'
1929:         WHERE question_id=testlog_question_id
1930:             AND testlog_testuser_id='.$testuser_id.'
1931:         ORDER BY testlog_id';
1932:     if ($r = F_db_query($sql, $db)) {
1933:         $i = 0;
1934:         $qprev = '';
1935:         $qsel = 1;
1936:         while ($m = F_db_fetch_array($r)) {
1937:             ++$i;
1938:             if ($m['testlog_id'] != $testlog_id) {
1939:                 $str .= '<li>';
1940:                 $str .= '<input type="submit" name="jumpquestion_'.$m['testlog_id'].'" id="jumpquestion_'.$m['testlog_id'].'" value="&gt;" title="'.F_tcecodeToTitle($m['question_description']).'" /> ';
1941:                 if ($testlog_id_last == $testlog_id) {
1942:                     $testlog_id_next = $m['testlog_id'];
1943:                 }
1944:             } else {
1945:                 $str .= '<li class="selected">';
1946:                 $str .= '<input type="button" name="jumpquestion_'.$m['testlog_id'].'" id="jumpquestion_'.$m['testlog_id'].'" value="&gt;" title="'.F_tcecodeToTitle($m['question_description']).'" disabled="disabled"/> ';
1947:                 $testlog_id_prev = $testlog_id_last;
1948:                 $question_timer = F_getBoolean($m['question_timer']);
1949:                 $qsel = $i;
1950:                 if ($qsel > 1) {
1951:                     $qprev = ' ('.($i - 1).')';
1952:                 }
1953:             }
1954:             // display mark when the current question has been displayed
1955:             $str .= '<acronym';
1956:             if (!empty($m['testlog_display_time'])) {
1957:                 $str .= ' class="onbox"';
1958:                 $str .= ' title="'.$l['h_question_displayed'].'">+';
1959:             } else {
1960:                 $str .= ' class="offbox"';
1961:                 $str .= ' title="'.$l['h_question_not_displayed'].'">-';
1962:             }
1963:             $str .= '</acronym>';
1964: 
1965:             $str .= '&nbsp;';
1966: 
1967:             // show mark when the current question has been answered
1968:             $str .= '<acronym';
1969:             if (!empty($m['testlog_change_time'])) {
1970:                 $str .= ' class="onbox"';
1971:                 $str .= ' title="'.$l['h_question_answered'].'">+';
1972:             } else {
1973:                 $str .= ' class="offbox"';
1974:                 $str .= ' title="'.$l['h_question_not_answered'].'">-';
1975:             }
1976:             $str .= '</acronym>';
1977:             $str .= '&nbsp;';
1978:             // show question score
1979:             $n_question_score = $testdata['test_score_right'] * $m['question_difficulty'];
1980:             $str .= '<acronym class="offbox" title="'.$l['w_max_score'].': '.$n_question_score.'">';
1981:             $str .= sprintf('% 5.1f', $n_question_score);
1982:             $str .= '</acronym>';
1983:             $str .= '&nbsp;';
1984:             if ($testlog_id == 0) {
1985:                 $testlog_id = $m['testlog_id'];
1986:                 $testlog_id_last = $testlog_id;
1987:             }
1988:             $testlog_id_last = $m['testlog_id'];
1989:             $str .= F_tcecodeToLine($m['question_description']);
1990:             $str .= '</li>'.K_NEWLINE;
1991:         }
1992:     } else {
1993:         F_display_db_error();
1994:     }
1995:     // build quick navigator links (previous - next)
1996:     $navlink = '';
1997: 
1998:     // button for previous question
1999:     if (!$question_timer) {
2000:         $navlink .= '<input type="submit" name="prevquestion" id="prevquestion" title="'.$l['w_previous'].'" value="&lt; '.$l['w_previous'].$qprev.'"';
2001:         if (($testlog_id_prev <= 0) or ($testlog_id_prev > $testlog_id)) {
2002:             $navlink .= ' disabled="disabled"';
2003:         }
2004:         $navlink .= ' />';
2005:         // button for confirm current question
2006:         $navlink .= '<input type="submit" name="confirmanswer" id="confirmanswer" value="('.$qsel.') '.$l['w_confirm'].'" />';
2007:     }
2008: 
2009:     // button for next question
2010:     $qnext = '';
2011:     if ($testlog_id_next > 0) {
2012:         $qnext = '('.($qsel + 1).') ';
2013:     }
2014:     $navlink .= '<input type="submit" name="nextquestion" id="nextquestion" title="'.$l['w_next'].'" value="'.$qnext.$l['w_next'].' &gt;"';
2015:     if ($testlog_id_next <= 0) {
2016:         $navlink .= ' disabled="disabled"';
2017:     }
2018:     $navlink .= ' />'.K_NEWLINE;
2019: 
2020:     if (($question_timer or $disable) and ($testlog_id_next <= 0)) {
2021:         // force test termination
2022:         $navlink .= '<input type="hidden" name="forceterminate" id="forceterminate" value="lasttimedquestion" />'.K_NEWLINE;
2023:     }
2024: 
2025:     $navlink .= '<input type="hidden" name="prevquestionid" id="prevquestionid" value="'.$testlog_id_prev.'" />'.K_NEWLINE;
2026:     $navlink .= '<input type="hidden" name="nextquestionid" id="nextquestionid" value="'.$testlog_id_next.'" />'.K_NEWLINE;
2027:     $navlink .= '<input type="hidden" name="autonext" id="autonext" value="" />'.K_NEWLINE;
2028:     $navlink = '<div class="navlink">'.$navlink.'</div>'.K_NEWLINE;
2029:     $rstr = '';
2030:     $rstr .= '<br />'.K_NEWLINE;
2031:     $rstr .= $navlink;
2032:     $rstr .= '<br />'.K_NEWLINE;
2033:     if (F_getBoolean($testdata['test_menu_enabled']) and (!$disable)) {
2034:         // display questions menu
2035:         $rstr .= '<a name="questionssection" id="questionssection"></a>'.K_NEWLINE;
2036:         $rstr .= '<div class="tcecontentbox">'.K_NEWLINE; //fieldset
2037:         //$rstr .= '<legend>';
2038:         $rstr .= $l['w_questions'];
2039:         //$rstr .= '</legend>'.K_NEWLINE;
2040:         $rstr .= '<ol class="qlist">'.K_NEWLINE.$str.'</ol>'.K_NEWLINE;
2041:         $rstr .= '</div>'.K_NEWLINE; //fieldset
2042:         $rstr .= '<br />'.K_NEWLINE;
2043:     }
2044:     return $rstr;
2045: }
2046: 
2047: /**
2048:  * Returns the number of omitted questions (unanswered + undisplayed).
2049:  * @param $test_id (int) test ID
2050:  * @return integer number
2051:  */
2052: function F_getNumOmittedQuestions($test_id)
2053: {
2054:     require_once('../config/tce_config.php');
2055:     global $db, $l;
2056:     $test_id = intval($test_id);
2057:     $user_id = intval($_SESSION['session_user_id']);
2058:     // get the number of omitted questions
2059:     $omitted = F_count_rows(
2060:         K_TABLE_TEST_USER.', '.K_TABLE_TESTS_LOGS,
2061:         'WHERE testlog_testuser_id=testuser_id
2062:             AND testuser_test_id='.$test_id.'
2063:             AND testuser_user_id='.$user_id.'
2064:             AND testuser_status<5
2065:             AND (testlog_change_time IS NULL OR testlog_display_time IS NULL)'
2066:     );
2067:     return $omitted;
2068: }
2069: 
2070: /**
2071:  * Display a textarea for user's comment.<br>
2072:  * @param $test_id (int) test ID
2073:  * @return string XHTML code
2074:  * @since 4.0.000 (2006-10-01)
2075:  */
2076: function F_testComment($test_id)
2077: {
2078:     require_once('../config/tce_config.php');
2079:     global $db, $l;
2080:     $test_id = intval($test_id);
2081:     $td = F_getTestData($test_id);
2082:     $user_id = intval($_SESSION['session_user_id']);
2083:     $str = '';
2084:     // user's comment
2085:     if (F_getBoolean($td['test_comment_enabled'])) {
2086:         // get user's test comment
2087:         $comment = '';
2088:         $sql = 'SELECT testuser_comment
2089:         FROM '.K_TABLE_TEST_USER.'
2090:         WHERE testuser_user_id='.$user_id.'
2091:             AND testuser_test_id='.$test_id.'
2092:             AND testuser_status<4
2093:         LIMIT 1';
2094:         if ($r = F_db_query($sql, $db)) {
2095:             if ($m = F_db_fetch_array($r)) {
2096:                 $comment = $m['testuser_comment'];
2097:             }
2098:         } else {
2099:             F_display_db_error();
2100:         }
2101:         $str .= '<label for="testcomment">'.$l['w_comment'].'</label><br />';
2102:         $str .= '<textarea cols="'.K_ANSWER_TEXTAREA_COLS.'" rows="4" name="testcomment" id="testcomment" class="answertext" title="'.$l['h_testcomment'].'">'.$comment.'</textarea><br />'.K_NEWLINE;
2103:     }
2104:     return $str;
2105: }
2106: 
2107: /**
2108:  * Updates user's test comment.<br>
2109:  * @param $test_id (int) test ID
2110:  * @param $testcomment (string) user comment.
2111:  * @return string XHTML code
2112:  * @since 4.0.000 (2006-10-01)
2113:  */
2114: function F_updateTestComment($test_id, $testcomment)
2115: {
2116:     require_once('../config/tce_config.php');
2117:     global $db, $l;
2118:     $test_id = intval($test_id);
2119:     $testcomment = F_escape_sql($db, $testcomment);
2120:     $user_id = intval($_SESSION['session_user_id']);
2121:     $sql = 'UPDATE '.K_TABLE_TEST_USER.'
2122:         SET testuser_comment=\''.$testcomment.'\'
2123:         WHERE testuser_test_id='.$test_id.'
2124:             AND testuser_user_id='.$user_id.'
2125:             AND testuser_status<4';
2126:     if (!$r = F_db_query($sql, $db)) {
2127:         F_display_db_error();
2128:     }
2129: }
2130: 
2131: /**
2132:  * Returns XHTML / CSS formatted page string to insert the test password.<br>
2133:  * The CSS classes used are:
2134:  * <ul>
2135:  * <li>div.login_form : container for login box</li>
2136:  * <li>div.login_form div.login_row : container for label + input field or button</li>
2137:  * <li>div.login_form div.login_row span.label : container for input label</li>
2138:  * <li>div.login_form div.login_row span.formw : container for input form</li>
2139:  * </ul>
2140:  * @param faction String action attribute
2141:  * @param fid String form ID attribute
2142:  * @param fmethod String method attribute (get/post)
2143:  * @param fenctype String enctype attribute
2144:  * @param test_id int ID of the test
2145:  * @return XHTML string for login form
2146:  */
2147: function F_testLoginForm($faction, $fid, $fmethod, $fenctype, $test_id)
2148: {
2149:     global $l;
2150:     require_once('../config/tce_config.php');
2151:     $str = '';
2152:     $str .= '<div class="container">'.K_NEWLINE;
2153:     $str .= '<div class="tceformbox">'.K_NEWLINE;
2154:     $str .= '<form action="'.$faction.'" method="'.$fmethod.'" id="'.$fid.'" enctype="'.$fenctype.'">'.K_NEWLINE;
2155:     // test password
2156:     $str .= getFormRowTextInput('xtest_password', $l['w_test_password'], $l['h_test_password'], '', '', '', 255, false, false, true, '');
2157:     // buttons
2158:     $str .= '<div class="row">'.K_NEWLINE;
2159:     $str .= '<input type="submit" name="login" id="login" value="'.$l['w_login'].'" title="'.$l['h_login_button'].'" />'.K_NEWLINE;
2160:     // the following field is used to check if the form has been submitted
2161:     $str .= '<input type="hidden" name="testpswaction" id="testpswaction" value="login" />'.K_NEWLINE;
2162:     $str .= '<input type="hidden" name="testid" id="testid" value="'.intval($test_id).'" />'.K_NEWLINE;
2163:     $str .= '</div>'.K_NEWLINE;
2164:     $str .= '</form>'.K_NEWLINE;
2165:     $str .= '</div>'.K_NEWLINE;
2166:     $str .= '<div class="pagehelp">'.$l['hp_test_password'].'</div>'.K_NEWLINE;
2167:     $str .= '</div>'.K_NEWLINE;
2168:     return $str;
2169: }
2170: 
2171: /**
2172:  * Get a comma separated list of valid group IDs for the selected test.
2173:  * @param $test_id (int) ID of the selected test
2174:  * @return string containing a comma separated list fo group IDs.
2175:  */
2176: function F_getTestGroups($test_id)
2177: {
2178:     require_once('../config/tce_config.php');
2179:     global $db, $l;
2180:     $test_id = intval($test_id);
2181:     $ids = '0';
2182:     // select groups in this test
2183:     $sql = 'SELECT tstgrp_group_id FROM '.K_TABLE_TEST_GROUPS.' WHERE tstgrp_test_id='.$test_id.' ORDER BY tstgrp_group_id';
2184:     if ($r = F_db_query($sql, $db)) {
2185:         while ($m = F_db_fetch_assoc($r)) {
2186:             $ids .= ','.$m['tstgrp_group_id'];
2187:         }
2188:     } else {
2189:         F_display_db_error();
2190:     }
2191:     return $ids;
2192: }
2193: 
2194: /**
2195:  * Get a comma separated list of valid SSL certificates IDs for the selected test.
2196:  * @param $test_id (int) ID of the selected test
2197:  * @return string containing a comma separated list SSL certificates IDs.
2198:  */
2199: function F_getTestSSLCerts($test_id)
2200: {
2201:     require_once('../config/tce_config.php');
2202:     global $db, $l;
2203:     $test_id = intval($test_id);
2204:     $ids = '0';
2205:     // select SSL certificates in this test
2206:     $sql = 'SELECT tstssl_ssl_id FROM '.K_TABLE_TEST_SSLCERTS.' WHERE tstssl_test_id='.$test_id.' ORDER BY tstssl_ssl_id';
2207:     if ($r = F_db_query($sql, $db)) {
2208:         while ($m = F_db_fetch_assoc($r)) {
2209:             $ids .= ','.$m['tstssl_ssl_id'];
2210:         }
2211:     } else {
2212:         F_display_db_error();
2213:     }
2214:     return $ids;
2215: }
2216: 
2217: //============================================================+
2218: // END OF FILE
2219: //============================================================+
2220: 
 

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