caa72894e601397b79899555565c2e7778104e3e
[mailer.git] / inc / template-functions.php
1 <?php
2 /************************************************************************
3  * Mailer v0.2.1-FINAL                                Start: 04/04/2009 *
4  * ===================                          Last change: 04/04/2009 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : template-functions.php                           *
8  * -------------------------------------------------------------------- *
9  * Short description : Template functions                               *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Template-Funktionen                              *
12  * -------------------------------------------------------------------- *
13  * Copyright (c) 2003 - 2009 by Roland Haeder                           *
14  * Copyright (c) 2009 - 2013 by Mailer Developer Team                   *
15  * For more information visit: http://mxchange.org                      *
16  *                                                                      *
17  * This program is free software; you can redistribute it and/or modify *
18  * it under the terms of the GNU General Public License as published by *
19  * the Free Software Foundation; either version 2 of the License, or    *
20  * (at your option) any later version.                                  *
21  *                                                                      *
22  * This program is distributed in the hope that it will be useful,      *
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
25  * GNU General Public License for more details.                         *
26  *                                                                      *
27  * You should have received a copy of the GNU General Public License    *
28  * along with this program; if not, write to the Free Software          *
29  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
30  * MA  02110-1301  USA                                                  *
31  ************************************************************************/
32
33 // Some security stuff...
34 if (!defined('__SECURITY')) {
35         die();
36 } // END - if
37
38 // Wrapper until we merged to the EL branch
39 function preCompileCode ($code, $full = TRUE) {
40         return compileCode($code, $full);
41 }
42
43 // Setter for 'is_template_html'
44 function enableTemplateHtml ($enable = TRUE) {
45         $GLOBALS['is_template_html'] = (bool) $enable;
46 }
47
48 // Checks whether the template is HTML or not by previously set flag
49 // Default: true
50 function isTemplateHtml () {
51         // Is the output_mode other than 0 (HTML), then no comments are enabled
52         if (!isHtmlOutputMode()) {
53                 // No HTML
54                 return FALSE;
55         } else {
56                 // Maybe HTML?
57                 return $GLOBALS['is_template_html'];
58         }
59 }
60
61 // Wrapper for writing debug informations to the browser
62 function debugOutput ($message) {
63         outputHtml('<div class="debug_message">' . $message . '</div>');
64 }
65
66 // "Fixes" an empty string into three dashes (use for templates)
67 function fixEmptyContentToDashes ($str) {
68         // Call inner function
69         $str = fixNullEmptyToDashes($str, 3);
70
71         // Return string
72         return $str;
73 }
74
75 // Init color switch
76 function initTemplateColorSwitch ($template) {
77         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'INIT:' . $template);
78         $GLOBALS['color_switch'][$template] = 2;
79 }
80
81 // "Getter" for color switch code
82 function getColorSwitchCode ($template) {
83         // Prepare the code
84         $code = "{DQUOTE} . doTemplateColorSwitch('" . $template . "', FALSE, FALSE) . {DQUOTE}";
85
86         // And return it
87         return $code;
88 }
89
90 // Output HTML code directly or 'render' it. You addionally switch the new-line character off
91 function outputHtml ($htmlCode = NULL, $newLine = TRUE) {
92         // Init output
93         if (!isset($GLOBALS['__output'])) {
94                 $GLOBALS['__output'] = '';
95         } // END - if
96
97         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'getOutputMode()=' . getOutputMode() . ',htmlCode(length)=' . strlen($htmlCode) . ',output(length)=' . strlen($GLOBALS['__output']));
98         // Is there HTML-Code here?
99         if ((!is_null($htmlCode)) && (!empty($htmlCode))) {
100                 // Yes, so we handle it as you have configured
101                 switch (getOutputMode()) {
102                         case 'render':
103                                 // But if PHP is caching, then we don't need to do that
104                                 if (getPhpCaching() == 'on') {
105                                         // Output into PHP's internal buffer
106                                         outputRawCode($htmlCode);
107
108                                         // That's why you don't need any \n at the end of your HTML code... :-)
109                                         if ($newLine === TRUE) {
110                                                 outputRawCode(PHP_EOL);
111                                         } // END - if
112                                 } else {
113                                         // Render mode for old or lame servers...
114                                         $GLOBALS['__output'] .= $htmlCode;
115
116                                         // That's why you don't need any \n at the end of your HTML code... :-)
117                                         if ($newLine === TRUE) {
118                                                 $GLOBALS['__output'] .= PHP_EOL;
119                                         } // END - if
120                                 }
121                                 break;
122
123                         case 'direct':
124                                 // If we are switching from 'render' to 'direct' mode, all data in '__output' must be flushed and cleared
125                                 if ((!empty($GLOBALS['__output'])) && (getPhpCaching() != 'on')) {
126                                         outputRawCode($GLOBALS['__output']);
127                                         $GLOBALS['__output'] = '';
128                                 } // END - if
129
130                                 // The same as above... ^
131                                 outputRawCode($htmlCode);
132                                 if ($newLine === TRUE) {
133                                         outputRawCode(PHP_EOL);
134                                 } // END - if
135                                 break;
136
137                         default:
138                                 // Huh, something goes wrong or maybe you have edited config.php ???
139                                 reportBug(__FUNCTION__, __LINE__, '<strong>{--FATAL_ERROR--}:</strong> {--NO_RENDER_DIRECT--}');
140                                 break;
141                 } // END - switch
142         } elseif ((getPhpCaching() == 'on') && (!isFilledArray($GLOBALS['http_header'])) && (!isRawOutputMode())) {
143                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'getPhpCaching()=' . getPhpCaching() . ',isset(http_header)=' . intval(isset($GLOBALS['http_header'])) . ',getScriptOutputMode()=' . getScriptOutputMode() . '');
144                 // Output cached HTML code
145                 $GLOBALS['__output'] = ob_get_contents();
146
147                 // Clear output buffer for later output if output is found
148                 if (!empty($GLOBALS['__output'])) {
149                         clearOutputBuffer();
150                 } // END - if
151
152                 // Send all HTTP headers
153                 sendHttpHeaders();
154
155                 // Compile and run finished rendered HTML code
156                 compileFinalOutput();
157
158                 // Output code here, DO NOT REMOVE! ;-)
159                 outputRawCode($GLOBALS['__output']);
160         } elseif ((getOutputMode() == 'render') && (!empty($GLOBALS['__output'])) && (!isRawOutputMode())) {
161                 // Send all HTTP headers
162                 sendHttpHeaders();
163
164                 // Compile and run finished rendered HTML code
165                 compileFinalOutput();
166
167                 // Output code here, DO NOT REMOVE! ;-)
168                 outputRawCode($GLOBALS['__output']);
169         } else {
170                 // And flush all headers
171                 flushHttpHeaders();
172         }
173 }
174
175 // Compiles the final output
176 function compileFinalOutput () {
177         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, '__output(length)=' . strlen($GLOBALS['__output']) . ',getScriptOutputMode()=' . getScriptOutputMode() . ' - ENTERED!');
178         // Is this function called?
179         if (isset($GLOBALS[__FUNCTION__])) {
180                 // Abort here
181                 reportBug(__FUNCTION__, __LINE__, 'Double call of ' . __FUNCTION__ . ' causes problems with sent headers.');
182         } // END - if
183
184         // Mark this function as called
185         $GLOBALS[__FUNCTION__] = TRUE;
186
187         // Add page header and footer
188         addPageHeaderFooter();
189         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, '__output(length)=' . strlen($GLOBALS['__output']) . ' - After addPageHeaderFooter() call.');
190
191         // Do the final (general) compilation
192         $GLOBALS['__output'] = doFinalCompilation($GLOBALS['__output']);
193
194         // Compile any other things out
195         $GLOBALS['__output'] = compileUriCode($GLOBALS['__output']);
196
197         // Extension 'rewrite' installed?
198         if ((isExtensionActive('rewrite')) && (!isCssOutputMode())) {
199                 $GLOBALS['__output'] = rewriteLinksInCode($GLOBALS['__output']);
200         } // END - if
201
202         // Compress it?
203         /**
204          * @TODO On some pages this is buggy
205         if (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && (isInStringIgnoreCase('gzip', $_SERVER['HTTP_ACCEPT_ENCODING']))) {
206                 // Compress it for HTTP gzip
207                 $GLOBALS['__output'] = gzencode($GLOBALS['__output'], 9);
208
209                 // Add header
210                 addHttpHeader('Content-Encoding: gzip');
211         } elseif (!empty($_SERVER['HTTP_ACCEPT_ENCODING']) && (isInStringIgnoreCase('deflate', $_SERVER['HTTP_ACCEPT_ENCODING']))) {
212                 // Compress it for HTTP deflate
213                 $GLOBALS['__output'] = gzcompress($GLOBALS['__output'], 9);
214
215                 // Add header
216                 addHttpHeader('Content-Encoding: deflate');
217         }
218         */
219
220         // Add final length
221         addHttpHeader('Content-Length: ' . strlen($GLOBALS['__output']));
222
223         // Flush all headers
224         flushHttpHeaders();
225 }
226
227 // Main compilation loop
228 function doFinalCompilation ($code, $insertComments = TRUE, $enableCodes = TRUE) {
229         // Insert comments? (Only valid with HTML templates, of course)
230         enableTemplateHtml($insertComments);
231
232         // Init counter
233         $totalCompilations = 0;
234
235         // Compile all out
236         while (((isInString('{--', $code)) || (isInString('{DQUOTE}', $code)) || (isInString('{?', $code)) || (isInString('{%', $code) !== FALSE)) && ($totalCompilations < 7)) {
237                 // Init common variables
238                 $content = array();
239                 $newContent = '';
240
241                 // Compile it
242                 //* DEBUG: */ debugOutput('<pre>'.lineNumberCode($code).'</pre>');
243                 $eval = '$newContent = "' . str_replace('{DQUOTE}', '"', compileCode(escapeQuotes($code), $enableCodes)) . '";';
244                 //* DEBUG: */ if (!$insertComments) print('EVAL=<pre>'.lineNumberCode($eval).'</pre>');
245                 eval($eval);
246                 //* DEBUG: */ if (!$insertComments) print('NEW=<pre>'.lineNumberCode($newContent).'</pre>');
247                 //* DEBUG: */ die('<pre>'.encodeEntities($newContent).'</pre>');
248
249                 // Was that eval okay?
250                 if (empty($newContent)) {
251                         // Something went wrong!
252                         reportBug(__FUNCTION__, __LINE__, 'Evaluation error:<pre>' . lineNumberCode($eval) . '</pre>', FALSE);
253                 } // END - if
254
255                 // Use it again
256                 $code = $newContent;
257
258                 // Compile the final code if insertComments is true
259                 if ($insertComments == TRUE) {
260                         // ... because SQL queries shall keep OPEN_CONFIG and such in
261                         $code = compileRawCode($code);
262                 } // END - if
263
264                 // Count round
265                 $totalCompilations++;
266         } // END - while
267
268         // Add debugging data in HTML code, if mode is enabled
269         if ((isDebugModeEnabled()) && ($insertComments === TRUE) && (isHtmlOutputMode())) {
270                 // Add loop count
271                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'isDebugModeEnabled()=' . intval(isDebugModeEnabled()) . ',insertComments=' . intval($insertComments) . ',isHtmlOutputMode()=' . intval(isHtmlOutputMode()));
272                 $code .= '<!-- Total compilation loop=' . $totalCompilations . ' //-->';
273         } // END - if
274
275         // Return the compiled code
276         return $code;
277 }
278
279 // Output the raw HTML code
280 function outputRawCode ($htmlCode) {
281         // Output stripped HTML code to avoid broken JavaScript code, etc.
282         print(str_replace('{BACK}', chr(92), $htmlCode));
283
284         // Flush the output if only getPhpCaching() is not 'on'
285         if (getPhpCaching() != 'on') {
286                 // Flush it
287                 flush();
288         } // END - if
289 }
290
291 // Load a template file and return it's content (only it's name; do not use ' or ")
292 function loadTemplate ($template, $return = FALSE, $content = array(), $compileCode = TRUE) {
293         // @TODO Remove these sanity checks if all is fine
294         if (!is_bool($return)) {
295                 // $return has to be boolean
296                 reportBug(__FUNCTION__, __LINE__, 'return[] is not bool (' . gettype($return) . ')');
297         } elseif (!is_string($template)) {
298                 // $template has to be string
299                 reportBug(__FUNCTION__, __LINE__, 'template[] is not string (' . gettype($template) . ')');
300         }
301
302         // Init returned content
303         $templateContent = '';
304
305         // Set current template
306         $GLOBALS['current_template'] = $template;
307
308         // Is there cache?
309         if ((!isDebugTemplateCacheEnabled()) && (isTemplateCached('html', $template))) {
310                 // Evaluate the cache
311                 $templateContent = readTemplateCache('html', $template, $content);
312
313                 // Better remove array element which is only needed in uncached mode
314                 unset($GLOBALS['template_eval']['html'][$template]);
315         } elseif (!isset($GLOBALS['template_eval']['html'][$template])) {
316                 // Make all template names lowercase
317                 $template = strtolower($template);
318
319                 // Base directory
320                 $basePath = getTemplateBasePath('html');
321                 $extraPath = detectExtraTemplatePath('html', $template);
322
323                 // Generate FQFN
324                 $FQFN = $basePath . '/' . $extraPath . $template . '.tpl';
325                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Template ' . $template . ' is solved to FQFN=' . $FQFN);
326
327                 // Does the special template exists?
328                 if (!isFileReadable($FQFN)) {
329                         // Reset to default template
330                         $FQFN = $basePath . '/' . $template . '.tpl';
331                 } // END - if
332
333                 // Now does the final template exists?
334                 if (isFileReadable($FQFN)) {
335                         // Count the template load
336                         incrementConfigEntry('num_templates');
337
338                         // The local file does exists so we load it. :)
339                         $GLOBALS['template_content']['html'][$template] = readFromFile($FQFN);
340
341                         // Is there to compile the code?
342                         if ((isInString('$', $GLOBALS['template_content']['html'][$template])) || (isInString('{--', $GLOBALS['template_content']['html'][$template])) || (isInString('{?', $GLOBALS['template_content']['html'][$template])) || (isInString('{%', $GLOBALS['template_content']['html'][$template]))) {
343                                 // Normal HTML output?
344                                 if ((isHtmlOutputMode()) && (substr($template, 0, 3) != 'js_')) {
345                                         // Add surrounding HTML comments to help finding bugs faster
346                                         $code = '<!-- Template ' . $template . ' - Start //-->' . $GLOBALS['template_content']['html'][$template] . '<!-- Template ' . $template . ' - End //-->';
347
348                                         // Prepare eval() command
349                                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
350                                         $GLOBALS['template_eval']['html'][$template] = '$templateContent = "' . getColorSwitchCode($template) . compileCode(escapeQuotes($code), TRUE, $compileCode) . '";';
351                                 } elseif (substr($template, 0, 3) == 'js_') {
352                                         // JavaScripts don't like entities, dollar signs and timings
353                                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
354                                         $GLOBALS['template_eval']['html'][$template] = '$templateContent = decodeEntities("' . escapeJavaScriptQuotes($GLOBALS['template_content']['html'][$template]) . '");';
355                                 } elseif (isAjaxOutputMode()) {
356                                         // AJAX (JSON content)
357                                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
358                                         $GLOBALS['template_eval']['html'][$template] = '$templateContent = "' . escapeJavaScriptQuotes($GLOBALS['template_content']['html'][$template]) . '";';
359                                 } else {
360                                         // Prepare eval() command, other output doesn't like entities, maybe
361                                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
362                                         $GLOBALS['template_eval']['html'][$template] = '$templateContent = decodeEntities("' . compileRawCode(escapeQuotes($GLOBALS['template_content']['html'][$template]), TRUE, $compileCode) . '");';
363                                 }
364                         } elseif (isHtmlOutputMode()) {
365                                 // Add surrounding HTML comments to help finding bugs faster
366                                 $templateContent = '<!-- Template ' . $template . ' - Start //-->' . $GLOBALS['template_content']['html'][$template] . '<!-- Template ' . $template . ' - End //-->';
367                                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
368                                 $GLOBALS['template_eval']['html'][$template] = '$templateContent = "' . getColorSwitchCode($template) . compileRawCode(escapeQuotes($templateContent), TRUE, $compileCode) . '";';
369                         } elseif (isAjaxOutputMode()) {
370                                 // AJAX (JSON content)
371                                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
372                                 $GLOBALS['template_eval']['html'][$template] = '$templateContent = "' . escapeJavaScriptQuotes($GLOBALS['template_content']['html'][$template]) . '";';
373                         } else {
374                                 // JavaScript again
375                                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
376                                 $GLOBALS['template_eval']['html'][$template] = '$templateContent = decodeEntities("' . escapeJavaScriptQuotes($GLOBALS['template_content']['html'][$template]) . '");';
377                         } // END - if
378                 } elseif ((isAdmin()) || ((isInstalling()) && (!isInstalled()))) {
379                         // Only admins shall see this warning or when installation mode is active
380                         $templateContent = '<div class="para">
381         {--TEMPLATE_404--}
382 </div>
383 <div class="para">
384         (' . $template . ')
385 </div>
386 <div class="para">
387         {--TEMPLATE_CONTENT--}:
388         <pre>' . print_r($content, TRUE) . '</pre>
389 </div>';
390                 } else {
391                         // No file!
392                         $GLOBALS['template_eval']['html'][$template] = '404';
393                 }
394         }
395
396         // Code set?
397         if ((isset($GLOBALS['template_eval']['html'][$template])) && ($GLOBALS['template_eval']['html'][$template] != '404')) {
398                 // Eval the code
399                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'template=' . $template . ' - BEFORE EVAL');
400                 ///* DEBUG: */ print('<pre>'.htmlentities($GLOBALS['template_eval']['html'][$template]).'</pre>');
401                 eval($GLOBALS['template_eval']['html'][$template]);
402                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'template=' . $template . ' - AFTER EVAL');
403         } // END - if
404
405         // Is there some content to output or return?
406         if ((empty($templateContent)) && (isDebugModeEnabled())) {
407                 // Warning, empty output!
408                 return 'E:' . $template . ',content=<pre>' . print_r($content, TRUE) . '</pre>';
409         } // END - if
410
411         // Not empty so let's put it out! ;)
412         if ($return === TRUE) {
413                 // Return the HTML code
414                 return $templateContent;
415         } else {
416                 // Output directly
417                 outputHtml($templateContent);
418         }
419 }
420
421 // Detects the extra template path from given template name
422 function detectExtraTemplatePath ($prefix, $template) {
423         // Default is empty
424         $extraPath = '';
425
426         // Is there cache?
427         if (!isset($GLOBALS['extra_path'][$prefix][$template])) {
428                 // Check for admin/guest/member/etc. templates
429                 if (substr($template, 0, 6) == 'admin_') {
430                         // Admin template found
431                         $extraPath = 'admin/';
432                 } elseif (substr($template, 0, 6) == 'guest_') {
433                         // Guest template found
434                         $extraPath = 'guest/';
435                 } elseif (substr($template, 0, 7) == 'member_') {
436                         // Member template found
437                         $extraPath = 'member/';
438                 } elseif (substr($template, 0, 7) == 'select_') {
439                         // Selection template found
440                         $extraPath = 'select/';
441                 } elseif (substr($template, 0, 8) == 'install_') {
442                         // Installation template found
443                         $extraPath = 'install/';
444                 } elseif (substr($template, 0, 4) == 'ext_') {
445                         // Extension template found
446                         $extraPath = 'ext/';
447                 } elseif (substr($template, 0, 3) == 'la_') {
448                         // 'Logical-area' template found
449                         $extraPath = 'la/';
450                 } elseif (substr($template, 0, 3) == 'js_') {
451                         // JavaScript template found
452                         $extraPath = 'js/';
453                 } elseif (substr($template, 0, 5) == 'menu_') {
454                         // Menu template found
455                         $extraPath = 'menu/';
456                 } else {
457                         // Test for extension
458                         $test = substr($template, 0, strpos($template, '_'));
459
460                         // Probe for valid extension name
461                         if (isExtensionNameValid($test)) {
462                                 // Set extra path to extension's name
463                                 $extraPath = $test . '/';
464                         } // END - if
465                 }
466
467                 // Store it in cache
468                 $GLOBALS['extra_path'][$prefix][$template] = $extraPath;
469         } // END - if
470
471         // Return result
472         return $GLOBALS['extra_path'][$prefix][$template];
473 }
474
475 // Loads an email template and compiles it
476 function loadEmailTemplate ($template, $content = array(), $userid = NULL, $loadUserData = TRUE) {
477         // Make sure all template names are lowercase!
478         $template = strtolower($template);
479
480         // Set current template
481         $GLOBALS['current_template'] = $template;
482
483         // Is content an array?
484         if (is_array($content)) {
485                 // Add expiration to array
486                 if ((isExtensionInstalled('autopurge')) && (isConfigEntrySet('auto_purge')) && (getAutoPurge() == '0')) {
487                         // Will never expire!
488                         $content['expiration'] = '{--MAIL_WILL_NEVER_EXPIRE--}';
489                 } elseif ((isExtensionInstalled('autopurge')) && (isConfigEntrySet('auto_purge'))) {
490                         // Create nice date string
491                         $content['expiration'] = '{%config,createFancyTime=auto_purge%}';
492                 } else {
493                         // Missing entry
494                         $content['expiration'] = '{--MAIL_NO_CONFIG_AUTO_PURGE--}';
495                 }
496         } // END - if
497
498         // Is there cache?
499         if ((!isDebugTemplateCacheEnabled()) && (isTemplateCached('email', $template))) {
500                 // Evaluate the cache
501                 $templateContent = readTemplateCache('email', $template, $content);
502
503                 // Better remove array element which is need only in uncached mode
504                 unset($GLOBALS['template_eval']['email'][$template]);
505         } elseif (!isset($GLOBALS['template_eval']['email'][$template])) {
506                 // Base directory
507                 $basePath = getTemplateBasePath('emails');
508
509                 // Detect extra path
510                 $extraPath = detectExtraTemplatePath('email', $template);
511
512                 // Generate full FQFN
513                 $FQFN = $basePath . '/' . $extraPath . $template . '.tpl';
514
515                 // Does the special template exists?
516                 if (!isFileReadable($FQFN)) {
517                         // Reset to default template
518                         $FQFN = $basePath . '/' . $template . '.tpl';
519                 } // END - if
520
521                 // Now does the final template exists?
522                 $templateContent = '';
523                 if (isFileReadable($FQFN)) {
524                         // The local file does exists so we load it. :)
525                         $GLOBALS['template_content']['email'][$template] = readFromFile($FQFN);
526
527                         // Run code
528                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Reached!');
529                         $GLOBALS['template_eval']['email'][$template] = '$templateContent = decodeEntities("' . compileRawCode(escapeQuotes($GLOBALS['template_content']['email'][$template])) . '");';
530                 } elseif (!empty($template)) {
531                         // Template file not found
532                         $templateContent = '<div class="para">
533         {--TEMPLATE_404--}: ' . $template . '
534 </div>
535 <div class="para">
536         {--TEMPLATE_CONTENT--}:
537         <pre>' . print_r($content, TRUE) . '</pre>
538 </div>';
539
540                         // Don't cache this, as there is no template to cache
541                         $GLOBALS['template_eval']['email'][$template] = '404';
542
543                         // Debug mode not active? Then remove the HTML tags
544                         if (!isDebugModeEnabled()) {
545                                 // Remove HTML tags
546                                 $templateContent = secureString($templateContent);
547                         } // END - if
548                 } else {
549                         // No template name supplied!
550                         $templateContent = '{--NO_TEMPLATE_SUPPLIED--}';
551                         $GLOBALS['template_eval']['email'][$template] = '404';
552                 }
553         }
554
555         // Is there something to eval?
556         if ((isset($GLOBALS['template_eval']['email'][$template])) && ($GLOBALS['template_eval']['email'][$template] != '404')) {
557                 // Eval the code
558                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'template=' . $template . ' - BEFORE EVAL');
559                 //* DEBUG: */ print('<pre>'.htmlentities($GLOBALS['template_eval']['email'][$template]).'</pre>');
560                 //* DEBUG: */ die('<pre>'.print_r($content, TRUE).'</pre><pre>'.htmlentities($GLOBALS['template_eval']['email'][$template]).'</pre>');
561                 eval($GLOBALS['template_eval']['email'][$template]);
562                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'template=' . $template . ' - AFTER EVAL');
563         } // END - if
564
565         // Are there some content?
566         if (empty($templateContent)) {
567                 // Compiling failed
568                 $templateContent = "Compiler error for template " . $template . " !\nUncompiled content:\n" . $GLOBALS['template_eval']['email'][$template];
569
570                 // Add last error if the required function exists
571                 if (function_exists('error_get_last')) {
572                         // Add last error and some lines for better overview
573                         $templateContent .= "\n--------------------------------------\nDebug:\n" . print_r(error_get_last(), TRUE) . "--------------------------------------\nPlease don't alter these informations!\nThanx.";
574                 } // END - if
575         } // END - if
576
577         // Remove content and data
578         unset($content);
579
580         // Return content
581         return $templateContent;
582 }
583
584 // "Getter" for menu CSS classes, mainly used in templates
585 function getMenuCssClasses ($data) {
586         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'data=' . $data);
587
588         // Is there cache?
589         if (!isset($GLOBALS[__FUNCTION__][$data])) {
590                 // $data needs to be converted into an array
591                 $content = explode('|', $data);
592
593                 // Non-existent index 2 will happen in menu blocks
594                 if (!isset($content[2])) {
595                         $content[2] = '';
596                 } // END - if
597
598                 // Re-construct the array: 0=visible,1=locked,2=prefix
599                 $content['visible'] = $content[0];
600                 $content['locked']  = $content[1];
601
602                 // Call our "translator" function
603                 $content = translateMenuVisibleLocked($content, $content[2]);
604
605                 // Set it in cache
606                 $GLOBALS[__FUNCTION__][$data] = ($content['visible_css'] . ' ' . $content['locked_css']);
607         } // END - if
608
609         // Return cache
610         return $GLOBALS[__FUNCTION__][$data];
611 }
612
613 // Generate XHTML code for the CAPTCHA
614 function generateCaptchaCode ($code, $type, $urlId, $userid) {
615         return '<img border="0" alt="Code ' . $code . '" src="{%url=mailid.php?userid=' . $userid . '&amp;' . $type . '=' . $urlId . '&amp;do=img&amp;code=' . $code . '%}" />';
616 }
617
618 // Compiles the given HTML/mail code
619 function compileCode ($code, $full = TRUE, $compileCode = TRUE) {
620         // Is the code a string or should we not compile?
621         if ((!is_string($code)) || ($compileCode === FALSE)) {
622                 // Silently return it
623                 return $code;
624         } // END - if
625
626         // Start couting
627         $startCompile = microtime(TRUE);
628
629         // Comile the code
630         $code = compileRawCode($code, $full, $compileCode);
631
632         // Get timing
633         $compilationTime = $startCompile - microtime(TRUE);
634
635         // Add timing if enabled
636         if (isTemplateHtml()) {
637                 // Add timing, this should be disabled in
638                 $code .= '<!-- Compilation time: ' . ($compilationTime * 1000). 'ms //-->';
639         } // END - if
640
641         // Return compiled code
642         return $code;
643 }
644
645 // Compiles the code
646 function compileRawCode ($code, $full = TRUE, $compileCode = TRUE) {
647         //* DIE: */ reportBug(__FUNCTION__, __LINE__, 'Called with ' . strlen($code) . ' code length.');
648         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Called with code()=' . strlen($code) . ',full=' . intval($full) . ',compileCode=' . intval($compileCode));
649
650         // Is the code a string or shall we not compile?
651         if ((!is_string($code)) || ($compileCode === FALSE)) {
652                 // Silently return it
653                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code[]= ' . gettype($code) . ' is not a string or compileCode(' . intval($compileCode) . ') is FALSE.');
654                 return $code;
655         } // END - if
656
657         // Init replacement-array with smaller set of security characters
658         $secChars = $GLOBALS['url_chars'];
659
660         // Select full set of chars to replace when we e.g. want to compile URLs
661         if ($full === TRUE) {
662                 $secChars = $GLOBALS['security_chars'];
663         } // END - if
664
665         // First compile these chars
666         array_unshift($secChars['to']  , '{--'       , '--}');
667         array_unshift($secChars['from'], '{%message,', '%}' );
668
669         // Replace QUOT and other non-HTML codes
670         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code()=' . strlen($code) . ' - before str_replace() ...');
671         $code = str_replace($secChars['to'], $secChars['from'], $code);
672         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code()=' . strlen($code) . ' - after str_replace() ...');
673
674         // Compile the prepared code through a filter chain
675         $code = runFilterChain('compile_code', $code);
676
677         // Find all $content[bla][blub] entries
678         preg_match_all('/\$content((\[([a-zA-Z0-9-_]+)\])*)/', $code, $matches);
679         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Second regex gave ' . count($matches[0]) . ' matches.');
680
681         // Are some matches found?
682         if ((isFilledArray($matches)) && (isFilledArray($matches[0]))) {
683                 // Replace all matches
684                 $matchesFound = array();
685                 foreach ($matches[0] as $key => $match) {
686                         // Fuzzy look has failed by default
687                         $fuzzyFound = FALSE;
688
689                         // "Cache" match length
690                         $matchLength = strlen($match);
691
692                         // Fuzzy look on match if already found
693                         foreach ($matchesFound as $found => $set) {
694                                 // Get test part
695                                 $test = substr($found, 0, $matchLength);
696
697                                 // Does this entry exist?
698                                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'found=' . $found . ',match=' . $match . ',set=' . $set);
699                                 if ($test == $match) {
700                                         // Match found
701                                         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'fuzzyFound!');
702                                         $fuzzyFound = TRUE;
703                                         break;
704                                 } // END - if
705                         } // END - foreach
706
707                         // Skip this entry?
708                         if ($fuzzyFound === TRUE) {
709                                 continue;
710                         } // END - if
711
712                         // Take all string elements
713                         if ((is_string($matches[3][$key])) && (!isset($matchesFound[$match])) && (!isset($matchesFound[$key.'_' . $matches[3][$key]]))) {
714                                 // Replace it in the code, replace dollar sign so it won't be detected by next regex (see there)
715                                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',match=' . $match);
716                                 $newMatch = str_replace(array('[', ']', '$'), array("['", "']", '{COMPILE_DOLLAR}'), $match);
717                                 $code = str_replace($match, '".' . $newMatch . '."', $code);
718                                 $matchesFound[$key . '_' . $matches[3][$key]] = 1;
719                                 $matchesFound[$match] = TRUE;
720                         } elseif (!isset($matchesFound[$match])) {
721                                 // Not yet replaced!
722                                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'match=' . $match);
723                                 $code = str_replace($match, '".' . $match . '."', $code);
724                                 $matchesFound[$match] = 1;
725                         } else {
726                                 // Everthing else should be a least logged
727                                 logDebugMessage(__FUNCTION__, __LINE__, 'match=' . $match . ',key=' . $key);
728                         }
729                 } // END - foreach
730         } // END - if
731
732         /*
733          * Find $foobar, $foo_bar and $fooBar entries. This regex would also find
734          * $content[foo_bar] which would result in {DOLLAR}content[foo_bar] and
735          * therefore the variable's value won't be inserted. This is why
736          * {COMPILE_DOLLAR} is being used in above loop and at the end of this
737          * function being replace with the original dollar sign again.
738          */
739         preg_match_all('/\$([a-z_A-Z\[\]]){0,}/', $code, $matches);
740
741         // Are some matches found?
742         if ((isFilledArray($matches)) && (isFilledArray($matches[0]))) {
743                 // Scan all matches for not $content
744                 foreach ($matches[0] as $match) {
745                         // Trim match
746                         $match = trim($match);
747
748                         // Debug message
749                         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'match=' . $match);
750
751                         // Is the first part not $content/$userid and not empty?
752                         // @TODO $userid is deprecated and should be removed from loadEmailTemplate() and replaced with $content[userid] in all templates
753                         if ((!empty($match)) && (substr($match, 0, 8) != '$content') && ($match != '$userid')) {
754                                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'match=' . $match . ' - SECURED!');
755                                 // Then replace $ with {DOLLAR}
756                                 $matchSecured = str_replace('$', '{DOLLAR}', $match);
757
758                                 // And in $code as well
759                                 $code = str_replace($match, $matchSecured, $code);
760                         } // END - if
761                 } // END - if
762         } // END - if
763
764         // Add 'COMPILE_DOLLAR' again
765         array_push($secChars['to']  , '{COMPILE_DOLLAR}');
766         array_push($secChars['from'], '$');
767
768         // Replace QUOT and other non-HTML codes
769         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code()=' . strlen($code) . ' - before str_replace() ...');
770         $code = str_replace($secChars['to'], $secChars['from'], $code);
771         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code()=' . strlen($code) . ' - after str_replace() ...');
772
773         // Finally return it
774         //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Exiting with code()=' . strlen($code));
775         return $code;
776 }
777
778 //
779 function addSelectionBox ($type, $default, $prefix = '', $id = NULL, $class = 'form_select') {
780         $OUT = '';
781
782         if ($type == 'yn') {
783                 // This is a yes/no selection only!
784                 if (isValidId($id)) $prefix .= '[' . $id . ']';
785                 $OUT .= '<select name="' . $prefix . '" class="' . $class . '" size="1">';
786         } else {
787                 // Begin with regular selection box here
788                 if (!empty($prefix)) $prefix .= '_';
789                 $type2 = $type;
790                 if (isValidId($id)) $type2 .= '[' . $id . ']';
791                 $OUT .= '<select name="' . strtolower($prefix . $type2) . '" class="' . $class . '" size="1">';
792         }
793
794         switch ($type) {
795                 case 'ye': // Years
796                         // Get current year
797                         $year = getYear();
798
799                         // Use configured min age or fixed?
800                         if (isExtensionInstalledAndNewer('other', '0.2.1')) {
801                                 // Configured
802                                 $startYear = $year - getMinAge();
803                         } else {
804                                 // Fixed 16 years
805                                 $startYear = $year - 16;
806                         }
807
808                         // Calculate earliest year (100 years old people can still enter Internet???)
809                         $minYear = $year - 100;
810
811                         // Check if the default value is larger than minimum and bigger than actual year
812                         if (($default > $minYear) && ($default >= $year)) {
813                                 for ($idx = $year; $idx < ($year + 11); $idx++) {
814                                         $OUT .= '<option value="' . $idx . '"';
815                                         if ($default == $idx) $OUT .= ' selected="selected"';
816                                         $OUT .= '>' . $idx . '</option>';
817                                 } // END - for
818                         } elseif ($default == -1) {
819                                 // Current year minus 1
820                                 for ($idx = $startYear; $idx <= ($year + 1); $idx++) {
821                                         $OUT .= '<option value="' . $idx . '">' . $idx . '</option>';
822                                 } // END - for
823                         } else {
824                                 // Get current year and subtract the configured minimum age
825                                 $OUT .= '<option value="' . ($minYear - 1) . '">&lt;' . $minYear . '</option>';
826
827                                 // Construct year selection list
828                                 for ($idx = $minYear; $idx <= $startYear; $idx++) {
829                                         $OUT .= '<option value="' . $idx . '"';
830                                         if ($default == $idx) $OUT .= ' selected="selected"';
831                                         $OUT .= '>' . $idx . '</option>';
832                                 } // END - for
833                         }
834                         break;
835
836                 case 'mo': // Months
837                         foreach ($GLOBALS['month_descr'] as $idx => $descr) {
838                                 $OUT .= '<option value="' . $idx . '"';
839                                 if ($default == $idx) $OUT .= ' selected="selected"';
840                                 $OUT .= '>' . $descr . '</option>';
841                         } // END - for
842                         break;
843
844                 case 'mn': // Months, numeric
845                         for ($idx = 0; $idx <= 12; $idx++) {
846                                 $OUT .= '<option value="' . $idx . '"';
847                                 if ($default == $idx) $OUT .= ' selected="selected"';
848                                 $OUT .= '>{%pipe,padLeftZero=' . $idx . '%}</option>';
849                         } // END - for
850                         break;
851
852                 case 'we': // Weeks
853                         for ($idx = 0; $idx <= 4; $idx++) {
854                                 $OUT .= '  <option value="' . $idx . '"';
855                                 if ($default == $idx) $OUT .= ' selected="selected"';
856                                 $OUT .= '>' . $idx . '</option>';
857                         } // END - for
858                         break;
859
860                 case 'da': // Days
861                         for ($idx = 0; $idx <= 31; $idx++) {
862                                 $OUT .= '<option value="' . $idx . '"';
863                                 if ($default == $idx) $OUT .= ' selected="selected"';
864                                 $OUT .= '>{%pipe,padLeftZero=' . $idx . '%}</option>';
865                         } // END - for
866                         break;
867
868                 case 'ho': // Hours
869                         for ($idx = 0; $idx <= 23; $idx++) {
870                                 $padded = padLeftZero($idx, 2);
871                                 $OUT .= '<option value="' . $padded . '"';
872                                 if ($default == $padded) $OUT .= ' selected="selected"';
873                                 $OUT .= '>' . $padded . '</option>';
874                         } // END - for
875                         break;
876
877                 case 'mi': // Minutes
878                 case 'se': // Seconds
879                         for ($idx = 0; $idx <= 59; $idx+=5) {
880                                 $padded = padLeftZero($idx, 2);
881                                 $OUT .= '<option value="' . $padded . '"';
882                                 if ($default == $padded) $OUT .= ' selected="selected"';
883                                 $OUT .= '>' . $padded . '</option>';
884                         } // END - for
885                         break;
886
887                 case 'yn': // Yes/No
888                         $OUT .= '<option value="Y"';
889                         if ($default == 'Y') $OUT .= ' selected="selected"';
890                         $OUT .= '>{--YES--}</option><option value="N"';
891                         if ($default != 'Y') $OUT .= ' selected="selected"';
892                         $OUT .= '>{--NO--}</option>';
893                         break;
894
895                 default: // Not detected
896                         reportBug(__FUNCTION__, __LINE__, 'type=' . $type . ',default=' . $default . ',prefix=' .  $prefix . ',id[' . gettype($id) . ']=' . $id . ',class=' . $class . ' - is not supported.');
897                         break;
898         }
899         $OUT .= '</select>';
900         return $OUT;
901 }
902
903 // Insert the code in $img_code into jpeg or PNG image
904 function generateImageOrCode ($img_code, $headerSent = TRUE) {
905         // Is the code size oversized or shouldn't we display it?
906         if ((strlen($img_code) > 6) || (empty($img_code)) || (getCodeLength() == '0')) {
907                 // Stop execution of function here because of over-sized code length
908                 reportBug(__FUNCTION__, __LINE__, 'img_code ' . $img_code .' has invalid length. img_code(length)=' . strlen($img_code) . ' code_length=' . getCodeLength());
909         } elseif ($headerSent === FALSE) {
910                 // Return an HTML code here
911                 return '<img src="{%url=img.php?code=' . $img_code . '%}" alt="Image" />';
912         }
913
914         // Load image
915         $img = sprintf('%s/theme/%s/images/code_bg.%s',
916                 getPath(),
917                 getCurrentTheme(),
918                 getImgType()
919         );
920
921         // Is it readable?
922         if (isFileReadable($img)) {
923                 // Switch image type
924                 switch (getImgType()) {
925                         case 'jpg': // Okay, load image and hide all errors
926                                 $image = imagecreatefromjpeg($img);
927                                 break;
928
929                         case 'png': // Okay, load image and hide all errors
930                                 $image = imagecreatefrompng($img);
931                                 break;
932                 } // END - switch
933         } else {
934                 // Silently log the error
935                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('File for image-type %s in theme %s not found.', getImgType(), getCurrentTheme()));
936                 return;
937         }
938
939         // Generate text color (red/green/blue; 0 = dark, 255 = bright)
940         $text_color = imagecolorallocate($image, 0, 0, 0);
941
942         // Insert code into image
943         imagestring($image, 5, 14, 2, $img_code, $text_color);
944
945         // Return to browser
946         setContentType('image/' . getImgType());
947
948         // Output image with matching image factory
949         switch (getImgType()) {
950                 case 'jpg': imagejpeg($image); break;
951                 case 'png': imagepng($image);  break;
952         } // END - switch
953
954         // Remove image from memory
955         imagedestroy($image);
956 }
957
958 // Create selection box or array of splitted timestamp
959 function createTimeSelections ($timestamp, $prefix = '', $display = '', $align = 'center', $asArray = FALSE) {
960         // Do not continue if ONE_DAY is absend
961         if (!isConfigEntrySet('ONE_DAY')) {
962                 // Abort here
963                 reportBug(__FUNCTION__, __LINE__, 'Configuration entry ONE_DAY is absend. timestamp=' . $timestamp . ',prefix=' . $prefix . ',align=' . $align . ',asArray=' . intval($asArray));
964         } // END - if
965
966         // Calculate 2-seconds timestamp
967         $stamp = round($timestamp);
968         //* DEBUG: */ debugOutput('*' . $stamp .'/' . $timestamp . '*');
969
970         // Is there a leap year?
971         $SWITCH = '0';
972         $TEST = getYear() / 4;
973         $M1 = getMonth();
974         $M2 = getMonth(time() + $timestamp);
975
976         // If so and if current time is before 02/29 and estimated time is after 02/29 then add 86400 seconds (one day)
977         if ((floor($TEST) == $TEST) && ($M1 == '02') && ($M2 > '02'))  {
978                 $SWITCH = getOneDay();
979         } // END - switch
980
981         // First of all years...
982         $year = abs(floor($timestamp / (31536000 + $SWITCH)));
983         //* DEBUG: */ debugOutput('year=' . $year);
984         // Next months...
985         $month = abs(floor($timestamp / 2628000 - $year * 12));
986         //* DEBUG: */ debugOutput('month=' . $month);
987         // Next weeks
988         $week = abs(floor($timestamp / 604800 - $year * ((365 + $SWITCH / getOneDay()) / 7) - ($month / 12 * (365 + $SWITCH / getOneDay()) / 7)));
989         //* DEBUG: */ debugOutput('week=' . $week);
990         // Next days...
991         $day = abs(floor($timestamp / 86400 - $year * (365 + $SWITCH / getOneDay()) - ($month / 12 * (365 + $SWITCH / getOneDay())) - $week * 7));
992         //* DEBUG: */ debugOutput('day=' . $day);
993         // Next hours...
994         $hour = abs(floor($timestamp / 3600 - $year * (365 + $SWITCH / getOneDay()) * 24 - ($month / 12 * (365 + $SWITCH / getOneDay()) * 24) - $week * 7 * 24 - $day * 24));
995         //* DEBUG: */ debugOutput('hour=' . $hour);
996         // Next minutes..
997         $minute = abs(floor($timestamp / 60 - $year * (365 + $SWITCH / getOneDay()) * 24 * 60 - ($month / 12 * (365 + $SWITCH / getOneDay()) * 24 * 60) - $week * 7 * 24 * 60 - $day * 24 * 60 - $hour * 60));
998         //* DEBUG: */ debugOutput('minute=' . $minute);
999         // And at last seconds...
1000         $second = abs(floor($timestamp - $year * (365 + $SWITCH / getOneDay()) * 24 * 3600 - ($month / 12 * (365 + $SWITCH / getOneDay()) * 24 * 3600) - $week * 7 * 24 * 3600 - $day * 24 * 3600 - $hour * 3600 - $minute * 60));
1001         //* DEBUG: */ debugOutput('second=' . $second);
1002
1003         // Is seconds zero and time is < 60 seconds?
1004         if (($second < 1) && ($timestamp < 60)) {
1005                 // Fix seconds
1006                 $second = round($timestamp);
1007         } // END - if
1008
1009         // Put all calculated values in array
1010         $data = array(
1011                 'Y' => $year,
1012                 'M' => $month,
1013                 'W' => $week,
1014                 'D' => $day,
1015                 'h' => $hour,
1016                 'm' => $minute,
1017                 's' => $second
1018         );
1019
1020         //
1021         // Now we convert them in seconds...
1022         //
1023         if ($asArray === TRUE) {
1024                 // Just put data array out
1025                 $OUT = $data;
1026         } else {
1027                 // Init array
1028                 $units = array(
1029                         // Time unit -> field name
1030                         'unit_field' => array(
1031                                 'Y' => 'ye',
1032                                 'M' => 'mn',
1033                                 'W' => 'we',
1034                                 'D' => 'da',
1035                                 'h' => 'ho',
1036                                 'm' => 'mi',
1037                                 's' => 'se'
1038                         ),
1039                         // Time unit -> label
1040                         'unit_label' => array(
1041                                 'Y' => 'YEAR',
1042                                 'M' => 'MONTH',
1043                                 'W' => 'WEEK',
1044                                 'D' => 'DAY',
1045                                 'h' => 'HOUR',
1046                                 'm' => 'MINUTE',
1047                                 's' => 'SECOND'
1048                         )
1049                 );
1050
1051                 // Generate table
1052                 $OUT  = '<div align="' . $align . '">';
1053                 $OUT .= '<table border="0" cellspacing="0" cellpadding="0" class="timebox_table dashed">';
1054                 $OUT .= '<tr>';
1055
1056                 // "Walk" through all units
1057                 foreach ($units['unit_field'] as $unit => $field) {
1058                         // Is this displayed or zero?
1059                         if (isInString($unit, $display) || (empty($display))) {
1060                                 // @TODO <label for="' . $prefix . '_' . $field . '"></<label> not working here
1061                                 $OUT .= '<td align="center" class="timebox_column bottom"><div class="tiny">{--TIME_UNIT_' . $units['unit_label'][$unit] . '--}</div></td>';
1062                         } // END - if
1063                 } // END - foreach
1064
1065                 // Close table row and open new one
1066                 $OUT .= '</tr>';
1067                 $OUT .= '<tr>';
1068
1069                 // "Walk" through all units again
1070                 foreach ($units['unit_field'] as $unit => $field) {
1071                         // Is this used?
1072                         if (isInString($unit, $display) || (empty($display))) {
1073                                 // Generate year selection
1074                                 $OUT .= '<td align="center">';
1075                                 $OUT .= addSelectionBox($field, $data[$unit], $prefix, NULL, 'mini_select');
1076                                 $OUT .= '</td>';
1077                         } else {
1078                                 $OUT .= '<input type="hidden" name="' . $prefix . '_' . $field . '" value="0" />';
1079                         }
1080                 } // END - foreach
1081
1082                 // Close all tags
1083                 $OUT .= '</tr>';
1084                 $OUT .= '</table>';
1085                 $OUT .= '</div>';
1086         }
1087
1088         // Return generated HTML code or data array
1089         return $OUT;
1090 }
1091
1092 // Generate a list of administrative links to a given userid
1093 function generateMemberAdminActionLinks ($userid) {
1094         // Make sure userid is a number
1095         if ($userid != bigintval($userid)) {
1096                 reportBug(__FUNCTION__, __LINE__, 'userid is not a number!');
1097         } // END - if
1098
1099         // Define all main targets
1100         $targetArray = runFilterChain('member_admin_actions', array('del_user', 'edit_user', 'lock_user', 'list_refs', 'list_links', 'add_points', 'sub_points'));
1101
1102         // Get user status
1103         $status = getFetchedUserData('userid', $userid, 'status');
1104
1105         // Begin of navigation links
1106         $OUT = '[';
1107
1108         foreach ($targetArray as $target) {
1109                 $OUT .= '<span class="admin_user_link"><a href="{%url=modules.php?module=admin&amp;what=' . $target . '&amp;userid=' . $userid . '%}" title="{--ADMIN_USER_ACTION_LINK_';
1110                 //* DEBUG: */ debugOutput('*' . $target.'/' . $status.'*');
1111                 if (($target == 'lock_user') && ($status == 'LOCKED')) {
1112                         // Locked accounts shall be unlocked
1113                         $OUT .= 'UNLOCK_USER';
1114                 } elseif ($target == 'del_user') {
1115                         // @TODO Deprecate this thing
1116                         $OUT .= 'DELETE_USER';
1117                 } else {
1118                         // All other status is fine
1119                         $OUT .= strtoupper($target);
1120                 }
1121                 $OUT .= '_TITLE--}">{--ADMIN_USER_ACTION_LINK_';
1122                 if (($target == 'lock_user') && ($status == 'LOCKED')) {
1123                         // Locked accounts shall be unlocked
1124                         $OUT .= 'UNLOCK_USER';
1125                 } elseif ($target == 'del_user') {
1126                         // @TODO Deprecate this thing
1127                         $OUT .= 'DELETE_USER';
1128                 } else {
1129                         // All other status is fine
1130                         $OUT .= strtoupper($target);
1131                 }
1132                 $OUT .= '--}</a></span>|';
1133         } // END - foreach
1134
1135         // Add special link, in case of the account is unconfirmed
1136         if ($status == 'UNCONFIRMED') {
1137                 // Add it
1138                 $OUT .= '<span class="admin_user_link"><a target="_blank" title="{--ADMIN_USER_ACTION_LINK_CONFIRM_ACCOUNT_TITLE--}" href="{%url=confirm.php?hash=' . getFetchedUserData('userid', $userid, 'user_hash') . '%}">{--ADMIN_USER_ACTION_LINK_CONFIRM_ACCOUNT--}</a></span>|';
1139         } // END - if
1140
1141         // Finish navigation link
1142         $OUT = substr($OUT, 0, -1) . ']';
1143
1144         // Return string
1145         return $OUT;
1146 }
1147
1148 // Generate an email link
1149 function generateEmailLink ($email, $table = 'admins') {
1150         // Default email link (INSECURE! Spammer can read this by harvester programs)
1151         $EMAIL = 'mailto:' . $email;
1152
1153         // Check for several extensions
1154         if ((isExtensionActive('admins')) && ($table == 'admins')) {
1155                 // Create email link for contacting admin in guest area
1156                 $EMAIL = generateAdminEmailLink($email);
1157         } elseif ((isExtensionInstalledAndNewer('user', '0.3.3')) && ($table == 'user_data')) {
1158                 // Create email link for contacting a member within admin area (or later in other areas, too?)
1159                 $EMAIL = generateUserEmailLink($email);
1160         } elseif ((isExtensionActive('sponsor')) && ($table == 'sponsor_data')) {
1161                 // Create email link to contact sponsor within admin area (or like the link above?)
1162                 $EMAIL = generateSponsorEmailLink($email);
1163         }
1164
1165         // Return email link
1166         return $EMAIL;
1167 }
1168
1169 /**
1170  * Outputs an error message in a "fashioned way" to the user, by putting it into
1171  * a nice looking web page, if one of HTML or CSS output mode is active.
1172  *
1173  * Please use reportBug() instead of this function. reportBug() has more helpful
1174  * functionality like logging and admin notification (which you can configure
1175  * through your admin area).
1176  *
1177  * @param       $file           Function or file basename where the error came from
1178  * @param       $line           Line number where the error came from
1179  * @param       $message        Message which shall be output to web
1180  * @return      void
1181  */
1182 function app_exit ($file, $line, $message) {
1183         // Check if Script is already dieing and not let it kill itself another 1000 times
1184         if (isset($GLOBALS['app_died'])) {
1185                 // Script tried to kill itself twice
1186                 die('[' . __FUNCTION__ . ':' . __LINE__ . ']: Script wanted to kill itself more than once! Raw message=' . $message . ', file/function=' . $file . ', line=' . $line);
1187         } // END - if
1188
1189         // Make sure, that the script realy realy diese here and now
1190         $GLOBALS['app_died'] = TRUE;
1191
1192         // Is this AJAX mode?
1193         if (isAjaxOutputMode()) {
1194                 // Set content type as application/json
1195                 setContentType('application/json');
1196         } else {
1197                 // Set content type as text/html
1198                 setContentType('text/html');
1199         }
1200
1201         // Load header
1202         loadPageHeader();
1203
1204         // Rewrite message for output
1205         $message = sprintf(
1206                 getMessage('MAILER_HAS_DIED'),
1207                 basename($file),
1208                 $line,
1209                 $message
1210         );
1211
1212         // Is this AJAX mode again
1213         if (isAjaxOutputMode()) {
1214                 // Load the message template
1215                 $OUT = loadTemplate('ajax_app_exit_message', TRUE, $message);
1216
1217                 // Output it as JSON encoded
1218                 outputHtml(encodeJson(array('reply_content' => urlencode(doFinalCompilation(compileRawCode($OUT))))));
1219         } else {
1220                 // Load the message template
1221                 loadTemplate('app_exit_message', FALSE, $message);
1222         }
1223
1224         // Load footer
1225         loadPageFooter();
1226 }
1227
1228 // Display parsing time and number of SQL queries in footer
1229 function displayParsingTime () {
1230         // Is the timer started?
1231         if (!isset($GLOBALS['__start_time'])) {
1232                 // Abort here
1233                 return FALSE;
1234         } // END - if
1235
1236         // Get end time
1237         $endTime = microtime(TRUE);
1238
1239         // "Explode" both times
1240         $start = explode(' ', $GLOBALS['__start_time']);
1241         $end = explode(' ', $endTime);
1242         $runTime = $end[0] - $start[0];
1243         if ($runTime < 0) {
1244                 $runTime = '0';
1245         } // END - if
1246
1247         // Prepare output
1248         // @TODO This can be easily moved out after the merge from EL branch to this is complete
1249         $content = array(
1250                 'run_time' => $runTime,
1251                 'sql_time' => (getConfig('sql_time') * 1000),
1252         );
1253
1254         // Load the template
1255         $GLOBALS['__page_footer'] .= loadTemplate('show_timings', TRUE, $content);
1256
1257         // Is debug enabled?
1258         if (isDebugModeEnabled()) {
1259                 // Log loading of total includes
1260                 //* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Loaded includes: ' . count($GLOBALS['inc_loaded']) . ', readable files: ' . count($GLOBALS['file_readable']));
1261         } // END - if
1262 }
1263
1264 /**
1265  * Outputs an error message and backtrace to the user, by default a mail with
1266  * all relevant data is being mailed to the configured administrators.
1267  *
1268  * This function shall be used "publicly" because of logging, admin notification
1269  * and double-call prevention (see first if() block) instead of app_exit().
1270  * app_exit() is more a "private" function and will only output a bug message to
1271  * the user, no email and no logging.
1272  *
1273  * @param       $file           Function or file basename where the error came from
1274  * @param       $line           Line number where the error came from
1275  * @param       $sendEmail      Wether to send an email to all configured administrators
1276  * @return      void
1277  */
1278 function reportBug ($file, $line, $message = '', $sendEmail = TRUE) {
1279         // Is this already called?
1280         if (isset($GLOBALS[__FUNCTION__])) {
1281                 // Other backtrace
1282                 print '[' . $file . ':' . $line . ':] ' . __FUNCTION__ . '() has already died! Message:' . $message . '<br />Backtrace:<pre>';
1283                 debug_print_backtrace();
1284                 die('</pre>');
1285         } // END - if
1286
1287         // Set HTTP status to 500 (e.g. for AJAX requests)
1288         setHttpStatus('500 Internal Server Error');
1289
1290         // Mark this function as called
1291         $GLOBALS[__FUNCTION__] = TRUE;
1292
1293         // Init message
1294         $debug = '';
1295
1296         // Is the optional message set?
1297         if (!empty($message)) {
1298                 // Use and log it
1299                 $debug = sprintf("Note: %s<br />\n",
1300                         $message
1301                 );
1302
1303                 // @TODO Add a little more infos here
1304                 logDebugMessage($file, $line, strip_tags($message));
1305         } // END - if
1306
1307         // Add output
1308         $debug .= 'Please report this bug at <a title="Direct link to the bug-tracker" href="http://bugs.mxchange.org" rel="external" target="_blank">http://bugs.mxchange.org</a> and include this whole message + logfile from <strong>' . str_replace(getPath(), '', getCachePath()) . 'debug.log</strong> in your report (you can now attach files).<br />Backtrace:<pre>';
1309         $debug .= debug_get_printable_backtrace();
1310         $debug .= '</pre>';
1311         $debug .= '<div class="para">Request-URI: ' . getRequestUri() . '</div>';
1312         $debug .= '<div class="para">Thank you for finding bugs.</div>';
1313
1314         // Send an email? (e.g. not wanted for evaluation errors)
1315         if (($sendEmail === TRUE) && (!isInstaller()) && (isAdminRegistered())) {
1316                 // Prepare content
1317                 $content = array(
1318                         'message'   => trim($message),
1319                         'backtrace' => trim(debug_get_mailable_backtrace())
1320                 );
1321
1322                 // Send email to webmaster
1323                 sendAdminNotification('{--REPORT_BUG_SUBJECT--}', 'admin_report_bug', $content);
1324         } // END - if
1325
1326         // Is there HTML/CSS/AJAX mode while debug-mode is enabled?
1327         if (((isDebugModeEnabled()) || (isInstaller())) && ((isHtmlOutputMode()) || (isCssOutputMode()) || (isAjaxOutputMode()))) {
1328                 // And abort here
1329                 app_exit($file, $line, $debug);
1330         } elseif (isAjaxOutputMode()) {
1331                 // Load include (again?)
1332                 loadIncludeOnce('inc/ajax-functions.php');
1333
1334                 // Init AJAX
1335                 initAjax();
1336
1337                 // Set HTTP status to 500 again
1338                 setHttpStatus('500 Internal Server Error');
1339
1340                 // Is AJAX output mode, then output message as JSON
1341                 setAjaxReplyContent($debug);
1342
1343                 // Send it out to browser
1344                 sendAjaxContent(TRUE);
1345
1346                 // Include footer
1347                 loadPageFooter();
1348         } else {
1349                 // Raw/image output mode and all other modes doesn't work well with text ...
1350                 die();
1351         }
1352 }
1353
1354 // Compile characters which are allowed in URLs
1355 function compileUriCode ($code, $simple = TRUE) {
1356         // Trim code
1357         $test = trim($code);
1358
1359         // Is it empty?
1360         if (empty($test)) {
1361                 // Then abort here and return the original code
1362                 return $code;
1363         } // END - if
1364
1365         // Compile these by default
1366         $charsCompile = array(
1367                 'from' => array(
1368                         '{DOT}',
1369                         '{SLASH}',
1370                         '{QUOT}',
1371                         '{DOLLAR}',
1372                         '{OPEN_ANCHOR}',
1373                         '{CLOSE_ANCHOR}',
1374                         '{OPEN_SQR}',
1375                         '{CLOSE_SQR}',
1376                         '{PER}'
1377                 ),
1378                 'to' => array(
1379                         '.',
1380                         '/',
1381                         chr(39),
1382                         '$',
1383                         '(',
1384                         ')',
1385                         '[',
1386                         ']',
1387                         '%'
1388                 )
1389         );
1390
1391         // Compile constants
1392         if ($simple === FALSE) {
1393                 // Add more 'from'
1394                 array_unshift($charsCompile['from'], '{--', '--}');
1395
1396                 // Add more 'to'
1397                 array_unshift($charsCompile['to'], '".', '."');
1398         } // END - if
1399
1400         // Compile QUOT and other non-HTML codes
1401         $code = str_replace($charsCompile['from'], $charsCompile['to'], $code);
1402         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'code=' . $code);
1403
1404         // Return compiled code
1405         return $code;
1406 }
1407
1408 // Handle message codes from URL
1409 function handleCodeMessage () {
1410         // Is 'code' set?
1411         if (isGetRequestElementSet('code')) {
1412                 // Default extension is 'unknown'
1413                 $ext = 'unknown';
1414
1415                 // Is extension given?
1416                 if (isGetRequestElementSet('ext')) {
1417                         $ext = getRequestElement('ext');
1418                 } // END - if
1419
1420                 // Convert the 'code' parameter from URL to a human-readable message
1421                 $message = getMessageFromErrorCode(getRequestElement('code'));
1422
1423                 // Load message template
1424                 loadTemplate('message', FALSE, $message);
1425         } // END - if
1426 }
1427
1428 // Generates a 'extension foo out-dated' message
1429 function generateExtensionOutdatedMessage ($ext_name, $ext_ver) {
1430         // Is the extension empty?
1431         if (empty($ext_name)) {
1432                 // This should not happen
1433                 reportBug(__FUNCTION__, __LINE__, 'Parameter ext is empty. This should not happen.');
1434         } // END - if
1435
1436         // Default message
1437         $message = '{%message,EXTENSION_PROBLEM_EXTENSION_OUTDATED=' . $ext_name . '%}';
1438
1439         // Is an admin logged in?
1440         if (isAdmin()) {
1441                 // Then output admin message
1442                 $message = sprintf(getMessage('ADMIN_EXTENSION_PROBLEM_EXTENSION_INACTIVE'), $ext_name, $ext_name, $ext_ver);
1443         } // END - if
1444
1445         // Return prepared message
1446         return $message;
1447 }
1448
1449 // Generates a 'extension foo inactive' message
1450 function generateExtensionInactiveMessage ($ext_name) {
1451         // Is the extension empty?
1452         if (empty($ext_name)) {
1453                 // This should not happen
1454                 reportBug(__FUNCTION__, __LINE__, 'Parameter ext is empty. This should not happen.');
1455         } // END - if
1456
1457         // Default message
1458         $message = '{%message,EXTENSION_PROBLEM_EXTENSION_INACTIVE=' . $ext_name . '%}';
1459
1460         // Is an admin logged in?
1461         if (isAdmin()) {
1462                 // Then output admin message
1463                 $message = '{%message,ADMIN_EXTENSION_PROBLEM_EXTENSION_INACTIVE=' . $ext_name . '%}';
1464         } // END - if
1465
1466         // Return prepared message
1467         return $message;
1468 }
1469
1470 // Generates a 'extension foo not installed' message
1471 function generateExtensionNotInstalledMessage ($ext_name) {
1472         // Is the extension empty?
1473         if (empty($ext_name)) {
1474                 // This should not happen
1475                 reportBug(__FUNCTION__, __LINE__, 'Parameter ext is empty. This should not happen.');
1476         } // END - if
1477
1478         // Default message
1479         $message = '{%message,EXTENSION_PROBLEM_EXTENSION_NOT_INSTALLED=' . $ext_name . '%}';
1480
1481         // Is an admin logged in?
1482         if (isAdmin()) {
1483                 // Then output admin message
1484                 $message = '{%message,ADMIN_EXTENSION_PROBLEM_EXTENSION_NOT_INSTALLED=' . $ext_name . '%}';
1485         } // END - if
1486
1487         // Return prepared message
1488         return $message;
1489 }
1490
1491 // Generates a message depending on if the extension is not installed or not
1492 // just activated
1493 function generateExtensionInactiveNotInstalledMessage ($ext_name) {
1494         // Init message
1495         $message = '';
1496
1497         // Is the extension not installed or just deactivated?
1498         switch (isExtensionInstalled($ext_name)) {
1499                 case TRUE; // Deactivated!
1500                         $message = generateExtensionInactiveMessage($ext_name);
1501                         break;
1502
1503                 case FALSE; // Not installed!
1504                         $message = generateExtensionNotInstalledMessage($ext_name);
1505                         break;
1506
1507                 default: // Should not happen!
1508                         logDebugMessage(__FUNCTION__, __LINE__, sprintf('Invalid state of extension %s detected.', $ext_name));
1509                         $message = sprintf('Invalid state of extension %s detected.', $ext_name);
1510                         break;
1511         } // END - switch
1512
1513         // Return the message
1514         return $message;
1515 }
1516
1517 // Print code with line numbers
1518 function lineNumberCode ($code)    {
1519         // By default copy the code
1520         $codeE = $code;
1521
1522         if (!is_array($code)) {
1523                 // We need an array, so try it with the new-line character
1524                 $codeE = explode(PHP_EOL, $code);
1525         } // END - if
1526
1527         $count_lines = count($codeE);
1528
1529         $r = 'Line | Code:<br />';
1530         foreach ($codeE as $line => $c) {
1531                 $r .= '<div class="line"><span class="linenum">';
1532                 if ($count_lines == 1) {
1533                         $r .= 1;
1534                 } else {
1535                         $r .= ($line == ($count_lines - 1)) ? '' : ($line+1);
1536                 }
1537                 $r .= '</span>|';
1538
1539                 // Add code
1540                 $r .= '<span class="linetext">' . encodeEntities($c) . '</span></div>';
1541         } // END - foreach
1542
1543         return '<div class="code">' . $r . '</div>';
1544 }
1545
1546 // Determines the right page title
1547 function determinePageTitle () {
1548         // Init page title
1549         $pageTitle = '';
1550
1551         // Config and database connection valid?
1552         if ((isConfigLocalLoaded()) && (isConfigurationLoaded()) && (isSqlLinkUp()) && (isExtensionInstalledAndNewer('sql_patches', '0.1.6'))) {
1553                 // Title decoration enabled?
1554                 if ((isTitleDecorationEnabled()) && (getTitleLeft() != '')) {
1555                         $pageTitle .= '{%config,trim=title_left%} ';
1556                 } // END - if
1557
1558                 // Is there an extra title?
1559                 if (isExtraTitleSet()) {
1560                         // Then prepend it
1561                         $pageTitle .= '{%pipe,getExtraTitle%} by ';
1562                 } // END - if
1563
1564                 // Add main title
1565                 $pageTitle .= '{?MAIN_TITLE?}';
1566
1567                 // Add title of module? (middle decoration will also be added!)
1568                 if ((isModuleTitleEnabled()) || ((!isWhatSet()) && (!isActionSet())) || (getModule() == 'admin')) {
1569                         $pageTitle .= ' {%config,trim=title_middle%} {DQUOTE} . getModuleTitle(getModule()) . {DQUOTE}';
1570                 } // END - if
1571
1572                 // Get menu mode from module
1573                 $menuMode = getMenuModeFromModule();
1574
1575                 // Add middle part (always in admin area!)
1576                 if ((!empty($menuMode)) && ((isWhatTitleEnabled()) || ($menuMode == 'admin'))) {
1577                         $pageTitle .= ' {%config,trim=title_middle%} ' . getTitleFromMenu($menuMode, getWhat());
1578                 } // END - if
1579
1580                 // Add title decorations? (right)
1581                 if ((isTitleDecorationEnabled()) && (getTitleRight() != '')) {
1582                         $pageTitle .= ' {%config,trim=title_right%}';
1583                 } // END - if
1584         } elseif ((isInstalled()) && (isAdminRegistered())) {
1585                 // Installed, admin registered but no ext-sql_patches
1586                 $pageTitle = '[-- {?MAIN_TITLE?} - {%pipe,getModule,getModuleTitle%} --]';
1587         } elseif ((isInstalled()) && (!isAdminRegistered())) {
1588                 // Installed but no admin registered
1589                 $pageTitle = '{--INSTALLER_OF_MAILER_NO_ADMIN--}';
1590         } elseif ((!isInstalled()) || (!isAdminRegistered())) {
1591                 // Installation mode
1592                 $pageTitle = '{--INSTALLER_OF_MAILER--}';
1593         } else {
1594                 // Configuration not found
1595                 $pageTitle = '{--NO_CONFIG_FOUND_TITLE--}';
1596
1597                 // Do not add the fatal message in installation mode
1598                 if ((!isInstalling()) && (!isConfigurationLoaded())) {
1599                         // Please report this
1600                         reportBug(__FUNCTION__, __LINE__, 'No configuration data found!');
1601                 } // END - if
1602         }
1603
1604         // Return title
1605         return decodeEntities($pageTitle);
1606 }
1607
1608 // Checks whethere there is a cache file there. This function is cached.
1609 function isTemplateCached ($prefix, $template) {
1610         // Is there cached this result?
1611         if (!isset($GLOBALS['template_cache'][$prefix][$template])) {
1612                 // Generate FQFN
1613                 $FQFN = generateCacheFqfn($prefix, $template);
1614
1615                 // Is it there?
1616                 $GLOBALS['template_cache'][$prefix][$template] = isFileReadable($FQFN);
1617         } // END - if
1618
1619         // Return it
1620         return $GLOBALS['template_cache'][$prefix][$template];
1621 }
1622
1623 // Flushes non-flushed template cache to disk
1624 function flushTemplateCache ($prefix, $template, $eval) {
1625         // Is this cache flushed?
1626         if ((isDebugTemplateCacheEnabled() === FALSE) && (isTemplateCached($prefix, $template) === FALSE) && ($eval != '404')) {
1627                 // Generate FQFN
1628                 $FQFN = generateCacheFqfn($prefix, $template);
1629
1630                 // Compile code another round for better performance and preserve $ signs
1631                 $eval = str_replace(array(chr(92), '{DOLLAR}', '{BACK}', '{CONTENT}'), array('', '$', chr(92), '$content'), compileCode(str_replace(array('$content', chr(92)), array('{CONTENT}', '{BACK}'), $eval)));
1632
1633                 // Is this a XML template?
1634                 if ($prefix == 'xml') {
1635                         // Compact only XML templates as emails needs new-line characters and HTML may contain required "comments"
1636                         $eval = compactContent($eval);
1637                 } // END - if
1638
1639                 // And flush it
1640                 writeToFile($FQFN, '<?php ' . $eval . ' ?>', TRUE);
1641         } // END - if
1642 }
1643
1644 // Reads a template cache
1645 function readTemplateCache ($prefix, $template, $content) {
1646         // Check it again
1647         if ((isDebugTemplateCacheEnabled()) || (!isTemplateCached($prefix, $template))) {
1648                 // This should not happen
1649                 reportBug(__FUNCTION__, __LINE__, 'Wether debugging of template cache is enabled or template ' . $template . ' is not cached while expected.');
1650         } // END - if
1651
1652         // Is it cached?
1653         if (!isset($GLOBALS['template_eval'][$prefix][$template])) {
1654                 // Generate FQFN
1655                 $FQFN = generateCacheFqfn($prefix, $template);
1656
1657                 /*
1658                  * And read from it.
1659                  *
1660                  * WARNING: Do not replace this include() call with loadInclude() as it
1661                  * would hide local variables away which is here required to make this
1662                  * work.
1663                  */
1664                 include($FQFN);
1665
1666                 // Is the template cache valid?
1667                 if (!isset($templateContent)) {
1668                         // Please clear your cache!
1669                         reportBug(__FUNCTION__, __LINE__, 'Template ' . $template . ' uses old structure. Please delete all template cache files and reload.');
1670                 } // END - if
1671         } // END - if
1672
1673         // And return it
1674         return $templateContent;
1675 }
1676
1677 // Escapes quotes (default is only double-quotes)
1678 function escapeQuotes ($str, $single = FALSE) {
1679         // Should we escape all?
1680         if ($single === TRUE) {
1681                 // Escape all (including null)
1682                 $str = addslashes($str);
1683         } else {
1684                 // Replace all chars at once
1685                 $str = str_replace(array("\\'", '"', "\\\\"), array(chr(39), "\\\"", chr(92)), $str);
1686         }
1687
1688         // Return the escape'd string
1689         return $str;
1690 }
1691
1692 // Escapes the JavaScript code, prevents \r and \n becoming char 10/13
1693 function escapeJavaScriptQuotes ($str) {
1694         // Replace all double-quotes and secure back-ticks
1695         $str = str_replace(array(chr(92), '"'), array('{BACK}', '\"'), $str);
1696
1697         // Return it
1698         return $str;
1699 }
1700
1701 // Send out mails depending on the 'mod/modes' combination
1702 // @TODO Lame description for this function
1703 function sendModeMails ($mod, $modes) {
1704         // Init user data
1705         $content = array ();
1706
1707         // Load hash
1708         if (fetchUserData(getMemberId())) {
1709                 // Extract salt from cookie
1710                 $salt = substr(getSession('u_hash'), 0, -40);
1711
1712                 // Now let's compare passwords
1713                 $hash = encodeHashForCookie(getUserData('password'));
1714
1715                 // Does the hash match or should we change it?
1716                 if (($hash == getSession('u_hash')) || (postRequestElement('password1') == postRequestElement('password2'))) {
1717                         // Load the data
1718                         $content = getUserDataArray();
1719
1720                         // Clear/init the content variable
1721                         $content['message'] = '';
1722
1723                         // Which mail?
1724                         // @TODO Move this in a filter
1725                         switch ($mod) {
1726                                 case 'mydata':
1727                                         foreach ($modes as $mode) {
1728                                                 switch ($mode) {
1729                                                         case 'normal': break; // Do not add any special lines
1730                                                         case 'email': // Email was changed!
1731                                                                 $content['message'] = '{--MEMBER_CHANGED_EMAIL--}' . ': ' . postRequestElement('old_email') . PHP_EOL;
1732                                                                 break;
1733
1734                                                         case 'password': // Password was changed
1735                                                                 $content['message'] = '{--MEMBER_CHANGED_PASSWORD--}' . PHP_EOL;
1736                                                                 break;
1737
1738                                                         default:
1739                                                                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unknown mode %s detected.', $mode));
1740                                                                 $content['message'] = '{%message,MEMBER_UNKNOWN_MODE=' .  $mode . '%}' . PHP_EOL . PHP_EOL;
1741                                                                 break;
1742                                                 } // END - switch
1743                                         } // END - foreach
1744
1745                                         if (isExtensionActive('country')) {
1746                                                 // Replace code with description
1747                                                 $content['country'] = generateCountryInfo(postRequestElement('country_code'));
1748                                         } // END - if
1749
1750                                         // Merge content with data from POST
1751                                         $content = merge_array($content, postRequestArray());
1752
1753                                         // Load template
1754                                         $message = loadEmailTemplate('member_mydata_notify', $content, getMemberId());
1755
1756                                         if (isAdminNotificationEnabled()) {
1757                                                 // The admin needs to be notified about a profile change
1758                                                 $message_admin = 'admin_mydata_notify';
1759                                                 $subjectAdmin   = '{--ADMIN_CHANGED_DATA_SUBJECT--}';
1760                                         } else {
1761                                                 // No mail to admin
1762                                                 $message_admin = '';
1763                                                 $subjectAdmin  = '';
1764                                         }
1765
1766                                         // Set subject lines
1767                                         $subjectMember = '{--MEMBER_CHANGED_DATA--}';
1768
1769                                         // Output success message
1770                                         $content['message'] = '<span class="message">{--MEMBER_MYDATA_MAIL_SENT--}</span>';
1771                                         break;
1772
1773                                 default: // Unsupported module!
1774                                         logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unsupported module %s detected.', $mod));
1775                                         $content['message'] = '<span class="bad">{%message,UNKNOWN_MODULE=' . $mod . '%}</span>';
1776                                         break;
1777                         } // END - switch
1778                 } else {
1779                         // Passwords mismatch
1780                         $content['message'] = '<span class="bad">{--MEMBER_PASSWORD_ERROR--}</span>';
1781                 }
1782         } else {
1783                 // Could not load profile
1784                 $content['message'] = '<span class="bad">{--MEMBER_CANNOT_LOAD_PROFILE--}</span>';
1785         }
1786
1787         // Send email to user if required
1788         if ((!empty($subjectMember)) && (!empty($message)) && (!empty($content['userid']))) {
1789                 // Send member mail
1790                 sendEmail($content['userid'], $subjectMember, $message);
1791         } // END - if
1792
1793         // Send only if no other error has occured
1794         if ((!empty($subjectAdmin)) && (!empty($message_admin)) && (isAdminNotificationEnabled())) {
1795                 // Send admin mail
1796                 sendAdminNotification($subjectAdmin, $message_admin, $content, getMemberId());
1797         } elseif (isAdminNotificationEnabled()) {
1798                 // Cannot send mails to admin!
1799                 $content['message'] = '{--CANNOT_SEND_ADMIN_MAILS--}';
1800         } else {
1801                 // No mail to admin
1802                 $content['message'] = '<span class="message">{--MEMBER_MYDATA_MAIL_SENT--}</span>';
1803         }
1804
1805         // Load template
1806         displayMessage($content['message']);
1807 }
1808
1809 // Generates a 'selection box' from given array
1810 function generateSelectionBoxFromArray ($options, $name, $optionKey, $optionContent = '', $extraName = '', $templateName = '', $default = NULL, $nameElement = '', $allowNone = FALSE, $useDefaultAsArray = FALSE) {
1811         // options must be an array
1812         assert(is_array($options));
1813
1814         // Default is empty
1815         $addKey = '';
1816
1817         // Use default value as array key?
1818         if ($useDefaultAsArray === TRUE) {
1819                 // Then set it
1820                 $addKey = '[' . convertNullToZero($default) . ']';
1821         } // END - if
1822
1823         // Start the output
1824         $OUT = '<select name="' . $name . $addKey . '" size="1" class="form_select">
1825 <option value="X" disabled="disabled">{--PLEASE_SELECT--}</option>';
1826
1827         // Allow none?
1828         if ($allowNone === TRUE) {
1829                 // Then add it
1830                 $OUT .= '<option value="0">{--SELECT_NONE--}</option>';
1831         } // END - if
1832
1833         // Walk through all options
1834         foreach ($options as $option) {
1835                 // Default 'default' is not set
1836                 $option['default'] = '';
1837
1838                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'name=' . $name . ',default[' . gettype($default) . ']=' . $default . ',optionKey[' . gettype($optionKey) . ']=' . $optionKey);
1839                 // Is default value same as given value?
1840                 if ((!is_null($default)) && (isset($option[$optionKey])) && ($default == $option[$optionKey])) {
1841                         // Then set default
1842                         $option['default'] = ' selected="selected"';
1843                 } // END - if
1844
1845                 // Is 'nameElement' set?
1846                 if ((!empty($nameElement)) && (isset($option[$nameElement]))) {
1847                         // Then set this as extraName, but lower-case
1848                         $extraName = '_' . strtolower($option[$nameElement]);
1849                 } // END - if
1850
1851                 // Add the <option> entry from ...
1852                 if (empty($optionContent)) {
1853                         // Is a template name given?
1854                         if (empty($templateName)) {
1855                                 // ... $name template
1856                                 $OUT .= loadTemplate('select_' . $name . $extraName . '_option', TRUE, $option);
1857                         } else {
1858                                 // ... $templateName template
1859                                 $OUT .= loadTemplate('select_' . $templateName . $extraName . '_option', TRUE, $option);
1860                         }
1861                 } else {
1862                         // ... direct HTML code
1863                         $OUT .= '<option value="' . $option[$optionKey] . '">' . $option[$optionContent] . '</option>';
1864                 }
1865         } // END - foreach
1866
1867         // Finish selection box
1868         $OUT .= '</select>';
1869
1870         // Prepare output
1871         $content = array(
1872                 'selection_box' => $OUT,
1873         );
1874
1875         // Load template and return it
1876         if (empty($templateName)) {
1877                 // Use name from $name + $extraName
1878                 return loadTemplate('select_' . $name . $extraName . '_box', TRUE, $content);
1879         } else {
1880                 // Use name from $templateName + $extraName
1881                 return loadTemplate('select_' . $templateName . $extraName . '_box', TRUE, $content);
1882         }
1883 }
1884
1885 // Prepares the header for HTML output
1886 function loadHtmlHeader () {
1887         /*
1888          * Run two filters:
1889          * 1.) pre_page_header (mainly loads the page_header template and includes
1890          *     meta description)
1891          */
1892         runFilterChain('pre_page_header');
1893
1894         /*
1895          * Here can be something be added, but normally one of the two filters
1896          * around this line should do the job for you.
1897          */
1898
1899         /*
1900          * 2.) post_page_header (mainly to load stylesheet, extra JavaScripts and
1901          *     to close the head-tag)
1902          * Include more header data here
1903          */
1904         runFilterChain('post_page_header');
1905 }
1906
1907 // Adds page header and footer to output array element
1908 function addPageHeaderFooter () {
1909         // Init output
1910         $OUT = '';
1911
1912         // Add them all together. This is maybe to simple
1913         foreach (array('__page_header', '__output', '__page_footer') as $pagePart) {
1914                 // Add page part if set
1915                 if (isset($GLOBALS[$pagePart])) {
1916                         $OUT .= $GLOBALS[$pagePart];
1917                 } // END - if
1918         } // END - foreach
1919
1920         // Transfer $OUT to '__output'
1921         $GLOBALS['__output'] = $OUT;
1922 }
1923
1924 // Generates meta description for current module and 'what' value
1925 function generateMetaDescriptionCode () {
1926         // Only include from guest area and if ext-sql_patches has correct version
1927         if ((getModule() == 'index') && (isExtensionInstalledAndNewer('sql_patches', '0.1.6'))) {
1928                 // Output it directly
1929                 $GLOBALS['__page_header'] .= '<meta name="description" content="' . '{?MAIN_TITLE?} ' . trim(getConfig('title_middle')) . ' ' . getTitleFromMenu('guest', getWhat()) . '" />';
1930         } // END - if
1931
1932         // Initialize referral system
1933         initReferralSystem();
1934 }
1935
1936 // Generates an FQFN for template cache from the given template name
1937 function generateCacheFqfn ($prefix, $template) {
1938         // Is this cached?
1939         if (!isset($GLOBALS['template_cache_fqfn'][$prefix][$template])) {
1940                 // Generate the FQFN
1941                 $GLOBALS['template_cache_fqfn'][$prefix][$template] = sprintf(
1942                         '%s%s_compiled/%s/%s%s',
1943                         getPath(),
1944                         getCachePath(),
1945                         $prefix,
1946                         $template,
1947                         getCacheExtension()
1948                 );
1949         } // END - if
1950
1951         // Return it
1952         return $GLOBALS['template_cache_fqfn'][$prefix][$template];
1953 }
1954
1955 // "Fixes" null or empty string to count of dashes
1956 function fixNullEmptyToDashes ($str, $num) {
1957         // Use str as default
1958         $return = $str;
1959
1960         // Is it empty?
1961         if ((is_null($str)) || (trim($str) == '')) {
1962                 // Set it
1963                 $return = str_repeat('-', $num);
1964         } // END - if
1965
1966         // Return final string
1967         return $return;
1968 }
1969
1970 // Translates the "pool type" into human-readable
1971 function translatePoolType ($type) {
1972         // Return "translation"
1973         return sprintf('{--POOL_TYPE_%s--}', strtoupper($type));
1974 }
1975
1976 // "Translates" given time unit
1977 function translateTimeUnit ($unit) {
1978         // Default is unknown
1979         $message = '{%message,TIME_UNIT_UNKNOWN=' . $unit . '%}';
1980
1981         // "Detect" it
1982         if (!isset($GLOBALS['time_units'][$unit])) {
1983                 // Not found
1984                 logDebugMessage(__FUNCTION__, __LINE__, 'Unknown time unit ' . $unit . ' detected.');
1985         } else {
1986                 // Translate it with generic function
1987                 $message = translateGeneric('TIME_UNIT' , $GLOBALS['time_units'][$unit]);
1988         }
1989
1990         // Return message
1991         return $message;
1992 }
1993
1994 // Displays given message in admin_settings_saved template
1995 function displayMessage ($message) {
1996         // Call inner function
1997         outputHtml(returnMessage($message));
1998 }
1999
2000 // Returns given message in admin_settings_saved template
2001 function returnMessage ($message) {
2002         // Load the template
2003         return loadTemplate('admin_settings_saved', TRUE, $message);
2004 }
2005
2006 // Displays given error message in admin_settings_unsaved template
2007 function displayErrorMessage ($message) {
2008         // Load the template
2009         outputHtml(returnErrorMessage($message));
2010 }
2011
2012 // Displays given error message in admin_settings_unsaved template
2013 function returnErrorMessage ($message) {
2014         // Load the template
2015         return loadTemplate('admin_settings_unsaved', TRUE, $message);
2016 }
2017
2018 // Generates a selection box for (maybe) given gender
2019 function generateGenderSelectionBox ($selectedGender = '', $fieldName = 'gender') {
2020         // Start the HTML code
2021         $out  = '<select name="' . $fieldName . '" size="1" class="form_select">';
2022
2023         // Add options
2024         $out .= generateOptions(
2025                 '/ARRAY/',
2026                 array(
2027                         'M',
2028                         'F',
2029                         'C'
2030                 ), array(
2031                         '{--GENDER_M--}',
2032                         '{--GENDER_F--}',
2033                         '{--GENDER_C--}'
2034                 ),
2035                 $selectedGender
2036         );
2037
2038         // Finish HTML code
2039         $out .= '</select>';
2040
2041         // Return the code
2042         return $out;
2043 }
2044
2045 // Generates a selection box for given default value
2046 function generateTimeUnitSelectionBox ($defaultUnit, $fieldName, $unitArray) {
2047         // Init variables
2048         $messageIds = array();
2049
2050         // Generate message id array
2051         foreach ($unitArray as $unit) {
2052                 // "Translate" it
2053                 array_push($messageIds, '{%pipe,translateTimeUnit=' . $unit . '%}');
2054         } // END - foreach
2055
2056         // Start the HTML code
2057         $out = '<select name="' . $fieldName . '" size="1" class="form_select">';
2058
2059         // Add options
2060         $out .= generateOptions('/ARRAY/', $unitArray, $messageIds, $defaultUnit);
2061
2062         // Finish HTML code
2063         $out .= '</select>';
2064
2065         // Return the code
2066         return $out;
2067 }
2068
2069 // Function to add style tag (whether display:none/block)
2070 function addStyleMenuContent ($menuMode, $mainAction, $action) {
2071         // Is there foo_menu_javascript enabled?
2072         if ((!isConfigEntrySet($menuMode . '_menu_javascript')) || (getConfig($menuMode . '_menu_javascript') == 'N')) {
2073                 // Silently abort here, not enabled
2074                 return '';
2075         } // END - if
2076
2077         // Is action=mainAction?
2078         if ($action == $mainAction) {
2079                 // Add "menu open" style
2080                 return ' style="display:block"';
2081         } else {
2082                 return ' style="display:none"';
2083         }
2084 }
2085
2086 // Function to add onclick attribute
2087 function addJavaScriptMenuContent ($menuMode, $mainAction, $action, $what) {
2088         // Is there foo_menu_javascript enabled?
2089         if ((!isConfigEntrySet($menuMode . '_menu_javascript')) || (getConfig($menuMode . '_menu_javascript') == 'N')) {
2090                 // Silently abort here, not enabled
2091                 return '';
2092         } // END - if
2093
2094         // Prepare output
2095         $OUT = ' onclick="return changeMenuFoldState(' . $menuMode . ', ' . $mainAction . ', ' . $action . ', ' . $what . ')';
2096
2097         // Return output
2098         return $OUT;
2099 }
2100
2101 // Tries to anonymize some sensitive data (e.g. IP address, user agent, referrer, etc.)
2102 function anonymizeSensitiveData ($data) {
2103         // Trim it
2104         $data = trim($data);
2105
2106         // Is it empty?
2107         if (empty($data)) {
2108                 // Then add three dashes
2109                 $data = '---';
2110         } elseif (isUrlValid($data)) {
2111                 // Is a referrer, so is it black-listed?
2112                 if (isAdmin()) {
2113                         // Is admin, has always priority
2114                         $data = '[<a href="{%pipe,generateFrametesterUrl=' . $data . '%}" target="_blank">{--ADMIN_TEST_URL--}</a>]';
2115                 } elseif ((isExtensionActive('blacklist')) && (isUrlBlacklisted($data))) {
2116                         // Yes, so replace it with text
2117                         $data = '<em>{--URL_IS_BLACKLISTED--}</em>';
2118                 } else {
2119                         // A  member is viewing this referral URL
2120                         $data = '[<a href="{%pipe,generateDereferrerUrl=' . $data . '%}" target="_blank">{--MEMBER_TEST_URL--}</a>]';
2121                 }
2122         } elseif (isIp4AddressValid($data)) {
2123                 // Is an IPv4 address
2124                 $ipArray = explode('.', $data);
2125
2126                 // Only display first 2 octets
2127                 $data = $ipArray[0] . '.' . $ipArray[1] . '.?.?';
2128         } else {
2129                 // Generic data
2130                 $data = '<em>{--DATA_IS_HIDDEN--}</em>';
2131         }
2132
2133         // Return it (hopefully) anonymized
2134         return $data;
2135 }
2136
2137 /**
2138  * Removes all comments, tabs and new-line characters to compact the content
2139  *
2140  * @param       $uncompactedContent             The uncompacted content
2141  * @return      $compactedContent               The compacted content
2142  */
2143 function compactContent ($uncompactedContent) {
2144         // First, remove all tab/new-line/revert characters
2145         $compactedContent = str_replace(chr(9), '', str_replace(PHP_EOL, '', str_replace(chr(13), '', $uncompactedContent)));
2146
2147         // Make a space after >
2148         $compactedContent = str_replace(array('>', '  '), array('> ', ' '), $compactedContent);
2149
2150         // Then regex all comments like <!-- //--> away
2151         preg_match_all('/<!--[\w\W]*?(\/\/){0,1}-->/', $compactedContent, $matches);
2152
2153         // Do we have entries?
2154         if (isset($matches[0][0])) {
2155                 // Remove all
2156                 foreach ($matches[0] as $match) {
2157                         // Remove the match
2158                         $compactedContent = str_replace($match, '', $compactedContent);
2159                 } // END - foreach
2160         } // END - if
2161
2162         // Return compacted content
2163         return $compactedContent;
2164 }
2165
2166 //-----------------------------------------------------------------------------
2167 //                     Template helper functions for EL code
2168 //-----------------------------------------------------------------------------
2169
2170 // Color-switch helper function
2171 function doTemplateColorSwitch ($templateName, $clear = FALSE, $return = TRUE) {
2172         // Is it there?
2173         if (!isset($GLOBALS['color_switch'][$templateName])) {
2174                 // Initialize it
2175                 initTemplateColorSwitch($templateName);
2176         } elseif ($clear === FALSE) {
2177                 // Switch color if called from loadTemplate()
2178                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'SWITCH:' . $templateName);
2179                 $GLOBALS['color_switch'][$templateName] = 3 - $GLOBALS['color_switch'][$templateName];
2180         }
2181
2182         // Return CSS class name
2183         if ($return === TRUE) {
2184                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'RETURN:' . $templateName . '=' . $GLOBALS['color_switch'][$templateName]);
2185                 return 'switch_sw' . $GLOBALS['color_switch'][$templateName];
2186         } // END - if
2187 }
2188
2189 // Helper function for extension registration link
2190 function doTemplateExtensionRegistrationLink ($templateName, $clear, $ext_name) {
2191         // Default is all non-productive
2192         $OUT = '<div style="cursor:help" title="{%message,ADMIN_EXTENSION_IS_NON_PRODUCTIVE_LINK_TITLE=' . $ext_name . '%}">{--ADMIN_EXTENSION_IS_NON_PRODUCTIVE_LINK--}</div>';
2193
2194         // Is the given extension non-productive?
2195         if (isExtensionDeprecated($ext_name)) {
2196                 // Is deprecated
2197                 $OUT = '<span title="{--ADMIN_EXTENSION_IS_DEPRECATED_TITLE--}">---</span>';
2198         } elseif (isExtensionProductive($ext_name)) {
2199                 // Productive code
2200                 $OUT = '<a title="{--ADMIN_TASK_REGISTER_EXTENSION_TITLE--}" href="{%url=modules.php?module=admin&amp;what=extensions&amp;register_ext=' . $ext_name . '%}">{--ADMIN_TASK_REGISTER_EXTENSION--}</a>';
2201         }
2202
2203         // Return code
2204         return $OUT;
2205 }
2206
2207 // Helper function to create bonus mail admin links
2208 function doTemplateAdminBonusMailLinks ($templateName, $clear, $bonusId) {
2209         // Call the inner function
2210         return generateAdminMailLinks('bonus', $bonusId);
2211 }
2212
2213 // Helper function to create member mail admin links
2214 function doTemplateAdminMemberMailLinks ($templateName, $clear, $mailId) {
2215         // Call the inner function
2216         return generateAdminMailLinks('normal', $mailId);
2217 }
2218
2219 // Helper function to create a selection box for YES/NO configuration entries
2220 function doTemplateConfigurationYesNoSelectionBox ($templateName, $clear, $configEntry) {
2221         // Default is a "missing entry" warning
2222         $OUT = '<div class="bad" style="cursor:help" title="{%message,ADMIN_CONFIG_ENTRY_MISSING=' . $configEntry . '%}">!' . $configEntry . '!</div>';
2223
2224         // Generate the HTML code
2225         if (isConfigEntrySet($configEntry)) {
2226                 // Configuration entry is found
2227                 $OUT = '<select name="' . $configEntry . '" class="form_select" size="1">
2228 {%config,generateYesNoOptions=' . $configEntry . '%}
2229 </select>';
2230         } // END - if
2231
2232         // Return it
2233         return $OUT;
2234 }
2235
2236 // Helper function to create a selection box for YES/NO form fields
2237 function doTemplateYesNoSelectionBox ($templateName, $clear, $formField) {
2238         // Generate the HTML code
2239         $OUT = '<select name="' . $formField . '" class="form_select" size="1">
2240 {%pipe,generateYesNoOptions%}
2241 </select>';
2242
2243         // Return it
2244         return $OUT;
2245 }
2246
2247 // Helper function to create a selection box for YES/NO form fields, by NO is default
2248 function doTemplateNoYesSelectionBox ($templateName, $clear, $formField) {
2249         // Generate the HTML code
2250         $OUT = '<select name="' . $formField . '" class="form_select" size="1">
2251 {%pipe,generateYesNoOptions=N%}
2252 </select>';
2253
2254         // Return it
2255         return $OUT;
2256 }
2257
2258 // Helper function to add extra content for guest area (module=index and others)
2259 function doTemplateGuestFooterExtras ($templateName, $clear) {
2260         // Init filter data
2261         $filterData = array(
2262                 // Name of used template
2263                 'template' => $templateName,
2264                 // Target array for gathered data
2265                 '__data'   => array(),
2266                 // Where the HTML output will go
2267                 '__output' => '',
2268         );
2269
2270         // Run the filter chain
2271         $filterData = runFilterChain('guest_footer_extras', $filterData);
2272
2273         // Return output
2274         return $filterData['__output'];
2275 }
2276
2277 // Helper function to add extra content for member area (module=login)
2278 function doTemplateMemberFooterExtras ($templateName, $clear) {
2279         // Is a member logged in?
2280         if (!isMember()) {
2281                 // This shall not happen
2282                 reportBug(__FUNCTION__, __LINE__, 'Please use this template helper only for logged-in members.');
2283         } // END - if
2284
2285         // Init filter data
2286         $filterData = array(
2287                 // Current user's id number
2288                 'userid'   => getMemberId(),
2289                 // Name of used template
2290                 'template' => $templateName,
2291                 // Target array for gathered data
2292                 '__data'   => array(),
2293                 // Where the HTML output will go
2294                 '__output' => '',
2295         );
2296
2297         // Run the filter chain
2298         $filterData = runFilterChain('member_footer_extras', $filterData);
2299
2300         // Return output
2301         return $filterData['__output'];
2302 }
2303
2304 /**
2305  * Helper function to determine whether current userid is set, if none is set,
2306  * return a zero, else an EL code is being returned as of this function is used
2307  * only in templates.
2308  *
2309  * @param       $templateName   Name of template (unused)
2310  * @param       $clear                  Wether to clear something (unused)
2311  * @return      $userId                 Wether zero or EL code snippet
2312  */
2313 function doTemplateUserId ($templateName, $clear) {
2314         // By default no userid is set
2315         $userId = '0';
2316
2317         // Is there a user id currently set?
2318         if (isCurrentUserIdSet()) {
2319                 // Then get the current user id
2320                 $userId = getCurrentUserId();
2321         } // END - if
2322
2323         // Return it
2324         return $userId;
2325 }
2326
2327 // Template helper function to generate "Terms&Conditions" link (EL code again)
2328 function doTemplateGetTermsConditionsLink ($templateName, $clear) {
2329         /*
2330          * Use default link by default ;-) This link, however, will become
2331          * deprecated once ext-terms is rolled out.
2332          */
2333         $linkCode = '{%url=modules.php?module=index&amp;what=agb%}';
2334
2335         // Is ext-terms installed?
2336         if (isExtensionInstalled('terms')) {
2337                 // Then use that link (only 'what' has changed)
2338                 $linkCode = '{%url=modules.php?module=index&amp;what=terms%}';
2339         } // END - if
2340
2341         // Return link (EL) code
2342         return $linkCode;
2343 }
2344
2345 // Template helper function to create selection box for "locked points mode"
2346 function doTemplatePointsLockedModeSelectionBox ($templateName, $clear = FALSE, $default = NULL) {
2347         // Init array
2348         $lockedModes = array(
2349                 0 => array('mode' => 'LOCKED'),
2350                 1 => array('mode' => 'UNLOCKED'),
2351         );
2352
2353         // Handle it over to generateSelectionBoxFromArray()
2354         $content = generateSelectionBoxFromArray($lockedModes, 'points_locked_mode', 'mode', '', '', '', $default);
2355
2356         // Return prepared content
2357         return $content;
2358 }
2359
2360 // Template helper function to create selection box for payment method
2361 function doTemplatePointsPaymentMethodSelectionBox ($templateName, $clear = FALSE, $default = NULL) {
2362         // Init array
2363         $paymentMethods = array(
2364                 0 => array('method' => 'DIRECT'),
2365                 1 => array('method' => 'REFERRAL'),
2366         );
2367
2368         // Handle it over to generateSelectionBoxFromArray()
2369         $content = generateSelectionBoxFromArray($paymentMethods, 'points_payment_method', 'method', '', '', '', $default);
2370
2371         // Return prepared content
2372         return $content;
2373 }
2374
2375 // Template helper function to create a deferrer code if URL is not empty
2376 function doTemplateDereferrerUrl ($templateName, $clear = FALSE, $url = NULL) {
2377         // Is the URL not NULL and not empty?
2378         if ((!is_null($url)) && (!empty($url))) {
2379                 // Set HTML with EL code
2380                 $url = '<a href="{%pipe,generateDereferrerUrl=' . $url . '%}" rel="external" target="_blank">{--ADMIN_TEST_URL--}</a>';
2381         } // END - if
2382
2383         // Return URL (or content) or dashes if empty
2384         return fixEmptyContentToDashes($url);
2385 }
2386
2387 // Load another template and return its content
2388 function doTemplateLoadTemplate ($templateName, $clear = FALSE, $theTemplate, $content = array()) {
2389         // Load "the" template
2390         return loadTemplate($theTemplate, TRUE, $content);
2391 }
2392
2393 // Output HTML code for favicon.ico, if found
2394 function doTemplateMetaFavIcon ($templateName, $clear = FALSE) {
2395         // Default is not found
2396         $out = '';
2397
2398         // Check all common extensions
2399         foreach (array('ico', 'gif', 'png') as $extension) {
2400                 // Is the file there?
2401                 if (isFileReadable(getPath() . 'favicon.' . $extension)) {
2402                         // Then use this and abort
2403                         $out = '<link rel="shortcut icon" href="{%url=favicon.' . $extension . '%}" type="image/' . $extension . '" />';
2404                         break;
2405                 } // END - if
2406         } // END - while
2407
2408         // Return code
2409         return $out;
2410 }
2411
2412 // Helper function to display referral id or hide it depending on settings
2413 function doTemplateDisplayReferralIdContent ($template, $clear = FALSE) {
2414         // Ddisplay the refid or make it editable?
2415         if (isDisplayRefidEnabled()) {
2416                 // Load "hide" form template
2417                 $out = loadTemplate('guest_register_refid_hide', TRUE);
2418         } else {
2419                 // Load template to enter it
2420                 $out = loadTemplate('guest_register_refid', TRUE);
2421         }
2422
2423         // Return code
2424         return $out;
2425 }
2426
2427 // "Getter" for template base path
2428 function getTemplateBasePath ($part) {
2429         // Is there cache?
2430         if (!isset($GLOBALS[__FUNCTION__][$part])) {
2431                 // "Build" path
2432                 $GLOBALS[__FUNCTION__][$part] = sprintf('%stemplates/%s/%s', getPath(), getLanguage(), $part);
2433         } // END - if
2434
2435         // Return cache
2436         return $GLOBALS[__FUNCTION__][$part];
2437 }
2438
2439 // Removes comments with @DEPRECATED
2440 function removeDeprecatedComment ($output) {
2441         // Explode it into pieces ... ;)
2442         $lines = explode(chr(10), $output);
2443
2444         // Walk through all
2445         $return = '';
2446         foreach ($lines as $line) {
2447                 // Is there a @DEPRECATED?
2448                 if (isInString('@DEPRECATED', $line)) {
2449                         // Ignore this line
2450                         continue;
2451                 } // END - if
2452
2453                 // Add it
2454                 $return .= $line . chr(13);
2455         } // END - foreach
2456
2457         // Returned cleaned content
2458         return $return;
2459 }
2460
2461 // Generates a selection box suitable for e.g. birthdays: day, month and year
2462 function generateDayMonthYearSelectionBox ($day, $month, $year) {
2463         // This depends on selected language
2464         switch (getLanguage()) {
2465                 case 'de': // German date format
2466                         $content = addSelectionBox('da', $day) . addSelectionBox('mo', $month) . addSelectionBox('ye', $year);
2467                         break;
2468
2469                 default: // Default is the US date format... :)
2470                         $content = addSelectionBox('mo', $month) . addSelectionBox('da', $day) . addSelectionBox('ye', $year);
2471                         break;
2472         } // END - switch
2473
2474         // Return content
2475         return $content;
2476 }
2477
2478 // Loads page header
2479 function loadPageHeader () {
2480         // Init header
2481         $GLOBALS['__page_header'] = '';
2482
2483         // Is the header already sent?
2484         if (($GLOBALS['__header_sent'] != 1) && ($GLOBALS['__header_sent'] != 2)) {
2485                 // Set default HTTP status to "200 OK"
2486                 setHttpStatus('200 OK');
2487
2488                 // If not in CSS mode generate the header
2489                 if ((!isCssOutputMode()) && (!isAjaxOutputMode()) && (!isImageOutputMode())) {
2490                         // Prepare the header for HTML output
2491                         loadHtmlHeader();
2492                 } // END - if
2493
2494                 // Closing HEAD tag
2495                 if ($GLOBALS['__header_sent'] == '0') {
2496                         $GLOBALS['__header_sent'] = 1;
2497                 } // END - if
2498         } // END - if
2499
2500         // Add BODY tag or not?
2501         // @TODO Find a way to not use direct module comparison
2502         if ((!isCssOutputMode()) && (!isRawOutputMode()) && ($GLOBALS['__header_sent'] == 1) && (getModule() != 'frametester') && (!isFramesetModeEnabled())) {
2503                 loadTemplate('page_body');
2504                 $GLOBALS['__header_sent'] = 2;
2505         } // END - if
2506 }
2507
2508 // Loads page footer and calls doShutdown()
2509 function loadPageFooter () {
2510         // Init page footer
2511         $GLOBALS['__page_footer'] = '';
2512
2513         // Footer disabled (e.g. CSS/AJAX/image output) or already sent?
2514         // 1234      5                         54    45                              5    5                              543    3                443    3                 443    3                  44321
2515         if ((((!isset($GLOBALS['__footer_sent'])) || (($GLOBALS['__footer_sent'] != 1) && ($GLOBALS['__footer_sent'] != 2))) && (!isCssOutputMode()) && (!isAjaxOutputMode()) && (!isImageOutputMode()))) {
2516                 // Run the filter, sweet huh?
2517                 runFilterChain('page_footer');
2518
2519                 // Load page footer
2520                 $GLOBALS['__page_footer'] .= loadTemplate('page_footer', TRUE);
2521         } // END - if
2522
2523         // Footer has been reached
2524         $GLOBALS['__footer_sent'] = 1;
2525
2526         // Shutdown
2527         doShutdown();
2528 }
2529
2530 // [EOF]
2531 ?>