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