2 /************************************************************************/
4 /************************************************************************/
5 /* Copyright (c) 2002 - 2009 */
6 /* Inclusive Design Institute */
8 /* This program is free software. You can redistribute it and/or */
9 /* modify it under the terms of the GNU General Public License */
10 /* as published by the Free Software Foundation. */
11 /************************************************************************/
14 if (!defined('AT_INCLUDE_PATH')) { exit; }
16 define('AT_DEVEL', 1);
17 define('AT_ERROR_REPORTING', E_ALL ^ E_NOTICE); // default is E_ALL ^ E_NOTICE, use E_ALL or E_ALL + E_STRICT for developing
18 define('AT_DEVEL_TRANSLATE', 0);
20 // Emulate register_globals off. src: http://php.net/manual/en/faq.misc.php#faq.misc.registerglobals
21 function unregister_GLOBALS() {
22 if (!ini_get('register_globals')) { return; }
24 // Might want to change this perhaps to a nicer error
25 if (isset($_REQUEST['GLOBALS'])) { die('GLOBALS overwrite attempt detected'); }
27 // Variables that shouldn't be unset
28 $noUnset = array('GLOBALS','_GET','_POST','_COOKIE','_REQUEST','_SERVER','_ENV', '_FILES');
29 $input = array_merge($_GET,$_POST,$_COOKIE,$_SERVER,$_ENV,$_FILES,isset($_SESSION) && is_array($_SESSION) ? $_SESSION : array());
31 foreach ($input as $k => $v) {
32 if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) { unset($GLOBALS[$k]); }
36 //functions for properly escaping input strings
37 function my_add_null_slashes( $string ) {
38 return mysql_real_escape_string(stripslashes($string));
40 function my_null_slashes($string) {
44 if ( get_magic_quotes_gpc() == 1 ) {
45 $addslashes = 'my_add_null_slashes';
46 $stripslashes = 'stripslashes';
48 $addslashes = 'mysql_real_escape_string';
49 $stripslashes = 'my_null_slashes';
52 function regenerate_session($reload = false)
54 if(!isset($_SESSION['IPaddress']) || $reload)
55 $_SESSION['IPaddress'] = $_SERVER['REMOTE_ADDR'];
57 if(!isset($_SESSION['userAgent']) || $reload)
58 $_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
60 $session_values = $_SESSION;
62 // Set current session to expire in 10 seconds
63 $_SESSION['OBSOLETE'] = true;
64 $_SESSION['EXPIRES'] = time() + 10;
66 // Create new session without destroying the old one
67 session_regenerate_id(false);
69 // Grab current session ID and close both sessions to allow other scripts to use them
70 $newSession = session_id();
71 session_write_close();
73 // Set session ID to the new one, and start it back up again
74 session_id($newSession);
77 $_SESSION = $session_values;
80 function check_session()
82 if($_SESSION['OBSOLETE'] && ($_SESSION['EXPIRES'] < time())) {
86 if($_SESSION['IPaddress'] != $_SERVER['REMOTE_ADDR']) {
90 if($_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT']) {
94 if(!$_SESSION['OBSOLETE']) {
101 * structure of this document (in order):
103 * 0. load config.inc.php
105 * 2. initialize db connection and populate $_config
106 * 3. initialize session
107 * 4. enable output compression
108 * 5. validate login user
110 * 7. load cache/ContentManagement/output/Savant/Message libraries
113 /**** 0. start system configuration options block ****/
114 //set the timezone, php 5.3+ problem. http://atutor.ca/atutor/mantis/view.php?id=4409
115 date_default_timezone_set('UTC');
118 if (!defined('AT_REDIRECT_LOADED')){
119 include_once(AT_INCLUDE_PATH.'config.inc.php');
121 error_reporting(AT_ERROR_REPORTING);
123 if (!defined('AT_INSTALL') || !AT_INSTALL) {
124 header('Cache-Control: no-store, no-cache, must-revalidate');
125 header('Pragma: no-cache');
127 $relative_path = substr(AT_INCLUDE_PATH, 0, -strlen('include/'));
128 header('Location: ' . $relative_path . 'install/not_installed.php');
131 /*** end system config block ***/
133 /*** 1. constants ***/
134 if (!defined('AT_REDIRECT_LOADED')){
135 require_once(AT_INCLUDE_PATH.'lib/constants.inc.php');
138 /*** 2. initialize db connection and populate $_config ***/
140 if (!defined('AT_REDIRECT_LOADED')){
141 require_once(AT_INCLUDE_PATH.'lib/mysql_connect.inc.php');
144 /* get config variables. if they're not in the db then it uses the installation default value in constants.inc.php */
145 $sql = "SELECT * FROM ".TABLE_PREFIX."config";
146 $result = mysql_query($sql, $db);
147 while ($row = mysql_fetch_assoc($result)) {
148 $_config[$row['name']] = $row['value'];
151 /***** 3. start session initilization block *****/
152 if (headers_sent()) {
153 require_once(AT_INCLUDE_PATH . 'classes/ErrorHandler/ErrorHandler.class.php');
154 $err = new ErrorHandler();
155 trigger_error('VITAL#<br /><br /><code><strong>An error occurred. Output sent before it should have. Please correct the above error(s).' . '</strong></code><br /><hr /><br />', E_USER_ERROR);
159 @ini_set('session.gc_maxlifetime', '36000'); /* 10 hours */
160 @session_cache_limiter('private, must-revalidate');
161 session_name('ATutorID');
162 error_reporting(AT_ERROR_REPORTING);
164 if (headers_sent()) {
165 require_once(AT_INCLUDE_PATH . 'classes/ErrorHandler/ErrorHandler.class.php');
166 $err = new ErrorHandler();
167 trigger_error('VITAL#<br /><code><strong>Headers already sent. ' .
168 'Cannot initialise session.</strong></code><br /><hr /><br />', E_USER_ERROR);
172 $isHttps = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
176 session_set_cookie_params(0, $_config["session_path"], "", $isHttps);
179 // Regenerate session id at every page refresh to prevent CSRF
180 $valid_session = true;
181 if (count($_SESSION) == 0) {
182 regenerate_session();
184 $valid_session = check_session();
187 $str = ob_get_contents();
189 unregister_GLOBALS();
191 // Re-direct to login page at a potential session hijack
192 if (!$valid_session) {
194 header('Location: '.AT_BASE_HREF.'login.php');
199 require_once(AT_INCLUDE_PATH . 'classes/ErrorHandler/ErrorHandler.class.php');
200 $err = new ErrorHandler();
201 trigger_error('VITAL#<br /><code><strong>Error initializing session. ' .
202 'Please varify that session.save_path is correctly set in your php.ini file ' .
203 'and the directory exists.</strong></code><br /><hr /><br />', E_USER_ERROR);
206 /***** end session initilization block ****/
208 /**** 4. enable output compression, if it isn't already enabled: ****/
209 if ((@ini_get('output_handler') == '') && (@ini_get('zlib.output_handler') == '')) {
210 @ini_set('zlib.output_compression', 1);
213 /**** 5. validate login user ****/
214 if (!isset($_SESSION['course_id']) && !isset($_SESSION['valid_user']) && (!isset($_user_location) || $_user_location != 'public') && !isset($_pretty_url_course_id)) {
215 if (isset($in_get) && $in_get && (($pos = strpos($_SERVER['PHP_SELF'], 'get.php/')) !== FALSE)) {
216 $redirect = substr($_SERVER['PHP_SELF'], 0, $pos) . 'login.php';
217 header('Location: '.$redirect);
221 header('Location: '.AT_BASE_HREF.'login.php');
225 /* following is added as a transition period and backwards compatability: */
226 define('EMAIL', $_config['contact_email']);
227 define('EMAIL_NOTIFY', $_config['email_notification']);
228 define('ALLOW_INSTRUCTOR_REQUESTS', $_config['allow_instructor_requests']);
229 define('AUTO_APPROVE_INSTRUCTORS', $_config['auto_approve_instructors']);
230 define('SITE_NAME', $_config['site_name']);
231 define('HOME_URL', $_config['home_url']);
232 define('DEFAULT_LANGUAGE', $_config['default_language']);
233 define('CACHE_DIR', $_config['cache_dir']);
234 define('AT_ENABLE_CATEGORY_THEMES', $_config['theme_categories']);
235 define('AT_COURSE_BACKUPS', $_config['course_backups']);
236 define('AT_EMAIL_CONFIRMATION', $_config['email_confirmation']);
237 define('AT_MASTER_LIST', $_config['master_list']);
238 $MaxFileSize = $_config['max_file_size'];
239 $MaxCourseSize = $_config['max_course_size'];
240 $MaxCourseFloat = $_config['max_course_float'];
241 $IllegalExtentions = explode('|',$_config['illegal_extentions']);
242 define('AT_DEFAULT_PREFS', isset($_config['prefs_default']) ? $_config['prefs_default'] : '');
243 $_config['home_defaults'] .= (isset($_config['home_defaults_2']) ? $_config['home_defaults_2'] : '');
244 $_config['main_defaults'] .= (isset($_config['main_defaults_2']) ? $_config['main_defaults_2'] : '');
246 if ($_config['time_zone']) {
247 //$sql = "SET time_zone='{$_config['time_zone']}'";
248 //mysql_query($sql, $db);
250 if (function_exists('date_default_timezone_set')) {
251 foreach($utc_timezones as $zone){
253 if($zone[1] == $_config['time_zone']){
254 $zone_name = $zone[2];
258 date_default_timezone_set($zone_name);
260 @putenv("TZ={$_config['time_zone']}");
263 /***** 6. load language *****/
264 // set current language
265 require(AT_INCLUDE_PATH . '../mods/_core/languages/classes/LanguageManager.class.php');
266 $languageManager = new LanguageManager();
268 $myLang =& $languageManager->getMyLanguage();
270 if ($myLang === FALSE) {
271 echo 'There are no languages installed!';
274 $myLang->saveToSession();
275 if (isset($_GET['lang']) && $_SESSION['valid_user']) {
276 if ($_SESSION['course_id'] == -1) {
277 $myLang->saveToPreferences($_SESSION['login'], 1); //1 for admin
279 $myLang->saveToPreferences($_SESSION['member_id'], 0); //0 for non-admin
282 $myLang->sendContentTypeHeader();
284 /* set right-to-left language */
286 if ($myLang->isRTL()) {
287 $rtl = 'rtl_'; /* basically the prefix to a rtl variant directory/filename. eg. rtl_tree */
289 /***** end language block ****/
291 /* 7. load common libraries */
292 require(AT_INCLUDE_PATH.'classes/ContentManager.class.php'); /* content management class */
293 require_once(AT_INCLUDE_PATH.'lib/output.inc.php'); /* output functions */
294 if (!(defined('AT_REDIRECT_LOADED'))){
295 require_once(AT_INCLUDE_PATH . 'classes/UrlRewrite/UrlParser.class.php'); /* pretty url tool */
297 require(AT_INCLUDE_PATH.'classes/Savant2/Savant2.php'); /* for the theme and template management */
299 // set default template paths:
300 $savant = new Savant2();
301 $savant->addPath('template', AT_INCLUDE_PATH . '../themes/default/');
303 //if user has requested theme change, make the change here
304 if (($_POST['theme'] || $_POST['mobile_theme']) && $_POST['submit']) {
305 //http://atutor.ca/atutor/mantis/view.php?id=4781
306 //Themes should be in the same folder, disallow '../'
307 $newTheme = str_replace("../", "", $_POST['theme']);
308 $newMobileTheme = str_replace("../", "", $_POST['mobile_theme']);
309 if ($newTheme != $_POST['theme'] || $newMobileTheme != $_POST['mobile_theme']) {
310 header('Location:'.AT_BASE_HREF.'users/preferences.php');
314 $_SESSION['prefs']['PREF_THEME'] = $addslashes($_POST['theme']);
315 $_SESSION['prefs']['PREF_MOBILE_THEME'] = $addslashes($_POST['mobile_theme']);
316 } else if ($_POST['set_default']) {
317 $_SESSION['prefs']['PREF_THEME'] = 'default';
318 $_SESSION['prefs']['PREF_MOBILE_THEME'] = 'mobile';
321 // Reset PREF_THEME when:
322 // 1. If PREF_THEME is not set
323 // 2. The request is from the mobile device but PREF_THEME is not a mobile theme
324 if (!isset($_SESSION['prefs']['PREF_THEME']) ||
325 $_SESSION['prefs']['PREF_THEME'] == "" ||
326 (is_mobile_device() && !is_mobile_theme($_SESSION['prefs']['PREF_THEME']))) {
328 $default_theme = get_default_theme();
330 $_SESSION['prefs']['PREF_THEME'] = $default_theme['dir_name'];
333 if (!is_dir(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME']) || $_SESSION['prefs']['PREF_THEME'] == '') {
334 $_SESSION['prefs']['PREF_THEME'] = get_system_default_theme();
337 // use "mobile" theme for mobile devices. For now, there's only one mobile theme and it's hardcoded.
338 // When more mobile themes come in, this should be changed.
339 if (isset($_SESSION['prefs']['PREF_THEME']) && file_exists(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME']) && isset($_SESSION['valid_user']) && $_SESSION['valid_user']) {
340 if ($_SESSION['course_id'] == -1) {
341 if ($_SESSION['prefs']['PREF_THEME'] == '' || !is_dir(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'])) {
342 $_SESSION['prefs']['PREF_THEME'] = get_system_default_theme();
346 $sql = "SELECT status FROM ".TABLE_PREFIX."themes WHERE dir_name = '".$_SESSION['prefs']['PREF_THEME']."'";
347 $result = mysql_query($sql, $db);
348 $row = mysql_fetch_assoc($result);
349 if ($row['status'] > 0) {
352 $default_theme = get_default_theme();
353 if (!is_dir(AT_INCLUDE_PATH . '../themes/' . $default_theme['dir_name'])) {
354 $default_theme = array('dir_name' => get_system_default_theme());
356 $_SESSION['prefs']['PREF_THEME'] = $default_theme['dir_name'];
361 $savant->addPath('template', AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'] . '/');
362 require(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'] . '/theme.cfg.php');
364 require(AT_INCLUDE_PATH.'classes/Message/Message.class.php');
365 $msg = new Message($savant);
367 $contentManager = new ContentManager($db, isset($_SESSION['course_id']) ? $_SESSION['course_id'] : $_GET['p_course']);
368 $contentManager->initContent();
370 /**************************************************/
371 require(AT_INCLUDE_PATH.'phpCache/phpCache.inc.php'); // cache library
372 require(AT_INCLUDE_PATH.'lib/utf8.php'); //UTF-8 multibyte library
374 if (!file_exists(AT_INCLUDE_PATH.'../sha-1factory.js')) {
375 require(AT_INCLUDE_PATH.'header.inc.php');
376 $msg->printErrors('MISSING_SHA1');
377 require(AT_INCLUDE_PATH.'footer.inc.php');
381 if (isset($_user_location) && ($_user_location == 'users') && $_SESSION['valid_user'] && ($_SESSION['course_id'] > 0)) {
382 $_SESSION['course_id'] = 0;
385 if ((!isset($_SESSION['course_id']) || $_SESSION['course_id'] == 0) && ($_user_location != 'users') && ($_user_location != 'prog') && !isset($_GET['h']) && ($_user_location != 'public') && (!isset($_pretty_url_course_id) || $_pretty_url_course_id == 0)) {
386 header('Location:'.AT_BASE_HREF.'users/index.php');
389 /* check if we are in the requested course, if not, bounce to it.
390 * @author harris, for pretty url, read AT_PRETTY_URL_HANDLER
392 if ((isset($_SESSION['course_id']) && isset($_pretty_url_course_id) && $_SESSION['course_id'] != $_pretty_url_course_id) ||
393 (isset($_pretty_url_course_id) && !isset($_SESSION['course_id']) && !isset($_REQUEST['ib']))) {
395 if($_config['pretty_url'] == 0){
396 header('Location: '.AT_BASE_HREF.'bounce.php?course='.$_pretty_url_course_id.SEP.'pu='.$_SERVER['PATH_INFO'].urlencode('?'.$_SERVER['QUERY_STRING']));
398 header('Location: '.AT_BASE_HREF.'bounce.php?course='.$_pretty_url_course_id.SEP.'pu='.$_SERVER['PATH_INFO']);
404 * This function is used for printing variables into log file for debugging.
406 * @param mixed $var The variable to output
407 * @param string $log The location of the log file. If not provided, use the default one.
408 * @author Cindy Qi Li
410 function debug_to_log($var, $log='') {
411 if (!defined('AT_DEVEL') || !AT_DEVEL) {
415 if ($log == '') $log = AT_CONTENT_DIR. 'atutor.log';
416 $handle = fopen($log, 'a');
417 fwrite($handle, "\n\n");
418 fwrite($handle, date("F j, Y, g:i a"));
419 fwrite($handle, "\n");
420 fwrite($handle, var_export($var,1));
426 * This function is used for printing variables for debugging.
428 * @param mixed $var The variable to output
429 * @param string $title The name of the variable, or some mark-up identifier.
430 * @author Joel Kronenberg
432 function debug($var, $title='') {
433 if (!defined('AT_DEVEL') || !AT_DEVEL) {
437 echo '<pre style="border: 1px black solid; padding: 0px; margin: 10px;" title="debugging box">';
439 echo '<h4>'.$title.'</h4>';
444 $str = ob_get_contents();
447 $str = str_replace('<', '<', $str);
449 $str = str_replace('[', '<span style="color: red; font-weight: bold;">[', $str);
450 $str = str_replace(']', ']</span>', $str);
451 $str = str_replace('=>', '<span style="color: blue; font-weight: bold;">=></span>', $str);
452 $str = str_replace('Array', '<span style="color: purple; font-weight: bold;">Array</span>', $str);
457 /********************************************************************/
458 /* the system course information */
459 /* system_courses[course_id] = array(title, description, subject) */
460 $system_courses = array();
462 // temporary set to a low number
463 $sql = 'SELECT * FROM '.TABLE_PREFIX.'courses ORDER BY title';
464 $result = mysql_query($sql, $db);
465 while ($row = mysql_fetch_assoc($result)) {
466 $course = $row['course_id'];
467 unset($row['course_id']);
468 $system_courses[$course] = $row;
471 /********************************************************************/
472 // p_course is set when pretty url is on and guests access a public course. @see bounce.php
473 // First, santinize p_course
474 if (isset($_REQUEST['p_course'])) {
475 $_REQUEST['p_course'] = intval($_REQUEST['p_course']);
478 if (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0 || $_REQUEST['p_course'] > 0) {
479 $sql = 'SELECT * FROM '.TABLE_PREFIX.'glossary
480 WHERE course_id='.($_SESSION['course_id']>0 ? $_SESSION['course_id'] : $_REQUEST['p_course']).'
482 $result = mysql_query($sql, $db);
484 $glossary_ids = array();
485 while ($row_g = mysql_fetch_assoc($result)) {
486 $row_g['word'] = htmlspecialchars($row_g['word'], ENT_QUOTES, 'UTF-8');
487 $glossary[$row_g['word']] = str_replace("'", "\'",$row_g['definition']);
488 $glossary_ids[$row_g['word_id']] = $row_g['word'];
490 /* a kludge to get the related id's for when editing content */
491 /* it's ugly, but beats putting this query AGAIN on the edit_content.php page */
492 if (isset($get_related_glossary)) {
493 $glossary_ids_related[$row_g['word']] = $row_g['related_word_id'];
498 function get_html_body($text) {
499 /* strip everything before <body> */
500 $start_pos = strpos(strtolower($text), '<body');
501 if ($start_pos !== false) {
502 $start_pos += strlen('<body');
503 $end_pos = strpos(strtolower($text), '>', $start_pos);
504 $end_pos += strlen('>');
506 $text = substr($text, $end_pos);
509 /* strip everything after </body> */
510 $end_pos = strpos(strtolower($text), '</body>');
511 if ($end_pos !== false) {
512 $text = trim(substr($text, 0, $end_pos));
518 function get_html_head ($text) {
519 /* make all text lower case */
520 // $text = strtolower($text);
522 /* strip everything before <head> */
523 $start_pos = stripos($text, '<head');
524 if ($start_pos !== false) {
525 $start_pos += strlen('<head');
526 $end_pos = stripos($text, '>', $start_pos);
527 $end_pos += strlen('>');
529 $text = substr($text, $end_pos);
532 /* strip everything after </head> */
533 $end_pos = stripos($text, '</head');
534 if ($end_pos !== false) {
535 $text = trim(substr($text, 0, $end_pos));
541 * This function cuts out requested tag information from html head
543 * @param $text html text
544 * @param $tags a string or an array of requested tags
545 * @author Cindy Qi Li
547 function get_html_head_by_tag($text, $tags)
549 $head = get_html_head($text);
552 if (!is_array($tags) && strlen(trim($tags)) > 0)
554 $tags = array(trim($tags));
556 foreach ($tags as $tag)
558 $tag = strtolower($tag);
560 /* strip everything before <{tag}> */
561 $start_pos = stripos($head, '<'.$tag);
564 while ($start_pos !== false)
566 $temp_text = substr($temp_head, $start_pos);
568 /* strip everything after </{tag}> or />*/
569 $end_pos = stripos($temp_text, '</' . $tag . '>');
571 if ($end_pos !== false)
573 $end_pos += strlen('</' . $tag . '>');
575 // add an empty line after each tag information
576 $rtn_text .= trim(substr($temp_text, 0, $end_pos)) . '
580 else // match /> as ending tag if </tag> is not found
582 $end_pos = stripos($temp_text, '/>');
584 if($end_pos === false && stripos($temp_text, $tag.'>')===false){
585 //if /> is not found, then this is not a valid XHTML
586 //text iff it's not tag>
587 $end_pos = stripos($temp_text, '>');
588 $end_pos += strlen('>');
590 $end_pos += strlen('/>');
592 // add an empty line after each tag information
593 $rtn_text .= trim(substr($temp_text, 0, $end_pos)) . '
598 // initialize vars for next round of matching
599 $temp_head = substr($temp_text, $end_pos);
600 $start_pos = stripos($temp_head, '<'.$tag);
606 if (version_compare(phpversion(), '4.3.0') < 0) {
607 function file_get_contents($filename) {
608 $fd = @fopen($filename, 'rb');
612 $content = @fread($fd, filesize($filename));
619 function mysql_real_escape_string($input) {
620 return mysql_escape_string($input);
625 function add_user_online() {
626 if (!isset($_SESSION['member_id']) || !($_SESSION['member_id'] > 0)) {
629 global $db, $addslashes;
631 $expiry = time() + 900; // 15min
632 $sql = 'REPLACE INTO '.TABLE_PREFIX.'users_online VALUES ('.$_SESSION['member_id'].', '.$_SESSION['course_id'].', "'.$addslashes(get_display_name($_SESSION['member_id'])).'", '.$expiry.')';
633 $result = mysql_query($sql, $db);
635 /* garbage collect and optimize the table every so often */
636 mt_srand((double) microtime() * 1000000);
637 $rand = mt_rand(1, 20);
639 $sql = 'DELETE FROM '.TABLE_PREFIX.'users_online WHERE expiry<'.time();
640 $result = @mysql_query($sql, $db);
645 * Returns the login name of a member.
647 * @param int $id The ID of the member.
648 * @return Returns the login name of the member whose ID is $id.
649 * @author Joel Kronenberg
651 function get_login($id){
652 global $db, $_config_defaults;
655 $id = implode(',',$id);
656 $sql = 'SELECT login, member_id FROM '.TABLE_PREFIX.'members WHERE member_id IN ('.$id.') ORDER BY login';
659 $result = mysql_query($sql, $db);
660 while( $row = mysql_fetch_assoc($result)) {
661 $rows[$row['member_id']] = $row['login'];
666 $sql = 'SELECT login FROM '.TABLE_PREFIX.'members WHERE member_id='.$id;
668 $result = mysql_query($sql, $db);
669 $row = mysql_fetch_assoc($result);
671 return $row['login'];
676 function get_display_name($id) {
677 static $db, $_config, $display_name_formats;
679 return $_SESSION['login'];
682 if (!isset($db, $_config)) {
683 global $db, $_config, $display_name_formats;
686 if (substr($id, 0, 2) == 'g_' || substr($id, 0, 2) == 'G_')
688 $sql = "SELECT name FROM ".TABLE_PREFIX."guests WHERE guest_id='".$id."'";
689 $result = mysql_query($sql, $db);
690 $row = mysql_fetch_assoc($result);
692 return _AT($display_name_formats[$_config['display_name_format']], '', $row['name'], '', '');
696 $sql = 'SELECT login, first_name, second_name, last_name FROM '.TABLE_PREFIX.'members WHERE member_id='.$id;
697 $result = mysql_query($sql, $db);
698 $row = mysql_fetch_assoc($result);
700 return _AT($display_name_formats[$_config['display_name_format']], $row['login'], $row['first_name'], $row['second_name'], $row['last_name']);
704 function get_forum_name($fid){
709 $sql = 'SELECT title FROM '.TABLE_PREFIX.'forums WHERE forum_id='.$fid;
710 $result = mysql_query($sql, $db);
711 if (($row = mysql_fetch_assoc($result)) && $row['title']) {
712 return $row['title'];
715 $sql = "SELECT group_id FROM ".TABLE_PREFIX."forums_groups WHERE forum_id=$fid";
716 $result = mysql_query($sql, $db);
717 if ($row = mysql_fetch_assoc($result)) {
718 return get_group_title($row['group_id']);
724 // takes the array of valid prefs and assigns them to the current session
725 // @params: prefs - an array of preferences
726 // @params: optional. Values are 0 or 1. Default value is 0
727 // when 1, assign PREF_MOBILE_THEME to PREF_THEME if the request is from a mobile device
728 // this value is to set when the prefs values are set for display
729 // if this function is used as a front shot for save_prefs(), the value should be 0
730 function assign_session_prefs($prefs, $switch_mobile_theme = 0) {
731 if (is_array($prefs)) {
732 foreach($prefs as $pref_name => $value) {
733 $_SESSION['prefs'][$pref_name] = $value;
736 if (is_mobile_device() && $switch_mobile_theme) {
737 $_SESSION['prefs']['PREF_THEME'] = $_SESSION['prefs']['PREF_MOBILE_THEME'];
741 function save_prefs( ) {
742 global $db, $addslashes;
744 if ($_SESSION['valid_user']) {
745 $data = $addslashes(serialize($_SESSION['prefs']));
746 $sql = 'UPDATE '.TABLE_PREFIX.'members SET preferences="'.$data.'", creation_date=creation_date, last_login=last_login WHERE member_id='.$_SESSION['member_id'];
747 $result = mysql_query($sql, $db);
751 function save_email_notification($mnot) {
754 if ($_SESSION['valid_user']) {
755 $sql = "UPDATE ".TABLE_PREFIX."members SET inbox_notify =". $mnot .", creation_date=creation_date, last_login=last_login WHERE member_id =".$_SESSION['member_id'];
756 $result = mysql_query($sql, $db);
761 * Saves the last viewed content page in a user's course so that on next visit, user can start reading where they left off
763 * @param int $cid the content page id
765 * @see $db in include/vitals.inc.php
766 * @author Joel Kronenberg
768 function save_last_cid($cid) {
769 if ($_SESSION['enroll'] == AT_ENROLL_NO) {
774 $_SESSION['s_cid'] = intval($_GET['cid']);
776 if (!$_SESSION['is_admin'] &&
777 !$_SESSION['privileges'] &&
779 !$_SESSION['cid_time'] &&
780 ($_SESSION['course_id'] > 0) )
782 $_SESSION['cid_time'] = time();
785 $sql = "UPDATE ".TABLE_PREFIX."course_enrollment SET last_cid=$cid WHERE course_id=$_SESSION[course_id] AND member_id=$_SESSION[member_id]";
786 mysql_query($sql, $db);
789 // there has to be a better way of expressing this if-statement!
790 // and, does it really have to be here?
791 if ((!isset($_SESSION['is_admin']) || !$_SESSION['is_admin']) &&
792 (!isset($_SESSION['privileges']) || !$_SESSION['privileges']) &&
794 isset($_SESSION['s_cid']) && $_SESSION['s_cid'] &&
795 isset($_SESSION['cid_time']) && $_SESSION['cid_time'] &&
796 ($_SESSION['course_id'] > 0) &&
797 ($_SESSION['s_cid'] != $_GET['cid']) &&
798 ($_SESSION['enroll'] != AT_ENROLL_NO) )
800 $diff = time() - $_SESSION['cid_time'];
802 $sql = "UPDATE ".TABLE_PREFIX."member_track SET counter=counter+1, duration=duration+$diff, last_accessed=NOW() WHERE member_id=$_SESSION[member_id] AND content_id=$_SESSION[s_cid]";
804 $result = mysql_query($sql, $db);
806 if (mysql_affected_rows($db) == 0) {
807 $sql = "INSERT INTO ".TABLE_PREFIX."member_track VALUES ($_SESSION[member_id], $_SESSION[course_id], $_SESSION[s_cid], 1, $diff, NOW())";
808 $result = mysql_query($sql, $db);
812 $_SESSION['cid_time'] = 0;
817 * Checks if the $_SESSION[member_id] is an instructor (true) or not (false)
818 * The result is only fetched once - it is then available via a static variable, $is_instructor
821 * @return bool true if is instructor, false otherwise.
822 * @see $db in include/vitals.inc.php
823 * @author Joel Kronenberg
825 function get_instructor_status() {
826 static $is_instructor;
828 if (isset($is_instructor)) {
829 return $is_instructor;
834 $is_instructor = false;
836 $sql = 'SELECT status FROM '.TABLE_PREFIX.'members WHERE member_id='.$_SESSION['member_id'];
837 $result = mysql_query($sql, $db);
838 if (!($row = @mysql_fetch_assoc($result))) {
839 $is_instructor = FALSE;
843 if ($row['status'] == AT_STATUS_INSTRUCTOR) {
844 $is_instructor = TRUE;
848 $is_instructor = FALSE;
852 /****************************************************/
853 /* update the user online list */
854 if (isset($_SESSION['valid_user']) && $_SESSION['valid_user']) {
855 $new_minute = time()/60;
856 if (!isset($_SESSION['last_updated'])) {
857 $_SESSION['last_updated'] = $new_minute;
859 $diff = abs($_SESSION['last_updated'] - $new_minute);
860 if ($diff > ONLINE_UPDATE) {
861 $_SESSION['last_updated'] = $new_minute;
866 /****************************************************/
867 /* compute the $_my_uri variable */
868 $bits = explode(SEP, getenv('QUERY_STRING'));
869 $num_bits = count($bits);
872 for ($i=0; $i<$num_bits; $i++) {
873 if ( (strpos($bits[$i], 'enable=') === 0)
874 || (strpos($bits[$i], 'disable=') === 0)
875 || (strpos($bits[$i], 'expand=') === 0)
876 || (strpos($bits[$i], 'collapse=') === 0)
877 || (strpos($bits[$i], 'lang=') === 0)
879 /* we don't want this variable added to $_my_uri */
883 if (($_my_uri == '') && ($bits[$i] != '')) {
884 $_my_uri .= htmlentities('?');
885 } else if ($bits[$i] != ''){
886 $_my_uri .= htmlentities(SEP);
888 $_my_uri .= $bits[$i];
890 if ($_my_uri == '') {
891 $_my_uri .= htmlentities('?');
893 $_my_uri .= htmlentities(SEP);
895 $_my_uri = $_SERVER['PHP_SELF'].$_my_uri;
898 * If MBString extension is loaded, 4.3.0+, then use it.
899 * Otherwise we will have to use include/utf8 library
904 if (extension_loaded('mbstring')){
905 $strtolower = 'mb_strtolower';
906 $strtoupper = 'mb_strtoupper';
907 $substr = 'mb_substr';
908 $strpos = 'mb_strpos';
909 $strrpos = 'mb_strrpos';
910 $strlen = 'mb_strlen';
912 $strtolower = 'utf8_strtolower';
913 $strtoupper = 'utf8_strtoupper';
914 $substr = 'utf8_substr';
915 $strpos = 'utf8_strpos';
916 $strrpos = 'utf8_strrpos';
917 $strlen = 'utf8_strlen';
921 /*~~~~~~~~~~~~~~~~~flash detection~~~~~~~~~~~~~~~~*/
922 if(isset($_COOKIE["flash"])){
923 $_SESSION['flash'] = $_COOKIE["flash"];
926 ATutor.setcookie("flash",'',time()-3600);
929 if (!isset($_SESSION["flash"])) {
931 <script type="text/javascript">
934 //VB-Script for InternetExplorer
935 function iExploreCheck()
937 document.writeln("<scr" + "ipt language=\'VBscript\'>");
938 //document.writeln("\'Test to see if VBScripting works");
939 document.writeln("detectableWithVB = False");
940 document.writeln("If ScriptEngineMajorVersion >= 2 then");
941 document.writeln(" detectableWithVB = True");
942 document.writeln("End If");
943 //document.writeln("\'This will check for the plugin");
944 document.writeln("Function detectActiveXControl(activeXControlName)");
945 document.writeln(" on error resume next");
946 document.writeln(" detectActiveXControl = False");
947 document.writeln(" If detectableWithVB Then");
948 document.writeln(" detectActiveXControl = IsObject(CreateObject(activeXControlName))");
949 document.writeln(" End If");
950 document.writeln("End Function");
951 document.writeln("</scr" + "ipt>");
952 return detectActiveXControl("ShockwaveFlash.ShockwaveFlash.1");
956 var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : false;
957 if(!(plugin) && (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0 && (navigator.appVersion.indexOf("Win") != -1)))
959 flash_detect = "flash=yes";
961 flash_detect = "flash=no";
964 flash_detect = "flash=yes";
966 flash_detect = "flash=no";
968 writeCookie(flash_detect);
970 function writeCookie(value)
972 var today = new Date();
973 var the_date = new Date("December 31, 2099");
974 var the_cookie_date = the_date.toGMTString();
975 var the_cookie = value + ";expires=" + the_cookie_date;
976 document.cookie = the_cookie;
985 /*~~~~~~~~~~~~~~end flash detection~~~~~~~~~~~~~~~*/
990 * Checks if the data exceeded the database predefined length, if so,
992 * This is used on data that are being inserted into the database.
993 * If this function is used for display purposes, you may want to add the '...'
994 * at the end of the string by setting the $forDisplay=1
995 * @param the mbstring that needed to be checked
996 * @param the byte length of what the input should be in the database.
998 * append '...' at the end of the string. Should not use this when
999 * dealing with database. This should only be set for display purposes.
1000 * @return the mbstring safe sql entry
1001 * @author Harris Wong
1003 function validate_length($input, $len, $forDisplay=0){
1004 global $strlen, $substr;
1005 $input_bytes_len = strlen($input);
1006 $input_len = $strlen($input);
1008 //If the input has exceeded the db column limit
1009 if ($input_bytes_len > $len){
1010 //calculate where to chop off the string
1011 $percentage = $input_bytes_len / $input_len;
1012 //Get the suitable length that should be stored in the db
1013 $suitable_len = floor($len / $percentage);
1015 if ($forDisplay===1){
1016 return $substr($input, 0, $suitable_len).'...';
1018 return $substr($input, 0, $suitable_len);
1024 * Instead of blindly cutting off the input from the given param
1026 global $strlen, $substr;
1027 if ($strlen($input) > $len) {
1028 if ($forDisplay===1){
1029 return $substr($input, 0, $len).'...';
1031 return $substr($input, 0, $len);
1038 * If pretty URL within admin config is switched on. We will apply pretty URL
1039 * to all the links in ATutor. This function will authenticate itself towards the current pages.
1040 * In our definition, admins, login, registration pages shouldn't have pretty url applied. However,
1041 * if one want to use url_rewrite on these pages, please force it by using the third parameter.
1042 * Note: If system config has turned off this feature, $force will have no effect.
1043 * @param string the Url should be a relative link, have to improve this later on, to check if
1044 * it's a relative link, if not, truncate it.
1045 * @param boolean Available values are AT_PRETTY_URL_IS_HEADER, AT_PRETTY_URL_NOT_HEADER(default)
1046 * use AT_PRETTY_URL_IS_HEADER if url_rewrite is used in php header('Location:..'), absolute path is needed for this.
1047 * @param boolean true to force the url_rewrite, false otheriwse. False is the default.
1048 * @author Harris Wong
1050 function url_rewrite($url, $is_rewriting_header=AT_PRETTY_URL_NOT_HEADER, $force=false){
1051 global $_config, $db;
1052 $url_parser = new UrlParser();
1053 $pathinfo = $url_parser->getPathArray();
1055 /* If this is any kind of admins, don't prettify the url
1056 * $_SESSION['is_guest'] is used to check against login/register/browse page, the links on this page will
1057 * only be prettified when a user has logged in.
1058 * Had used $_SESSION[valid_user] before but it created this problem:
1059 * http://www.atutor.ca/atutor/mantis/view.php?id=3426
1061 if ($force || (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0)) {
1062 //if course id is defined, apply pretty url.
1064 //if this is something that is displayed on the login page, don't modify the urls.
1065 else if ( (admin_authenticate(AT_ADMIN_PRIV_ADMIN, AT_PRIV_RETURN)
1066 || (isset($_SESSION['privileges']) && admin_authenticate($_SESSION['privileges'], AT_PRIV_RETURN)))
1067 || (isset($_SESSION['is_guest']) && $_SESSION['is_guest']==1)){
1071 //if we allow pretty url in the system
1072 if ($_config['pretty_url'] > 0){
1074 //If we allow course dir name from sys perf
1075 if ($_config['course_dir_name'] > 0){
1076 if (preg_match('/bounce.php\?course=([\d]+)$/', $url, $matches) == 1){
1077 // bounce has the highest priority, even if session is set, work on
1079 $course_id = $url_parser->getCourseDirName($matches[1]);
1080 } elseif (isset($_REQUEST['course'])){
1082 $course_id = $url_parser->getCourseDirName($_REQUEST['course']);
1083 } elseif (isset($_REQUEST['p_course'])){
1084 // is set when guests access public course. @see bounce.php
1085 $course_id = $url_parser->getCourseDirName($_REQUEST['p_course']);
1086 } elseif (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0){
1087 $course_id = $url_parser->getCourseDirName($_SESSION['course_id']);
1090 $course_id = $_SESSION['course_id'];
1092 $url = $pathinfo[1]->convertToPrettyUrl($course_id, $url);
1093 } elseif ($_config['course_dir_name'] > 0) {
1094 //enabled course directory name, disabled pretty url
1095 if (preg_match('/bounce.php\?course=([\d]+)$/', $url, $matches) == 1){
1096 // bounce has the highest priority, even if session is set, work on
1098 $course_id = $url_parser->getCourseDirName($matches[1]);
1099 } elseif (isset($_REQUEST['course'])){
1100 $course_id = $url_parser->getCourseDirName($_REQUEST['course']);
1101 } elseif (isset($_REQUEST['p_course'])){
1102 // is set when guests access public course. @see bounce.php
1103 $course_id = $url_parser->getCourseDirName($_REQUEST['p_course']);
1104 } elseif (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0){
1105 $course_id = $url_parser->getCourseDirName($_SESSION['course_id']);
1107 $url = $pathinfo[1]->convertToPrettyUrl($course_id, $url);
1110 //instead of putting AT_BASE_HREF in all the headers location, we will put it here.
1111 //Abs paths are required for pretty url because otherwise the url location will be appeneded.
1112 //ie. ATutor_161/blogs/CoURSe_rOAd/blogs/view.php/ot/1/oid/1/ instead of
1113 // ATutor_161/CoURSe_rOAd/blogs/view.php/ot/1/oid/1/
1114 if ($is_rewriting_header==true){
1115 return AT_BASE_HREF.$url;
1122 * Applies $addslashes or intval() recursively.
1124 * @param mixed $input The input to clean.
1125 * @return A safe version of $input
1126 * @author Joel Kronenberg
1128 function sql_quote($input) {
1131 if (is_array($input)) {
1132 foreach ($input as $key => $value) {
1133 if (is_array($input[$key])) {
1134 $input[$key] = sql_quote($input[$key]);
1135 } else if (!empty($input[$key]) && is_numeric($input[$key])) {
1136 $input[$key] = intval($input[$key]);
1138 $input[$key] = $addslashes(trim($input[$key]));
1142 if (!empty($input) && is_numeric($input)) {
1143 $input = intval($input);
1145 $input = $addslashes(trim($input));
1151 function query_bit( $bitfield, $bit ) {
1152 if (!is_int($bitfield)) {
1153 $bitfield = intval($bitfield);
1155 if (!is_int($bit)) {
1156 $bit = intval($bit);
1158 return ( $bitfield & $bit ) ? true : false;
1162 * Authenticates the current user against the specified privilege.
1164 * @param int $privilege privilege to check against.
1165 * @param bool $check whether or not to return the result or to abort/exit.
1166 * @return bool true if this user is authenticated, false otherwise.
1167 * @see query_bit() in include/vitals.inc.php
1168 * @author Joel Kronenberg
1170 function authenticate($privilege, $check = false) {
1171 if ($_SESSION['is_admin']) {
1175 $auth = query_bit($_SESSION['privileges'], $privilege);
1177 if (!$_SESSION['valid_user'] || !$auth) {
1180 $msg->addInfo('NO_PERMISSION');
1181 require(AT_INCLUDE_PATH.'header.inc.php');
1182 require(AT_INCLUDE_PATH.'footer.inc.php');
1191 function admin_authenticate($privilege = 0, $check = false) {
1192 if (!isset($_SESSION['valid_user']) || !$_SESSION['valid_user'] || ($_SESSION['course_id'] != -1)) {
1196 header('Location: '.AT_BASE_HREF.'login.php');
1200 if ($_SESSION['privileges'] == AT_ADMIN_PRIV_ADMIN) {
1205 $auth = query_bit($_SESSION['privileges'], $privilege);
1212 $msg->addError('ACCESS_DENIED');
1213 require(AT_INCLUDE_PATH.'header.inc.php');
1214 require(AT_INCLUDE_PATH.'footer.inc.php');
1221 function get_default_theme() {
1224 if (is_mobile_device()) {
1225 $default_status = 3;
1227 $default_status = 2;
1229 $sql = "SELECT dir_name FROM ".TABLE_PREFIX."themes WHERE status=".$default_status;
1230 $result = mysql_query($sql, $db);
1231 $row = mysql_fetch_assoc($result);
1236 function get_system_default_theme() {
1237 if (is_mobile_device()) {
1244 function is_mobile_theme($theme) {
1247 $sql = "SELECT dir_name FROM ".TABLE_PREFIX."themes WHERE type='".MOBILE_DEVICE."'";
1248 $result = mysql_query($sql, $db);
1249 while ($row = mysql_fetch_assoc($result)) {
1250 if ($row['dir_name'] == $theme && is_dir(AT_INCLUDE_PATH . '../themes/' . $theme)) return true;
1256 if (isset($_GET['expand'])) {
1257 $_SESSION['menu'][intval($_GET['expand'])] = 1;
1258 } else if (isset($_GET['collapse'])) {
1259 unset($_SESSION['menu'][intval($_GET['collapse'])]);
1263 * Writes present action to admin log db
1265 * @param string $operation_type The type of operation
1266 * @param string $table_name The table affected
1267 * @param string $num_affected The number of rows in the table affected
1268 * @author Shozub Qureshi
1270 function write_to_log($operation_type, $table_name, $num_affected, $details) {
1271 global $db, $addslashes;
1273 if ($num_affected > 0) {
1274 $details = $addslashes(stripslashes($details));
1275 $sql = "INSERT INTO ".TABLE_PREFIX."admin_log VALUES ('$_SESSION[login]', NULL, $operation_type, '$table_name', $num_affected, '$details')";
1276 $result = mysql_query($sql, $db);
1280 function get_group_title($group_id) {
1282 $sql = "SELECT title FROM ".TABLE_PREFIX."groups WHERE group_id=$group_id";
1283 $result = mysql_query($sql, $db);
1284 if ($row = mysql_fetch_assoc($result)) {
1285 return $row['title'];
1290 function get_status_name($status_id) {
1291 switch ($status_id) {
1292 case AT_STATUS_DISABLED:
1293 return _AT('disabled');
1295 case AT_STATUS_UNCONFIRMED:
1296 return _AT('unconfirmed');
1298 case AT_STATUS_STUDENT:
1299 return _AT('student');
1301 case AT_STATUS_INSTRUCTOR:
1302 return _AT('instructor');
1307 function profile_image_exists($id) {
1308 $extensions = array('gif', 'jpg', 'png');
1310 foreach ($extensions as $extension) {
1311 if (file_exists(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension)) {
1318 * print thumbnails or profile pic
1319 * @param int image id
1320 * @param int 1 for thumbnail, 2 for profile
1322 function print_profile_img($id, $type=1) {
1323 global $moduleFactory;
1324 $mod = $moduleFactory->getModule('_standard/profile_pictures');
1325 if ($mod->isEnabled() === FALSE) {
1328 if (profile_image_exists($id)) {
1330 echo '<img src="get_profile_img.php?id='.$id.'" class="profile-picture" alt="" />';
1332 echo '<img src="get_profile_img.php?id='.$id.SEP.'size=p" class="profile-picture" alt="" />';
1335 echo '<img src="images/clr.gif" height="100" width="100" class="profile-picture" alt="" />';
1339 function profile_image_delete($id) {
1340 $extensions = array('gif', 'jpg', 'png');
1342 foreach ($extensions as $extension) {
1343 if (file_exists(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension)) {
1344 unlink(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension);
1346 if (file_exists(AT_CONTENT_DIR.'profile_pictures/profile/'. $id.'.'.$extension)) {
1347 unlink(AT_CONTENT_DIR.'profile_pictures/profile/'. $id.'.'.$extension);
1349 if (file_exists(AT_CONTENT_DIR.'profile_pictures/thumbs/'. $id.'.'.$extension)) {
1350 unlink(AT_CONTENT_DIR.'profile_pictures/thumbs/'. $id.'.'.$extension);
1357 * returns a list of $field values from $table using $where_clause, separated by $separator.
1358 * uses mysql's GROUP_CONCAT() if available and if within the limit (default is 1024), otherwise
1359 * it does it the old school way.
1360 * returns the list (as a string) or (int) 0, if none found.
1362 function get_group_concat($table, $field, $where_clause = 1, $separator = ',') {
1363 global $_config, $db;
1364 if (!isset($_config['mysql_group_concat_max_len'])) {
1365 $sql = "SELECT @@global.group_concat_max_len AS max";
1366 $result = mysql_query($sql, $db);
1367 if ($result && ($row = mysql_fetch_assoc($result))) {
1368 $_config['mysql_group_concat_max_len'] = $row['max'];
1370 $_config['mysql_group_concat_max_len'] = 0;
1372 $sql = "REPLACE INTO ".TABLE_PREFIX."config VALUES ('mysql_group_concat_max_len', '{$_config['mysql_group_concat_max_len']}')";
1373 mysql_query($sql, $db);
1375 if ($_config['mysql_group_concat_max_len'] > 0) {
1376 $sql = "SELECT GROUP_CONCAT($field SEPARATOR '$separator') AS list FROM ".TABLE_PREFIX."$table WHERE $where_clause";
1377 $result = mysql_query($sql, $db);
1378 if ($row = mysql_fetch_assoc($result)) {
1379 if (!$row['list']) {
1381 } else if ($row['list'] && strlen($row['list']) < $_config['mysql_group_concat_max_len']) {
1382 return $row['list'];
1383 } // else: list is truncated, do it the old way
1385 // doesn't actually get here.
1391 $sql = "SELECT $field AS id FROM ".TABLE_PREFIX."$table WHERE $where_clause";
1392 $result = mysql_query($sql, $db);
1393 while ($row = mysql_fetch_assoc($result)) {
1394 $list .= $row['id'] . ',';
1397 return substr($list, 0, -1); }
1401 function get_human_time($seconds) {
1403 $out = '0'._AT('second_short');
1404 } else if ($seconds > 60 * 60) { // more than 60 minutes.
1405 $hours = floor($seconds / 60 / 60);
1406 $minutes = floor(($seconds - $hours * 60 * 60) / 60);
1407 $out = $hours ._AT('hour_short').' '.$minutes._AT('minute_short');
1410 } else if ($seconds > 60) { // more than a minute
1411 $minutes = floor($seconds / 60);
1412 $out = $minutes ._AT('minute_short').' '.($seconds - $minutes * 60)._AT('second_short');
1413 } else { // less than a minute
1414 $out = $seconds . _AT('second_short');
1420 function is_mobile_device() {
1421 $http_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
1422 return ((stripos($http_user_agent, IPOD_DEVICE) !== false && stripos($http_user_agent, IPOD_DEVICE) >= 0) ||
1423 (stripos($http_user_agent, IPHONE_DEVICE) !== false && stripos($http_user_agent, IPHONE_DEVICE) >= 0) ||
1424 (stripos($http_user_agent, BLACKBERRY_DEVICE) !== false && stripos($http_user_agent, BLACKBERRY_DEVICE) >= 0) ||
1425 (stripos($http_user_agent, ANDROID_DEVICE) !== false && stripos($http_user_agent, ANDROID_DEVICE) >= 0))
1429 function get_mobile_device_type() {
1430 $http_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
1431 if (stripos($http_user_agent, IPOD_DEVICE) !== false && stripos($http_user_agent, IPOD_DEVICE) >= 0) {
1433 } else if (stripos($http_user_agent, IPHONE_DEVICE) !== false && stripos($http_user_agent, IPHONE_DEVICE) >= 0) {
1434 return IPHONE_DEVICE;
1435 } else if (stripos($http_user_agent, BLACKBERRY_DEVICE) !== false && stripos($http_user_agent, BLACKBERRY_DEVICE) >= 0) {
1436 return BLACKBERRY_DEVICE;
1437 } else if (stripos($http_user_agent, ANDROID_DEVICE) !== false && stripos($http_user_agent, ANDROID_DEVICE) >= 0) {
1438 return ANDROID_DEVICE;
1440 return UNKNOWN_DEVICE;
1445 * Convert all input to htmlentities output, in UTF-8.
1446 * @param string input to be convert
1447 * @param boolean true if we wish to change all newlines(\r\n) to a <br/> tag, false otherwise.
1448 * ref: http://php.net/manual/en/function.nl2br.php
1449 * @author Harris Wong
1450 * @date March 12, 2010
1452 function htmlentities_utf8($str, $use_nl2br=true){
1453 $return = htmlentities($str, ENT_QUOTES, 'UTF-8');
1455 return nl2br($return);
1461 * Convert all '&' to '&' from the input
1462 * @param string any string input, mainly URLs.
1463 * @return input with & replaced to '&'
1464 * @author Harris Wong
1467 function convert_amp($input){
1468 $input = str_replace('&', '&', $input); //convert everything to '&' first
1469 return str_replace('&', '&', $input);
1473 * Check if json_encode/json_decode exists, if not, use the json service library.
1474 * NOTE: json_encode(), json_decode() are NOT available piror to php 5.2
1475 * @author Harris Wong
1476 * @date April 21, 2010
1478 if ( !function_exists('json_encode') ){
1479 function json_encode($content){
1480 require_once (AT_INCLUDE_PATH.'lib/json.inc.php');
1481 $json = new Services_JSON;
1482 return $json->encode($content);
1485 if ( !function_exists('json_decode') ){
1486 function json_decode($content, $assoc=false){
1487 require_once (AT_INCLUDE_PATH.'lib/json.inc.php');
1489 $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
1491 $json = new Services_JSON;
1493 return $json->decode($content);
1498 * Finds the image in the theme image folder first. If the image does not exist, look up in
1499 * core image folder.
1500 * @param: image_name - The relative path and name to the image.
1501 * "Relative" means relative to the "image" folder, with subfolders and image name.
1502 * actual_relative_path - Used when find_image() is called, for example in a class,
1503 * which is then called by different scripts that give different AT_INCLUDE_PATH. However,
1504 * the path to the image itself is consistent regardless of the caller script. This value
1505 * should be the consistent relative path to the image itself.
1506 * @return: The path to the image in the theme folder, if exists.
1507 * Otherwise, the path to the image in the core image folder.
1509 * 1. pass in "rtl_tree/tree/collapse.gif"
1510 * 2. return the path to this image in the theme folder: include/../themes/default/images/rtl_tree/tree/collapse.gif
1511 * if the theme image does not exist, return the path to the image in the core "image" folder: include/../images/rtl_tree/tree/collapse.gif
1512 * These pathes are relative to ATutor installation directory.
1514 function find_image($image_name, $actual_relative_path = AT_INCLUDE_PATH) {
1515 // The returned path is determined by AT_INCLUDE_PATH. If AT_INCLUDE_PATH is undefined, return the parameter itself.
1516 if (!defined('AT_INCLUDE_PATH')) return $image_name;
1518 // string concanation cannot be used at assigning parameter default value
1519 if ($actual_relative_path == AT_INCLUDE_PATH) $actual_relative_path .= '../';
1521 // remove leading "/"
1522 if (substr($image_name, 0, 1) == "/") $image_name = substr($image_name, 1);
1524 $theme_image_folder = 'themes/'.$_SESSION['prefs']['PREF_THEME'].'/images/';
1525 $atutor_image_folder = 'images/';
1527 // Use the path that is relative to AT_INCLUDE_PATH in the caller script, to check the existence of the image
1528 // but the return path is based on the pass-in actual path parameter.
1529 if (file_exists(AT_INCLUDE_PATH.'../'.$theme_image_folder.$image_name)) {
1530 return $actual_relative_path.$theme_image_folder.$image_name;
1532 return $actual_relative_path.$atutor_image_folder.$image_name;
1536 require(AT_INCLUDE_PATH . '../mods/_core/modules/classes/Module.class.php');
1538 $moduleFactory = new ModuleFactory(TRUE); // TRUE is for auto_loading the module.php files
1540 if (isset($_GET['submit_language']) && $_SESSION['valid_user']) {
1541 if ($_SESSION['course_id'] == -1) {
1542 $sql = "UPDATE ".TABLE_PREFIX."admins SET language = '$_SESSION[lang]' WHERE login = '$_SESSION[login]'";
1543 $result = mysql_query($sql, $db);
1545 $sql = "UPDATE ".TABLE_PREFIX."members SET language = '$_SESSION[lang]', creation_date=creation_date, last_login=last_login WHERE member_id = $_SESSION[member_id]";
1546 $result = mysql_query($sql, $db);
1550 if (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0) {
1551 $_custom_head .= '<script type="text/javascript" src="'.$_base_path.'jscripts/ATutorCourse.js"></script>';