1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Mouf\Mvc\Splash\Utils; |
4
|
|
|
|
5
|
|
|
class ExceptionUtils |
6
|
|
|
{ |
7
|
|
|
/** |
8
|
|
|
* Returns the Exception Backtrace as a nice HTML view. |
9
|
|
|
* |
10
|
|
|
* @param unknown_type $backtrace |
11
|
|
|
* |
12
|
|
|
* @return unknown |
13
|
|
|
*/ |
14
|
|
|
private static function getHTMLBackTrace($backtrace) |
15
|
|
|
{ |
16
|
|
|
$str = ''; |
17
|
|
|
|
18
|
|
|
foreach ($backtrace as $step) { |
19
|
|
|
if ($step['function'] != 'getHTMLBackTrace' && $step['function'] != 'handle_error') { |
20
|
|
|
$str .= '<tr><td style="border-bottom: 1px solid #EEEEEE">'; |
21
|
|
|
$str .= ((isset($step['class'])) ? htmlspecialchars($step['class'], ENT_NOQUOTES, 'UTF-8') : ''). |
22
|
|
|
((isset($step['type'])) ? htmlspecialchars($step['type'], ENT_NOQUOTES, 'UTF-8') : '').htmlspecialchars($step['function'], ENT_NOQUOTES, 'UTF-8').'('; |
23
|
|
|
|
24
|
|
View Code Duplication |
if (is_array($step['args'])) { |
|
|
|
|
25
|
|
|
$drawn = false; |
26
|
|
|
$params = ''; |
27
|
|
|
foreach ($step['args'] as $param) { |
28
|
|
|
$params .= self::getPhpVariableAsText($param); |
29
|
|
|
//$params .= var_export($param, true); |
30
|
|
|
$params .= ', '; |
31
|
|
|
$drawn = true; |
32
|
|
|
} |
33
|
|
|
$str .= htmlspecialchars($params, ENT_NOQUOTES, 'UTF-8'); |
34
|
|
|
if ($drawn == true) { |
|
|
|
|
35
|
|
|
$str = substr($str, 0, strlen($str) - 2); |
36
|
|
|
} |
37
|
|
|
} |
38
|
|
|
$str .= ')'; |
39
|
|
|
$str .= '</td><td style="border-bottom: 1px solid #EEEEEE">'; |
40
|
|
|
$str .= ((isset($step['file'])) ? htmlspecialchars(self::displayFile($step['file']), ENT_NOQUOTES, 'UTF-8') : ''); |
41
|
|
|
$str .= '</td><td style="border-bottom: 1px solid #EEEEEE">'; |
42
|
|
|
$str .= ((isset($step['line'])) ? $step['line'] : ''); |
43
|
|
|
$str .= '</td></tr>'; |
44
|
|
|
} |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
return $str; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Function called to display an exception if it occurs. |
52
|
|
|
* It will make sure to purge anything in the buffer before calling the exception displayer. |
53
|
|
|
* |
54
|
|
|
* @param Exception $exception |
55
|
|
|
*/ |
56
|
|
|
public static function getHtmlForException(\Exception $exception) |
57
|
|
|
{ |
58
|
|
|
//global $sys_error_reporting_mail; |
59
|
|
|
//global $sys_error_messages; |
60
|
|
|
$msg = ''; |
|
|
|
|
61
|
|
|
|
62
|
|
|
$msg = '<table>'; |
63
|
|
|
|
64
|
|
|
$display_errors = ini_get('display_errors'); |
|
|
|
|
65
|
|
|
$color = '#FF0000'; |
66
|
|
|
$type = 'Uncaught '.get_class($exception); |
67
|
|
|
if ($exception->getCode() != null) { |
68
|
|
|
$type .= ' with error code '.$exception->getCode(); |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
$msg .= "<tr><td colspan='3' style='background-color:$color; color:white; text-align:center'><b>$type</b></td></tr>"; |
72
|
|
|
|
73
|
|
|
$msg .= "<tr><td style='background-color:#AAAAAA; color:white; text-align:center'>Context/Message</td>"; |
74
|
|
|
$msg .= "<td style='background-color:#AAAAAA; color:white; text-align:center'>File</td>"; |
75
|
|
|
$msg .= "<td style='background-color:#AAAAAA; color:white; text-align:center'>Line</td></tr>"; |
76
|
|
|
|
77
|
|
|
$msg .= "<tr><td style='background-color:#EEEEEE; color:black'><b>".nl2br($exception->getMessage()).'</b></td>'; |
78
|
|
|
$msg .= "<td style='background-color:#EEEEEE; color:black'>".self::displayFile($exception->getFile()).'</td>'; |
79
|
|
|
$msg .= "<td style='background-color:#EEEEEE; color:black'>".$exception->getLine().'</td></tr>'; |
80
|
|
|
$msg .= self::getHTMLBackTrace($exception->getTrace()); |
|
|
|
|
81
|
|
|
$msg .= '</table>'; |
82
|
|
|
|
83
|
|
|
return $msg; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Function called to display an exception if it occurs. |
88
|
|
|
* It will make sure to purge anything in the buffer before calling the exception displayer. |
89
|
|
|
* |
90
|
|
|
* @param Exception $exception |
91
|
|
|
*/ |
92
|
|
|
public static function getTextForException(\Exception $exception) |
93
|
|
|
{ |
94
|
|
|
// Now, let's compute the same message, but without the HTML markup for the error log. |
95
|
|
|
$textTrace = 'Message: '.$exception->getMessage()."\n"; |
96
|
|
|
$textTrace .= 'File: '.$exception->getFile()."\n"; |
97
|
|
|
$textTrace .= 'Line: '.$exception->getLine()."\n"; |
98
|
|
|
$textTrace .= "Stacktrace:\n"; |
99
|
|
|
$textTrace .= self::getTextBackTrace($exception->getTrace()); |
|
|
|
|
100
|
|
|
|
101
|
|
|
return $textTrace; |
102
|
|
|
} |
103
|
|
|
/** |
104
|
|
|
* Returns the Exception Backtrace as a text string. |
105
|
|
|
* |
106
|
|
|
* @param unknown_type $backtrace |
107
|
|
|
* |
108
|
|
|
* @return unknown |
109
|
|
|
*/ |
110
|
|
|
private static function getTextBackTrace($backtrace) |
111
|
|
|
{ |
112
|
|
|
$str = ''; |
113
|
|
|
|
114
|
|
|
foreach ($backtrace as $step) { |
115
|
|
|
if ($step['function'] != 'getTextBackTrace' && $step['function'] != 'handle_error') { |
116
|
|
|
if (isset($step['file']) && isset($step['line'])) { |
117
|
|
|
$str .= 'In '.$step['file'].' at line '.$step['line'].': '; |
118
|
|
|
} |
119
|
|
|
if (isset($step['class']) && isset($step['type']) && isset($step['function'])) { |
120
|
|
|
$str .= $step['class'].$step['type'].$step['function'].'('; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
View Code Duplication |
if (is_array($step['args'])) { |
|
|
|
|
124
|
|
|
$drawn = false; |
125
|
|
|
$params = ''; |
126
|
|
|
foreach ($step['args'] as $param) { |
127
|
|
|
$params .= self::getPhpVariableAsText($param); |
128
|
|
|
//$params .= var_export($param, true); |
129
|
|
|
$params .= ', '; |
130
|
|
|
$drawn = true; |
131
|
|
|
} |
132
|
|
|
$str .= $params; |
133
|
|
|
if ($drawn == true) { |
|
|
|
|
134
|
|
|
$str = substr($str, 0, strlen($str) - 2); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
$str .= ')'; |
138
|
|
|
$str .= "\n"; |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
return $str; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* Used by the debug function to display a nice view of the parameters. |
147
|
|
|
* |
148
|
|
|
* @param unknown_type $var |
149
|
|
|
* |
150
|
|
|
* @return unknown |
151
|
|
|
*/ |
152
|
|
|
private static function getPhpVariableAsText($var) |
153
|
|
|
{ |
154
|
|
|
if (is_string($var)) { |
155
|
|
|
return('"'.str_replace(array("\x00", "\x0a", "\x0d", "\x1a", "\x09"), array('\0', '\n', '\r', '\Z', '\t'), $var).'"'); |
156
|
|
|
} elseif (is_int($var) || is_float($var)) { |
157
|
|
|
return($var); |
158
|
|
|
} elseif (is_bool($var)) { |
159
|
|
|
if ($var) { |
160
|
|
|
return('true'); |
161
|
|
|
} else { |
162
|
|
|
return('false'); |
163
|
|
|
} |
164
|
|
|
} elseif (is_array($var)) { |
165
|
|
|
$result = 'array( '; |
166
|
|
|
$comma = ''; |
167
|
|
|
foreach ($var as $key => $val) { |
168
|
|
|
$result .= $comma.self::getPhpVariableAsText($key).' => '.self::getPhpVariableAsText($val); |
|
|
|
|
169
|
|
|
$comma = ', '; |
170
|
|
|
} |
171
|
|
|
$result .= ' )'; |
172
|
|
|
|
173
|
|
|
return($result); |
174
|
|
|
} elseif (is_object($var)) { |
175
|
|
|
return 'Object '.get_class($var); |
176
|
|
|
} elseif (is_resource($var)) { |
177
|
|
|
return 'Resource '.get_resource_type($var); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
return 'Unknown type variable'; |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
private static function displayFile($file) |
184
|
|
|
{ |
185
|
|
|
$realpath = realpath($file); |
186
|
|
|
if (!$realpath) { |
187
|
|
|
// If the file is a phar::// or something... |
188
|
|
|
|
189
|
|
|
return $file; |
190
|
|
|
} |
191
|
|
|
$cwd = getcwd().DIRECTORY_SEPARATOR; |
192
|
|
|
|
193
|
|
|
return self::getRelativePath($cwd, $realpath); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
/** |
197
|
|
|
* Returns a relative path based on 2 absolute paths. |
198
|
|
|
* |
199
|
|
|
* @param string $from |
200
|
|
|
* @param string $to |
201
|
|
|
* |
202
|
|
|
* @return string |
203
|
|
|
*/ |
204
|
|
|
private static function getRelativePath($from, $to) |
205
|
|
|
{ |
206
|
|
|
$from = explode('/', $from); |
207
|
|
|
$to = explode('/', $to); |
208
|
|
|
$relPath = $to; |
209
|
|
|
|
210
|
|
|
foreach ($from as $depth => $dir) { |
211
|
|
|
// find first non-matching dir |
212
|
|
|
if (isset($to[$depth]) && $dir === $to[$depth]) { |
213
|
|
|
// ignore this directory |
214
|
|
|
array_shift($relPath); |
215
|
|
|
} else { |
216
|
|
|
// get number of remaining dirs to $from |
217
|
|
|
$remaining = count($from) - $depth; |
218
|
|
|
if ($remaining > 1) { |
219
|
|
|
// add traversals up to first matching dir |
220
|
|
|
$padLength = (count($relPath) + $remaining - 1) * -1; |
221
|
|
|
$relPath = array_pad($relPath, $padLength, '..'); |
222
|
|
|
break; |
223
|
|
|
} else { |
224
|
|
|
$relPath[0] = './'.$relPath[0]; |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
return implode('/', $relPath); |
230
|
|
|
} |
231
|
|
|
} |
232
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.