1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/* |
3
|
|
|
* debug.php :: Clase Debug, maneja reporte de eventos |
4
|
|
|
* |
5
|
|
|
* V4.0 copyright 2010-2011 by Gorlum for http://supernova.ws |
6
|
|
|
* [!] Merged `errors` to `logs` |
7
|
|
|
* [+] Now debugger can work with database detached. All messages would be dumped to page |
8
|
|
|
* [+] Now `logs` has both human-readable and machine-readable fields |
9
|
|
|
* |
10
|
|
|
* V3.0 copyright 2010 by Gorlum for http://supernova.ws |
11
|
|
|
* [+] Full rewrtie & optimize |
12
|
|
|
* [*] Now there is fallback procedure if no link to db detected |
13
|
|
|
* |
14
|
|
|
* V2.0 copyright 2010 by Gorlum for http://supernova.ws |
15
|
|
|
* [*] Now error also contains backtrace - to see exact way problem comes |
16
|
|
|
* [*] New method 'warning' sends message to dedicated SQL-table for non-errors |
17
|
|
|
* |
18
|
|
|
* V1.0 Created by Perberos. All rights reversed (C) 2006 |
19
|
|
|
* |
20
|
|
|
* Experiment code!!! |
21
|
|
|
* |
22
|
|
|
* vamos a experimentar >:) |
23
|
|
|
* le veo futuro a las classes, ayudaria mucho a tener un codigo mas ordenado... |
24
|
|
|
* que esperabas!!! soy newbie!!! D':< |
25
|
|
|
*/ |
26
|
|
|
|
27
|
|
|
if(!defined('INSIDE')) { |
28
|
|
|
die("attemp hacking"); |
29
|
|
|
} |
30
|
|
|
|
31
|
|
|
class debug { |
|
|
|
|
32
|
|
|
var $log, $numqueries; |
|
|
|
|
33
|
|
|
var $log_array; |
|
|
|
|
34
|
|
|
|
35
|
|
|
private $log_file_handler = null; |
36
|
|
|
|
37
|
|
|
function log_file($message, $ident_change = 0) { |
38
|
|
|
static $ident = 0; |
39
|
|
|
|
40
|
|
|
if(!defined('SN_DEBUG_LOG')) { |
41
|
|
|
return; |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
if($this->log_file_handler === null) { |
45
|
|
|
$this->log_file_handler = @fopen(SN_ROOT_PHYSICAL . '/.logs/supernova.log', 'a+'); |
46
|
|
|
@fwrite($this->log_file_handler, "\r\n\r\n"); |
|
|
|
|
47
|
|
|
} |
48
|
|
|
$ident_change < 0 ? $ident += $ident_change * 2 : false; |
49
|
|
|
if($this->log_file_handler) { |
50
|
|
|
@fwrite($this->log_file_handler, date(FMT_DATE_TIME_SQL, time()) . str_repeat(' ', $ident + 1) . $message . "\r\n"); |
51
|
|
|
} |
52
|
|
|
$ident_change > 0 ? $ident += $ident_change * 2 : false; |
53
|
|
|
} |
54
|
|
|
|
55
|
|
|
public function __construct() { |
56
|
|
|
$this->vars = $this->log = ''; |
|
|
|
|
57
|
|
|
$this->numqueries = 0; |
58
|
|
|
} |
59
|
|
|
|
60
|
|
|
function add($mes) { |
|
|
|
|
61
|
|
|
$this->log .= $mes; |
62
|
|
|
$this->numqueries++; |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
function add_to_array($mes) { |
|
|
|
|
66
|
|
|
$this->log_array[] = $mes; |
67
|
|
|
} |
68
|
|
|
|
69
|
|
|
function echo_log() { |
|
|
|
|
70
|
|
|
echo '<br><table><tr><td class=k colspan=4><a href="' . SN_ROOT_PHYSICAL . "admin/settings.php\">Debug Log</a>:</td></tr>{$this->log}</table>"; |
71
|
|
|
die(); |
|
|
|
|
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
function compact_backtrace($backtrace, $long_comment = false) { |
|
|
|
|
75
|
|
|
static $exclude_functions = array( |
76
|
|
|
// 'doquery', |
|
|
|
|
77
|
|
|
// 'db_query_select', 'db_query_delete', 'db_query_insert', 'db_query_update', |
78
|
|
|
// 'db_get_record_list', 'db_user_by_id', 'db_get_user_by_id' |
79
|
|
|
); |
80
|
|
|
|
81
|
|
|
$result = array(); |
82
|
|
|
$transaction_id = SN::db_transaction_check(false) ? SN::$transaction_id : SN::$transaction_id++; |
83
|
|
|
$result[] = "tID {$transaction_id}"; |
84
|
|
|
foreach($backtrace as $a_trace) { |
85
|
|
|
if(in_array($a_trace['function'], $exclude_functions)) { |
86
|
|
|
continue; |
87
|
|
|
} |
88
|
|
|
$function = |
89
|
|
|
(!empty($a_trace['type']) |
90
|
|
|
? ($a_trace['type'] == '->' |
91
|
|
|
? "({$a_trace['class']})" . get_class($a_trace['object']) |
92
|
|
|
: $a_trace['class'] |
93
|
|
|
) . $a_trace['type'] |
94
|
|
|
: '' |
95
|
|
|
) . $a_trace['function'] . '()'; |
96
|
|
|
|
97
|
|
|
$file = str_replace(SN_ROOT_PHYSICAL, '', str_replace('\\', '/', !empty($a_trace['file']) ? $a_trace['file'] : '')); |
98
|
|
|
|
99
|
|
|
$line = !empty($a_trace['line']) ? $a_trace['line'] : '_UNDEFINED_'; |
100
|
|
|
$result[] = "{$function} - '{$file}' Line {$line}"; |
101
|
|
|
|
102
|
|
|
if(!$long_comment) { |
103
|
|
|
break; |
104
|
|
|
} |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
return $result; |
108
|
|
|
} |
109
|
|
|
|
110
|
|
|
function dump($dump = false, $force_base = false, $deadlock = false) { |
|
|
|
|
111
|
|
|
if($dump === false) { |
112
|
|
|
return; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
$error_backtrace = array(); |
116
|
|
|
$base_dump = false; |
117
|
|
|
|
118
|
|
|
if($force_base === true) { |
119
|
|
|
$base_dump = true; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
if($dump === true) { |
123
|
|
|
$base_dump = true; |
124
|
|
|
} else { |
125
|
|
|
if(!is_array($dump)) { |
126
|
|
|
$dump = array('var' => $dump); |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
foreach($dump as $dump_var_name => $dump_var) { |
130
|
|
|
if($dump_var_name == 'base_dump') { |
131
|
|
|
$base_dump = $dump_var; |
132
|
|
|
} else { |
133
|
|
|
$error_backtrace[$dump_var_name] = $dump_var; |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
if($deadlock && ($q = db_fetch(SN::$db->mysql_get_innodb_status()))) { |
|
|
|
|
139
|
|
|
$error_backtrace['deadlock'] = explode("\n", $q['Status']); |
140
|
|
|
$error_backtrace['locks'] = _SnCacheInternal::$locks; |
141
|
|
|
$error_backtrace['cSN_data'] = _SnCacheInternal::$data; |
142
|
|
|
foreach($error_backtrace['cSN_data'] as &$location) { |
143
|
|
|
foreach($location as $location_id => &$location_data) // $location_data = $location_id; |
|
|
|
|
144
|
|
|
{ |
145
|
|
|
$location_data = isset($location_data['username']) ? $location_data['username'] : |
146
|
|
|
(isset($location_data['name']) ? $location_data['name'] : $location_id); |
147
|
|
|
} |
148
|
|
|
} |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
if($base_dump) { |
152
|
|
|
if(!is_array($this->log_array) || empty($this->log_array)) { |
153
|
|
|
$this->log_array = []; |
154
|
|
|
} else { |
155
|
|
|
foreach($this->log_array as $log) { |
156
|
|
|
$error_backtrace['queries'][] = $log; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
$error_backtrace['backtrace'] = debug_backtrace(); |
161
|
|
|
unset($error_backtrace['backtrace'][1]); |
162
|
|
|
unset($error_backtrace['backtrace'][0]); |
163
|
|
|
|
164
|
|
|
// Converting object instances to object names |
165
|
|
|
|
166
|
|
|
foreach ($error_backtrace['backtrace'] as &$backtrace) { |
167
|
|
|
if(is_object($backtrace['object'])) { |
168
|
|
|
$backtrace['object'] = get_class($backtrace['object']); |
169
|
|
|
} |
170
|
|
|
|
171
|
|
|
if(empty($backtrace['args'])) { |
172
|
|
|
continue; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
// Doing same conversion for backtrace params |
176
|
|
|
foreach($backtrace['args'] as &$arg) { |
177
|
|
|
if(is_object($arg)) { |
178
|
|
|
$arg = 'object::' . get_class($arg); |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
// $error_backtrace['query_log'] = "\r\n\r\nQuery log\r\n<table><tr><th>Number</th><th>Query</th><th>Page</th><th>Table</th><th>Rows</th></tr>{$this->log}</table>\r\n"; |
|
|
|
|
184
|
|
|
$error_backtrace['$_GET'] = $_GET; |
185
|
|
|
$error_backtrace['$_POST'] = $_POST; |
186
|
|
|
$error_backtrace['$_REQUEST'] = $_REQUEST; |
187
|
|
|
$error_backtrace['$_COOKIE'] = $_COOKIE; |
188
|
|
|
$error_backtrace['$_SESSION'] = $_SESSION; |
189
|
|
|
$error_backtrace['$_SERVER'] = $_SERVER; |
190
|
|
|
global $user, $planetrow; |
|
|
|
|
191
|
|
|
$error_backtrace['user'] = $user; |
192
|
|
|
$error_backtrace['planetrow'] = $planetrow; |
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
return $error_backtrace; |
196
|
|
|
} |
197
|
|
|
|
198
|
|
|
function error_fatal($die_message, $details = 'There is a fatal error on page') { |
|
|
|
|
199
|
|
|
// TODO - Записывать детали ошибки в лог-файл |
200
|
|
|
die($die_message); |
|
|
|
|
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
function error($message = 'There is a error on page', $title = 'Internal Error', $error_code = 500, $dump = true) { |
|
|
|
|
204
|
|
|
global $config, $sys_stop_log_hit, $lang, $sys_log_disabled, $user; |
|
|
|
|
205
|
|
|
|
206
|
|
|
if(empty(SN::$db->connected)) { |
207
|
|
|
// TODO - писать ошибку в файл |
208
|
|
|
die('SQL server currently unavailable. Please contact Administration...'); |
|
|
|
|
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
sn_db_transaction_rollback(); |
212
|
|
|
|
213
|
|
|
if(SN::$config->debug == 1) { |
|
|
|
|
214
|
|
|
echo "<h2>{$title}</h2><br><font color=red>" . htmlspecialchars($message) . "</font><br><hr>"; |
215
|
|
|
echo "<table>{$this->log}</table>"; |
216
|
|
|
} |
217
|
|
|
|
218
|
|
|
$fatal_error = 'Fatal error: cannot write to `logs` table. Please contact Administration...'; |
219
|
|
|
|
220
|
|
|
$error_text = db_escape($message); |
221
|
|
|
$error_backtrace = $this->dump($dump, true, strpos($message, 'Deadlock') !== false); |
222
|
|
|
|
223
|
|
|
if(!$sys_log_disabled) { |
224
|
|
|
$query = "INSERT INTO `{{logs}}` SET |
225
|
|
|
`log_time` = '" . time() . "', `log_code` = '" . db_escape($error_code) . "', `log_sender` = '" . ($user['id'] ? db_escape($user['id']) : 0) . "', |
226
|
|
|
`log_username` = '" . db_escape($user['user_name']) . "', `log_title` = '" . db_escape($title) . "', `log_text` = '" . db_escape($message) . "', |
227
|
|
|
`log_page` = '" . db_escape(strpos($_SERVER['SCRIPT_NAME'], SN_ROOT_RELATIVE) === false ? $_SERVER['SCRIPT_NAME'] : substr($_SERVER['SCRIPT_NAME'], strlen(SN_ROOT_RELATIVE))) . "'" . |
228
|
|
|
", `log_dump` = '" . ($error_backtrace ? db_escape(serialize($error_backtrace)) : '') . "'" . ";"; |
229
|
|
|
doquery($query, '', false, true) or die($fatal_error . db_error()); |
|
|
|
|
230
|
|
|
|
231
|
|
|
$message = "Пожалуйста, свяжитесь с админом, если ошибка повторится. Ошибка №: <b>" . db_insert_id() . "</b>"; |
232
|
|
|
|
233
|
|
|
$sys_stop_log_hit = true; |
234
|
|
|
$sys_log_disabled = true; |
235
|
|
|
!function_exists('messageBox') ? die($message) : messageBox($message, 'Ошибка', '', 0, false); |
|
|
|
|
236
|
|
|
} else { |
237
|
|
|
// // TODO Здесь надо писать в файло |
238
|
|
|
ob_start(); |
239
|
|
|
print("<hr>User ID {$user['id']} raised error code {$error_code} titled '{$title}' with text '{$error_text}' on page {$_SERVER['SCRIPT_NAME']}"); |
240
|
|
|
|
241
|
|
|
foreach($error_backtrace as $name => $value) { |
242
|
|
|
print('<hr>'); |
243
|
|
|
pdump($value, $name); |
244
|
|
|
} |
245
|
|
|
ob_end_flush(); |
246
|
|
|
die(); |
|
|
|
|
247
|
|
|
} |
248
|
|
|
} |
249
|
|
|
|
250
|
|
|
function warning($message, $title = 'System Message', $log_code = 300, $dump = false) { |
|
|
|
|
251
|
|
|
global $user, $lang, $sys_log_disabled; |
|
|
|
|
252
|
|
|
|
253
|
|
|
if(empty(SN::$db->connected)) { |
254
|
|
|
// TODO - писать ошибку в файл |
255
|
|
|
die('SQL server currently unavailable. Please contact Administration...'); |
|
|
|
|
256
|
|
|
} |
257
|
|
|
|
258
|
|
|
$error_backtrace = $this->dump($dump, false); |
259
|
|
|
|
260
|
|
|
if(!$sys_log_disabled) { |
261
|
|
|
$query = "INSERT INTO `{{logs}}` SET |
262
|
|
|
`log_time` = '" . time() . "', `log_code` = '" . db_escape($log_code) . "', `log_sender` = '" . ($user['id'] ? db_escape($user['id']) : 0) . "', |
263
|
|
|
`log_username` = '" . db_escape($user['user_name']) . "', `log_title` = '" . db_escape($title) . "', `log_text` = '" . db_escape($message) . "', |
264
|
|
|
`log_page` = '" . db_escape(strpos($_SERVER['SCRIPT_NAME'], SN_ROOT_RELATIVE) === false ? $_SERVER['SCRIPT_NAME'] : substr($_SERVER['SCRIPT_NAME'], strlen(SN_ROOT_RELATIVE))) . "'" . |
265
|
|
|
", `log_dump` = '" . ($error_backtrace ? db_escape(serialize($error_backtrace)) : '') . "'" . ";"; |
266
|
|
|
doquery($query, '', false, true); |
267
|
|
|
} else { |
268
|
|
|
// // TODO Здесь надо писать в файло |
269
|
|
|
print("<hr>User ID {$user['id']} made log entry with code {$log_code} titled '{$title}' with text '{$message}' on page {$_SERVER['SCRIPT_NAME']}"); |
270
|
|
|
} |
271
|
|
|
} |
272
|
|
|
} |
273
|
|
|
|
274
|
|
|
// Copyright (c) 2009-2010 Gorlum for http://supernova.ws |
275
|
|
|
// Dump variables nicer then var_dump() |
276
|
|
|
|
277
|
|
|
function dump($value, $varname = null, $level = 0, $dumper = '') { |
278
|
|
|
if(isset($varname)) { |
279
|
|
|
$varname .= " = "; |
280
|
|
|
} |
281
|
|
|
|
282
|
|
|
if($level == -1) { |
283
|
|
|
$trans[' '] = '∴'; |
|
|
|
|
284
|
|
|
$trans["\t"] = '⇒'; |
285
|
|
|
$trans["\n"] = '¶;'; |
286
|
|
|
$trans["\r"] = '⇐'; |
287
|
|
|
$trans["\0"] = '⊕'; |
288
|
|
|
|
289
|
|
|
return strtr(htmlspecialchars($value), $trans); |
290
|
|
|
} |
291
|
|
|
if($level == 0) { |
292
|
|
|
// $dumper = '<pre>' . mt_rand(10, 99) . '|' . $varname; |
|
|
|
|
293
|
|
|
$dumper = mt_rand(10, 99) . '|' . $varname; |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
$type = gettype($value); |
297
|
|
|
$dumper .= $type; |
298
|
|
|
|
299
|
|
|
if($type == 'string') { |
300
|
|
|
$dumper .= '(' . strlen($value) . ')'; |
301
|
|
|
$value = dump($value, '', -1); |
302
|
|
|
} elseif($type == 'boolean') { |
303
|
|
|
$value = ($value ? 'true' : 'false'); |
304
|
|
|
} elseif($type == 'object') { |
305
|
|
|
$props = get_class_vars(get_class($value)); |
306
|
|
|
$dumper .= '(' . count($props) . ') <u>' . get_class($value) . '</u>'; |
307
|
|
|
foreach($props as $key => $val) { |
308
|
|
|
$dumper .= "\n" . str_repeat("\t", $level + 1) . $key . ' => '; |
309
|
|
|
$dumper .= dump($value->$key, '', $level + 1); |
310
|
|
|
} |
311
|
|
|
$value = ''; |
312
|
|
|
} elseif($type == 'array') { |
313
|
|
|
$dumper .= '(' . count($value) . ')'; |
314
|
|
|
foreach($value as $key => $val) { |
315
|
|
|
$dumper .= "\n" . str_repeat("\t", $level + 1) . dump($key, '', -1) . ' => '; |
316
|
|
|
$dumper .= dump($val, '', $level + 1); |
317
|
|
|
} |
318
|
|
|
$value = ''; |
319
|
|
|
} |
320
|
|
|
$dumper .= " <b>$value</b>"; |
321
|
|
|
// if($level == 0) { |
|
|
|
|
322
|
|
|
// $dumper .= '</pre>'; |
323
|
|
|
// } |
324
|
|
|
|
325
|
|
|
return $dumper; |
326
|
|
|
} |
327
|
|
|
|
328
|
|
|
function pdump($value, $varname = null) { |
329
|
|
|
$backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); |
330
|
|
|
// print_rr($backtrace); |
|
|
|
|
331
|
|
|
// $backtrace = $backtrace[1]; |
332
|
|
|
|
333
|
|
|
$caller = ''; |
334
|
|
|
if(defined('SN_DEBUG_PDUMP_CALLER') && SN_DEBUG_PDUMP_CALLER) { |
|
|
|
|
335
|
|
|
$caller = (!empty($backtrace[1]['class']) ? $backtrace[1]['class'] : '') . |
336
|
|
|
(!empty($backtrace[1]['type']) ? $backtrace[1]['type'] : '') . |
337
|
|
|
$backtrace[1]['function'] . |
338
|
|
|
(!empty($backtrace[0]['file']) |
339
|
|
|
? ( |
340
|
|
|
' (' . substr($backtrace[0]['file'], SN_ROOT_PHYSICAL_STR_LEN) . |
341
|
|
|
(!empty($backtrace[0]['line']) ? ':' . $backtrace[0]['line'] : '') . |
342
|
|
|
')' |
343
|
|
|
) |
344
|
|
|
: '' |
345
|
|
|
); |
346
|
|
|
$caller = "\r\n" . $caller; |
347
|
|
|
} |
348
|
|
|
|
349
|
|
|
print('<pre style="text-align: left; background-color: #111111; color: #0A0; font-family: Courier, monospace !important; padding: 1em 0; font-weight: 800; font-size: 14px;">' . |
350
|
|
|
dump($value, $varname) . |
351
|
|
|
$caller . |
352
|
|
|
'</pre>' |
353
|
|
|
); |
354
|
|
|
} |
355
|
|
|
|
356
|
|
|
function debug($value, $varname = null) { |
357
|
|
|
pdump($value, $varname); |
358
|
|
|
} |
359
|
|
|
|
360
|
|
|
function pr($prePrint = false) { |
361
|
|
|
if($prePrint) { |
362
|
|
|
print("<br>"); |
363
|
|
|
} |
364
|
|
|
print(mt_rand() . "<br>"); |
365
|
|
|
} |
366
|
|
|
|
367
|
|
|
function pc($prePrint = false) { |
368
|
|
|
global $_PRINT_COUNT_VALUE; |
|
|
|
|
369
|
|
|
$_PRINT_COUNT_VALUE++; |
370
|
|
|
|
371
|
|
|
if($prePrint) { |
372
|
|
|
print("<br>"); |
373
|
|
|
} |
374
|
|
|
print($_PRINT_COUNT_VALUE . "<br>"); |
375
|
|
|
} |
376
|
|
|
|
377
|
|
|
function prep($message) { |
378
|
|
|
print('<pre>' . $message . '</pre>'); |
379
|
|
|
} |
380
|
|
|
|
381
|
|
|
function backtrace_no_arg() { |
382
|
|
|
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); |
383
|
|
|
array_shift($trace); |
384
|
|
|
return $trace; |
385
|
|
|
} |
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.