Chris@76: '<', '>' => '>', '"' => '"')); Chris@76: $error_message = strtr($error_message, array('<br />' => '
', '<b>' => '', '</b>' => '', "\n" => '
')); Chris@76: Chris@76: // Add a file and line to the error message? Chris@76: // Don't use the actual txt entries for file and line but instead use %1$s for file and %2$s for line Chris@76: if ($file == null) Chris@76: $file = ''; Chris@76: else Chris@76: // Window style slashes don't play well, lets convert them to the unix style. Chris@76: $file = str_replace('\\', '/', $file); Chris@76: Chris@76: if ($line == null) Chris@76: $line = 0; Chris@76: else Chris@76: $line = (int) $line; Chris@76: Chris@76: // Just in case there's no id_member or IP set yet. Chris@76: if (empty($user_info['id'])) Chris@76: $user_info['id'] = 0; Chris@76: if (empty($user_info['ip'])) Chris@76: $user_info['ip'] = ''; Chris@76: Chris@76: // Find the best query string we can... Chris@76: $query_string = empty($_SERVER['QUERY_STRING']) ? (empty($_SERVER['REQUEST_URL']) ? '' : str_replace($scripturl, '', $_SERVER['REQUEST_URL'])) : $_SERVER['QUERY_STRING']; Chris@76: Chris@76: // Don't log the session hash in the url twice, it's a waste. Chris@76: $query_string = htmlspecialchars((SMF == 'SSI' ? '' : '?') . preg_replace(array('~;sesc=[^&;]+~', '~' . session_name() . '=' . session_id() . '[&;]~'), array(';sesc', ''), $query_string)); Chris@76: Chris@76: // Just so we know what board error messages are from. Chris@76: if (isset($_POST['board']) && !isset($_GET['board'])) Chris@76: $query_string .= ($query_string == '' ? 'board=' : ';board=') . $_POST['board']; Chris@76: Chris@76: // What types of categories do we have? Chris@76: $known_error_types = array( Chris@76: 'general', Chris@76: 'critical', Chris@76: 'database', Chris@76: 'undefined_vars', Chris@76: 'user', Chris@76: 'template', Chris@76: 'debug', Chris@76: ); Chris@76: Chris@76: // Make sure the category that was specified is a valid one Chris@76: $error_type = in_array($error_type, $known_error_types) && $error_type !== true ? $error_type : 'general'; Chris@76: Chris@76: // Don't log the same error countless times, as we can get in a cycle of depression... Chris@76: $error_info = array($user_info['id'], time(), $user_info['ip'], $query_string, $error_message, (string) $sc, $error_type, $file, $line); Chris@76: if (empty($last_error) || $last_error != $error_info) Chris@76: { Chris@76: // Insert the error into the database. Chris@76: $smcFunc['db_insert']('', Chris@76: '{db_prefix}log_errors', Chris@76: array('id_member' => 'int', 'log_time' => 'int', 'ip' => 'string-16', 'url' => 'string-65534', 'message' => 'string-65534', 'session' => 'string', 'error_type' => 'string', 'file' => 'string-255', 'line' => 'int'), Chris@76: $error_info, Chris@76: array('id_error') Chris@76: ); Chris@76: $last_error = $error_info; Chris@76: } Chris@76: Chris@76: // Return the message to make things simpler. Chris@76: return $error_message; Chris@76: } Chris@76: Chris@76: // An irrecoverable error. Chris@76: function fatal_error($error, $log = 'general') Chris@76: { Chris@76: global $txt, $context, $modSettings; Chris@76: Chris@76: // We don't have $txt yet, but that's okay... Chris@76: if (empty($txt)) Chris@76: die($error); Chris@76: Chris@76: setup_fatal_error_context($log || (!empty($modSettings['enableErrorLogging']) && $modSettings['enableErrorLogging'] == 2) ? log_error($error, $log) : $error); Chris@76: } Chris@76: Chris@76: // A fatal error with a message stored in the language file. Chris@76: function fatal_lang_error($error, $log = 'general', $sprintf = array()) Chris@76: { Chris@76: global $txt, $language, $modSettings, $user_info, $context; Chris@76: static $fatal_error_called = false; Chris@76: Chris@76: // Try to load a theme if we don't have one. Chris@76: if (empty($context['theme_loaded']) && empty($fatal_error_called)) Chris@76: { Chris@76: $fatal_error_called = true; Chris@76: loadTheme(); Chris@76: } Chris@76: Chris@76: // If we have no theme stuff we can't have the language file... Chris@76: if (empty($context['theme_loaded'])) Chris@76: die($error); Chris@76: Chris@76: $reload_lang_file = true; Chris@76: // Log the error in the forum's language, but don't waste the time if we aren't logging Chris@76: if ($log || (!empty($modSettings['enableErrorLogging']) && $modSettings['enableErrorLogging'] == 2)) Chris@76: { Chris@76: loadLanguage('Errors', $language); Chris@76: $reload_lang_file = $language != $user_info['language']; Chris@76: $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); Chris@76: log_error($error_message, $log); Chris@76: } Chris@76: Chris@76: // Load the language file, only if it needs to be reloaded Chris@76: if ($reload_lang_file) Chris@76: { Chris@76: loadLanguage('Errors'); Chris@76: $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); Chris@76: } Chris@76: Chris@76: setup_fatal_error_context($error_message); Chris@76: } Chris@76: Chris@76: // Handler for standard error messages. Chris@76: function error_handler($error_level, $error_string, $file, $line) Chris@76: { Chris@76: global $settings, $modSettings, $db_show_debug; Chris@76: Chris@76: // Ignore errors if we're ignoring them or they are strict notices from PHP 5 (which cannot be solved without breaking PHP 4.) Chris@76: if (error_reporting() == 0 || (defined('E_STRICT') && $error_level == E_STRICT && (empty($modSettings['enableErrorLogging']) || $modSettings['enableErrorLogging'] != 2))) Chris@76: return; Chris@76: Chris@76: if (strpos($file, 'eval()') !== false && !empty($settings['current_include_filename'])) Chris@76: { Chris@76: if (function_exists('debug_backtrace')) Chris@76: { Chris@76: $array = debug_backtrace(); Chris@76: for ($i = 0; $i < count($array); $i++) Chris@76: { Chris@76: if ($array[$i]['function'] != 'loadSubTemplate') Chris@76: continue; Chris@76: Chris@76: // This is a bug in PHP, with eval, it seems! Chris@76: if (empty($array[$i]['args'])) Chris@76: $i++; Chris@76: break; Chris@76: } Chris@76: Chris@76: if (isset($array[$i]) && !empty($array[$i]['args'])) Chris@76: $file = realpath($settings['current_include_filename']) . ' (' . $array[$i]['args'][0] . ' sub template - eval?)'; Chris@76: else Chris@76: $file = realpath($settings['current_include_filename']) . ' (eval?)'; Chris@76: } Chris@76: else Chris@76: $file = realpath($settings['current_include_filename']) . ' (eval?)'; Chris@76: } Chris@76: Chris@76: if (isset($db_show_debug) && $db_show_debug === true) Chris@76: { Chris@76: // Commonly, undefined indexes will occur inside attributes; try to show them anyway! Chris@76: if ($error_level % 255 != E_ERROR) Chris@76: { Chris@76: $temporary = ob_get_contents(); Chris@76: if (substr($temporary, -2) == '="') Chris@76: echo '"'; Chris@76: } Chris@76: Chris@76: // Debugging! This should look like a PHP error message. Chris@76: echo '
Chris@76: ', $error_level % 255 == E_ERROR ? 'Error' : ($error_level % 255 == E_WARNING ? 'Warning' : 'Notice'), ': ', $error_string, ' in ', $file, ' on line ', $line, '
'; Chris@76: } Chris@76: Chris@76: $error_type = strpos(strtolower($error_string), 'undefined') !== false ? 'undefined_vars' : 'general'; Chris@76: Chris@76: $message = log_error($error_level . ': ' . $error_string, $error_type, $file, $line); Chris@76: Chris@76: // Let's give integrations a chance to ouput a bit differently Chris@76: call_integration_hook('integrate_output_error', array($message, $error_type, $error_level, $file, $line)); Chris@76: Chris@76: // Dying on these errors only causes MORE problems (blank pages!) Chris@76: if ($file == 'Unknown') Chris@76: return; Chris@76: Chris@76: // If this is an E_ERROR or E_USER_ERROR.... die. Violently so. Chris@76: if ($error_level % 255 == E_ERROR) Chris@76: obExit(false); Chris@76: else Chris@76: return; Chris@76: Chris@76: // If this is an E_ERROR, E_USER_ERROR, E_WARNING, or E_USER_WARNING.... die. Violently so. Chris@76: if ($error_level % 255 == E_ERROR || $error_level % 255 == E_WARNING) Chris@76: fatal_error(allowedTo('admin_forum') ? $message : $error_string, false); Chris@76: Chris@76: // We should NEVER get to this point. Any fatal error MUST quit, or very bad things can happen. Chris@76: if ($error_level % 255 == E_ERROR) Chris@76: die('Hacking attempt...'); Chris@76: } Chris@76: Chris@76: function setup_fatal_error_context($error_message) Chris@76: { Chris@76: global $context, $txt, $ssi_on_error_method; Chris@76: static $level = 0; Chris@76: Chris@76: // Attempt to prevent a recursive loop. Chris@76: ++$level; Chris@76: if ($level > 1) Chris@76: return false; Chris@76: Chris@76: // Maybe they came from dlattach or similar? Chris@76: if (SMF != 'SSI' && empty($context['theme_loaded'])) Chris@76: loadTheme(); Chris@76: Chris@76: // Don't bother indexing errors mate... Chris@76: $context['robot_no_index'] = true; Chris@76: Chris@76: if (!isset($context['error_title'])) Chris@76: $context['error_title'] = $txt['error_occured']; Chris@76: $context['error_message'] = isset($context['error_message']) ? $context['error_message'] : $error_message; Chris@76: Chris@76: if (empty($context['page_title'])) Chris@76: $context['page_title'] = $context['error_title']; Chris@76: Chris@76: // Display the error message - wireless? Chris@76: if (defined('WIRELESS') && WIRELESS) Chris@76: $context['sub_template'] = WIRELESS_PROTOCOL . '_error'; Chris@76: // Load the template and set the sub template. Chris@76: else Chris@76: { Chris@76: loadTemplate('Errors'); Chris@76: $context['sub_template'] = 'fatal_error'; Chris@76: } Chris@76: Chris@76: // If this is SSI, what do they want us to do? Chris@76: if (SMF == 'SSI') Chris@76: { Chris@76: if (!empty($ssi_on_error_method) && $ssi_on_error_method !== true && is_callable($ssi_on_error_method)) Chris@76: $ssi_on_error_method(); Chris@76: elseif (empty($ssi_on_error_method) || $ssi_on_error_method !== true) Chris@76: loadSubTemplate('fatal_error'); Chris@76: Chris@76: // No layers? Chris@76: if (empty($ssi_on_error_method) || $ssi_on_error_method !== true) Chris@76: exit; Chris@76: } Chris@76: Chris@76: // We want whatever for the header, and a footer. (footer includes sub template!) Chris@76: obExit(null, true, false, true); Chris@76: Chris@76: /* DO NOT IGNORE: Chris@76: If you are creating a bridge to SMF or modifying this function, you MUST Chris@76: make ABSOLUTELY SURE that this function quits and DOES NOT RETURN TO NORMAL Chris@76: PROGRAM FLOW. Otherwise, security error messages will not be shown, and Chris@76: your forum will be in a very easily hackable state. Chris@76: */ Chris@76: trigger_error('Hacking attempt...', E_USER_ERROR); Chris@76: } Chris@76: Chris@76: // Show an error message for the connection problems. Chris@76: function show_db_error($loadavg = false) Chris@76: { Chris@76: global $sourcedir, $mbname, $maintenance, $mtitle, $mmessage, $modSettings; Chris@76: global $db_connection, $webmaster_email, $db_last_error, $db_error_send, $smcFunc; Chris@76: Chris@76: // Just check we're not in any buffers, just in case. Chris@76: for ($i = ob_get_level(); $i > 0; $i--) Chris@76: @ob_end_clean(); Chris@76: Chris@76: // Don't cache this page! Chris@76: header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); Chris@76: header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); Chris@76: header('Cache-Control: no-cache'); Chris@76: Chris@76: // Send the right error codes. Chris@76: header('HTTP/1.1 503 Service Temporarily Unavailable'); Chris@76: header('Status: 503 Service Temporarily Unavailable'); Chris@76: header('Retry-After: 3600'); Chris@76: Chris@76: if ($loadavg == false) Chris@76: { Chris@76: // For our purposes, we're gonna want this on if at all possible. Chris@76: $modSettings['cache_enable'] = '1'; Chris@76: Chris@76: if (($temp = cache_get_data('db_last_error', 600)) !== null) Chris@76: $db_last_error = max($db_last_error, $temp); Chris@76: Chris@76: if ($db_last_error < time() - 3600 * 24 * 3 && empty($maintenance) && !empty($db_error_send)) Chris@76: { Chris@76: require_once($sourcedir . '/Subs-Admin.php'); Chris@76: Chris@76: // Avoid writing to the Settings.php file if at all possible; use shared memory instead. Chris@76: cache_put_data('db_last_error', time(), 600); Chris@76: if (($temp = cache_get_data('db_last_error', 600)) == null) Chris@76: updateLastDatabaseError(); Chris@76: Chris@76: // Language files aren't loaded yet :(. Chris@76: $db_error = @$smcFunc['db_error']($db_connection); Chris@76: @mail($webmaster_email, $mbname . ': SMF Database Error!', 'There has been a problem with the database!' . ($db_error == '' ? '' : "\n" . $smcFunc['db_title'] . ' reported:' . "\n" . $db_error) . "\n\n" . 'This is a notice email to let you know that SMF could not connect to the database, contact your host if this continues.'); Chris@76: } Chris@76: } Chris@76: Chris@76: if (!empty($maintenance)) Chris@76: echo ' Chris@76: Chris@76: Chris@76: Chris@76: ', $mtitle, ' Chris@76: Chris@76: Chris@76:

', $mtitle, '

Chris@76: ', $mmessage, ' Chris@76: Chris@76: '; Chris@76: // If this is a load average problem, display an appropriate message (but we still don't have language files!) Chris@76: elseif ($loadavg) Chris@76: echo ' Chris@76: Chris@76: Chris@76: Chris@76: Temporarily Unavailable Chris@76: Chris@76: Chris@76:

Temporarily Unavailable

Chris@76: Due to high stress on the server the forum is temporarily unavailable. Please try again later. Chris@76: Chris@76: '; Chris@76: // What to do? Language files haven't and can't be loaded yet... Chris@76: else Chris@76: echo ' Chris@76: Chris@76: Chris@76: Chris@76: Connection Problems Chris@76: Chris@76: Chris@76:

Connection Problems

Chris@76: Sorry, SMF was unable to connect to the database. This may be caused by the server being busy. Please try again later. Chris@76: Chris@76: '; Chris@76: Chris@76: die; Chris@76: } Chris@76: Chris@76: ?>