albertlast /
SMF2.1
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * The purpose of this file is... errors. (hard to guess, I guess?) It takes |
||
| 5 | * care of logging, error messages, error handling, database errors, and |
||
| 6 | * error log administration. |
||
| 7 | * |
||
| 8 | * Simple Machines Forum (SMF) |
||
| 9 | * |
||
| 10 | * @package SMF |
||
| 11 | * @author Simple Machines https://www.simplemachines.org |
||
| 12 | * @copyright 2025 Simple Machines and individual contributors |
||
| 13 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
| 14 | * |
||
| 15 | * @version 2.1.5 |
||
| 16 | */ |
||
| 17 | |||
| 18 | if (!defined('SMF')) |
||
| 19 | die('No direct access...'); |
||
| 20 | |||
| 21 | /** |
||
| 22 | * Log an error, if the error logging is enabled. |
||
| 23 | * filename and line should be __FILE__ and __LINE__, respectively. |
||
| 24 | * Example use: |
||
| 25 | * die(log_error($msg)); |
||
| 26 | * |
||
| 27 | * @param string $error_message The message to log |
||
| 28 | * @param string|bool $error_type The type of error |
||
| 29 | * @param string $file The name of the file where this error occurred |
||
| 30 | * @param int $line The line where the error occurred |
||
| 31 | * @return string The message that was logged |
||
| 32 | */ |
||
| 33 | function log_error($error_message, $error_type = 'general', $file = null, $line = null) |
||
| 34 | { |
||
| 35 | global $modSettings, $sc, $user_info, $smcFunc, $scripturl, $last_error, $context, $db_show_debug; |
||
| 36 | static $tried_hook = false; |
||
| 37 | static $error_call = 0; |
||
| 38 | |||
| 39 | $error_call++; |
||
| 40 | |||
| 41 | // Collect a backtrace |
||
| 42 | if (!isset($db_show_debug) || $db_show_debug === false) |
||
| 43 | $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); |
||
| 44 | else |
||
| 45 | $backtrace = debug_backtrace(); |
||
| 46 | |||
| 47 | // are we in a loop? |
||
| 48 | if ($error_call > 2) |
||
| 49 | { |
||
| 50 | var_dump($backtrace); |
||
|
0 ignored issues
–
show
Security
Debugging Code
introduced
by
Loading history...
|
|||
| 51 | die('Error loop.'); |
||
|
0 ignored issues
–
show
|
|||
| 52 | } |
||
| 53 | |||
| 54 | // Check if error logging is actually on. |
||
| 55 | if (empty($modSettings['enableErrorLogging'])) |
||
| 56 | return $error_message; |
||
| 57 | |||
| 58 | // Basically, htmlspecialchars it minus &. (for entities!) |
||
| 59 | $error_message = strtr($error_message, array('<' => '<', '>' => '>', '"' => '"')); |
||
| 60 | $error_message = strtr($error_message, array('<br />' => '<br>', '<br>' => '<br>', '<b>' => '<strong>', '</b>' => '</strong>', "\n" => '<br>')); |
||
| 61 | |||
| 62 | // Add a file and line to the error message? |
||
| 63 | // Don't use the actual txt entries for file and line but instead use %1$s for file and %2$s for line |
||
| 64 | if ($file == null) |
||
|
0 ignored issues
–
show
|
|||
| 65 | $file = ''; |
||
| 66 | else |
||
| 67 | // Windows style slashes don't play well, lets convert them to the unix style. |
||
| 68 | $file = str_replace('\\', '/', $file); |
||
| 69 | |||
| 70 | if ($line == null) |
||
|
0 ignored issues
–
show
|
|||
| 71 | $line = 0; |
||
| 72 | else |
||
| 73 | $line = (int) $line; |
||
| 74 | |||
| 75 | // Just in case there's no id_member or IP set yet. |
||
| 76 | if (empty($user_info['id'])) |
||
| 77 | $user_info['id'] = 0; |
||
| 78 | if (empty($user_info['ip'])) |
||
| 79 | $user_info['ip'] = ''; |
||
| 80 | |||
| 81 | // Find the best query string we can... |
||
| 82 | $query_string = empty($_SERVER['QUERY_STRING']) ? (empty($_SERVER['REQUEST_URL']) ? '' : str_replace($scripturl, '', $_SERVER['REQUEST_URL'])) : $_SERVER['QUERY_STRING']; |
||
| 83 | |||
| 84 | // Don't log the session hash in the url twice, it's a waste. |
||
| 85 | if (!empty($smcFunc['htmlspecialchars'])) |
||
| 86 | $query_string = $smcFunc['htmlspecialchars']((SMF == 'SSI' || SMF == 'BACKGROUND' ? '' : '?') . preg_replace(array('~;sesc=[^&;]+~', '~' . session_name() . '=' . session_id() . '[&;]~'), array(';sesc', ''), $query_string)); |
||
|
0 ignored issues
–
show
|
|||
| 87 | |||
| 88 | // Just so we know what board error messages are from. |
||
| 89 | if (isset($_POST['board']) && !isset($_GET['board'])) |
||
| 90 | $query_string .= ($query_string == '' ? 'board=' : ';board=') . $_POST['board']; |
||
| 91 | |||
| 92 | // What types of categories do we have? |
||
| 93 | $known_error_types = array( |
||
| 94 | 'general', |
||
| 95 | 'critical', |
||
| 96 | 'database', |
||
| 97 | 'undefined_vars', |
||
| 98 | 'user', |
||
| 99 | 'ban', |
||
| 100 | 'template', |
||
| 101 | 'debug', |
||
| 102 | 'cron', |
||
| 103 | 'paidsubs', |
||
| 104 | 'backup', |
||
| 105 | 'login', |
||
| 106 | ); |
||
| 107 | |||
| 108 | // This prevents us from infinite looping if the hook or call produces an error. |
||
| 109 | $other_error_types = array(); |
||
| 110 | if (empty($tried_hook)) |
||
| 111 | { |
||
| 112 | $tried_hook = true; |
||
| 113 | // Allow the hook to change the error_type and know about the error. |
||
| 114 | call_integration_hook('integrate_error_types', array(&$other_error_types, &$error_type, $error_message, $file, $line)); |
||
| 115 | $known_error_types = array_merge($known_error_types, $other_error_types); |
||
| 116 | } |
||
| 117 | // Make sure the category that was specified is a valid one |
||
| 118 | $error_type = in_array($error_type, $known_error_types) && $error_type !== true ? $error_type : 'general'; |
||
| 119 | |||
| 120 | // leave out the call to log_error |
||
| 121 | array_splice($backtrace, 0, 1); |
||
| 122 | $backtrace = !empty($smcFunc['json_encode']) ? $smcFunc['json_encode']($backtrace) : json_encode($backtrace); |
||
| 123 | |||
| 124 | // Don't log the same error countless times, as we can get in a cycle of depression... |
||
| 125 | $error_info = array($user_info['id'], time(), $user_info['ip'], $query_string, $error_message, (string) $sc, $error_type, $file, $line, $backtrace); |
||
| 126 | if (empty($last_error) || $last_error != $error_info) |
||
| 127 | { |
||
| 128 | // Insert the error into the database. |
||
| 129 | $smcFunc['db_error_insert']($error_info); |
||
| 130 | $last_error = $error_info; |
||
| 131 | |||
| 132 | // Get an error count, if necessary |
||
| 133 | if (!isset($context['num_errors'])) |
||
| 134 | { |
||
| 135 | $query = $smcFunc['db_query']('', ' |
||
| 136 | SELECT COUNT(*) |
||
| 137 | FROM {db_prefix}log_errors', |
||
| 138 | array() |
||
| 139 | ); |
||
| 140 | |||
| 141 | list($context['num_errors']) = $smcFunc['db_fetch_row']($query); |
||
| 142 | $smcFunc['db_free_result']($query); |
||
| 143 | } |
||
| 144 | else |
||
| 145 | $context['num_errors']++; |
||
| 146 | } |
||
| 147 | |||
| 148 | // reset error call |
||
| 149 | $error_call = 0; |
||
| 150 | |||
| 151 | // Return the message to make things simpler. |
||
| 152 | return $error_message; |
||
| 153 | } |
||
| 154 | |||
| 155 | /** |
||
| 156 | * An irrecoverable error. This function stops execution and displays an error message. |
||
| 157 | * It logs the error message if $log is specified. |
||
| 158 | * |
||
| 159 | * @param string $error The error message |
||
| 160 | * @param string|bool $log = 'general' What type of error to log this as (false to not log it)) |
||
| 161 | * @param int $status The HTTP status code associated with this error |
||
| 162 | */ |
||
| 163 | function fatal_error($error, $log = 'general', $status = 500) |
||
| 164 | { |
||
| 165 | global $txt; |
||
| 166 | |||
| 167 | // Send the appropriate HTTP status header - set this to 0 or false if you don't want to send one at all |
||
| 168 | if (!empty($status)) |
||
| 169 | send_http_status($status); |
||
| 170 | |||
| 171 | // We don't have $txt yet, but that's okay... |
||
| 172 | if (empty($txt)) |
||
| 173 | die($error); |
||
|
0 ignored issues
–
show
|
|||
| 174 | |||
| 175 | log_error_online($error); |
||
| 176 | setup_fatal_error_context($log ? log_error($error, $log) : $error); |
||
| 177 | } |
||
| 178 | |||
| 179 | /** |
||
| 180 | * Shows a fatal error with a message stored in the language file. |
||
| 181 | * |
||
| 182 | * This function stops execution and displays an error message by key. |
||
| 183 | * - uses the string with the error_message_key key. |
||
| 184 | * - logs the error in the forum's default language while displaying the error |
||
| 185 | * message in the user's language. |
||
| 186 | * - uses Errors language file and applies the $sprintf information if specified. |
||
| 187 | * - the information is logged if log is specified. |
||
| 188 | * |
||
| 189 | * @param string $error The error message |
||
| 190 | * @param string|false $log The type of error, or false to not log it |
||
| 191 | * @param array $sprintf An array of data to be sprintf()'d into the specified message |
||
| 192 | * @param int $status = false The HTTP status code associated with this error |
||
| 193 | */ |
||
| 194 | function fatal_lang_error($error, $log = 'general', $sprintf = array(), $status = 403) |
||
| 195 | { |
||
| 196 | global $txt, $language, $user_info, $context; |
||
| 197 | static $fatal_error_called = false; |
||
| 198 | |||
| 199 | // Ensure this is an array. |
||
| 200 | $sprintf = (array) $sprintf; |
||
| 201 | |||
| 202 | // Send the status header - set this to 0 or false if you don't want to send one at all |
||
| 203 | if (!empty($status)) |
||
| 204 | send_http_status($status); |
||
| 205 | |||
| 206 | // Try to load a theme if we don't have one. |
||
| 207 | if (empty($context['theme_loaded']) && empty($fatal_error_called)) |
||
| 208 | { |
||
| 209 | $fatal_error_called = true; |
||
| 210 | loadTheme(); |
||
| 211 | } |
||
| 212 | |||
| 213 | // Attempt to load the text string. |
||
| 214 | loadLanguage('Errors'); |
||
| 215 | if (empty($txt[$error])) |
||
| 216 | $error_message = $error; |
||
| 217 | else |
||
| 218 | $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); |
||
| 219 | |||
| 220 | // Send a custom header if we have a custom message. |
||
| 221 | if (isset($_REQUEST['js']) || isset($_REQUEST['xml']) || isset($_RQEUEST['ajax'])) |
||
|
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
| 222 | header('X-SMF-errormsg: ' . $error_message); |
||
| 223 | |||
| 224 | // If we have no theme stuff we can't have the language file... |
||
| 225 | if (empty($context['theme_loaded'])) |
||
| 226 | die($error); |
||
|
0 ignored issues
–
show
|
|||
| 227 | |||
| 228 | $reload_lang_file = true; |
||
| 229 | // Log the error in the forum's language, but don't waste the time if we aren't logging |
||
| 230 | if ($log) |
||
| 231 | { |
||
| 232 | loadLanguage('Errors', $language); |
||
| 233 | $reload_lang_file = $language != $user_info['language']; |
||
| 234 | if (empty($txt[$error])) |
||
| 235 | $error_message = $error; |
||
| 236 | else |
||
| 237 | $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); |
||
| 238 | log_error($error_message, $log); |
||
| 239 | } |
||
| 240 | |||
| 241 | // Load the language file, only if it needs to be reloaded |
||
| 242 | if ($reload_lang_file && !empty($txt[$error])) |
||
| 243 | { |
||
| 244 | loadLanguage('Errors'); |
||
| 245 | $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); |
||
| 246 | } |
||
| 247 | |||
| 248 | log_error_online($error, $sprintf); |
||
| 249 | setup_fatal_error_context($error_message, $error); |
||
| 250 | } |
||
| 251 | |||
| 252 | /** |
||
| 253 | * Handler for standard error messages, standard PHP error handler replacement. |
||
| 254 | * It dies with fatal_error() if the error_level matches with error_reporting. |
||
| 255 | * |
||
| 256 | * @param int $error_level A pre-defined error-handling constant (see {@link https://php.net/errorfunc.constants}) |
||
| 257 | * @param string $error_string The error message |
||
| 258 | * @param string $file The file where the error occurred |
||
| 259 | * @param int $line The line where the error occurred |
||
| 260 | */ |
||
| 261 | function smf_error_handler($error_level, $error_string, $file, $line) |
||
| 262 | { |
||
| 263 | global $settings, $modSettings, $db_show_debug; |
||
| 264 | |||
| 265 | // Error was suppressed with the @-operator. |
||
| 266 | if (error_reporting() == 0 || error_reporting() == (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) |
||
| 267 | return true; |
||
| 268 | |||
| 269 | // Ignore errors that should should not be logged. |
||
| 270 | $error_match = error_reporting() & $error_level; |
||
| 271 | if (empty($error_match) || empty($modSettings['enableErrorLogging'])) |
||
| 272 | return false; |
||
| 273 | |||
| 274 | if (strpos($file, 'eval()') !== false && !empty($settings['current_include_filename'])) |
||
| 275 | { |
||
| 276 | $array = debug_backtrace(); |
||
| 277 | $count = count($array); |
||
| 278 | for ($i = 0; $i < $count; $i++) |
||
| 279 | { |
||
| 280 | if ($array[$i]['function'] != 'loadSubTemplate') |
||
| 281 | continue; |
||
| 282 | |||
| 283 | // This is a bug in PHP, with eval, it seems! |
||
| 284 | if (empty($array[$i]['args'])) |
||
| 285 | $i++; |
||
| 286 | break; |
||
| 287 | } |
||
| 288 | |||
| 289 | if (isset($array[$i]) && !empty($array[$i]['args'])) |
||
| 290 | $file = realpath($settings['current_include_filename']) . ' (' . $array[$i]['args'][0] . ' sub template - eval?)'; |
||
| 291 | else |
||
| 292 | $file = realpath($settings['current_include_filename']) . ' (eval?)'; |
||
| 293 | } |
||
| 294 | |||
| 295 | if (isset($db_show_debug) && $db_show_debug === true) |
||
| 296 | { |
||
| 297 | // Commonly, undefined indexes will occur inside attributes; try to show them anyway! |
||
| 298 | if ($error_level % 255 != E_ERROR) |
||
| 299 | { |
||
| 300 | $temporary = ob_get_contents(); |
||
| 301 | if (substr($temporary, -2) == '="') |
||
| 302 | echo '"'; |
||
| 303 | } |
||
| 304 | |||
| 305 | // Debugging! This should look like a PHP error message. |
||
| 306 | echo '<br> |
||
| 307 | <strong>', $error_level % 255 == E_ERROR ? 'Error' : ($error_level % 255 == E_WARNING ? 'Warning' : 'Notice'), '</strong>: ', $error_string, ' in <strong>', $file, '</strong> on line <strong>', $line, '</strong><br>'; |
||
| 308 | } |
||
| 309 | |||
| 310 | $error_type = stripos($error_string, 'undefined') !== false ? 'undefined_vars' : 'general'; |
||
| 311 | |||
| 312 | $message = log_error($error_level . ': ' . $error_string, $error_type, $file, $line); |
||
| 313 | |||
| 314 | // Let's give integrations a chance to ouput a bit differently |
||
| 315 | call_integration_hook('integrate_output_error', array($message, $error_type, $error_level, $file, $line)); |
||
| 316 | |||
| 317 | // Dying on these errors only causes MORE problems (blank pages!) |
||
| 318 | if ($file == 'Unknown') |
||
| 319 | return; |
||
| 320 | |||
| 321 | // If this is an E_ERROR or E_USER_ERROR.... die. Violently so. |
||
| 322 | if ($error_level % 255 == E_ERROR) |
||
| 323 | obExit(false); |
||
| 324 | else |
||
| 325 | return; |
||
| 326 | |||
| 327 | // If this is an E_ERROR, E_USER_ERROR, E_WARNING, or E_USER_WARNING.... die. Violently so. |
||
| 328 | if ($error_level % 255 == E_ERROR || $error_level % 255 == E_WARNING) |
||
| 329 | fatal_error(allowedTo('admin_forum') ? $message : $error_string, false); |
||
| 330 | |||
| 331 | // We should NEVER get to this point. Any fatal error MUST quit, or very bad things can happen. |
||
| 332 | if ($error_level % 255 == E_ERROR) |
||
| 333 | die('No direct access...'); |
||
|
0 ignored issues
–
show
|
|||
| 334 | } |
||
| 335 | |||
| 336 | /** |
||
| 337 | * Generic handler for uncaught exceptions. |
||
| 338 | * |
||
| 339 | * Always ends execution. |
||
| 340 | * |
||
| 341 | * @param \Throwable $e The uncaught exception. |
||
| 342 | */ |
||
| 343 | function smf_exception_handler(\Throwable $e) |
||
| 344 | { |
||
| 345 | global $modSettings, $txt; |
||
| 346 | |||
| 347 | loadLanguage('Errors'); |
||
| 348 | |||
| 349 | $message = $txt[$e->getMessage()] ?? $e->getMessage(); |
||
| 350 | |||
| 351 | if (!empty($modSettings['enableErrorLogging'])) { |
||
| 352 | log_error($message, 'general', $e->getFile(), $e->getLine()); |
||
| 353 | } |
||
| 354 | |||
| 355 | fatal_error($message, false); |
||
| 356 | } |
||
| 357 | |||
| 358 | /** |
||
| 359 | * It is called by {@link fatal_error()} and {@link fatal_lang_error()}. |
||
| 360 | * |
||
| 361 | * @uses template_fatal_error() |
||
| 362 | * |
||
| 363 | * @param string $error_message The error message |
||
| 364 | * @param string $error_code An error code |
||
| 365 | * @return void|false Normally doesn't return anything, but returns false if a recursive loop is detected |
||
| 366 | */ |
||
| 367 | function setup_fatal_error_context($error_message, $error_code = null) |
||
| 368 | { |
||
| 369 | global $context, $txt, $ssi_on_error_method; |
||
| 370 | static $level = 0; |
||
| 371 | |||
| 372 | // Attempt to prevent a recursive loop. |
||
| 373 | ++$level; |
||
| 374 | if ($level > 1) |
||
| 375 | return false; |
||
| 376 | |||
| 377 | // Maybe they came from dlattach or similar? |
||
| 378 | if (SMF != 'SSI' && SMF != 'BACKGROUND' && empty($context['theme_loaded'])) |
||
|
0 ignored issues
–
show
|
|||
| 379 | loadTheme(); |
||
| 380 | |||
| 381 | // Don't bother indexing errors mate... |
||
| 382 | $context['robot_no_index'] = true; |
||
| 383 | |||
| 384 | if (!isset($context['error_title'])) |
||
| 385 | $context['error_title'] = $txt['error_occured']; |
||
| 386 | $context['error_message'] = isset($context['error_message']) ? $context['error_message'] : $error_message; |
||
| 387 | |||
| 388 | $context['error_code'] = isset($error_code) ? 'id="' . $error_code . '" ' : ''; |
||
| 389 | |||
| 390 | $context['error_link'] = isset($context['error_link']) ? $context['error_link'] : 'javascript:document.location=document.referrer'; |
||
| 391 | |||
| 392 | if (empty($context['page_title'])) |
||
| 393 | $context['page_title'] = $context['error_title']; |
||
| 394 | |||
| 395 | loadTemplate('Errors'); |
||
| 396 | $context['sub_template'] = 'fatal_error'; |
||
| 397 | |||
| 398 | // If this is SSI, what do they want us to do? |
||
| 399 | if (SMF == 'SSI') |
||
| 400 | { |
||
| 401 | if (!empty($ssi_on_error_method) && $ssi_on_error_method !== true && is_callable($ssi_on_error_method)) |
||
| 402 | $ssi_on_error_method(); |
||
| 403 | elseif (empty($ssi_on_error_method) || $ssi_on_error_method !== true) |
||
| 404 | loadSubTemplate('fatal_error'); |
||
| 405 | |||
| 406 | // No layers? |
||
| 407 | if (empty($ssi_on_error_method) || $ssi_on_error_method !== true) |
||
| 408 | exit; |
||
|
0 ignored issues
–
show
|
|||
| 409 | } |
||
| 410 | // Alternatively from the cron call? |
||
| 411 | elseif (SMF == 'BACKGROUND') |
||
| 412 | { |
||
| 413 | // We can't rely on even having language files available. |
||
| 414 | if (defined('FROM_CLI') && FROM_CLI) |
||
| 415 | echo 'cron error: ', $context['error_message']; |
||
| 416 | else |
||
| 417 | echo 'An error occurred. More information may be available in your logs.'; |
||
| 418 | exit; |
||
|
0 ignored issues
–
show
|
|||
| 419 | } |
||
| 420 | |||
| 421 | // We want whatever for the header, and a footer. (footer includes sub template!) |
||
| 422 | obExit(null, true, false, true); |
||
| 423 | |||
| 424 | /* DO NOT IGNORE: |
||
| 425 | If you are creating a bridge to SMF or modifying this function, you MUST |
||
| 426 | make ABSOLUTELY SURE that this function quits and DOES NOT RETURN TO NORMAL |
||
| 427 | PROGRAM FLOW. Otherwise, security error messages will not be shown, and |
||
| 428 | your forum will be in a very easily hackable state. |
||
| 429 | */ |
||
| 430 | die('No direct access...'); |
||
|
0 ignored issues
–
show
|
|||
| 431 | } |
||
| 432 | |||
| 433 | /** |
||
| 434 | * Show a message for the (full block) maintenance mode. |
||
| 435 | * It shows a complete page independent of language files or themes. |
||
| 436 | * It is used only if $maintenance = 2 in Settings.php. |
||
| 437 | * It stops further execution of the script. |
||
| 438 | */ |
||
| 439 | function display_maintenance_message() |
||
| 440 | { |
||
| 441 | global $maintenance, $mtitle, $mmessage; |
||
| 442 | |||
| 443 | set_fatal_error_headers(); |
||
| 444 | |||
| 445 | if (!empty($maintenance)) |
||
| 446 | echo '<!DOCTYPE html> |
||
| 447 | <html> |
||
| 448 | <head> |
||
| 449 | <meta name="robots" content="noindex"> |
||
| 450 | <title>', $mtitle, '</title> |
||
| 451 | </head> |
||
| 452 | <body> |
||
| 453 | <h3>', $mtitle, '</h3> |
||
| 454 | ', $mmessage, ' |
||
| 455 | </body> |
||
| 456 | </html>'; |
||
| 457 | |||
| 458 | die(); |
||
|
0 ignored issues
–
show
|
|||
| 459 | } |
||
| 460 | |||
| 461 | /** |
||
| 462 | * Show an error message for the connection problems. |
||
| 463 | * It shows a complete page independent of language files or themes. |
||
| 464 | * It is used only if there's no way to connect to the database. |
||
| 465 | * It stops further execution of the script. |
||
| 466 | */ |
||
| 467 | function display_db_error() |
||
| 468 | { |
||
| 469 | global $mbname, $modSettings, $maintenance; |
||
| 470 | global $db_connection, $webmaster_email, $db_last_error, $db_error_send, $smcFunc, $sourcedir, $cache_enable; |
||
| 471 | |||
| 472 | require_once($sourcedir . '/Logging.php'); |
||
| 473 | set_fatal_error_headers(); |
||
| 474 | |||
| 475 | // For our purposes, we're gonna want this on if at all possible. |
||
| 476 | $cache_enable = '1'; |
||
| 477 | |||
| 478 | if (($temp = cache_get_data('db_last_error', 600)) !== null) |
||
| 479 | $db_last_error = max($db_last_error, $temp); |
||
| 480 | |||
| 481 | if ($db_last_error < time() - 3600 * 24 * 3 && empty($maintenance) && !empty($db_error_send)) |
||
| 482 | { |
||
| 483 | // Avoid writing to the Settings.php file if at all possible; use shared memory instead. |
||
| 484 | cache_put_data('db_last_error', time(), 600); |
||
| 485 | if (($temp = cache_get_data('db_last_error', 600)) === null) |
||
|
0 ignored issues
–
show
|
|||
| 486 | logLastDatabaseError(); |
||
| 487 | |||
| 488 | // Language files aren't loaded yet :(. |
||
| 489 | $db_error = @$smcFunc['db_error']($db_connection); |
||
| 490 | @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.'); |
||
| 491 | } |
||
| 492 | |||
| 493 | // What to do? Language files haven't and can't be loaded yet... |
||
| 494 | echo '<!DOCTYPE html> |
||
| 495 | <html> |
||
| 496 | <head> |
||
| 497 | <meta name="robots" content="noindex"> |
||
| 498 | <title>Connection Problems</title> |
||
| 499 | </head> |
||
| 500 | <body> |
||
| 501 | <h3>Connection Problems</h3> |
||
| 502 | Sorry, SMF was unable to connect to the database. This may be caused by the server being busy. Please try again later. |
||
| 503 | </body> |
||
| 504 | </html>'; |
||
| 505 | |||
| 506 | die(); |
||
|
0 ignored issues
–
show
|
|||
| 507 | } |
||
| 508 | |||
| 509 | /** |
||
| 510 | * Show an error message for load average blocking problems. |
||
| 511 | * It shows a complete page independent of language files or themes. |
||
| 512 | * It is used only if the load averages are too high to continue execution. |
||
| 513 | * It stops further execution of the script. |
||
| 514 | */ |
||
| 515 | function display_loadavg_error() |
||
| 516 | { |
||
| 517 | // If this is a load average problem, display an appropriate message (but we still don't have language files!) |
||
| 518 | |||
| 519 | set_fatal_error_headers(); |
||
| 520 | |||
| 521 | echo '<!DOCTYPE html> |
||
| 522 | <html> |
||
| 523 | <head> |
||
| 524 | <meta name="robots" content="noindex"> |
||
| 525 | <title>Temporarily Unavailable</title> |
||
| 526 | </head> |
||
| 527 | <body> |
||
| 528 | <h3>Temporarily Unavailable</h3> |
||
| 529 | Due to high stress on the server the forum is temporarily unavailable. Please try again later. |
||
| 530 | </body> |
||
| 531 | </html>'; |
||
| 532 | |||
| 533 | die(); |
||
|
0 ignored issues
–
show
|
|||
| 534 | } |
||
| 535 | |||
| 536 | /** |
||
| 537 | * Small utility function for fatal error pages. |
||
| 538 | * Used by {@link display_db_error()}, {@link display_loadavg_error()}, |
||
| 539 | * {@link display_maintenance_message()} |
||
| 540 | */ |
||
| 541 | function set_fatal_error_headers() |
||
| 542 | { |
||
| 543 | if (headers_sent()) |
||
| 544 | return; |
||
| 545 | |||
| 546 | // Don't cache this page! |
||
| 547 | header('expires: Mon, 26 Jul 1997 05:00:00 GMT'); |
||
| 548 | header('last-modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); |
||
| 549 | header('cache-control: no-cache'); |
||
| 550 | |||
| 551 | // Send the right error codes. |
||
| 552 | send_http_status(503, 'Service Temporarily Unavailable'); |
||
| 553 | header('status: 503 Service Temporarily Unavailable'); |
||
| 554 | header('retry-after: 3600'); |
||
| 555 | } |
||
| 556 | |||
| 557 | /** |
||
| 558 | * Small utility function for fatal error pages. |
||
| 559 | * Used by fatal_error(), fatal_lang_error() |
||
| 560 | * |
||
| 561 | * @param string $error The error |
||
| 562 | * @param array $sprintf An array of data to be sprintf()'d into the specified message |
||
| 563 | */ |
||
| 564 | function log_error_online($error, $sprintf = array()) |
||
| 565 | { |
||
| 566 | global $smcFunc, $user_info, $modSettings; |
||
| 567 | |||
| 568 | // Don't bother if Who's Online is disabled. |
||
| 569 | if (empty($modSettings['who_enabled'])) |
||
| 570 | return; |
||
| 571 | |||
| 572 | // Maybe they came from SSI or similar where sessions are not recorded? |
||
| 573 | if (SMF == 'SSI' || SMF == 'BACKGROUND') |
||
|
0 ignored issues
–
show
|
|||
| 574 | return; |
||
| 575 | |||
| 576 | $session_id = !empty($user_info['is_guest']) ? 'ip' . $user_info['ip'] : session_id(); |
||
| 577 | |||
| 578 | // First, we have to get the online log, because we need to break apart the serialized string. |
||
| 579 | $request = $smcFunc['db_query']('', ' |
||
| 580 | SELECT url |
||
| 581 | FROM {db_prefix}log_online |
||
| 582 | WHERE session = {string:session}', |
||
| 583 | array( |
||
| 584 | 'session' => $session_id, |
||
| 585 | ) |
||
| 586 | ); |
||
| 587 | if ($smcFunc['db_num_rows']($request) != 0) |
||
| 588 | { |
||
| 589 | // If this happened very early on in SMF startup, $smcFunc may not fully be defined. |
||
| 590 | if (!isset($smcFunc['json_decode'])) |
||
| 591 | { |
||
| 592 | $smcFunc['json_decode'] = 'smf_json_decode'; |
||
| 593 | $smcFunc['json_encode'] = 'json_encode'; |
||
| 594 | } |
||
| 595 | |||
| 596 | list ($url) = $smcFunc['db_fetch_row']($request); |
||
| 597 | $url = $smcFunc['json_decode']($url, true); |
||
| 598 | $url['error'] = $error; |
||
| 599 | // Url field got a max length of 1024 in db |
||
| 600 | if (strlen($url['error']) > 500) |
||
| 601 | $url['error'] = substr($url['error'], 0, 500); |
||
| 602 | |||
| 603 | if (!empty($sprintf)) |
||
| 604 | $url['error_params'] = $sprintf; |
||
| 605 | |||
| 606 | $smcFunc['db_query']('', ' |
||
| 607 | UPDATE {db_prefix}log_online |
||
| 608 | SET url = {string:url} |
||
| 609 | WHERE session = {string:session}', |
||
| 610 | array( |
||
| 611 | 'url' => $smcFunc['json_encode']($url), |
||
| 612 | 'session' => $session_id, |
||
| 613 | ) |
||
| 614 | ); |
||
| 615 | } |
||
| 616 | $smcFunc['db_free_result']($request); |
||
| 617 | } |
||
| 618 | |||
| 619 | ?> |