initial check-in: a copy of AFrame
[acontent.git] / docs / include / lib / output.inc.php
1 <?php
2 /************************************************************************/
3 /* AFrame                                                               */
4 /************************************************************************/
5 /* Copyright (c) 2009                                                   */
6 /* Adaptive Technology Resource Centre / University of Toronto          */
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
13 if (!defined('AF_INCLUDE_PATH')) { exit; }
14 require(AF_INCLUDE_PATH . 'classes/DAO/LanguageTextDAO.class.php');
15
16 /**********************************************************************************/
17 /* Output functions found in this file, in order:
18 /*
19 /*      - AC(term)
20 /*
21 /**********************************************************************************/
22
23 /**
24 * Converts language code to actual language message, caches them according to page url
25 * @access       public
26 * @param        args                            unlimited number of arguments allowed but first arg MUST be name of the language variable/term
27 *                                                               i.e             $args[0] = the term to the format string $_template[term]
28 *                                                                               $args[1..x] = optional arguments to the formatting string 
29 * @return       string|array            full resulting message
30 * @see          $db                             in include/vitals.inc.php
31 * @see          cache()                         in include/phpCache/phpCache.inc.php
32 * @see          cache_variable()        in include/phpCache/phpCache.inc.php
33 * @author       Joel Kronenberg
34 */
35 function _AT() {
36         global $_cache_template, $lang_et, $_rel_url;
37         static $_template;
38
39         $args = func_get_args();
40         
41         if ($args[0] == "") return "";
42         
43         $languageTextDAO = new LanguageTextDAO();
44         
45         // a feedback msg
46         if (!is_array($args[0])) {
47                 /**
48                  * Added functionality for translating language code String (AF_ERROR|AF_INFOS|AF_WARNING|AF_FEEDBACK).*
49                  * to its text and returning the result. No caching needed.
50                  * @author Jacek Materna
51                  */
52
53                 // Check for specific language prefix, extendible as needed
54                 // 0002767:  a substring+in_array test should be faster than a preg_match test.
55                 // replaced the preg_match with a test of the substring.
56                 $sub_arg = substr($args[0], 0, 7); // 7 is the shortest type of msg (AF_INFO)
57                 if (in_array($sub_arg, array('AF_ERRO','AF_INFO','AF_WARN','AF_FEED','AF_CONF'))) {
58                         global $_base_path, $addslashes;
59
60                         $args[0] = $addslashes($args[0]);
61                                         
62                         /* get $_msgs_new from the DB */
63                         $rows = $languageTextDAO->getMsgByTermAndLang($args[0], $_SESSION['lang']);
64                         $msgs = '';
65                                         
66                         if (is_array($rows)) 
67                         {
68                                 $row = $rows[0];
69                                 // do not cache key as a digit (no contstant(), use string)
70                                 $msgs = str_replace('SITE_URL/', $_base_path, $row['text']);
71                                 if (defined('AF_DEVEL') && AF_DEVEL) {
72                                         $msgs .= ' <small><small>('. $args[0] .')</small></small>';
73                                 }
74                         }
75
76                         return $msgs;
77                 }
78         }
79         
80         // a template variable
81         if (!isset($_template)) {
82                 $url_parts = parse_url(AF_BASE_HREF);
83                 $name = substr($_SERVER['PHP_SELF'], strlen($url_parts['path'])-1);
84
85                 if ( !($lang_et = cache(120, 'lang', $_SESSION['lang'].'_'.$name)) ) {
86                         /* get $_template from the DB */
87                         $rows = $languageTextDAO->getAllTemplateByLang($_SESSION['lang']);
88                         
89                         if (is_array($rows))
90                         {
91                                 foreach ($rows as $id => $row) 
92                                 {
93                                         //Do not overwrite the variable that existed in the cache_template already.
94                                         //The edited terms (_c_template) will always be at the top of the resultset
95                                         //0003279
96                                         if (isset($_cache_template[$row['term']])){
97                                                 continue;
98                                         }
99         
100                                         // saves us from doing an ORDER BY
101                                         if ($row['language_code'] == $_SESSION['lang']) {
102                                                 $_cache_template[$row['term']] = stripslashes($row['text']);
103                                         } else if (!isset($_cache_template[$row['term']])) {
104                                                 $_cache_template[$row['term']] = stripslashes($row['text']);
105                                         }
106                                 }
107                         }
108                 
109                         cache_variable('_cache_template');
110                         endcache(true, false);
111                 }
112                 $_template = $_cache_template;
113         }
114
115         $num_args = func_num_args();
116         if (is_array($args[0])) {
117                 $args = $args[0];
118                 $num_args = count($args);
119         }
120         $format   = array_shift($args);
121
122         if (isset($_template[$format]) && count($args) > 0) {
123                 $outString      = vsprintf($_template[$format], $args);
124                 $str = ob_get_contents();
125         } else {
126                 $outString = '';
127         }
128
129         if ($outString === false) {
130                 return ('[Error parsing language. Variable: <code>'.$format.'</code>. Language: <code>'.$_SESSION['lang'].'</code> ]');
131         }
132
133         if (empty($outString)) {
134
135                 $rows = $languageTextDAO->getByTermAndLang($format, $_SESSION['lang']);
136                 if (is_array($rows))
137                 {
138                         $row = $rows[0];
139                         $_template[$row['term']] = stripslashes($row['text']);
140                         $outString = $_template[$row['term']];
141                 }
142
143                 if (empty($outString)) {
144                         return ('[ '.$format.' ]');
145                 }
146         }
147
148         return $outString;
149 }
150
151 /* 
152         The following options were added as language dependant:
153         %D: A textual representation of a week, three letters Mon through Sun
154         %F: A full textual representation of a month, such as January or March January through December
155         %l (lowercase 'L'): A full textual representation of the day of the week Sunday through Saturday
156         %M: A short textual representation of a month, three letters Jan through Dec
157
158         Support for the following maybe added later:
159         ?? %S: English ordinal suffix for the day of the month, 2 characters st, nd, rd or th. Works well with j
160         ?? %a: Lowercase Ante meridiem and Post meridiem am or pm 
161         ?? %A: Uppercase Ante meridiem and Post meridiem AM or PM 
162
163         valid formAF_types:
164         AF_DATE_MYSQL_DATETIME:         YYYY-MM-DD HH:MM:SS
165         AF_DATE_MYSQL_TIMESTAMP_14:     YYYYMMDDHHMMSS
166         AF_DATE_UNIX_TIMESTAMP:         seconds since epoch
167         AF_DATE_INDEX_VALUE:            0-x, index into a date array
168 */
169 function AF_date($format='%Y-%M-%d', $timestamp = '', $formAF_type=AF_DATE_MYSQL_DATETIME) {    
170         static $day_name_ext, $day_name_con, $month_name_ext, $month_name_con;
171         global $_config;
172
173         if (!isset($day_name_ext)) {
174                 $day_name_ext = array(  'date_sunday', 
175                                                                 'date_monday', 
176                                                                 'date_tuesday', 
177                                                                 'date_wednesday', 
178                                                                 'date_thursday', 
179                                                                 'date_friday',
180                                                                 'date_saturday');
181
182                 $day_name_con = array(  'date_sun', 
183                                                                 'date_mon', 
184                                                                 'date_tue', 
185                                                                 'date_wed',
186                                                                 'date_thu', 
187                                                                 'date_fri', 
188                                                                 'date_sat');
189
190                 $month_name_ext = array('date_january', 
191                                                                 'date_february', 
192                                                                 'date_march', 
193                                                                 'date_april', 
194                                                                 'date_may',
195                                                                 'date_june', 
196                                                                 'date_july', 
197                                                                 'date_august', 
198                                                                 'date_september', 
199                                                                 'date_october', 
200                                                                 'date_november',
201                                                                 'date_december');
202
203                 $month_name_con = array('date_jan', 
204                                                                 'date_feb', 
205                                                                 'date_mar', 
206                                                                 'date_apr', 
207                                                                 'date_may_short',
208                                                                 'date_jun', 
209                                                                 'date_jul', 
210                                                                 'date_aug', 
211                                                                 'date_sep', 
212                                                                 'date_oct', 
213                                                                 'date_nov',
214                                                                 'date_dec');
215         }
216
217         if ($formAF_type == AF_DATE_INDEX_VALUE) {
218                 // apply timezone offset
219                 apply_timezone($timestamp);
220         
221                 if ($format == '%D') {
222                         return _AT($day_name_con[$timestamp-1]);
223                 } else if ($format == '%l') {
224                         return _AT($day_name_ext[$timestamp-1]);
225                 } else if ($format == '%F') {
226                         return _AT($month_name_ext[$timestamp-1]);
227                 } else if ($format == '%M') {
228                         return _AT($month_name_con[$timestamp-1]);
229                 }
230         }
231
232         if ($timestamp == '') {
233                 $timestamp = time();
234                 $formAF_type = AF_DATE_UNIX_TIMESTAMP;
235         }
236
237         /* convert the date to a Unix timestamp before we do anything with it */
238         if ($formAF_type == AF_DATE_MYSQL_DATETIME) {
239                 $year   = substr($timestamp,0,4);
240                 $month  = substr($timestamp,5,2);
241                 $day    = substr($timestamp,8,2);
242                 $hour   = substr($timestamp,11,2);
243                 $min    = substr($timestamp,14,2);
244                 $sec    = substr($timestamp,17,2);
245             $timestamp  = mktime($hour, $min, $sec, $month, $day, $year);
246
247         } else if ($formAF_type == AF_DATE_MYSQL_TIMESTAMP_14) {
248             $year               = substr($timestamp,0,4);
249             $month              = substr($timestamp,4,2);
250             $day                = substr($timestamp,6,2);
251                 $hour           = substr($timestamp,8,2);
252             $minute             = substr($timestamp,10,2);
253             $second             = substr($timestamp,12,2);
254             $timestamp  = mktime($hour, $minute, $second, $month, $day, $year);  
255         }
256
257         // apply timezone offset
258         apply_timezone($timestamp);
259
260         /* pull out all the %X items from $format */
261         $first_token = strpos($format, '%');
262         if ($first_token === false) {
263                 /* no tokens found */
264                 return $timestamp;
265         } else {
266                 $tokened_format = substr($format, $first_token);
267         }
268         $tokens = explode('%', $tokened_format);
269         array_shift($tokens);
270         $num_tokens = count($tokens);
271
272         $output = $format;
273         for ($i=0; $i<$num_tokens; $i++) {
274                 $tokens[$i] = substr($tokens[$i],0,1);
275
276                 if ($tokens[$i] == 'D') {
277                         $output = str_replace('%D', _AT($day_name_con[date('w', $timestamp)]),$output);
278                 
279                 } else if ($tokens[$i] == 'l') {
280                         $output = str_replace('%l', _AT($day_name_ext[date('w', $timestamp)]),$output);
281                 
282                 } else if ($tokens[$i] == 'F') {
283                         $output = str_replace('%F', _AT($month_name_ext[date('n', $timestamp)-1]),$output);             
284                 
285                 } else if ($tokens[$i] == 'M') {
286                         $output = str_replace('%M', _AT($month_name_con[date('n', $timestamp)-1]),$output);
287
288                 } else {
289
290                         /* this token doesn't need translating */
291                         $value = date($tokens[$i], $timestamp);
292                         if ($value != $tokens[$i]) {
293                                 $output = str_replace('%'.$tokens[$i], $value, $output);
294                         } /* else: this token isn't valid. so don't replace it. Eg. try %q */
295                 }
296         }
297
298         return $output;
299 }
300
301 /**********************************************************************************************************/
302         /**
303         *       Transforms text based on formatting preferences.  Original $input is also changed (passed by reference).
304         *       Can be called as:
305         *       1) $output = AF_print($input, $name);
306         *          echo $output;
307         *
308         *       2) echo AF_print($input, $name); // prefered method
309         *
310         * @access       public
311         * @param        string $input                   text being transformed
312         * @param        string $name                    the unique name of this field (convension: table_name.field_name)
313         * @param        boolean $runtime_html   forcefully disables html formatting for $input (only used by fields that 
314         *                                                                       have the 'formatting' option
315         * @return       string                                  transformed $input
316         * @see          AF_FORMAT constants             in include/lib/constants.inc.php
317         * @see          query_bit()                             in include/vitals.inc.php
318         * @author       Joel Kronenberg
319         */
320         function AF_print($input, $name, $runtime_html = true) {
321                 global $_field_formatting;
322
323                 if (!isset($_field_formatting[$name])) {
324                         /* field not set, check if there's a global setting */
325                         $parts = explode('.', $name);
326                         
327                         /* check if wildcard is set: */
328                         if (isset($_field_formatting[$parts[0].'.*'])) {
329                                 $name = $parts[0].'.*';
330                         } else {
331                                 /* field not set, and there's no global setting */
332                                 /* same as AF_FORMAF_NONE */
333                                 return $input;
334                         }
335                 }
336
337                 if (query_bit($_field_formatting[$name], AF_FORMAF_QUOTES)) {
338                         $input = str_replace('"', '&quot;', $input);
339                 }
340
341                 if (query_bit($_field_formatting[$name], AF_FORMAF_CONTENT_DIR)) {
342                         $input = str_replace('CONTENT_DIR/', '', $input);
343                 }
344
345                 if (query_bit($_field_formatting[$name], AF_FORMAF_HTML) && $runtime_html) {
346                         /* what special things do we have to do if this is HTML ? remove unwanted HTML? validate? */
347                 } else {
348                         $input = str_replace('<', '&lt;', $input);
349                         $input = nl2br($input);
350                 }
351
352                 /* this has to be here, only because AF_FORMAF_HTML is the only check that has an else-block */
353                 if ($_field_formatting[$name] === AF_FORMAF_NONE) {
354                         return $input;
355                 }
356
357                 if (query_bit($_field_formatting[$name], AF_FORMAF_EMOTICONS)) {
358                         $input = smile_replace($input);
359                 }
360
361                 if (query_bit($_field_formatting[$name], AF_FORMAF_ATCODES)) {
362                         $input = trim(myCodes(' ' . $input . ' '));
363                 }
364
365                 if (query_bit($_field_formatting[$name], AF_FORMAF_LINKS)) {
366                         $input = trim(make_clickable(' ' . $input . ' '));
367                 }
368
369                 if (query_bit($_field_formatting[$name], AF_FORMAF_IMAGES)) {
370                         $input = trim(image_replace(' ' . $input . ' '));
371                 }
372
373         
374                 return $input;
375         }
376
377 /********************************************************************************************/
378 // Global variables for emoticons
379  
380 global $smile_pics;
381 global $smile_codes;
382 if (!isset($smile_pics)) {
383         $smile_pics[0] = $_base_path.'images/forum/smile.gif';
384         $smile_pics[1] = $_base_path.'images/forum/wink.gif';
385         $smile_pics[2] = $_base_path.'images/forum/frown.gif';
386         $smile_pics[3] = $_base_path.'images/forum/ohwell.gif';
387         $smile_pics[4] = $_base_path.'images/forum/tongue.gif';
388         $smile_pics[5] = $_base_path.'images/forum/51.gif';
389         $smile_pics[6] = $_base_path.'images/forum/52.gif';
390         $smile_pics[7] = $_base_path.'images/forum/54.gif';
391         $smile_pics[8] = $_base_path.'images/forum/27.gif';
392         $smile_pics[9] = $_base_path.'images/forum/19.gif';
393         $smile_pics[10] = $_base_path.'images/forum/3.gif';
394         $smile_pics[11] = $_base_path.'images/forum/56.gif';
395 }
396
397 if (!isset($smile_codes)) {
398         $smile_codes[0] = ':)';
399         $smile_codes[1] = ';)';
400         $smile_codes[2] = ':(';
401         $smile_codes[3] = '::ohwell::';
402         $smile_codes[4] = ':P';
403         $smile_codes[5] = '::evil::';
404         $smile_codes[6] = '::angry::';
405         $smile_codes[7] = '::lol::';
406         $smile_codes[8] = '::crazy::';
407         $smile_codes[9] = '::tired::';
408         $smile_codes[10] = '::confused::';
409         $smile_codes[11] = '::muah::';
410 }
411
412 /**
413 * Replaces smile-code text into smilie image.
414 * @access       public
415 * @param        string $text            smile text to be transformed
416 * @return       string                          transformed $text
417 * @see          $smile_pics                     in include/lib/output.inc.php (above)
418 * @see          $smile_codes            in include/lib/output.inc.php (above)
419 * @author       Joel Kronenberg
420 */
421 function smile_replace($text) {
422         global $smile_pics;
423         global $smile_codes;
424         static $smiles;
425
426         $smiles[0] = '<img src="'.$smile_pics[0].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_smile').'" />';
427         $smiles[1] = '<img src="'.$smile_pics[1].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_wink').'" />';
428         $smiles[2] = '<img src="'.$smile_pics[2].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_frown').'" />';
429         $smiles[3]= '<img src="'.$smile_pics[3].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_oh_well').'" />';
430         $smiles[4]= '<img src="'.$smile_pics[4].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tongue').'" />';
431         $smiles[5]= '<img src="'.$smile_pics[5].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_evil').'" />';
432         $smiles[6]= '<img src="'.$smile_pics[6].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_angry').'" />';
433         $smiles[7]= '<img src="'.$smile_pics[7].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_lol').'" />';
434         $smiles[8]= '<img src="'.$smile_pics[8].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_crazy').'" />';
435         $smiles[9]= '<img src="'.$smile_pics[9].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_tired').'" />';
436         $smiles[10]= '<img src="'.$smile_pics[10].'" border="0" height="17" width="19" align="bottom" alt="'._AT('smile_confused').'" />';
437         $smiles[11]= '<img src="'.$smile_pics[11].'" border="0" height="15" width="15" align="bottom" alt="'._AT('smile_muah').'" />';
438
439         $text = str_replace($smile_codes[0],$smiles[0],$text);
440         $text = str_replace($smile_codes[1],$smiles[1],$text);
441         $text = str_replace($smile_codes[2],$smiles[2],$text);
442         $text = str_replace($smile_codes[3],$smiles[3],$text);
443         $text = str_replace($smile_codes[4],$smiles[4],$text);
444         $text = str_replace($smile_codes[5],$smiles[5],$text);
445         $text = str_replace($smile_codes[6],$smiles[6],$text);
446         $text = str_replace($smile_codes[7],$smiles[7],$text);
447         $text = str_replace($smile_codes[8],$smiles[8],$text);
448         $text = str_replace($smile_codes[9],$smiles[9],$text);
449         $text = str_replace($smile_codes[10],$smiles[10],$text);
450         $text = str_replace($smile_codes[11],$smiles[11],$text);
451
452         return $text;
453 }
454
455
456 /* Used specifically for the visual editor
457 */
458 function smile_javascript () {
459         global $_base_path;
460         global $smile_pics;
461         global $smile_codes;
462
463         static $i = 0;
464
465         while ($smile_pics [$i]) {
466                 echo 'case "'.$smile_codes[$i].'":'."\n";
467                 echo 'pic = "'.$smile_pics[$i].'";'."\n";
468                 echo 'break;'."\n";
469                 $i++;
470         }
471 }
472
473 function myCodes($text, $html = false) {
474         global $_base_path;
475         global $HTTP_USER_AGENT;
476
477         if (substr($HTTP_USER_AGENT,0,11) == 'Mozilla/4.7') {
478                 $text = str_replace('[quote]','</p><p class="block">',$text);
479                 $text = str_replace('[/quote]','</p><p>',$text);
480
481                 $text = str_replace('[reply]','</p><p class="block">',$text);
482                 $text = str_replace('[/reply]','</p><p>',$text);
483         } else {
484                 $text = str_replace('[quote]','<blockquote>',$text);
485                 $text = str_replace('[/quote]','</blockquote><p>',$text);
486
487                 $text = str_replace('[reply]','</p><blockquote class="block"><p>',$text);
488                 $text = str_replace('[/reply]','</p></blockquote><p>',$text);
489         }
490
491         $text = str_replace('[b]','<strong>',$text);
492         $text = str_replace('[/b]','</strong>',$text);
493
494         $text = str_replace('[i]','<em>',$text);
495         $text = str_replace('[/i]','</em>',$text);
496
497         $text = str_replace('[u]','<u>',$text);
498         $text = str_replace('[/u]','</u>',$text);
499
500         $text = str_replace('[center]','<center>',$text);
501         $text = str_replace('[/center]','</center><p>',$text);
502
503         /* colours */
504         $text = str_replace('[blue]','<span style="color: blue;">',$text);
505         $text = str_replace('[/blue]','</span>',$text);
506
507         $text = str_replace('[orange]','<span style="color: orange;">',$text);
508         $text = str_replace('[/orange]','</span>',$text);
509
510         $text = str_replace('[red]','<span style="color: red;">',$text);
511         $text = str_replace('[/red]','</span>',$text);
512
513         $text = str_replace('[purple]','<span style="color: purple;">',$text);
514         $text = str_replace('[/purple]','</span>',$text);
515
516         $text = str_replace('[green]','<span style="color: green;">',$text);
517         $text = str_replace('[/green]','</span>',$text);
518
519         $text = str_replace('[gray]','<span style="color: gray;">',$text);
520         $text = str_replace('[/gray]','</span>',$text);
521
522         $text = str_replace('[op]','<span class="bigspacer"></span> <a href="',$text);
523         $text = str_replace('[/op]','">'._AT('view_entire_post').'</a>',$text);
524
525         $text = str_replace('[head1]','<h2>',$text);
526         $text = str_replace('[/head1]','</h2>',$text);
527
528         $text = str_replace('[head2]','<h3>',$text);
529         $text = str_replace('[/head2]','</h3>',$text);
530
531         $text = str_replace('[cid]',$_base_path.'content.php?cid='.$_SESSION['s_cid'],$text);
532
533         global $sequence_links;
534         if (isset($sequence_links['previous']) && $sequence_links['previous']['url']) {
535                 $text = str_replace('[pid]', $sequence_links['previous']['url'], $text);
536         }
537         if (isset($sequence_links['next']) && $sequence_links['next']['url']) {
538                 $text = str_replace('[nid]', $sequence_links['next']['url'], $text);
539         }
540         if (isset($sequence_links['resume']) && $sequence_links['resume']['url']) {
541                 $text = str_replace('[nid]', $sequence_links['resume']['url'], $text);
542         }
543         if (isset($sequence_links['first']) && $sequence_links['first']['url']) {
544                 $text = str_replace('[fid]', $sequence_links['first']['url'], $text);
545         }
546
547         /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
548         $html = !$html ? 0 : 1;
549         $text = preg_replace("/\[code\]\s*(.*)\s*\[\\/code\]/Usei", "highlight_code(fix_quotes('\\1'), $html)", $text);
550
551         return $text;
552 }
553
554 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
555 function highlight_code($code, $html) {
556         // XHTMLize PHP highlight_string output until it gets fixed in PHP
557         static $search = array(
558                 '<br>',
559                 '<font',
560                 '</font>',
561                 'color="');
562
563         static $replace = array(
564                 '<br />',
565                 '<span',
566                 '</span>',
567                 'style="color:');
568         if (!$html) {
569                 $code = str_replace('&lt;', '<', $code);
570                 $code = str_replace("\r", '', $code);
571         }
572
573         return str_replace($search, $replace, highlight_string($code, true));
574 }
575
576 /* contributed by Thomas M. Duffey <tduffey at homeboyz.com> */
577 function fix_quotes($text){
578         return str_replace('\\"', '"', $text);
579 }
580
581 function embed_media($text) {
582         if (preg_match("/\[media(\|[0-9]+\|[0-9]+)?\]*/", $text)==0){
583                 return $text;
584         }
585
586         $media_matches = Array();
587         
588         /*
589                 First, we search though the text for all different kinds of media defined by media tags and store the results in $media_matches.
590                 
591                 Then the different replacements for the different media tags are stored in $media_replace.
592                 
593                 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.
594                 
595         */
596         
597         // youtube videos
598         preg_match_all("#\[media[0-9a-z\|]*\]http://([a-z0-9\.]*)?youtube.com/watch\?v=([a-z0-9_-]+)\[/media\]#i",$text,$media_matches[1],PREG_SET_ORDER);
599         $media_replace[1] = '<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>';
600                 
601         // .mpg
602         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mpg\[/media\]#i",$text,$media_matches[2],PREG_SET_ORDER);
603         $media_replace[2] = "<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>";
604         
605         // .avi
606         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).avi\[/media\]#i",$text,$media_matches[3],PREG_SET_ORDER);
607         $media_replace[3] = "<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>";
608         
609         // .wmv
610         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).wmv\[/media\]#i",$text,$media_matches[4],PREG_SET_ORDER);
611         $media_replace[4] = "<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>";
612         
613         // .mov
614         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).mov\[/media\]#i",$text,$media_matches[5],PREG_SET_ORDER);
615         $media_replace[5] = "<object classid=\"clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B\" codebase=\"http://www.apple.com/qtactivex/qtplugin.cab\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"src\" value=\"##MEDIA1##.mov\"><param name=\"controller\" value=\"true\"><param name=\"autoplay\" value=\"false\"><!--[if gte IE 7]> <!--><object type=\"video/quicktime\" data=\"##MEDIA1##.mov\" width=\"##WIDTH##\" height=\"##HEIGHT##\"><param name=\"controller\" value=\"true\"><param name=\"autoplay\" value=\"false\"><a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a></object><!--<![endif]--><!--[if lt IE 7]><a href=\"##MEDIA1##.mov\">##MEDIA1##.mov</a><![endif]--></object>";
616         
617         // .swf
618         preg_match_all("#\[media[0-9a-z\|]*\]([.\w\d]+[^\s\"]+).swf\[/media\]#i",$text,$media_matches[6],PREG_SET_ORDER);
619         $media_replace[6] = "<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>";
620         
621         // .mp3
622         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mp3\[/media\]#i",$text,$media_matches[7],PREG_SET_ORDER);
623         $media_replace[7] = "<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>";
624         
625         // .wav
626         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).wav\[/media\]#i",$text,$media_matches[8],PREG_SET_ORDER);
627         $media_replace[8] ="<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>";
628         
629         // .ogg
630         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).ogg\[/media\]#i",$text,$media_matches[9],PREG_SET_ORDER);
631         $media_replace[9] ="<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>";
632         
633         // .mid
634         preg_match_all("#\[media[0-9a-z\|]*\](.+[^\s\"]+).mid\[/media\]#i",$text,$media_matches[10],PREG_SET_ORDER);
635         $media_replace[10] ="<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>";
636         
637         $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);
638
639         // Executing the replace
640         for ($i=1;$i<=count($media_replace);$i++){
641                 foreach($media_matches[$i] as $media)
642                 {
643                         
644                         //find width and height for each matched media
645                         if (preg_match("/\[media\|([0-9]*)\|([0-9]*)\]*/", $media[0], $matches)) 
646                         {
647                                 $width = $matches[1];
648                                 $height = $matches[2];
649                         }
650                         else
651                         {
652                                 $width = 425;
653                                 $height = 350;
654                         }
655                         
656                         //replace media tags with embedded media for each media tag
657                         $media_input = $media_replace[$i];
658                         $media_input = str_replace("##WIDTH##","$width",$media_input);
659                         $media_input = str_replace("##HEIGHT##","$height",$media_input);
660                         $media_input = str_replace("##MEDIA1##","$media[1]",$media_input);
661                         $media_input = str_replace("##MEDIA2##","$media[2]",$media_input);
662                         $text = str_replace($media[0],$media_input,$text);
663                 }
664         }
665                 
666         return $text;
667 }
668
669 function make_clickable($text) {
670         $text = embed_media($text);
671
672         $text = preg_replace("/([\s])(http[s]?):\/\/([\^\s\<]*)([a-zA-Z0-9\#\?\/\&\=])/i", 
673                              "\\1<a href=\"\\2://\\3\\4\">\\3\\4</a>", $text);
674         
675         $text = preg_replace('/([_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.
676                                                 '\@'.'[_a-zA-Z0-9\-]+(\.[_a-zA-Z0-9\-]+)*'.'(\.[a-zA-Z]{1,6})+)/i',
677                                                 "<a href=\"mailto:\\1\">\\1</a>",
678                                                 $text);
679         
680         return $text;
681 }
682
683 function image_replace($text) {
684         /* image urls do not require http:// */
685         
686         $text = preg_replace("/\[image(\|)?([a-zA-Z0-9\s]*)\]".
687                              "[\s]*".
688                              "([a-zA-Z0-9\#\?\/\&\=\:\\\"\'\_\.\-]+)[\s]*".
689                              "((\[\/image\])|(.*\[\/image\]))/i",
690                                   "<img src=\"\\3\" alt=\"\\2\" />",
691                                   $text);
692         
693         return $text;
694 }
695
696 function formAF_final_output($text, $nl2br = true) {
697         global $_base_path;
698
699         $text = str_replace('CONTENT_DIR/', '', $text);
700
701         if ($nl2br) {
702                 return nl2br(image_replace(make_clickable(myCodes(' '.$text, false))));
703         }
704         return image_replace(make_clickable(myCodes(' '.$text, true)));
705 }
706
707 /****************************************************************************************/
708 /* @See: ./user/search.php & ./index.php */
709 function highlight($input, $var) {//$input is the string, $var is the text to be highlighted
710         if ($var != "") {
711                 $xtemp = "";
712                 $i=0;
713                 /*
714                         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.
715                 */
716                 if (strpos('<strong class="highlight">', $var) !== false) {
717                         return $input;
718                 }
719                 while($i<strlen($input)){
720                         if((($i + strlen($var)) <= strlen($input)) && (strcasecmp($var, substr($input, $i, strlen($var))) == 0)) {
721                                 $xtemp .= '<strong class="highlight">' . substr($input, $i , strlen($var)) . '</strong>';
722                                 $i += strlen($var);
723                         }
724                         else {
725                                 $xtemp .= $input{$i};
726                                 $i++;
727                         }
728                 }
729                 $input = $xtemp;
730         }
731         return $input;
732 }
733
734
735 /* @See: ./index.php */
736 function formAF_content($input, $html = 0, $glossary, $simple = false) {
737         global $_base_path, $_config_defaults;
738
739         if (!$html) {
740                 $input = str_replace('<', '&lt;', $input);
741                 $input = str_replace('&lt;?php', '<?php', $input); // for bug #2087
742         }
743
744         /* do the glossary search and replace: */
745         if (is_array($glossary)) {
746                 foreach ($glossary as $k => $v) {
747                         $k = urldecode($k);
748                         $v = str_replace("\n", '<br />', $v);
749                         $v = str_replace("\r", '', $v);
750
751                         /* escape special characters */
752                         $k = preg_quote($k);
753
754                         $k = str_replace('&lt;', '<', $k);
755                         $k = str_replace('/', '\/', $k);
756
757                         $original_term = $k;
758                         $term = $original_term;
759
760                         $term = '(\s*'.$term.'\s*)';
761                         $term = str_replace(' ','((<br \/>)*\s*)', $term); 
762
763                         $def = htmlspecialchars($v);            
764                         if ($simple) {
765                                 $input = preg_replace
766                                                 ("/(\[\?\])$term(\[\/\?\])/i",
767                                                 '<a href="'.$simple.'glossary.html#'.urlencode($original_term).'" target="body" class="at-term">\\2</a>',
768                                                 $input);
769                         } else {
770                                 $input = preg_replace
771                                                 ("/(\[\?\])$term(\[\/\?\])/i",
772                                                 '\\2<sup><a href="'.$_base_path.'glossary/index.php?g_cid='.$_SESSION['s_cid'].SEP.'w='.urlencode($original_term).'#term" onmouseover="return overlib(\''.$def.'\', CAPTION, \''.addslashes($original_term).'\', AUTOSTATUS);" onmouseout="return nd();" onfocus="return overlib(\''.$def.'\', CAPTION, \''.addslashes($original_term).'\', AUTOSTATUS);" onblur="return nd();"><span style="color: blue; text-decoration: none;font-size:small; font-weight:bolder;">?</span></a></sup>',
773                                                 $input);
774                         }
775                 }
776         } else if (!$user_glossary) {
777                 $input = str_replace(array('[?]','[/?]'), '', $input);
778         }
779
780         $input = str_replace('CONTENT_DIR', '', $input);
781
782         if (isset($_config_defaults['latex_server']) && $_config_defaults['latex_server']) {
783                 // see: http://www.forkosh.com/mimetex.html
784                 $input = preg_replace('/\[tex\](.*?)\[\/tex\]/sie', "'<img src=\"'.\$_config_defaults['latex_server'].rawurlencode('$1').'\" align=\"middle\">'", $input);
785         }
786
787         if ($html) {
788                 $x = formAF_final_output($input, false);
789                 return $x;
790         }
791
792         $output = formAF_final_output($input);
793
794         $output = '<p>'.$output.'</p>';
795
796         return $output;
797 }
798
799 /***********************************************************************
800         @See /include/Classes/Message/Message.class.php
801         Jacek Materna
802 */
803
804 /**
805 * Take a code as input and grab its language specific message. Also cache the resulting 
806 * message. Return the message. Same as get_message but key value in cache is string
807 * @access  public
808 * @param   string $codes        Message Code to translate - > 'term' field in DB
809 * @return  string                       The translated language specific message for code $code
810 * @author  Jacek Materna
811 */
812 function getTranslatedCodeStr($codes) {
813         
814         /* this is where we want to get the msgs from the database inside a static variable */
815         global $_cache_msgs_new;
816         static $_msgs_new;
817
818         if (!isset($_msgs_new)) {
819                 if ( !($lang_et = cache(120, 'msgs_new', $_SESSION['lang'])) ) {
820                         global $db, $_base_path;
821
822                         $parent = Language::getParentCode($_SESSION['lang']);
823
824                         /* get $_msgs_new from the DB */
825                         $sql    = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs" AND (language_code="'.$_SESSION['lang'].'" OR language_code="'.$parent.'")';
826                         $result = @mysql_query($sql, $db);
827                         $i = 1;
828                         while ($row = @mysql_fetch_assoc($result)) {
829                                 // do not cache key as a digit (no contstant(), use string)
830                                 $_cache_msgs_new[$row['term']] = str_replace('SITE_URL/', $_base_path, $row['text']);
831                                 if (AF_DEVEL) {
832                                         $_cache_msgs_new[$row['term']] .= ' <small><small>('.$row['term'].')</small></small>';
833                                 }
834                         }
835
836                         cache_variable('_cache_msgs_new');
837                         endcache(true, false);
838                 }
839                 $_msgs_new = $_cache_msgs_new;
840         }
841
842         if (is_array($codes)) {
843                 /* this is an array with terms to replace */            
844                 $code           = array_shift($codes);
845
846                 $message        = $_msgs_new[$code];
847                 $terms          = $codes;
848
849                 /* replace the tokens with the terms */
850                 $message        = vsprintf($message, $terms);
851
852         } else {
853                 $message = $_msgs_new[$codes];
854
855                 if ($message == '') {
856                         /* the language for this msg is missing: */
857                 
858                         $sql    = 'SELECT * FROM '.TABLE_PREFIX.'language_text WHERE variable="_msgs"';
859                         $result = @mysql_query($sql, $db);
860                         $i = 1;
861                         while ($row = @mysql_fetch_assoc($result)) {
862                                 if (($row['term']) === $codes) {
863                                         $message = '['.$row['term'].']';
864                                         break;
865                                 }
866                         }
867                 }
868                 $code = $codes;
869         }
870         return $message;
871 }
872
873 function html_get_list($array) {
874         $list = '';
875         foreach ($array as $value) {
876                 $list .= '<li>'.$value.'</li>';
877         }
878         return $list;
879 }
880
881 /**
882  * print_paginator
883  *
884  * print out list of page links
885  */
886 function print_paginator($current_page, $num_rows, $request_args, $rows_per_page = 50, $window = 5) {
887         $num_pages = ceil($num_rows / $rows_per_page);
888         $request_args = '?'.$request_args;
889
890     if ($num_rows) {
891                 echo '<div class="paging">';
892             echo '<ul>';
893                 
894                 $i=max($current_page-$window - max($window-$num_pages+$current_page,0), 1);
895
896                 if ($i > 1) {
897                         echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p=1">1</a></li>';
898                         if ($i > 2) {
899                         echo '<li>&hellip;</li>';
900                         }
901                 }
902
903                 for ($i; $i<= min($current_page+$window -min($current_page-$window,0),$num_pages); $i++) {
904                         if ($current_page == $i) {
905                                 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'" class="current"><em>'.$current_page.'</em></a></li>';
906                         } else {
907                                 echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$i.'">'.$i.'</a></li>';
908                         }
909                 }
910         if ($i <= $num_pages) {
911                         if ($i < $num_pages) {
912                         echo '<li>&hellip;</li>';
913                 }
914                         echo '<li><a href="'.$_SERVER['PHP_SELF'].$request_args.htmlspecialchars(SEP).'p='.$num_pages.'">'.$num_pages.'</a></li>';
915                 }
916                 echo '</ul>';
917                 echo '</div>';
918         }
919 }
920
921 /**
922 * apply_timezone
923 * converts a unix timestamp into another UNIX timestamp with timezone offset added up.
924 * Adds the user's timezone offset, then converts back to a MYSQL timestamp
925 * Available both as a system config option, and a user preference, if both are set
926 * they are added together
927 * @param   date  MYSQL timestamp.
928 * @return  date  MYSQL timestamp plus user's and/or system's timezone offset.
929 * @author  Greg Gay  .
930 */
931 function apply_timezone($timestamp){
932         global $_config;
933
934         if($_config['time_zone']){
935                 $timestamp = ($timestamp + ($_config['time_zone']*3600));
936         }
937
938         if(isset($_SESSION['prefs']['PREF_TIMEZONE'])){
939                 $timestamp = ($timestamp + ($_SESSION['prefs']['PREF_TIMEZONE']*3600));
940         }
941
942         return $timestamp;
943 }
944 ?>