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