8ee494887e081796557887f72e59bcf39019af30
[atutor.git] / docs / include / vitals.inc.php
1 <?php
2 /************************************************************************/
3 /* ATutor                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2002 - 2009                                            */
6 /* Inclusive Design Institute                                           */
7 /*                                                                      */
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 /************************************************************************/
12 // $Id$
13
14 if (!defined('AT_INCLUDE_PATH')) { exit; }
15
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);
19
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; }
23
24    // Might want to change this perhaps to a nicer error
25    if (isset($_REQUEST['GLOBALS'])) { die('GLOBALS overwrite attempt detected'); }
26
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());
30   
31    foreach ($input as $k => $v) {
32        if (!in_array($k, $noUnset) && isset($GLOBALS[$k])) { unset($GLOBALS[$k]); }
33    }
34 }
35
36 //functions for properly escaping input strings
37 function my_add_null_slashes( $string ) {
38     return mysql_real_escape_string(stripslashes($string));
39 }
40 function my_null_slashes($string) {
41     return $string;
42 }
43
44 if ( get_magic_quotes_gpc() == 1 ) {
45     $addslashes   = 'my_add_null_slashes';
46     $stripslashes = 'stripslashes';
47 } else {
48     $addslashes   = 'mysql_real_escape_string';
49     $stripslashes = 'my_null_slashes';
50 }
51
52 function regenerate_session($reload = false)
53 {
54         if(!isset($_SESSION['IPaddress']) || $reload)
55                 $_SESSION['IPaddress'] = $_SERVER['REMOTE_ADDR'];
56
57         if(!isset($_SESSION['userAgent']) || $reload)
58                 $_SESSION['userAgent'] = $_SERVER['HTTP_USER_AGENT'];
59
60         $session_values = $_SESSION;
61
62         // Set current session to expire in 10 seconds
63         $_SESSION['OBSOLETE'] = true;
64         $_SESSION['EXPIRES'] = time() + 10;
65
66         // Create new session without destroying the old one
67         session_regenerate_id(false);
68
69         // Grab current session ID and close both sessions to allow other scripts to use them
70         $newSession = session_id();
71         session_write_close();
72
73         // Set session ID to the new one, and start it back up again
74         session_id($newSession);
75         session_start();
76
77         $_SESSION = $session_values; 
78 }
79
80 function check_session()
81 {
82         if($_SESSION['OBSOLETE'] && ($_SESSION['EXPIRES'] < time())) {
83                 return false;
84         }
85                     
86         if($_SESSION['IPaddress'] != $_SERVER['REMOTE_ADDR']) {
87                 return false;
88         }
89                     
90         if($_SESSION['userAgent'] != $_SERVER['HTTP_USER_AGENT']) {
91                 return false;
92         }
93                     
94         if(!$_SESSION['OBSOLETE']) {
95                 regenerate_session();
96         }
97         return true;
98 }
99
100 /*
101  * structure of this document (in order):
102  *
103  * 0. load config.inc.php
104  * 1. load constants
105  * 2. initialize db connection and populate $_config
106  * 3. initialize session
107  * 4. enable output compression
108  * 5. validate login user
109  * 6. load language
110  * 7. load cache/ContentManagement/output/Savant/Message libraries
111  ***/
112
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');
116
117         error_reporting(0);
118         if (!defined('AT_REDIRECT_LOADED')){
119                 include_once(AT_INCLUDE_PATH.'config.inc.php');
120         }
121         error_reporting(AT_ERROR_REPORTING);
122
123         if (!defined('AT_INSTALL') || !AT_INSTALL) {
124                 header('Cache-Control: no-store, no-cache, must-revalidate');
125                 header('Pragma: no-cache');
126
127                 $relative_path = substr(AT_INCLUDE_PATH, 0, -strlen('include/'));
128                 header('Location: ' . $relative_path . 'install/not_installed.php');
129                 exit;
130         }
131 /*** end system config block ***/
132
133 /*** 1. constants ***/
134 if (!defined('AT_REDIRECT_LOADED')){
135         require_once(AT_INCLUDE_PATH.'lib/constants.inc.php');
136 }
137
138 /*** 2. initialize db connection and populate $_config ***/
139
140 if (!defined('AT_REDIRECT_LOADED')){
141         require_once(AT_INCLUDE_PATH.'lib/mysql_connect.inc.php');
142 }
143
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'];
149 }
150
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);
156 }
157
158 @set_time_limit(0);
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);
163
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);
169         exit;
170 }
171
172 $isHttps = (!isset($_SERVER['HTTPS']) || $_SERVER['HTTPS'] != "on")
173            ? false
174            : true;
175 ob_start();
176 session_set_cookie_params(0, $_config["session_path"], "", $isHttps);
177 session_start();
178
179 // Regenerate session id at every page refresh to prevent CSRF
180 $valid_session = true;
181 if (count($_SESSION) == 0) {
182         regenerate_session();
183 } else {
184         $valid_session = check_session();
185 }
186
187 $str = ob_get_contents();
188 ob_end_clean();
189 unregister_GLOBALS();
190
191 // Re-direct to login page at a potential session hijack
192 if (!$valid_session) {
193         $_SESSION = array();
194         header('Location: '.AT_BASE_HREF.'login.php');
195         exit;
196 }
197
198 if ($str) {
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);
204         exit;
205 }
206 /***** end session initilization block ****/
207
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);
211 }
212
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);
218                 exit;
219         }
220
221         header('Location: '.AT_BASE_HREF.'login.php');
222         exit;
223 }
224
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'] : '');
245
246 if ($_config['time_zone']) {
247         //$sql = "SET time_zone='{$_config['time_zone']}'";
248         //mysql_query($sql, $db);
249
250         if (function_exists('date_default_timezone_set')) {
251         foreach($utc_timezones as $zone){
252
253                 if($zone[1] ==  $_config['time_zone']){
254                 $zone_name = $zone[2];
255                 break;
256                 }
257         }
258                 date_default_timezone_set($zone_name);
259         } else {
260                 @putenv("TZ={$_config['time_zone']}");
261         }
262 }
263 /***** 6. load language *****/
264 // set current language
265 require(AT_INCLUDE_PATH . '../mods/_core/languages/classes/LanguageManager.class.php');
266 $languageManager = new LanguageManager();
267
268 $myLang =& $languageManager->getMyLanguage();
269
270 if ($myLang === FALSE) {
271         echo 'There are no languages installed!';
272         exit;
273 }
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                   
278         } else {
279                 $myLang->saveToPreferences($_SESSION['member_id'], 0);  //0 for non-admin
280         }
281 }
282 $myLang->sendContentTypeHeader();
283
284 /* set right-to-left language */
285 $rtl = '';
286 if ($myLang->isRTL()) {
287         $rtl = 'rtl_'; /* basically the prefix to a rtl variant directory/filename. eg. rtl_tree */
288 }
289 /***** end language block ****/
290
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 */
296 }
297 require(AT_INCLUDE_PATH.'classes/Savant2/Savant2.php');       /* for the theme and template management */
298
299 // set default template paths:
300 $savant = new Savant2();
301 $savant->addPath('template', AT_INCLUDE_PATH . '../themes/default/');
302
303 //if user has requested theme change, make the change here
304 if (($_POST['theme'] || $_POST['mobile_theme']) && $_POST['submit']) {
305     $_SESSION['prefs']['PREF_THEME'] = $addslashes($_POST['theme']);
306     $_SESSION['prefs']['PREF_MOBILE_THEME'] = $addslashes($_POST['mobile_theme']);
307 } else if ($_POST['set_default']) {
308     $_SESSION['prefs']['PREF_THEME'] = 'default';
309     $_SESSION['prefs']['PREF_MOBILE_THEME'] = 'mobile';
310 }
311
312 // Reset PREF_THEME when:
313 // 1. If PREF_THEME is not set 
314 // 2. The request is from the mobile device but PREF_THEME is not a mobile theme 
315 if (!isset($_SESSION['prefs']['PREF_THEME']) ||
316     $_SESSION['prefs']['PREF_THEME'] == "" ||
317     (is_mobile_device() && !is_mobile_theme($_SESSION['prefs']['PREF_THEME']))) {
318         // get default
319         $default_theme = get_default_theme();
320         
321         $_SESSION['prefs']['PREF_THEME'] = $default_theme['dir_name'];
322 }
323
324 if (!is_dir(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME']) || $_SESSION['prefs']['PREF_THEME'] == '') {
325         $_SESSION['prefs']['PREF_THEME'] = get_system_default_theme();
326 }
327
328 // use "mobile" theme for mobile devices. For now, there's only one mobile theme and it's hardcoded.
329 // When more mobile themes come in, this should be changed.
330 if (isset($_SESSION['prefs']['PREF_THEME']) && file_exists(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME']) && isset($_SESSION['valid_user']) && $_SESSION['valid_user']) {
331         if ($_SESSION['course_id'] == -1) {
332                 if ($_SESSION['prefs']['PREF_THEME'] == '' || !is_dir(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'])) {
333                         $_SESSION['prefs']['PREF_THEME'] = get_system_default_theme();
334                 }
335         } else {
336                 //check if enabled
337                 $sql    = "SELECT status FROM ".TABLE_PREFIX."themes WHERE dir_name = '".$_SESSION['prefs']['PREF_THEME']."'";
338                 $result = mysql_query($sql, $db);
339                 $row = mysql_fetch_assoc($result);
340                 if ($row['status'] > 0) {
341                 } else {
342                         // get default
343                         $default_theme = get_default_theme();
344                         if (!is_dir(AT_INCLUDE_PATH . '../themes/' . $default_theme['dir_name'])) {
345                                 $default_theme = array('dir_name' => get_system_default_theme());
346                         }
347                         $_SESSION['prefs']['PREF_THEME'] = $default_theme['dir_name'];
348                 }
349         }
350 }
351
352 $savant->addPath('template', AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'] . '/');
353 require(AT_INCLUDE_PATH . '../themes/' . $_SESSION['prefs']['PREF_THEME'] . '/theme.cfg.php');
354
355 require(AT_INCLUDE_PATH.'classes/Message/Message.class.php');
356 $msg = new Message($savant);
357
358 $contentManager = new ContentManager($db, isset($_SESSION['course_id']) ? $_SESSION['course_id'] : $_GET['p_course']);
359 $contentManager->initContent();
360
361 /**************************************************/
362 require(AT_INCLUDE_PATH.'phpCache/phpCache.inc.php'); // cache library
363 require(AT_INCLUDE_PATH.'lib/utf8.php');                        //UTF-8 multibyte library
364
365 if (!file_exists(AT_INCLUDE_PATH.'../sha-1factory.js')) {
366         require(AT_INCLUDE_PATH.'header.inc.php');
367         $msg->printErrors('MISSING_SHA1');
368         require(AT_INCLUDE_PATH.'footer.inc.php');
369         exit;
370 }
371
372 if (isset($_user_location) && ($_user_location == 'users') && $_SESSION['valid_user'] && ($_SESSION['course_id'] > 0)) {
373         $_SESSION['course_id'] = 0;
374 }
375
376 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)) {
377         header('Location:'.AT_BASE_HREF.'users/index.php');
378         exit;
379 }
380 /* check if we are in the requested course, if not, bounce to it.
381  * @author harris, for pretty url, read AT_PRETTY_URL_HANDLER
382  */ 
383 if ((isset($_SESSION['course_id']) && isset($_pretty_url_course_id) && $_SESSION['course_id'] != $_pretty_url_course_id) ||
384         (isset($_pretty_url_course_id) && !isset($_SESSION['course_id']) && !isset($_REQUEST['ib']))) {
385
386         if($_config['pretty_url'] == 0){
387                 header('Location: '.AT_BASE_HREF.'bounce.php?course='.$_pretty_url_course_id.SEP.'pu='.$_SERVER['PATH_INFO'].urlencode('?'.$_SERVER['QUERY_STRING']));
388         } else {
389                 header('Location: '.AT_BASE_HREF.'bounce.php?course='.$_pretty_url_course_id.SEP.'pu='.$_SERVER['PATH_INFO']);
390         }
391         exit;
392 }
393
394    /**
395    * This function is used for printing variables into log file for debugging.
396    * @access  public
397    * @param   mixed $var        The variable to output
398    * @param   string $log       The location of the log file. If not provided, use the default one.
399    * @author  Cindy Qi Li
400    */
401 function debug_to_log($var, $log='') {
402         if (!defined('AT_DEVEL') || !AT_DEVEL) {
403                 return;
404         }
405         
406         if ($log == '') $log = AT_CONTENT_DIR. 'atutor.log';
407         $handle = fopen($log, 'a');
408         fwrite($handle, "\n\n");
409         fwrite($handle, date("F j, Y, g:i a"));
410         fwrite($handle, "\n");
411         fwrite($handle, var_export($var,1));
412         
413         fclose($handle);
414 }
415
416    /**
417    * This function is used for printing variables for debugging.
418    * @access  public
419    * @param   mixed $var        The variable to output
420    * @param   string $title     The name of the variable, or some mark-up identifier.
421    * @author  Joel Kronenberg
422    */
423 function debug($var, $title='') {
424         if (!defined('AT_DEVEL') || !AT_DEVEL) {
425                 return;
426         }
427         
428         echo '<pre style="border: 1px black solid; padding: 0px; margin: 10px;" title="debugging box">';
429         if ($title) {
430                 echo '<h4>'.$title.'</h4>';
431         }
432         
433         ob_start();
434         print_r($var);
435         $str = ob_get_contents();
436         ob_end_clean();
437
438         $str = str_replace('<', '&lt;', $str);
439
440         $str = str_replace('[', '<span style="color: red; font-weight: bold;">[', $str);
441         $str = str_replace(']', ']</span>', $str);
442         $str = str_replace('=>', '<span style="color: blue; font-weight: bold;">=></span>', $str);
443         $str = str_replace('Array', '<span style="color: purple; font-weight: bold;">Array</span>', $str);
444         echo $str;
445         echo '</pre>';
446 }
447
448 /********************************************************************/
449 /* the system course information                                                                        */
450 /* system_courses[course_id] = array(title, description, subject)       */
451 $system_courses = array();
452
453 // temporary set to a low number
454 $sql = 'SELECT * FROM '.TABLE_PREFIX.'courses ORDER BY title';
455 $result = mysql_query($sql, $db);
456 while ($row = mysql_fetch_assoc($result)) {
457         $course = $row['course_id'];
458         unset($row['course_id']);
459         $system_courses[$course] = $row;
460 }
461 /*                                                                                                                                      */
462 /********************************************************************/
463 // p_course is set when pretty url is on and guests access a public course. @see bounce.php
464 // First, santinize p_course
465 if (isset($_REQUEST['p_course'])) {
466         $_REQUEST['p_course'] = intval($_REQUEST['p_course']);
467 }
468
469 if (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0 || $_REQUEST['p_course'] > 0) {
470         $sql = 'SELECT * FROM '.TABLE_PREFIX.'glossary 
471                  WHERE course_id='.($_SESSION['course_id']>0 ? $_SESSION['course_id'] : $_REQUEST['p_course']).' 
472                  ORDER BY word';
473         $result = mysql_query($sql, $db);
474         $glossary = array();
475         $glossary_ids = array();
476         while ($row_g = mysql_fetch_assoc($result)) {           
477                 $row_g['word'] = htmlspecialchars($row_g['word'], ENT_QUOTES, 'UTF-8');
478                 $glossary[$row_g['word']] = str_replace("'", "\'",$row_g['definition']);
479                 $glossary_ids[$row_g['word_id']] = $row_g['word'];
480
481                 /* a kludge to get the related id's for when editing content */
482                 /* it's ugly, but beats putting this query AGAIN on the edit_content.php page */
483                 if (isset($get_related_glossary)) {
484                         $glossary_ids_related[$row_g['word']] = $row_g['related_word_id'];
485                 }
486         }
487 }
488
489 function get_html_body($text) {
490         /* strip everything before <body> */
491         $start_pos      = strpos(strtolower($text), '<body');
492         if ($start_pos !== false) {
493                 $start_pos      += strlen('<body');
494                 $end_pos        = strpos(strtolower($text), '>', $start_pos);
495                 $end_pos        += strlen('>');
496
497                 $text = substr($text, $end_pos);
498         }
499
500         /* strip everything after </body> */
501         $end_pos        = strpos(strtolower($text), '</body>');
502         if ($end_pos !== false) {
503                 $text = trim(substr($text, 0, $end_pos));
504         }
505
506         return $text;
507 }
508
509 function get_html_head ($text) {
510         /* make all text lower case */
511 //      $text = strtolower($text);
512
513         /* strip everything before <head> */
514         $start_pos      = stripos($text, '<head');
515         if ($start_pos !== false) {
516                 $start_pos      += strlen('<head');
517                 $end_pos        = stripos($text, '>', $start_pos);
518                 $end_pos        += strlen('>');
519
520                 $text = substr($text, $end_pos);
521         }
522
523         /* strip everything after </head> */
524         $end_pos        = stripos($text, '</head');
525         if ($end_pos !== false) {
526                 $text = trim(substr($text, 0, $end_pos));
527         }
528         return $text;
529 }
530
531 /**
532 * This function cuts out requested tag information from html head
533 * @access  public
534 * @param   $text  html text
535 * @param   $tags  a string or an array of requested tags
536 * @author  Cindy Qi Li
537 */
538 function get_html_head_by_tag($text, $tags)
539 {
540         $head = get_html_head($text);
541         $rtn_text = "";
542         
543         if (!is_array($tags) && strlen(trim($tags)) > 0)
544         {
545                 $tags = array(trim($tags));
546         }
547         foreach ($tags as $tag)
548         {
549                 $tag = strtolower($tag);
550
551                 /* strip everything before <{tag}> */
552                 $start_pos      = stripos($head, '<'.$tag);
553                 $temp_head = $head;
554                 
555                 while ($start_pos !== false) 
556                 {
557                         $temp_text = substr($temp_head, $start_pos);
558         
559                         /* strip everything after </{tag}> or />*/
560                         $end_pos        = stripos($temp_text, '</' . $tag . '>');
561         
562                         if ($end_pos !== false) 
563                         {
564                                 $end_pos += strlen('</' . $tag . '>');
565                                 
566                                 // add an empty line after each tag information
567                                 $rtn_text .= trim(substr($temp_text, 0, $end_pos)) . '
568         
569 ';
570                         }
571                         else  // match /> as ending tag if </tag> is not found
572                         {
573                                 $end_pos        = stripos($temp_text, '/>');
574                                 
575                                 if($end_pos === false && stripos($temp_text, $tag.'>')===false){
576                                         //if /> is not found, then this is not a valid XHTML
577                                         //text iff it's not tag>
578                                         $end_pos = stripos($temp_text, '>');
579                                         $end_pos += strlen('>');
580                                 } else {
581                                         $end_pos += strlen('/>');
582                                 }
583                                 // add an empty line after each tag information
584                                 $rtn_text .= trim(substr($temp_text, 0, $end_pos)) . '
585         
586 ';
587                         }
588                         
589                         // initialize vars for next round of matching
590                         $temp_head = substr($temp_text, $end_pos);
591                         $start_pos = stripos($temp_head, '<'.$tag);
592                 }
593         }
594         return $rtn_text;
595 }
596
597 if (version_compare(phpversion(), '4.3.0') < 0) {
598         function file_get_contents($filename) {
599                 $fd = @fopen($filename, 'rb');
600                 if ($fd === false) {
601                         $content = false;
602                 } else {
603                         $content = @fread($fd, filesize($filename));
604                         @fclose($fd);
605                 }
606
607                 return $content;
608         }
609
610         function mysql_real_escape_string($input) {
611                 return mysql_escape_string($input);
612         }
613 }
614
615
616 function add_user_online() {
617         if (!isset($_SESSION['member_id']) || !($_SESSION['member_id'] > 0)) {
618                 return;
619         }
620         global $db, $addslashes;
621
622     $expiry = time() + 900; // 15min
623     $sql    = 'REPLACE INTO '.TABLE_PREFIX.'users_online VALUES ('.$_SESSION['member_id'].', '.$_SESSION['course_id'].', "'.$addslashes(get_display_name($_SESSION['member_id'])).'", '.$expiry.')';
624     $result = mysql_query($sql, $db);
625
626         /* garbage collect and optimize the table every so often */
627         mt_srand((double) microtime() * 1000000);
628         $rand = mt_rand(1, 20);
629         if ($rand == 1) {
630                 $sql = 'DELETE FROM '.TABLE_PREFIX.'users_online WHERE expiry<'.time();
631                 $result = @mysql_query($sql, $db);
632         }
633 }
634
635 /**
636  * Returns the login name of a member.
637  * @access  public
638  * @param   int $id     The ID of the member.
639  * @return  Returns the login name of the member whose ID is $id.
640  * @author  Joel Kronenberg
641  */
642 function get_login($id){
643         global $db, $_config_defaults;
644
645         if (is_array($id)) {
646                 $id             = implode(',',$id);
647                 $sql    = 'SELECT login, member_id FROM '.TABLE_PREFIX.'members WHERE member_id IN ('.$id.') ORDER BY login';
648
649                 $rows = array();
650                 $result = mysql_query($sql, $db);
651                 while( $row     = mysql_fetch_assoc($result)) {
652                         $rows[$row['member_id']] = $row['login'];
653                 }
654                 return $rows;
655         } else {
656                 $id             = intval($id);
657                 $sql    = 'SELECT login FROM '.TABLE_PREFIX.'members WHERE member_id='.$id;
658
659                 $result = mysql_query($sql, $db);
660                 $row    = mysql_fetch_assoc($result);
661
662                 return $row['login'];
663         }
664
665 }
666
667 function get_display_name($id) {
668         static $db, $_config, $display_name_formats;
669         if (!$id) {
670                 return $_SESSION['login'];
671         }
672
673         if (!isset($db, $_config)) {
674                 global $db, $_config, $display_name_formats;
675         }
676
677         if (substr($id, 0, 2) == 'g_' || substr($id, 0, 2) == 'G_')
678         {
679                 $sql    = "SELECT name FROM ".TABLE_PREFIX."guests WHERE guest_id='".$id."'";
680                 $result = mysql_query($sql, $db);
681                 $row    = mysql_fetch_assoc($result);
682
683                 return _AT($display_name_formats[$_config['display_name_format']], '', $row['name'], '', '');
684         }
685         else
686         {
687                 $sql    = 'SELECT login, first_name, second_name, last_name FROM '.TABLE_PREFIX.'members WHERE member_id='.$id;
688                 $result = mysql_query($sql, $db);
689                 $row    = mysql_fetch_assoc($result);
690
691                 return _AT($display_name_formats[$_config['display_name_format']], $row['login'], $row['first_name'], $row['second_name'], $row['last_name']);
692         }
693 }
694
695 function get_forum_name($fid){
696         global $db;
697
698         $fid = intval($fid);
699
700         $sql    = 'SELECT title FROM '.TABLE_PREFIX.'forums WHERE forum_id='.$fid;
701         $result = mysql_query($sql, $db);
702         if (($row = mysql_fetch_assoc($result)) && $row['title']) {
703                 return $row['title'];           
704         }
705
706         $sql = "SELECT group_id FROM ".TABLE_PREFIX."forums_groups WHERE forum_id=$fid";
707         $result = mysql_query($sql, $db);
708         if ($row = mysql_fetch_assoc($result)) {
709                 return get_group_title($row['group_id']);
710         }
711
712         return FALSE;
713 }
714
715 // takes the array of valid prefs and assigns them to the current session 
716 // @params: prefs - an array of preferences
717 // @params: optional. Values are 0 or 1. Default value is 0
718 //          when 1, assign PREF_MOBILE_THEME to PREF_THEME if the request is from a mobile device
719 //                  this value is to set when the prefs values are set for display
720 //                  if this function is used as a front shot for save_prefs(), the value should be 0
721 function assign_session_prefs($prefs, $switch_mobile_theme = 0) {
722         if (is_array($prefs)) {
723                 foreach($prefs as $pref_name => $value) {
724                         $_SESSION['prefs'][$pref_name] = $value;
725                 }
726         }
727         if (is_mobile_device() && $switch_mobile_theme) {
728                 $_SESSION['prefs']['PREF_THEME'] = $_SESSION['prefs']['PREF_MOBILE_THEME'];
729         }
730 }
731
732 function save_prefs( ) {
733         global $db, $addslashes;
734
735         if ($_SESSION['valid_user']) {
736                 $data   = $addslashes(serialize($_SESSION['prefs']));
737                 $sql    = 'UPDATE '.TABLE_PREFIX.'members SET preferences="'.$data.'", creation_date=creation_date, last_login=last_login WHERE member_id='.$_SESSION['member_id'];
738                 $result = mysql_query($sql, $db); 
739         }
740 }
741
742 function save_email_notification($mnot) {
743     global $db;
744     
745     if ($_SESSION['valid_user']) {
746         $sql = "UPDATE ".TABLE_PREFIX."members SET inbox_notify =". $mnot .", creation_date=creation_date, last_login=last_login WHERE member_id =".$_SESSION['member_id'];
747         $result = mysql_query($sql, $db);
748     }
749 }
750
751 /**
752 * Saves the last viewed content page in a user's course so that on next visit, user can start reading where they left off
753 * @access  public
754 * @param   int $cid             the content page id
755 * @return  none
756 * @see     $db                  in include/vitals.inc.php
757 * @author  Joel Kronenberg
758 */
759 function save_last_cid($cid) {
760         if ($_SESSION['enroll'] == AT_ENROLL_NO) {
761                 return;
762         }
763         global $db;
764
765         $_SESSION['s_cid']    = intval($_GET['cid']);
766
767         if (!$_SESSION['is_admin']   && 
768                 !$_SESSION['privileges'] && 
769                 !isset($in_get)          && 
770                 !$_SESSION['cid_time']   && 
771                 ($_SESSION['course_id'] > 0) ) 
772                 {
773                         $_SESSION['cid_time'] = time();
774         }
775
776         $sql = "UPDATE ".TABLE_PREFIX."course_enrollment SET last_cid=$cid WHERE course_id=$_SESSION[course_id] AND member_id=$_SESSION[member_id]";
777         mysql_query($sql, $db);
778 }
779
780 // there has to be a better way of expressing this if-statement!
781 // and, does it really have to be here?
782 if ((!isset($_SESSION['is_admin']) || !$_SESSION['is_admin'])       && 
783         (!isset($_SESSION['privileges']) || !$_SESSION['privileges'])     &&
784         !isset($in_get)              && 
785         isset($_SESSION['s_cid']) && $_SESSION['s_cid'] && 
786         isset($_SESSION['cid_time']) && $_SESSION['cid_time'] &&
787     ($_SESSION['course_id'] > 0) && 
788         ($_SESSION['s_cid'] != $_GET['cid']) && 
789         ($_SESSION['enroll'] != AT_ENROLL_NO) )  
790         {
791                 $diff = time() - $_SESSION['cid_time'];
792                 if ($diff > 0) {
793                         $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]";
794
795                         $result = mysql_query($sql, $db);
796
797                         if (mysql_affected_rows($db) == 0) {
798                                 $sql = "INSERT INTO ".TABLE_PREFIX."member_track VALUES ($_SESSION[member_id], $_SESSION[course_id], $_SESSION[s_cid], 1, $diff, NOW())";
799                                 $result = mysql_query($sql, $db);
800                         }
801                 }
802
803                 $_SESSION['cid_time'] = 0;
804 }
805
806
807 /**
808 * Checks if the $_SESSION[member_id] is an instructor (true) or not (false)
809 * The result is only fetched once - it is then available via a static variable, $is_instructor
810 * @access  public
811 * @param   none
812 * @return  bool true if is instructor, false otherwise.
813 * @see     $db   in include/vitals.inc.php
814 * @author  Joel Kronenberg
815 */      
816 function get_instructor_status() {
817         static $is_instructor;
818
819         if (isset($is_instructor)) {
820                 return $is_instructor;
821         }
822
823         global $db;
824
825         $is_instructor = false;
826
827         $sql = 'SELECT status FROM '.TABLE_PREFIX.'members WHERE member_id='.$_SESSION['member_id'];
828         $result = mysql_query($sql, $db);
829         if (!($row = @mysql_fetch_assoc($result))) {
830                 $is_instructor = FALSE;
831                 return FALSE;
832         }
833
834         if ($row['status'] == AT_STATUS_INSTRUCTOR) {
835                 $is_instructor = TRUE;
836                 return TRUE;
837         }
838
839         $is_instructor = FALSE;
840         return FALSE;
841 }
842
843 /****************************************************/
844 /* update the user online list                                          */
845 if (isset($_SESSION['valid_user']) && $_SESSION['valid_user']) {
846         $new_minute = time()/60;
847         if (!isset($_SESSION['last_updated'])) {
848                 $_SESSION['last_updated'] = $new_minute;
849         }
850         $diff       = abs($_SESSION['last_updated'] - $new_minute);
851         if ($diff > ONLINE_UPDATE) {
852                 $_SESSION['last_updated'] = $new_minute;
853                 add_user_online();
854         }
855 }
856
857 /****************************************************/
858 /* compute the $_my_uri variable                                        */
859         $bits     = explode(SEP, getenv('QUERY_STRING'));
860         $num_bits = count($bits);
861         $_my_uri  = '';
862
863         for ($i=0; $i<$num_bits; $i++) {
864                 if (    (strpos($bits[$i], 'enable=')   === 0) 
865                         ||      (strpos($bits[$i], 'disable=')  === 0)
866                         ||      (strpos($bits[$i], 'expand=')   === 0)
867                         ||      (strpos($bits[$i], 'collapse=') === 0)
868                         ||      (strpos($bits[$i], 'lang=')             === 0)
869                         ) {
870                         /* we don't want this variable added to $_my_uri */
871                         continue;
872                 }
873
874                 if (($_my_uri == '') && ($bits[$i] != '')) {
875                         $_my_uri .= htmlentities('?');
876                 } else if ($bits[$i] != ''){
877                         $_my_uri .= htmlentities(SEP);
878                 }
879                 $_my_uri .= $bits[$i];
880         }
881         if ($_my_uri == '') {
882                 $_my_uri .= htmlentities('?');
883         } else {
884                 $_my_uri .= htmlentities(SEP);
885         }
886         $_my_uri = $_SERVER['PHP_SELF'].$_my_uri;
887
888 /**
889  * If MBString extension is loaded, 4.3.0+, then use it.
890  * Otherwise we will have to use include/utf8 library
891  * @author      Harris
892  * @date Oct 10, 2007
893  * @version     1.5.6
894  */
895  if (extension_loaded('mbstring')){
896          $strtolower = 'mb_strtolower';
897          $strtoupper = 'mb_strtoupper';
898          $substr = 'mb_substr';
899          $strpos = 'mb_strpos';
900          $strrpos = 'mb_strrpos';
901          $strlen = 'mb_strlen';
902  } else {
903          $strtolower = 'utf8_strtolower';
904          $strtoupper = 'utf8_strtoupper';
905          $substr = 'utf8_substr';
906          $strpos = 'utf8_strpos';
907          $strrpos = 'utf8_strrpos';
908          $strlen = 'utf8_strlen';
909  }
910
911
912 /*~~~~~~~~~~~~~~~~~flash detection~~~~~~~~~~~~~~~~*/
913 if(isset($_COOKIE["flash"])){
914     $_SESSION['flash'] = $_COOKIE["flash"];
915
916     //delete the cookie
917     ATutor.setcookie("flash",'',time()-3600);
918 }
919
920 if (!isset($_SESSION["flash"])) {
921         $_custom_head .= '
922                 <script type="text/javascript">
923                 <!--
924
925                         //VB-Script for InternetExplorer
926                         function iExploreCheck()
927                         {
928                                 document.writeln("<scr" + "ipt language=\'VBscript\'>");
929                                 //document.writeln("\'Test to see if VBScripting works");
930                                 document.writeln("detectableWithVB = False");
931                                 document.writeln("If ScriptEngineMajorVersion >= 2 then");
932                                 document.writeln("   detectableWithVB = True");
933                                 document.writeln("End If");
934                                 //document.writeln("\'This will check for the plugin");
935                                 document.writeln("Function detectActiveXControl(activeXControlName)");
936                                 document.writeln("   on error resume next");
937                                 document.writeln("   detectActiveXControl = False");
938                                 document.writeln("   If detectableWithVB Then");
939                                 document.writeln("      detectActiveXControl = IsObject(CreateObject(activeXControlName))");
940                                 document.writeln("   End If");
941                                 document.writeln("End Function");
942                                 document.writeln("</scr" + "ipt>");
943                                 return detectActiveXControl("ShockwaveFlash.ShockwaveFlash.1");
944                         }
945
946
947                         var plugin = (navigator.mimeTypes && navigator.mimeTypes["application/x-shockwave-flash"]) ? navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin : false;
948                         if(!(plugin) && (navigator.userAgent && navigator.userAgent.indexOf("MSIE")>=0 && (navigator.appVersion.indexOf("Win") != -1)))
949                                 if (iExploreCheck())
950                                         flash_detect = "flash=yes";
951                                 else
952                                         flash_detect = "flash=no";
953
954                         else if(plugin)
955                                 flash_detect = "flash=yes";
956                         else
957                                 flash_detect = "flash=no";
958
959                         writeCookie(flash_detect);
960
961                         function writeCookie(value)
962                         {
963                                 var today = new Date();
964                                 var the_date = new Date("December 31, 2099");
965                                 var the_cookie_date = the_date.toGMTString();
966                                 var the_cookie = value + ";expires=" + the_cookie_date;
967                                 document.cookie = the_cookie;
968                         }
969                 //-->
970                 </script>
971 ';
972 }
973
974
975
976 /*~~~~~~~~~~~~~~end flash detection~~~~~~~~~~~~~~~*/
977
978
979
980 /**
981 * Checks if the data exceeded the database predefined length, if so,
982 * truncate it.
983 * This is used on data that are being inserted into the database.
984 * If this function is used for display purposes, you may want to add the '...' 
985 *  at the end of the string by setting the $forDisplay=1
986 * @param        the mbstring that needed to be checked
987 * @param        the byte length of what the input should be in the database.
988 * @param        (OPTIONAL)
989 *                       append '...' at the end of the string.  Should not use this when 
990 *                       dealing with database.  This should only be set for display purposes.
991 * @return       the mbstring safe sql entry
992 * @author       Harris Wong
993 */
994 function validate_length($input, $len, $forDisplay=0){
995         global $strlen, $substr;
996         $input_bytes_len = strlen($input);
997         $input_len = $strlen($input);
998
999         //If the input has exceeded the db column limit
1000         if ($input_bytes_len > $len){
1001                 //calculate where to chop off the string
1002                 $percentage = $input_bytes_len / $input_len;
1003                 //Get the suitable length that should be stored in the db
1004                 $suitable_len = floor($len / $percentage);
1005
1006                 if ($forDisplay===1){
1007                         return $substr($input, 0, $suitable_len).'...';
1008                 }
1009                 return $substr($input, 0, $suitable_len);
1010         }
1011         //if valid length
1012         return $input;
1013
1014 /*
1015  * Instead of blindly cutting off the input from the given param
1016  * 
1017         global $strlen, $substr;
1018         if ($strlen($input) > $len) {
1019                 if ($forDisplay===1){
1020                         return $substr($input, 0, $len).'...';
1021                 }
1022                 return $substr($input, 0, $len);
1023         }
1024         return $input;
1025 */
1026 }
1027
1028 /**
1029  * If pretty URL within admin config is switched on.  We will apply pretty URL 
1030  * to all the links in ATutor.  This function will authenticate itself towards the current pages.
1031  * In our definition, admins, login, registration pages shouldn't have pretty url applied.  However,
1032  * if one want to use url_rewrite on these pages, please force it by using the third parameter.  
1033  * Note: If system config has turned off this feature, $force will have no effect.
1034  * @param       string  the Url should be a relative link, have to improve this later on, to check if 
1035  *                                      it's a relative link, if not, truncate it.
1036  * @param       boolean Available values are AT_PRETTY_URL_IS_HEADER, AT_PRETTY_URL_NOT_HEADER(default)
1037  *                      use AT_PRETTY_URL_IS_HEADER if url_rewrite is used in php header('Location:..'), absolute path is needed for this.
1038  * @param       boolean true to force the url_rewrite, false otheriwse.  False is the default.
1039  * @author      Harris Wong
1040  */
1041 function url_rewrite($url, $is_rewriting_header=AT_PRETTY_URL_NOT_HEADER, $force=false){
1042         global $_config, $db;
1043         $url_parser = new UrlParser();
1044         $pathinfo = $url_parser->getPathArray();
1045
1046         /* If this is any kind of admins, don't prettify the url
1047          * $_SESSION['is_guest'] is used to check against login/register/browse page, the links on this page will 
1048          * only be prettified when a user has logged in.
1049          * Had used $_SESSION[valid_user] before but it created this problem: 
1050          * http://www.atutor.ca/atutor/mantis/view.php?id=3426
1051          */
1052         if ($force || (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0)) {
1053                 //if course id is defined, apply pretty url.
1054         } 
1055         //if this is something that is displayed on the login page, don't modify the urls.
1056         else if ( (admin_authenticate(AT_ADMIN_PRIV_ADMIN, AT_PRIV_RETURN) 
1057                         || (isset($_SESSION['privileges']) && admin_authenticate($_SESSION['privileges'], AT_PRIV_RETURN))) 
1058                         || (isset($_SESSION['is_guest']) && $_SESSION['is_guest']==1)){
1059                 return $url;
1060         } 
1061
1062         //if we allow pretty url in the system
1063         if ($_config['pretty_url'] > 0){
1064                 $course_id = 0;
1065                 //If we allow course dir name from sys perf             
1066                 if ($_config['course_dir_name'] > 0){
1067                         if (preg_match('/bounce.php\?course=([\d]+)$/', $url, $matches) == 1){
1068                                 // bounce has the highest priority, even if session is set, work on 
1069                                 // bounce first.
1070                                 $course_id = $url_parser->getCourseDirName($matches[1]);
1071                         } elseif (isset($_REQUEST['course'])){
1072                                 //jump menu
1073                                 $course_id = $url_parser->getCourseDirName($_REQUEST['course']);
1074                         } elseif (isset($_REQUEST['p_course'])){
1075                                 // is set when guests access public course. @see bounce.php
1076                                 $course_id = $url_parser->getCourseDirName($_REQUEST['p_course']);
1077                         } elseif (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0){
1078                                 $course_id = $url_parser->getCourseDirName($_SESSION['course_id']);
1079                         } 
1080                 } else {
1081                         $course_id = $_SESSION['course_id'];
1082                 }
1083                 $url = $pathinfo[1]->convertToPrettyUrl($course_id, $url);
1084         } elseif ($_config['course_dir_name'] > 0) {
1085                 //enabled course directory name, disabled pretty url
1086                 if (preg_match('/bounce.php\?course=([\d]+)$/', $url, $matches) == 1){
1087                         // bounce has the highest priority, even if session is set, work on 
1088                         // bounce first.
1089                         $course_id = $url_parser->getCourseDirName($matches[1]);
1090                 } elseif (isset($_REQUEST['course'])){
1091                         $course_id = $url_parser->getCourseDirName($_REQUEST['course']);
1092                 } elseif (isset($_REQUEST['p_course'])){
1093                         // is set when guests access public course. @see bounce.php
1094                         $course_id = $url_parser->getCourseDirName($_REQUEST['p_course']);
1095                 } elseif (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0){
1096                         $course_id = $url_parser->getCourseDirName($_SESSION['course_id']);
1097                 } 
1098                 $url = $pathinfo[1]->convertToPrettyUrl($course_id, $url);
1099         }
1100
1101         //instead of putting AT_BASE_HREF in all the headers location, we will put it here.
1102         //Abs paths are required for pretty url because otherwise the url location will be appeneded.
1103         //ie.   ATutor_161/blogs/CoURSe_rOAd/blogs/view.php/ot/1/oid/1/ instead of 
1104         //              ATutor_161/CoURSe_rOAd/blogs/view.php/ot/1/oid/1/
1105         if ($is_rewriting_header==true){
1106                 return AT_BASE_HREF.$url;
1107         } 
1108         return $url;
1109 }
1110
1111
1112 /**
1113 * Applies $addslashes or intval() recursively.
1114 * @access  public
1115 * @param   mixed $input The input to clean.
1116 * @return  A safe version of $input
1117 * @author  Joel Kronenberg
1118 */
1119 function sql_quote($input) {
1120         global $addslashes;
1121
1122         if (is_array($input)) {
1123                 foreach ($input as $key => $value) {
1124                         if (is_array($input[$key])) {
1125                                 $input[$key] = sql_quote($input[$key]);
1126                         } else if (!empty($input[$key]) && is_numeric($input[$key])) {
1127                                 $input[$key] = intval($input[$key]);
1128                         } else {
1129                                 $input[$key] = $addslashes(trim($input[$key]));
1130                         }
1131                 }
1132         } else {
1133                 if (!empty($input) && is_numeric($input)) {
1134                         $input = intval($input);
1135                 } else {
1136                         $input = $addslashes(trim($input));
1137                 }
1138         }
1139         return $input;
1140 }
1141
1142 function query_bit( $bitfield, $bit ) {
1143         if (!is_int($bitfield)) {
1144                 $bitfield = intval($bitfield);
1145         }
1146         if (!is_int($bit)) {
1147                 $bit = intval($bit);
1148         }
1149         return ( $bitfield & $bit ) ? true : false;
1150
1151
1152 /**
1153 * Authenticates the current user against the specified privilege.
1154 * @access  public
1155 * @param   int  $privilege              privilege to check against.
1156 * @param   bool $check                  whether or not to return the result or to abort/exit.
1157 * @return  bool true if this user is authenticated, false otherwise.
1158 * @see     query_bit() in include/vitals.inc.php
1159 * @author  Joel Kronenberg
1160 */
1161 function authenticate($privilege, $check = false) {
1162         if ($_SESSION['is_admin']) {
1163                 return true;
1164         }
1165
1166         $auth = query_bit($_SESSION['privileges'], $privilege);
1167         
1168         if (!$_SESSION['valid_user'] || !$auth) {
1169                 if (!$check){
1170                         global $msg;
1171                         $msg->addInfo('NO_PERMISSION');
1172                         require(AT_INCLUDE_PATH.'header.inc.php'); 
1173                         require(AT_INCLUDE_PATH.'footer.inc.php'); 
1174                         exit;
1175                 } else {
1176                         return false;
1177                 }
1178         }
1179         return true;
1180 }
1181
1182 function admin_authenticate($privilege = 0, $check = false) {
1183         if (!isset($_SESSION['valid_user']) || !$_SESSION['valid_user'] || ($_SESSION['course_id'] != -1)) {
1184                 if ($check) {
1185                         return false;
1186                 }
1187                 header('Location: '.AT_BASE_HREF.'login.php');
1188                 exit;
1189         }
1190
1191         if ($_SESSION['privileges'] == AT_ADMIN_PRIV_ADMIN) {
1192                 return true;
1193         }
1194
1195         if ($privilege) {
1196                 $auth = query_bit($_SESSION['privileges'], $privilege);
1197
1198                 if (!$auth) {
1199                         if ($check) {
1200                                 return false;
1201                         }
1202                         global $msg;
1203                         $msg->addError('ACCESS_DENIED');
1204                         require(AT_INCLUDE_PATH.'header.inc.php'); 
1205                         require(AT_INCLUDE_PATH.'footer.inc.php'); 
1206                         exit;
1207                 }
1208         }
1209         return true;
1210 }
1211
1212 function get_default_theme() {
1213         global $db;
1214
1215         if (is_mobile_device()) {
1216                 $default_status = 3;
1217         } else {
1218                 $default_status = 2;
1219         }
1220         $sql    = "SELECT dir_name FROM ".TABLE_PREFIX."themes WHERE status=".$default_status;
1221         $result = mysql_query($sql, $db);
1222         $row = mysql_fetch_assoc($result);
1223
1224         return $row;
1225 }
1226
1227 function get_system_default_theme() {
1228         if (is_mobile_device()) {
1229                 return 'mobile';
1230         } else {
1231                 return 'default';
1232         }
1233 }
1234
1235 function is_mobile_theme($theme) {
1236         global $db;
1237
1238         $sql    = "SELECT dir_name FROM ".TABLE_PREFIX."themes WHERE type='".MOBILE_DEVICE."'";
1239         $result = mysql_query($sql, $db);
1240         while ($row = mysql_fetch_assoc($result)) {
1241                 if ($row['dir_name'] == $theme && is_dir(AT_INCLUDE_PATH . '../themes/' . $theme)) return true;
1242         }
1243
1244         return false;
1245 }
1246
1247 if (isset($_GET['expand'])) {
1248         $_SESSION['menu'][intval($_GET['expand'])] = 1;
1249 } else if (isset($_GET['collapse'])) {
1250         unset($_SESSION['menu'][intval($_GET['collapse'])]);
1251 }
1252
1253 /**
1254 * Writes present action to admin log db
1255 * @access  private
1256 * @param   string $operation_type       The type of operation
1257 * @param   string $table_name           The table affected
1258 * @param   string $num_affected         The number of rows in the table affected
1259 * @author  Shozub Qureshi
1260 */
1261 function write_to_log($operation_type, $table_name, $num_affected, $details) {
1262         global $db, $addslashes;
1263
1264         if ($num_affected > 0) {
1265                 $details = $addslashes(stripslashes($details));
1266                 $sql    = "INSERT INTO ".TABLE_PREFIX."admin_log VALUES ('$_SESSION[login]', NULL, $operation_type, '$table_name', $num_affected, '$details')";
1267                 $result = mysql_query($sql, $db);
1268         }
1269 }
1270
1271 function get_group_title($group_id) {
1272         global $db;
1273         $sql = "SELECT title FROM ".TABLE_PREFIX."groups WHERE group_id=$group_id";
1274         $result = mysql_query($sql, $db);
1275         if ($row = mysql_fetch_assoc($result)) {
1276                 return $row['title'];
1277         }
1278         return FALSE;
1279 }
1280
1281 function get_status_name($status_id) {
1282         switch ($status_id) {
1283                 case AT_STATUS_DISABLED:
1284                                 return _AT('disabled');
1285                                 break;
1286                 case AT_STATUS_UNCONFIRMED:
1287                         return _AT('unconfirmed');
1288                         break;
1289                 case AT_STATUS_STUDENT:
1290                         return _AT('student');
1291                         break;
1292                 case AT_STATUS_INSTRUCTOR:
1293                         return _AT('instructor');
1294                         break;
1295         }
1296 }
1297
1298 function profile_image_exists($id) {
1299         $extensions = array('gif', 'jpg', 'png');
1300
1301         foreach ($extensions as $extension) {
1302                 if (file_exists(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension)) {
1303                         return true;
1304                 }
1305         }
1306 }
1307
1308 /**
1309  * print thumbnails or profile pic
1310  * @param       int             image id
1311  * @param       int             1 for thumbnail, 2 for profile
1312  */
1313 function print_profile_img($id, $type=1) {
1314         global $moduleFactory;
1315         $mod = $moduleFactory->getModule('_standard/profile_pictures');
1316         if ($mod->isEnabled() === FALSE) {
1317                 return;
1318         }
1319         if (profile_image_exists($id)) {
1320                 if ($type==1){
1321                         echo '<img src="get_profile_img.php?id='.$id.'" class="profile-picture" alt="" />';
1322                 } elseif($type==2){
1323                         echo '<img src="get_profile_img.php?id='.$id.SEP.'size=p" class="profile-picture" alt="" />';
1324                 }
1325         } else {
1326                 echo '<img src="images/clr.gif" height="100" width="100" class="profile-picture" alt="" />';
1327         }
1328 }
1329
1330 function profile_image_delete($id) {
1331         $extensions = array('gif', 'jpg', 'png');
1332
1333         foreach ($extensions as $extension) {
1334                 if (file_exists(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension)) {
1335                         unlink(AT_CONTENT_DIR.'profile_pictures/originals/'. $id.'.'.$extension);
1336                 }
1337                 if (file_exists(AT_CONTENT_DIR.'profile_pictures/profile/'. $id.'.'.$extension)) {
1338                         unlink(AT_CONTENT_DIR.'profile_pictures/profile/'. $id.'.'.$extension);
1339                 }
1340                 if (file_exists(AT_CONTENT_DIR.'profile_pictures/thumbs/'. $id.'.'.$extension)) {
1341                         unlink(AT_CONTENT_DIR.'profile_pictures/thumbs/'. $id.'.'.$extension);
1342                 }               
1343         }
1344 }
1345
1346 /**
1347  * get_group_concat
1348  * returns a list of $field values from $table using $where_clause, separated by $separator.
1349  * uses mysql's GROUP_CONCAT() if available and if within the limit (default is 1024), otherwise
1350  * it does it the old school way.
1351  * returns the list (as a string) or (int) 0, if none found.
1352  */
1353 function get_group_concat($table, $field, $where_clause = 1, $separator = ',') {
1354         global $_config, $db;
1355         if (!isset($_config['mysql_group_concat_max_len'])) {
1356                 $sql = "SELECT  @@global.group_concat_max_len AS max";
1357                 $result = mysql_query($sql, $db);
1358                 if ($result && ($row = mysql_fetch_assoc($result))) {
1359                         $_config['mysql_group_concat_max_len'] = $row['max'];
1360                 } else {
1361                         $_config['mysql_group_concat_max_len'] = 0;
1362                 }
1363                 $sql = "REPLACE INTO ".TABLE_PREFIX."config VALUES ('mysql_group_concat_max_len', '{$_config['mysql_group_concat_max_len']}')";
1364                 mysql_query($sql, $db);
1365         }
1366         if ($_config['mysql_group_concat_max_len'] > 0) {
1367                 $sql = "SELECT GROUP_CONCAT($field SEPARATOR '$separator') AS list FROM ".TABLE_PREFIX."$table WHERE $where_clause";
1368                 $result = mysql_query($sql, $db);
1369                 if ($row = mysql_fetch_assoc($result)) {
1370                         if (!$row['list']) {
1371                                 return 0; // empty
1372                         } else if ($row['list'] && strlen($row['list']) < $_config['mysql_group_concat_max_len']) {
1373                                 return $row['list'];
1374                         } // else: list is truncated, do it the old way
1375                 } else {
1376                         // doesn't actually get here.
1377                         return 0; // empty
1378                 }
1379         } // else:
1380
1381         $list = '';
1382         $sql = "SELECT $field AS id FROM ".TABLE_PREFIX."$table WHERE $where_clause";
1383         $result = mysql_query($sql, $db);
1384         while ($row = mysql_fetch_assoc($result)) {
1385                 $list .= $row['id'] . ',';
1386         }
1387         if ($list) {
1388                 return substr($list, 0, -1); }
1389         return 0;
1390 }
1391
1392 function get_human_time($seconds) {
1393         if ($seconds < 0) { 
1394                 $out = '0'._AT('second_short'); 
1395         } else if ($seconds > 60 * 60) { // more than 60 minutes.
1396                 $hours = floor($seconds / 60 / 60);
1397                 $minutes = floor(($seconds - $hours * 60 * 60) / 60);
1398                 $out = $hours ._AT('hour_short').' '.$minutes._AT('minute_short');
1399
1400                 //$out = ($seconds
1401         } else if ($seconds > 60) { // more than a minute
1402                 $minutes = floor($seconds / 60);
1403                 $out = $minutes ._AT('minute_short').' '.($seconds - $minutes * 60)._AT('second_short');
1404         } else { // less than a minute
1405                 $out = $seconds . _AT('second_short');
1406         }
1407
1408         return $out;
1409 }
1410
1411 function is_mobile_device() {
1412         $http_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
1413         return ((stripos($http_user_agent, IPOD_DEVICE) !== false && stripos($http_user_agent, IPOD_DEVICE) >= 0) ||
1414                         (stripos($http_user_agent, IPHONE_DEVICE) !== false && stripos($http_user_agent, IPHONE_DEVICE) >= 0) ||
1415                 (stripos($http_user_agent, BLACKBERRY_DEVICE) !== false && stripos($http_user_agent, BLACKBERRY_DEVICE) >= 0) ||
1416                 (stripos($http_user_agent, ANDROID_DEVICE) !== false && stripos($http_user_agent, ANDROID_DEVICE) >= 0)) 
1417                 ? true : false;
1418 }
1419
1420 function get_mobile_device_type() {
1421         $http_user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
1422         if (stripos($http_user_agent, IPOD_DEVICE) !== false && stripos($http_user_agent, IPOD_DEVICE) >= 0) {
1423                 return IPOD_DEVICE;
1424         } else if (stripos($http_user_agent, IPHONE_DEVICE) !== false && stripos($http_user_agent, IPHONE_DEVICE) >= 0) {
1425                 return IPHONE_DEVICE;
1426         } else if (stripos($http_user_agent, BLACKBERRY_DEVICE) !== false && stripos($http_user_agent, BLACKBERRY_DEVICE) >= 0) {
1427                 return BLACKBERRY_DEVICE;
1428         } else if (stripos($http_user_agent, ANDROID_DEVICE) !== false && stripos($http_user_agent, ANDROID_DEVICE) >= 0) {
1429                 return ANDROID_DEVICE;
1430         } else {
1431                 return UNKNOWN_DEVICE;
1432         }
1433 }
1434
1435 /**
1436  * Convert all input to htmlentities output, in UTF-8.
1437  * @param       string  input to be convert
1438  * @param       boolean true if we wish to change all newlines(\r\n) to a <br/> tag, false otherwise.  
1439  *                      ref: http://php.net/manual/en/function.nl2br.php
1440  * @author      Harris Wong
1441  * @date        March 12, 2010
1442  */
1443 function htmlentities_utf8($str, $use_nl2br=true){
1444         $return = htmlentities($str, ENT_QUOTES, 'UTF-8');
1445         if ($use_nl2br){
1446                 return nl2br($return);
1447         } 
1448         return $return;
1449 }
1450
1451 /**
1452  * Convert all '&' to '&amp;' from the input
1453  * @param   string  any string input, mainly URLs.
1454  * @return  input with & replaced to '&amp;'
1455  * @author  Harris Wong
1456  * @date    Oct 7, 2010
1457  */
1458 function convert_amp($input){
1459     $input = str_replace('&amp;', '&', $input); //convert everything to '&' first
1460     return str_replace('&', '&amp;', $input);
1461 }
1462
1463 /**
1464  * Check if json_encode/json_decode exists, if not, use the json service library.
1465  * NOTE:  json_encode(), json_decode() are NOT available piror to php 5.2
1466  * @author      Harris Wong
1467  * @date        April 21, 2010
1468  */
1469  if ( !function_exists('json_encode') ){
1470     function json_encode($content){
1471                 require_once (AT_INCLUDE_PATH.'lib/json.inc.php');
1472                 $json = new Services_JSON;               
1473         return $json->encode($content);
1474     }
1475 }
1476 if ( !function_exists('json_decode') ){
1477     function json_decode($content, $assoc=false){
1478                 require_once (AT_INCLUDE_PATH.'lib/json.inc.php');
1479                 if ( $assoc ){
1480                         $json = new Services_JSON(SERVICES_JSON_LOOSE_TYPE);
1481         } else {
1482                         $json = new Services_JSON;
1483                 }
1484         return $json->decode($content);
1485     }
1486 }
1487
1488 /*
1489  * Finds the image in the theme image folder first. If the image does not exist, look up in 
1490  * core image folder.
1491  * @param: image_name - The relative path and name to the image. 
1492  *             "Relative" means relative to the "image" folder, with subfolders and image name.
1493  *         actual_relative_path - Used when find_image() is called, for example in a class,
1494  *             which is then called by different scripts that give different AT_INCLUDE_PATH. However,
1495  *             the path to the image itself is consistent regardless of the caller script. This value
1496  *             should be the consistent relative path to the image itself.
1497  * @return: The path to the image in the theme folder, if exists. 
1498  *          Otherwise, the path to the image in the core image folder.
1499  * Example: 
1500  *   1. pass in "rtl_tree/tree/collapse.gif"
1501  *   2. return the path to this image in the theme folder: include/../themes/default/images/rtl_tree/tree/collapse.gif
1502  *      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
1503  *      These pathes are relative to ATutor installation directory.
1504  */
1505 function find_image($image_name, $actual_relative_path = AT_INCLUDE_PATH) {
1506         // The returned path is determined by AT_INCLUDE_PATH. If AT_INCLUDE_PATH is undefined, return the parameter itself.
1507         if (!defined('AT_INCLUDE_PATH')) return $image_name;
1508         
1509         // string concanation cannot be used at assigning parameter default value
1510         if ($actual_relative_path == AT_INCLUDE_PATH) $actual_relative_path .= '../';
1511         
1512         // remove leading "/"
1513         if (substr($image_name, 0, 1) == "/") $image_name = substr($image_name, 1);
1514         
1515         $theme_image_folder = 'themes/'.$_SESSION['prefs']['PREF_THEME'].'/images/';
1516         $atutor_image_folder = 'images/';
1517         
1518         // Use the path that is relative to AT_INCLUDE_PATH in the caller script, to check the existence of the image
1519         // but the return path is based on the pass-in actual path parameter.
1520         if (file_exists(AT_INCLUDE_PATH.'../'.$theme_image_folder.$image_name)) {
1521                 return $actual_relative_path.$theme_image_folder.$image_name;
1522         } else {
1523                 return $actual_relative_path.$atutor_image_folder.$image_name;
1524         }
1525 }
1526
1527 require(AT_INCLUDE_PATH . '../mods/_core/modules/classes/Module.class.php');
1528
1529 $moduleFactory = new ModuleFactory(TRUE); // TRUE is for auto_loading the module.php files
1530
1531 if (isset($_GET['submit_language']) && $_SESSION['valid_user']) {
1532         if ($_SESSION['course_id'] == -1) {
1533                 $sql = "UPDATE ".TABLE_PREFIX."admins SET language = '$_SESSION[lang]' WHERE login = '$_SESSION[login]'";
1534                 $result = mysql_query($sql, $db);
1535         } else {
1536                 $sql = "UPDATE ".TABLE_PREFIX."members SET language = '$_SESSION[lang]', creation_date=creation_date, last_login=last_login WHERE member_id = $_SESSION[member_id]";
1537                 $result = mysql_query($sql, $db);
1538         }
1539 }
1540
1541 if (isset($_SESSION['course_id']) && $_SESSION['course_id'] > 0) {
1542     $_custom_head .= '<script type="text/javascript" src="'.$_base_path.'jscripts/ATutorCourse.js"></script>';
1543 }
1544 ?>