Next stage of HTML rewriting, lesser br-tags
[mailer.git] / inc / 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              : functions.php                                    *
8  * -------------------------------------------------------------------- *
9  * Short description : Many non-MySQL functions (also file access)      *
10  * -------------------------------------------------------------------- *
11  * Kurzbeschreibung  : Viele Nicht-MySQL-Funktionen (auch Dateizugriff) *
12  * -------------------------------------------------------------------- *
13  * $Revision::                                                        $ *
14  * $Date::                                                            $ *
15  * $Tag:: 0.2.1-FINAL                                                 $ *
16  * $Author::                                                          $ *
17  * Needs to be in all Files and every File needs "svn propset           *
18  * svn:keywords Date Revision" (autoprobset!) at least!!!!!!            *
19  * -------------------------------------------------------------------- *
20  * Copyright (c) 2003 - 2009 by Roland Haeder                           *
21  * For more information visit: http://www.mxchange.org                  *
22  *                                                                      *
23  * This program is free software; you can redistribute it and/or modify *
24  * it under the terms of the GNU General Public License as published by *
25  * the Free Software Foundation; either version 2 of the License, or    *
26  * (at your option) any later version.                                  *
27  *                                                                      *
28  * This program is distributed in the hope that it will be useful,      *
29  * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
30  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        *
31  * GNU General Public License for more details.                         *
32  *                                                                      *
33  * You should have received a copy of the GNU General Public License    *
34  * along with this program; if not, write to the Free Software          *
35  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,               *
36  * MA  02110-1301  USA                                                  *
37  ************************************************************************/
38
39 // Some security stuff...
40 if (!defined('__SECURITY')) {
41         die();
42 } // END - if
43
44 // Output HTML code directly or 'render' it. You addionally switch the new-line character off
45 function outputHtml ($htmlCode, $newLine = true) {
46         // Init output
47         if (!isset($GLOBALS['output'])) $GLOBALS['output'] = '';
48
49         // Transfer username
50         $username = getMessage('USERNAME_UNKNOWN');
51         if (isset($GLOBALS['username'])) $username = getUsername();
52
53         // Do we have HTML-Code here?
54         if (!empty($htmlCode)) {
55                 // Yes, so we handle it as you have configured
56                 switch (getConfig('OUTPUT_MODE')) {
57                         case 'render':
58                                 // That's why you don't need any \n at the end of your HTML code... :-)
59                                 if (getPhpCaching() == 'on') {
60                                         // Output into PHP's internal buffer
61                                         outputRawCode($htmlCode);
62
63                                         // That's why you don't need any \n at the end of your HTML code... :-)
64                                         if ($newLine === true) print("\n");
65                                 } else {
66                                         // Render mode for old or lame servers...
67                                         $GLOBALS['output'] .= $htmlCode;
68
69                                         // That's why you don't need any \n at the end of your HTML code... :-)
70                                         if ($newLine === true) $GLOBALS['output'] .= "\n";
71                                 }
72                                 break;
73
74                         case 'direct':
75                                 // If we are switching from render to direct output rendered code
76                                 if ((!empty($GLOBALS['output'])) && (getPhpCaching() != 'on')) { outputRawCode($GLOBALS['output']); $GLOBALS['output'] = ''; }
77
78                                 // The same as above... ^
79                                 outputRawCode($htmlCode);
80                                 if ($newLine === true) print("\n");
81                                 break;
82
83                         default:
84                                 // Huh, something goes wrong or maybe you have edited config.php ???
85                                 app_die(__FUNCTION__, __LINE__, '<strong>{--FATAL_ERROR--}:</strong> {--LANG_NO_RENDER_DIRECT--}');
86                                 break;
87                 } // END - switch
88         } elseif ((getPhpCaching() == 'on') && (isset($GLOBALS['footer_sent'])) && ($GLOBALS['footer_sent'] == 1)) {
89                 // Headers already sent?
90                 if (headers_sent()) {
91                         // Log this error
92                         logDebugMessage(__FUNCTION__, __LINE__, 'Headers already sent! We need debug backtrace here.');
93
94                         // Trigger an user error
95                         debug_report_bug('Headers are already sent!');
96                 } // END - if
97
98                 // Output cached HTML code
99                 $GLOBALS['output'] = ob_get_contents();
100
101                 // Clear output buffer for later output if output is found
102                 if (!empty($GLOBALS['output'])) {
103                         clearOutputBuffer();
104                 } // END - if
105
106                 // Extension 'rewrite' installed?
107                 if ((isExtensionActive('rewrite')) && (getOutputMode() != 1)) {
108                         $GLOBALS['output'] = rewriteLinksInCode($GLOBALS['output']);
109                 } // END - if
110
111                 // Send all HTTP headers
112                 sendHttpHeaders();
113
114                 // Compile and run finished rendered HTML code
115                 compileFinalOutput();
116
117                 // Output code here, DO NOT REMOVE! ;-)
118                 outputRawCode($GLOBALS['output']);
119         } elseif ((getConfig('OUTPUT_MODE') == 'render') && (!empty($GLOBALS['output']))) {
120                 // Rewrite links when rewrite extension is active
121                 if ((isExtensionActive('rewrite')) && (getOutputMode() != 1)) {
122                         $GLOBALS['output'] = rewriteLinksInCode($GLOBALS['output']);
123                 } // END - if
124
125                 // Send all HTTP headers
126                 sendHttpHeaders();
127
128                 // Compile and run finished rendered HTML code
129                 compileFinalOutput();
130
131                 // Output code here, DO NOT REMOVE! ;-)
132                 outputRawCode($GLOBALS['output']);
133         }
134 }
135
136 // Sends out all headers required for HTTP/1.1 reply
137 function sendHttpHeaders () {
138         // Used later
139         $now = gmdate('D, d M Y H:i:s') . ' GMT';
140
141         // Send HTTP header
142         sendHeader('HTTP/1.1 200');
143
144         // General headers for no caching
145         sendHeader('Expired: ' . $now); // RFC2616 - Section 14.21
146         sendHeader('Last-Modified: ' . $now);
147         sendHeader('Cache-Control: no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0'); // HTTP/1.1
148         sendHeader('Pragma: no-cache'); // HTTP/1.0
149         sendHeader('Connection: Close');
150         sendHeader('Content-Type: ' . getContentType() . '; charset=UTF-8');
151         sendHeader('Content-Language: ' . getLanguage());
152 }
153
154 // Compiles the final output
155 function compileFinalOutput () {
156         // Init counter
157         $cnt = '0';
158
159         // Compile all out
160         while (((strpos($GLOBALS['output'], '{--') > 0) || (strpos($GLOBALS['output'], '{!') > 0) || (strpos($GLOBALS['output'], '{?') > 0)) && ($cnt < 3)) {
161                 // Init common variables
162                 $content = array();
163                 $newContent = '';
164
165                 // Compile it
166                 $eval = "\$newContent = \"".compileCode(escapeQuotes($GLOBALS['output']))."\";";
167                 eval($eval);
168
169                 // Was that eval okay?
170                 if (empty($newContent)) {
171                         // Something went wrong!
172                         debug_report_bug('Evaluation error:<pre>' . linenumberCode($eval) . '</pre>', false);
173                 } // END - if
174                 $GLOBALS['output'] = $newContent;
175
176                 // Count round
177                 $cnt++;
178         } // END - while
179
180         // Add final length
181         sendHeader('Content-Length: ' . strlen($GLOBALS['output']));
182 }
183
184 // Output the raw HTML code
185 function outputRawCode ($htmlCode) {
186         // Output stripped HTML code to avoid broken JavaScript code, etc.
187         print(str_replace('{BACK}', "\\", $htmlCode));
188
189         // Flush the output if only getPhpCaching() is not 'on'
190         if (getPhpCaching() != 'on') {
191                 // Flush it
192                 flush();
193         } // END - if
194 }
195
196 // Init fatal message array
197 function initFatalMessages () {
198         $GLOBALS['fatal_messages'] = array();
199 }
200
201 // Getter for whole fatal error messages
202 function getFatalArray () {
203         return $GLOBALS['fatal_messages'];
204 }
205
206 // Add a fatal error message to the queue array
207 function addFatalMessage ($F, $L, $message, $extra = '') {
208         if (is_array($extra)) {
209                 // Multiple extras for a message with masks
210                 $message = call_user_func_array('sprintf', $extra);
211         } elseif (!empty($extra)) {
212                 // $message is text with a mask plus extras to insert into the text
213                 $message = sprintf($message, $extra);
214         }
215
216         // Add message to $GLOBALS['fatal_messages']
217         $GLOBALS['fatal_messages'][] = $message;
218
219         // Log fatal messages away
220         debug_report_bug($message);
221         logDebugMessage($F, $L, 'Fatal error message: ' . $message);
222 }
223
224 // Getter for total fatal message count
225 function getTotalFatalErrors () {
226         // Init coun
227         $count = '0';
228
229         // Do we have at least the first entry?
230         if (!empty($GLOBALS['fatal_messages'][0])) {
231                 // Get total count
232                 $count = count($GLOBALS['fatal_messages']);
233         } // END - if
234
235         // Return value
236         return $count;
237 }
238
239 // Load a template file and return it's content (only it's name; do not use ' or ")
240 function loadTemplate ($template, $return = false, $content = array()) {
241         // @TODO Remove this sanity-check if all is fine
242         if (!is_bool($return)) debug_report_bug('return is not bool (' . gettype($return) . ')');
243
244         // @TODO Try to rewrite all $DATA to $content
245         global $DATA;
246
247         // Do we have cache?
248         if (isTemplateCached($template)) {
249                 // Evaluate the cache
250                 eval(readTemplateCache($template));
251         } elseif (!isset($GLOBALS['template_eval'][$template])) {
252                 // Add more variables which you want to use in your template files
253                 $username = getUsername();
254
255                 // Make all template names lowercase
256                 $template = strtolower($template);
257
258                 // Init some data
259                 $ret = '';
260                 if (empty($GLOBALS['refid'])) $GLOBALS['refid'] = '0';
261
262                 // Base directory
263                 $basePath = sprintf("%stemplates/%s/html/", getConfig('PATH'), getLanguage());
264                 $extraPath = detectExtraTemplatePath($template);;
265
266                 ////////////////////////
267                 // Generate file name //
268                 ////////////////////////
269                 $FQFN = $basePath . $extraPath . $template . '.tpl';
270
271                 // Does the special template exists?
272                 if (!isFileReadable($FQFN)) {
273                         // Reset to default template
274                         $FQFN = $basePath . $template . '.tpl';
275                 } // END - if
276
277                 // Now does the final template exists?
278                 if (isFileReadable($FQFN)) {
279                         // Count the template load
280                         incrementConfigEntry('num_templates');
281
282                         // The local file does exists so we load it. :)
283                         $GLOBALS['tpl_content'] = readFromFile($FQFN);
284
285                         // Do we have to compile the code?
286                         $ret = '';
287                         if ((strpos($GLOBALS['tpl_content'], '$') !== false) || (strpos($GLOBALS['tpl_content'], '{--') !== false) || (strpos($GLOBALS['tpl_content'], '{!') !== false) || (strpos($GLOBALS['tpl_content'], '{?') !== false)) {
288                                 // Normal HTML output?
289                                 if (getOutputMode() == '0') {
290                                         // Add surrounding HTML comments to help finding bugs faster
291                                         $ret = '<!-- Template ' . $template . " - Start -->\n" . $GLOBALS['tpl_content'] . '<!-- Template ' . $template . " - End -->\n";
292
293                                         // Prepare eval() command
294                                         $eval = '$ret = "' . compileCode(escapeQuotes($ret)) . '";';
295                                 } elseif (substr($template, 0, 3) == 'js_') {
296                                         // JavaScripts don't like entities and timings
297                                         $eval = '$ret = decodeEntities("' . compileRawCode(escapeJavaScriptQuotes($GLOBALS['tpl_content'])) . '");';
298                                 } else {
299                                         // Prepare eval() command, other output doesn't like entities, maybe
300                                         $eval = '$ret = decodeEntities("' . compileRawCode(escapeQuotes($GLOBALS['tpl_content'])) . '");';
301                                 }
302                         } else {
303                                 // Add surrounding HTML comments to help finding bugs faster
304                                 $ret = '<!-- Template ' . $template . " - Start -->\n" . $GLOBALS['tpl_content'] . '<!-- Template ' . $template . " - End -->\n";
305                                 $eval = '$ret = "' . compileRawCode(escapeQuotes($ret)) . '";';
306                         } // END - if
307
308                         // Cache the eval() command here
309                         $GLOBALS['template_eval'][$template] = $eval;
310
311                         // Eval the code
312                         eval($GLOBALS['template_eval'][$template]);
313                 } elseif ((isAdmin()) || ((isInstalling()) && (!isInstalled()))) {
314                         // Only admins shall see this warning or when installation mode is active
315                         $ret = '<br /><span class="guest_failed">{--TEMPLATE_404--}</span><br />
316 (' . $template . ')<br />
317 <br />
318 {--TEMPLATE_CONTENT--}
319 <pre>' . print_r($content, true) . '</pre>
320 {--TEMPLATE_DATA--}
321 <pre>' . print_r($DATA, true) . '</pre>
322 <br /><br />';
323                 } else {
324                         // No file!
325                         $GLOBALS['template_eval'][$template] = '404';
326                 }
327         } else {
328                 // Eval the code
329                 eval($GLOBALS['template_eval'][$template]);
330         }
331
332         // Do we have some content to output or return?
333         if (!empty($ret)) {
334                 // Not empty so let's put it out! ;)
335                 if ($return === true) {
336                         // Return the HTML code
337                         return $ret;
338                 } else {
339                         // Output directly
340                         outputHtml($ret);
341                 }
342         } elseif (isDebugModeEnabled()) {
343                 // Warning, empty output!
344                 return 'E:' . $template . ',content=<pre>' . print_r($content, true) . '</pre>';
345         }
346 }
347
348 // Detects the extra template path from given template name
349 function detectExtraTemplatePath ($template) {
350         // Default is empty
351         $extraPath = '';
352
353         // Do we have cache?
354         if (!isset($GLOBALS['extra_path'][$template])) {
355                 // Check for admin/guest/member/etc. templates
356                 if (substr($template, 0, 6) == 'admin_') {
357                         // Admin template found
358                         $extraPath = 'admin/';
359                 } elseif (substr($template, 0, 6) == 'guest_') {
360                         // Guest template found
361                         $extraPath = 'guest/';
362                 } elseif (substr($template, 0, 7) == 'member_') {
363                         // Member template found
364                         $extraPath = 'member/';
365                 } elseif (substr($template, 0, 7) == 'select_') {
366                         // Selection template found
367                         $extraPath = 'select/';
368                 } elseif (substr($template, 0, 8) == 'install_') {
369                         // Installation template found
370                         $extraPath = 'install/';
371                 } elseif (substr($template, 0, 4) == 'ext_') {
372                         // Extension template found
373                         $extraPath = 'ext/';
374                 } elseif (substr($template, 0, 3) == 'la_') {
375                         // 'Logical-area' template found
376                         $extraPath = 'la/';
377                 } elseif (substr($template, 0, 3) == 'js_') {
378                         // JavaScript template found
379                         $extraPath = 'js/';
380                 } elseif (substr($template, 0, 5) == 'menu_') {
381                         // Menu template found
382                         $extraPath = 'menu/';
383                 } else {
384                         // Test for extension
385                         $test = substr($template, 0, strpos($template, '_'));
386
387                         // Probe for valid extension name
388                         if (isExtensionNameValid($test)) {
389                                 // Set extra path to extension's name
390                                 $extraPath = $test . '/';
391                         } // END - if
392                 }
393
394                 // Store it in cache
395                 $GLOBALS['extra_path'][$template] = $extraPath;
396         } // END - if
397
398         // Return result
399         return $GLOBALS['extra_path'][$template];
400 }
401
402 // Loads an email template and compiles it
403 function loadEmailTemplate ($template, $content = array(), $userid = '0') {
404         global $DATA;
405
406         // Make sure all template names are lowercase!
407         $template = strtolower($template);
408
409         // Default 'nickname' if extension is not installed
410         $nick = '---';
411
412         // Neutral email address is default
413         $email = getConfig('WEBMASTER');
414
415         // Is content an array?
416         if (is_array($content)) {
417                 // Add expiration to array
418                 if (getConfig('auto_purge') == '0') {
419                         // Will never expire!
420                         $content['expiration'] = getMessage('MAIL_WILL_NEVER_EXPIRE');
421                 } else {
422                         // Create nice date string
423                         $content['expiration'] = createFancyTime(getConfig('auto_purge'));
424                 }
425         } // END - if
426
427         // Load user's data
428         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):UID={$userid},template={$template},content[]=".gettype($content).'<br />');
429         if (($userid > 0) && (is_array($content))) {
430                 // If nickname extension is installed, fetch nickname as well
431                 if ((isExtensionActive('nickname')) && (isNicknameUsed($userid))) {
432                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):NICKNAME!<br />");
433                         // Load by nickname
434                         fetchUserData($userid, 'nickname');
435                 } else {
436                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):NO-NICK!<br />");
437                         /// Load by userid
438                         fetchUserData($userid);
439                 }
440
441                 // Merge data if valid
442                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):content()=".count($content)." - PRE<br />");
443                 if (isUserDataValid()) {
444                         $content = merge_array($content, getUserDataArray());
445                 } // END - if
446                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):content()=".count($content)." - AFTER<br />");
447         } // END - if
448
449         // Translate M to male or F to female if present
450         if (isset($content['gender'])) $content['gender'] = translateGender($content['gender']);
451
452         // Overwrite email from data if present
453         if (isset($content['email'])) $email = $content['email'];
454
455         // Store email for some functions in global data array
456         // @TODO Do only use $content, not $DATA or raw variables
457         $DATA['email'] = $email;
458
459         // Base directory
460         $basePath = sprintf("%stemplates/%s/emails/", getConfig('PATH'), getLanguage());
461
462         // Detect extra path
463         $extraPath = detectExtraTemplatePath($template);
464
465         // Generate full FQFN
466         $FQFN = $basePath . $extraPath . $template . '.tpl';
467
468         // Does the special template exists?
469         if (!isFileReadable($FQFN)) {
470                 // Reset to default template
471                 $FQFN = $basePath . $template . '.tpl';
472         } // END - if
473
474         // Now does the final template exists?
475         $newContent = '';
476         if (isFileReadable($FQFN)) {
477                 // The local file does exists so we load it. :)
478                 $GLOBALS['tpl_content'] = readFromFile($FQFN);
479
480                 // Run code
481                 $GLOBALS['tpl_content'] = "\$newContent = decodeEntities(\"".compileRawCode(escapeQuotes($GLOBALS['tpl_content']))."\");";
482                 eval($GLOBALS['tpl_content']);
483         } elseif (!empty($template)) {
484                 // Template file not found!
485                 $newContent = '{--TEMPLATE_404--}: ' . $template . '<br />
486 {--TEMPLATE_CONTENT--}
487 <pre>' . print_r($content, true) . '</pre>
488 {--TEMPLATE_DATA--}
489 <pre>' . print_r($DATA, true) . '</pre>
490 <br /><br />';
491
492                 // Debug mode not active? Then remove the HTML tags
493                 if (!isDebugModeEnabled()) $newContent = secureString($newContent);
494         } else {
495                 // No template name supplied!
496                 $newContent = getMessage('NO_TEMPLATE_SUPPLIED');
497         }
498
499         // Is there some content?
500         if (empty($newContent)) {
501                 // Compiling failed
502                 $newContent = "Compiler error for template " . $template . " !\nUncompiled content:\n" . $GLOBALS['tpl_content'];
503
504                 // Add last error if the required function exists
505                 if (function_exists('error_get_last')) $newContent .= "\n--------------------------------------\nDebug:\n".print_r(error_get_last(), true)."--------------------------------------\nPlease don't alter these informations!\nThanx.";
506         } // END - if
507
508         // Remove content and data
509         unset($content);
510         unset($DATA);
511
512         // Return content
513         return $newContent;
514 }
515
516 // Send mail out to an email address
517 function sendEmail ($toEmail, $subject, $message, $isHtml = 'N', $mailHeader = '') {
518         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):TO={$toEmail},SUBJECT={$subject}<br />");
519
520         // Compile subject line (for POINTS constant etc.)
521         eval("\$subject = decodeEntities(\"".compileRawCode(escapeQuotes($subject))."\");");
522
523         // Set from header
524         if ((!eregi('@', $toEmail)) && ($toEmail > 0)) {
525                 // Value detected, is the message extension installed?
526                 // @TODO Extension 'msg' does not exist
527                 if (isExtensionActive('msg')) {
528                         ADD_MESSAGE_TO_BOX($toEmail, $subject, $message, $isHtml);
529                         return;
530                 } else {
531                         // Does the user exist?
532                         if (fetchUserData($toEmail)) {
533                                 // Get the email
534                                 $toEmail = getUserData('email');
535                         } else {
536                                 // Set webmaster
537                                 $toEmail = getConfig('WEBMASTER');
538                         }
539                 }
540         } elseif ($toEmail == '0') {
541                 // Is the webmaster!
542                 $toEmail = getConfig('WEBMASTER');
543         }
544         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):TO={$toEmail}<br />");
545
546         // Check for PHPMailer or debug-mode
547         if (!checkPhpMailerUsage()) {
548                 // Not in PHPMailer-Mode
549                 if (empty($mailHeader)) {
550                         // Load email header template
551                         $mailHeader = loadEmailTemplate('header');
552                 } else {
553                         // Append header
554                         $mailHeader .= loadEmailTemplate('header');
555                 }
556         } elseif (isDebugModeEnabled()) {
557                 if (empty($mailHeader)) {
558                         // Load email header template
559                         $mailHeader = loadEmailTemplate('header');
560                 } else {
561                         // Append header
562                         $mailHeader .= loadEmailTemplate('header');
563                 }
564         }
565
566         // Compile "TO"
567         eval("\$toEmail = \"".compileRawCode(escapeQuotes($toEmail))."\";");
568
569         // Compile "MSG"
570         eval("\$message = \"".str_replace('$', '&#36;', compileRawCode(escapeQuotes($message)))."\";");
571
572         // Fix HTML parameter (default is no!)
573         if (empty($isHtml)) $isHtml = 'N';
574         if (isDebugModeEnabled()) {
575                 // In debug mode we want to display the mail instead of sending it away so we can debug this part
576                 outputHtml('<pre>
577 Headers : ' . str_replace('<', '&lt', str_replace('>', '&gt;', secureString(trim($mailHeader)))) . '
578 To      : ' . $toEmail . '
579 Subject : ' . $subject . '
580 Message : ' . $message . '
581 </pre>');
582         } elseif (($isHtml == 'Y') && (isExtensionActive('html_mail'))) {
583                 // Send mail as HTML away
584                 sendHtmlEmail($toEmail, $subject, $message, $mailHeader);
585         } elseif (!empty($toEmail)) {
586                 // Send Mail away
587                 sendRawEmail($toEmail, $subject, $message, $mailHeader);
588         } elseif ($isHtml != 'Y') {
589                 // Problem found!
590                 sendRawEmail(getConfig('WEBMASTER'), '[PROBLEM:]' . $subject, $message, $mailHeader);
591         }
592 }
593
594 // Check to use wether legacy mail() command or PHPMailer class
595 // @TODO Rewrite this to an extension 'smtp'
596 // @private
597 function checkPhpMailerUsage() {
598         return ((getConfig('SMTP_HOSTNAME') != '') && (getConfig('SMTP_USER') != ''));
599 }
600
601 // Send out a raw email with PHPMailer class or legacy mail() command
602 function sendRawEmail ($toEmail, $subject, $message, $from) {
603         // Just compile all again, to put out all configs, etc.
604         eval('$toEmail = decodeEntities("' . compileRawCode(escapeQuotes($toEmail)) . '");');
605         eval('$subject = decodeEntities("' . compileRawCode(escapeQuotes($subject)) . '");');
606         eval('$message = decodeEntities("' . compileRawCode(escapeQuotes($message)) . '");');
607         eval('$from    = decodeEntities("' . compileRawCode(escapeQuotes($from))    . '");');
608
609         // Shall we use PHPMailer class or legacy mode?
610         if (checkPhpMailerUsage()) {
611                 // Use PHPMailer class with SMTP enabled
612                 loadIncludeOnce('inc/phpmailer/class.phpmailer.php');
613                 loadIncludeOnce('inc/phpmailer/class.smtp.php');
614
615                 // get new instance
616                 $mail = new PHPMailer();
617
618                 // Set charset to UTF-8
619                 $mail->CharSet('UTF-8');
620
621                 // Path for PHPMailer
622                 $mail->PluginDir  = sprintf("%sinc/phpmailer/", getConfig('PATH'));
623
624                 $mail->IsSMTP();
625                 $mail->SMTPAuth   = true;
626                 $mail->Host       = getConfig('SMTP_HOSTNAME');
627                 $mail->Port       = 25;
628                 $mail->Username   = getConfig('SMTP_USER');
629                 $mail->Password   = getConfig('SMTP_PASSWORD');
630                 if (empty($from)) {
631                         $mail->From = getConfig('WEBMASTER');
632                 } else {
633                         $mail->From = $from;
634                 }
635                 $mail->FromName   = getConfig('MAIN_TITLE');
636                 $mail->Subject    = $subject;
637                 if ((isExtensionActive('html_mail')) && (secureString($message) != $message)) {
638                         $mail->Body       = $message;
639                         $mail->AltBody    = 'Your mail program required HTML support to read this mail!';
640                         $mail->WordWrap   = 70;
641                         $mail->IsHTML(true);
642                 } else {
643                         $mail->Body       = decodeEntities($message);
644                 }
645                 $mail->AddAddress($toEmail, '');
646                 $mail->AddReplyTo(getConfig('WEBMASTER'), getConfig('MAIN_TITLE'));
647                 $mail->AddCustomHeader('Errors-To:' . getConfig('WEBMASTER'));
648                 $mail->AddCustomHeader('X-Loop:' . getConfig('WEBMASTER'));
649                 $mail->Send();
650         } else {
651                 // Use legacy mail() command
652                 mail($toEmail, $subject, decodeEntities($message), $from);
653         }
654 }
655
656 // Generate a password in a specified length or use default password length
657 function generatePassword ($length = '0') {
658         // Auto-fix invalid length of zero
659         if ($length == '0') $length = getConfig('pass_len');
660
661         // Initialize array with all allowed chars
662         $ABC = explode(',', 'a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,V,W,X,Y,Z,0,1,2,3,4,5,6,7,8,9,-,+,_,/,.');
663
664         // Start creating password
665         $PASS = '';
666         for ($i = '0'; $i < $length; $i++) {
667                 $PASS .= $ABC[mt_rand(0, count($ABC) -1)];
668         } // END - for
669
670         // When the size is below 40 we can also add additional security by scrambling
671         // it. Otherwise we may corrupt hashes
672         if (strlen($PASS) <= 40) {
673                 // Also scramble the password
674                 $PASS = scrambleString($PASS);
675         } // END - if
676
677         // Return the password
678         return $PASS;
679 }
680
681 // Generates a human-readable timestamp from the Uni* stamp
682 function generateDateTime ($time, $mode = '0') {
683         // Filter out numbers
684         $time = bigintval($time);
685
686         // If the stamp is zero it mostly didn't "happen"
687         if ($time == '0') {
688                 // Never happend
689                 return getMessage('NEVER_HAPPENED');
690         } // END - if
691
692         switch (getLanguage()) {
693                 case 'de': // German date / time format
694                         switch ($mode) {
695                                 case '0': $ret = date("d.m.Y \u\m H:i \U\h\\r", $time); break;
696                                 case '1': $ret = strtolower(date('d.m.Y - H:i', $time)); break;
697                                 case '2': $ret = date('d.m.Y|H:i', $time); break;
698                                 case '3': $ret = date('d.m.Y', $time); break;
699                                 default:
700                                         logDebugMessage(__FUNCTION__, __LINE__, sprintf("Invalid date mode %s detected.", $mode));
701                                         break;
702                         }
703                         break;
704
705                 default: // Default is the US date / time format!
706                         switch ($mode) {
707                                 case '0': $ret = date('r', $time); break;
708                                 case '1': $ret = date('Y-m-d - g:i A', $time); break;
709                                 case '2': $ret = date('y-m-d|H:i', $time); break;
710                                 case '3': $ret = date('y-m-d', $time); break;
711                                 default:
712                                         logDebugMessage(__FUNCTION__, __LINE__, sprintf("Invalid date mode %s detected.", $mode));
713                                         break;
714                         } // END - switch
715         } // END - switch
716
717         // Return result
718         return $ret;
719 }
720
721 // Translates Y/N to yes/no
722 function translateYesNo ($yn) {
723         // Default
724         $translated = '??? (' . $yn . ')';
725         switch ($yn) {
726                 case 'Y': $translated = getMessage('YES'); break;
727                 case 'N': $translated = getMessage('NO'); break;
728                 default:
729                         // Log unknown value
730                         logDebugMessage(__FUNCTION__, __LINE__, sprintf("Unknown value %s. Expected Y/N!", $yn));
731                         break;
732         }
733
734         // Return it
735         return $translated;
736 }
737
738 // Translates the "pool type" into human-readable
739 function translatePoolType ($type) {
740         // Default?type is unknown
741         $translated = sprintf(getMessage('POOL_TYPE_UNKNOWN'), $type);
742
743         // Generate constant
744         $constName = sprintf("POOL_TYPE_%s", $type);
745
746         // Does it exist?
747         if (isMessageIdValid($constName)) {
748                 // Then use it
749                 $translated = getMessage($constName);
750         } // END - if
751
752         // Return "translation"
753         return $translated;
754 }
755
756 // Translates the american decimal dot into a german comma
757 function translateComma ($dotted, $cut = true, $max = '0') {
758         // Default is 3 you can change this in admin area "Misc -> Misc Options"
759         if (!isConfigEntrySet('max_comma')) setConfigEntry('max_comma', 3);
760
761         // Use from config is default
762         $maxComma = getConfig('max_comma');
763
764         // Use from parameter?
765         if ($max > 0) $maxComma = $max;
766
767         // Cut zeros off?
768         if (($cut === true) && ($max == '0')) {
769                 // Test for commata if in cut-mode
770                 $com = explode('.', $dotted);
771                 if (count($com) < 2) {
772                         // Don't display commatas even if there are none... ;-)
773                         $maxComma = '0';
774                 }
775         } // END - if
776
777         // Debug log
778         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, "dotted={$dotted},maxComma={$maxComma}");
779
780         // Translate it now
781         switch (getLanguage()) {
782                 case 'de': // German language
783                         $dotted = number_format($dotted, $maxComma, ',', '.');
784                         break;
785
786                 default: // All others
787                         $dotted = number_format($dotted, $maxComma, '.', ',');
788                         break;
789         }
790
791         // Return translated value
792         return $dotted;
793 }
794
795 // Translate Uni*-like gender to human-readable
796 function translateGender ($gender) {
797         // Default
798         $ret = '!' . $gender . '!';
799
800         // Male/female or company?
801         switch ($gender) {
802                 case 'M': $ret = getMessage('GENDER_M'); break;
803                 case 'F': $ret = getMessage('GENDER_F'); break;
804                 case 'C': $ret = getMessage('GENDER_C'); break;
805                 default:
806                         // Log unknown gender
807                         logDebugMessage(__FUNCTION__, __LINE__, sprintf("Unknown gender %s detected.", $gender));
808                         break;
809         }
810
811         // Return translated gender
812         return $ret;
813 }
814
815 // "Translates" the user status
816 function translateUserStatus ($status) {
817         // Generate message depending on status
818         switch ($status) {
819                 case 'UNCONFIRMED':
820                 case 'CONFIRMED':
821                 case 'LOCKED':
822                         $ret = getMessage(sprintf("ACCOUNT_%s", $status));
823                         break;
824
825                 case '':
826                 case null:
827                         $ret = getMessage('ACCOUNT_DELETED');
828                         break;
829
830                 default:
831                         logDebugMessage(__FUNCTION__, __LINE__, sprintf("Unknown status %s detected.", $status));
832                         $ret = sprintf(getMessage('UNKNOWN_STATUS'), $status);
833                         break;
834         } // END - switch
835
836         // Return it
837         return $ret;
838 }
839
840 // Generates an URL for the dereferer
841 function generateDerefererUrl ($URL) {
842         // Don't de-refer our own links!
843         if (substr($URL, 0, strlen(getConfig('URL'))) != getConfig('URL')) {
844                 // De-refer this link
845                 $URL = '{%url=modules.php?module=loader&amp;url=' . encodeString(compileUriCode($URL)) . '%}';
846         } // END - if
847
848         // Return link
849         return $URL;
850 }
851
852 // Generates an URL for the frametester
853 function generateFrametesterUrl ($URL) {
854         // Prepare frametester URL
855         $frametesterUrl = sprintf("{%%url=modules.php?module=frametester&amp;url=%s%%}",
856                 encodeString(compileUriCode($URL))
857         );
858
859         // Return the new URL
860         return $frametesterUrl;
861 }
862
863 // Count entries from e.g. a selection box
864 function countSelection ($array) {
865         // Integrity check
866         if (!is_array($array)) {
867                 // Not an array!
868                 debug_report_bug(__FUNCTION__.': No array provided.');
869         } // END - if
870
871         // Init count
872         $ret = '0';
873
874         // Count all entries
875         foreach ($array as $key => $selected) {
876                 // Is it checked?
877                 if (!empty($selected)) $ret++;
878         } // END - foreach
879
880         // Return counted selections
881         return $ret;
882 }
883
884 // Generate XHTML code for the CAPTCHA
885 function generateCaptchaCode ($code, $type, $DATA, $userid) {
886         return '<img border="0" alt="Code ' . $code . '" src="{%url=mailid_top.php?userid=' . $userid . '&amp;' . $type . '=' . $DATA . '&amp;mode=img&amp;code=' . $code . '%}" />';
887 }
888
889 // Generates a timestamp (some wrapper for mktime())
890 function makeTime ($hours, $minutes, $seconds, $stamp) {
891         // Extract day, month and year from given timestamp
892         $days   = date('d', $stamp);
893         $months = date('m', $stamp);
894         $years  = date('Y', $stamp);
895
896         // Create timestamp for wished time which depends on extracted date
897         return mktime(
898                 $hours,
899                 $minutes,
900                 $seconds,
901                 $months,
902                 $days,
903                 $years
904         );
905 }
906
907 // Redirects to an URL and if neccessarry extends it with own base URL
908 function redirectToUrl ($URL) {
909         // Compile out codes
910         eval('$URL = "' . compileRawCode(encodeUrl($URL)) . '";');
911
912         // Default 'rel' value is external, nofollow is evil from Google and hurts the Internet
913         $rel = ' rel="external"';
914
915         // Do we have internal or external URL?
916         if (substr($URL, 0, strlen(getConfig('URL'))) == getConfig('URL')) {
917                 // Own (=internal) URL
918                 $rel = '';
919         } // END - if
920
921         // Get output buffer
922         $GLOBALS['output'] = ob_get_contents();
923
924         // Clear it only if there is content
925         if (!empty($GLOBALS['output'])) {
926                 clearOutputBuffer();
927         } // END - if
928
929         // Three different ways to debug...
930         //* DEBUG: */ debug_report_bug(sprintf("%s[%s:] URL=%s", __FUNCTION__, __LINE__, $URL));
931         //* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, 'URL=' . $URL);
932         //* DEBUG: */ die($URL);
933
934         // Simple probe for bots/spiders from search engines
935         if (isSpider()) {
936                 // Secure the URL against bad things such als HTML insertions and so on...
937                 $URL = secureString($URL);
938
939                 // Output new location link as anchor
940                 outputHtml('<a href="' . $URL . '"' . $rel . '>' . $URL . '</a>');
941         } elseif (!headers_sent()) {
942                 // Clear own output buffer
943                 $GLOBALS['output'] = '';
944
945                 // Load URL when headers are not sent
946                 sendHeader('Location: '.str_replace('&amp;', '&', $URL));
947         } else {
948                 // Output error message
949                 loadInclude('inc/header.php');
950                 loadTemplate('redirect_url', false, str_replace('&amp;', '&', $URL));
951                 loadInclude('inc/footer.php');
952         }
953
954         // Shut the mailer down here
955         shutdown();
956 }
957
958 // Wrapper for redirectToUrl but URL comes from a configuration entry
959 function redirectToConfiguredUrl ($configEntry) {
960         // Get the URL
961         $URL = getConfig($configEntry);
962
963         // Is this URL set?
964         if (is_null($URL)) {
965                 // Then abort here
966                 debug_report_bug(sprintf("Configuration entry %s is not set!", $configEntry));
967         } // END - if
968
969         // Load the URL
970         redirectToUrl($URL);
971 }
972
973 // Compiles the given HTML/mail code
974 function compileCode ($code, $simple = false, $constants = true, $full = true) {
975         // Is the code a string?
976         if (!is_string($code)) {
977                 // Silently return it
978                 return $code;
979         } // END - if
980
981         // Start couting
982         $startCompile = microtime(true);
983
984         // Comile the code
985         $code = compileRawCode($code, $simple, $constants, $full);
986
987         // Get timing
988         $compiled = microtime(true);
989
990         // Add timing
991         $code .= '<!-- Compilation time: ' . (($compiled - $startCompile) * 1000). 'ms //-->';
992
993         // Return compiled code
994         return $code;
995 }
996
997 // Compiles the code (use compileCode() only for HTML because of the comments)
998 // @TODO $simple is deprecated
999 function compileRawCode ($code, $simple = false, $constants = true, $full = true) {
1000         // Is the code a string?
1001         if (!is_string($code)) {
1002                 // Silently return it
1003                 return $code;
1004         } // END - if
1005
1006         // Init replacement-array with smaller set of security characters
1007         $secChars = $GLOBALS['url_chars'];
1008
1009         // Select full set of chars to replace when we e.g. want to compile URLs
1010         if ($full === true) $secChars = $GLOBALS['security_chars'];
1011
1012         // Compile more through a filter
1013         $code = runFilterChain('compile_code', $code);
1014
1015         // Compile constants
1016         if ($constants === true) {
1017                 // BEFORE 0.2.1 : Language and data constants
1018                 // WITH 0.2.1+  : Only language constants
1019                 $code = str_replace('{--', "\" . getMessage('", str_replace('--}', "') . \"", $code));
1020
1021                 // BEFORE 0.2.1 : Not used
1022                 // WITH 0.2.1+  : Data constants
1023                 $code = str_replace('{!', "\" . constant('", str_replace('!}', "') . \"", $code));
1024         } // END - if
1025
1026         // Compile QUOT and other non-HTML codes
1027         foreach ($secChars['to'] as $k => $to) {
1028                 // Do the reversed thing as in inc/libs/security_functions.php
1029                 $code = str_replace($to, $secChars['from'][$k], $code);
1030         } // END - foreach
1031
1032         // Find $content[bla][blub] entries
1033         // @TODO Do only use $content and deprecate $GLOBALS and $DATA in templates
1034         preg_match_all('/\$(content|GLOBALS|DATA)((\[([a-zA-Z0-9-_]+)\])*)/', $code, $matches);
1035
1036         // Are some matches found?
1037         if ((count($matches) > 0) && (count($matches[0]) > 0)) {
1038                 // Replace all matches
1039                 $matchesFound = array();
1040                 foreach ($matches[0] as $key => $match) {
1041                         // Fuzzy look has failed by default
1042                         $fuzzyFound = false;
1043
1044                         // Fuzzy look on match if already found
1045                         foreach ($matchesFound as $found => $set) {
1046                                 // Get test part
1047                                 $test = substr($found, 0, strlen($match));
1048
1049                                 // Does this entry exist?
1050                                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):found={$found},match={$match},set={$set}<br />");
1051                                 if ($test == $match) {
1052                                         // Match found!
1053                                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):fuzzyFound!<br />");
1054                                         $fuzzyFound = true;
1055                                         break;
1056                                 } // END - if
1057                         } // END - foreach
1058
1059                         // Skip this entry?
1060                         if ($fuzzyFound === true) continue;
1061
1062                         // Take all string elements
1063                         if ((is_string($matches[4][$key])) && (!isset($matchesFound[$match])) && (!isset($matchesFound[$key."_" . $matches[4][$key]]))) {
1064                                 // Replace it in the code
1065                                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):key={$key},match={$match}<br />");
1066                                 $newMatch = str_replace('[', "['", str_replace(']', "']", $match));
1067                                 $code = str_replace($match, '".' . $newMatch . '."', $code);
1068                                 $matchesFound[$key . '_' . $matches[4][$key]] = 1;
1069                                 $matchesFound[$match] = 1;
1070                         } elseif (!isset($matchesFound[$match])) {
1071                                 // Not yet replaced!
1072                                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):match={$match}<br />");
1073                                 $code = str_replace($match, '".' . $match . '."', $code);
1074                                 $matchesFound[$match] = 1;
1075                         }
1076                 } // END - foreach
1077         } // END - if
1078
1079         // Return it
1080         return $code;
1081 }
1082
1083 /************************************************************************
1084  *                                                                      *
1085  * Gaenderter Sortier-Algorythmus, $array wird nach dem Array (!)       *
1086  * $a_sort sortiert:                                                    *
1087  *                                                                      *
1088  * $array - Das 3-dimensionale Array, das paralell sortiert werden soll *
1089  * $a_sort - Array, das die Sortiereihenfolge der ersten Elementeben    *
1090  * $primary_key - Prim.rschl.ssel aus $a_sort, nach dem sortiert wird   *
1091  * $order - Sortiereihenfolge: -1 = a-Z, 0 = keine, 1 = Z-a             *
1092  * $nums - true = Als Zahlen sortieren, false = Als Zeichen sortieren   *
1093  *                                                                      *
1094  * $a_sort muss Elemente enthalten, deren Wert Schluessel von $array    *
1095  * sind... Klingt kompliziert, suchen Sie mal mein Beispiel, dann sehen *
1096  * Sie, dass es doch nicht so schwer ist! :-)                           *
1097  *                                                                      *
1098  ************************************************************************/
1099 function array_pk_sort (&$array, $a_sort, $primary_key = '0', $order = -1, $nums = false) {
1100         $dummy = $array;
1101         while ($primary_key < count($a_sort)) {
1102                 foreach ($dummy[$a_sort[$primary_key]] as $key => $value) {
1103                         foreach ($dummy[$a_sort[$primary_key]] as $key2 => $value2) {
1104                                 $match = false;
1105                                 if ($nums === false) {
1106                                         // Sort byte-by-byte (also numbers will be interpreted as chars! E.g.: "9" > "10")
1107                                         if (($key != $key2) && (strcmp(strtolower($dummy[$a_sort[$primary_key]][$key]), strtolower($dummy[$a_sort[$primary_key]][$key2])) == $order)) $match = true;
1108                                 } elseif ($key != $key2) {
1109                                         // Sort numbers (E.g.: 9 < 10)
1110                                         if (($dummy[$a_sort[$primary_key]][$key] < $dummy[$a_sort[$primary_key]][$key2]) && ($order == -1)) $match = true;
1111                                         if (($dummy[$a_sort[$primary_key]][$key] > $dummy[$a_sort[$primary_key]][$key2]) && ($order == 1))  $match = true;
1112                                 }
1113
1114                                 if ($match) {
1115                                         // We have found two different values, so let's sort whole array
1116                                         foreach ($dummy as $sort_key => $sort_val) {
1117                                                 $t                       = $dummy[$sort_key][$key];
1118                                                 $dummy[$sort_key][$key]  = $dummy[$sort_key][$key2];
1119                                                 $dummy[$sort_key][$key2] = $t;
1120                                                 unset($t);
1121                                         } // END - foreach
1122                                 } // END - if
1123                         } // END - foreach
1124                 } // END - foreach
1125
1126                 // Count one up
1127                 $primary_key++;
1128         } // END - while
1129
1130         // Write back sorted array
1131         $array = $dummy;
1132 }
1133
1134 //
1135 function addSelectionBox ($type, $default, $prefix = '', $id = '0', $class = 'register_select') {
1136         $OUT = '';
1137
1138         if ($type == 'yn') {
1139                 // This is a yes/no selection only!
1140                 if ($id > 0) $prefix .= "[" . $id."]";
1141                 $OUT .= "    <select name=\"" . $prefix."\" class=\"" . $class . "\" size=\"1\">\n";
1142         } else {
1143                 // Begin with regular selection box here
1144                 if (!empty($prefix)) $prefix .= "_";
1145                 $type2 = $type;
1146                 if ($id > 0) $type2 .= "[" . $id."]";
1147                 $OUT .= "    <select name=\"".strtolower($prefix . $type2)."\" class=\"" . $class . "\" size=\"1\">\n";
1148         }
1149
1150         switch ($type) {
1151                 case 'day': // Day
1152                         for ($idx = 1; $idx < 32; $idx++) {
1153                                 $OUT .= "<option value=\"" . $idx."\"";
1154                                 if ($default == $idx) $OUT .= ' selected="selected"';
1155                                 $OUT .= ">" . $idx."</option>\n";
1156                         } // END - for
1157                         break;
1158
1159                 case 'month': // Month
1160                         foreach ($GLOBALS['month_descr'] as $month => $descr) {
1161                                 $OUT .= "<option value=\"" . $month."\"";
1162                                 if ($default == $month) $OUT .= ' selected="selected"';
1163                                 $OUT .= ">" . $descr."</option>\n";
1164                         } // END - for
1165                         break;
1166
1167                 case 'year': // Year
1168                         // Get current year
1169                         $year = date('Y', time());
1170
1171                         // Use configured min age or fixed?
1172                         if ((isExtensionActive('other')) && (getExtensionVersion('other') >= '0.2.1')) {
1173                                 // Configured
1174                                 $startYear = $year - getConfig('min_age');
1175                         } else {
1176                                 // Fixed 16 years
1177                                 $startYear = $year - 16;
1178                         }
1179
1180                         // Calculate earliest year (100 years old people can still enter Internet???)
1181                         $minYear = $year - 100;
1182
1183                         // Check if the default value is larger than minimum and bigger than actual year
1184                         if (($default > $minYear) && ($default >= $year)) {
1185                                 for ($idx = $year; $idx < ($year + 11); $idx++) {
1186                                         $OUT .= "<option value=\"" . $idx."\"";
1187                                         if ($default == $idx) $OUT .= ' selected="selected"';
1188                                         $OUT .= ">" . $idx."</option>\n";
1189                                 } // END - for
1190                         } elseif ($default == -1) {
1191                                 // Current year minus 1
1192                                 for ($idx = $startYear; $idx <= ($year + 1); $idx++)
1193                                 {
1194                                         $OUT .= "<option value=\"" . $idx."\">" . $idx."</option>\n";
1195                                 }
1196                         } else {
1197                                 // Get current year and subtract the configured minimum age
1198                                 $OUT .= "<option value=\"".($minYear - 1)."\">&lt;" . $minYear."</option>\n";
1199                                 // Calculate earliest year depending on extension version
1200                                 if ((isExtensionActive('other')) && (getExtensionVersion('other') >= '0.2.1')) {
1201                                         // Use configured minimum age
1202                                         $year = date('Y', time()) - getConfig('min_age');
1203                                 } else {
1204                                         // Use fixed 16 years age
1205                                         $year = date('Y', time()) - 16;
1206                                 }
1207
1208                                 // Construct year selection list
1209                                 for ($idx = $minYear; $idx <= $year; $idx++) {
1210                                         $OUT .= "<option value=\"" . $idx."\"";
1211                                         if ($default == $idx) $OUT .= ' selected="selected"';
1212                                         $OUT .= ">" . $idx."</option>\n";
1213                                 } // END - for
1214                         }
1215                         break;
1216
1217                 case 'sec':
1218                 case 'min':
1219                         for ($idx = '0'; $idx < 60; $idx+=5) {
1220                                 if (strlen($idx) == 1) $idx = '0' . $idx;
1221                                 $OUT .= "<option value=\"" . $idx."\"";
1222                                 if ($default == $idx) $OUT .= ' selected="selected"';
1223                                 $OUT .= ">" . $idx."</option>\n";
1224                         } // END - for
1225                         break;
1226
1227                 case 'hour':
1228                         for ($idx = '0'; $idx < 24; $idx++) {
1229                                 if (strlen($idx) == 1) $idx = '0' . $idx;
1230                                 $OUT .= "<option value=\"" . $idx."\"";
1231                                 if ($default == $idx) $OUT .= ' selected="selected"';
1232                                 $OUT .= ">" . $idx."</option>\n";
1233                         } // END - for
1234                         break;
1235
1236                 case 'yn':
1237                         $OUT .= "<option value=\"Y\"";
1238                         if ($default == 'Y') $OUT .= ' selected="selected"';
1239                         $OUT .= ">{--YES--}</option>\n<option value=\"N\"";
1240                         if ($default != 'Y') $OUT .= ' selected="selected"';
1241                         $OUT .= ">{--NO--}</option>\n";
1242                         break;
1243         }
1244         $OUT .= "    </select>\n";
1245         return $OUT;
1246 }
1247
1248 //
1249 // Deprecated : $length
1250 // Optional   : $DATA
1251 //
1252 function generateRandomCode ($length, $code, $userid, $DATA = '') {
1253         // Build server string
1254         $server = $_SERVER['PHP_SELF'] . getConfig('ENCRYPT_SEPERATOR') . detectUserAgent() . getConfig('ENCRYPT_SEPERATOR') . getenv('SERVER_SOFTWARE') . getConfig('ENCRYPT_SEPERATOR') . detectRemoteAddr().":'.':".filemtime(getConfig('PATH').'inc/databases.php');
1255
1256         // Build key string
1257         $keys = getConfig('SITE_KEY') . getConfig('ENCRYPT_SEPERATOR') . getConfig('DATE_KEY');
1258         if (isConfigEntrySet('secret_key'))  $keys .= getConfig('ENCRYPT_SEPERATOR').getConfig('secret_key');
1259         if (isConfigEntrySet('file_hash'))   $keys .= getConfig('ENCRYPT_SEPERATOR').getConfig('file_hash');
1260         $keys .= getConfig('ENCRYPT_SEPERATOR') . date('d-m-Y (l-F-T)', getConfig('patch_ctime'));
1261         if (isConfigEntrySet('master_salt')) $keys .= getConfig('ENCRYPT_SEPERATOR').getConfig('master_salt');
1262
1263         // Build string from misc data
1264         $data   = $code . getConfig('ENCRYPT_SEPERATOR') . $userid . getConfig('ENCRYPT_SEPERATOR') . $DATA;
1265
1266         // Add more additional data
1267         if (isSessionVariableSet('u_hash'))         $data .= getConfig('ENCRYPT_SEPERATOR') . getSession('u_hash');
1268
1269         // Add referal id, language, theme and userid
1270         $data .= getConfig('ENCRYPT_SEPERATOR') . determineReferalId();
1271         $data .= getConfig('ENCRYPT_SEPERATOR') . getLanguage();
1272         $data .= getConfig('ENCRYPT_SEPERATOR') . getCurrentTheme();
1273         $data .= getConfig('ENCRYPT_SEPERATOR') . getMemberId();
1274
1275         // Calculate number for generating the code
1276         $a = $code + getConfig('_ADD') - 1;
1277
1278         if (isConfigEntrySet('master_salt')) {
1279                 // Generate hash with master salt from modula of number with the prime number and other data
1280                 $saltedHash = generateHash(($a % getConfig('_PRIME')) . getConfig('ENCRYPT_SEPERATOR') . $server . getConfig('ENCRYPT_SEPERATOR') . $keys . getConfig('ENCRYPT_SEPERATOR') . $data . getConfig('ENCRYPT_SEPERATOR') . getConfig('DATE_KEY') . getConfig('ENCRYPT_SEPERATOR') . $a, getConfig('master_salt'));
1281
1282                 // Create number from hash
1283                 $rcode = hexdec(substr($saltedHash, strlen(getConfig('master_salt')), 9)) / abs(getConfig('rand_no') - $a + sqrt(getConfig('_ADD'))) / pi();
1284         } else {
1285                 // Generate hash with "hash of site key" from modula of number with the prime number and other data
1286                 $saltedHash = generateHash(($a % getConfig('_PRIME')) . getConfig('ENCRYPT_SEPERATOR') . $server . getConfig('ENCRYPT_SEPERATOR') . $keys . getConfig('ENCRYPT_SEPERATOR') . $data . getConfig('ENCRYPT_SEPERATOR') . getConfig('DATE_KEY') . getConfig('ENCRYPT_SEPERATOR') . $a, substr(sha1(getConfig('SITE_KEY')), 0, getConfig('salt_length')));
1287
1288                 // Create number from hash
1289                 $rcode = hexdec(substr($saltedHash, 8, 9)) / abs(getConfig('rand_no') - $a + sqrt(getConfig('_ADD'))) / pi();
1290         }
1291
1292         // At least 10 numbers shall be secure enought!
1293         $len = getConfig('code_length');
1294         if ($len == '0') $len = $length;
1295         if ($len == '0') $len = 10;
1296
1297         // Cut off requested counts of number
1298         $return = substr(str_replace('.', '', $rcode), 0, $len);
1299
1300         // Done building code
1301         return $return;
1302 }
1303
1304 // Does only allow numbers
1305 function bigintval ($num, $castValue = true) {
1306         // Filter all numbers out
1307         $ret = preg_replace('/[^0123456789]/', '', $num);
1308
1309         // Shall we cast?
1310         if ($castValue === true) $ret = (double)$ret;
1311
1312         // Has the whole value changed?
1313         if ('' . $ret . '' != '' . $num . '') {
1314                 // Log the values
1315                 debug_report_bug('Problem with number found. ret=' . $ret . ', num='. $num);
1316         } // END - if
1317
1318         // Return result
1319         return $ret;
1320 }
1321
1322 // Insert the code in $img_code into jpeg or PNG image
1323 function generateImageOrCode ($img_code, $headerSent = true) {
1324         // Is the code size oversized or shouldn't we display it?
1325         if ((strlen($img_code) > 6) || (empty($img_code)) || (getConfig('code_length') == '0')) {
1326                 // Stop execution of function here because of over-sized code length
1327                 debug_report_bug('img_code ' . $img_code .' has invalid length. img_code()=' . strlen($img_code) . ' code_length=' . getConfig('code_length'));
1328         } elseif ($headerSent === false) {
1329                 // Return an HTML code here
1330                 return "<img src=\"{%url=img.php?code=" . $img_code."%}\" alt=\"Image\" />\n";
1331         }
1332
1333         // Load image
1334         $img = sprintf("%s/theme/%s/images/code_bg.%s",
1335                 getConfig('PATH'),
1336                 getCurrentTheme(),
1337                 getConfig('img_type')
1338         );
1339
1340         // Is it readable?
1341         if (isFileReadable($img)) {
1342                 // Switch image type
1343                 switch (getConfig('img_type'))
1344                 {
1345                         case 'jpg':
1346                                 // Okay, load image and hide all errors
1347                                 $image = imagecreatefromjpeg($img);
1348                                 break;
1349
1350                         case 'png':
1351                                 // Okay, load image and hide all errors
1352                                 $image = imagecreatefrompng($img);
1353                                 break;
1354                 }
1355         } else {
1356                 // Exit function here
1357                 logDebugMessage(__FUNCTION__, __LINE__, sprintf("File for image type %s not found.", getConfig('img_type')));
1358                 return;
1359         }
1360
1361         // Generate text color (red/green/blue; 0 = dark, 255 = bright)
1362         $text_color = imagecolorallocate($image, 0, 0, 0);
1363
1364         // Insert code into image
1365         imagestring($image, 5, 14, 2, $img_code, $text_color);
1366
1367         // Return to browser
1368         sendHeader('Content-Type: image/' . getConfig('img_type'));
1369
1370         // Output image with matching image factory
1371         switch (getConfig('img_type')) {
1372                 case 'jpg': imagejpeg($image); break;
1373                 case 'png': imagepng($image);  break;
1374         }
1375
1376         // Remove image from memory
1377         imagedestroy($image);
1378 }
1379 // Create selection box or array of splitted timestamp
1380 function createTimeSelections ($timestamp, $prefix = '', $display = '', $align = 'center', $return_array=false) {
1381         // Calculate 2-seconds timestamp
1382         $stamp = round($timestamp);
1383         //* DEBUG: */ print("*" . $stamp.'/' . $timestamp."*<br />");
1384
1385         // Do we have a leap year?
1386         $SWITCH = '0';
1387         $TEST = date('Y', time()) / 4;
1388         $M1 = date('m', time());
1389         $M2 = date('m', (time() + $timestamp));
1390
1391         // If so and if current time is before 02/29 and estimated time is after 02/29 then add 86400 seconds (one day)
1392         if ((floor($TEST) == $TEST) && ($M1 == "02") && ($M2 > "02"))  $SWITCH = getConfig('ONE_DAY');
1393
1394         // First of all years...
1395         $Y = abs(floor($timestamp / (31536000 + $SWITCH)));
1396         //* DEBUG: */ print("Y={$Y}<br />");
1397         // Next months...
1398         $M = abs(floor($timestamp / 2628000 - $Y * 12));
1399         //* DEBUG: */ print("M={$M}<br />");
1400         // Next weeks
1401         $W = abs(floor($timestamp / 604800 - $Y * ((365 + $SWITCH / getConfig('ONE_DAY')) / 7) - ($M / 12 * (365 + $SWITCH / getConfig('ONE_DAY')) / 7)));
1402         //* DEBUG: */ print("W={$W}<br />");
1403         // Next days...
1404         $D = abs(floor($timestamp / 86400 - $Y * (365 + $SWITCH / getConfig('ONE_DAY')) - ($M / 12 * (365 + $SWITCH / getConfig('ONE_DAY'))) - $W * 7));
1405         //* DEBUG: */ print("D={$D}<br />");
1406         // Next hours...
1407         $h = abs(floor($timestamp / 3600 - $Y * (365 + $SWITCH / getConfig('ONE_DAY')) * 24 - ($M / 12 * (365 + $SWITCH / getConfig('ONE_DAY')) * 24) - $W * 7 * 24 - $D * 24));
1408         //* DEBUG: */ print("h={$h}<br />");
1409         // Next minutes..
1410         $m = abs(floor($timestamp / 60 - $Y * (365 + $SWITCH / getConfig('ONE_DAY')) * 24 * 60 - ($M / 12 * (365 + $SWITCH / getConfig('ONE_DAY')) * 24 * 60) - $W * 7 * 24 * 60 - $D * 24 * 60 - $h * 60));
1411         //* DEBUG: */ print("m={$m}<br />");
1412         // And at last seconds...
1413         $s = abs(floor($timestamp - $Y * (365 + $SWITCH / getConfig('ONE_DAY')) * 24 * 3600 - ($M / 12 * (365 + $SWITCH / getConfig('ONE_DAY')) * 24 * 3600) - $W * 7 * 24 * 3600 - $D * 24 * 3600 - $h * 3600 - $m * 60));
1414         //* DEBUG: */ print("s={$s}<br />");
1415
1416         // Is seconds zero and time is < 60 seconds?
1417         if (($s == '0') && ($timestamp < 60)) {
1418                 // Fix seconds
1419                 $s = round($timestamp);
1420         } // END - if
1421
1422         //
1423         // Now we convert them in seconds...
1424         //
1425         if ($return_array) {
1426                 // Just put all data in an array for later use
1427                 $OUT = array(
1428                         'YEARS'   => $Y,
1429                         'MONTHS'  => $M,
1430                         'WEEKS'   => $W,
1431                         'DAYS'    => $D,
1432                         'HOURS'   => $h,
1433                         'MINUTES' => $m,
1434                         'SECONDS' => $s
1435                 );
1436         } else {
1437                 // Generate table
1438                 $OUT  = "<div align=\"" . $align."\">\n";
1439                 $OUT .= "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\" class=\"timebox_table dashed\">\n";
1440                 $OUT .= "<tr>\n";
1441
1442                 if (ereg('Y', $display) || (empty($display))) {
1443                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_YEARS--}</strong></td>\n";
1444                 }
1445
1446                 if (ereg('M', $display) || (empty($display))) {
1447                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_MONTHS--}</strong></td>\n";
1448                 }
1449
1450                 if (ereg('W', $display) || (empty($display))) {
1451                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_WEEKS--}</strong></td>\n";
1452                 }
1453
1454                 if (ereg('D', $display) || (empty($display))) {
1455                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_DAYS--}</strong></td>\n";
1456                 }
1457
1458                 if (ereg('h', $display) || (empty($display))) {
1459                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_HOURS--}</strong></td>\n";
1460                 }
1461
1462                 if (ereg('m', $display) || (empty($display))) {
1463                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_MINUTES--}</strong></td>\n";
1464                 }
1465
1466                 if (ereg('s', $display) || (empty($display))) {
1467                         $OUT .= "  <td align=\"center\" class=\"timebox_column bottom\"><div class=\"tiny\">{--_SECONDS--}</strong></td>\n";
1468                 }
1469
1470                 $OUT .= "</tr>\n";
1471                 $OUT .= "<tr>\n";
1472
1473                 if (ereg('Y', $display) || (empty($display))) {
1474                         // Generate year selection
1475                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_ye\" size=\"1\">\n";
1476                         for ($idx = '0'; $idx <= 10; $idx++) {
1477                                 $OUT .= "    <option class=\"mini_select\" value=\"" . $idx."\"";
1478                                 if ($idx == $Y) $OUT .= ' selected="selected"';
1479                                 $OUT .= ">" . $idx."</option>\n";
1480                         }
1481                         $OUT .= "  </select></td>\n";
1482                 } else {
1483                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_ye\" value=\"0\" />\n";
1484                 }
1485
1486                 if (ereg('M', $display) || (empty($display))) {
1487                         // Generate month selection
1488                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_mo\" size=\"1\">\n";
1489                         for ($idx = '0'; $idx <= 11; $idx++)
1490                         {
1491                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1492                                 if ($idx == $M) $OUT .= ' selected="selected"';
1493                                 $OUT .= ">" . $idx."</option>\n";
1494                         }
1495                         $OUT .= "  </select></td>\n";
1496                 } else {
1497                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_mo\" value=\"0\" />\n";
1498                 }
1499
1500                 if (ereg('W', $display) || (empty($display))) {
1501                         // Generate week selection
1502                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_we\" size=\"1\">\n";
1503                         for ($idx = '0'; $idx <= 4; $idx++) {
1504                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1505                                 if ($idx == $W) $OUT .= ' selected="selected"';
1506                                 $OUT .= ">" . $idx."</option>\n";
1507                         }
1508                         $OUT .= "  </select></td>\n";
1509                 } else {
1510                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_we\" value=\"0\" />\n";
1511                 }
1512
1513                 if (ereg('D', $display) || (empty($display))) {
1514                         // Generate day selection
1515                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_da\" size=\"1\">\n";
1516                         for ($idx = '0'; $idx <= 31; $idx++) {
1517                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1518                                 if ($idx == $D) $OUT .= ' selected="selected"';
1519                                 $OUT .= ">" . $idx."</option>\n";
1520                         }
1521                         $OUT .= "  </select></td>\n";
1522                 } else {
1523                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_da\" value=\"0\" />\n";
1524                 }
1525
1526                 if (ereg('h', $display) || (empty($display))) {
1527                         // Generate hour selection
1528                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_ho\" size=\"1\">\n";
1529                         for ($idx = '0'; $idx <= 23; $idx++)    {
1530                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1531                                 if ($idx == $h) $OUT .= ' selected="selected"';
1532                                 $OUT .= ">" . $idx."</option>\n";
1533                         }
1534                         $OUT .= "  </select></td>\n";
1535                 } else {
1536                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_ho\" value=\"0\" />\n";
1537                 }
1538
1539                 if (ereg('m', $display) || (empty($display))) {
1540                         // Generate minute selection
1541                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_mi\" size=\"1\">\n";
1542                         for ($idx = '0'; $idx <= 59; $idx++) {
1543                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1544                                 if ($idx == $m) $OUT .= ' selected="selected"';
1545                                 $OUT .= ">" . $idx."</option>\n";
1546                         }
1547                         $OUT .= "  </select></td>\n";
1548                 } else {
1549                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_mi\" value=\"0\" />\n";
1550                 }
1551
1552                 if (ereg('s', $display) || (empty($display))) {
1553                         // Generate second selection
1554                         $OUT .= "  <td align=\"center\"><select class=\"mini_select\" name=\"" . $prefix."_se\" size=\"1\">\n";
1555                         for ($idx = '0'; $idx <= 59; $idx++) {
1556                                 $OUT .= "  <option class=\"mini_select\" value=\"" . $idx."\"";
1557                                 if ($idx == $s) $OUT .= ' selected="selected"';
1558                                 $OUT .= ">" . $idx."</option>\n";
1559                         }
1560                         $OUT .= "  </select></td>\n";
1561                 } else {
1562                         $OUT .= "<input type=\"hidden\" name=\"" . $prefix."_se\" value=\"0\" />\n";
1563                 }
1564                 $OUT .= "</tr>\n";
1565                 $OUT .= "</table>\n";
1566                 $OUT .= "</div>\n";
1567                 // Return generated HTML code
1568         }
1569         return $OUT;
1570 }
1571
1572 //
1573 function createTimestampFromSelections ($prefix, $postData) {
1574         // Initial return value
1575         $ret = '0';
1576
1577         // Do we have a leap year?
1578         $SWITCH = '0';
1579         $TEST = date('Y', time()) / 4;
1580         $M1   = date('m', time());
1581         // If so and if current time is before 02/29 and estimated time is after 02/29 then add 86400 seconds (one day)
1582         if ((floor($TEST) == $TEST) && ($M1 == "02") && ($postData[$prefix."_mo"] > "02"))  $SWITCH = getConfig('ONE_DAY');
1583         // First add years...
1584         $ret += $postData[$prefix."_ye"] * (31536000 + $SWITCH);
1585         // Next months...
1586         $ret += $postData[$prefix."_mo"] * 2628000;
1587         // Next weeks
1588         $ret += $postData[$prefix."_we"] * 604800;
1589         // Next days...
1590         $ret += $postData[$prefix."_da"] * 86400;
1591         // Next hours...
1592         $ret += $postData[$prefix."_ho"] * 3600;
1593         // Next minutes..
1594         $ret += $postData[$prefix."_mi"] * 60;
1595         // And at last seconds...
1596         $ret += $postData[$prefix."_se"];
1597         // Return calculated value
1598         return $ret;
1599 }
1600
1601 // Creates a 'fancy' human-readable timestamp from a Uni* stamp
1602 function createFancyTime ($stamp) {
1603         // Get data array with years/months/weeks/days/...
1604         $data = createTimeSelections($stamp, '', '', '', true);
1605         $ret = '';
1606         foreach($data as $k => $v) {
1607                 if ($v > 0) {
1608                         // Value is greater than 0 "eval" data to return string
1609                         eval("\$ret .= \", \".\$v.\" {--_".strtoupper($k)."--}\";");
1610                         break;
1611                 } // END - if
1612         } // END - foreach
1613
1614         // Do we have something there?
1615         if (strlen($ret) > 0) {
1616                 // Remove leading commata and space
1617                 $ret = substr($ret, 2);
1618         } else {
1619                 // Zero seconds
1620                 $ret = "0 {--_SECONDS--}";
1621         }
1622
1623         // Return fancy time string
1624         return $ret;
1625 }
1626
1627 // Generates a navigation row for listing emails
1628 function addEmailNavigation ($PAGES, $offset, $show_form, $colspan, $return=false) {
1629         $SEP = ''; $TOP = '';
1630         if ($show_form === false) {
1631                 $TOP = " top";
1632                 $SEP = "<tr><td colspan=\"" . $colspan."\" class=\"seperator\">&nbsp;</td></tr>";
1633         }
1634
1635         $NAV = '';
1636         for ($page = 1; $page <= $PAGES; $page++) {
1637                 // Is the page currently selected or shall we generate a link to it?
1638                 if (($page == getRequestElement('page')) || ((!isGetRequestElementSet('page')) && ($page == 1))) {
1639                         // Is currently selected, so only highlight it
1640                         $NAV .= '<strong>-';
1641                 } else {
1642                         // Open anchor tag and add base URL
1643                         $NAV .= '<a href="{%url=modules.php?module=admin&amp;what=' . getWhat() . '&amp;page=' . $page . '&amp;offset=' . $offset;
1644
1645                         // Add userid when we shall show all mails from a single member
1646                         if ((isGetRequestElementSet('userid')) && (bigintval(getRequestElement('userid')) > 0)) $NAV .= '&amp;userid=' . bigintval(getRequestElement('userid'));
1647
1648                         // Close open anchor tag
1649                         $NAV .= '%}">';
1650                 }
1651                 $NAV .= $page;
1652                 if (($page == getRequestElement('page')) || ((!isGetRequestElementSet('page')) && ($page == 1))) {
1653                         // Is currently selected, so only highlight it
1654                         $NAV .= '-</strong>';
1655                 } else {
1656                         // Close anchor tag
1657                         $NAV .= '</a>';
1658                 }
1659
1660                 // Add seperator if we have not yet reached total pages
1661                 if ($page < $PAGES) $NAV .= '&nbsp;|&nbsp;';
1662         } // END - for
1663
1664         // Define constants only once
1665         $content['nav']  = $NAV;
1666         $content['span'] = $colspan;
1667         $content['top']  = $TOP;
1668         $content['sep']  = $SEP;
1669
1670         // Load navigation template
1671         $OUT = loadTemplate('admin_email_nav_row', true, $content);
1672
1673         if ($return === true) {
1674                 // Return generated HTML-Code
1675                 return $OUT;
1676         } else {
1677                 // Output HTML-Code
1678                 outputHtml($OUT);
1679         }
1680 }
1681
1682 // Extract host from script name
1683 function extractHostnameFromUrl (&$script) {
1684         // Use default SERVER_URL by default... ;) So?
1685         $url = getConfig('SERVER_URL');
1686
1687         // Is this URL valid?
1688         if (substr($script, 0, 7) == 'http://') {
1689                 // Use the hostname from script URL as new hostname
1690                 $url = substr($script, 7);
1691                 $extract = explode('/', $url);
1692                 $url = $extract[0];
1693                 // Done extracting the URL :)
1694         } // END - if
1695
1696         // Extract host name
1697         $host = str_replace('http://', '', $url);
1698         if (ereg('/', $host)) $host = substr($host, 0, strpos($host, '/'));
1699
1700         // Generate relative URL
1701         //* DEBUG: */ print("SCRIPT=" . $script.'<br />');
1702         if (substr(strtolower($script), 0, 7) == 'http://') {
1703                 // But only if http:// is in front!
1704                 $script = substr($script, (strlen($url) + 7));
1705         } elseif (substr(strtolower($script), 0, 8) == 'https://') {
1706                 // Does this work?!
1707                 $script = substr($script, (strlen($url) + 8));
1708         }
1709
1710         //* DEBUG: */ print("SCRIPT=" . $script.'<br />');
1711         if (substr($script, 0, 1) == '/') $script = substr($script, 1);
1712
1713         // Return host name
1714         return $host;
1715 }
1716
1717 // Send a GET request
1718 function sendGetRequest ($script, $data = array()) {
1719         // Extract host name from script
1720         $host = extractHostnameFromUrl($script);
1721
1722         // Add data
1723         $scriptData = http_build_query($data, '', '&');
1724
1725         // Do we have a question-mark in the script?
1726         if (strpos($script, '?') === false) {
1727                 // No, so first char must be question mark
1728                 $scriptData = '?' . $scriptData;
1729         } else {
1730                 // Ok, add &
1731                 $scriptData = '&' . $scriptData;
1732         }
1733
1734         // Add script data
1735         $script .= $scriptData;
1736
1737         // Generate GET request header
1738         $request  = 'GET /' . trim($script) . ' HTTP/1.1' . getConfig('HTTP_EOL');
1739         $request .= 'Host: ' . $host . getConfig('HTTP_EOL');
1740         $request .= 'Referer: ' . getConfig('URL') . '/admin.php' . getConfig('HTTP_EOL');
1741         if (isConfigEntrySet('FULL_VERSION')) {
1742                 $request .= 'User-Agent: ' . getConfig('TITLE') . '/' . getConfig('FULL_VERSION') . getConfig('HTTP_EOL');
1743         } else {
1744                 $request .= 'User-Agent: ' . getConfig('TITLE') . '/' . getConfig('VERSION') . getConfig('HTTP_EOL');
1745         }
1746         $request .= 'Content-Type: text/plain' . getConfig('HTTP_EOL');
1747         $request .= 'Cache-Control: no-cache' . getConfig('HTTP_EOL');
1748         $request .= 'Connection: Close' . getConfig('HTTP_EOL') . getConfig('HTTP_EOL');
1749
1750         // Send the raw request
1751         $response = sendRawRequest($host, $request);
1752
1753         // Return the result to the caller function
1754         return $response;
1755 }
1756
1757 // Send a POST request
1758 function sendPostRequest ($script, $postData) {
1759         // Is postData an array?
1760         if (!is_array($postData)) {
1761                 // Abort here
1762                 logDebugMessage(__FUNCTION__, __LINE__, sprintf("postData is not an array. Type: %s", gettype($postData)));
1763                 return array('', '', '');
1764         } // END - if
1765
1766         // Extract host name from script
1767         $host = extractHostnameFromUrl($script);
1768
1769         // Construct request
1770         $data = http_build_query($postData, '', '&');
1771
1772         // Generate POST request header
1773         $request  = 'POST /' . trim($script) . ' HTTP/1.1' . getConfig('HTTP_EOL');
1774         $request .= 'Host: ' . $host . getConfig('HTTP_EOL');
1775         $request .= 'Referer: ' . getConfig('URL') . '/admin.php' . getConfig('HTTP_EOL');
1776         $request .= 'User-Agent: ' . getConfig('TITLE') . '/' . getConfig('FULL_VERSION') . getConfig('HTTP_EOL');
1777         $request .= 'Content-Type: application/x-www-form-urlencoded' . getConfig('HTTP_EOL');
1778         $request .= 'Content-length: ' . strlen($data) . getConfig('HTTP_EOL');
1779         $request .= 'Cache-Control: no-cache' . getConfig('HTTP_EOL');
1780         $request .= 'Connection: Close' . getConfig('HTTP_EOL') . getConfig('HTTP_EOL');
1781         $request .= $data;
1782
1783         // Send the raw request
1784         $response = sendRawRequest($host, $request);
1785
1786         // Return the result to the caller function
1787         return $response;
1788 }
1789
1790 // Sends a raw request to another host
1791 function sendRawRequest ($host, $request) {
1792         // Init errno and errdesc with 'all fine' values
1793         $errno = '0'; $errdesc = '';
1794
1795         // Initialize array
1796         $response = array('', '', '');
1797
1798         // Default is not to use proxy
1799         $useProxy = false;
1800
1801         // Are proxy settins set?
1802         if ((isConfigEntrySet('proxy_host')) && (getConfig('proxy_host') != '') && (isConfigEntrySet('proxy_port')) && (getConfig('proxy_port') > 0)) {
1803                 // Then use it
1804                 $useProxy = true;
1805         } // END - if
1806
1807         // Open connection
1808         //* DEBUG: */ die("SCRIPT=" . $script.'<br />');
1809         if ($useProxy === true) {
1810                 // Connect to host through proxy connection
1811                 $fp = @fsockopen(compileRawCode(getConfig('proxy_host')), bigintval(getConfig('proxy_port')), $errno, $errdesc, 30);
1812         } else {
1813                 // Connect to host directly
1814                 $fp = @fsockopen($host, 80, $errno, $errdesc, 30);
1815         }
1816
1817         // Is there a link?
1818         if (!is_resource($fp)) {
1819                 // Failed!
1820                 return $response;
1821         } // END - if
1822
1823         // Do we use proxy?
1824         if ($useProxy === true) {
1825                 // Generate CONNECT request header
1826                 $proxyTunnel  = "CONNECT " . $host . ":80 HTTP/1.1" . getConfig('HTTP_EOL');
1827                 $proxyTunnel .= "Host: " . $host . getConfig('HTTP_EOL');
1828
1829                 // Use login data to proxy? (username at least!)
1830                 if (getConfig('proxy_username') != '') {
1831                         // Add it as well
1832                         $encodedAuth = base64_encode(compileRawCode(getConfig('proxy_username')) . getConfig('ENCRYPT_SEPERATOR') . compileRawCode(getConfig('proxy_password')));
1833                         $proxyTunnel .= "Proxy-Authorization: Basic " . $encodedAuth . getConfig('HTTP_EOL');
1834                 } // END - if
1835
1836                 // Add last new-line
1837                 $proxyTunnel .= getConfig('HTTP_EOL');
1838                 //* DEBUG: */ print("<strong>proxyTunnel=</strong><pre>" . $proxyTunnel."</pre>");
1839
1840                 // Write request
1841                 fputs($fp, $proxyTunnel);
1842
1843                 // Got response?
1844                 if (feof($fp)) {
1845                         // No response received
1846                         return $response;
1847                 } // END - if
1848
1849                 // Read the first line
1850                 $resp = trim(fgets($fp, 10240));
1851                 $respArray = explode(' ', $resp);
1852                 if ((strtolower($respArray[0]) !== 'http/1.0') || ($respArray[1] != '200')) {
1853                         // Invalid response!
1854                         return $response;
1855                 } // END - if
1856         } // END - if
1857
1858         // Write request
1859         fputs($fp, $request);
1860
1861         // Read response
1862         while (!feof($fp)) {
1863                 $response[] = trim(fgets($fp, 1024));
1864         } // END - while
1865
1866         // Close socket
1867         fclose($fp);
1868
1869         // Skip first empty lines
1870         $resp = $response;
1871         foreach ($resp as $idx => $line) {
1872                 // Trim space away
1873                 $line = trim($line);
1874
1875                 // Is this line empty?
1876                 if (empty($line)) {
1877                         // Then remove it
1878                         array_shift($response);
1879                 } else {
1880                         // Abort on first non-empty line
1881                         break;
1882                 }
1883         } // END - foreach
1884
1885         //* DEBUG: */ print("<strong>Response:</strong><pre>".print_r($response, true)."</pre>");
1886
1887         // Proxy agent found?
1888         if ((substr(strtolower($response[0]), 0, 11) == 'proxy-agent') && ($useProxy === true)) {
1889                 // Proxy header detected, so remove two lines
1890                 array_shift($response);
1891                 array_shift($response);
1892         } // END - if
1893
1894         // Was the request successfull?
1895         if ((!eregi('200 OK', $response[0])) || (empty($response[0]))) {
1896                 // Not found / access forbidden
1897                 $response = array('', '', '');
1898         } // END - if
1899
1900         // Return response
1901         return $response;
1902 }
1903
1904 // Taken from www.php.net eregi() user comments
1905 function isEmailValid ($email) {
1906         // Check first part of email address
1907         $first = '[-a-z0-9!#$%&\'*+/=?^_<{|}~]+(\.[-a-zA-Z0-9!#$%&\'*+/=?^_<{|}~]+)*';
1908
1909         //  Check domain
1910         $domain = '[a-z0-9-]+(\.[a-z0-9-]{2,5})+';
1911
1912         // Generate pattern
1913         $regex = '@^' . $first . '\@' . $domain . '$@iU';
1914
1915         // Return check result
1916         return preg_match($regex, $email);
1917 }
1918
1919 // Function taken from user comments on www.php.net / function eregi()
1920 function isUrlValid ($URL, $compile=true) {
1921         // Trim URL a little
1922         $URL = trim(urldecode($URL));
1923         //* DEBUG: */ outputHtml($URL.'<br />');
1924
1925         // Compile some chars out...
1926         if ($compile === true) $URL = compileUriCode($URL, false, false, false);
1927         //* DEBUG: */ outputHtml($URL.'<br />');
1928
1929         // Check for the extension filter
1930         if (isExtensionActive('filter')) {
1931                 // Use the extension's filter set
1932                 return FILTER_VALIDATE_URL($URL, false);
1933         } // END - if
1934
1935         // If not installed, perform a simple test. Just make it sure there is always a http:// or
1936         // https:// in front of the URLs
1937         return isUrlValidSimple($URL);
1938 }
1939
1940 // Generate a list of administrative links to a given userid
1941 function generateMemberAdminActionLinks ($userid, $status = '') {
1942         // Make sure userid is a number
1943         if ($userid != bigintval($userid)) debug_report_bug('userid is not a number!');
1944
1945         // Define all main targets
1946         $targetArray = array('del_user', 'edit_user', 'lock_user', 'add_points', 'sub_points');
1947
1948         // Begin of navigation links
1949         $OUT = "[&nbsp;";
1950
1951         foreach ($targetArray as $tar) {
1952                 $OUT .= "<span class=\"admin_user_link\"><a href=\"{%url=modules.php?module=admin&amp;what=" . $tar . "&amp;userid=" . $userid . "%}\" title=\"{--ADMIN_LINK_";
1953                 //* DEBUG: */ outputHtml("*" . $tar.'/' . $status."*<br />");
1954                 if (($tar == 'lock_user') && ($status == 'LOCKED')) {
1955                         // Locked accounts shall be unlocked
1956                         $OUT .= 'UNLOCK_USER';
1957                 } else {
1958                         // All other status is fine
1959                         $OUT .= strtoupper($tar);
1960                 }
1961                 $OUT .= "_TITLE--}\">{--ADMIN_";
1962                 if (($tar == 'lock_user') && ($status == 'LOCKED')) {
1963                         // Locked accounts shall be unlocked
1964                         $OUT .= 'UNLOCK_USER';
1965                 } else {
1966                         // All other status is fine
1967                         $OUT .= strtoupper($tar);
1968                 }
1969                 $OUT .= "--}</a></span>&nbsp;|&nbsp;";
1970         }
1971
1972         // Finish navigation link
1973         $OUT = substr($OUT, 0, -7) . ']';
1974
1975         // Return string
1976         return $OUT;
1977 }
1978
1979 // Generate an email link
1980 function generateEmailLink ($email, $table = 'admins') {
1981         // Default email link (INSECURE! Spammer can read this by harvester programs)
1982         $EMAIL = 'mailto:' . $email;
1983
1984         // Check for several extensions
1985         if ((isExtensionActive('admins')) && ($table == 'admins')) {
1986                 // Create email link for contacting admin in guest area
1987                 $EMAIL = generateAdminEmailLink($email);
1988         } elseif ((isExtensionActive('user')) && (getExtensionVersion('user') >= '0.3.3') && ($table == 'user_data')) {
1989                 // Create email link for contacting a member within admin area (or later in other areas, too?)
1990                 $EMAIL = generateUserEmailLink($email, 'admin');
1991         } elseif ((isExtensionActive('sponsor')) && ($table == 'sponsor_data')) {
1992                 // Create email link to contact sponsor within admin area (or like the link above?)
1993                 $EMAIL = generateSponsorEmailLink($email, 'sponsor_data');
1994         }
1995
1996         // Shall I close the link when there is no admin?
1997         if ((!isAdmin()) && ($EMAIL == $email)) $EMAIL = '#'; // Closed!
1998
1999         // Return email link
2000         return $EMAIL;
2001 }
2002
2003 // Generate a hash for extra-security for all passwords
2004 function generateHash ($plainText, $salt = '') {
2005         // Is the required extension 'sql_patches' there and a salt is not given?
2006         if (((isExtensionInstalledAndOlder('sql_patches', '0.3.6')) || (!isExtensionActive('sql_patches')) || (!isExtensionInstalledAndNewer('other', '0.2.5'))) && (empty($salt))) {
2007                 // Extension sql_patches is missing/outdated so we hash the plain text with MD5
2008                 return md5($plainText);
2009         } // END - if
2010
2011         // Do we miss an arry element here?
2012         if (!isConfigEntrySet('file_hash')) {
2013                 // Stop here
2014                 debug_report_bug('Missing file_hash in ' . __FUNCTION__ . '.');
2015         } // END - if
2016
2017         // When the salt is empty build a new one, else use the first x configured characters as the salt
2018         if (empty($salt)) {
2019                 // Build server string (inc/databases.php is no longer updated with every commit)
2020                 $server = $_SERVER['PHP_SELF'] . getConfig('ENCRYPT_SEPERATOR') . detectUserAgent() . getConfig('ENCRYPT_SEPERATOR') . getenv('SERVER_SOFTWARE') . getConfig('ENCRYPT_SEPERATOR') . detectRemoteAddr();
2021
2022                 // Build key string
2023                 $keys   = getConfig('SITE_KEY') . getConfig('ENCRYPT_SEPERATOR') . getConfig('DATE_KEY') . getConfig('ENCRYPT_SEPERATOR') . getConfig('secret_key') . getConfig('ENCRYPT_SEPERATOR') . getConfig('file_hash') . getConfig('ENCRYPT_SEPERATOR') . date('d-m-Y (l-F-T)', getConfig('patch_ctime')) . getConfig('ENCRYPT_SEPERATOR') . getConfig('master_salt');
2024
2025                 // Additional data
2026                 $data = $plainText . getConfig('ENCRYPT_SEPERATOR') . uniqid(mt_rand(), true) . getConfig('ENCRYPT_SEPERATOR') . time();
2027
2028                 // Calculate number for generating the code
2029                 $a = time() + getConfig('_ADD') - 1;
2030
2031                 // Generate SHA1 sum from modula of number and the prime number
2032                 $sha1 = sha1(($a % getConfig('_PRIME')) . $server . getConfig('ENCRYPT_SEPERATOR') . $keys . getConfig('ENCRYPT_SEPERATOR') . $data . getConfig('ENCRYPT_SEPERATOR') . getConfig('DATE_KEY') . getConfig('ENCRYPT_SEPERATOR') . $a);
2033                 //* DEBUG: */ outputHtml("SHA1=" . $sha1." (".strlen($sha1).")<br />");
2034                 $sha1 = scrambleString($sha1);
2035                 //* DEBUG: */ outputHtml("Scrambled=" . $sha1." (".strlen($sha1).")<br />");
2036                 //* DEBUG: */ $sha1b = descrambleString($sha1);
2037                 //* DEBUG: */ outputHtml("Descrambled=" . $sha1b." (".strlen($sha1b).")<br />");
2038
2039                 // Generate the password salt string
2040                 $salt = substr($sha1, 0, getConfig('salt_length'));
2041                 //* DEBUG: */ outputHtml($salt." (".strlen($salt).")<br />");
2042         } else {
2043                 // Use given salt
2044                 //* DEBUG: */ print 'salt=' . $salt . '<br />';
2045                 $salt = substr($salt, 0, getConfig('salt_length'));
2046                 //* DEBUG: */ print 'salt=' . $salt . '(' . strlen($salt) . '/' . getConfig('salt_length') . ')<br />';
2047
2048                 // Sanity check on salt
2049                 if (strlen($salt) != getConfig('salt_length')) {
2050                         // Not the same!
2051                         debug_report_bug(__FUNCTION__.': salt length mismatch! ('.strlen($salt).'/'.getConfig('salt_length').')');
2052                 } // END - if
2053         }
2054
2055         // Return hash
2056         return $salt.sha1($salt . $plainText);
2057 }
2058
2059 // Scramble a string
2060 function scrambleString($str) {
2061         // Init
2062         $scrambled = '';
2063
2064         // Final check, in case of failture it will return unscrambled string
2065         if (strlen($str) > 40) {
2066                 // The string is to long
2067                 return $str;
2068         } elseif (strlen($str) == 40) {
2069                 // From database
2070                 $scrambleNums = explode(':', getConfig('pass_scramble'));
2071         } else {
2072                 // Generate new numbers
2073                 $scrambleNums = explode(':', genScrambleString(strlen($str)));
2074         }
2075
2076         // Scramble string here
2077         //* DEBUG: */ outputHtml("***Original=" . $str."***<br />");
2078         for ($idx = '0'; $idx < strlen($str); $idx++) {
2079                 // Get char on scrambled position
2080                 $char = substr($str, $scrambleNums[$idx], 1);
2081
2082                 // Add it to final output string
2083                 $scrambled .= $char;
2084         } // END - for
2085
2086         // Return scrambled string
2087         //* DEBUG: */ outputHtml("***Scrambled=" . $scrambled."***<br />");
2088         return $scrambled;
2089 }
2090
2091 // De-scramble a string scrambled by scrambleString()
2092 function descrambleString($str) {
2093         // Scramble only 40 chars long strings
2094         if (strlen($str) != 40) return $str;
2095
2096         // Load numbers from config
2097         $scrambleNums = explode(':', getConfig('pass_scramble'));
2098
2099         // Validate numbers
2100         if (count($scrambleNums) != 40) return $str;
2101
2102         // Begin descrambling
2103         $orig = str_repeat(' ', 40);
2104         //* DEBUG: */ outputHtml("+++Scrambled=" . $str."+++<br />");
2105         for ($idx = '0'; $idx < 40; $idx++) {
2106                 $char = substr($str, $idx, 1);
2107                 $orig = substr_replace($orig, $char, $scrambleNums[$idx], 1);
2108         } // END - for
2109
2110         // Return scrambled string
2111         //* DEBUG: */ outputHtml("+++Original=" . $orig."+++<br />");
2112         return $orig;
2113 }
2114
2115 // Generated a "string" for scrambling
2116 function genScrambleString ($len) {
2117         // Prepare array for the numbers
2118         $scrambleNumbers = array();
2119
2120         // First we need to setup randomized numbers from 0 to 31
2121         for ($idx = '0'; $idx < $len; $idx++) {
2122                 // Generate number
2123                 $rand = mt_rand(0, ($len -1));
2124
2125                 // Check for it by creating more numbers
2126                 while (array_key_exists($rand, $scrambleNumbers)) {
2127                         $rand = mt_rand(0, ($len -1));
2128                 } // END - while
2129
2130                 // Add number
2131                 $scrambleNumbers[$rand] = $rand;
2132         } // END - for
2133
2134         // So let's create the string for storing it in database
2135         $scrambleString = implode(':', $scrambleNumbers);
2136         return $scrambleString;
2137 }
2138
2139 // Generate an PGP-like encrypted hash of given hash for e.g. cookies
2140 function generatePassString ($passHash) {
2141         // Return vanilla password hash
2142         $ret = $passHash;
2143
2144         // Is a secret key and master salt already initialized?
2145         if ((isExtensionInstalled('sql_patches')) && (isExtensionInstalledAndNewer('other', '0.2.5')) && (isConfigEntrySet('_PRIME')) && (isConfigEntrySet('secret_key')) && (isConfigEntrySet('master_salt'))) {
2146                 // Only calculate when the secret key is generated
2147                 $newHash = ''; $start = 9;
2148                 for ($idx = '0'; $idx < 10; $idx++) {
2149                         $part1 = hexdec(substr($passHash, $start, 4));
2150                         $part2 = hexdec(substr(getConfig('secret_key'), $start, 4));
2151                         $mod = dechex($idx);
2152                         if ($part1 > $part2) {
2153                                 $mod = dechex(sqrt(($part1 - $part2) * getConfig('_PRIME') / pi()));
2154                         } elseif ($part2 > $part1) {
2155                                 $mod = dechex(sqrt(($part2 - $part1) * getConfig('_PRIME') / pi()));
2156                         }
2157                         $mod = substr($mod, 0, 4);
2158                         //* DEBUG: */ outputHtml('part1='.$part1.'/part2='.$part2.'/mod=' . $mod . '('.strlen($mod).')<br />');
2159                         $mod = str_repeat(0, (4 - strlen($mod))) . $mod;
2160                         //* DEBUG: */ outputHtml('*' . $start . '=' . $mod . '*<br />');
2161                         $start += 4;
2162                         $newHash .= $mod;
2163                 } // END - for
2164
2165                 //* DEBUG: */ print($passHash.'<br />' . $newHash." (".strlen($newHash).')<br />');
2166                 $ret = generateHash($newHash, getConfig('master_salt'));
2167                 //* DEBUG: */ print('ret='.$ret.'<br />');
2168         } else {
2169                 // Hash it simple
2170                 //* DEBUG: */ outputHtml("--" . $passHash."--<br />");
2171                 $ret = md5($passHash);
2172                 //* DEBUG: */ outputHtml("++" . $ret."++<br />");
2173         }
2174
2175         // Return result
2176         return $ret;
2177 }
2178
2179 // Fix "deleted" cookies
2180 function fixDeletedCookies ($cookies) {
2181         // Is this an array with entries?
2182         if ((is_array($cookies)) && (count($cookies) > 0)) {
2183                 // Then check all cookies if they are marked as deleted!
2184                 foreach ($cookies as $cookieName) {
2185                         // Is the cookie set to "deleted"?
2186                         if (getSession($cookieName) == 'deleted') {
2187                                 setSession($cookieName, '');
2188                         } // END - if
2189                 } // END - foreach
2190         } // END - if
2191 }
2192
2193 // Output error messages in a fasioned way and die...
2194 function app_die ($F, $L, $message) {
2195         // Check if Script is already dieing and not let it kill itself another 1000 times
2196         if (!isset($GLOBALS['app_died'])) {
2197                 // Make sure, that the script realy realy diese here and now
2198                 $GLOBALS['app_died'] = true;
2199
2200                 // Load header
2201                 loadIncludeOnce('inc/header.php');
2202
2203                 // Rewrite message for output
2204                 $message = sprintf(getMessage('MXCHANGE_HAS_DIED'), basename($F), $L, $message);
2205
2206                 // Better log this message away
2207                 logDebugMessage($F, $L, $message);
2208
2209                 // Load the message template
2210                 loadTemplate('admin_settings_saved', false, $message);
2211
2212                 // Load footer
2213                 loadIncludeOnce('inc/footer.php');
2214         } else {
2215                 // Script tried to kill itself twice
2216                 debug_report_bug('Script wanted to kill itself more than once! Raw message=' . $message . ', file/function=' . $F . ', line=' . $L);
2217         }
2218 }
2219
2220 // Display parsing time and number of SQL queries in footer
2221 function displayParsingTime() {
2222         // Is the timer started?
2223         if (!isset($GLOBALS['startTime'])) {
2224                 // Abort here
2225                 return false;
2226         } // END - if
2227
2228         // Get end time
2229         $endTime = microtime(true);
2230
2231         // "Explode" both times
2232         $start = explode(' ', $GLOBALS['startTime']);
2233         $end = explode(' ', $endTime);
2234         $runTime = $end[0] - $start[0];
2235         if ($runTime < 0) $runTime = '0';
2236
2237         // Prepare output
2238         $content = array(
2239                 'runtime'  => translateComma($runTime),
2240                 'timeSQLs' => translateComma(getConfig('sql_time') * 1000),
2241         );
2242
2243         // Load the template
2244         loadTemplate('show_timings', false, $content);
2245 }
2246
2247 // Check wether a boolean constant is set
2248 // Taken from user comments in PHP documentation for function constant()
2249 function isBooleanConstantAndTrue ($constName) { // : Boolean
2250         // Failed by default
2251         $res = false;
2252
2253         // In cache?
2254         if (isset($GLOBALS['cache_array']['const'][$constName])) {
2255                 // Use cache
2256                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>): " . $constName."-CACHE!<br />");
2257                 $res = ($GLOBALS['cache_array']['const'][$constName] === true);
2258         } else {
2259                 // Check constant
2260                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>): " . $constName."-RESOLVE!<br />");
2261                 if (defined($constName)) {
2262                         // Found!
2263                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>): " . $constName."-FOUND!<br />");
2264                         $res = (constant($constName) === true);
2265                 } // END - if
2266
2267                 // Set cache
2268                 $GLOBALS['cache_array']['const'][$constName] = $res;
2269         }
2270         //* DEBUG: */ var_dump($res);
2271
2272         // Return value
2273         return $res;
2274 }
2275
2276 // Checks if a given apache module is loaded
2277 function isApacheModuleLoaded ($apacheModule) {
2278         // Check it and return result
2279         return (((function_exists('apache_get_modules')) && (in_array($apacheModule, apache_get_modules()))) || (!function_exists('apache_get_modules')));
2280 }
2281
2282 // Get current theme name
2283 function getCurrentTheme () {
2284         // The default theme is 'default'... ;-)
2285         $ret = 'default';
2286
2287         // Do we have ext-theme installed and active?
2288         if (isExtensionActive('theme')) {
2289                 // Call inner method
2290                 $ret = getActualTheme();
2291         } // END - if
2292
2293         // Return theme value
2294         return $ret;
2295 }
2296
2297 // Generates an error code from given account status
2298 function generateErrorCodeFromUserStatus ($status='') {
2299         // If no status is provided, use the default, cached
2300         if ((empty($status)) && (isMember())) {
2301                 // Get user status
2302                 $status = getUserData('status');
2303         } // END - if
2304
2305         // Default error code if unknown account status
2306         $errorCode = getCode('UNKNOWN_STATUS');
2307
2308         // Generate constant name
2309         $codeName = sprintf("ID_%s", $status);
2310
2311         // Is the constant there?
2312         if (isCodeSet($codeName)) {
2313                 // Then get it!
2314                 $errorCode = getCode($codeName);
2315         } else {
2316                 // Unknown status
2317                 logDebugMessage(__FUNCTION__, __LINE__, sprintf("Unknown error status %s detected.", $status));
2318         }
2319
2320         // Return error code
2321         return $errorCode;
2322 }
2323
2324 // Function to search for the last modifified file
2325 function searchDirsRecursive ($dir, &$last_changed) {
2326         // Get dir as array
2327         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):dir=" . $dir.'<br />');
2328         // Does it match what we are looking for? (We skip a lot files already!)
2329         // RegexPattern to exclude  ., .., .revision,  .svn, debug.log or .cache in the filenames
2330         $excludePattern = '@(\.revision|debug\.log|\.cache|config\.php)$@';
2331         $ds = getArrayFromDirectory($dir, '', true, false, array(), '.php', $excludePattern);
2332         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):ds[]=".count($ds).'<br />');
2333
2334         // Walk through all entries
2335         foreach ($ds as $d) {
2336                 // Generate proper FQFN
2337                 $FQFN = str_replace('//', '/', getConfig('PATH') . $dir. '/'. $d);
2338
2339                 // Is it a file and readable?
2340                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):FQFN={$FQFN}<br />");
2341                 if (isDirectory($FQFN)) {
2342                         // $FQFN is a directory so also crawl into this directory
2343                         $newDir = $d;
2344                         if (!empty($dir)) $newDir = $dir . '/'. $d;
2345                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):DESCENT: " . $newDir.'<br />');
2346                         searchDirsRecursive($newDir, $last_changed);
2347                 } elseif (isFileReadable($FQFN)) {
2348                         // $FQFN is a filename and no directory
2349                         $time = filemtime($FQFN);
2350                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):File: " . $d." found. (".($last_changed['time'] - $time).")<br />");
2351                         if ($last_changed['time'] < $time) {
2352                                 // This file is newer as the file before
2353                                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>) - NEWER!<br />");
2354                                 $last_changed['path_name'] = $FQFN;
2355                                 $last_changed['time'] = $time;
2356                         } // END - if
2357                 }
2358         } // END - foreach
2359 }
2360
2361 // "Getter" for revision/version data
2362 function getActualVersion ($type = 'Revision') {
2363         // By default nothing is new... ;-)
2364         $new = false;
2365
2366         // Is the cache entry there?
2367         if (isset($GLOBALS['cache_array']['revision'][$type])) {
2368                 // Found so increase cache hit
2369                 incrementStatsEntry('cache_hits');
2370
2371                 // Return it
2372                 return $GLOBALS['cache_array']['revision'][$type][0];
2373         } else {
2374                 // FQFN of revision file
2375                 $FQFN = sprintf("%s/.revision", getConfig('CACHE_PATH'));
2376
2377                 // Check if 'check_revision_data' is setted (switch for manually rewrite the .revision-File)
2378                 if ((isGetRequestElementSet('check_revision_data')) && (getRequestElement('check_revision_data') == 'yes')) {
2379                         // Forced rebuild of .revision file
2380                         $new = true;
2381                 } else {
2382                         // Check for revision file
2383                         if (!isFileReadable($FQFN)) {
2384                                 // Not found, so we need to create it
2385                                 $new = true;
2386                         } else {
2387                                 // Revision file found
2388                                 $ins_vers = explode("\n", readFromFile($FQFN));
2389
2390                                 // Get array for mapping information
2391                                 $mapper = array_flip(getSearchFor());
2392                                 //* DEBUG: */ print('<pre>mapper='.print_r($mapper, true).'</pre>ins_vers=<pre>'.print_r($ins_vers, true).'</pre>');
2393
2394                                 // Is the content valid?
2395                                 if ((!is_array($ins_vers)) || (count($ins_vers) <= 0) || (!isset($ins_vers[$mapper[$type]])) || (trim($ins_vers[$mapper[$type]]) == '') || ($ins_vers[0]) == 'new') {
2396                                         // File needs update!
2397                                         $new = true;
2398                                 } else {
2399                                         // Generate fake cache entry
2400                                         foreach ($mapper as $map => $idx) {
2401                                                 $GLOBALS['cache_array']['revision'][$map][0] = $ins_vers[$idx];
2402                                         } // END - foreach
2403
2404                                         // Return found value
2405                                         return trim($ins_vers[$mapper[$type]]);
2406                                 }
2407                         }
2408                 }
2409
2410                 // Has it been updated?
2411                 if ($new === true)  {
2412                         // Write it
2413                         writeToFile($FQFN, implode("\n", getArrayFromActualVersion()));
2414
2415                         // ... and call recursive
2416                         return getActualVersion($type);
2417                 } // END - if
2418         }
2419 }
2420
2421 // Repares an array we are looking for
2422 // The returned Array is needed twice (in getArrayFromActualVersion() and in getActualVersion() in the old .revision-fallback) so I puted it in an extra function to not polute the global namespace
2423 function getSearchFor () {
2424         // Add Revision, Date, Tag and Author
2425         $searchFor = array('Revision', 'Date', 'Tag', 'Author', 'File');
2426
2427         // Return the created array
2428         return $searchFor;
2429 }
2430
2431 // @TODO Please describe this function
2432 function getArrayFromActualVersion () {
2433         // Init variables
2434         $next_dir = '';
2435
2436         // Directory to start with search
2437         $last_changed = array(
2438                 'path_name' => '',
2439                 'time'      => 0
2440         );
2441
2442         // Init return array
2443         $akt_vers = array();
2444
2445         // Init value for counting the founded keywords
2446         $res = '0';
2447
2448         // Searches all Files and there date of the last modifikation and puts the newest File in $last_changed.
2449         searchDirsRecursive($next_dir, $last_changed); // @TODO small change to API to $last_changed = searchDirsRecursive($next_dir, $time);
2450
2451         // Get file
2452         $last_file = readFromFile($last_changed['path_name']);
2453
2454         // Get all the keywords to search for
2455         $searchFor = getSearchFor();
2456
2457         // This foreach loops the $searchFor-Tags (array('Revision', 'Date', 'Tag', 'Author') --> could easaly extended in the future)
2458         foreach ($searchFor as $search) {
2459                 // Searches for "$search-tag:VALUE$" or "$search-tag::VALUE$"(the stylish keywordversion ;-)) in the lates modified file
2460                 $res += preg_match('@\$' . $search.'(:|::) (.*) \$@U', $last_file, $t);
2461                 // This trimms the search-result and puts it in the $GLOBALS['cache_array']['revision']-return array
2462                 if (isset($t[2])) $GLOBALS['cache_array']['revision'][$search] = trim($t[2]);
2463         } // END - foreach
2464
2465         // Save the last-changed filename for debugging
2466         $GLOBALS['cache_array']['revision']['File'] = $last_changed['path_name'];
2467
2468         // at least 3 keyword-Tags are needed for propper values
2469         if ($res && $res >= 3
2470         && isset($GLOBALS['cache_array']['revision']['Revision']) && $GLOBALS['cache_array']['revision']['Revision'] != ''
2471         && isset($GLOBALS['cache_array']['revision']['Date']) && $GLOBALS['cache_array']['revision']['Date'] != ''
2472         && isset($GLOBALS['cache_array']['revision']['Tag']) && $GLOBALS['cache_array']['revision']['Tag'] != '') {
2473                 // Prepare content witch need special treadment
2474
2475                 // Prepare timestamp for date
2476                 preg_match('@(....)-(..)-(..) (..):(..):(..)@', $GLOBALS['cache_array']['revision']['Date'], $match_d);
2477                 $GLOBALS['cache_array']['revision']['Date'] = mktime($match_d[4], $match_d[5], $match_d[6], $match_d[2], $match_d[3], $match_d[1]);
2478
2479                 // Add author to the Tag if the author is set and is not quix0r (lead coder)
2480                 if ((isset($GLOBALS['cache_array']['revision']['Author'])) && ($GLOBALS['cache_array']['revision']['Author'] != 'quix0r')) {
2481                         $GLOBALS['cache_array']['revision']['Tag'] .= '-'.strtoupper($GLOBALS['cache_array']['revision']['Author']);
2482                 } // END - if
2483
2484         } else {
2485                 // No valid Data from the last modificated file so read the Revision from the Server. Fallback-solution!! Should not be removed I think.
2486                 $version = sendGetRequest('check-updates3.php');
2487
2488                 // Prepare content
2489                 // Only sets not setted or not proper values to the Online-Server-Fallback-Solution
2490                 if (!isset($GLOBALS['cache_array']['revision']['Revision']) || $GLOBALS['cache_array']['revision']['Revision'] == '') $GLOBALS['cache_array']['revision']['Revision'] = trim($version[10]);
2491                 if (!isset($GLOBALS['cache_array']['revision']['Date'])     || $GLOBALS['cache_array']['revision']['Date']     == '') $GLOBALS['cache_array']['revision']['Date']     = trim($version[9]);
2492                 if (!isset($GLOBALS['cache_array']['revision']['Tag'])      || $GLOBALS['cache_array']['revision']['Tag']      == '') $GLOBALS['cache_array']['revision']['Tag']      = trim($version[8]);
2493                 if (!isset($GLOBALS['cache_array']['revision']['Author'])   || $GLOBALS['cache_array']['revision']['Author']   == '') $GLOBALS['cache_array']['revision']['Author']   = 'quix0r';
2494                 if (!isset($GLOBALS['cache_array']['revision']['File'])     || $GLOBALS['cache_array']['revision']['File']     == '') $GLOBALS['cache_array']['revision']['File']     = trim($version[11]);
2495         }
2496
2497         // Return prepared array
2498         return $GLOBALS['cache_array']['revision'];
2499 }
2500
2501 // Back-ported from the new ship-simu engine. :-)
2502 function debug_get_printable_backtrace () {
2503         // Init variable
2504         $backtrace = "<ol>\n";
2505
2506         // Get and prepare backtrace for output
2507         $backtraceArray = debug_backtrace();
2508         foreach ($backtraceArray as $key => $trace) {
2509                 if (!isset($trace['file'])) $trace['file'] = __FUNCTION__;
2510                 if (!isset($trace['line'])) $trace['line'] = __LINE__;
2511                 if (!isset($trace['args'])) $trace['args'] = array();
2512                 $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>\n";
2513         } // END - foreach
2514
2515         // Close it
2516         $backtrace .= "</ol>\n";
2517
2518         // Return the backtrace
2519         return $backtrace;
2520 }
2521
2522 // A mail-able backtrace
2523 function debug_get_mailable_backtrace () {
2524         // Init variable
2525         $backtrace = '';
2526
2527         // Get and prepare backtrace for output
2528         $backtraceArray = debug_backtrace();
2529         foreach ($backtraceArray as $key => $trace) {
2530                 if (!isset($trace['file'])) $trace['file'] = __FUNCTION__;
2531                 if (!isset($trace['line'])) $trace['line'] = __LINE__;
2532                 if (!isset($trace['args'])) $trace['args'] = array();
2533                 $backtrace .= ($key+1) . '.:' . basename($trace['file']) . ':' . $trace['line'] . ', ' . $trace['function'] . '(' . count($trace['args']) . ")\n";
2534         } // END - foreach
2535
2536         // Return the backtrace
2537         return $backtrace;
2538 }
2539
2540 // Output a debug backtrace to the user
2541 function debug_report_bug ($message = '', $sendEmail = true) {
2542         // Is this already called?
2543         if (isset($GLOBALS[__FUNCTION__])) {
2544                 // Other backtrace
2545                 print 'Message:'.$message.'<br />Backtrace:<pre>';
2546                 debug_print_backtrace();
2547                 die('</pre>');
2548         } // END - if
2549
2550         // Set this function as called
2551         $GLOBALS[__FUNCTION__] = true;
2552
2553         // Init message
2554         $debug = '';
2555
2556         // Is the optional message set?
2557         if (!empty($message)) {
2558                 // Use and log it
2559                 $debug = sprintf("Note: %s<br />\n",
2560                         $message
2561                 );
2562
2563                 // @TODO Add a little more infos here
2564                 logDebugMessage(__FUNCTION__, __LINE__, strip_tags($message));
2565         } // END - if
2566
2567         // Add output
2568         $debug .= "Please report this bug at <a title=\"Direct link to the bug-tracker\" href=\"http://bugs.mxchange.org\" rel=\"external\" target=\"_blank\">http://bugs.mxchange.org</a> and include the logfile from <strong>" . str_replace(getConfig('PATH'), '', getConfig('CACHE_PATH')) . "debug.log</strong> in your report (you can now attach files):<pre>";
2569         $debug .= debug_get_printable_backtrace();
2570         $debug .= "</pre>\nRequest-URI: " . getRequestUri()."<br />\n";
2571         $debug .= "Thank you for finding bugs.";
2572
2573         // Send an email? (e.g. not wanted for evaluation errors)
2574         if ($sendEmail === true) {
2575                 // Prepare content
2576                 $content = array(
2577                         'message'     => trim($message),
2578                         'backtrace'   => trim(debug_get_mailable_backtrace())
2579                 );
2580
2581                 // Send email to webmaster
2582                 sendAdminNotification(getMessage('DEBUG_REPORT_BUG_SUBJECT'), 'admin_report_bug', $content);
2583         } // END - if
2584
2585         // And abort here
2586         // @TODO This cannot be rewritten to app_die(), try to find a solution for this.
2587         die($debug);
2588 }
2589
2590 // Generates a ***weak*** seed
2591 function generateSeed () {
2592         return microtime(true) * 100000;
2593 }
2594
2595 // Converts a message code to a human-readable message
2596 function getMessageFromErrorCode ($code) {
2597         $message = '';
2598         switch ($code) {
2599                 case '': break;
2600                 case getCode('LOGOUT_DONE')      : $message = getMessage('LOGOUT_DONE'); break;
2601                 case getCode('LOGOUT_FAILED')    : $message = "<span class=\"guest_failed\">{--LOGOUT_FAILED--}</span>"; break;
2602                 case getCode('DATA_INVALID')     : $message = getMessage('MAIL_DATA_INVALID'); break;
2603                 case getCode('POSSIBLE_INVALID') : $message = getMessage('MAIL_POSSIBLE_INVALID'); break;
2604                 case getCode('ACCOUNT_LOCKED')   : $message = getMessage('MEMBER_ACCOUNT_LOCKED_UNC'); break;
2605                 case getCode('USER_404')         : $message = getMessage('USER_404'); break;
2606                 case getCode('STATS_404')        : $message = getMessage('MAIL_STATS_404'); break;
2607                 case getCode('ALREADY_CONFIRMED'): $message = getMessage('MAIL_ALREADY_CONFIRMED'); break;
2608                 case getCode('WRONG_PASS')       : $message = getMessage('LOGIN_WRONG_PASS'); break;
2609                 case getCode('WRONG_ID')         : $message = getMessage('LOGIN_WRONG_ID'); break;
2610                 case getCode('ID_LOCKED')        : $message = getMessage('LOGIN_ID_LOCKED'); break;
2611                 case getCode('ID_UNCONFIRMED')   : $message = getMessage('LOGIN_ID_UNCONFIRMED'); break;
2612                 case getCode('ID_GUEST')         : $message = getMessage('LOGIN_ID_GUEST'); break;
2613                 case getCode('COOKIES_DISABLED') : $message = getMessage('LOGIN_COOKIES_DISABLED'); break;
2614                 case getCode('BEG_SAME_AS_OWN')  : $message = getMessage('BEG_SAME_UID_AS_OWN'); break;
2615                 case getCode('LOGIN_FAILED')     : $message = getMessage('LOGIN_FAILED_GENERAL'); break;
2616                 case getCode('MODULE_MEM_ONLY')  : $message = sprintf(getMessage('MODULE_MEM_ONLY'), getRequestElement('mod')); break;
2617                 case getCode('OVERLENGTH')       : $message = getMessage('MEMBER_TEXT_OVERLENGTH'); break;
2618                 case getCode('URL_FOUND')        : $message = getMessage('MEMBER_TEXT_CONTAINS_URL'); break;
2619                 case getCode('SUBJ_URL')         : $message = getMessage('MEMBER_SUBJ_CONTAINS_URL'); break;
2620                 case getCode('BLIST_URL')        : $message = "{--MEMBER_URL_BLACK_LISTED--}<br />\n{--MEMBER_BLIST_TIME--}: ".generateDateTime(getRequestElement('blist'), 0); break;
2621                 case getCode('NO_RECS_LEFT')     : $message = getMessage('MEMBER_SELECTED_MORE_RECS'); break;
2622                 case getCode('INVALID_TAGS')     : $message = getMessage('MEMBER_HTML_INVALID_TAGS'); break;
2623                 case getCode('MORE_POINTS')      : $message = getMessage('MEMBER_MORE_POINTS_NEEDED'); break;
2624                 case getCode('MORE_RECEIVERS1')  : $message = getMessage('MEMBER_ENTER_MORE_RECEIVERS'); break;
2625                 case getCode('MORE_RECEIVERS2')  : $message = getMessage('MEMBER_NO_MORE_RECEIVERS_FOUND'); break;
2626                 case getCode('MORE_RECEIVERS3')  : $message = sprintf(getMessage('MEMBER_ENTER_MORE_MIN_RECEIVERS'), getConfig('order_min')); break;
2627                 case getCode('INVALID_URL')      : $message = getMessage('MEMBER_ENTER_INVALID_URL'); break;
2628
2629                 case getCode('ERROR_MAILID'):
2630                         if (isExtensionActive('mailid', true)) {
2631                                 $message = getMessage('ERROR_CONFIRMING_MAIL');
2632                         } else {
2633                                 $message = sprintf(getMessage('EXTENSION_PROBLEM_NOT_INSTALLED'), 'mailid');
2634                         }
2635                         break;
2636
2637                 case getCode('EXTENSION_PROBLEM'):
2638                         if (isGetRequestElementSet('ext')) {
2639                                 $message = generateExtensionInactiveNotInstalledMessage(getRequestElement('ext'));
2640                         } else {
2641                                 $message = getMessage('EXTENSION_PROBLEM_UNSET_EXT');
2642                         }
2643                         break;
2644
2645                 case getCode('URL_TLOCK'):
2646                         $result = SQL_QUERY_ESC("SELECT `timestamp` FROM `{?_MYSQL_PREFIX?}_pool` WHERE `id`=%s LIMIT 1",
2647                                 array(bigintval(getRequestElement('id'))), __FILE__, __LINE__);
2648
2649                         // Load timestamp from last order
2650                         list($timestamp) = SQL_FETCHROW($result);
2651                         $timestamp = generateDateTime($timestamp, 1);
2652
2653                         // Free memory
2654                         SQL_FREERESULT($result);
2655
2656                         // Calculate hours...
2657                         $STD = round(getConfig('url_tlock') / 60 / 60);
2658
2659                         // Minutes...
2660                         $MIN = round((getConfig('url_tlock') - $STD * 60 * 60) / 60);
2661
2662                         // And seconds
2663                         $SEC = getConfig('url_tlock') - $STD * 60 * 60 - $MIN * 60;
2664
2665                         // Finally contruct the message
2666                         // @TODO Rewrite this old lost code to a template
2667                         $message = "{--MEMBER_URL_TIME_LOCK--}<br />{--CONFIG_URL_TLOCK--} ".$STD."
2668                         {--_HOURS--}, ".$MIN." {--_MINUTES--} {--_AND--} ".$SEC." {--_SECONDS--}<br />
2669                         {--MEMBER_LAST_TLOCK--}: ".$timestamp;
2670                         break;
2671
2672                 default:
2673                         // Missing/invalid code
2674                         $message = sprintf(getMessage('UNKNOWN_MAILID_CODE'), $code);
2675
2676                         // Log it
2677                         logDebugMessage(__FUNCTION__, __LINE__, $message);
2678                         break;
2679         } // END - switch
2680
2681         // Return the message
2682         return $message;
2683 }
2684
2685 // Compile characters which are allowed in URLs
2686 function compileUriCode ($code, $simple = true) {
2687         // Compile constants
2688         if ($simple === false) $code = str_replace('{--', '".', str_replace('--}', '."', $code));
2689
2690         // Compile QUOT and other non-HTML codes
2691         $code = str_replace('{DOT}', '.',
2692                 str_replace('{SLASH}', '/',
2693                 str_replace('{QUOT}', "'",
2694                 str_replace('{DOLLAR}', '$',
2695                 str_replace('{OPEN_ANCHOR}', '(',
2696                 str_replace('{CLOSE_ANCHOR}', ')',
2697                 str_replace('{OPEN_SQR}', '[',
2698                 str_replace('{CLOSE_SQR}', ']',
2699                 str_replace('{PER}', '%',
2700                 $code
2701         )))))))));
2702
2703         // Return compiled code
2704         return $code;
2705 }
2706
2707 // Function taken from user comments on www.php.net / function eregi()
2708 function isUrlValidSimple ($url) {
2709         // Prepare URL
2710         $url = secureString(str_replace("\\", '', compileRawCode(urldecode($url))));
2711
2712         // Allows http and https
2713         $http      = "(http|https)+(:\/\/)";
2714         // Test domain
2715         $domain1   = "([[:alnum:]]([-[:alnum:]])*\.)?([[:alnum:]][-[:alnum:]\.]*[[:alnum:]])(\.[[:alpha:]]{2,5})?";
2716         // Test double-domains (e.g. .de.vu)
2717         $domain2   = "([-[:alnum:]])?(\.[[:alnum:]][-[:alnum:]\.]*[[:alnum:]])(\.[[:alpha:]]{2,5})(\.[[:alpha:]]{2,5})?";
2718         // Test IP number
2719         $ip        = "([[:digit:]]{1,3})\.([[:digit:]]{1,3})\.([[:digit:]]{1,3})\.([[:digit:]]{1,3})";
2720         // ... directory
2721         $dir       = "((/)+([-_\.[:alnum:]])+)*";
2722         // ... page
2723         $page      = "/([-_[:alnum:]][-\._[:alnum:]]*\.[[:alnum:]]{2,5})?";
2724         // ... and the string after and including question character
2725         $getstring1 = "([\?/]([[:alnum:]][-\._%[:alnum:]]*(=)?([-\@\._:%[:alnum:]])+)(&([[:alnum:]]([-_%[:alnum:]])*(=)?([-\@\[\._:%[:alnum:]])+(\])*))*)?";
2726         // Pattern for URLs like http://url/dir/doc.html?var=value
2727         $pattern['d1dpg1']  = $http . $domain1 . $dir . $page . $getstring1;
2728         $pattern['d2dpg1']  = $http . $domain2 . $dir . $page . $getstring1;
2729         $pattern['ipdpg1']  = $http . $ip . $dir . $page . $getstring1;
2730         // Pattern for URLs like http://url/dir/?var=value
2731         $pattern['d1dg1']  = $http . $domain1 . $dir.'/' . $getstring1;
2732         $pattern['d2dg1']  = $http . $domain2 . $dir.'/' . $getstring1;
2733         $pattern['ipdg1']  = $http . $ip . $dir.'/' . $getstring1;
2734         // Pattern for URLs like http://url/dir/page.ext
2735         $pattern['d1dp']  = $http . $domain1 . $dir . $page;
2736         $pattern['d1dp']  = $http . $domain2 . $dir . $page;
2737         $pattern['ipdp']  = $http . $ip . $dir . $page;
2738         // Pattern for URLs like http://url/dir
2739         $pattern['d1d']  = $http . $domain1 . $dir;
2740         $pattern['d2d']  = $http . $domain2 . $dir;
2741         $pattern['ipd']  = $http . $ip . $dir;
2742         // Pattern for URLs like http://url/?var=value
2743         $pattern['d1g1']  = $http . $domain1 . '/' . $getstring1;
2744         $pattern['d2g1']  = $http . $domain2 . '/' . $getstring1;
2745         $pattern['ipg1']  = $http . $ip . '/' . $getstring1;
2746         // Pattern for URLs like http://url?var=value
2747         $pattern['d1g12']  = $http . $domain1 . $getstring1;
2748         $pattern['d2g12']  = $http . $domain2 . $getstring1;
2749         $pattern['ipg12']  = $http . $ip . $getstring1;
2750         // Test all patterns
2751         $reg = false;
2752         foreach ($pattern as $key => $pat) {
2753                 // Debug regex?
2754                 if (isDebugRegExpressionEnabled()) {
2755                         // @TODO Are these convertions still required?
2756                         $pat = str_replace('.', "&#92;&#46;", $pat);
2757                         $pat = str_replace('@', "&#92;&#64;", $pat);
2758                         //* DEBUG: */ outputHtml($key."=&nbsp;" . $pat . '<br />');
2759                 } // END - if
2760
2761                 // Check if expression matches
2762                 $reg = ($reg || preg_match(('^' . $pat.'^'), $url));
2763
2764                 // Does it match?
2765                 if ($reg === true) break;
2766         }
2767
2768         // Return true/false
2769         return $reg;
2770 }
2771
2772 // Wtites data to a config.php-style file
2773 // @TODO Rewrite this function to use readFromFile() and writeToFile()
2774 function changeDataInFile ($FQFN, $comment, $prefix, $suffix, $DATA, $seek=0) {
2775         // Initialize some variables
2776         $done = false;
2777         $seek++;
2778         $next  = -1;
2779         $found = false;
2780
2781         // Is the file there and read-/write-able?
2782         if ((isFileReadable($FQFN)) && (is_writeable($FQFN))) {
2783                 $search = 'CFG: ' . $comment;
2784                 $tmp = $FQFN . '.tmp';
2785
2786                 // Open the source file
2787                 $fp = fopen($FQFN, 'r') or outputHtml('<strong>READ:</strong> ' . $FQFN . '<br />');
2788
2789                 // Is the resource valid?
2790                 if (is_resource($fp)) {
2791                         // Open temporary file
2792                         $fp_tmp = fopen($tmp, 'w') or outputHtml('<strong>WRITE:</strong> ' . $tmp . '<br />');
2793
2794                         // Is the resource again valid?
2795                         if (is_resource($fp_tmp)) {
2796                                 // Mark temporary file as readable
2797                                 $GLOBALS['file_readable'][$tmp] = true;
2798
2799                                 // Start reading
2800                                 while (!feof($fp)) {
2801                                         // Read from source file
2802                                         $line = fgets ($fp, 1024);
2803
2804                                         if (strpos($line, $search) > -1) { $next = '0'; $found = true; }
2805
2806                                         if ($next > -1) {
2807                                                 if ($next === $seek) {
2808                                                         $next = -1;
2809                                                         $line = $prefix . $DATA . $suffix . "\n";
2810                                                 } else {
2811                                                         $next++;
2812                                                 }
2813                                         } // END - if
2814
2815                                         // Write to temp file
2816                                         fputs($fp_tmp, $line);
2817                                 } // END - while
2818
2819                                 // Close temp file
2820                                 fclose($fp_tmp);
2821
2822                                 // Finished writing tmp file
2823                                 $done = true;
2824                         } // END - if
2825
2826                         // Close source file
2827                         fclose($fp);
2828
2829                         if (($done === true) && ($found === true)) {
2830                                 // Copy back tmp file and delete tmp :-)
2831                                 copyFileVerified($tmp, $FQFN, 0644);
2832                                 return removeFile($tmp);
2833                         } elseif ($found === false) {
2834                                 outputHtml('<strong>CHANGE:</strong> 404!');
2835                         } else {
2836                                 outputHtml('<strong>TMP:</strong> UNDONE!');
2837                         }
2838                 }
2839         } else {
2840                 // File not found, not readable or writeable
2841                 outputHtml('<strong>404:</strong> ' . $FQFN . '<br />');
2842         }
2843
2844         // An error was detected!
2845         return false;
2846 }
2847 // Send notification to admin
2848 function sendAdminNotification ($subject, $templateName, $content=array(), $userid = '0') {
2849         if ((isExtensionInstalledAndNewer('admins', '0.4.1')) && (function_exists('sendAdminsEmails'))) {
2850                 // Send new way
2851                 sendAdminsEmails($subject, $templateName, $content, $userid);
2852         } else {
2853                 // Send out out-dated way
2854                 $message = loadEmailTemplate($templateName, $content, $userid);
2855                 sendAdminEmails($subject, $message);
2856         }
2857 }
2858
2859 // Debug message logger
2860 function logDebugMessage ($funcFile, $line, $message, $force=true) {
2861         // Is debug mode enabled?
2862         if ((isDebugModeEnabled()) || ($force === true)) {
2863                 // Remove CRLF
2864                 $message = str_replace("\r", '', str_replace("\n", '', $message));
2865
2866                 // Log this message away, we better don't call app_die() here to prevent an endless loop
2867                 $fp = fopen(getConfig('CACHE_PATH') . 'debug.log', 'a') or die(__FUNCTION__.'['.__LINE__.']: Cannot write logfile debug.log!');
2868                 fwrite($fp, date('d.m.Y|H:i:s', time()) . '|' . getModule(false) . '|' . basename($funcFile) . '|' . $line . '|' . $message . "\n");
2869                 fclose($fp);
2870         } // END - if
2871 }
2872
2873 // Handle extra values
2874 function handleExtraValues ($filterFunction, $value, $extraValue) {
2875         // Default is the value itself
2876         $ret = $value;
2877
2878         // Do we have a special filter function?
2879         if (!empty($filterFunction)) {
2880                 // Does the filter function exist?
2881                 if (function_exists($filterFunction)) {
2882                         // Do we have extra parameters here?
2883                         if (!empty($extraValue)) {
2884                                 // Put both parameters in one new array by default
2885                                 $args = array($value, $extraValue);
2886
2887                                 // If we have an array simply use it and pre-extend it with our value
2888                                 if (is_array($extraValue)) {
2889                                         // Make the new args array
2890                                         $args = merge_array(array($value), $extraValue);
2891                                 } // END - if
2892
2893                                 // Call the multi-parameter call-back
2894                                 $ret = call_user_func_array($filterFunction, $args);
2895                         } else {
2896                                 // One parameter call
2897                                 $ret = call_user_func($filterFunction, $value);
2898                         }
2899                 } // END - if
2900         } // END - if
2901
2902         // Return the value
2903         return $ret;
2904 }
2905
2906 // Converts timestamp selections into a timestamp
2907 function convertSelectionsToTimestamp (&$postData, &$DATA, &$id, &$skip) {
2908         // Init test variable
2909         $skip  = false;
2910         $test2 = '';
2911
2912         // Get last three chars
2913         $test = substr($id, -3);
2914
2915         // Improved way of checking! :-)
2916         if (in_array($test, array('_ye', '_mo', '_we', '_da', '_ho', '_mi', '_se'))) {
2917                 // Found a multi-selection for timings?
2918                 $test = substr($id, 0, -3);
2919                 if ((isset($postData[$test.'_ye'])) && (isset($postData[$test.'_mo'])) && (isset($postData[$test.'_we'])) && (isset($postData[$test.'_da'])) && (isset($postData[$test.'_ho'])) && (isset($postData[$test.'_mi'])) && (isset($postData[$test.'_se'])) && ($test != $test2)) {
2920                         // Generate timestamp
2921                         $postData[$test] = createTimestampFromSelections($test, $postData);
2922                         $DATA[] = sprintf("`%s`='%s'", $test, $postData[$test]);
2923                         $GLOBALS['skip_config'][$test] = true;
2924
2925                         // Remove data from array
2926                         foreach (array('ye', 'mo', 'we', 'da', 'ho', 'mi', 'se') as $rem) {
2927                                 unset($postData[$test . '_' . $rem]);
2928                         } // END - foreach
2929
2930                         // Skip adding
2931                         unset($id);
2932                         $skip = true;
2933                         $test2 = $test;
2934                 } // END - if
2935         } // END - if
2936 }
2937
2938 // Reverts the german decimal comma into Computer decimal dot
2939 function convertCommaToDot ($str) {
2940         // Default float is not a float... ;-)
2941         $float = false;
2942
2943         // Which language is selected?
2944         switch (getLanguage()) {
2945                 case 'de': // German language
2946                         // Remove german thousand dots first
2947                         $str = str_replace('.', '', $str);
2948
2949                         // Replace german commata with decimal dot and cast it
2950                         $float = (float)str_replace(',', '.', $str);
2951                         break;
2952
2953                 default: // US and so on
2954                         // Remove thousand dots first and cast
2955                         $float = (float)str_replace(',', '', $str);
2956                         break;
2957         }
2958
2959         // Return float
2960         return $float;
2961 }
2962
2963 // Handle menu-depending failed logins and return the rendered content
2964 function handleLoginFailtures ($accessLevel) {
2965         // Default output is empty ;-)
2966         $OUT = '';
2967
2968         // Is the session data set?
2969         if ((isSessionVariableSet('mxchange_' . $accessLevel.'_failures')) && (isSessionVariableSet('mxchange_' . $accessLevel.'_last_fail'))) {
2970                 // Ignore zero values
2971                 if (getSession('mxchange_' . $accessLevel.'_failures') > 0) {
2972                         // Non-guest has login failures found, get both data and prepare it for template
2973                         //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>):accessLevel={$accessLevel}<br />");
2974                         $content = array(
2975                                 'login_failures' => getSession('mxchange_' . $accessLevel.'_failures'),
2976                                 'last_failure'   => generateDateTime(getSession('mxchange_' . $accessLevel.'_last_fail'), 2)
2977                         );
2978
2979                         // Load template
2980                         $OUT = loadTemplate('login_failures', true, $content);
2981                 } // END - if
2982
2983                 // Reset session data
2984                 setSession('mxchange_' . $accessLevel.'_failures', '');
2985                 setSession('mxchange_' . $accessLevel.'_last_fail', '');
2986         } // END - if
2987
2988         // Return rendered content
2989         return $OUT;
2990 }
2991
2992 // Rebuild cache
2993 function rebuildCacheFile ($cache, $inc = '', $force = false) {
2994         // Debug message
2995         /* DEBUG: */ logDebugMessage(__FUNCTION__, __LINE__, sprintf("cache=%s, inc=%s, force=%s", $cache, $inc, intval($force)));
2996
2997         // Shall I remove the cache file?
2998         if (isCacheInstanceValid()) {
2999                 // Rebuild cache
3000                 if ($GLOBALS['cache_instance']->loadCacheFile($cache)) {
3001                         // Destroy it
3002                         $GLOBALS['cache_instance']->removeCacheFile($force);
3003                 } // END - if
3004
3005                 // Include file given?
3006                 if (!empty($inc)) {
3007                         // Construct FQFN
3008                         $inc = sprintf("inc/loader/load_cache-%s.php", $inc);
3009
3010                         // Is the include there?
3011                         if (isIncludeReadable($inc)) {
3012                                 // And rebuild it from scratch
3013                                 //* DEBUG: */ outputHtml(__FUNCTION__."(<font color=\"#0000aa\">".__LINE__."</font>): inc={$inc} - LOADED!<br />");
3014                                 loadInclude($inc);
3015                         } else {
3016                                 // Include not found!
3017                                 logDebugMessage(__FUNCTION__, __LINE__, "Include {$inc} not found. cache={$cache}");
3018                         }
3019                 } // END - if
3020         } // END - if
3021 }
3022
3023 // Determines the real remote address
3024 function determineRealRemoteAddress () {
3025         // Is a proxy in use?
3026         if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
3027                 // Proxy was used
3028                 $address = $_SERVER['HTTP_X_FORWARDED_FOR'];
3029         } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
3030                 // Yet, another proxy
3031                 $address = $_SERVER['HTTP_CLIENT_IP'];
3032         } else {
3033                 // The regular address when no proxy was used
3034                 $address = $_SERVER['REMOTE_ADDR'];
3035         }
3036
3037         // This strips out the real address from proxy output
3038         if (strstr($address, ',')) {
3039                 $addressArray = explode(',', $address);
3040                 $address = $addressArray[0];
3041         } // END - if
3042
3043         // Return the result
3044         return $address;
3045 }
3046
3047 // Adds a bonus mail to the queue
3048 // This is a high-level function!
3049 function addNewBonusMail ($data, $mode = '', $output=true) {
3050         // Use mode from data if not set and availble ;-)
3051         if ((empty($mode)) && (isset($data['mode']))) $mode = $data['mode'];
3052
3053         // Generate receiver list
3054         $receiver = generateReceiverList($data['cat'], $data['receiver'], $mode);
3055
3056         // Receivers added?
3057         if (!empty($receiver)) {
3058                 // Add bonus mail to queue
3059                 addBonusMailToQueue(
3060                 $data['subject'],
3061                 $data['text'],
3062                 $receiver,
3063                 $data['points'],
3064                 $data['seconds'],
3065                 $data['url'],
3066                 $data['cat'],
3067                 $mode,
3068                 $data['receiver']
3069                 );
3070
3071                 // Mail inserted into bonus pool
3072                 if ($output) loadTemplate('admin_settings_saved', false, getMessage('ADMIN_BONUS_SEND'));
3073         } elseif ($output) {
3074                 // More entered than can be reached!
3075                 loadTemplate('admin_settings_saved', false, getMessage('ADMIN_MORE_SELECTED'));
3076         } else {
3077                 // Debug log
3078                 logDebugMessage(__FUNCTION__, __LINE__, "cat={$data['cat']},receiver={$data['receiver']},data=".base64_encode(serialize($data))." More selected, than available!");
3079         }
3080 }
3081
3082 // Determines referal id and sets it
3083 function determineReferalId () {
3084         // Skip this in non-html-mode and outside ref.php
3085         if ((getOutputMode() != 0) && (basename($_SERVER['PHP_SELF']) != 'ref.php')) return false;
3086
3087         // Check if refid is set
3088         if ((isset($GLOBALS['refid'])) && ($GLOBALS['refid'] > 0)) {
3089                 // This is fine...
3090         } elseif ((isGetRequestElementSet('user')) && (basename($_SERVER['PHP_SELF']) == 'click.php')) {
3091                 // The variable user comes from the click-counter script click.php and we only accept this here
3092                 $GLOBALS['refid'] = bigintval(getRequestElement('user'));
3093         } elseif (isPostRequestElementSet('refid')) {
3094                 // Get referal id from variable refid (so I hope this makes my script more compatible to other scripts)
3095                 $GLOBALS['refid'] = secureString(postRequestElement('refid'));
3096         } elseif (isGetRequestElementSet('refid')) {
3097                 // Get referal id from variable refid (so I hope this makes my script more compatible to other scripts)
3098                 $GLOBALS['refid'] = secureString(getRequestElement('refid'));
3099         } elseif (isGetRequestElementSet('ref')) {
3100                 // Set refid=ref (the referal link uses such variable)
3101                 $GLOBALS['refid'] = secureString(getRequestElement('ref'));
3102         } elseif ((isSessionVariableSet('refid')) && (getSession('refid') != 0)) {
3103                 // Set session refid als global
3104                 $GLOBALS['refid'] = bigintval(getSession('refid'));
3105         } elseif ((isExtensionInstalledAndNewer('user', '0.3.4')) && (getConfig('select_user_zero_refid') == 'Y')) {
3106                 // Select a random user which has confirmed enougth mails
3107                 $GLOBALS['refid'] = determineRandomReferalId();
3108         } elseif ((isExtensionInstalled('sql_patches')) && (getConfig('def_refid') > 0)) {
3109                 // Set default refid as refid in URL
3110                 $GLOBALS['refid'] = getConfig('def_refid');
3111         } else {
3112                 // No default id when sql_patches is not installed or none set
3113                 $GLOBALS['refid'] = '0';
3114         }
3115
3116         // Set cookie when default refid > 0
3117         if (!isSessionVariableSet('refid') || (!empty($GLOBALS['refid'])) || ((getSession('refid') == '0') && (isConfigEntrySet('def_refid')) && (getConfig('def_refid') > 0))) {
3118                 // Default is not found
3119                 $found = false;
3120
3121                 // Do we have nickname or userid set?
3122                 if ((isExtensionActive('nickname')) && (isNicknameUsed($GLOBALS['refid']))) {
3123                         // Nickname in URL, so load the id
3124                         $found = fetchUserData($GLOBALS['refid'], 'nickname');