Moved scripts in "docs" one level up into root folder. In addition, removed "docs...
[atutor.git] / include / lib / output.inc.php
1 <?php
2 /****************************************************************/
3 /* ATutor                                                                                                               */
4 /****************************************************************/
5 /* Copyright (c) 2002-2009                                                                              */
6 /* Inclusive Design Institute                                   */
7 /* http://atutor.ca                                                                                             */
8 /*                                                              */
9 /* This program is free software. You can redistribute it and/or*/
10 /* modify it under the terms of the GNU General Public License  */
11 /* as published by the Free Software Foundation.                                */
12 /****************************************************************/
13 // $Id: output.inc.php 10550 2010-12-17 17:48:06Z cindy $
14 if (!defined('AT_INCLUDE_PATH')) { exit; }
15 //require_once(AT_INCLUDE_PATH . 'classes/ContentOutputUtils.class.php');
16
17 /**********************************************************************************/
18 /* Output functions found in this file, in order:
19 /*
20 /*      - AT_date(format, timestamp, format_type)
21 /*
22 /*      - _AT([...])
23 /*      - AT_print(input, name, Boolean runtime_html)
24 /*
25 /*      - smile_replace(text)
26 /*      - myCodes(text)
27 /*      - make_clickable(text)
28 /*      - image_replace(text)
29 /*      - format_final_output(text, Boolean nl2br)
30 /*      - highlight (input, var)
31 /*      - format_content(input, Boolean html, glossary)
32 /*      - find_terms(find_text)
33 /*
34 /**********************************************************************************/
35
36
37 /**
38 * Returns a formatted date string - Uses the same options as date(), but requires a % infront of each argument and the
39 * textual values are language dependent (unlike date()).
40 * @access  public
41 * @param   string $format               preferred date format 
42 * @param   string $timestamp    value of timestamp
43 * @param   int $format_type             timestamp format, an AT_DATE constant
44 * @return  string                               formatted date
45 * @see     AT_DATE constants    in include/lib/constants.inc.php
46 * @author  Joel Kronenberg
47 */
48
49 /* 
50         The following options were added as language dependant:
51         %D: A textual representation of a week, three letters Mon through Sun
52         %F: A full textual representation of a month, such as January or March January through December
53         %l (lowercase 'L'): A full textual representation of the day of the week Sunday through Saturday
54         %M: A short textual representation of a month, three letters Jan through Dec
55
56         Support for the following maybe added later:
57         ?? %S: English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
58         ?? %a: Lowercase Ante meridiem and Post meridiem am or pm 
59         ?? %A: Uppercase Ante meridiem and Post meridiem AM or PM 
60
61         valid format_types:
62         AT_DATE_MYSQL_DATETIME:         YYYY-MM-DD HH:MM:SS
63         AT_DATE_MYSQL_TIMESTAMP_14:     YYYYMMDDHHMMSS
64         AT_DATE_UNIX_TIMESTAMP:         seconds since epoch
65         AT_DATE_INDEX_VALUE:            0-x, index into a date array
66 */
67 function AT_date($format='%Y-%M-%d', $timestamp = '', $format_type=AT_DATE_MYSQL_DATETIME) {    
68         static $day_name_ext, $day_name_con, $month_name_ext, $month_name_con;
69         global $_config;
70
71         if (!isset($day_name_ext)) {
72                 $day_name_ext = array(  'date_sunday', 
73                                                                 'date_monday', 
74                                                                 'date_tuesday', 
75                                                                 'date_wednesday', 
76                                                                 'date_thursday', 
77                                                                 'date_friday',
78                                                                 'date_saturday');
79
80                 $day_name_con = array(  'date_sun', 
81                                                                 'date_mon', 
82                                                                 'date_tue', 
83                                                                 'date_wed',
84                                                                 'date_thu', 
85                                                                 'date_fri', 
86                                                                 'date_sat');
87
88                 $month_name_ext = array('date_january', 
89                                                                 'date_february', 
90                                                                 'date_march', 
91                                                                 'date_april', 
92                                                                 'date_may',
93                                                                 'date_june', 
94                                                                 'date_july', 
95                                                                 'date_august', 
96                                                                 'date_september', 
97                                                                 'date_october', 
98                                                                 'date_november',
99                                                                 'date_december');
100
101                 $month_name_con = array('date_jan', 
102                                                                 'date_feb', 
103                                                                 'date_mar', 
104                                                                 'date_apr', 
105                                                                 'date_may_short',
106                                                                 'date_jun', 
107                                                                 'date_jul', 
108                                                                 'date_aug', 
109                                                                 'date_sep', 
110                                                                 'date_oct', 
111                                                                 'date_nov',
112                                                                 'date_dec');
113         }
114
115         if ($format_type == AT_DATE_INDEX_VALUE) {
116                 // apply timezone offset
117 //              $timestamp = apply_timezone($timestamp);
118         
119                 if ($format == '%D') {
120                         return _AT($day_name_con[$timestamp-1]);
121                 } else if ($format == '%l') {
122                         return _AT($day_name_ext[$timestamp-1]);
123                 } else if ($format == '%F') {
124                         return _AT($month_name_ext[$timestamp-1]);
125                 } else if ($format == '%M') {
126                         return _AT($month_name_con[$timestamp-1]);
127                 }
128         }
129
130         if ($timestamp == '') {
131                 $timestamp = time();
132                 $format_type = AT_DATE_UNIX_TIMESTAMP;
133         }
134
135         /* convert the date to a Unix timestamp before we do anything with it */
136         if ($format_type == AT_DATE_MYSQL_DATETIME) {
137                 $year   = substr($timestamp,0,4);
138                 $month  = substr($timestamp,5,2);
139                 $day    = substr($timestamp,8,2);
140                 $hour   = substr($timestamp,11,2);
141                 $min    = substr($timestamp,14,2);
142                 $sec    = substr($timestamp,17,2);
143             $timestamp  = mktime($hour, $min, $sec, $month, $day, $year);
144
145         } else if ($format_type == AT_DATE_MYSQL_TIMESTAMP_14) {
146             $year               = substr($timestamp,0,4);
147             $month              = substr($timestamp,4,2);
148             $day                = substr($timestamp,6,2);
149                 $hour           = substr($timestamp,8,2);
150             $minute             = substr($timestamp,10,2);
151             $second             = substr($timestamp,12,2);
152             $timestamp  = mktime($hour, $minute, $second, $month, $day, $year);  
153         }
154
155         // apply timezone offset
156         $timestamp = apply_timezone($timestamp);
157
158         /* pull out all the %X items from $format */
159         $first_token = strpos($format, '%');
160         if ($first_token === false) {
161                 /* no tokens found */
162                 return $timestamp;
163         } else {
164                 $tokened_format = substr($format, $first_token);
165         }
166         $tokens = explode('%', $tokened_format);
167         array_shift($tokens);
168         $num_tokens = count($tokens);
169
170         $output = $format;
171         for ($i=0; $i<$num_tokens; $i++) {
172                 $tokens[$i] = substr($tokens[$i],0,1);
173
174                 if ($tokens[$i] == 'D') {
175                         $output = str_replace('%D', _AT($day_name_con[date('w', $timestamp)]),$output);
176                 
177                 } else if ($tokens[$i] == 'l') {
178                         $output = str_replace('%l', _AT($day_name_ext[date('w', $timestamp)]),$output);
179                 
180                 } else if ($tokens[$i] == 'F') {
181                         $output = str_replace('%F', _AT($month_name_ext[date('n', $timestamp)-1]),$output);             
182                 
183                 } else if ($tokens[$i] == 'M') {
184                         $output = str_replace('%M', _AT($month_name_con[date('n', $timestamp)-1]),$output);
185
186                 } else {
187
188                         /* this token doesn't need translating */
189                         $value = date($tokens[$i], $timestamp);
190                         if ($value != $tokens[$i]) {
191                                 $output = str_replace('%'.$tokens[$i], $value, $output);
192                         } /* else: this token isn't valid. so don't replace it. Eg. try %q */
193                 }
194         }
195
196         return $output;
197 }
198
199 /**
200 * Converts language code to actual language message, caches them according to page url
201 * @access       public
202 * @param        args                            unlimited number of arguments allowed but first arg MUST be name of the language variable/term
203 *                                                               i.e             $args[0] = the term to the format string $_template[term]
204 *                                                                               $args[1..x] = optional arguments to the formatting string 
205 * @return       string|array            full resulting message
206 * @see          $db                             in include/vitals.inc.php
207 * @see          cache()                         in include/phpCache/phpCache.inc.php
208 * @see          cache_variable()        in include/phpCache/phpCache.inc.php
209 * @author       Joel Kronenberg
210 */
211 function _AT() {
212         global $_cache_template, $lang_et, $_rel_url;
213         static $_template;
214         
215         $args = func_get_args();
216         
217         // a feedback msg
218         if (!is_array($args[0])) {
219                 /**
220                  * Added functionality for translating language code String (AT_ERROR|AT_INFOS|AT_WARNING|AT_FEEDBACK|AT_HELP).*
221                  * to its text and returning the result. No caching needed.
222                  * @author Jacek Materna
223                  */
224
225                 // Check for specific language prefix, extendible as needed
226                 // 0002767:  a substring+in_array test should be faster than a preg_match test.
227                 // replaced the preg_match with a test of the substring.
228                 $sub_arg = substr($args[0], 0, 7); // 7 is the shortest type of msg (AT_HELP)
229                 if (in_array($sub_arg, array('AT_ERRO','AT_INFO','AT_WARN','AT_FEED','AT_HELP','AT_CONF'))) {
230                         global $db;
231                         global $_base_path, $addslashes;
232
233                         $args[0] = $addslashes($args[0]);
234                                         
235                         /* get $_msgs_new from the DB */
236                         $sql    = 'SELECT text FROM '.TABLE_PREFIX.'language_text WHERE term="' . $args[0] . '" AND (variable="_msgs" OR variable="_c_msgs") AND language_code="'.$_SESSION['lang'].'" ORDER BY variable ASC LIMIT 1';
237
238                         $result = @mysql_query($sql, $db);
239                         $i = 1;
240                         $msgs = '';
241                                         
242                         if ($row = @mysql_fetch_assoc($result)) {
243                                 // do not cache key as a digit (no contstant(), use string)
244                                 $msgs = str_replace('SITE_URL/', $_base_path, $row['text']);
245                                 if (defined('AT_DEVEL') && AT_DEVEL) {
246                                         $msgs .= ' <small><small>('. $args[0] .')</small></small>';
247                                 }
248                         }
249
250                         $sql = 'INSERT INTO '.TABLE_PREFIX.'language_pages (`term`, `page`) VALUES ("'.$args[0].'", "'.$_rel_url.'")';
251                         mysql_query($sql, $db);
252
253                         return $msgs;
254                 }
255         }
256         
257         // a template variable
258         if (!isset($_template)) {
259                 $url_parts = parse_url(AT_BASE_HREF);
260                 $name = substr($_SERVER['PHP_SELF'], strlen($url_parts['path'])-1);
261
262                 if ( !($lang_et = cache(120, 'lang', $_SESSION['lang'].'_'.$name)) ) {
263                         global $db;
264
265                         /* get $_template from the DB */
266                         
267                         $sql = "SELECT L.* FROM ".TABLE_PREFIX."language_text L, ".TABLE_PREFIX."language_pages P WHERE L.language_code='{$_SESSION['lang']}' AND L.variable<>'_msgs' AND L.term=P.term AND P.page='$_rel_url' ORDER BY L.variable ASC";
268                         $result = mysql_query($sql, $db);
269                         while ($row = mysql_fetch_assoc($result)) {
270                                 //Do not overwrite the variable that existed in the cache_template already.
271                                 //The edited terms (_c_template) will always be at the top of the resultset
272                                 //0003279
273                                 if (isset($_cache_template[$row['term']])){
274                                         continue;
275                                 }
276
277                                 // saves us from doing an ORDER BY
278                                 if ($row['language_code'] == $_SESSION['lang']) {
279                                         $_cache_template[$row['term']] = stripslashes($row['text']);
280                                 } else if (!isset($_cache_template[$row['term']])) {
281                                         $_cache_template[$row['term']] = stripslashes($row['text']);
282                                 }
283                         }
284                 
285                         cache_variable('_cache_template');
286                         endcache(true, false);
287                 }
288                 $_template = $_cache_template;
289         }
290         $num_args = func_num_args();
291         if (is_array($args[0])) {
292                 $args = $args[0];
293                 $num_args = count($args);
294         }
295         $format   = array_shift($args);
296
297         if (isset($_template[$format])) {
298                 /*
299                 var_dump($_template);
300                 var_dump($format);
301                 var_dump($args);
302                 exit;
303                 */
304                 $outString      = vsprintf($_template[$format], $args);
305                 $str = ob_get_contents();
306         } else {
307                 $outString = '';
308         }
309
310
311         if ($outString === false) {
312                 return ('[Error parsing language. Variable: <code>'.$format.'</code>. Language: <code>'.$_SESSION['lang'].'</code> ]');
313         }
314
315         if (empty($outString)) {
316                 global $db;
317                 $sql    = 'SELECT L.* FROM '.TABLE_PREFIX.'language_text L WHERE L.language_code="'.$_SESSION['lang'].'" AND L.variable<>"_msgs" AND L.term="'.$format.'"';
318
319                 $result = mysql_query($sql, $db);
320                 $row = mysql_fetch_assoc($result);
321
322                 $_template[$row['term']] = stripslashes($row['text']);
323                 $outString = $_template[$row['term']];
324                 if (empty($outString)) {
325                         return ('[ '.$format.' ]');
326                 }
327                 $outString = $_template[$row['term']];
328                 $outString = vsprintf($outString, $args);
329
330                 /* update the locations */
331                 $sql = 'INSERT INTO '.TABLE_PREFIX.'language_pages (`term`, `page`) VALUES ("'.$format.'", "'.$_rel_url.'")';
332                 mysql_query($sql, $db);
333         }
334
335         return $outString;
336 }
337
338 /**********************************************************************************************************/
339         /**
340         *       Transforms text based on formatting preferences.  Original $input is also changed (passed by reference).
341         *       Can be called as:
342         *       1) $output = AT_print($input, $name);
343         *          echo $output;
344         *
345         *       2) echo AT_print($input, $name); // prefered method
346         *
347         * @access       public
348         * @param        string $input                   text being transformed
349         * @param        string $name                    the unique name of this field (convension: table_name.field_name)
350         * @param        boolean $runtime_html   forcefully disables html formatting for $input (only used by fields that 
351         *                                                                       have the 'formatting' option
352         * @return       string                                  transformed $input
353         * @see          AT_FORMAT constants             in include/lib/constants.inc.php
354         * @see          query_bit()                             in include/vitals.inc.php
355         * @author       Joel Kronenberg
356         */
357         function AT_print($input, $name, $runtime_html = true) {
358                 global $_field_formatting, $_config;
359
360                 if (!isset($_field_formatting[$name])) {
361                         /* field not set, check if there's a global setting */
362                         $parts = explode('.', $name);
363                         
364                         /* check if wildcard is set: */
365                         if (isset($_field_formatting[$parts[0].'.*'])) {
366                                 $name = $parts[0].'.*';
367                         } else {
368                                 /* field not set, and there's no global setting */
369                                 /* same as AT_FORMAT_NONE */
370                                 return $input;
371                         }
372                 }
373
374                 if (query_bit($_field_formatting[$name], AT_FORMAT_QUOTES)) {
375                         $input = str_replace('"', '&quot;', $input);
376                 }
377
378                 if (query_bit($_field_formatting[$name], AT_FORMAT_CONTENT_DIR)) {
379                         $input = str_replace('CONTENT_DIR/', '', $input);
380                 }
381
382                 if (query_bit($_field_formatting[$name], AT_FORMAT_HTML) && $runtime_html) {
383                         /* what special things do we have to do if this is HTML ? remove unwanted HTML? validate? */
384                 } else {
385                         $input = str_replace('<', '&lt;', $input);
386                         $input = nl2br($input);
387                 }
388
389                 if (isset($_config['latex_server']) && $_config['latex_server']) {
390                         $input = preg_replace('/\[tex\](.*?)\[\/tex\]/sie', "'<img src=\"'.\$_config['latex_server'].rawurlencode('$1').'\" align=\"middle\" alt=\"'.'$1'.'\" title=\"'.'$1'.'\">'", $input);
391                 }
392
393                 /* this has to be here, only because AT_FORMAT_HTML is the only check that has an else-block */
394                 if ($_field_formatting[$name] === AT_FORMAT_NONE) {
395                         return $input;
396                 }
397
398                 if (query_bit($_field_formatting[$name], AT_FORMAT_EMOTICONS)) {
399                         $input = smile_replace($input);
400                 }
401
402                 if (query_bit($_field_formatting[$name], AT_FORMAT_ATCODES)) {
403                         $input = trim(myCodes(' ' . $input . ' '));
404                 }
405
406                 if (query_bit($_field_formatting[$name], AT_FORMAT_LINKS)) {
407                         $input = trim(make_clickable(' ' . $input . ' '));
408                 }
409
410                 if (query_bit($_field_formatting[$name], AT_FORMAT_IMAGES)) {
411                         $input = trim(image_replace(' ' . $input . ' '));
412                 }
413
414         
415                 return $input;
416         }
417
418 /********************************************************************************************/
419 // Global variables for emoticons
420  
421 global $smile_pics;
422 global $smile_codes;
423 if (!isset($smile_pics)) {
424         $smile_pics[0] = $_base_path.'images/forum/smile.gif';
425         $smile_pics[1] = $_base_path.'images/forum/wink.gif';
426         $smile_pics[2] = $_base_path.'images/forum/frown.gif';
427         $smile_pics[3] = $_base_path.'images/forum/ohwell.gif';
428         $smile_pics[4] = $_base_path.'images/forum/tongue.gif';
429         $smile_pics[5] = $_base_path.'images/forum/51.gif';
430         $smile_pics[6] = $_base_path.'images/forum/52.gif';
431         $smile_pics[7] = $_base_path.'images/forum/54.gif';
432         $smile_pics[8] = $_base_path.'images/forum/27.gif';
433         $smile_pics[9] = $_base_path.'images/forum/19.gif';
434         $smile_pics[10] = $_base_path.'images/forum/3.gif';
435         $smile_pics[11] = $_base_path.'images/forum/56.gif';
436 }
437
438 if (!isset($smile_codes)) {
439         $smile_codes[0] = ':)';
440         $smile_codes[1] = ';)';
441         $smile_codes[2] = ':(';
442         $smile_codes[3] = '::ohwell::';
443         $smile_codes[4] = ':P';
444         $smile_codes[5] = '::evil::';
445         $smile_codes[6] = '::angry::';
446         $smile_codes[7] = '::lol::';
447         $smile_codes[8] = '::crazy::';
448         $smile_codes[9] = '::tired::';
449         $smile_codes[10] = '::confused::';
450         $smile_codes[11] = '::muah::';
451 }
452
453 /**
454 * Replaces smile-code text into smilie image.
455 * @access       public
456 * @param        string $text            smile text to be transformed
457 * @return       string                          transformed $text
458 * @see          $smile_pics                     in include/lib/output.inc.php (above)
459 * @see          $smile_codes            in include/lib/output.inc.php (above)
460 * @author       Joel Kronenberg
461 */
462 function smile_replace($text) {
463         global $smile_pics;
464         global $smile_codes;
465         static $smiles;
466
467         $smiles[0] = '<img src="'.$smile_pics[0].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_smile').'" />';
468         $smiles[1] = '<img src="'.$smile_pics[1].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_wink').'" />';
469         $smiles[2] = '<img src="'.$smile_pics[2].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_frown').'" />';
470         $smiles[3]= '<img src="'.$smile_pics[3].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_oh_well').'" />';
471         $smiles[4]= '<img src="'.$smile_pics[4].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tongue').'" />';
472         $smiles[5]= '<img src="'.$smile_pics[5].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_evil').'" />';
473         $smiles[6]= '<img src="'.$smile_pics[6].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_angry').'" />';
474         $smiles[7]= '<img src="'.$smile_pics[7].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_lol').'" />';
475         $smiles[8]= '<img src="'.$smile_pics[8].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_crazy').'" />';
476         $smiles[9]= '<img src="'.$smile_pics[9].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tired').'" />';
477         $smiles[10]= '<img src="'.$smile_pics[10].'" border="0" height="17" width="19" align="bottom" alt="'._AT('smile_confused').'" />';
478         $smiles[11]= '<img src="'.$smile_pics[11].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_muah').'" />';
479
480         $text = str_replace($smile_codes[0],$smiles[0],$text);
481         $text = str_replace($smile_codes[1],$smiles[1],$text);
482         $text = str_replace($smile_codes[2],$smiles[2],$text);
483         $text = str_replace($smile_codes[3],$smiles[3],$text);
484         $text = str_replace($smile_codes[4],$smiles[4],$text);
485         $text = str_replace($smile_codes[5],$smiles[5],$text);
486         $text = str_replace($smile_codes[6],$smiles[6],$text);
487         $text = str_replace($smile_codes[7],$smiles[7],$text);
488         $text = str_replace($smile_codes[8],$smiles[8],$text);
489         $text = str_replace($smile_codes[9],$smiles[9],$text);
490         $text = str_replace($smile_codes[10],$smiles[10],$text);
491         $text = str_replace($smile_codes[11],$smiles[11],$text);
492
493         return $text;
494 }
495
496
497 /* Used specifically for the visual editor
498 */
499 function smile_javascript () {
500         global $_base_path;
501         global $smile_pics;
502         global $smile_codes;
503
504         static $i = 0;
505
506         while ($smile_pics [$i]) {
507                 echo 'case "'.$smile_codes[$i].'":'."\n";
508                 echo 'pic = "'.$smile_pics[$i].'";'."\n";
509                 echo 'break;'."\n";
510                 $i++;
511         }
512 }
513     
514 function myCodes($text, $html = false) {
515         global $_base_path;
516         global $HTTP_USER_AGENT;
517
518         if (substr($HTTP_USER_AGENT,0,11) == 'Mozilla/4.7') {
519                 $text = str_replace('[quote]','</p><p class="block">',$text);
520                 $text = str_replace('[/quote]','</p><p>',$text);
521
522                 $text = str_replace('[reply]','</p><p class="block">',$text);
523                 $text = str_replace('[/reply]','</p><p>',$text);
524         } else {
525                 $text = str_replace('[quote]','<blockquote>',$text);
526                 $text = str_replace('[/quote]','</blockquote><p>',$text);
527
528                 $text = str_replace('[reply]','</p><blockquote class="block"><p>',$text);
529                 $text = str_replace('[/reply]','</p></blockquote><p>',$text);
530         }
531
532         $text = str_replace('[b]','<strong>',$text);
533         $text = str_replace('[/b]','</strong>',$text);
534
535         $text = str_replace('[i]','<em>',$text);
536         $text = str_replace('[/i]','</em>',$text);
537
538         $text = str_replace('[u]','<u>',$text);
539         $text = str_replace('[/u]','</u>',$text);
540
541         $text = str_replace('[center]','<center>',$text);
542         $text = str_replace('[/center]','</center><p>',$text);
543
544         /* colours */
545         $text = str_replace('[blue]','<span style="color: blue;">',$text);
546         $text = str_replace('[/blue]','</span>',$text);
547
548         $text = str_replace('[orange]','<span style="color: orange;">',$text);
549         $text = str_replace('[/orange]','</span>',$text);
550
551         $text = str_replace('[red]','<span style="color: red;">',$text);
552         $text = str_replace('[/red]','</span>',$text);
553
554         $text = str_replace('[purple]','<span style="color: purple;">',$text);
555         $text = str_replace('[/purple]','</span>',$text);
556
557         $text = str_replace('[green]','<span style="color: green;">',$text);
558         $text = str_replace('[/green]','</span>',$text);
559
560         $text = str_replace('[gray]','<span style="color: gray;">',$text);
561         $text = str_replace('[/gray]','</span>',$text);
562
563         $text = str_replace('[op]','<span class="bigspacer"></span> <a href="',$text);
564         $text = str_replace('[/op]','">'._AT('view_entire_post').'</a>',$text);
565
566         $text = str_replace('[head1]','<h2>',$text);
567         $text = str_replace('[/head1]','</h2>',$text);
568
569         $text = str_replace('[head2]','<h3>',$text);
570         $text = str_replace('[/head2]','</h3>',$text);
571
572         $text = str_replace('[cid]',$_base_path.'content.php?cid='.$_SESSION['s_cid'],$text);
573
574         // fix for http://www.atutor.ca/atutor/mantis/view.php?id=4104
575         global $sequence_links;
576         if ($_SESSION['course_id'] > 0 && !isset($sequence_links) && $_REQUEST['cid'] > 0) {
577                 global $contentManager;
578                 $sequence_links = $contentManager->generateSequenceCrumbs($_REQUEST['cid']);
579         }
580         if (isset($sequence_links['previous']) && $sequence_links['previous']['url']) {
581                 $text = str_replace('[pid]', $sequence_links['previous']['url'], $text);
582         }
583         if (isset($sequence_links['next']) && $sequence_links['next']['url']) {
584                 $text = str_replace('[nid]', $sequence_links['next']['url'], $text);
585         }
586         if (isset($sequence_links['resume']) && $sequence_links['resume']['url']) {
587                 $text = str_replace('[nid]', $sequence_links['resume']['url'], $text);
588         }
589         if (isset($sequence_links['first']) && $sequence_links['first']['url']) {
590                 $text = str_replace('[fid]', $sequence_links['first']['url'], $text);
591         }
592
593 //LAW - replace </p><p> tags in [code] tags with <br />
594 //http://www.atutor.ca/atutor/mantis/view.php?id=4134 - attempt to fix this bug - does not work as required
595 //      $outputUtils = new ContentOutputUtils();
596 //      $text = $outputUtils ->stripPtags($text);
597         
598         /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
599     $html = !$html ? 0 : 1;
600     
601         // little hack added by greg to add syntax highlighting without using <?php \?\>
602         
603         $text = str_replace("[code]","[code]<?php",$text);
604         $text = str_replace("[/code]","?>[/code]",$text);
605
606         $text = preg_replace("/\[code\]\s*(.*)\s*\[\\/code\]/Usei", "highlight_code(fix_quotes('\\1'), $html)", $text);
607         // now remove the <?php added above and leave the syntax colour behind.
608         $text = str_replace("&lt;?php", "", $text);
609         $text = str_replace("?&gt;", "", $text);
610
611         return $text;
612 }
613
614 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
615 function highlight_code($code, $html) {
616         // XHTMLize PHP highlight_string output until it gets fixed in PHP
617         static $search = array(
618                 '<br>',
619                 '<font',
620                 '</font>',
621                 'color="');
622
623         static $replace = array(
624                 '<br />',
625                 '<span',
626                 '</span>',
627                 'style="color:');
628         if (!$html) {
629                 $code = str_replace('&lt;', '<', $code);
630                 $code = str_replace("\r", '', $code);
631         }
632
633         return str_replace($search, $replace, highlight_string($code, true));
634 }
635
636 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
637 function fix_quotes($text){
638         return str_replace('\\"', '"', $text);
639 }
640
641 /*
642  * This function converts the youtube playable url used in <object> tag (for instance: http://www.youtube.com/v/a0ryB0m0MiM)
643  * to youtube url that is used to browse (for instance: http://www.youtube.com/watch?v=a0ryB0m0MiM)
644  * @param: youtube playable URL. For instance, http://www.youtube.com/v/a0ryB0m0MiM
645  * @return: if the param is a youtube playable url, return the according youtube URL used to browse. 
646  *          For instance: http://www.youtube.com/watch?v=a0ryB0m0MiM
647  *          Otherwise, return the original send-in parameter.
648  */
649 function convert_youtube_playURL_to_watchURL($youtube_playURL) {
650         return preg_replace("/(http:\/\/[a-z0-9\.]*)?youtube.com\/v\/(.*)/",
651                             "\\1youtube.com/watch?v=\\2", $youtube_playURL);
652 }
653
654 /*
655  * This function converts the youtube url that is used to browse (for instance: http://www.youtube.com/watch?v=a0ryB0m0MiM)
656  * to youtube playable url used in <object> tag (for instance: http://www.youtube.com/v/a0ryB0m0MiM)
657  * @param: the youtube URL used to browse. 
658  *         For instance: http://www.youtube.com/watch?v=a0ryB0m0MiM
659  * @return: if the param is a youtube url used to browse, return the according youtube playable URL. 
660  *          For instance, http://www.youtube.com/v/a0ryB0m0MiM
661  *          Otherwise, return the original send-in parameter.
662  */
663 function convert_youtube_watchURL_to_playURL($youtube_watchURL) {
664         return preg_replace("/(http:\/\/[a-z0-9\.]*)?youtube.com\/watch\?v=(.*)/",
665                             "\\1youtube.com/v/\\2", $youtube_watchURL);
666 }
667
668 function embed_media($text) {
669         global $_base_path;
670         
671         if (preg_match("/\[media(\|[0-9]+\|[0-9]+)?\]*/", $text)==0){
672                 return $text;
673         }
674
675         // 1. remove the spaces in [media] tag, otherwise, the next line converts URL inside [media] into <a> tag
676         $text = preg_replace("/(\[media\])([\s]*)(.*)(\[\/media\])/", '$1$3$4', $text);
677         $text = preg_replace("/(\[media\])(.*)([\s]*)(\[\/media\])/U", '$1$2$4', $text);
678         
679         $media_matches = array();
680         $media_replace = array();
681         
682         // First, we search though the text for all different kinds of media defined by media tags and store the results in $media_matches.
683         // Then the different replacements for the different media tags are stored in $media_replace.
684         // Lastly, we loop through all $media_matches / $media_replaces. (We choose $media_replace as index because $media_matches is multi-dimensioned.) It is important that for each $media_matches there is a $media_replace with the same index. For each media match we check the width/height, or we use the default value of 425x350. We then replace the height/width/media1/media2 parameter placeholders in $media_replace with the correct ones, before running a str_replace on $text, replacing the given media with its correct replacement.
685
686         // youtube videos
687         if (is_mobile_device() && get_mobile_device_type() == BLACKBERRY_DEVICE) {
688                 preg_match_all("#\[media[0-9a-z\|]*\]http://([a-z0-9\.]*)?youtube.com/watch\?v=(.*)\[/media\]#iU",$text,$media_matches[],PREG_SET_ORDER);
689                 $media_replace[] = '<script type="text/javascript" src="'.$_base_path.'jscripts/ATutorYouTubeOnBlackberry.js"></script>'."\n".
690                         '<p id="blackberry_##MEDIA2##">'."\n".
691                         '<script'."\n".
692                         '  src="http://gdata.youtube.com/feeds/mobile/videos/##MEDIA2##?alt=json-in-script&amp;callback=ATutor.course.showYouTubeOnBlackberry&amp;format=6" [^]'."\n".
693                         '  type="text/javascript">'."\n".
694                         '</script>';
695         } else {
696                 preg_match_all("#\[media[0-9a-z\|]*\]http://([a-z0-9\.]*)?youtube.com/watch\?v=(.*)\[/media\]#iU",$text,$media_matches[],PREG_SET_ORDER);
697                 $media_replace[] = '<object width="##WIDTH##" height="##HEIGHT##"><param name="movie" value="http://##MEDIA1##youtube.com/v/##MEDIA2##"></param><embed src="http://##MEDIA1##youtube.com/v/##MEDIA2##" type="application/x-shockwave-flash" width="##WIDTH##" height="##HEIGHT##"></embed></object>';
698         }
699         
700         // .mpg
701         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mpg\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
702         $media_replace[] = "<object data=\"##MEDIA1##.mpg\" type=\"video/mpeg\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mpg\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.mpg\">##MEDIA1##.mpg</a></object>";
703         
704         // .avi
705         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).avi\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
706         $media_replace[] = "<object data=\"##MEDIA1##.avi\" type=\"video/x-msvideo\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.avi\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.avi\">##MEDIA1##.avi</a></object>";
707         
708         // .wmv
709         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).wmv\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
710         $media_replace[] = "<object data=\"##MEDIA1##.wmv\" type=\"video/x-ms-wmv\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.wmv\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.wmv\">##MEDIA1##.wmv</a></object>";
711         
712         // .mov
713         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mov\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
714         $media_replace[] = "<object classid=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\" codebase=\"http://www.apple.com/qtactivex/qtplugin.cab\" width=\"##WIDTH##\" height=\"##HEIGHT##\">\n".
715                            "  <param name=\"src\" value=\"##MEDIA1##.mov\">\n".
716                            "  <param name=\"controller\" value=\"true\">\n".
717                            "  <param name=\"autoplay\" value=\"false\">\n".
718                            "  <!--[if gte IE 7] > <!-->\n".
719                            "  <object type=\"video/quicktime\" data=\"##MEDIA1##.mov\" width=\"##WIDTH##\" height=\"##HEIGHT##\">\n".
720                            "    <param name=\"controller\" value=\"true\">\n".
721                            "    <param name=\"autoplay\" value=\"false\">\n".
722                            "    <a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a>\n".
723                            "  </object>\n".
724                            "  <!--<![endif]-->\n".
725                            "  <!--[if lt IE 7]>\n".
726                            "  <a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a>\n".
727                            "  <![endif]-->\n".
728                            "</object>";
729         
730         // .swf
731         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).swf\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
732         $media_replace[] = "<object type=\"application/x-shockwave-flash\" data=\"##MEDIA1##.swf\" width=\"##WIDTH##\" height=\"##HEIGHT##\">  <param name=\"movie\" value=\"##MEDIA1##.swf\"><param name=\"loop\" value=\"false\"><a href=\"##MEDIA1##.swf\">##MEDIA1##.swf</a></object>";
733
734         // .mp3
735         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mp3\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
736         $media_replace[] = "<object type=\"audio/mpeg\" data=\"##MEDIA1##.mp3\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mp3\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.mp3\">##MEDIA1##.mp3</a></object>";
737         
738         // .wav
739         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).wav\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
740         $media_replace[] ="<object type=\"audio/x-wav\" data=\"##MEDIA1##.wav\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.wav\"><param name=\"autoplay\" value=\"false\"><param name=\"autoStart\" value=\"0\"><a href=\"##MEDIA1##.wav\">##MEDIA1##.wav</a></object>";
741         
742         // .ogg
743         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).ogg\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
744         $media_replace[] ="<object type=\"application/ogg\" data=\"##MEDIA1##.ogg\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.ogg\"><a href=\"##MEDIA1##.ogg\">##MEDIA1##.ogg</a></object>";
745         
746         // .ogm
747         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).ogm\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
748         $media_replace[] ="<object type=\"application/ogm\" data=\"##MEDIA1##.ogm\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.ogm\"><a href=\"##MEDIA1##.ogg\">##MEDIA1##.ogm</a></object>";
749         
750         // .mid
751         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mid\[/media\]#i",$text,$media_matches[],PREG_SET_ORDER);
752         $media_replace[] ="<object type=\"application/x-midi\" data=\"##MEDIA1##.mid\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mid\"><a href=\"##MEDIA1##.mid\">##MEDIA1##.mid</a></object>";
753         
754         $text = preg_replace("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mid\[/media\]#i", "<object type=\"application/x-midi\" data=\"\\1.mid\" width=\"".$width."\" height=\"".$height."\"><param name=\"src\" value=\"\\1.mid\"><a href=\"\\1.mid\">\\1.mid</a></object>", $text);
755
756         // Executing the replace
757         for ($i=0;$i<count($media_replace);$i++){
758                 foreach($media_matches[$i] as $media)
759                 {
760                         //debug($media);
761                         //find width and height for each matched media
762                         if (preg_match("/\[media\|([0-9]*)\|([0-9]*)\]*/", $media[0], $matches)) 
763                         {
764                                 $width = $matches[1];
765                                 $height = $matches[2];
766                         }
767                         else
768                         {
769                                 $width = 425;
770                                 $height = 350;
771                         }
772                         
773                         //replace media tags with embedded media for each media tag
774                         $media_input = $media_replace[$i];
775                         $media_input = str_replace("##WIDTH##","$width",$media_input);
776                         $media_input = str_replace("##HEIGHT##","$height",$media_input);
777                         $media_input = str_replace("##MEDIA1##","$media[1]",$media_input);
778                         $media_input = str_replace("##MEDIA2##","$media[2]",$media_input);
779                         
780                         $text = str_replace($media[0],$media_input,$text);
781                 }
782         }
783         return $text;
784
785 }
786
787 function make_clickable($text) {
788         $text = embed_media($text);
789
790 //      $text = eregi_replace("([[:space:]])(http[s]?)://([^[:space:]<]*)([[:alnum:]#?/&=])", "\\1<a href=\"\\2://\\3\\4\">\\3\\4</a>", $text);
791 //
792 //      $text = eregi_replace(  '([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.
793 //                                                      '\@'.'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+)',
794 //                                                      "<a href=\"mailto:\\1\">\\1</a>",
795 //                                                      $text);
796
797         // convert plain text URL to clickable URL.
798         // Limited conversion: It doesn't cover the case when the stuff in front of the URL is not a word. For example:
799         // <p>http://google.ca</p>
800         // "http://google.ca" 
801         $text = preg_replace('/(^|[\n ])([\w]*?)((?<!(\[media\]))http(s)?:\/\/[\w]+[^ \,\"\n\r\t\)<]*)/is', 
802                              '$1$2<a href="$3">$3</a>', $text);
803         
804         // convert email address to clickable URL that pops up "send email" interface with the address filled in
805         $text = preg_replace('/(?|<a href="mailto[\s]*:[\s]*([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'\@'
806                             .'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+)">(.*)<\/a>'
807                             .'|((((([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'\@'
808                             .'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+))))))/i',
809                                                 "<a href=\"mailto:\\1\">\\5</a>",
810                                                 $text);
811         return $text;
812 }
813
814 function image_replace($text) {
815         /* image urls do not require http:// */
816         
817 //      $text = eregi_replace("\[image(\|)?([[:alnum:][:space:]]*)\]" .
818 //                                               "[:space:]*" .
819 //                                               "([[:alnum:]#?/&=:\"'_.-]+)" .
820 //                                               "[:space:]*" .
821 //                                               "((\[/image\])|(.*\[/image\]))",
822 //                                "<img src=\"\\3\" alt=\"\\2\" />",
823 //                                $text);
824          
825         $text = preg_replace("/\[image(\|)?([a-zA-Z0-9\s]*)\]".
826                              "[\s]*".
827                              "([a-zA-Z0-9\#\?\/\&\=\:\\\"\'\_\.\-]+)[\s]*".
828                              "((\[\/image\])|(.*\[\/image\]))/i",
829                                   "<img src=\"\\3\" alt=\"\\2\" />",
830                                   $text);
831                                   
832         return $text;
833 }
834
835 function format_final_output($text, $nl2br = true) {
836         global $_base_path;
837
838         $text = str_replace('CONTENT_DIR/', '', $text);
839         if ($nl2br) {
840                 return nl2br(image_replace(make_clickable(myCodes(' '.$text, false))));
841         }
842
843         return image_replace(make_clickable(myCodes(' '.$text, true)));
844 }
845
846 // 
847 function apply_customized_format($input) {
848         global $_input, $moduleFactory, $content_base_href, $_content_base_href;
849         
850         $_input = $input;
851         $_content_base_href = $content_base_href;
852         
853         $enabled_modules = $moduleFactory->getModules(AT_MODULE_STATUS_ENABLED);
854
855         if (is_array($enabled_modules))
856         {
857                 foreach ($enabled_modules as $dir_name => $mod)
858                 {
859                         $module_content_format_file = AT_INCLUDE_PATH . '../mods/'.$dir_name.'/module_format_content.php';
860                         if (file_exists($module_content_format_file))
861                         {
862                                 include($module_content_format_file);
863                         }
864                 }
865         }
866         
867         return $_input;
868 }
869 /****************************************************************************************/
870 /* @See: ./user/search.php & ./index.php */
871 function highlight($input, $var) {//$input is the string, $var is the text to be highlighted
872         if ($var != "") {
873                 $xtemp = "";
874                 $i=0;
875                 /*
876                         The following 'if' statement is a check to ensure that the search term is not part of the tag, '<strong class="highlight">'.  Words within this string are avoided in case a previously highlighted string is used for the haystack, $input.  To avoid any html breaks in the highlighted string, the search word is avoided completely.
877                 */
878                 if (strpos('<strong class="highlight">', $var) !== false) {
879                         return $input;
880                 }
881                 while($i<strlen($input)){
882                         if((($i + strlen($var)) <= strlen($input)) && (strcasecmp($var, substr($input, $i, strlen($var))) == 0)) {
883                                 $xtemp .= '<strong class="highlight">' . substr($input, $i , strlen($var)) . '</strong>';
884                                 $i += strlen($var);
885                         }
886                         else {
887                                 $xtemp .= $input{$i};
888                                 $i++;
889                         }
890                 }
891                 $input = $xtemp;
892         }
893         return $input;
894 }
895
896
897 /* @See: ./index.php */
898 function format_content($input, $html = 0, $glossary, $simple = false) {
899         global $_base_path, $_config;
900
901         if (!$html) {
902                 $input = str_replace('<', '&lt;', $input);
903                 $input = str_replace('&lt;?php', '<?php', $input); // for bug #2087
904         } elseif ($html==2) {
905                 $output = '<iframe width="100%" frameborder="0" id="content_frame" marginheight="0" marginwidth="0" src="'.$input.'"></iframe>';
906                 $output .=      '<script type="text/javascript">
907                                         function resizeIframe() {
908                                                 var height = document.documentElement.clientHeight;
909                                                 
910                                                 // not sure how to get this dynamically
911                                                 height -= 20; /* whatever you set your body bottom margin/padding to be */
912                                                 
913                                                 document.getElementById(\'content_frame\').style.height = height +"px";
914                                                 
915                                         };
916                                         document.getElementById(\'content_frame\').onload = resizeIframe;
917                                         window.onresize = resizeIframe;
918                                         </script>';
919                 return $output;
920         }
921
922         /* do the glossary search and replace: */
923         if (is_array($glossary)) {
924                 foreach ($glossary as $k => $v) {
925                         $k = urldecode($k);
926                         $v = str_replace("\n", '<br />', $v);
927                         $v = str_replace("\r", '', $v);
928
929                         /* escape special characters */
930                         $k = preg_quote($k);
931
932                         $k = str_replace('&lt;', '<', $k);
933                         $k = str_replace('/', '\/', $k);
934
935                         $original_term = $k;
936                         $term = $original_term;
937
938                         $term = '(\s*'.$term.'\s*)';
939                         $term = str_replace(' ','((<br \/>)*\s*)', $term); 
940
941                         $def = htmlspecialchars($v, ENT_QUOTES, 'UTF-8');               
942                         if ($simple) {
943                                 $input = preg_replace
944                                                 ("/(\[\?\])$term(\[\/\?\])/i",
945                                                 '<a href="'.$simple.'glossary.html#'.urlencode($original_term).'" target="body" class="at-term">\\2</a>',
946                                                 $input);
947                         } else {/*
948                                 $input = preg_replace
949                                                 ("/(\[\?\])$term(\[\/\?\])/i",
950                                                 '\\2<sup><a class="tooltip" href="'.$_base_path.'mods/_core/glossary/index.php?g_cid='.$_SESSION['s_cid'].htmlentities(SEP).'w='.urlencode($original_term).'#term" title="'.addslashes($original_term).': '.$def.'">?</a></sup>',$input);*/
951
952                                 $input = preg_replace
953                                                 ("/(\[\?\])$term(\[\/\?\])/i",
954                                                 '<a class="tooltip" href="'.$_base_path.'mods/_core/glossary/index.php?g_cid='.$_SESSION['s_cid'].htmlentities(SEP).'w='.urlencode($original_term).'#term" title="'.addslashes($original_term).': '.$def.'">\\2</a>',$input);
955                         }
956                 }
957         } else if (!$user_glossary) {
958                 $input = str_replace(array('[?]','[/?]'), '', $input);
959         }
960         
961         $input = str_replace('CONTENT_DIR', '', $input);
962
963         if (isset($_config['latex_server']) && $_config['latex_server']) {
964                 $input = preg_replace('/\[tex\](.*?)\[\/tex\]/sie', "'<img src=\"'.\$_config['latex_server'].rawurlencode('$1').'\" align=\"middle\" alt=\"'.'$1'.'\" title=\"'.'$1'.'\">'", $input);
965         }
966
967         if ($html) {
968                 $x = apply_customized_format(format_final_output($input, false));
969                 return $x;
970         }
971
972 // the following has been taken out for this: 
973 // http://atutor.ca/atutor/mantis/view.php?id=4593
974 // @date Oct 18, 2010
975 //      $output = apply_customized_format(format_final_output($input));
976     $output = $input;
977
978         $output = '<p>'.$output.'</p>';
979         return $output;
980 }
981
982 function get_content_table($content)
983 {
984         preg_match_all("/<(h[\d]+)[^>]*>(.*)<\/(\s*)\\1(\s*)>/i", $content, $found_headers, PREG_SET_ORDER);
985         
986         if (count($found_headers) == 0) return array("", $content);
987         else
988         {
989                 $num_of_headers = 0;
990
991                 for ($i = 0; $i < count($found_headers); $i++)
992                 {
993                         $div_id = "_header_" . $num_of_headers++;
994                         
995                         if ($i == 0)
996                         {
997                                 $content_table = "<div id=\"toc\">\n<fieldset class=\"toc\"><legend>". _AT("table_of_contents")."</legend>\n";
998                         }
999
1000                         $content = str_replace($found_headers[$i][0], '<div id="'.$div_id.'">'.$found_headers[$i][0].'</div>', $content);
1001                         $content_table .= '<a href="'.$_SERVER["REQUEST_URI"].'#'.$div_id.'" class="'.$found_headers[$i][1].'">'. $found_headers[$i][2]."</a>\n";
1002
1003                         if ($i == count($found_headers) - 1)
1004                         {
1005                                 $content_table .= "</fieldset></div><br />";
1006                         }
1007                 }
1008                 return array($content_table, $content);
1009         }
1010 }
1011
1012 function find_terms($find_text) {
1013         preg_match_all("/(\[\?\])(.[^\?]*)(\[\/\?\])/i", $find_text, $found_terms, PREG_PATTERN_ORDER);
1014         return $found_terms;
1015 }
1016
1017 /***********************************************************************
1018         @See /include/Classes/Message/Message.class.php
1019         Jacek Materna
1020 */
1021
1022 /**
1023 * Take a code as input and grab its language specific message. Also cache the resulting 
1024 * message. Return the message. Same as get_message but key value in cache is string
1025 * @access  public
1026 * @param   string $codes        Message Code to translate - > 'term' field in DB
1027 * @return  string                       The translated language specific message for code $code
1028 * @author  Jacek Materna
1029 */
1030 function getTranslatedCodeStr($codes) {
1031         
1032         /* this is where we want to get the msgs from the database inside a static variable */
1033         global $_cache_msgs_new;
1034         static $_msgs_new;
1035
1036         if (!isset($_msgs_new)) {
1037                 if ( !($lang_et = cache(120, 'msgs_new', $_SESSION['lang'])) ) {
1038                         global $db, $_base_path;
1039
1040                         $parent = Language::getParentCode($_SESSION['lang']);
1041
1042                         /* get $_msgs_new from the DB */
1043                         $sql    = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs" AND (language_code="'.$_SESSION['lang'].'" OR language_code="'.$parent.'")';
1044                         $result = @mysql_query($sql, $db);
1045                         $i = 1;
1046                         while ($row = @mysql_fetch_assoc($result)) {
1047                                 // do not cache key as a digit (no contstant(), use string)
1048                                 $_cache_msgs_new[$row['term']] = str_replace('SITE_URL/', $_base_path, $row['text']);
1049                                 if (AT_DEVEL) {
1050                                         $_cache_msgs_new[$row['term']] .= ' <small><small>('.$row['term'].')</small></small>';
1051                                 }
1052                         }
1053
1054                         cache_variable('_cache_msgs_new');
1055                         endcache(true, false);
1056                 }
1057                 $_msgs_new = $_cache_msgs_new;
1058         }
1059
1060         if (is_array($codes)) {
1061                 /* this is an array with terms to replace */            
1062                 $code           = array_shift($codes);
1063
1064                 $message        = $_msgs_new[$code];
1065                 $terms          = $codes;
1066
1067                 /* replace the tokens with the terms */
1068                 $message        = vsprintf($message, $terms);
1069
1070         } else {
1071                 $message = $_msgs_new[$codes];
1072
1073                 if ($message == '') {
1074                         /* the language for this msg is missing: */
1075                 
1076                         $sql    = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs"';
1077                         $result = @mysql_query($sql, $db);
1078                         $i = 1;
1079                         while ($row = @mysql_fetch_assoc($result)) {
1080                                 if (($row['term']) === $codes) {
1081                                         $message = '['.$row['term'].']';
1082                                         break;
1083                                 }
1084                         }
1085                 }
1086                 $code = $codes;
1087         }
1088         return $message;
1089 }
1090
1091 function html_get_list($array) {
1092         $list = '';
1093         foreach ($array as $value) {
1094                 $list .= '<li>'.$value.'</li>';
1095         }
1096         return $list;
1097 }
1098
1099 /**
1100  * print_paginator
1101  *
1102  * print out list of page links
1103  */
1104 function print_paginator($current_page, $num_rows, $request_args, $rows_per_page = 50, $window = 5) {
1105         $num_pages = ceil($num_rows / $rows_per_page);
1106         $request_args = '?'.$request_args;
1107
1108     if ($num_rows) {
1109                 echo '<div class="paging">';
1110             echo '<ul>';
1111                 
1112                 $i=max($current_page-$window - max($window-$num_pages+$current_page,0), 1);
1113
1114                 if ($i > 1) {
1115                         echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p=1" title="'._AT('page').' 1">1</a></li>';
1116                         if ($i > 2) {
1117                         echo '<li>&hellip;</li>';
1118                         }
1119                 }
1120
1121                 for ($i; $i<= min($current_page+$window -min($current_page-$window,0),$num_pages); $i++) {
1122                         if ($current_page == $i) {
1123                                 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'" class="current" title="'._AT('page').' '. $current_page.'"><em>'.$current_page.'</em></a></li>';
1124                         } else {
1125                                 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'" title="'._AT('page').' '. $i.'">'.$i.'</a></li>';
1126                         }
1127                 }
1128         if ($i <= $num_pages) {
1129                         if ($i < $num_pages) {
1130                         echo '<li>&hellip;</li>';
1131                 }
1132                         echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$num_pages.'" title="'._AT('page').' '. $num_pages.'">'.$num_pages.'</a></li>';
1133                 }
1134                 echo '</ul>';
1135                 echo '</div>';
1136         }
1137 }
1138
1139 /**
1140 * Replace or append source object with alternatives according to user's preferences
1141 * @access       public
1142 * @param        $cid:                           content id.
1143 * @param        $content:                       the original content page ($content_row['text'], from content.php).
1144 * @param    $info_only:         boolean. Default value is "false". When it's "true", returns an array of 4 values:
1145 *                               $has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative
1146 * @param    $only_on_secondary_type: Default value is "". Accept one of the values: 1(auditory), 2(sign_language), 3(text), 4(visual)
1147 *                               When the value is given, ignore the alternative preference settings and only replace/append 
1148 *                               (replace or append is still from session preference) the objects with the alternatives with
1149 *                               the given alternative types.
1150 * @return       string                          $content: the content page with the appropriated resources.
1151 * @see          $db                             from include/vitals.inc.php
1152 * @author       Cindy Qi Li
1153 */
1154 function provide_alternatives($cid, $content, $info_only = false, $only_on_secondary_type = 0){
1155         global $db;
1156         
1157         $video_exts = array("mpg", "avi", "wmv", "mov", "swf", "mp4", "flv");
1158         
1159         $audio_exts = array("mp3", "wav", "ogg", "mid");
1160         $audio_width = 425;
1161         $audio_height = 27;
1162         
1163         $txt_exts = array("txt", "html", "htm");
1164         $image_exts = array("gif", "bmp", "png", "jpg", "jpeg", "png", "tif");
1165         $only_on_secondary_type = intval($only_on_secondary_type);
1166         
1167         // intialize the 4 returned values when $info_only is on
1168         if ($info_only)
1169         {
1170                 $has_text_alternative = false;
1171                 $has_audio_alternative = false;
1172                 $has_visual_alternative = false;
1173                 $has_sign_lang_alternative = false;
1174         }
1175
1176         if (!$info_only && !$only_on_secondary_type && 
1177             ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_TEXT']==0) && 
1178             ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_AUDIO']==0) && 
1179             ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_VISUAL']==0)) 
1180         {
1181                 //No user's preferences related to content format are declared
1182                 if (!$info_only) {
1183                         return $content;
1184                 } else {
1185                         return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1186                 }
1187         }
1188         
1189         // get all relations between primary resources and their alternatives
1190         $sql = "SELECT DISTINCT c.content_path, pr.resource, prt.type_id primary_type, 
1191                        sr.secondary_resource, srt.type_id secondary_type
1192                   FROM ".TABLE_PREFIX."primary_resources pr, ".
1193                          TABLE_PREFIX."primary_resources_types prt,".
1194                          TABLE_PREFIX."secondary_resources sr,".
1195                          TABLE_PREFIX."secondary_resources_types srt,".
1196                          TABLE_PREFIX."content c
1197                  WHERE pr.content_id=".$cid."
1198                        AND pr.primary_resource_id = prt.primary_resource_id
1199                        AND pr.primary_resource_id = sr.primary_resource_id
1200                        AND sr.language_code='".$_SESSION['lang']."'
1201                        AND sr.secondary_resource_id = srt.secondary_resource_id
1202                    AND pr.content_id = c.content_id";
1203         if ($only_on_secondary_type > 0) {
1204                 $sql .= " AND srt.type_id=".$only_on_secondary_type;
1205         }
1206         $sql .= " ORDER BY pr.primary_resource_id, prt.type_id";
1207         
1208         $result = mysql_query($sql, $db);
1209
1210         if (mysql_num_rows($result) == 0) {
1211                 if (!$info_only) {
1212                         return $content;
1213                 } else {
1214                         return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1215                 }
1216         }
1217         
1218         $primary_resource_names = array();
1219         while ($row = mysql_fetch_assoc($result)) {
1220                 // if the primary resource is defined with multiple resource type,
1221                 // the primary resource would be replaced/appended multiple times.
1222                 // This is what we want at applying alternatives by default, but
1223                 // not when only one secondary type is chosen to apply.
1224                 // This fix is to remove the duplicates on the same primary resource.
1225                 // A dilemma of this fix is, for example, if the primary resource type
1226                 // is "text" and "visual", but
1227                 // $_SESSION['prefs']['PREF_ALT_TO_TEXT_APPEND_OR_REPLACE'] == 'replace'
1228                 // $_SESSION['prefs']['PREF_ALT_TO_VISUAL_APPEND_OR_REPLACE'] == 'append'
1229                 // so, should replace happen or append happen? With this fix, whichever
1230                 // the first in the sql return gets preserved in the array and processed.
1231                 // The further improvement is requried to keep rows based on the selected
1232                 // secondary type (http://www.atutor.ca/atutor/mantis/view.php?id=4598). 
1233                 if ($only_on_secondary_type > 0) {
1234                         if (in_array($row['resource'], $primary_resource_names)) {
1235                                 continue;
1236                         } else {
1237                                 $primary_resource_names[] = $row['resource'];
1238                         }
1239                 }
1240                 $alternative_rows[] = $row;
1241                 
1242                 $youtube_playURL = convert_youtube_watchURL_to_playURL($row['resource']);
1243                 
1244                 if ($row['resource'] <> $youtube_playURL) {
1245                         $row['resource'] = $youtube_playURL;
1246                         $alternative_rows[] = $row;
1247                 }
1248         }
1249
1250         foreach ($alternative_rows as $row) 
1251         {
1252                 if ($info_only || $only_on_secondary_type ||
1253                     ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_TEXT']==1 && $row['primary_type']==3 &&
1254                     ($_SESSION['prefs']['PREF_ALT_TO_TEXT']=="audio" && $row['secondary_type']==1 || 
1255                      $_SESSION['prefs']['PREF_ALT_TO_TEXT']=="visual" && $row['secondary_type']==4 || 
1256                      $_SESSION['prefs']['PREF_ALT_TO_TEXT']=="sign_lang" && $row['secondary_type']==2)) ||
1257                      
1258                      ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_AUDIO']==1 && $row['primary_type']==1 &&
1259                      ($_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="visual" && $row['secondary_type']==4 || 
1260                       $_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="text" && $row['secondary_type']==3 || 
1261                       $_SESSION['prefs']['PREF_ALT_TO_AUDIO']=="sign_lang" && $row['secondary_type']==2)) ||
1262                       
1263                      ($_SESSION['prefs']['PREF_USE_ALTERNATIVE_TO_VISUAL']==1 && $row['primary_type']==4 &&
1264                      ($_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="audio" && $row['secondary_type']==1 || 
1265                       $_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="text" && $row['secondary_type']==3 || 
1266                       $_SESSION['prefs']['PREF_ALT_TO_VISUAL']=="sign_lang" && $row['secondary_type']==2))
1267                     )
1268                 {
1269                         $ext = substr($row['secondary_resource'], strrpos($row['secondary_resource'], '.')+1);
1270                         
1271                         // alternative is video or a youtube url
1272                         if (in_array($ext, $video_exts) || in_array($ext, $audio_exts) || 
1273                             preg_match("/http:\/\/.*youtube.com\/watch.*/", $row['secondary_resource'])) {
1274                             if (in_array($ext, $audio_exts)) {
1275                                 // display audio medias in a smaller width/height (425 * 27)
1276                                 // A hack for now to handle audio media player size
1277                                 $target = '[media|'.$audio_width.'|'.$audio_height.']'.$row['secondary_resource'].'[/media]';
1278                             } else {
1279                                 // use default media size for video medias
1280                                 $target = '[media]'.$row['secondary_resource'].'[/media]';
1281                             }
1282                         }
1283                         // a text primary to be replaced by a visual alternative 
1284                         else if (in_array($ext, $txt_exts))
1285                         {
1286                                 if ($row['content_path'] <> '') 
1287                                         $file_location = $row['content_path'].'/'.$row['secondary_resource'];
1288                                 else 
1289                                         $file_location = $row['secondary_resource'];
1290                                 
1291                                 $file = AT_CONTENT_DIR.$_SESSION['course_id'] . '/'.$file_location;
1292                                 $target = '<br />'.file_get_contents($file);
1293                                 
1294                                 // check whether html file
1295                                 if (preg_match('/.*\<html.*\<\/html\>.*/s', $target))
1296                                 { // is a html file, use iframe to display
1297                                         // get real path to the text file
1298                                         if (defined('AT_FORCE_GET_FILE') && AT_FORCE_GET_FILE) {
1299                                                 $course_base_href = 'get.php/';
1300                                         } else {
1301                                                 $course_base_href = 'content/' . $_SESSION['course_id'] . '/';
1302                                         }
1303         
1304                                         $file = AT_BASE_HREF . $course_base_href.$file_location;
1305                                                 
1306                                         $target = '<iframe width="100%" frameborder="0" class="autoHeight" scrolling="auto" src="'.$file.'"></iframe>';
1307                                 }
1308                                 else
1309                                 { // is a text file, insert/replace into content
1310                                         $target = nl2br($target);
1311                                 }
1312                         } 
1313                         else if (in_array($ext, $image_exts))
1314                                 $target = '<img border="0" alt="'._AT('alternate_text').'" src="'.$row['secondary_resource'].'"/>';
1315                         // otherwise
1316                         else
1317                                 $target = '<p><a href="'.$row['secondary_resource'].'">'.$row['secondary_resource'].'</a></p>';
1318
1319                         // replace or append the target alternative to the source
1320                         if (($row['primary_type']==3 && $_SESSION['prefs']['PREF_ALT_TO_TEXT_APPEND_OR_REPLACE'] == 'replace') ||
1321                                 ($row['primary_type']==1 && $_SESSION['prefs']['PREF_ALT_TO_AUDIO_APPEND_OR_REPLACE']=='replace') ||
1322                                 ($row['primary_type']==4 && $_SESSION['prefs']['PREF_ALT_TO_VISUAL_APPEND_OR_REPLACE']=='replace'))
1323                                 $pattern_replace_to = '${1}'."\n".$target."\n".'${3}';
1324                         else
1325                                 $pattern_replace_to = '${1}${2}'."<br /><br />\n".$target."\n".'${3}';
1326
1327                         // *** Alternative replace/append starts from here ***
1328                         $processed = false;    // one primary resource is only processed once 
1329                         
1330                         // append/replace target alternative to [media]source[/media]
1331                         if (!$processed && preg_match("/".preg_quote("[media").".*".preg_quote("]".$row['resource']."[/media]", "/")."/sU", $content))
1332                         {
1333                                 $processed = true;
1334                                 if (!$info_only) {
1335                                         $content = preg_replace("/(.*)(".preg_quote("[media").".*".preg_quote("]".$row['resource']."[/media]", "/").")(.*)/sU", 
1336                                      $pattern_replace_to, $content);
1337                                 } else {
1338                                         if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1339                                         if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1340                                         if ($row['secondary_type'] == 3) $has_text_alternative = true;
1341                                         if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1342                                 }
1343                         }
1344                         
1345                         // append/replace target alternative to <img ... src="source" ...></a>
1346                         if (!$processed && preg_match("/\<img.*src=\"".preg_quote($row['resource'], "/")."\".*\/\>/sU", $content))
1347                         {
1348                                 $processed = true;
1349                                 if (!$info_only) {
1350                                         $content = preg_replace("/(.*)(\<img.*src=\"".preg_quote($row['resource'], "/")."\".*\/\>)(.*)/sU", 
1351                                                 $pattern_replace_to, $content);
1352                                 } else {
1353                                         if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1354                                         if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1355                                         if ($row['secondary_type'] == 3) $has_text_alternative = true;
1356                                         if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1357                                 }
1358                         }
1359                         
1360                         // append/replace target alternative to <object ... source ...></object>
1361                         if (!$processed && preg_match("/\<object.*".preg_quote($row['resource'], "/").".*\<\/object\>/sU", $content))
1362                         {
1363                                 $processed = true;
1364                                 if (!$info_only) {
1365                                         $content = preg_replace("/(.*)(\<object.*".preg_quote($row['resource'], "/").".*\<\/object\>)(.*)/sU", 
1366                                                 $pattern_replace_to, $content);
1367                                 } else {
1368                                         if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1369                                         if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1370                                         if ($row['secondary_type'] == 3) $has_text_alternative = true;
1371                                         if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1372                                 }
1373                         }
1374                         
1375                         // append/replace target alternative to <a>...source...</a> or <a ...source...>...</a>
1376                         // skip this "if" when the source object has been processed in aboved <img> tag
1377                         if (!$processed && preg_match("/\<a.*".preg_quote($row['resource'], "/").".*\<\/a\>/sU", $content))
1378                         {
1379                                 $processed = true;
1380                                 if (!$info_only) {
1381                                         $content = preg_replace("/(.*)(\<a.*".preg_quote($row['resource'], "/").".*\<\/a\>)(.*)/sU", 
1382                                                 $pattern_replace_to, $content);
1383                                 } else {
1384                                         if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1385                                         if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1386                                         if ($row['secondary_type'] == 3) $has_text_alternative = true;
1387                                         if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1388                                 }
1389                         }
1390                         
1391                         // append/replace target alternative to <embed ... source ...>
1392                         if (!$processed && preg_match("/\<embed.*".preg_quote($row['resource'], "/").".*\>/sU", $content))
1393                         {
1394                                 $processed = true;
1395                                 if (!$info_only) {
1396                                         $content = preg_replace("/(.*)(\<embed.*".preg_quote($row['resource'], "/").".*\>)(.*)/sU", 
1397                                                 $pattern_replace_to, $content);
1398                                 } else {
1399                                         if ($row['secondary_type'] == 1) $has_audio_alternative = true;
1400                                         if ($row['secondary_type'] == 2) $has_sign_lang_alternative = true;
1401                                         if ($row['secondary_type'] == 3) $has_text_alternative = true;
1402                                         if ($row['secondary_type'] == 4) $has_visual_alternative = true;
1403                                 }
1404                         }
1405                 }
1406         }
1407         
1408         if (!$info_only) {
1409                 return $content;
1410         } else {
1411                 return array($has_text_alternative, $has_audio_alternative, $has_visual_alternative, $has_sign_lang_alternative);
1412         }
1413 }       
1414                 
1415 /**
1416 * apply_timezone
1417 * converts a unix timestamp into another UNIX timestamp with timezone offset added up.
1418 * Adds the user's timezone offset, then converts back to a MYSQL timestamp
1419 * Available both as a system config option, and a user preference, if both are set
1420 * they are added together
1421 * @param   date  MYSQL timestamp.
1422 * @return  date  MYSQL timestamp plus user's and/or system's timezone offset.
1423 * @author  Greg Gay  .
1424 */
1425 function apply_timezone($timestamp){
1426         global $_config;
1427 /*
1428         if($_config['time_zone']){
1429                 $timestamp = ($timestamp + ($_config['time_zone']*3600));
1430         }
1431 */
1432
1433         if(isset($_SESSION['prefs']['PREF_TIMEZONE'])){
1434                 $timestamp = ($timestamp + ($_SESSION['prefs']['PREF_TIMEZONE']*3600));
1435         }
1436
1437         return $timestamp;
1438 }
1439 ?>