Continued a bit:
[mailer.git] / inc / general-functions.php
1 <?php
2 /************************************************************************
3  * Mailer v0.2.1-FINAL                                Start: 08/25/2003 *
4  * ===================                          Last change: 11/29/2005 *
5  *                                                                      *
6  * -------------------------------------------------------------------- *
7  * File              : general-functions.php                            *
8  * -------------------------------------------------------------------- *
9  * Short description : Many non-database functions (also file access)   *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Viele Nicht-Datenbank-Funktionen                 *
12  * -------------------------------------------------------------------- *
13  * Copyright (c) 2003 - 2009 by Roland Haeder                           *
14  * Copyright (c) 2009 - 2016 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 // Initialize application
39 function initApplication ($path) {
40         // Initialize the configuration
41         initConfig();
42
43         // Set base path in configuration
44         setConfigEntry('PATH', $path);
45
46         // Load global configuration file
47         loadIncludeOnce('inc/config-global.php');
48
49         // Load more libraries
50         loadLibraries();
51
52         // Set error handler
53         set_error_handler('__errorHandler');
54
55         // Disable block-mode by default
56         enableBlockMode(FALSE);
57
58         // Init error handler
59         initErrorHandler();
60
61         // Init request
62         initRequest();
63
64         // Init userid
65         initMemberId();
66
67         // Set important header_sent
68         if (!isset($GLOBALS['__header_sent'])) {
69                 $GLOBALS['__header_sent'] = '0';
70         } // END - if
71
72         // Init fatal messages
73         initFatalMessages();
74
75         // Enable HTML templates by default
76         enableTemplateHtml();
77
78         // Init stats system
79         initStatsSystem();
80
81         // Init HTTP handling
82         initHttp();
83
84         // Are we in installation phase?
85         if ((!isInstaller()) && (isInstalled())) {
86                 // Regular bootstrap
87                 doNormalBootstrap();
88         } else {
89                 // Installer bootstrap
90                 doInstallerBootstrap();
91         }
92
93         // Handle fatal errors
94         runFilterChain('handle_fatal_errors');
95 }
96
97 // Loads additional libraries
98 function loadLibraries () {
99         // Init arrays
100         $__functions = array();
101         $__libs = array(
102                 'stats',
103                 'xml',
104                 'callback',
105                 'referral',
106                 'email',
107                 'request',
108                 'session',
109                 'code',
110                 'pool',
111                 'language',
112                 'sql',
113                 'expression',
114                 'encryption',
115                 'filter',
116                 'extensions',
117                 'database',
118                 'error',
119                 'math',
120         );
121
122         // Init include file array as it follows same naming scheme
123         foreach ($__libs as $lib) {
124                 // Add it
125                 array_push($__functions, $lib . '-functions');
126         } // END - foreach
127
128         // Add more libs (let's get rid of them slowly)
129         foreach (array('filters') as $lib) {
130                 // Add it
131                 array_push($__functions, $lib);
132         } // END - foreach
133
134         // Load all
135         foreach ($__functions as $lib) {
136                 // Load special functions
137                 loadIncludeOnce('inc/' . $lib . '.php');
138         } // END - foreach
139
140         // Is installer phase?
141         if ((isInstaller()) || (!isInstalled())) {
142                 // Add installer lib as well
143                 loadIncludeOnce('inc/install-functions.php');
144         } // END - if
145 }
146
147 // Init fatal message array
148 function initFatalMessages () {
149         $GLOBALS['fatal_messages'] = array();
150 }
151
152 // Getter for whole fatal error messages
153 function getFatalArray () {
154         return $GLOBALS['fatal_messages'];
155 }
156
157 // Add a fatal error message to the queue array
158 function addFatalMessage ($file, $line, $message, $extra = '') {
159         if (is_array($extra)) {
160                 // Multiple extras for a message with masks
161                 $message = call_user_func_array('sprintf', $extra);
162         } elseif (!empty($extra)) {
163                 // $message is text with a mask plus extras to insert into the text
164                 $message = sprintf($message, $extra);
165         }
166
167         // Add message to $GLOBALS['fatal_messages']
168         array_push($GLOBALS['fatal_messages'], $message);
169
170         // Log fatal messages away
171         logDebugMessage($file, $line, 'Fatal error message: ' . compileCode($message));
172 }
173
174 // Getter for total fatal message count
175 function getTotalFatalErrors () {
176         // Init count
177         $count = 0;
178
179         // Is there at least the first entry?
180         if (!empty($GLOBALS['fatal_messages'][0])) {
181                 // Get total count
182                 $count = count($GLOBALS['fatal_messages']);
183                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'count=' . $count . ' - FROM ARRAY');
184         } // END - if
185
186         // Return value
187         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'count=' . $count . ' - EXIT!');
188         return $count;
189 }
190
191 // Generate a password in a specified length or use default password length
192 function generatePassword ($length = '0', $exclude = array()) {
193         // Auto-fix invalid length of zero
194         if ($length == '0') {
195                 $length = getMinPasswordLength();
196         } // END - if
197
198         // Exclude some entries
199         $localAbc = array_diff($GLOBALS['_abc'], $exclude);
200
201         // $localAbc must have at least 10 entries
202         assert(count($localAbc) >= 10);
203
204         // Start creating password
205         $password = '';
206         while (strlen($password) < $length) {
207                 $password .= $localAbc[mt_rand(0, count($localAbc) -1)];
208         } // END - while
209
210         /*
211          * When the length of the password is below 40 characters additional
212          * security can be added by scrambling it. Otherwise the hash may
213          * corrupted.
214          */
215         if (strlen($password) <= 40) {
216                 // Also scramble the password
217                 $password = scrambleString($password);
218         } // END - if
219
220         // Return the password
221         return $password;
222 }
223
224 // Generates a human-readable timestamp from the Uni* stamp
225 function generateDateTime ($time, $mode = '0') {
226         // Is there cache?
227         if (isset($GLOBALS[__FUNCTION__][$time][$mode])) {
228                 // Return it instead
229                 return $GLOBALS[__FUNCTION__][$time][$mode];
230         } // END - if
231
232         // If the stamp is zero it mostly didn't "happen"
233         if (($time == '0') || (is_null($time))) {
234                 // Never happend
235                 return '{--NEVER_HAPPENED--}';
236         } // END - if
237
238         // Filter out numbers
239         $timeSecured = bigintval($time);
240
241         // Detect language
242         switch (getLanguage()) {
243                 case 'de': // German date / time format
244                         switch ($mode) {
245                                 case '0': $ret = date("d.m.Y \u\m H:i \U\h\\r", $timeSecured); break;
246                                 case '1': $ret = strtolower(date('d.m.Y - H:i', $timeSecured)); break;
247                                 case '2': $ret = date('d.m.Y|H:i', $timeSecured); break;
248                                 case '3': $ret = date('d.m.Y', $timeSecured); break;
249                                 case '4': $ret = date('d.m.Y|H:i:s', $timeSecured); break;
250                                 case '5': $ret = date('d-m-Y (l-F-T)', $timeSecured); break;
251                                 case '6': $ret = date('Ymd', $timeSecured); break;
252                                 case '7': $ret = date('Y-m-d H:i:s', $timeSecured); break; // Compatible with MySQL TIMESTAMP
253                                 default:
254                                         logDebugMessage(__FUNCTION__, __LINE__, sprintf('Invalid date mode %s detected.', $mode));
255                                         break;
256                         } // END - switch
257                         break;
258
259                 default: // Default is the US date / time format!
260                         switch ($mode) {
261                                 case '0': $ret = date('r', $timeSecured); break;
262                                 case '1': $ret = strtolower(date('Y-m-d - g:i A', $timeSecured)); break;
263                                 case '2': $ret = date('y-m-d|H:i', $timeSecured); break;
264                                 case '3': $ret = date('y-m-d', $timeSecured); break;
265                                 case '4': $ret = date('d.m.Y|H:i:s', $timeSecured); break;
266                                 case '5': $ret = date('d-m-Y (l-F-T)', $timeSecured); break;
267                                 case '6': $ret = date('Ymd', $timeSecured); break;
268                                 case '7': $ret = date('Y-m-d H:i:s', $timeSecured); break; // Compatible with MySQL TIMESTAMP
269                                 default:
270                                         logDebugMessage(__FUNCTION__, __LINE__, sprintf('Invalid date mode %s detected.', $mode));
271                                         break;
272                         } // END - switch
273         } // END - switch
274
275         // Store it in cache
276         $GLOBALS[__FUNCTION__][$time][$mode] = $ret;
277
278         // Return result
279         return $ret;
280 }
281
282 // Translates Y/N to yes/no
283 function translateYesNo ($yn) {
284         // Is it cached?
285         if (!isset($GLOBALS[__FUNCTION__][$yn])) {
286                 // Default
287                 $GLOBALS[__FUNCTION__][$yn] = '??? (' . $yn . ')';
288                 switch ($yn) {
289                         case 'Y': // Yes
290                                 $GLOBALS[__FUNCTION__][$yn] = '{--YES--}';
291                                 break;
292
293                         case 'N': // No
294                                 $GLOBALS[__FUNCTION__][$yn] = '{--NO--}';
295                                 break;
296
297                         default: // Log unknown value
298                                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unknown value %s. Expected: Y/N', $yn));
299                                 break;
300                 } // END - switch
301         } // END - if
302
303         // Return it
304         return $GLOBALS[__FUNCTION__][$yn];
305 }
306
307 // "Translates" Y/N into "de-/active"
308 function translateActivationStatus ($status) {
309         // Is it cached?
310         if (!isset($GLOBALS[__FUNCTION__][$status])) {
311                 // Default
312                 $GLOBALS[__FUNCTION__][$status] = '??? (' . $status . ')';
313                 switch ($status) {
314                         case 'Y': // Activated
315                                 $GLOBALS[__FUNCTION__][$status] = '{--ACTIVATED--}';
316                                 break;
317
318                         case 'N': // Deactivated
319                                 $GLOBALS[__FUNCTION__][$status] = '{--DEACTIVATED--}';
320                                 break;
321
322                         default: // Log unknown value
323                                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unknown value %s. Expected: Y/N', $status));
324                                 break;
325                 } // END - switch
326         } // END - if
327
328         // Return it
329         return $GLOBALS[__FUNCTION__][$status];
330 }
331
332 // Translates the american decimal dot into a german comma
333 // OPPOMENT: convertCommaToDot()
334 function translateComma ($dotted, $cut = TRUE, $max = '0') {
335         // First, cast all to double, due to PHP changes
336         $double = (double) $dotted;
337
338         // Use from config is default
339         $maxComma = getConfig('max_comma');
340
341         // Use from parameter?
342         if ($max > 0) {
343                 $maxComma = $max;
344         } // END - if
345
346         // Cut zeros off?
347         if (($cut === TRUE) && ($max == '0')) {
348                 // Test for commata if in cut-mode
349                 $com = explode('.', $double);
350                 if (count($com) < 2) {
351                         // Don't display commatas even if there are none... ;-)
352                         $maxComma = '0';
353                 } // END - if
354         } // END - if
355
356         // Debug log
357
358         // Translate it now
359         $translated = $double;
360         switch (getLanguage()) {
361                 case 'de': // German language
362                         $translated = number_format($double, $maxComma, ',', '.');
363                         break;
364
365                 default: // All others
366                         $translated = number_format($double, $maxComma, '.', ',');
367                         break;
368         } // END - switch
369
370         // Return translated value
371         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'double=' . $double . ',translated=' . $translated . ',maxComma=' . $maxComma);
372         return $translated;
373 }
374
375 // Translate Uni*-like gender to human-readable
376 function translateGender ($gender) {
377         // Default
378         $ret = '!' . $gender . '!';
379
380         // Male/female or company?
381         switch ($gender) {
382                 case 'M': // Male
383                 case 'F': // Female
384                 case 'C': // Company
385                         // Use generic function
386                         $ret = translateGeneric('GENDER', $gender);
387                         break;
388
389                 default:
390                         // Please report bugs on unknown genders
391                         reportBug(__FUNCTION__, __LINE__, sprintf('Unknown gender %s detected.', $gender));
392                         break;
393         } // END - switch
394
395         // Return translated gender
396         return $ret;
397 }
398
399 // "Translates" the user status
400 function translateUserStatus ($status) {
401         // Default status is unknown if something goes through
402         $ret = '{--ACCOUNT_STATUS_UNKNOWN--}';
403
404         // Generate message depending on status
405         switch ($status) {
406                 case 'UNCONFIRMED':
407                 case 'CONFIRMED':
408                 case 'LOCKED':
409                         // Use generic function for all "normal" cases
410                         $ret = translateGeneric('ACCOUNT_STATUS', $status);
411                         break;
412
413                 case '': // Account deleted
414                 case NULL: // Account deleted
415                         $ret = '{--ACCOUNT_STATUS_DELETED--}';
416                         break;
417
418                 default: // Please report all unknown status
419                         reportBug(__FUNCTION__, __LINE__, sprintf('Unknown status %s(%s) detected.', $status, gettype($status)));
420                         break;
421         } // END - switch
422
423         // Return it
424         return $ret;
425 }
426
427 // "Translates" 'visible' and 'locked' to a CSS class
428 function translateMenuVisibleLocked ($content, $prefix = '') {
429         // 1st parameter should be an array
430         assert(is_array($content));
431
432         // Default is 'menu_unknown'
433         $content['visible_css'] = $prefix . 'menu_unknown';
434
435         // Translate 'visible' and keep an eye on the prefix
436         switch ($content['visible']) {
437                 case 'Y': // Should be visible
438                         $content['visible_css'] = $prefix . 'menu_visible';
439                         break;
440
441                 case 'N': // Is invisible
442                         $content['visible_css'] = $prefix . 'menu_invisible';
443                         break;
444
445                 default: // Please report this
446                         reportBug(__FUNCTION__, __LINE__, 'Unsupported visible value detected. content=<pre>' . print_r($content, TRUE) . '</pre>');
447                         break;
448         } // END - switch
449
450         // Translate 'locked' and keep an eye on the prefix
451         switch ($content['locked']) {
452                 case 'Y': // Should be locked, only admins can call this
453                         $content['locked_css'] = $prefix . 'menu_locked';
454                         break;
455
456                 case 'N': // Is unlocked and visible to members/guests/sponsors
457                         $content['locked_css'] = $prefix . 'menu_unlocked';
458                         break;
459
460                 default: // Please report this
461                         reportBug(__FUNCTION__, __LINE__, 'Unsupported locked value detected. content=<pre>' . print_r($content, TRUE) . '</pre>');
462                         break;
463         } // END - switch
464
465         // Return the resulting array
466         return $content;
467 }
468
469 // Generates an URL for the dereferer
470 function generateDereferrerUrl ($url) {
471         // Don't de-refer our own links!
472         if ((!empty($url)) && (substr($url, 0, strlen(getUrl())) != getUrl())) {
473                 // Encode URL
474                 $encodedUrl = encodeString(compileUriCode($url));
475
476                 // Generate hash
477                 $hash = generateHash($url . getSiteKey() . getDateKey());
478
479                 // Log plain URL and hash
480                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ',hash=' . $hash . '(' . strlen($hash) . ')');
481
482                 // De-refer this URL
483                 $url = sprintf(
484                                 '{%%url=modules.php?module=loader&amp;url=%s&amp;hash=%s&amp;salt=%s%%}',
485                                 $encodedUrl,
486                                 encodeHashForCookie($hash),
487                                 substr($hash, 0, getSaltLength())
488                 );
489         } // END - if
490
491         // Return link
492         return $url;
493 }
494
495 // Generates an URL for the frametester
496 function generateFrametesterUrl ($url) {
497         // Prepare frametester URL
498         $frametesterUrl = sprintf('{%%url=modules.php?module=frametester&amp;url=%s%%}',
499                 encodeString(compileUriCode($url))
500         );
501
502         // Return the new URL
503         return $frametesterUrl;
504 }
505
506 // Count entries from e.g. a selection box
507 function countSelection ($array) {
508         // Integrity check
509         if (!is_array($array)) {
510                 // Not an array!
511                 reportBug(__FUNCTION__, __LINE__, 'No array provided.');
512         } // END - if
513
514         // Init count
515         $ret = '0';
516
517         // Count all entries
518         foreach ($array as $selected) {
519                 // Is it checked?
520                 if (!empty($selected)) {
521                         // Yes, then count it
522                         $ret++;
523                 } // END - if
524         } // END - foreach
525
526         // Return counted selections
527         return $ret;
528 }
529
530 // Generates a timestamp (some wrapper for mktime())
531 function makeTime ($hours, $minutes, $seconds, $stamp) {
532         // Extract day, month and year from given timestamp
533         $days   = getDay($stamp);
534         $months = getMonth($stamp);
535         $years  = getYear($stamp);
536
537         // Create timestamp for wished time which depends on extracted date
538         return mktime(
539                 $hours,
540                 $minutes,
541                 $seconds,
542                 $months,
543                 $days,
544                 $years
545         );
546 }
547
548 // Redirects to an URL and if neccessarry extends it with own base URL
549 // @TODO $allowSpider is unused
550 function redirectToUrl ($url, $allowSpider = TRUE, $compileCode = TRUE) {
551         // Is the output mode -2?
552         if (isAjaxOutputMode()) {
553                 // This is always (!) an AJAX request and shall not be redirected
554                 return;
555         } // END - if
556
557         // Remove {%url=
558         if (substr($url, 0, 6) == '{%url=') {
559                 $url = substr($url, 6, -2);
560         } // END - if
561
562         // Compile codes out?
563         if ($compileCode === TRUE) {
564                 // Compile out codes
565                 eval('$url = "' . compileRawCode(encodeUrl($url)) . '";');
566         } // END - if
567
568         // Default 'rel' value is external, nofollow is evil from Google and hurts the Internet
569         $rel = ' rel="external"';
570
571         // Is there internal or external URL?
572         if (substr($url, 0, strlen(getUrl())) == getUrl()) {
573                 // Own (=internal) URL
574                 $rel = '';
575         } // END - if
576
577         // Three different ways to debug...
578         //* DEBUG: */ reportBug(__FUNCTION__, __LINE__, 'URL=' . $url);
579         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'URL=' . $url);
580         //* DEBUG-DIE: */ die(__METHOD__ . ':url=' . $url . '<br />compileCode=' . intval($compileCode));
581
582         // We should not sent a redirect if headers are already sent
583         if (!headers_sent()) {
584                 // Compile again?
585                 if ($compileCode === TRUE) {
586                         // Do final compilation
587                         $url = doFinalCompilation(str_replace('&amp;', '&', $url), FALSE);
588                 } // END - if
589
590                 // Load URL when headers are not sent
591                 sendRawRedirect($url);
592         } else {
593                 // Output error message
594                 loadPageHeader();
595                 loadTemplate('redirect_url', FALSE, str_replace('&amp;', '&', $url));
596                 loadPageFooter();
597         }
598
599         // Shut the mailer down here
600         doShutdown();
601 }
602
603 /************************************************************************
604  *                                                                      *
605  * Gaenderter Sortier-Algorythmus, $array wird nach dem Array (!)       *
606  * $a_sort sortiert:                                                    *
607  *                                                                      *
608  * $array - Das 3-dimensionale Array, das paralell sortiert werden soll *
609  * $a_sort - Array, das die Sortiereihenfolge der ersten Elementeben    *
610  * $primary_key - Primaerschl.ssel aus $a_sort, nach dem sortiert wird  *
611  * $order - Sortiereihenfolge: -1 = a-Z, 0 = keine, 1 = Z-a             *
612  * $nums - TRUE = Als Zahlen sortieren, FALSE = Als Zeichen sortieren   *
613  *                                                                      *
614  * $a_sort muss Elemente enthalten, deren Wert Schluessel von $array    *
615  * sind... Klingt kompliziert, suchen Sie mal mein Beispiel, dann sehen *
616  * Sie, dass es doch nicht so schwer ist! :-)                           *
617  *                                                                      *
618  ************************************************************************/
619 function array_pk_sort (&$array, $a_sort, $primary_key = '0', $order = -1, $nums = FALSE) {
620         $temporaryArray = $array;
621         while ($primary_key < count($a_sort)) {
622                 foreach ($temporaryArray[$a_sort[$primary_key]] as $key => $value) {
623                         foreach ($temporaryArray[$a_sort[$primary_key]] as $key2 => $value2) {
624                                 $match = FALSE;
625                                 if ($nums === FALSE) {
626                                         // Sort byte-by-byte (also numbers will be interpreted as chars! E.g.: "9" > "10")
627                                         if (($key != $key2) && (strcmp(strtolower($temporaryArray[$a_sort[$primary_key]][$key]), strtolower($temporaryArray[$a_sort[$primary_key]][$key2])) == $order)) $match = TRUE;
628                                 } elseif ($key != $key2) {
629                                         // Sort numbers (E.g.: 9 < 10)
630                                         if (($temporaryArray[$a_sort[$primary_key]][$key] < $temporaryArray[$a_sort[$primary_key]][$key2]) && ($order == -1)) $match = TRUE;
631                                         if (($temporaryArray[$a_sort[$primary_key]][$key] > $temporaryArray[$a_sort[$primary_key]][$key2]) && ($order ==  1)) $match = TRUE;
632                                 }
633
634                                 if ($match) {
635                                         // We have found two different values, so let's sort whole array
636                                         foreach ($temporaryArray as $sort_key => $sort_val) {
637                                                 $t = $temporaryArray[$sort_key][$key];
638                                                 $temporaryArray[$sort_key][$key]  = $temporaryArray[$sort_key][$key2];
639                                                 $temporaryArray[$sort_key][$key2] = $t;
640                                                 unset($t);
641                                         } // END - foreach
642                                 } // END - if
643                         } // END - foreach
644                 } // END - foreach
645
646                 // Count one up
647                 $primary_key++;
648         } // END - while
649
650         // Write back sorted array
651         $array = $temporaryArray;
652 }
653
654
655 //
656 // Deprecated : $length (still has one reference in this function)
657 // Optional   : $extraData
658 //
659 function generateRandomCode ($length, $code, $userid, $extraData = '') {
660         // Build server string
661         $server = $_SERVER['REQUEST_URI'] . getEncryptSeparator() . detectUserAgent() . getEncryptSeparator() . getenv('SERVER_SOFTWARE') . getEncryptSeparator() . detectRealIpAddress() . getEncryptSeparator() . detectRemoteAddr();
662
663         // Build key string
664         $keys = getSiteKey() . getEncryptSeparator() . getDateKey();
665         if (isConfigEntrySet('secret_key')) {
666                 $keys .= getEncryptSeparator() . getSecretKey();
667         } // END - if
668         if (isConfigEntrySet('file_hash')) {
669                 $keys .= getEncryptSeparator() . getFileHash();
670         } // END - if
671
672         if (isConfigEntrySet('master_salt')) {
673                 $keys .= getEncryptSeparator() . getMasterSalt();
674         } // END - if
675
676         // Build string from misc data
677         $data  = $code . getEncryptSeparator() . $userid . getEncryptSeparator() . $extraData;
678
679         // Add more additional data
680         if (isSessionVariableSet('u_hash')) {
681                 $data .= getEncryptSeparator() . getSession('u_hash');
682         } // END - if
683
684         // Add referral id, language, theme and userid
685         $data .= getEncryptSeparator() . determineReferralId();
686         $data .= getEncryptSeparator() . getLanguage();
687         $data .= getEncryptSeparator() . getCurrentTheme();
688         $data .= getEncryptSeparator() . getMemberId();
689
690         // Calculate number for generating the code
691         $a = $code + getConfig('_ADD') - 1;
692
693         if (isConfigEntrySet('master_salt')) {
694                 // Generate hash with master salt from modula of number with the prime number and other data
695                 $saltedHash = generateHash(($a % getPrime()) . getEncryptSeparator() . $server . getEncryptSeparator() . $keys . getEncryptSeparator() . $data . getEncryptSeparator() . getDateKey() . getEncryptSeparator() . $a, getMasterSalt());
696         } else {
697                 // Generate hash with "hash of site key" from modula of number with the prime number and other data
698                 $saltedHash = generateHash(($a % getPrime()) . getEncryptSeparator() . $server . getEncryptSeparator() . $keys . getEncryptSeparator() . $data . getEncryptSeparator() . getDateKey() . getEncryptSeparator() . $a, substr(sha1(getSiteKey()), 0, getSaltLength()));
699         }
700
701         // Create number from hash
702         $rcode = hexdec(substr($saltedHash, getSaltLength(), 9)) / abs(getRandNo() - $a + sqrt(getConfig('_ADD'))) / pi();
703
704         // At least 10 numbers shall be secure enought!
705         if (isExtensionActive('other')) {
706                 $len = getCodeLength();
707         } else {
708                 $len = $length;
709         } // END - if
710
711         // Smaller 1 is not okay
712         if ($len < 1) {
713                 // Fix it to 10
714                 $len = 10;
715         } // END - if
716
717         // Cut off requested counts of number, but skip first digit (which is mostly a zero)
718         $return = substr($rcode, (strpos($rcode, '.') + 1), $len);
719
720         // Done building code
721         return $return;
722 }
723
724 // Does only allow numbers
725 function bigintval ($num, $castValue = TRUE, $abortOnMismatch = TRUE) {
726         //* DEBUG: */ debugOutput('[' . __FUNCTION__ . ':' . __LINE__ . '] ' . 'num=' . $num . ',castValue=' . intval($castValue) . ',abortOnMismatch=' . intval($abortOnMismatch) . ' - ENTERED!');
727         // Filter all non-number chars out, so only number chars will remain
728         $ret = preg_replace('/[^0123456789]/', '', $num);
729
730         // Shall we cast?
731         if ($castValue === TRUE) {
732                 // Cast to biggest numeric type
733                 $ret = (double) $ret;
734         } // END - if
735
736         // Has the whole value changed?
737         if (('' . $ret . '' != '' . $num . '') && ($abortOnMismatch === TRUE) && (!is_null($num))) {
738                 // Log the values
739                 reportBug(__FUNCTION__, __LINE__, 'Problem with number found. ret[' . gettype($ret) . ']=' . $ret . ', num[' . gettype($num) . ']='. $num);
740         } // END - if
741
742         // Return result
743         //* DEBUG: */ debugOutput('[' . __FUNCTION__ . ':' . __LINE__ . '] ' . 'num=' . $num . ',castValue=' . intval($castValue) . ',abortOnMismatch=' . intval($abortOnMismatch) . ',ret=' . $ret . ' - EXIT!');
744         return $ret;
745 }
746
747 // Creates a Uni* timestamp from given selection data and prefix
748 function createEpocheTimeFromSelections ($prefix, $postData) {
749         // Assert on typical array element (maybe all?)
750         assert(isset($postData[$prefix . '_ye']));
751
752         // Initial return value
753         $ret = '0';
754
755         // Is there a leap year?
756         $SWITCH = '0';
757         $TEST   = getYear() / 4;
758         $M1     = getMonth();
759
760         // If so and if current time is before 02/29 and estimated time is after 02/29 then add 86400 seconds (one day)
761         // 01     2     2         1    1           1    123     4                          43    3                                 32    233    4                          43    3                                 3210
762         if ((floor($TEST) == $TEST) && ($M1 == '02') && (((isset($postData[$prefix . '_mo'])) && ($postData[$prefix . '_mo'] > '02')) || ((isset($postData[$prefix . '_mn'])) && ($postData[$prefix . '_mn'] > '02')))) {
763                 $SWITCH = getOneDay();
764         } // END - if
765
766         // First add years...
767         $ret += $postData[$prefix . '_ye'] * (31536000 + $SWITCH);
768
769         // Next months...
770         if (isset($postData[$prefix . '_mo'])) {
771                 $ret += $postData[$prefix . '_mo'] * 2628000;
772         } elseif (isset($postData[$prefix . '_mn'])) {
773                 $ret += $postData[$prefix . '_mn'] * 2628000;
774         }
775
776         // Next weeks
777         $ret += $postData[$prefix . '_we'] * 604800;
778
779         // Next days...
780         $ret += $postData[$prefix . '_da'] * 86400;
781
782         // Next hours...
783         $ret += $postData[$prefix . '_ho'] * 3600;
784
785         // Next minutes..
786         $ret += $postData[$prefix . '_mi'] * 60;
787
788         // And at last seconds...
789         $ret += $postData[$prefix . '_se'];
790
791         // Return calculated value
792         return $ret;
793 }
794
795 // Creates a 'fancy' human-readable timestamp from a Uni* stamp
796 function createFancyTime ($stamp) {
797         // Get data array with years/months/weeks/days/...
798         $data = createTimeSelections($stamp, '', '', '', TRUE);
799         $ret = '';
800         foreach ($data as $k => $v) {
801                 if ($v > 0) {
802                         // Value is greater than 0 "eval" data to return string
803                         $ret .= ', ' . $v . ' {%pipe,translateTimeUnit=' . $k . '%}';
804                         break;
805                 } // END - if
806         } // END - foreach
807
808         // Is something there?
809         if (!empty($ret)) {
810                 // Remove leading commata and space
811                 $ret = substr($ret, 2);
812         } else {
813                 // Zero seconds
814                 $ret = '0 {--TIME_UNIT_SECOND--}';
815         }
816
817         // Return fancy time string
818         return $ret;
819 }
820
821 // Taken from www.php.net isInStringIgnoreCase() user comments
822 function isEmailValid ($email) {
823         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'email=' . $email . ' - ENTERED!');
824
825         // Is there cache?
826         if (!isset($GLOBALS[__FUNCTION__][$email])) {
827                 // Check first part of email address
828                 $first = '[-a-z0-9!#$%&\'*+/=?^_<{|}~]+(\.[-a-zA-Z0-9!#$%&\'*+/=?^_<{|}~]+)*';
829
830                 //  Check domain
831                 $domain = '[a-z0-9-]+(\.[a-z0-9-]{2,5})+';
832
833                 // Generate pattern
834                 $regex = '@^' . $first . '\@' . $domain . '$@iU';
835
836                 // Determine it
837                 $GLOBALS[__FUNCTION__][$email] = (($email != getMessage('DEFAULT_WEBMASTER')) && (preg_match($regex, $email)));
838         } // END - if
839
840         // Return check result
841         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'email=' . $email . ',isValid=' . intval($GLOBALS[__FUNCTION__][$email]) . ' - EXIT!');
842         return $GLOBALS[__FUNCTION__][$email];
843 }
844
845 // Function taken from user comments on www.php.net / function isInStringIgnoreCase()
846 function isUrlValid ($url, $compile = TRUE) {
847         // Trim URL a little
848         $url = trim(urldecode($url));
849         //* DEBUG: */ debugOutput($url);
850
851         // Compile some chars out...
852         if ($compile === TRUE) {
853                 $url = compileUriCode($url, FALSE, FALSE, FALSE);
854         } // END - if
855         //* DEBUG: */ debugOutput($url);
856
857         // Check for the extension filter
858         if (isExtensionActive('filter')) {
859                 // Use the extension's filter set
860                 return FILTER_VALIDATE_URL($url, FALSE);
861         } // END - if
862
863         /*
864          * If not installed, perform a simple test. Just make it sure there is always a
865          * http:// or https:// in front of the URLs.
866          */
867         return isUrlValidSimple($url);
868 }
869
870 // Generate a hash for extra-security for all passwords
871 function generateHash ($plainText, $salt = '', $hash = TRUE) {
872         // Debug output
873         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'plainText('.strlen($plainText).')=' . $plainText . ',salt('.strlen($salt).')=' . $salt . ',hash=' . intval($hash));
874
875         // Is the required extension 'sql_patches' there and a salt is not given?
876         // 123                            4                      43    3     4     432    2                  3             32    2                             3                32    2      3     3      21
877         if (((isExtensionInstalledAndOlder('sql_patches', '0.3.6')) && (empty($salt))) || (!isExtensionActive('sql_patches')) || (!isExtensionInstalledAndNewer('other', '0.2.5')) || (strlen($salt) == 32)) {
878                 // Extension ext-sql_patches is missing/outdated so we hash the plain text with MD5
879                 if ($hash === TRUE) {
880                         // Is plain password
881                         return md5($plainText);
882                 } else {
883                         // Is already a hash
884                         return $plainText;
885                 }
886         } // END - if
887
888         // Is an arry element missing here?
889         if (!isConfigEntrySet('file_hash')) {
890                 // Stop here
891                 reportBug(__FUNCTION__, __LINE__, 'Missing file_hash in ' . __FUNCTION__ . '.');
892         } // END - if
893
894         // When the salt is empty build a new one, else use the first x configured characters as the salt
895         if (empty($salt)) {
896                 // Build server string for more entropy
897                 $server = $_SERVER['REQUEST_URI'] . getEncryptSeparator() . detectUserAgent() . getEncryptSeparator() . getenv('SERVER_SOFTWARE') . getEncryptSeparator() . detectRealIpAddress() . getEncryptSeparator() . detectRemoteAddr();
898
899                 // Build key string
900                 $keys = getSiteKey() . getEncryptSeparator() . getDateKey() . getEncryptSeparator() . getFileHash() . getEncryptSeparator() . getMasterSalt();
901
902                 // Is the secret_key config entry set?
903                 if (isConfigEntrySet('secret_key')) {
904                         // Add it
905                         $keys .= getEncryptSeparator() . getSecretKey();
906                 } // END - if
907
908                 // Additional data
909                 $data = $plainText . getEncryptSeparator() . uniqid(mt_rand(), TRUE) . getEncryptSeparator() . time();
910
911                 // Calculate number for generating the code
912                 $a = time() + getConfig('_ADD') - 1;
913
914                 // Generate SHA1 sum from modula of number and the prime number
915                 $sha1 = sha1(($a % getPrime()) . $server . getEncryptSeparator() . $keys . getEncryptSeparator() . $data . getEncryptSeparator() . getDateKey() . getEncryptSeparator() . $a);
916                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'SHA1=' . $sha1.' ('.strlen($sha1).')');
917                 $sha1 = scrambleString($sha1);
918                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Scrambled=' . $sha1.' ('.strlen($sha1).')');
919                 //* DEBUG: */ $sha1b = descrambleString($sha1);
920                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Descrambled=' . $sha1b.' ('.strlen($sha1b).')');
921
922                 // Generate the password salt string
923                 $salt = substr($sha1, 0, getSaltLength());
924                 //* DEBUG: */ debugOutput($salt.' ('.strlen($salt).')');
925         } else {
926                 // Use given salt
927                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'salt=' . $salt);
928                 $salt = substr($salt, 0, getSaltLength());
929                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'salt=' . $salt . '(' . strlen($salt) . '/' . getSaltLength() . ')');
930
931                 // Sanity check on salt
932                 if (strlen($salt) != getSaltLength()) {
933                         // Not the same!
934                         reportBug(__FUNCTION__, __LINE__, 'salt length mismatch! (' . strlen($salt) . '/' . getSaltLength() . ')');
935                 } // END - if
936         }
937
938         // Generate final hash (for debug output)
939         $finalHash = $salt . sha1($salt . $plainText);
940
941         // Debug output
942         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'finalHash('.strlen($finalHash).')=' . $finalHash);
943
944         // Return hash
945         return $finalHash;
946 }
947
948 // Scramble a string
949 function scrambleString ($str) {
950         // Init
951         $scrambled = '';
952
953         // Final check, in case of failure it will return unscrambled string
954         if (strlen($str) > 40) {
955                 // The string is to long
956                 return $str;
957         } elseif ((strlen($str) == 40) && (getPassScramble() != '')) {
958                 // From database
959                 $scramble = getPassScramble();
960         } else {
961                 // Generate new numbers
962                 $scramble = genScrambleString(strlen($str));
963         }
964
965         // Convert it into an array
966         $scrambleNums = explode(':', $scramble);
967
968         // Assert on both lengths
969         assert(strlen($str) == count($scrambleNums));
970
971         // Scramble string here
972         //* DEBUG: */ debugOutput('***Original=' . $str.'***<br />');
973         for ($idx = 0; $idx < strlen($str); $idx++) {
974                 // Get char on scrambled position
975                 $char = substr($str, $scrambleNums[$idx], 1);
976
977                 // Add it to final output string
978                 $scrambled .= $char;
979         } // END - for
980
981         // Return scrambled string
982         //* DEBUG: */ debugOutput('***Scrambled=' . $scrambled.'***<br />');
983         return $scrambled;
984 }
985
986 // De-scramble a string scrambled by scrambleString()
987 function descrambleString ($str) {
988         // Scramble only 40 chars long strings
989         if (strlen($str) != 40) {
990                 return $str;
991         } // END - if
992
993         // Load numbers from config
994         $scrambleNums = explode(':', getPassScramble());
995
996         // Validate numbers
997         if (count($scrambleNums) != 40) {
998                 return $str;
999         } // END - if
1000
1001         // Begin descrambling
1002         $orig = str_repeat(' ', 40);
1003         //* DEBUG: */ debugOutput('+++Scrambled=' . $str.'+++<br />');
1004         for ($idx = 0; $idx < 40; $idx++) {
1005                 $char = substr($str, $idx, 1);
1006                 $orig = substr_replace($orig, $char, $scrambleNums[$idx], 1);
1007         } // END - for
1008
1009         // Return scrambled string
1010         //* DEBUG: */ debugOutput('+++Original=' . $orig.'+++<br />');
1011         return $orig;
1012 }
1013
1014 // Generated a "string" for scrambling
1015 function genScrambleString ($len) {
1016         // Prepare array for the numbers
1017         $scrambleNumbers = array();
1018
1019         // First we need to setup randomized numbers from 0 to 31
1020         for ($idx = 0; $idx < $len; $idx++) {
1021                 // Generate number
1022                 $rand = mt_rand(0, ($len - 1));
1023
1024                 // Check for it by creating more numbers
1025                 while (array_key_exists($rand, $scrambleNumbers)) {
1026                         $rand = mt_rand(0, ($len - 1));
1027                 } // END - while
1028
1029                 // Add number
1030                 $scrambleNumbers[$rand] = $rand;
1031         } // END - for
1032
1033         // So let's create the string for storing it in database
1034         $scrambleString = implode(':', $scrambleNumbers);
1035
1036         // Return it
1037         return $scrambleString;
1038 }
1039
1040 // Generate an PGP-like encrypted hash of given hash for e.g. cookies
1041 function encodeHashForCookie ($passHash) {
1042         // Return vanilla password hash
1043         $ret = $passHash;
1044
1045         // Is a secret key and master salt already initialized?
1046         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, intval(isExtensionInstalled('sql_patches')) . '/' . intval(isConfigEntrySet('_PRIME')) . '/' . intval(isConfigEntrySet('secret_key')) . '/' . intval(isConfigEntrySet('master_salt')));
1047         if ((isExtensionInstalled('sql_patches')) && (isConfigEntrySet('_PRIME')) && (isConfigEntrySet('secret_key')) && (isConfigEntrySet('master_salt'))) {
1048                 // Only calculate when the secret key is generated
1049                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, strlen($passHash) . '/' . strlen(getSecretKey()));
1050                 if ((strlen($passHash) != 49) || (strlen(getSecretKey()) != 40)) {
1051                         // Both keys must have same length so return unencrypted
1052                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, strlen($passHash) . '!=49/' . strlen(getSecretKey()) . '!=40 -  EXIT!');
1053                         return $ret;
1054                 } // END - if
1055
1056                 $newHash = ''; $start = 9;
1057                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'passHash=' . $passHash . '(' . strlen($passHash) . ')');
1058                 for ($idx = 0; $idx < 20; $idx++) {
1059                         // Get hash parts and convert them (00-FF) to matching ASCII value (0-255)
1060                         $part1 = hexdec(substr($passHash     , $start, 2));
1061                         $part2 = hexdec(substr(getSecretKey(), $start, 2));
1062
1063                         // Default is hexadecimal of index if both are same
1064                         $mod = dechex($idx);
1065
1066                         // Is part1 larger or part2 than its counter part?
1067                         if ($part1 > $part2) {
1068                                 // part1 is larger
1069                                 $mod = dechex(sqrt(($part1 - $part2) * getPrime() / pi()));
1070                         } elseif ($part2 > $part1) {
1071                                 // part2 is larger
1072                                 $mod = dechex(sqrt(($part2 - $part1) * getPrime() / pi()));
1073                         }
1074
1075                         $mod = substr($mod, 0, 2);
1076                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'idx=' . $idx . ',part1=' . $part1 . '/part2=' . $part2 . '/mod=' . $mod . '(' . strlen($mod) . ')');
1077                         $mod = padLeftZero($mod, 2);
1078                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'mod(' . ($idx * 2) . ')=' . $mod . '*');
1079                         $start += 2;
1080                         $newHash .= $mod;
1081                 } // END - for
1082
1083                 // Just copy it over, as the master salt is not really helpful here
1084                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, $passHash . '(' . strlen($passHash) . '),' . $newHash . ' (' . strlen($newHash) . ')');
1085                 $ret = $newHash;
1086         } // END - if
1087
1088         // Return result
1089         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'ret=' . $ret . '');
1090         return $ret;
1091 }
1092
1093 // Fix "deleted" cookies
1094 function fixDeletedCookies ($cookies) {
1095         // Is this an array with entries?
1096         if (isFilledArray($cookies)) {
1097                 // Then check all cookies if they are marked as deleted!
1098                 foreach ($cookies as $cookieName) {
1099                         // Is the cookie set to "deleted"?
1100                         if (getSession($cookieName) == 'deleted') {
1101                                 setSession($cookieName, '');
1102                         } // END - if
1103                 } // END - foreach
1104         } // END - if
1105 }
1106
1107 // Checks if a given apache module is loaded
1108 function isApacheModuleLoaded ($apacheModule) {
1109         // Check it and return result
1110         return (((function_exists('apache_get_modules')) && (in_array($apacheModule, apache_get_modules()))) || (!function_exists('apache_get_modules')));
1111 }
1112
1113 // Get current theme name
1114 function getCurrentTheme () {
1115         // The default theme is 'default'... ;-)
1116         $ret = 'default';
1117
1118         // Is there ext-theme installed and active or is 'theme' in URL or POST data?
1119         if (isExtensionActive('theme')) {
1120                 // Call inner method
1121                 $ret = getActualTheme();
1122         } elseif ((isPostRequestElementSet('theme')) && (isThemeReadable(postRequestElement('theme')))) {
1123                 // Use value from POST data
1124                 $ret = postRequestElement('theme');
1125         } elseif ((isGetRequestElementSet('theme')) && (isThemeReadable(getRequestElement('theme')))) {
1126                 // Use value from GET data
1127                 $ret = getRequestElement('theme');
1128         } elseif ((isMailerThemeSet()) && (isThemeReadable(getMailerTheme()))) {
1129                 // Use value from GET data
1130                 $ret = getMailerTheme();
1131         }
1132
1133         // Return theme value
1134         return $ret;
1135 }
1136
1137 // Generates an error code from given account status
1138 function generateErrorCodeFromUserStatus ($status = '') {
1139         // If no status is provided, use the default, cached
1140         if ((empty($status)) && (isMember())) {
1141                 // Get user status
1142                 $status = getUserData('status');
1143         } // END - if
1144
1145         // Default error code if unknown account status
1146         $errorCode = getCode('ACCOUNT_UNKNOWN');
1147
1148         // Generate constant name
1149         $codeName = sprintf('ACCOUNT_%s', strtoupper($status));
1150
1151         // Is the constant there?
1152         if (isCodeSet($codeName)) {
1153                 // Then get it!
1154                 $errorCode = getCode($codeName);
1155         } else {
1156                 // Unknown status
1157                 logDebugMessage(__FUNCTION__, __LINE__, sprintf('Unknown error status %s detected.', $status));
1158         }
1159
1160         // Return error code
1161         return $errorCode;
1162 }
1163
1164 // Back-ported from the new ship-simu engine. :-)
1165 function debug_get_printable_backtrace () {
1166         // Init variable
1167         $backtrace = '<ol>';
1168
1169         // Get and prepare backtrace for output
1170         $backtraceArray = debug_backtrace();
1171         foreach ($backtraceArray as $key => $trace) {
1172                 if (!isset($trace['file'])) $trace['file'] = __FUNCTION__;
1173                 if (!isset($trace['line'])) $trace['line'] = __LINE__;
1174                 if (!isset($trace['args'])) $trace['args'] = array();
1175                 $backtrace .= '<li class="debug_list"><span class="backtrace_file">' . basename($trace['file']) . '</span>:' . $trace['line'] . ', <span class="backtrace_function">' . $trace['function'] . '(' . count($trace['args']) . ')</span></li>';
1176         } // END - foreach
1177
1178         // Close it
1179         $backtrace .= '</ol>';
1180
1181         // Return the backtrace
1182         return $backtrace;
1183 }
1184
1185 // A mail-able backtrace
1186 function debug_get_mailable_backtrace () {
1187         // Init variable
1188         $backtrace = '';
1189
1190         // Get and prepare backtrace for output
1191         $backtraceArray = debug_backtrace();
1192         foreach ($backtraceArray as $key => $trace) {
1193                 if (!isset($trace['file'])) $trace['file'] = __FUNCTION__;
1194                 if (!isset($trace['line'])) $trace['line'] = __LINE__;
1195                 if (!isset($trace['args'])) $trace['args'] = array();
1196                 $backtrace .= ($key+1) . '.:' . basename($trace['file']) . ':' . $trace['line'] . ', ' . $trace['function'] . '(' . count($trace['args']) . ")\n";
1197         } // END - foreach
1198
1199         // Return the backtrace
1200         return $backtrace;
1201 }
1202
1203 // Generates a ***weak*** seed
1204 function generateSeed () {
1205         return microtime(TRUE) * 100000;
1206 }
1207
1208 // Converts a message code to a human-readable message
1209 function getMessageFromErrorCode ($code) {
1210         // Default is an unknown error code
1211         $message = '{%message,UNKNOWN_ERROR_CODE=' . $code . '%}';
1212
1213         // Which code is provided?
1214         switch ($code) {
1215                 case '':
1216                         // No error code is bad coding practice
1217                         reportBug(__FUNCTION__, __LINE__, 'Empty error code supplied. Please fix your code.');
1218                         break;
1219
1220                 // All error messages
1221                 case getCode('LOGOUT_DONE')         : $message = '{--LOGOUT_DONE--}'; break;
1222                 case getCode('LOGOUT_FAILED')       : $message = '<span class="bad">{--LOGOUT_FAILED--}</span>'; break;
1223                 case getCode('DATA_INVALID')        : $message = '{--MAIL_DATA_INVALID--}'; break;
1224                 case getCode('POSSIBLE_INVALID')    : $message = '{--MAIL_POSSIBLE_INVALID--}'; break;
1225                 case getCode('USER_404')            : $message = '{--USER_404--}'; break;
1226                 case getCode('STATS_404')           : $message = '{--MAIL_STATS_404--}'; break;
1227                 case getCode('ALREADY_CONFIRMED')   : $message = '{--MAIL_ALREADY_CONFIRMED--}'; break;
1228                 case getCode('BEG_SAME_AS_OWN')     : $message = '{--BEG_SAME_USERID_AS_OWN--}'; break;
1229                 case getCode('LOGIN_FAILED')        : $message = '{--GUEST_LOGIN_FAILED_GENERAL--}'; break;
1230                 case getCode('MODULE_MEMBER_ONLY')  : $message = '{%message,MODULE_MEMBER_ONLY=' . getRequestElement('mod') . '%}'; break;
1231                 case getCode('OVERLENGTH')          : $message = '{--MEMBER_TEXT_OVERLENGTH--}'; break;
1232                 case getCode('URL_FOUND')           : $message = '{--MEMBER_TEXT_CONTAINS_URL--}'; break;
1233                 case getCode('SUBJECT_URL')         : $message = '{--MEMBER_SUBJECT_CONTAINS_URL--}'; break;
1234                 case getCode('BLIST_URL')           : $message = '{--MEMBER_URL_BLACK_LISTED--}<br />{--MEMBER_BLIST_TIME--}: ' . generateDateTime(getRequestElement('blist'), 0); break;
1235                 case getCode('NO_RECS_LEFT')        : $message = '{--MEMBER_SELECTED_MORE_RECS--}'; break;
1236                 case getCode('INVALID_TAGS')        : $message = '{--MEMBER_HTML_INVALID_TAGS--}'; break;
1237                 case getCode('MORE_POINTS')         : $message = '{--MEMBER_MORE_POINTS_NEEDED--}'; break;
1238                 case getCode('MORE_RECEIVERS1')     : $message = '{--MEMBER_ENTER_MORE_RECEIVERS--}'; break;
1239                 case getCode('MORE_RECEIVERS2')     : $message = '{--MEMBER_NO_MORE_RECEIVERS_FOUND--}'; break;
1240                 case getCode('MORE_RECEIVERS3')     : $message = '{--MEMBER_ENTER_MORE_MIN_RECEIVERS--}'; break;
1241                 case getCode('INVALID_URL')         : $message = '{--MEMBER_ENTER_INVALID_URL--}'; break;
1242                 case getCode('NO_MAIL_TYPE')        : $message = '{--MEMBER_NO_MAIL_TYPE_SELECTED--}'; break;
1243                 case getCode('PROFILE_UPDATED')     : $message = '{--MEMBER_PROFILE_UPDATED--}'; break;
1244                 case getCode('UNKNOWN_REDIRECT')    : $message = '{--UNKNOWN_REDIRECT_VALUE--}'; break;
1245                 case getCode('WRONG_PASS')          : $message = '{--LOGIN_WRONG_PASS--}'; break;
1246                 case getCode('WRONG_ID')            : $message = '{--LOGIN_WRONG_ID--}'; break;
1247                 case getCode('ACCOUNT_LOCKED')      : $message = '{--LOGIN_STATUS_LOCKED--}'; break;
1248                 case getCode('ACCOUNT_UNCONFIRMED') : $message = '{--LOGIN_STATUS_UNCONFIRMED--}'; break;
1249                 case getCode('COOKIES_DISABLED')    : $message = '{--LOGIN_COOKIES_DISABLED--}'; break;
1250                 case getCode('UNKNOWN_ERROR')       : $message = '{--LOGIN_UNKNOWN_ERROR--}'; break;
1251                 case getCode('UNKNOWN_STATUS')      : $message = '{--LOGIN_UNKNOWN_STATUS--}'; break;
1252                 case getCode('LOGIN_EMPTY_ID')      : $message = '{--LOGIN_ID_IS_EMPTY--}'; break;
1253                 case getCode('LOGIN_EMPTY_PASSWORD'): $message = '{--LOGIN_PASSWORD_IS_EMPTY--}'; break;
1254
1255                 case getCode('ERROR_MAILID'):
1256                         if (isExtensionActive('mailid', TRUE)) {
1257                                 $message = '{--ERROR_CONFIRMING_MAIL--}';
1258                         } else {
1259                                 $message = '{%pipe,generateExtensionInactiveNotInstalledMessage=mailid%}';
1260                         }
1261                         break;
1262
1263                 case getCode('EXTENSION_PROBLEM'):
1264                         if (isGetRequestElementSet('ext')) {
1265                                 $message = '{%pipe,generateExtensionInactiveNotInstalledMessage=' . getRequestElement('ext') . '%}';
1266                         } else {
1267                                 $message = '{--EXTENSION_PROBLEM_UNSET_EXT--}';
1268                         }
1269                         break;
1270
1271                 case getCode('URL_TIME_LOCK'):
1272                         // Load timestamp from last order
1273                         $content = getPoolDataFromId(getRequestElement('id'));
1274
1275                         // Translate it for templates
1276                         $content['timestamp'] = generateDateTime($content['timestamp'], 1);
1277
1278                         // Calculate hours...
1279                         $content['hours'] = round(getUrlTlock() / 60 / 60);
1280
1281                         // Minutes...
1282                         $content['minutes'] = round((getUrlTlock() - $content['hours'] * 60 * 60) / 60);
1283
1284                         // And seconds
1285                         $content['seconds'] = round(getUrlTlock() - $content['hours'] * 60 * 60 - $content['minutes'] * 60);
1286
1287                         // Finally contruct the message
1288                         $message = loadTemplate('tlock_message', TRUE, $content);
1289                         break;
1290
1291                 default:
1292                         // Log missing/invalid error codes
1293                         logDebugMessage(__FUNCTION__, __LINE__, getMessage('UNKNOWN_MAILID_CODE', $code));
1294                         break;
1295         } // END - switch
1296
1297         // Return the message
1298         return $message;
1299 }
1300
1301 // Function taken from user comments on www.php.net / function isInStringIgnoreCase()
1302 function isUrlValidSimple ($url) {
1303         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ' - ENTERED!');
1304         // Prepare URL
1305         $url = secureString(str_replace(chr(92), '', compileRawCode(urldecode($url))));
1306
1307         // Allows http and https
1308         $http      = "(http|https)+(:\/\/)";
1309         // Test domain
1310         $domain1   = "([[:alnum:]]([-[:alnum:]])*\.)?([[:alnum:]][-[:alnum:]\.]*[[:alnum:]])(\.[[:alpha:]]{2,5})?";
1311         // Test double-domains (e.g. .de.vu)
1312         $domain2   = "([-[:alnum:]])?(\.[[:alnum:]][-[:alnum:]\.]*[[:alnum:]])(\.[[:alpha:]]{2,5})(\.[[:alpha:]]{2,5})?";
1313         // Test IP number
1314         $ip        = "([[:digit:]]{1,3})\.([[:digit:]]{1,3})\.([[:digit:]]{1,3})\.([[:digit:]]{1,3})";
1315         // ... directory
1316         $dir       = "((/)+([-_\.[:alnum:]])+)*";
1317         // ... page
1318         $page      = "/([-_[:alnum:]][-\._[:alnum:]]*\.[[:alnum:]]{2,5})?";
1319         // ... and the string after and including question character
1320         $getstring1 = "([\?/]([[:alnum:]][-\._%[:alnum:]]*(=)?([-\@\._:%[:alnum:]])+)(&([[:alnum:]]([-_%[:alnum:]])*(=)?([-\@\[\._:%[:alnum:]])+(\])*))*)?";
1321         // Pattern for URLs like http://url/dir/doc.html?var=value
1322         $pattern['d1dpg1']  = $http . $domain1 . $dir . $page . $getstring1;
1323         $pattern['d2dpg1']  = $http . $domain2 . $dir . $page . $getstring1;
1324         $pattern['ipdpg1']  = $http . $ip . $dir . $page . $getstring1;
1325         // Pattern for URLs like http://url/dir/?var=value
1326         $pattern['d1dg1']  = $http . $domain1 . $dir.'/' . $getstring1;
1327         $pattern['d2dg1']  = $http . $domain2 . $dir.'/' . $getstring1;
1328         $pattern['ipdg1']  = $http . $ip . $dir.'/' . $getstring1;
1329         // Pattern for URLs like http://url/dir/page.ext
1330         $pattern['d1dp']  = $http . $domain1 . $dir . $page;
1331         $pattern['d1dp']  = $http . $domain2 . $dir . $page;
1332         $pattern['ipdp']  = $http . $ip . $dir . $page;
1333         // Pattern for URLs like http://url/dir
1334         $pattern['d1d']  = $http . $domain1 . $dir;
1335         $pattern['d2d']  = $http . $domain2 . $dir;
1336         $pattern['ipd']  = $http . $ip . $dir;
1337         // Pattern for URLs like http://url/?var=value
1338         $pattern['d1g1']  = $http . $domain1 . '/' . $getstring1;
1339         $pattern['d2g1']  = $http . $domain2 . '/' . $getstring1;
1340         $pattern['ipg1']  = $http . $ip . '/' . $getstring1;
1341         // Pattern for URLs like http://url?var=value
1342         $pattern['d1g12']  = $http . $domain1 . $getstring1;
1343         $pattern['d2g12']  = $http . $domain2 . $getstring1;
1344         $pattern['ipg12']  = $http . $ip . $getstring1;
1345
1346         // Test all patterns
1347         $reg = FALSE;
1348         foreach ($pattern as $key => $pat) {
1349                 // Debug regex?
1350                 if (isDebugRegularExpressionEnabled()) {
1351                         // @TODO Are these convertions still required?
1352                         $pat = str_replace('.', '&#92;&#46;', $pat);
1353                         $pat = str_replace('@', '&#92;&#64;', $pat);
1354                         //* DEBUG: */ debugOutput($key . '=&nbsp;' . $pat);
1355                 } // END - if
1356
1357                 // Check if expression matches
1358                 $reg = ($reg || preg_match(('^' . $pat . '^'), $url));
1359
1360                 // Does it match?
1361                 if ($reg === TRUE) {
1362                         break;
1363                 } // END - if
1364         } // END - foreach
1365
1366         // Return true/false
1367         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ',reg=' . intval($reg) . ' - EXIT!');
1368         return $reg;
1369 }
1370
1371 // Wtites data to a config.php-style file
1372 // @TODO Rewrite this function to use readFromFile() and writeToFile()
1373 function changeDataInFile ($FQFN, $comment, $prefix, $suffix, $inserted, $seek = 0) {
1374         // Initialize some variables
1375         $done = FALSE;
1376         $seek++;
1377         $next  = -1;
1378         $found = FALSE;
1379
1380         // Is the file there and read-/write-able?
1381         if ((isFileReadable($FQFN)) && (is_writeable($FQFN))) {
1382                 $search = 'CFG: ' . $comment;
1383                 $tmp = $FQFN . '.tmp';
1384
1385                 // Open the source file
1386                 $fp = fopen($FQFN, 'r') or reportBug(__FUNCTION__, __LINE__, 'Cannot read. file=' . basename($FQFN));
1387
1388                 // Is the resource valid?
1389                 if (is_resource($fp)) {
1390                         // Open temporary file
1391                         $fp_tmp = fopen($tmp, 'w') or reportBug(__FUNCTION__, __LINE__, 'Cannot write. tmp=' . basename($tmp) . ',file=' . $FQFN);
1392
1393                         // Is the resource again valid?
1394                         if (is_resource($fp_tmp)) {
1395                                 // Mark temporary file as readable
1396                                 $GLOBALS['file_readable'][$tmp] = TRUE;
1397
1398                                 // Start reading
1399                                 while (!feof($fp)) {
1400                                         // Read from source file
1401                                         $line = fgets($fp, 1024);
1402
1403                                         if (isInString($search, $line)) {
1404                                                 $next = '0';
1405                                                 $found = TRUE;
1406                                         } // END - if
1407
1408                                         if ($next > -1) {
1409                                                 if ($next === $seek) {
1410                                                         $next = -1;
1411                                                         $line = $prefix . $inserted . $suffix . PHP_EOL;
1412                                                 } else {
1413                                                         $next++;
1414                                                 }
1415                                         } // END - if
1416
1417                                         // Write to temp file
1418                                         fwrite($fp_tmp, $line);
1419                                 } // END - while
1420
1421                                 // Close temp file
1422                                 fclose($fp_tmp);
1423
1424                                 // Finished writing tmp file
1425                                 $done = TRUE;
1426                         } // END - if
1427
1428                         // Close source file
1429                         fclose($fp);
1430
1431                         if (($done === TRUE) && ($found === TRUE)) {
1432                                 // Copy back temporary->FQFN file and ...
1433                                 copyFileVerified($tmp, $FQFN, 0644);
1434
1435                                 // ... delete temporay file :-)
1436                                 return removeFile($tmp);
1437                         } elseif ($found === FALSE) {
1438                                 // Entry not found
1439                                 logDebugMessage(__FUNCTION__, __LINE__, 'File ' . basename($FQFN) . ' cannot be changed: comment=' . $comment . ',prefix=' . $prefix . ',inserted=' . $inserted . ',seek=' . $seek . ' - 404!');
1440                         } else {
1441                                 // Temporary file not fully written
1442                                 logDebugMessage(__FUNCTION__, __LINE__, 'File ' . basename($FQFN) . ' cannot be changed: comment=' . $comment . ',prefix=' . $prefix . ',inserted=' . $inserted . ',seek=' . $seek . ' - Temporary file unfinished!');
1443                         }
1444                 }
1445         } else {
1446                 // File not found, not readable or writeable
1447                 reportBug(__FUNCTION__, __LINE__, 'File not readable/writeable. file=' . basename($FQFN) . ',comment=' . $comment . ',prefix=' . $prefix . ',inserted=' . $inserted . ',seek=' . $seek);
1448         }
1449
1450         // An error was detected!
1451         return FALSE;
1452 }
1453
1454 // Debug message logger
1455 function logDebugMessage ($funcFile, $line, $message, $force=true) {
1456         // Is debug mode enabled?
1457         if ((isDebugModeEnabled()) || ($force === TRUE)) {
1458                 // Remove CRLF
1459                 $message = str_replace(array(chr(13), PHP_EOL), array('', ''), $message);
1460
1461                 // Log this message away
1462                 appendLineToFile(getPath() . getCachePath() . 'debug.log', generateDateTime(time(), '4') . '|' . getModule(FALSE) . ':' . getExtraModule() . '|' . basename($funcFile) . '|' . $line . '|' . $message);
1463         } // END - if
1464 }
1465
1466 // Handle extra values
1467 function handleExtraValues ($filterFunction, $value, $extraValue) {
1468         // Default is the value itself
1469         $ret = $value;
1470
1471         // Is there a special filter function?
1472         if ((empty($filterFunction)) || (!function_exists($filterFunction))) {
1473                 // Call-back function does not exist or is empty
1474                 reportBug(__FUNCTION__, __LINE__, 'Filter function ' . $filterFunction . ' does not exist or is empty: value[' . gettype($value) . ']=' . $value . ',extraValue[' . gettype($extraValue) . ']=' . $extraValue);
1475         } // END - if
1476
1477         // Is there extra parameters here?
1478         if ((!is_null($extraValue)) && (!empty($extraValue))) {
1479                 // Put both parameters in one new array by default
1480                 $args = array($value, $extraValue);
1481
1482                 // If we have an array simply use it and pre-extend it with our value
1483                 if (is_array($extraValue)) {
1484                         // Make the new args array
1485                         $args = merge_array(array($value), $extraValue);
1486                 } // END - if
1487
1488                 // Call the multi-parameter call-back
1489                 $ret = call_user_func_array($filterFunction, $args);
1490
1491                 // Is $ret 'true'?
1492                 if ($ret === TRUE) {
1493                         // Test passed, so write direct value
1494                         $ret = $args;
1495                 } // END - if
1496         } else {
1497                 // One parameter call
1498                 $ret = call_user_func($filterFunction, $value);
1499                 //* BUG */ die('ret['.gettype($ret).']=' . $ret . ',value=' . $value.',filterFunction=' . $filterFunction);
1500
1501                 // Is $ret 'true'?
1502                 if ($ret === TRUE) {
1503                         // Test passed, so write direct value
1504                         $ret = $value;
1505                 } // END - if
1506         }
1507
1508         // Return the value
1509         return $ret;
1510 }
1511
1512 // Tries to determine if call-back functions and/or extra values shall be parsed
1513 function doHandleExtraValues ($filterFunctions, $extraValues, $key, $entries, $userIdColumn, $search, $id = NULL) {
1514         // Debug mode enabled?
1515         if (isDebugModeEnabled()) {
1516                 // Debug message
1517                 /* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key . ',entries=' . $entries . ',userIdColumn=' . $userIdColumn[0] . ',search=' . $search . ',filterFunctions=' . print_r($filterFunctions, TRUE) . ',extraValues=' . print_r($extraValues, TRUE));
1518         } // END - if
1519
1520         // Send data through the filter function if found
1521         if ($key === $userIdColumn[0]) {
1522                 // Is the userid, we have to process it with convertZeroToNull()
1523                 $entries = convertZeroToNull($entries);
1524         } elseif ((!empty($filterFunctions[$key])) && (isset($extraValues[$key]))) {
1525                 // Debug mode enabled?
1526                 if (isDebugModeEnabled()) {
1527                         // Then log it
1528                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$key] . ',extraValues=' . $extraValues[$key] . ',key=' . $key . ',id=' . $id . ',entries[' . gettype($entries) . ']=' . $entries . ' - BEFORE!');
1529                 } // END - if
1530
1531                 // Filter function + extra value set
1532                 $entries = handleExtraValues($filterFunctions[$key], $entries, $extraValues[$key]);
1533
1534                 // Debug mode enabled?
1535                 if (isDebugModeEnabled()) {
1536                         // Then log it
1537                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$key] . ',extraValues=' . $extraValues[$key] . ',key=' . $key . ',id=' . $id . ',entries[' . gettype($entries) . ']=' . $entries . ' - AFTER!');
1538                 } // END - if
1539         } elseif ((!empty($filterFunctions[$search])) && (!empty($extraValues[$search]))) {
1540                 // Debug mode enabled?
1541                 if (isDebugModeEnabled()) {
1542                         // Then log it
1543                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$search] . ',key=' . $key . ',search=' . $search . ',entries[' . gettype($entries) . ']=' . $entries . ' - BEFORE!');
1544                 } // END - if
1545
1546                 // Handle extra values
1547                 $entries = handleExtraValues($filterFunctions[$search], $entries, $extraValues[$search]);
1548
1549                 // Debug mode enabled?
1550                 if (isDebugModeEnabled()) {
1551                         // Then log it
1552                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$search] . ',key=' . $key . ',search=' . $search . ',entries[' . gettype($entries) . ']=' . $entries . ' - AFTER!');
1553                 } // END - if
1554
1555                 // Make sure entries is not bool, then something went wrong
1556                 assert(!is_bool($entries));
1557         } elseif (!empty($filterFunctions[$search])) {
1558                 // Debug mode enabled?
1559                 if (isDebugModeEnabled()) {
1560                         // Then log it
1561                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$search] . ',key=' . $key . ',search=' . $search . ',entries[' . gettype($entries) . ']=' . $entries . ' - BEFORE!');
1562                 } // END - if
1563
1564                 // Handle extra values
1565                 $entries = handleExtraValues($filterFunctions[$search], $entries, NULL);
1566
1567                 // Debug mode enabled?
1568                 if (isDebugModeEnabled()) {
1569                         // Then log it
1570                         /* NOISY-DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'search=' . $search . ',filterFunctions=' . $filterFunctions[$search] . ',key=' . $key . ',search=' . $search . ',entries[' . gettype($entries) . ']=' . $entries . ' - AFTER!');
1571                 } // END - if
1572
1573                 // Make sure entries is not bool, then something went wrong
1574                 assert(!is_bool($entries));
1575         }
1576
1577         // Return value
1578         return $entries;
1579 }
1580
1581 // Converts timestamp selections into a timestamp
1582 function convertSelectionsToEpocheTime (array &$postData, array &$content, &$id, &$skip) {
1583         // Init test variable
1584         $skip  = FALSE;
1585         $test2 = '';
1586
1587         // Get last three chars
1588         $test = substr($id, -3);
1589
1590         // Improved way of checking! :-)
1591         if (in_array($test, array('_ye', '_mo', '_mn', '_we', '_da', '_ho', '_mi', '_se'))) {
1592                 // Found a multi-selection for timings?
1593                 $test = substr($id, 0, -3);
1594                 if ((isset($postData[$test . '_ye'])) && ((isset($postData[$test . '_mo'])) || (isset($postData[$test . '_mn']))) && (isset($postData[$test . '_we'])) && (isset($postData[$test . '_da'])) && (isset($postData[$test . '_ho'])) && (isset($postData[$test . '_mi'])) && (isset($postData[$test . '_se'])) && ($test != $test2)) {
1595                         // Generate timestamp
1596                         $postData[$test] = createEpocheTimeFromSelections($test, $postData);
1597                         array_push($content, sprintf("`%s`='%s'", $test, $postData[$test]));
1598                         $GLOBALS['skip_config'][$test] = TRUE;
1599
1600                         // Remove data from array
1601                         foreach (array('ye', 'mo', 'mn', 'we', 'da', 'ho', 'mi', 'se') as $rem) {
1602                                 unset($postData[$test . '_' . $rem]);
1603                         } // END - foreach
1604
1605                         // Skip adding
1606                         unset($id);
1607                         $skip = TRUE;
1608                         $test2 = $test;
1609                 } // END - if
1610         } // END - if
1611 }
1612
1613 // Reverts the german decimal comma into Computer decimal dot
1614 // OPPOMENT: translateComma()
1615 function convertCommaToDot ($str) {
1616         // Default float is not a float... ;-)
1617         $float = FALSE;
1618
1619         // Which language is selected?
1620         switch (getLanguage()) {
1621                 case 'de': // German language
1622                         // Remove german thousand dots first
1623                         $str = str_replace('.', '', $str);
1624
1625                         // Replace german commata with decimal dot and cast it
1626                         $float = sprintf(getConfig('FLOAT_MASK'), str_replace(',', '.', $str));
1627                         break;
1628
1629                 default: // US and so on
1630                         // Remove thousand commatas first and cast
1631                         $float = sprintf(getConfig('FLOAT_MASK'), str_replace(',', '', $str));
1632                         break;
1633         } // END - switch
1634
1635         // Return float
1636         return $float;
1637 }
1638
1639 // Handle menu-depending failed logins and return the rendered content
1640 function handleLoginFailures ($accessLevel) {
1641         // Default output is empty ;-)
1642         $OUT = '';
1643
1644         // Is the session data set?
1645         if ((isSessionVariableSet('mailer_' . $accessLevel . '_failures')) && (isSessionVariableSet('mailer_' . $accessLevel . '_last_failure'))) {
1646                 // Ignore zero values
1647                 if (getSession('mailer_' . $accessLevel . '_failures') > 0) {
1648                         // Non-guest has login failures found, get both data and prepare it for template
1649                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'accessLevel=' . $accessLevel . '<br />');
1650                         $content = array(
1651                                 'login_failures' => 'mailer_' . $accessLevel . '_failures',
1652                                 'last_failure'   => generateDateTime(getSession('mailer_' . $accessLevel . '_last_failure'), 2)
1653                         );
1654
1655                         // Load template
1656                         $OUT = loadTemplate('login_failures', TRUE, $content);
1657                 } // END - if
1658
1659                 // Reset session data
1660                 setSession('mailer_' . $accessLevel . '_failures', '');
1661                 setSession('mailer_' . $accessLevel . '_last_failure', '');
1662         } // END - if
1663
1664         // Return rendered content
1665         return $OUT;
1666 }
1667
1668 // Rebuild cache
1669 function rebuildCache ($cache, $inc = '', $force = FALSE) {
1670         // Debug message
1671         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, sprintf("cache=%s, inc=%s, force=%s", $cache, $inc, intval($force)));
1672
1673         // Shall I remove the cache file?
1674         if ((isExtensionInstalled('cache')) && (isValidCacheInstance()) && (isHtmlOutputMode())) {
1675                 // Rebuild cache only in HTML output-mode
1676                 // @TODO This should be rewritten not to load the cache file for just checking if it is there for save removal.
1677                 if ($GLOBALS['cache_instance']->loadCacheFile($cache)) {
1678                         // Destroy it
1679                         $GLOBALS['cache_instance']->removeCacheFile($force);
1680                 } // END - if
1681
1682                 // Include file given?
1683                 if (!empty($inc)) {
1684                         // Construct FQFN
1685                         $inc = sprintf('inc/loader/load-%s.php', $inc);
1686
1687                         // Is the include there?
1688                         if (isIncludeReadable($inc)) {
1689                                 // And rebuild it from scratch
1690                                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'inc=' . $inc . ' - LOADED!');
1691                                 loadInclude($inc);
1692                         } else {
1693                                 // Include not found, which needs now tracing
1694                                 reportBug(__FUNCTION__, __LINE__, 'Include ' . $inc . ' not found. cache=' . $cache);
1695                         }
1696                 } // END - if
1697         } // END - if
1698 }
1699
1700 // Determines the real remote address
1701 function determineRealRemoteAddress ($remoteAddr = FALSE) {
1702         // Default is 127.0.0.1
1703         $address = '127.0.0.1';
1704
1705         // Is a proxy in use?
1706         if ((isset($_SERVER['HTTP_X_FORWARDED_FOR'])) && (!$remoteAddr)) {
1707                 // Proxy was used
1708                 $address = $_SERVER['HTTP_X_FORWARDED_FOR'];
1709         } elseif ((isset($_SERVER['HTTP_CLIENT_IP'])) && (!$remoteAddr)) {
1710                 // Yet, another proxy
1711                 $address = $_SERVER['HTTP_CLIENT_IP'];
1712         } elseif (isset($_SERVER['REMOTE_ADDR'])) {
1713                 // The regular address when no proxy was used
1714                 $address = $_SERVER['REMOTE_ADDR'];
1715         }
1716
1717         // This strips out the real address from proxy output
1718         if (strstr($address, ',')) {
1719                 $addressArray = explode(',', $address);
1720                 $address = $addressArray[0];
1721         } // END - if
1722
1723         // Return the result
1724         return $address;
1725 }
1726
1727 // Adds a bonus mail to the queue
1728 // This is a high-level function!
1729 function addNewBonusMail ($data, $mode = '', $output = TRUE) {
1730         // Use mode from data if not set and availble ;-)
1731         if ((empty($mode)) && (isset($data['mail_mode']))) {
1732                 $mode = $data['mail_mode'];
1733         } // END - if
1734
1735         // Generate receiver list
1736         $receiver = generateReceiverList($data['cat'], $data['receiver'], $mode);
1737
1738         // Receivers added?
1739         if (!empty($receiver)) {
1740                 // Add bonus mail to queue
1741                 addBonusMailToQueue(
1742                         $data['subject'],
1743                         $data['text'],
1744                         $receiver,
1745                         $data['points'],
1746                         $data['seconds'],
1747                         $data['url'],
1748                         $data['cat'],
1749                         $mode,
1750                         $data['receiver']
1751                 );
1752
1753                 // Mail inserted into bonus pool
1754                 if ($output === TRUE) {
1755                         displayMessage('{--ADMIN_BONUS_SEND--}');
1756                 } // END - if
1757         } elseif ($output === TRUE) {
1758                 // More entered than can be reached!
1759                 displayMessage('{--ADMIN_MORE_SELECTED--}');
1760         } else {
1761                 // Debug log
1762                 logDebugMessage(__FUNCTION__, __LINE__, 'cat=' . $data['cat'] . ',receiver=' . $data['receiver'] . ',data=' . base64_encode(serialize($data)) . ' More selected, than available!');
1763         }
1764 }
1765
1766 // Enables the hourly reset mode and runs it
1767 function doHourly () {
1768         // Enable the hourly reset mode
1769         $GLOBALS['hourly_enabled'] = TRUE;
1770
1771         // Run filters (one always!)
1772         runFilterChain('hourly');
1773
1774         // Do not update in hourly debug mode
1775         if ((!isConfigEntrySet('DEBUG_HOURLY')) || (!isDebugHourlyEnabled())) {
1776                 // Update database
1777                 updateConfiguration('last_hourly', getHour());
1778         } // END - if
1779 }
1780
1781 // Enables the daily reset mode and runs it
1782 function doDaily () {
1783         // Enable the reset mode
1784         $GLOBALS['daily_enabled'] = TRUE;
1785
1786         // Run filters
1787         runFilterChain('daily');
1788
1789         // Do not update in daily debug mode
1790         if ((!isConfigEntrySet('DEBUG_DAILY')) || (!isDebugDailyEnabled())) {
1791                 // Update database
1792                 updateConfiguration('last_daily', getDay());
1793         } // END - if
1794 }
1795
1796 // Enables the weekly reset mode and runs it
1797 function doWeekly () {
1798         // Enable the reset mode
1799         $GLOBALS['weekly_enabled'] = TRUE;
1800
1801         // Run filters
1802         runFilterChain('weekly');
1803
1804         // Do not update in weekly debug mode
1805         if ((!isConfigEntrySet('DEBUG_WEEKLY')) || (!isDebugWeeklyEnabled())) {
1806                 // Update database
1807                 updateConfiguration('last_weekly', getWeek());
1808         } // END - if
1809 }
1810
1811 // Enables the monthly reset mode and runs it
1812 function doMonthly () {
1813         // Enable the reset mode
1814         $GLOBALS['monthly_enabled'] = TRUE;
1815
1816         // Run filters
1817         runFilterChain('monthly');
1818
1819         // Do not update in monthly debug mode
1820         if ((!isConfigEntrySet('DEBUG_MONTHLY')) || (!isDebugMonthlyEnabled())) {
1821                 // Update database
1822                 updateConfiguration('last_monthly', getMonth());
1823         } // END - if
1824 }
1825
1826 // Enables the yearly reset mode and runs it
1827 function doYearly () {
1828         // Enable the reset mode
1829         $GLOBALS['yearly_enabled'] = TRUE;
1830
1831         // Run filters
1832         runFilterChain('yearly');
1833
1834         // Do not update in yearly debug mode
1835         if ((!isConfigEntrySet('DEBUG_YEARLY')) || (!isDebugYearlyEnabled())) {
1836                 // Update database
1837                 updateConfiguration('last_yearly', getYear());
1838         } // END - if
1839 }
1840
1841 // Shuts down the mailer (e.g. closing database link, flushing output/filters, etc.)
1842 function doShutdown () {
1843         // Call the filter chain 'shutdown'
1844         runFilterChain('shutdown', NULL);
1845
1846         // Check if link is up
1847         if (isSqlLinkUp()) {
1848                 // Close link
1849                 sqlCloseLink(__FUNCTION__, __LINE__);
1850         } elseif (!isInstaller()) {
1851                 // No database link
1852                 reportBug(__FUNCTION__, __LINE__, 'Database link is already down, while shutdown is running.');
1853         }
1854
1855         // Stop executing here
1856         exit;
1857 }
1858
1859 // Init member id
1860 function initMemberId () {
1861         $GLOBALS['member_id'] = '0';
1862 }
1863
1864 // Setter for member id
1865 function setMemberId ($memberId) {
1866         // We should not set member id to zero
1867         if (!isValidId($memberId)) {
1868                 reportBug(__FUNCTION__, __LINE__, 'Userid should not be set zero.');
1869         } // END - if
1870
1871         // Set it secured
1872         $GLOBALS['member_id'] = bigintval($memberId);
1873 }
1874
1875 // Getter for member id or returns zero
1876 function getMemberId () {
1877         // Default member id
1878         $memberId = '0';
1879
1880         // Is the member id set?
1881         if (isMemberIdSet()) {
1882                 // Then use it
1883                 $memberId = $GLOBALS['member_id'];
1884         } // END - if
1885
1886         // Return it
1887         return $memberId;
1888 }
1889
1890 // Checks ether the member id is set
1891 function isMemberIdSet () {
1892         return (isset($GLOBALS['member_id']));
1893 }
1894
1895 // Setter for extra title
1896 function setExtraTitle ($extraTitle) {
1897         $GLOBALS['extra_title'] = $extraTitle;
1898 }
1899
1900 // Getter for extra title
1901 function getExtraTitle () {
1902         // Is the extra title set?
1903         if (!isExtraTitleSet()) {
1904                 // No, then abort here
1905                 reportBug(__FUNCTION__, __LINE__, 'extra_title is not set!');
1906         } // END - if
1907
1908         // Return it
1909         return $GLOBALS['extra_title'];
1910 }
1911
1912 // Checks if the extra title is set
1913 function isExtraTitleSet () {
1914         return ((isset($GLOBALS['extra_title'])) && (!empty($GLOBALS['extra_title'])));
1915 }
1916
1917 /**
1918  * Reads a directory recursively by default and searches for files not matching
1919  * an exclusion pattern. You can now keep the exclusion pattern empty for reading
1920  * a whole directory.
1921  *
1922  * @param       $baseDir                        Relative base directory to PATH to scan from
1923  * @param       $prefix                         Prefix for all positive matches (which files should be found)
1924  * @param       $fileIncludeDirs        Whether to include directories in the final output array
1925  * @param       $addBaseDir                     Whether to add $baseDir to all array entries
1926  * @param       $excludeArray           Excluded files and directories, these must be full files names, e.g. 'what-' will exclude all files named 'what-' but won't exclude 'what-foo.php'
1927  * @param       $extension                      File extension for all positive matches
1928  * @param       $excludePattern         Regular expression to exclude more files (preg_match())
1929  * @param       $recursive                      Whether to scan recursively
1930  * @param       $suffix                         Suffix for positive matches ($extension will be appended, too)
1931  * @param       $withPrefixSuffix       Whether to include prefix/suffix in found entries
1932  * @return      $foundMatches           All found positive matches for above criteria
1933  */
1934 function getArrayFromDirectory ($baseDir, $prefix, $fileIncludeDirs = FALSE, $addBaseDir = TRUE, $excludeArray = array(), $extension = '.php', $excludePattern = '@(\.|\.\.)$@', $recursive = TRUE, $suffix = '', $withPrefixSuffix = TRUE) {
1935         // Add default entries we should always exclude
1936         array_unshift($excludeArray, '.', '..', '.svn', '.htaccess');
1937
1938         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'baseDir=' . $baseDir . ',prefix=' . $prefix . ' - Entered!');
1939         // Init found includes
1940         $foundMatches = array();
1941
1942         // Open directory
1943         $dirPointer = opendir(getPath() . $baseDir) or reportBug(__FUNCTION__, __LINE__, 'Cannot read directory ' . basename($baseDir) . '.');
1944
1945         // Read all entries
1946         while ($baseFile = readdir($dirPointer)) {
1947                 // Exclude '.', '..' and entries in $excludeArray automatically
1948                 if (in_array($baseFile, $excludeArray, TRUE))  {
1949                         // Exclude them
1950                         //* DEBUG: */ debugOutput('excluded=' . $baseFile);
1951                         continue;
1952                 } // END - if
1953
1954                 // Construct include filename and FQFN
1955                 $fileName = $baseDir . $baseFile;
1956                 $FQFN = getPath() . $fileName;
1957
1958                 // Remove double slashes
1959                 $FQFN = str_replace('//', '/', $FQFN);
1960
1961                 // Check if the base filenname matches an exclusion pattern and if the pattern is not empty
1962                 if ((!empty($excludePattern)) && (preg_match($excludePattern, $baseFile, $match))) {
1963                         // Debug message
1964                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'baseDir=' . $baseDir . ',baseFile=' . $baseFile . ',FQFN=' . $FQFN);
1965
1966                         // Exclude this one
1967                         continue;
1968                 } // END - if
1969
1970                 // Skip also files with non-matching prefix genericly
1971                 if (($recursive === TRUE) && (isDirectory($FQFN))) {
1972                         // Is a redirectory so read it as well
1973                         $foundMatches = merge_array($foundMatches, getArrayFromDirectory($baseDir . $baseFile . '/', $prefix, $fileIncludeDirs, $addBaseDir, $excludeArray, $extension, $excludePattern, $recursive));
1974
1975                         // And skip further processing
1976                         continue;
1977                 } elseif (!isFilePrefixFound($baseFile, $prefix)) {
1978                         // Skip this file
1979                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Invalid prefix in file ' . $baseFile . ', prefix=' . $prefix);
1980                         continue;
1981                 } elseif ((!empty($suffix)) && (substr($baseFile, -(strlen($suffix . $extension)), (strlen($suffix . $extension))) != $suffix . $extension)) {
1982                         // Skip wrong suffix as well
1983                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'Invalid suffix in file ' . $baseFile . ', suffix=' . $suffix);
1984                         continue;
1985                 } elseif (!isFileReadable($FQFN)) {
1986                         // Not readable so skip it
1987                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'File ' . $FQFN . ' is not readable!');
1988                 } elseif (filesize($FQFN) < 50) {
1989                         // Might be deprecated
1990                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'File ' . $FQFN . ' is to small (' . filesize($FQFN) . ')!');
1991                         continue;
1992                 } elseif (($extension == '.php') && (filesize($FQFN) < 50)) {
1993                         // This PHP script is deprecated
1994                         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'File ' . $FQFN . ' is a deprecated PHP script!');
1995                         continue;
1996                 }
1997
1998                 // Get file' extension (last 4 chars)
1999                 $fileExtension = substr($baseFile, -4, 4);
2000
2001                 // Is the file a PHP script or other?
2002                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'baseDir=' . $baseDir . ',prefix=' . $prefix . ',baseFile=' . $baseFile);
2003                 if (($fileExtension == '.php') || (($fileIncludeDirs === TRUE) && (isDirectory($FQFN)))) {
2004                         // Is this a valid include file?
2005                         if ($extension == '.php') {
2006                                 // Remove both for extension name
2007                                 $extName = substr($baseFile, strlen($prefix), -4);
2008
2009                                 // Add file with or without base path
2010                                 if ($addBaseDir === TRUE) {
2011                                         // With base path
2012                                         array_push($foundMatches, $fileName);
2013                                 } elseif (($withPrefixSuffix === FALSE) && (!empty($extension))) {
2014                                         // No prefix/suffix
2015                                         array_push($foundMatches, substr($baseFile, strlen($prefix), -strlen($suffix . $extension)));
2016                                 } else {
2017                                         // No base path
2018                                         array_push($foundMatches, $baseFile);
2019                                 }
2020                         } else {
2021                                 // We found .php file but should not search for them, why?
2022                                 reportBug(__FUNCTION__, __LINE__, 'We should find files with extension=' . $extension . ', but we found a PHP script. (baseFile=' . $baseFile . ')');
2023                         }
2024                 } elseif ((($fileExtension == $extension) || (empty($extension))) && (isFileReadable($FQFN))) {
2025                         // Other, generic file found
2026                         if ($addBaseDir === TRUE) {
2027                                 // With base path
2028                                 array_push($foundMatches, $fileName);
2029                         } elseif (($withPrefixSuffix === FALSE) && (!empty($extension))) {
2030                                 // No prefix/suffix
2031                                 array_push($foundMatches, substr($baseFile, strlen($prefix), -strlen($suffix . $extension)));
2032                         } else {
2033                                 // No base path
2034                                 array_push($foundMatches, $baseFile);
2035                         }
2036                 }
2037         } // END - while
2038
2039         // Close directory
2040         closedir($dirPointer);
2041
2042         // Sort array
2043         sort($foundMatches);
2044
2045         // Return array with include files
2046         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, '- Left!');
2047         return $foundMatches;
2048 }
2049
2050 // Checks whether $prefix is found in $fileName
2051 function isFilePrefixFound ($fileName, $prefix) {
2052         // @TODO Find a way to cache this
2053         return (substr($fileName, 0, strlen($prefix)) == $prefix);
2054 }
2055
2056 // Maps a module name into a database table name
2057 function mapModuleToTable ($moduleName) {
2058         // Map only these, still lame code...
2059         switch ($moduleName) {
2060                 case 'index': // 'index' is the guest's menu
2061                         $moduleName = 'guest';
2062                         break;
2063
2064                 case 'login': // ... and 'login' the member's menu
2065                         $moduleName = 'member';
2066                         break;
2067                 // Anything else will not be mapped, silently.
2068         } // END - switch
2069
2070         // Return result
2071         return $moduleName;
2072 }
2073
2074 // Add SQL debug data to array for later output
2075 function addSqlToDebug ($result, $sqlString, $timing, $file, $line) {
2076         // Is there cache?
2077         if (!isset($GLOBALS['debug_sql_available'])) {
2078                 // Check it and cache it in $GLOBALS
2079                 $GLOBALS['debug_sql_available'] = ((isConfigurationLoaded()) && (isDisplayDebugSqlEnabled()));
2080         } // END - if
2081
2082         // Don't execute anything here if we don't need or ext-other is missing
2083         if ($GLOBALS['debug_sql_available'] === FALSE) {
2084                 return;
2085         } // END - if
2086
2087         // Already executed?
2088         if (isset($GLOBALS['debug_sqls'][$file][$line][$sqlString])) {
2089                 // Then abort here, we don't need to profile a query twice
2090                 return;
2091         } // END - if
2092
2093         // Remeber this as profiled (or not, but we don't care here)
2094         $GLOBALS['debug_sqls'][$file][$line][$sqlString] = TRUE;
2095
2096         // Generate record
2097         $record = array(
2098                 'num_rows' => sqlNumRows($result),
2099                 'affected' => sqlAffectedRows(),
2100                 'sql_str'  => $sqlString,
2101                 'timing'   => $timing,
2102                 'file'     => basename($file),
2103                 'line'     => $line
2104         );
2105
2106         // Add it
2107         array_push($GLOBALS['debug_sqls'], $record);
2108 }
2109
2110 // Initializes the cache instance
2111 function initCacheInstance () {
2112         // Check for double-initialization
2113         if (isset($GLOBALS['cache_instance'])) {
2114                 // This should not happen and must be fixed
2115                 reportBug(__FUNCTION__, __LINE__, 'Double initialization of cache system detected. cache_instance[]=' . gettype($GLOBALS['cache_instance']));
2116         } // END - if
2117
2118         // Load include for CacheSystem class
2119         loadIncludeOnce('inc/classes/cachesystem.class.php');
2120
2121         // Initialize cache system only when it's needed
2122         $GLOBALS['cache_instance'] = new CacheSystem();
2123
2124         // Did it work?
2125         if ($GLOBALS['cache_instance']->getStatusCode() != 'done') {
2126                 // Failed to initialize cache sustem
2127                 reportBug(__FUNCTION__, __LINE__, 'Cache system returned with unexpected error. getStatusCode()=' . $GLOBALS['cache_instance']->getStatusCode());
2128         } // END - if
2129 }
2130
2131 // Getter for message from array or raw message
2132 function getMessageFromIndexedArray ($message, $pos, $array) {
2133         // Check if the requested message was found in array
2134         if (isset($array[$pos])) {
2135                 // ... if yes then use it!
2136                 $ret = $array[$pos];
2137         } else {
2138                 // ... else use default message
2139                 $ret = $message;
2140         }
2141
2142         // Return result
2143         return $ret;
2144 }
2145
2146 // Convert ';' to ', ' for e.g. receiver list
2147 function convertReceivers ($old) {
2148         return str_replace(';', ', ', $old);
2149 }
2150
2151 // Get a module from filename and access level
2152 function getModuleFromFileName ($file, $accessLevel) {
2153         // Default is 'invalid';
2154         $modCheck = 'invalid';
2155
2156         // @TODO This is still very static, rewrite it somehow
2157         switch ($accessLevel) {
2158                 case 'admin':
2159                         $modCheck = 'admin';
2160                         break;
2161
2162                 case 'sponsor':
2163                 case 'guest':
2164                 case 'member':
2165                         $modCheck = getModule();
2166                         break;
2167
2168                 default: // Unsupported file name / access level
2169                         reportBug(__FUNCTION__, __LINE__, 'Unsupported file name=' . basename($file) . '/access level=' . $accessLevel);
2170                         break;
2171         } // END - switch
2172
2173         // Return result
2174         return $modCheck;
2175 }
2176
2177 // Encodes an URL for adding session id, etc.
2178 function encodeUrl ($url, $outputMode = '0') {
2179         // Is there already have a PHPSESSID inside or view.php is called? Then abort here
2180         if ((isInStringIgnoreCase(session_name(), $url)) || (isRawOutputMode())) {
2181                 // Raw output mode detected or session_name() found in URL
2182                 return $url;
2183         } // END - if
2184
2185         // Is there a valid session?
2186         if ((!isValidSession()) && (!isSpider())) {
2187                 // Determine right separator
2188                 $separator = '&amp;';
2189                 if (!isInString('?', $url)) {
2190                         // No question mark
2191                         $separator = '?';
2192                 } // END - if
2193
2194                 // Then add it to URL
2195                 $url .= $separator . session_name() . '=' . session_id();
2196         } // END - if
2197
2198         // Add {?URL?} ?
2199         if ((substr($url, 0, strlen(getUrl())) != getUrl()) && (substr($url, 0, 7) != '{?URL?}') && (!isFullQualifiedUrl($url))) {
2200                 // Add it
2201                 $url = '{?URL?}/' . $url;
2202         } // END - if
2203
2204         // Debug message
2205         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ',isHtmlOutputMode()=' . intval(isHtmlOutputMode()) . ',outputMode=' . $outputMode);
2206
2207         // Is there to decode entities?
2208         if (!isHtmlOutputMode()) {
2209                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ' - BEFORE DECODING');
2210                 // Decode them for e.g. JavaScript parts
2211                 $url = decodeEntities($url);
2212                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ' - AFTER DECODING');
2213         } // END - if
2214
2215         // Debug log
2216         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'url=' . $url . ',outputMode=' . $outputMode);
2217
2218         // Return the encoded URL
2219         return $url;
2220 }
2221
2222 // Simple check for spider
2223 function isSpider () {
2224         // Get the UA and trim it down
2225         $userAgent = trim(detectUserAgent(TRUE));
2226
2227         // It should not be empty, if so it is better a browser
2228         if (empty($userAgent)) {
2229                 // It is a browser that blocks its UA string
2230                 return FALSE;
2231         } // END - if
2232
2233         // Is it a spider?
2234         return ((isInStringIgnoreCase('spider', $userAgent)) || (isInStringIgnoreCase('slurp', $userAgent)) || (isInStringIgnoreCase('bot', $userAgent)) || (isInStringIgnoreCase('archiver', $userAgent)));
2235 }
2236
2237 // Handles the braces [] of a field (e.g. value of 'name' attribute)
2238 function handleFieldWithBraces ($field) {
2239         // Are there braces [] at the end?
2240         if (substr($field, -2, 2) == '[]') {
2241                 /*
2242                  * Try to find one and replace it. I do it this way to allow easy
2243                  * extending of this code.
2244                  */
2245                 foreach (array('admin_list_builder_id_value') as $key) {
2246                         /* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key);
2247                         // Is the cache entry set?
2248                         if (isset($GLOBALS[$key])) {
2249                                 // Insert it
2250                                 $field = str_replace('[]', '[' . $GLOBALS[$key] . ']', $field);
2251
2252                                 // And abort
2253                                 /* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'key=' . $key, 'field=' . $field);
2254                                 break;
2255                         } // END - if
2256                 } // END - foreach
2257         } // END - if
2258
2259         // Return it
2260         return $field;
2261 }
2262
2263 // Converts a zero or NULL to word 'NULL'
2264 function convertZeroToNull ($number) {
2265         // Is it a valid username?
2266         if (isValidNumber($number)) {
2267                 // Always secure it
2268                 $number = bigintval($number);
2269         } else {
2270                 // Is not valid or zero
2271                 $number = 'NULL';
2272         }
2273
2274         // Return it
2275         return $number;
2276 }
2277
2278 // Converts an empty string to NULL, else leaves it untouched
2279 function convertEmptyToNull ($str) {
2280         // Is the string empty?
2281         if (strlen($str) == 0) {
2282                 // Is really empty
2283                 $str = NULL;
2284         } // END - if
2285
2286         // Return it
2287         return $str;
2288 }
2289
2290 // Converts a NULL|empty string|< 1 to zero
2291 function convertNullToZero ($number) {
2292         // Is it a valid username?
2293         if (!isValidNumber($number)) {
2294                 // Is not valid or zero
2295                 $number = '0';
2296         } // END - if
2297
2298         // Return it
2299         return $number;
2300 }
2301
2302 // Capitalizes a string with underscores, e.g.: some_foo_string will become SomeFooString
2303 // Note: This function is cached
2304 function capitalizeUnderscoreString ($str) {
2305         // Is there cache?
2306         if (!isset($GLOBALS[__FUNCTION__][$str])) {
2307                 // Init target string
2308                 $capitalized = '';
2309
2310                 // Explode it with the underscore, but rewrite dashes to underscore before
2311                 $strArray = explode('_', str_replace('-', '_', $str));
2312
2313                 // "Walk" through all elements and make them lower-case but first upper-case
2314                 foreach ($strArray as $part) {
2315                         // Capitalize the string part
2316                         $capitalized .= firstCharUpperCase($part);
2317                 } // END - foreach
2318
2319                 // Store the converted string in cache array
2320                 $GLOBALS[__FUNCTION__][$str] = $capitalized;
2321         } // END - if
2322
2323         // Return cache
2324         return $GLOBALS[__FUNCTION__][$str];
2325 }
2326
2327 // Generate admin links for mail order
2328 // mailType can be: 'normal' or 'bonus'
2329 function generateAdminMailLinks ($mailType, $mailId) {
2330         // Init variables
2331         $OUT = '';
2332         $table = '';
2333
2334         // Default column for mail status is 'data_type'
2335         // @TODO Rename column data_type to e.g. mail_status
2336         $statusColumn = 'data_type';
2337
2338         // Which mail do we have?
2339         switch ($mailType) {
2340                 case 'bonus': // Bonus mail
2341                         $table = 'bonus';
2342                         break;
2343
2344                 case 'normal': // Member mail
2345                         $table = 'pool';
2346                         break;
2347
2348                 default: // Handle unsupported types
2349                         logDebugMessage(__FUNCTION__, __LINE__, 'Unsupported mail type ' . $mailType . ' for mailId=' . $mailId . ' detected.');
2350                         $OUT = '<div align="center">{%message,ADMIN_UNSUPPORTED_MAIL_TYPE_DETECTED=' . $mailType . '%}</div>';
2351                         break;
2352         } // END - switch
2353
2354         // Is the mail type supported?
2355         if (!empty($table)) {
2356                 // Query for the mail
2357                 $result = sqlQueryEscaped("SELECT `id`, `%s` AS `mail_status` FROM `{?_MYSQL_PREFIX?}_%s` WHERE `id`=%s LIMIT 1",
2358                         array(
2359                                 $statusColumn,
2360                                 $table,
2361                                 bigintval($mailId)
2362                         ), __FILE__, __LINE__);
2363
2364                 // Is there one entry there?
2365                 if (sqlNumRows($result) == 1) {
2366                         // Load the entry
2367                         $content = sqlFetchArray($result);
2368
2369                         // Add output and type
2370                         $content['type']     = $mailType;
2371                         $content['__output'] = '';
2372
2373                         // Filter all data
2374                         $content = runFilterChain('generate_admin_mail_links', $content);
2375
2376                         // Get output back
2377                         $OUT = $content['__output'];
2378                 } // END - if
2379
2380                 // Free result
2381                 sqlFreeResult($result);
2382         } // END - if
2383
2384         // Return generated HTML code
2385         return $OUT;
2386 }
2387
2388
2389 /**
2390  * Determine if a string can represent a number in hexadecimal
2391  *
2392  * @param       $hex    A string to check if it is hex-encoded
2393  * @return      $foo    True if the string is a hex, otherwise false
2394  * @author      Marques Johansson
2395  * @link        http://php.net/manual/en/function.http-chunked-decode.php#89786
2396  */
2397 function isHexadecimal ($hex) {
2398         // Make it lowercase
2399         $hex = strtolower(trim(ltrim($hex, '0')));
2400
2401         // Fix empty strings to zero
2402         if (empty($hex)) {
2403                 $hex = 0;
2404         } // END - if
2405
2406         // Simply compare decode->encode result with original
2407         return ($hex == dechex(hexdec($hex)));
2408 }
2409
2410 /**
2411  * Replace chr(13) with "[r]" and PHP_EOL with "[n]" and add a final new-line to make
2412  * them visible to the developer. Use this function to debug e.g. buggy HTTP
2413  * response handler functions.
2414  *
2415  * @param       $str    String to overwork
2416  * @return      $str    Overworked string
2417  */
2418 function replaceReturnNewLine ($str) {
2419         return str_replace(array(chr(13), chr(10)), array('[r]', '[n]'), $str);
2420 }
2421
2422 // Converts a given string by splitting it up with given delimiter similar to
2423 // explode(), but appending the delimiter again
2424 function stringToArray ($delimiter, $string) {
2425         // Init array
2426         $strArray = array();
2427
2428         // "Walk" through all entries
2429         foreach (explode($delimiter, $string) as $split) {
2430                 //  Append the delimiter and add it to the array
2431                 array_push($strArray, $split . $delimiter);
2432         } // END - foreach
2433
2434         // Return array
2435         return $strArray;
2436 }
2437
2438 // Detects the prefix 'mb_' if a multi-byte string is given
2439 function detectMultiBytePrefix ($str) {
2440         // Default is without multi-byte
2441         $mbPrefix = '';
2442
2443         // Detect multi-byte (strictly)
2444         if (mb_detect_encoding($str, 'auto', TRUE) !== FALSE) {
2445                 // With multi-byte encoded string
2446                 $mbPrefix = 'mb_';
2447         } // END - if
2448
2449         // Return the prefix
2450         return $mbPrefix;
2451 }
2452
2453 // Searches given array for a sub-string match and returns all found keys in an array
2454 function getArrayKeysFromSubStrArray ($heystack, $needles, $offset = 0) {
2455         // Init array for all found keys
2456         $keys = array();
2457
2458         // Now check all entries
2459         foreach ($needles as $key => $needle) {
2460                 // Is there found a partial string?
2461                 //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'heystack='.$heystack.',key='.$key.',needle='.$needle.',offset='.$offset);
2462                 if (strpos($heystack, $needle, $offset) !== FALSE) {
2463                         // Add the found key
2464                         array_push($keys, $key);
2465                 } // END - if
2466         } // END - foreach
2467
2468         // Return the array
2469         return $keys;
2470 }
2471
2472 // Determines database column name from given subject and locked
2473 function determinePointsColumnFromSubjectLocked ($subject, $locked) {
2474         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'subject=' . $subject . ',locked=' . intval($locked) . ' - ENTERED!');
2475         // Default is 'normal' points
2476         $pointsColumn = 'points';
2477
2478         // Which points, locked or normal?
2479         if ($locked === TRUE) {
2480                 $pointsColumn = 'locked_points';
2481         } // END - if
2482
2483         // Prepare array for filter
2484         $filterData = array(
2485                 'subject' => $subject,
2486                 'locked'  => $locked,
2487                 'column'  => $pointsColumn
2488         );
2489
2490         // Run the filter
2491         $filterData = runFilterChain('determine_points_column_name', $filterData);
2492
2493         // Extract column name from array
2494         $pointsColumn = $filterData['column'];
2495
2496         // Return it
2497         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'subject=' . $subject . ',locked=' . intval($locked) . ',pointsColumn=' . $pointsColumn . ' - EXIT!');
2498         return $pointsColumn;
2499 }
2500
2501 // Converts a boolean variable into 'Y' for true and 'N' for false
2502 function convertBooleanToYesNo ($boolean) {
2503         // Default is 'N'
2504         $converted = 'N';
2505         if ($boolean === TRUE) {
2506                 // Set 'Y'
2507                 $converted = 'Y';
2508         } // END - if
2509
2510         // Return it
2511         return $converted;
2512 }
2513
2514 // "Translates" 'true' to true and 'false' to false
2515 function convertStringToBoolean ($str) {
2516         // Debug message (to measure how often this function is called)
2517         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'str=' . $str);
2518
2519         // Is there cache?
2520         if (!isset($GLOBALS[__FUNCTION__][$str])) {
2521                 // Trim it lower-case for validation
2522                 $strTrimmed = trim(strtolower($str));
2523
2524                 // Is it valid?
2525                 if (!in_array($strTrimmed, array('true', 'false'))) {
2526                         // Not valid!
2527                         reportBug(__FUNCTION__, __LINE__, 'str=' . $str . '(' . $strTrimmed . ') is not true/false');
2528                 } // END - if
2529
2530                 // Determine it
2531                 $GLOBALS[__FUNCTION__][$str] = ($strTrimmed == 'true');
2532         } // END - if
2533
2534         // Return cache
2535         return $GLOBALS[__FUNCTION__][$str];
2536 }
2537
2538 /**
2539  * "Makes" a variable in given string parseable, this function will throw an
2540  * error if the first character is not a dollar sign.
2541  *
2542  * @param       $varString      String which contains a variable
2543  * @return      $return         String with added single quotes for better parsing
2544  */
2545 function makeParseableVariable ($varString) {
2546         // The first character must be a dollar sign
2547         if (substr($varString, 0, 1) != '$') {
2548                 // Please report this
2549                 reportBug(__FUNCTION__, __LINE__, 'varString=' . $varString . ' - No dollar sign detected, will not parse it.');
2550         } // END - if
2551
2552         // Is there cache?
2553         if (!isset($GLOBALS[__FUNCTION__][$varString])) {
2554                 // Snap them in, if [,] are there
2555                 $GLOBALS[__FUNCTION__][$varString] = str_replace(array('[', ']'), array("['", "']"), $varString);
2556         } // END - if
2557
2558         // Return cache
2559         return $GLOBALS[__FUNCTION__][$varString];
2560 }
2561
2562 // "Getter" for random TAN
2563 function getRandomTan () {
2564         // Generate one
2565         return mt_rand(0, 99999);
2566 }
2567
2568 // Removes any : from subject
2569 function removeDoubleDotFromSubject ($subject) {
2570         // Remove it
2571         $subjectArray = explode(':', $subject);
2572         $subject = $subjectArray[0];
2573         unset($subjectArray);
2574
2575         // Return it
2576         return $subject;
2577 }
2578
2579 // Adds a given entry to the database
2580 function memberAddEntries ($tableName, $columns = array(), $filterFunctions = array(), $extraValues = array(), $timeColumns = array(), $columnIndex = NULL) {
2581         // Is it a member?
2582         if (!isMember()) {
2583                 // Then abort here
2584                 return FALSE;
2585         } // END - if
2586
2587         // Set POST data generic userid
2588         setPostRequestElement('userid', getMemberId());
2589
2590         // Call inner function
2591         doGenericAddEntries($tableName, $columns, $filterFunctions, $extraValues, $timeColumns, $columnIndex);
2592
2593         // Entry has been added?
2594         if ((!ifSqlHasZeroAffectedRows()) && ($GLOBALS['__XML_PARSE_RESULT'] === TRUE)) {
2595                 // Display success message
2596                 displayMessage('{--MEMBER_ENTRY_ADDED--}');
2597         } else {
2598                 // Display failed message
2599                 displayMessage('{--MEMBER_ENTRY_NOT_ADDED--}');
2600         }
2601 }
2602
2603 // Edit rows by given id numbers
2604 function memberEditEntriesConfirm ($tableName, $columns = array(), $filterFunctions = array(), $extraValues = array(), $timeColumns = array(), $editNow = array(FALSE), $idColumn = array('id'), $userIdColumn = array('userid'), $rawUserId = array('userid'), $cacheFiles = array(), $content = array()) {
2605         // $tableName must be an array
2606         if ((!is_array($tableName)) || (count($tableName) != 1)) {
2607                 // No tableName specified
2608                 reportBug(__FUNCTION__, __LINE__, 'tableName is not given. Please fix your XML,tableName[]=' . gettype($tableName) . '!=array: userIdColumn=' . $userIdColumn);
2609         } elseif (!is_array($idColumn)) {
2610                 // $idColumn is no array
2611                 reportBug(__FUNCTION__, __LINE__, 'idColumn[]=' . gettype($idColumn) . '!=array: userIdColumn=' . $userIdColumn);
2612         } elseif (!is_array($userIdColumn)) {
2613                 // $userIdColumn is no array
2614                 reportBug(__FUNCTION__, __LINE__, 'userIdColumn[]=' . gettype($userIdColumn) . '!=array: userIdColumn=' . $userIdColumn);
2615         } elseif (!is_array($editNow)) {
2616                 // $editNow is no array
2617                 reportBug(__FUNCTION__, __LINE__, 'editNow[]=' . gettype($editNow) . '!=array: userIdColumn=' . $userIdColumn);
2618         } // END - if
2619
2620         // Shall we change here or list for editing?
2621         if ($editNow[0] === TRUE) {
2622                 // Add generic userid field
2623                 setPostRequestElement('userid', getMemberId());
2624
2625                 // Call generic change method
2626                 $affected = doGenericEditEntriesConfirm($tableName, $columns, $filterFunctions, $extraValues, $timeColumns, $editNow, $idColumn, $userIdColumn, $rawUserId, $cacheFiles, 'mem_edit');
2627
2628                 // Was this fine?
2629                 if ($affected == countPostSelection($idColumn[0])) {
2630                         // All deleted
2631                         displayMessage('{--MEMBER_ALL_ENTRIES_EDITED--}');
2632                 } else {
2633                         // Some are still there :(
2634                         displayMessage(sprintf(getMessage('MEMBER_SOME_ENTRIES_NOT_EDITED'), $affected, countPostSelection($idColumn[0])));
2635                 }
2636         } else {
2637                 // List for editing
2638                 memberListBuilder('edit', $tableName, $columns, $filterFunctions, $extraValues, $idColumn, $userIdColumn, $rawUserId, $content);
2639         }
2640 }
2641
2642 // Delete rows by given id numbers
2643 function memberDeleteEntriesConfirm ($tableName, $columns = array(), $filterFunctions = array(), $extraValues = array(), $deleteNow = array(FALSE), $idColumn = array('id'), $userIdColumn = array('userid'), $rawUserId = array('userid'), $cacheFiles = array(), $content = array()) {
2644         // Do this only for members
2645         assert(isMember());
2646
2647         // $tableName must be an array
2648         if ((!is_array($tableName)) || (count($tableName) != 1)) {
2649                 // No tableName specified
2650                 reportBug(__FUNCTION__, __LINE__, 'tableName is not given. Please fix your XML,tableName[]=' . gettype($tableName) . '!=array: userIdColumn=' . $userIdColumn);
2651         } elseif (!is_array($idColumn)) {
2652                 // $idColumn is no array
2653                 reportBug(__FUNCTION__, __LINE__, 'idColumn[]=' . gettype($idColumn) . '!=array: userIdColumn=' . $userIdColumn);
2654         } elseif (!is_array($userIdColumn)) {
2655                 // $userIdColumn is no array
2656                 reportBug(__FUNCTION__, __LINE__, 'userIdColumn[]=' . gettype($userIdColumn) . '!=array: userIdColumn=' . $userIdColumn);
2657         } elseif (!is_array($deleteNow)) {
2658                 // $deleteNow is no array
2659                 reportBug(__FUNCTION__, __LINE__, 'deleteNow[]=' . gettype($deleteNow) . '!=array: userIdColumn=' . $userIdColumn);
2660         } // END - if
2661
2662         // Shall we delete here or list for deletion?
2663         if ($deleteNow[0] === TRUE) {
2664                 // Add generic userid field
2665                 setPostRequestElement('userid', getMemberId());
2666
2667                 // Call generic function
2668                 $affected = doGenericDeleteEntriesConfirm($tableName, $columns, $filterFunctions, $extraValues, $deleteNow, $idColumn, $userIdColumn, $rawUserId, $cacheFiles, 'mem_delete');
2669
2670                 // Was this fine?
2671                 if ($affected == countPostSelection($idColumn[0])) {
2672                         // All deleted
2673                         displayMessage('{--MEMBER_ALL_ENTRIES_REMOVED--}');
2674                 } else {
2675                         // Some are still there :(
2676                         displayMessage(sprintf(getMessage('MEMBER_SOME_ENTRIES_NOT_DELETED'), sqlAffectedRows(), countPostSelection($idColumn[0])));
2677                 }
2678         } else {
2679                 // List for deletion confirmation
2680                 memberListBuilder('delete', $tableName, $columns, $filterFunctions, $extraValues, $idColumn, $userIdColumn, $rawUSerId, $content);
2681         }
2682 }
2683
2684 // Build a special template list
2685 // @TODO cacheFiles is not yet supported
2686 function memberListBuilder ($listType, $tableName, $columns, $filterFunctions, $extraValues, $idColumn, $userIdColumn, $rawUserId = array('userid'), $content = array()) {
2687         // Do this only for logged in member
2688         assert(isMember());
2689
2690         // Call inner (general) function
2691         doGenericListBuilder('member', $listType, $tableName, $columns, $filterFunctions, $extraValues, $idColumn, $userIdColumn, $rawUserId, $content);
2692 }
2693
2694 // Checks whether given address is IPv4
2695 function isIp4AddressValid ($address) {
2696         // Is there cache?
2697         if (!isset($GLOBALS[__FUNCTION__][$address])) {
2698                 // Determine it ...
2699                 $GLOBALS[__FUNCTION__][$address] = preg_match('/((25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9])\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[1-9]|0)\.(25[0-5]|2[0-4][0-9]|[0-1]{1}[0-9]{2}|[1-9]{1}[0-9]{1}|[0-9]))/', $address);
2700         } // END - if
2701
2702         // Return cache
2703         return $GLOBALS[__FUNCTION__][$address];
2704 }
2705
2706 // Returns the string if not empty or FALSE if empty
2707 function validateIsEmpty ($str) {
2708         // Trim it
2709         $trimmed = trim($str);
2710
2711         // Is the string empty?
2712         if (empty($trimmed)) {
2713                 // Then set FALSE
2714                 $str = FALSE;
2715         } // END - if
2716
2717         // Return it
2718         return $str;
2719 }
2720
2721 // "Getter" for seconds from given time unit
2722 function getSecondsFromTimeUnit ($timeUnit) {
2723         // Default is not found
2724         $seconds = NULL;
2725
2726         // "Detect" it
2727         switch ($timeUnit) {
2728                 case 's': // Seconds = 1
2729                         $seconds = 1;
2730                         break;
2731
2732                 case 'm': // Minutes
2733                         $seconds = 60;
2734                         break;
2735
2736                 case 'h': // Hours
2737                         $seconds = 60*60;
2738                         break;
2739
2740                 case 'D': // Days
2741                         $seconds = 60*60*24;
2742                         break;
2743
2744                 case 'W': // Weeks
2745                         $seconds = 60*60*24*7;
2746                         break;
2747
2748                 default: // Unsupported
2749                         reportBug(__FUNCTION__, __LINE__, 'Unsupported time unit ' . $timeUnit . ' detected.');
2750                         break;
2751         } // END - switch
2752
2753         // Return value
2754         return $seconds;
2755 }
2756
2757 // Calulates value for given seconds and time unit
2758 function caluculateTimeUnitValue ($seconds, $timeUnit) {
2759         // Calculate it
2760         return ($seconds / getSecondsFromTimeUnit($timeUnit));
2761 }
2762
2763 // "Getter" for an array from given one but only one index of it
2764 function getArrayFromArrayIndex ($array, $key) {
2765         // Some simple validation
2766         assert(isset($array[0][$key]));
2767
2768         // Init new array
2769         $newArray = array();
2770
2771         // "Walk" through all elements
2772         foreach ($array as $element) {
2773                 $newArray[] = $element[$key];
2774         } // END - if
2775
2776         // Return it
2777         return $newArray;
2778 }
2779
2780 /**
2781  * Compress given data and encodes it into BASE64 to be stored in database with
2782  * sqlQueryEscaped()
2783  *
2784  * @param       $data   Data to be compressed and encoded
2785  * @return      $data   Compressed+encoded data
2786  */
2787 function compress ($data) {
2788         // Compress it
2789         return base64_encode(gzcompress($data));
2790 }
2791
2792 /**
2793  * Decompress given data previously compressed with compress().
2794  *
2795  * @param       $data   Data compressed with compress()
2796  * @reurn       $data   Uncompressed data
2797  */
2798 function decompress ($data) {
2799         // Decompress it
2800         return gzuncompress(base64_decode($data));
2801 }
2802
2803 /**
2804  * Converts given charset in given string to UTF-8 if not UTF-8. This function
2805  * is currently limited to iconv().
2806  *
2807  * @param       $str            String to convert charset in
2808  * @param       $charset        Charset to convert from
2809  * @return      $str            Converted string
2810  */
2811 function convertCharsetToUtf8 ($str, $charset) {
2812         // Is iconv() available?
2813         if (!function_exists('iconv')) {
2814                 // Please make it sure
2815                 reportBug(__FUNCTION__, __LINE__, 'PHP function iconv() is currently required to do charset convertion.');
2816         } // END - if
2817
2818         // Is the charset not UTF-8?
2819         if (strtoupper($charset) != 'UTF-8') {
2820                 // Convert it to UTF-8
2821                 $str = iconv(strtoupper($charset), 'UTF-8//TRANSLIT', $str);
2822         } // END - if
2823
2824         // Return converted string
2825         return $str;
2826 }
2827
2828 // ----------------------------------------------------------------------------
2829 //              "Translatation" functions for points_data table
2830 // ----------------------------------------------------------------------------
2831
2832 // Translates generically some data into a target string
2833 function translateGeneric ($messagePrefix, $data, $messageSuffix = '') {
2834         // Is the method null or empty?
2835         if (is_null($data)) {
2836                 // Is NULL
2837                 $data = 'NULL';
2838         } elseif (empty($data)) {
2839                 // Is empty (string)
2840                 $data = 'EMPTY';
2841         } // END - if
2842
2843         // Default column name is unknown
2844         $return = '{%message,' . $messagePrefix . '_UNKNOWN' . $messageSuffix . '=' . strtoupper($data) . '%}';
2845
2846         // Construct message id
2847         $messageId = $messagePrefix . '_' . strtoupper($data) . $messageSuffix;
2848
2849         // Is it there?
2850         if (isMessageIdValid($messageId)) {
2851                 // Then use it as message string
2852                 $return = '{--' . $messageId . '--}';
2853         } // END - if
2854
2855         // Return the column name
2856         return $return;
2857 }
2858
2859 // Translates points subject to human-readable
2860 function translatePointsSubject ($subject) {
2861         // Remove any :x
2862         $subject = removeDoubleDotFromSubject($subject);
2863
2864         // Return it
2865         return translateGeneric('POINTS_SUBJECT', $subject);
2866 }
2867
2868 // "Translates" given points account type
2869 function translatePointsAccountType ($accountType) {
2870         // Return it
2871         return translateGeneric('POINTS_ACCOUNT_TYPE', $accountType);
2872 }
2873
2874 // "Translates" given points "locked mode"
2875 function translatePointsLockedMode ($lockedMode) {
2876         // Return it
2877         return translateGeneric('POINTS_LOCKED_MODE', $lockedMode);
2878 }
2879
2880 // "Translates" given points payment method
2881 function translatePointsPaymentMethod ($paymentMethod) {
2882         // Return it
2883         return translateGeneric('POINTS_PAYMENT_METHOD', $paymentMethod);
2884 }
2885
2886 // "Translates" given points account provider
2887 function translatePointsAccountProvider ($accountProvider) {
2888         // Return it
2889         return translateGeneric('POINTS_ACCOUNT_PROVIDER', $accountProvider);
2890 }
2891
2892 // "Translates" given points notify recipient
2893 function translatePointsNotifyRecipient ($notifyRecipient) {
2894         // Return it
2895         return translateGeneric('POINTS_NOTIFY_RECIPIENT', $notifyRecipient);
2896 }
2897
2898 // "Translates" given mode to a human-readable version
2899 function translatePointsMode ($pointsMode) {
2900         // Return it
2901         return translateGeneric('POINTS_MODE', $pointsMode);
2902 }
2903
2904 // "Translates" task type to a human-readable version
2905 function translateTaskType ($taskType) {
2906         // Return it
2907         return translateGeneric('ADMIN_TASK_TYPE', $taskType);
2908 }
2909
2910 // "Translates" task status to a human-readable version
2911 function translateTaskStatus ($taskStatus) {
2912         // Return it
2913         return translateGeneric('ADMIN_TASK_STATUS', $taskStatus);
2914 }
2915
2916 /*
2917  *-----------------------------------------------------------------------------
2918  * Automatically re-created functions, all taken from user comments on
2919  * www.php.net
2920  *-----------------------------------------------------------------------------
2921  */
2922 if (!function_exists('html_entity_decode')) {
2923         // Taken from documentation on www.php.net
2924         function html_entity_decode ($string) {
2925                 $trans_tbl = get_html_translation_table(HTML_ENTITIES);
2926                 $trans_tbl = array_flip($trans_tbl);
2927                 return strtr($string, $trans_tbl);
2928         }
2929 } // END - if
2930
2931 // "Getter" for base path from theme
2932 function getBasePathFromTheme ($theme) {
2933         return sprintf('%stheme/%s/css/', getPath(), $theme);
2934 }
2935
2936 // Wrapper to check whether given theme is readable
2937 function isThemeReadable ($theme) {
2938         // Is there cache?
2939         if (!isset($GLOBALS[__FUNCTION__][$theme])) {
2940                 // Determine it
2941                 $GLOBALS[__FUNCTION__][$theme] = (isIncludeReadable(sprintf('theme/%s/theme.php', $theme)));
2942         } // END - if
2943
2944         // Return cache
2945         return $GLOBALS[__FUNCTION__][$theme];
2946 }
2947
2948 // Checks whether a given PHP extension is loaded or can be loaded at runtime
2949 //
2950 // Supported OS: Windows, Linux, (Mac?)
2951 function isPhpExtensionLoaded ($extension) {
2952         // Is the extension loaded?
2953         if (extension_loaded($extension)) {
2954                 // All fine
2955                 return TRUE;
2956         } // END - if
2957
2958         // Try to load the extension
2959         return loadLibrary($extension);
2960 }
2961
2962 // Loads given library (aka. PHP extension)
2963 function loadLibrary ($n, $f = NULL) {
2964         // Is the actual function dl() available? (Not on all SAPIs since 5.3)
2965         if (!is_callable('dl')) {
2966                 // Not callable
2967                 /* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'dl() is not callable for n=' . $n . ',f[' . gettype($f) . ']=' . $f);
2968                 return FALSE;
2969         } // END - if
2970
2971         // Try to load PHP library
2972         return dl(((PHP_SHLIB_SUFFIX === 'dll') ? 'php_' : '') . ($f ? $f : $n) . '.' . PHP_SHLIB_SUFFIX);
2973 }
2974
2975 // "Translates" given PHP extension name into a readable version
2976 function translatePhpExtension ($extension) {
2977         // Return the language element
2978         return '{--PHP_EXTENSION_' . strtoupper($extension) . '--}';
2979 }
2980
2981 // Loads stylesheet files in different ways, depending on output mode
2982 function loadStyleSheets () {
2983         // Default styles
2984         $stylesList = array(
2985                 'general.css',
2986                 'ajax.css',
2987         );
2988
2989         // Add stylesheet for installation
2990         if ((isInstaller())) {
2991                 array_push($stylesList, 'install.css');
2992         } // END - if
2993
2994         // When no CSS output-mode is set, set it to file-output
2995         if (!isConfigEntrySet('css_php')) {
2996                 setConfigEntry('css_php', 'FILE');
2997         } // END - if
2998
2999         // Get current theme
3000         $currentTheme = getCurrentTheme();
3001
3002         // Has the theme changed?
3003         if ($currentTheme != getSession('mailer_theme')) {
3004                 // Then set it
3005                 setMailerTheme($currentTheme);
3006         } // END - if
3007
3008         // Output CSS files or content or link to css.php ?
3009         if ((isCssOutputMode()) || (getCssPhp() == 'DIRECT')) {
3010                 // Load CSS files
3011                 $stylesList = merge_array($stylesList, getExtensionCssFiles());
3012
3013                 // Generate base path
3014                 $basePath = getBasePathFromTheme($currentTheme);
3015
3016                 // Output inclusion lines
3017                 foreach ($stylesList as $value) {
3018                         // Only include found CSS files (to reduce 404 requests)
3019                         $FQFN = $basePath . '/' . $value;
3020
3021                         // Do include only existing files and whose are not empty
3022                         if ((isFileReadable($FQFN)) && (filesize($FQFN) > 0)) {
3023                                 switch (getCssPhp()) {
3024                                         case 'DIRECT': // Just link them (unsupported)
3025                                                 $GLOBALS['__page_header'] .= '<link rel="stylesheet" type="text/css" href="{%url=theme/' . getCurrentTheme() . '/' . $value . '%}" />';
3026                                                 break;
3027
3028                                         case 'FILE': // Output contents
3029                                                 $GLOBALS['__page_header'] .= removeDeprecatedComment(readFromFile($FQFN));
3030                                                 break;
3031
3032                                         default: // Invalid mode!
3033                                                 reportBug(__FILE__, __LINE__, sprintf('Invalid css_php value %s detected.', getCssPhp()));
3034                                                 break;
3035                                 } // END - switch
3036                         } // END - if
3037                 } // END - foreach
3038         } elseif ((isHtmlOutputMode()) || (getCssPhp() == 'INLINE')) {
3039                 // Load CSS files
3040                 $stylesList = merge_array($stylesList, getExtensionCssFiles());
3041
3042                 // Generate base path
3043                 $basePath = getBasePathFromTheme(getCurrentTheme());
3044
3045                 // Output inclusion lines
3046                 $OUT = '';
3047                 foreach ($stylesList as $value) {
3048                         // Only include found CSS files (to reduce 404 requests)
3049                         $FQFN = $basePath . '/' . $value;
3050
3051                         // Do include only existing files and whose are not empty
3052                         if ((isFileReadable($FQFN)) && (filesize($FQFN) > 0)) {
3053                                 // Load CSS content
3054                                 $OUT .= readFromFile($FQFN);
3055                         } // END - if
3056                 } // END - foreach
3057
3058                 // Load template
3059                 $GLOBALS['__page_header'] .= loadTemplate('css_inline', TRUE, removeDeprecatedComment($OUT));
3060         } else {
3061                 // Now we load all CSS files from css.php!
3062                 $OUT = '<link rel="stylesheet" type="text/css" href="{%url=css.php';
3063
3064                 if ((isInstaller())) {
3065                         // Default theme first
3066                         $OUT .= '?theme=' . getCurrentTheme() . '&amp;installing=1';
3067                 } else {
3068                         // Add version + a number to bypass caching problems
3069                         $OUT .= '?ver={?FULL_VERSION?}&amp;cb={?CACHE_BUSTER?}';
3070                 }
3071
3072                 // Close tag
3073                 $GLOBALS['__page_header'] .= $OUT . '%}{%ext,version=sql_patches%}" />';
3074         }
3075 }
3076
3077 // [EOF]
3078 ?>