3 * General functions library
5 * @author Roland Haeder <webmaster@shipsimu.org>
7 * @copyright Copyright (c) 2009 - 2011 Cracker Tracker Team
8 * @license GNU GPL 3.0 or any newer version
9 * @link http://www.shipsimu.org
11 * This program is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 3 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25 if (!function_exists('implode_r')) {
26 // Implode recursive a multi-dimension array, taken from www.php.net
27 function implode_r ($glue, $array, $array_name = NULL) {
29 while(list($key,$value) = @each($array)) {
30 if(is_array($value)) {
31 // Is an array again, so call recursive
32 $return[] = implode_r($glue, $value, (string) $key);
34 if($array_name != NULL) {
35 $return[] = $array_name . '[' . (string) $key . ']=' . $value . "\n";
37 $return[] = $key . '=' . $value."\n";
42 // Return resulting array
43 return(implode($glue, $return));
47 if (!function_exists('implode_secure')) {
48 // Implode a simple array with a 'call-back' to our escaper function
49 function implode_secure ($array) {
54 foreach ($array as $entry) {
56 if (in_array($entry, array('NOW()'))) {
57 // Add it with non-string glue
58 $return .= $entry . ',';
59 } elseif (empty($entry)) {
60 // Empty strings need no escaping
63 // Secure this string and add it
64 $return .= '"' . crackerTrackerEscapeString($entry) . '",';
69 $return = substr($return, 0, -1);
76 // Load configuration, if found
77 function crackerTrackerLoadConfiguration () {
79 $fqfn = sprintf('%s/config/db_config.php', $GLOBALS['ctracker_base_path']);
81 // Is the file readable?
82 if (!isCrackerTrackerFileFound($fqfn)) {
83 // No config file found
84 die(__FUNCTION__.': No configuration file found.');
91 $GLOBALS['ctracker_header'] = crackerTrackerLoadEmailTemplate('header');
94 // Getter for ctracker_debug_enabled
95 function isCrackerTrackerDebug () {
97 $result = ((isset($GLOBALS['ctracker_debug_enabled'])) && ($GLOBALS['ctracker_debug_enabled'] === TRUE));
100 //* DEBUG: */ error_log('result=' . intval($result));
106 // Determines the real remote address
107 function determineCrackerTrackerRealRemoteAddress () {
109 $address = '0.0.0.0';
111 // Is a proxy in use?
112 if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
114 $address = trim($_SERVER['HTTP_X_FORWARDED_FOR']);
115 } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
116 // Yet, another proxy
117 $address = trim($_SERVER['HTTP_CLIENT_IP']);
118 } elseif (isset($_SERVER['REMOTE_ADDR'])) {
119 // The regular address when no proxy was used
120 $address = trim(getenv('REMOTE_ADDR'));
123 if ($address == 'unknown') {
124 // Invalid IP somehow given
125 $address = '0.0.0.0';
126 } elseif (strstr($address, ',')) {
127 // This strips out the real address from proxy output
128 $addressArray = explode(',', $address);
129 $address = $addressArray[0];
136 // Determine if a proxy was used
137 function isCrackerTrackerProxyUsed () {
138 // Check if specific entries are set
139 $proxyUsed = ((isset($_SERVER['HTTP_X_FORWARDED_FOR'])) || (isset($_SERVER['HTTP_CLIENT_IP'])));
145 // Detects the user-agent string
146 function crackerTrackerUserAgent ($sanitize = FALSE) {
147 // Default is 'unknown'
150 // Is the entry there?
151 if (isset($_SERVER['HTTP_USER_AGENT'])) {
152 // Then use it securely
153 $ua = crackerTrackerSecureString(urldecode($_SERVER['HTTP_USER_AGENT']));
157 if ($sanitize === TRUE) {
159 $ua = crackerTrackerSanitize($ua);
166 // Detects the script name
167 function crackerTrackerScriptName ($sanitize = FALSE) {
172 if (!empty($_SERVER['SCRIPT_NAME'])) {
174 $scriptName = crackerTrackerSecureString($_SERVER['SCRIPT_NAME']);
178 if ($sanitize === TRUE) {
180 $scriptName = crackerTrackerSanitize($scriptName);
187 // Detects the query string
188 function crackerTrackerQueryString ($sanitize = FALSE) {
193 if (!empty($_SERVER['QUERY_STRING'])) {
194 // Get string escaped
195 $query = crackerTrackerEscapeString(urldecode($_SERVER['QUERY_STRING']));
196 } elseif (!empty($_SERVER['REQUEST_URI'])) {
197 // Get string escaped
198 $query = crackerTrackerEscapeString(urldecode($_SERVER['REQUEST_URI']));
202 if ((!empty($query)) && ($sanitize === TRUE)) {
204 $query = crackerTrackerSanitize($query);
211 // Detects the server's name
212 function crackerTrackerServerName ($sanitize = FALSE) {
217 if (!empty($_SERVER['SERVER_NAME'])) {
219 $serverName = crackerTrackerSecureString($_SERVER['SERVER_NAME']);
223 if ($sanitize === TRUE) {
225 $serverName = crackerTrackerSanitize($serverName);
232 // Detects the referer
233 function crackerTrackerReferer ($sanitize = FALSE) {
238 if (!empty($_SERVER['HTTP_REFERER'])) {
239 // Then use it securely
240 $referer = crackerTrackerSecureString(urldecode($_SERVER['HTTP_REFERER']));
244 if ($sanitize === TRUE) {
246 $referer = crackerTrackerSanitize($referer);
253 // Detects request method
254 function crackerTrackerRequestMethod () {
259 if (!empty($_SERVER['REQUEST_METHOD'])) {
261 $method = $_SERVER['REQUEST_METHOD'];
268 // Detects the scripts path
269 function crackerTrackerScriptPath () {
270 // Should always be there!
271 $path = dirname(crackerTrackerScriptName()) . '/';
273 // Return detected path
277 // Detects wether we have SSL
278 function crackerTrackerSecured () {
280 $ssl = ((isset($_SERVER['HTTPS'])) && ($_SERVER['HTTPS'] != 'off'));
286 // Secures a string by escaping it and passing it through strip_tags,htmlentities-chain
287 function crackerTrackerSecureString ($str) {
289 $str = crackerTrackerEscapeString($str);
291 // Then pass it through the functions
292 $str = htmlentities(strip_tags($str), ENT_QUOTES);
298 // Is the file there and readable?
299 function isCrackerTrackerFileFound ($FQFN) {
301 return ((file_exists($FQFN)) && (is_readable($FQFN)));
304 // Loads a given "template" (this is more an include file)
305 function crackerTrackerLoadTemplate ($template) {
306 // Create the full-qualified filename (FQFN)
307 $FQFN = sprintf('%s/libs/templates/%s.tpl.php',
308 $GLOBALS['ctracker_base_path'],
312 // Is this template found?
313 if (isCrackerTrackerFileFound($FQFN)) {
315 crackerTrackerLanguage();
320 // Not found, so die here
325 // Loads a given "template" (this is more an include file)
326 function crackerTrackerLoadLocalizedTemplate ($template) {
327 // Create the full-qualified filename (FQFN)
328 $FQFN = sprintf('%s/libs/templates/%s/%s.tpl.php',
329 $GLOBALS['ctracker_base_path'],
330 getCrackerTrackerLanguage(),
334 // Is this template found?
335 if (isCrackerTrackerFileFound($FQFN)) {
339 // Not found, so die here
344 // Detects the browser's language file and tries to load it, fall-back on english!
345 function crackerTrackerLanguage () {
346 // Default is English
347 $GLOBALS['ctracker_language'] = 'en';
350 // Is the language string there?
351 if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
353 foreach (explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']) as $lang) {
354 // Split it again for q=x.x value
355 $langArray = explode(';', $lang);
357 // If there is an entry, we have a weight
358 if ((isset($langArray[1])) && ($langArray[1] > $weight)) {
359 // Use this language/weight instead
360 $GLOBALS['ctracker_language'] = $langArray[0];
361 $weight = $langArray[1];
367 $FQFN = sprintf('%s/libs/language/%s.php',
368 $GLOBALS['ctracker_base_path'],
369 getCrackerTrackerLanguage()
372 // Is it not there, switch to "en"
373 if ((getCrackerTrackerLanguage() != 'en') && (!isCrackerTrackerFileFound($FQFN))) {
374 // English is default!
375 $GLOBALS['ctracker_language'] = 'en';
377 // Construct FQFN again
378 $FQFN = sprintf('%s/libs/language/en.php', $GLOBALS['ctracker_base_path']);
381 // Load the language file
385 // Loads a given email template and passes through $content
386 function crackerTrackerLoadEmailTemplate ($template, array $content = array(), $language = NULL) {
388 crackerTrackerLanguage();
391 $FQFN = sprintf('%s/libs/mails/%s/%s.tpl',
392 $GLOBALS['ctracker_base_path'],
393 getCrackerTrackerLanguage($language),
397 // So is the file there?
398 if (isCrackerTrackerFileFound($FQFN)) {
400 $result = 'No result from template ' . $template . '. Please report this at http://forum.shipsimu.org Thank you.';
403 //* DEBUG-DIE: */ die('<pre>$result = "' . crackerTrackerCompileCode(trim(file_get_contents($FQFN))) . '";</pre>');
404 eval('$result = "' . crackerTrackerCompileCode(trim(file_get_contents($FQFN))) . '";');
414 // Getter for message
415 function getCrackerTrackerLocalized ($message) {
417 $output = '!' . $message . '!';
419 // Is the language string there?
420 if (isset($GLOBALS['ctracker_localized'][$message])) {
422 $output = $GLOBALS['ctracker_localized'][$message];
429 // Tries to find a message and outputs it
430 function crackerTrackerOutputLocalized ($message) {
432 print getCrackerTrackerLocalized($message);
435 // Compiles the given code
436 function crackerTrackerCompileCode ($code) {
437 // Find all $content[foo]
438 preg_match_all('/\$(content|GLOBALS)((\[([a-zA-Z0-9-_]+)\])*)/', $code, $matches);
440 // Replace " with {QUOTE}
441 $code = str_replace('"', '{QUOTE}', $code);
444 foreach ($matches[0] as $key=>$match) {
446 if (substr($match, 0, 8) == '$GLOBALS') {
448 $code = str_replace($match, "\" . \$GLOBALS['" . $matches[4][$key] . "'] . \"", $code);
449 } elseif (substr($match, 0, 8) == '$content') {
451 $code = str_replace($match, "\" . \$content['" . $matches[4][$key] . "'] . \"", $code);
459 // "Getter" for language
460 function getCrackerTrackerLanguage ($lang = NULL) {
461 // Default is from browser
462 $language = $GLOBALS['ctracker_language'];
465 if (!is_null($lang)) {
466 // Then use this instead
474 // "Getter" for ticket id
475 function getCrackerTrackerTicketId () {
480 if (isset($GLOBALS['ctracker_last_ticket']['ctracker_ticket'])) {
482 $id = $GLOBALS['ctracker_last_ticket']['ctracker_ticket'];
489 // Sends a cookie to the user that he would not see this security warning again
490 function sendCrackerTrackerCookie () {
492 // @TODO Why can't domain be set to value from crackerTrackerServerName() ?
493 setcookie('ctracker_ticket', getCrackerTrackerTicketId(), (time() + 60*60*24), '/', '', crackerTrackerSecured(), TRUE);
494 $_COOKIE['ctracker_ticket'] = getCrackerTrackerTicketId();
497 // Is the cookie set?
498 function ifCrackerTrackerCookieIsSet () {
499 // Is it set and valid?
500 return ((isset($_COOKIE['ctracker_ticket'])) && ($_COOKIE['ctracker_ticket'] > 0));
503 // Redirects to the same URL
504 function crackerTrackerRedirectSameUrl () {
506 $url = '://' . crackerTrackerServerName() . crackerTrackerScriptName() . '?' . crackerTrackerQueryString();
509 if (crackerTrackerSecured()) {
511 $url = 'https' . $url;
514 $url = 'http' . $url;
518 crackerTrackerSendRawRedirect($url);
522 * Send a HTTP redirect to the browser. This function was taken from DokuWiki
523 * (GNU GPL 2; http://www.dokuwiki.org) and modified to fit into this script.
525 * Works arround Microsoft IIS cookie sending bug. Does exit the script.
527 * @link http://support.microsoft.com/kb/q176113/
528 * @author Andreas Gohr <andi@splitbrain.org>
531 function crackerTrackerSendRawRedirect ($url) {
532 // Better remove any data by ctracker
535 // always close the session
536 session_write_close();
538 // Revert entity &
539 $url = str_replace('&', '&', $url);
541 // check if running on IIS < 6 with CGI-PHP
542 if ((isset($_SERVER['SERVER_SOFTWARE'])) && (isset($_SERVER['GATEWAY_INTERFACE'])) &&
543 (strpos($_SERVER['GATEWAY_INTERFACE'],'CGI') !== FALSE) &&
544 (preg_match('|^Microsoft-IIS/(\d)\.\d$|', trim($_SERVER['SERVER_SOFTWARE']), $matches)) &&
546 // Send the IIS header
547 header('Refresh: 0;url=' . $url);
549 // Send generic header
550 header('Location: ' . $url);
555 // Removes all ctracker-related data from global space
556 function unsetCtrackerData () {
558 //* DEBUG: */ error_log(__FUNCTION__ . ': CALLED!');
560 // Unset all ctracker data
562 'ctracker_base_path',
567 'ctracker_debug_enabled',
569 'ctracker_whitelist',
570 'ctracker_get_blacklist',
571 'ctracker_post_blacklist',
573 'ctracker_post_track',
574 'ctracker_checked_get',
575 'ctracker_checked_post',
576 'ctracker_checked_ua',
578 'ctracker_last_result',
582 'ctracker_localized',
584 'ctracker_blocked_requests',
587 unset($GLOBALS[$key]);
592 function crackerTrackerSanitize ($str) {
593 return str_replace(array('//', '/./'), array('/', '/'), $str);