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 2022 Simple Machines and individual contributors |
||
13 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
14 | * |
||
15 | * @version 2.1.2 |
||
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
![]() |
|||
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 += $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 | // If we have no theme stuff we can't have the language file... |
||
214 | if (empty($context['theme_loaded'])) |
||
215 | die($error); |
||
0 ignored issues
–
show
|
|||
216 | |||
217 | $reload_lang_file = true; |
||
218 | // Log the error in the forum's language, but don't waste the time if we aren't logging |
||
219 | if ($log) |
||
220 | { |
||
221 | loadLanguage('Errors', $language); |
||
222 | $reload_lang_file = $language != $user_info['language']; |
||
223 | if (empty($txt[$error])) |
||
224 | $error_message = $error; |
||
225 | else |
||
226 | $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); |
||
227 | log_error($error_message, $log); |
||
228 | } |
||
229 | |||
230 | // Load the language file, only if it needs to be reloaded |
||
231 | if ($reload_lang_file) |
||
0 ignored issues
–
show
|
|||
232 | { |
||
233 | loadLanguage('Errors'); |
||
234 | $error_message = empty($sprintf) ? $txt[$error] : vsprintf($txt[$error], $sprintf); |
||
235 | } |
||
236 | |||
237 | log_error_online($error, $sprintf); |
||
238 | setup_fatal_error_context($error_message, $error); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
239 | } |
||
240 | |||
241 | /** |
||
242 | * Handler for standard error messages, standard PHP error handler replacement. |
||
243 | * It dies with fatal_error() if the error_level matches with error_reporting. |
||
244 | * |
||
245 | * @param int $error_level A pre-defined error-handling constant (see {@link https://php.net/errorfunc.constants}) |
||
246 | * @param string $error_string The error message |
||
247 | * @param string $file The file where the error occurred |
||
248 | * @param int $line The line where the error occurred |
||
249 | */ |
||
250 | function smf_error_handler($error_level, $error_string, $file, $line) |
||
251 | { |
||
252 | global $settings, $modSettings, $db_show_debug; |
||
253 | |||
254 | // Error was suppressed with the @-operator. |
||
255 | if (error_reporting() == 0 || error_reporting() == (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR)) |
||
256 | return true; |
||
257 | |||
258 | // Ignore errors that should should not be logged. |
||
259 | $error_match = error_reporting() & $error_level; |
||
260 | if (empty($error_match) || empty($modSettings['enableErrorLogging'])) |
||
261 | return false; |
||
262 | |||
263 | if (strpos($file, 'eval()') !== false && !empty($settings['current_include_filename'])) |
||
264 | { |
||
265 | $array = debug_backtrace(); |
||
266 | $count = count($array); |
||
267 | for ($i = 0; $i < $count; $i++) |
||
268 | { |
||
269 | if ($array[$i]['function'] != 'loadSubTemplate') |
||
270 | continue; |
||
271 | |||
272 | // This is a bug in PHP, with eval, it seems! |
||
273 | if (empty($array[$i]['args'])) |
||
274 | $i++; |
||
275 | break; |
||
276 | } |
||
277 | |||
278 | if (isset($array[$i]) && !empty($array[$i]['args'])) |
||
279 | $file = realpath($settings['current_include_filename']) . ' (' . $array[$i]['args'][0] . ' sub template - eval?)'; |
||
280 | else |
||
281 | $file = realpath($settings['current_include_filename']) . ' (eval?)'; |
||
282 | } |
||
283 | |||
284 | if (isset($db_show_debug) && $db_show_debug === true) |
||
285 | { |
||
286 | // Commonly, undefined indexes will occur inside attributes; try to show them anyway! |
||
287 | if ($error_level % 255 != E_ERROR) |
||
288 | { |
||
289 | $temporary = ob_get_contents(); |
||
290 | if (substr($temporary, -2) == '="') |
||
291 | echo '"'; |
||
292 | } |
||
293 | |||
294 | // Debugging! This should look like a PHP error message. |
||
295 | echo '<br> |
||
296 | <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>'; |
||
297 | } |
||
298 | |||
299 | $error_type = stripos($error_string, 'undefined') !== false ? 'undefined_vars' : 'general'; |
||
300 | |||
301 | $message = log_error($error_level . ': ' . $error_string, $error_type, $file, $line); |
||
302 | |||
303 | // Let's give integrations a chance to ouput a bit differently |
||
304 | call_integration_hook('integrate_output_error', array($message, $error_type, $error_level, $file, $line)); |
||
305 | |||
306 | // Dying on these errors only causes MORE problems (blank pages!) |
||
307 | if ($file == 'Unknown') |
||
308 | return; |
||
309 | |||
310 | // If this is an E_ERROR or E_USER_ERROR.... die. Violently so. |
||
311 | if ($error_level % 255 == E_ERROR) |
||
312 | obExit(false); |
||
313 | else |
||
314 | return; |
||
315 | |||
316 | // If this is an E_ERROR, E_USER_ERROR, E_WARNING, or E_USER_WARNING.... die. Violently so. |
||
317 | if ($error_level % 255 == E_ERROR || $error_level % 255 == E_WARNING) |
||
318 | fatal_error(allowedTo('admin_forum') ? $message : $error_string, false); |
||
319 | |||
320 | // We should NEVER get to this point. Any fatal error MUST quit, or very bad things can happen. |
||
321 | if ($error_level % 255 == E_ERROR) |
||
322 | die('No direct access...'); |
||
0 ignored issues
–
show
|
|||
323 | } |
||
324 | |||
325 | /** |
||
326 | * It is called by {@link fatal_error()} and {@link fatal_lang_error()}. |
||
327 | * |
||
328 | * @uses template_fatal_error() |
||
329 | * |
||
330 | * @param string $error_message The error message |
||
331 | * @param string $error_code An error code |
||
332 | * @return void|false Normally doesn't return anything, but returns false if a recursive loop is detected |
||
333 | */ |
||
334 | function setup_fatal_error_context($error_message, $error_code = null) |
||
335 | { |
||
336 | global $context, $txt, $ssi_on_error_method; |
||
337 | static $level = 0; |
||
338 | |||
339 | // Attempt to prevent a recursive loop. |
||
340 | ++$level; |
||
341 | if ($level > 1) |
||
342 | return false; |
||
343 | |||
344 | // Maybe they came from dlattach or similar? |
||
345 | if (SMF != 'SSI' && SMF != 'BACKGROUND' && empty($context['theme_loaded'])) |
||
0 ignored issues
–
show
|
|||
346 | loadTheme(); |
||
347 | |||
348 | // Don't bother indexing errors mate... |
||
349 | $context['robot_no_index'] = true; |
||
350 | |||
351 | if (!isset($context['error_title'])) |
||
352 | $context['error_title'] = $txt['error_occured']; |
||
353 | $context['error_message'] = isset($context['error_message']) ? $context['error_message'] : $error_message; |
||
354 | |||
355 | $context['error_code'] = isset($error_code) ? 'id="' . $error_code . '" ' : ''; |
||
356 | |||
357 | $context['error_link'] = isset($context['error_link']) ? $context['error_link'] : 'javascript:document.location=document.referrer'; |
||
358 | |||
359 | if (empty($context['page_title'])) |
||
360 | $context['page_title'] = $context['error_title']; |
||
361 | |||
362 | loadTemplate('Errors'); |
||
363 | $context['sub_template'] = 'fatal_error'; |
||
364 | |||
365 | // If this is SSI, what do they want us to do? |
||
366 | if (SMF == 'SSI') |
||
367 | { |
||
368 | if (!empty($ssi_on_error_method) && $ssi_on_error_method !== true && is_callable($ssi_on_error_method)) |
||
369 | $ssi_on_error_method(); |
||
370 | elseif (empty($ssi_on_error_method) || $ssi_on_error_method !== true) |
||
371 | loadSubTemplate('fatal_error'); |
||
372 | |||
373 | // No layers? |
||
374 | if (empty($ssi_on_error_method) || $ssi_on_error_method !== true) |
||
375 | exit; |
||
0 ignored issues
–
show
|
|||
376 | } |
||
377 | // Alternatively from the cron call? |
||
378 | elseif (SMF == 'BACKGROUND') |
||
379 | { |
||
380 | // We can't rely on even having language files available. |
||
381 | if (defined('FROM_CLI') && FROM_CLI) |
||
382 | echo 'cron error: ', $context['error_message']; |
||
383 | else |
||
384 | echo 'An error occurred. More information may be available in your logs.'; |
||
385 | exit; |
||
0 ignored issues
–
show
|
|||
386 | } |
||
387 | |||
388 | // We want whatever for the header, and a footer. (footer includes sub template!) |
||
389 | obExit(null, true, false, true); |
||
390 | |||
391 | /* DO NOT IGNORE: |
||
392 | If you are creating a bridge to SMF or modifying this function, you MUST |
||
393 | make ABSOLUTELY SURE that this function quits and DOES NOT RETURN TO NORMAL |
||
394 | PROGRAM FLOW. Otherwise, security error messages will not be shown, and |
||
395 | your forum will be in a very easily hackable state. |
||
396 | */ |
||
397 | trigger_error('No direct access...', E_USER_ERROR); |
||
398 | } |
||
399 | |||
400 | /** |
||
401 | * Show a message for the (full block) maintenance mode. |
||
402 | * It shows a complete page independent of language files or themes. |
||
403 | * It is used only if $maintenance = 2 in Settings.php. |
||
404 | * It stops further execution of the script. |
||
405 | */ |
||
406 | function display_maintenance_message() |
||
407 | { |
||
408 | global $maintenance, $mtitle, $mmessage; |
||
409 | |||
410 | set_fatal_error_headers(); |
||
411 | |||
412 | if (!empty($maintenance)) |
||
413 | echo '<!DOCTYPE html> |
||
414 | <html> |
||
415 | <head> |
||
416 | <meta name="robots" content="noindex"> |
||
417 | <title>', $mtitle, '</title> |
||
418 | </head> |
||
419 | <body> |
||
420 | <h3>', $mtitle, '</h3> |
||
421 | ', $mmessage, ' |
||
422 | </body> |
||
423 | </html>'; |
||
424 | |||
425 | die(); |
||
0 ignored issues
–
show
|
|||
426 | } |
||
427 | |||
428 | /** |
||
429 | * Show an error message for the connection problems. |
||
430 | * It shows a complete page independent of language files or themes. |
||
431 | * It is used only if there's no way to connect to the database. |
||
432 | * It stops further execution of the script. |
||
433 | */ |
||
434 | function display_db_error() |
||
435 | { |
||
436 | global $mbname, $modSettings, $maintenance; |
||
437 | global $db_connection, $webmaster_email, $db_last_error, $db_error_send, $smcFunc, $sourcedir, $cache_enable; |
||
438 | |||
439 | require_once($sourcedir . '/Logging.php'); |
||
440 | set_fatal_error_headers(); |
||
441 | |||
442 | // For our purposes, we're gonna want this on if at all possible. |
||
443 | $cache_enable = '1'; |
||
444 | |||
445 | if (($temp = cache_get_data('db_last_error', 600)) !== null) |
||
446 | $db_last_error = max($db_last_error, $temp); |
||
447 | |||
448 | if ($db_last_error < time() - 3600 * 24 * 3 && empty($maintenance) && !empty($db_error_send)) |
||
449 | { |
||
450 | // Avoid writing to the Settings.php file if at all possible; use shared memory instead. |
||
451 | cache_put_data('db_last_error', time(), 600); |
||
452 | if (($temp = cache_get_data('db_last_error', 600)) === null) |
||
0 ignored issues
–
show
|
|||
453 | logLastDatabaseError(); |
||
454 | |||
455 | // Language files aren't loaded yet :(. |
||
456 | $db_error = @$smcFunc['db_error']($db_connection); |
||
457 | @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.'); |
||
458 | } |
||
459 | |||
460 | // What to do? Language files haven't and can't be loaded yet... |
||
461 | echo '<!DOCTYPE html> |
||
462 | <html> |
||
463 | <head> |
||
464 | <meta name="robots" content="noindex"> |
||
465 | <title>Connection Problems</title> |
||
466 | </head> |
||
467 | <body> |
||
468 | <h3>Connection Problems</h3> |
||
469 | Sorry, SMF was unable to connect to the database. This may be caused by the server being busy. Please try again later. |
||
470 | </body> |
||
471 | </html>'; |
||
472 | |||
473 | die(); |
||
0 ignored issues
–
show
|
|||
474 | } |
||
475 | |||
476 | /** |
||
477 | * Show an error message for load average blocking problems. |
||
478 | * It shows a complete page independent of language files or themes. |
||
479 | * It is used only if the load averages are too high to continue execution. |
||
480 | * It stops further execution of the script. |
||
481 | */ |
||
482 | function display_loadavg_error() |
||
483 | { |
||
484 | // If this is a load average problem, display an appropriate message (but we still don't have language files!) |
||
485 | |||
486 | set_fatal_error_headers(); |
||
487 | |||
488 | echo '<!DOCTYPE html> |
||
489 | <html> |
||
490 | <head> |
||
491 | <meta name="robots" content="noindex"> |
||
492 | <title>Temporarily Unavailable</title> |
||
493 | </head> |
||
494 | <body> |
||
495 | <h3>Temporarily Unavailable</h3> |
||
496 | Due to high stress on the server the forum is temporarily unavailable. Please try again later. |
||
497 | </body> |
||
498 | </html>'; |
||
499 | |||
500 | die(); |
||
0 ignored issues
–
show
|
|||
501 | } |
||
502 | |||
503 | /** |
||
504 | * Small utility function for fatal error pages. |
||
505 | * Used by {@link display_db_error()}, {@link display_loadavg_error()}, |
||
506 | * {@link display_maintenance_message()} |
||
507 | */ |
||
508 | function set_fatal_error_headers() |
||
509 | { |
||
510 | if (headers_sent()) |
||
511 | return; |
||
512 | |||
513 | // Don't cache this page! |
||
514 | header('expires: Mon, 26 Jul 1997 05:00:00 GMT'); |
||
515 | header('last-modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); |
||
516 | header('cache-control: no-cache'); |
||
517 | |||
518 | // Send the right error codes. |
||
519 | send_http_status(503, 'Service Temporarily Unavailable'); |
||
520 | header('status: 503 Service Temporarily Unavailable'); |
||
521 | header('retry-after: 3600'); |
||
522 | } |
||
523 | |||
524 | /** |
||
525 | * Small utility function for fatal error pages. |
||
526 | * Used by fatal_error(), fatal_lang_error() |
||
527 | * |
||
528 | * @param string $error The error |
||
529 | * @param array $sprintf An array of data to be sprintf()'d into the specified message |
||
530 | */ |
||
531 | function log_error_online($error, $sprintf = array()) |
||
532 | { |
||
533 | global $smcFunc, $user_info, $modSettings; |
||
534 | |||
535 | // Don't bother if Who's Online is disabled. |
||
536 | if (empty($modSettings['who_enabled'])) |
||
537 | return; |
||
538 | |||
539 | // Maybe they came from SSI or similar where sessions are not recorded? |
||
540 | if (SMF == 'SSI' || SMF == 'BACKGROUND') |
||
0 ignored issues
–
show
|
|||
541 | return; |
||
542 | |||
543 | $session_id = !empty($user_info['is_guest']) ? 'ip' . $user_info['ip'] : session_id(); |
||
544 | |||
545 | // First, we have to get the online log, because we need to break apart the serialized string. |
||
546 | $request = $smcFunc['db_query']('', ' |
||
547 | SELECT url |
||
548 | FROM {db_prefix}log_online |
||
549 | WHERE session = {string:session}', |
||
550 | array( |
||
551 | 'session' => $session_id, |
||
552 | ) |
||
553 | ); |
||
554 | if ($smcFunc['db_num_rows']($request) != 0) |
||
555 | { |
||
556 | // If this happened very early on in SMF startup, $smcFunc may not fully be defined. |
||
557 | if (!isset($smcFunc['json_decode'])) |
||
558 | { |
||
559 | $smcFunc['json_decode'] = 'smf_json_decode'; |
||
560 | $smcFunc['json_encode'] = 'json_encode'; |
||
561 | } |
||
562 | |||
563 | list ($url) = $smcFunc['db_fetch_row']($request); |
||
564 | $url = $smcFunc['json_decode']($url, true); |
||
565 | $url['error'] = $error; |
||
566 | // Url field got a max length of 1024 in db |
||
567 | if (strlen($url['error']) > 500) |
||
568 | $url['error'] = substr($url['error'], 0, 500); |
||
569 | |||
570 | if (!empty($sprintf)) |
||
571 | $url['error_params'] = $sprintf; |
||
572 | |||
573 | $smcFunc['db_query']('', ' |
||
574 | UPDATE {db_prefix}log_online |
||
575 | SET url = {string:url} |
||
576 | WHERE session = {string:session}', |
||
577 | array( |
||
578 | 'url' => $smcFunc['json_encode']($url), |
||
579 | 'session' => $session_id, |
||
580 | ) |
||
581 | ); |
||
582 | } |
||
583 | $smcFunc['db_free_result']($request); |
||
584 | } |
||
585 | |||
586 | ?> |