1 | <?php |
||||||
2 | |||||||
3 | namespace Yaro\LogEnvelope; |
||||||
4 | |||||||
5 | use Exception; |
||||||
6 | use SplFileObject; |
||||||
7 | use Illuminate\Support\Facades\Log; |
||||||
8 | use Illuminate\Support\Facades\Request; |
||||||
9 | use Illuminate\Support\Facades\Session; |
||||||
10 | use Yaro\LogEnvelope\Drivers\DriverFactory; |
||||||
11 | |||||||
12 | class LogEnvelope |
||||||
13 | { |
||||||
14 | private $config = []; |
||||||
15 | private $cachedConfig = []; |
||||||
16 | |||||||
17 | public function __construct() |
||||||
18 | { |
||||||
19 | $this->config['censored_fields'] = config('yaro.log-envelope.censored_fields', ['password']); |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
20 | $this->config['except'] = config('yaro.log-envelope.except', []); |
||||||
21 | $this->config['count'] = config('yaro.log-envelope.lines_count', 6); |
||||||
22 | $this->config['drivers'] = config('yaro.log-envelope.drivers', []); |
||||||
23 | } // end __construct |
||||||
24 | |||||||
25 | public function send($exception) |
||||||
26 | { |
||||||
27 | $this->onBefore(); |
||||||
28 | |||||||
29 | try { |
||||||
30 | $data = $this->getExceptionData($exception); |
||||||
31 | |||||||
32 | if ($this->isSkipException($data['class'])) { |
||||||
33 | return; |
||||||
34 | } |
||||||
35 | |||||||
36 | foreach ($this->config['drivers'] as $driver => $driverConfig) { |
||||||
37 | DriverFactory::create($driver, $data)->setConfig($driverConfig)->send(); |
||||||
38 | } |
||||||
39 | } catch (Exception $e) { |
||||||
40 | Log::error($e); |
||||||
41 | } |
||||||
42 | |||||||
43 | $this->onAfter(); |
||||||
44 | } // end send |
||||||
45 | |||||||
46 | private function onBefore() |
||||||
47 | { |
||||||
48 | $this->cachedConfig = []; |
||||||
49 | $forcedConfig = config('yaro.log-envelope.force_config', []); |
||||||
0 ignored issues
–
show
The function
config was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
50 | foreach ($forcedConfig as $configKey => $configValue) { |
||||||
51 | $this->cachedConfig[$configKey] = config($configKey); |
||||||
52 | } |
||||||
53 | if ($forcedConfig) { |
||||||
54 | config($forcedConfig); |
||||||
55 | } |
||||||
56 | } // end onBefore |
||||||
57 | |||||||
58 | private function onAfter() |
||||||
59 | { |
||||||
60 | if ($this->cachedConfig) { |
||||||
0 ignored issues
–
show
The expression
$this->cachedConfig of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using ![]() |
|||||||
61 | config($this->cachedConfig); |
||||||
0 ignored issues
–
show
The function
config was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
62 | } |
||||||
63 | } // end onAfter |
||||||
64 | |||||||
65 | public function isSkipException($exceptionClass) |
||||||
66 | { |
||||||
67 | return in_array($exceptionClass, $this->config['except']); |
||||||
68 | } // end isSkipException |
||||||
69 | |||||||
70 | private function getExceptionData($exception) |
||||||
71 | { |
||||||
72 | $data = []; |
||||||
73 | |||||||
74 | $data['host'] = Request::server('HTTP_HOST'); |
||||||
75 | $data['method'] = Request::method(); |
||||||
76 | $data['fullUrl'] = Request::fullUrl(); |
||||||
77 | if (php_sapi_name() === 'cli') { |
||||||
78 | $data['host'] = parse_url(config('app.url'), PHP_URL_HOST); |
||||||
0 ignored issues
–
show
The function
config was not found. Maybe you did not declare it correctly or list all dependencies?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
79 | $data['method'] = 'CLI'; |
||||||
80 | } |
||||||
81 | $data['exception'] = $exception->getMessage(); |
||||||
82 | $data['error'] = $exception->getTraceAsString(); |
||||||
83 | $data['line'] = $exception->getLine(); |
||||||
84 | $data['file'] = $exception->getFile(); |
||||||
85 | $data['class'] = get_class($exception); |
||||||
86 | $data['storage'] = array( |
||||||
87 | 'SERVER' => Request::server(), |
||||||
88 | 'GET' => Request::query(), |
||||||
89 | 'POST' => $_POST, |
||||||
90 | 'FILE' => Request::file(), |
||||||
91 | 'OLD' => Request::hasSession() ? Request::old() : [], |
||||||
92 | 'COOKIE' => Request::cookie(), |
||||||
93 | 'SESSION' => Request::hasSession() ? Session::all() : [], |
||||||
94 | 'HEADERS' => Request::header(), |
||||||
95 | ); |
||||||
96 | |||||||
97 | // Remove empty, false and null values |
||||||
98 | $data['storage'] = array_filter($data['storage']); |
||||||
99 | |||||||
100 | // Censor sensitive field values |
||||||
101 | array_walk_recursive($data['storage'], self::censorSensitiveFields(...)); |
||||||
102 | |||||||
103 | $count = $this->config['count']; |
||||||
104 | |||||||
105 | $data['exegutor'] = []; |
||||||
106 | $data['file_lines'] = []; |
||||||
107 | |||||||
108 | $file = new SplFileObject($data['file']); |
||||||
109 | for ($i = -1 * abs($count); $i <= abs($count); $i++) { |
||||||
110 | list($line, $exegutorLine) = $this->getLineInfo($file, $data['line'], $i); |
||||||
111 | if (!$line && !$exegutorLine) { |
||||||
112 | continue; |
||||||
113 | } |
||||||
114 | $data['exegutor'][] = $exegutorLine; |
||||||
115 | $data['file_lines'][$data['line'] + $i] = $line; |
||||||
116 | } |
||||||
117 | |||||||
118 | // to make Symfony exception more readable |
||||||
119 | if ($data['class'] == 'Symfony\Component\Debug\Exception\FatalErrorException') { |
||||||
120 | preg_match("~^(.+)' in ~", $data['exception'], $matches); |
||||||
121 | if (isset($matches[1])) { |
||||||
122 | $data['exception'] = $matches[1]; |
||||||
123 | } |
||||||
124 | } |
||||||
125 | |||||||
126 | return $data; |
||||||
127 | } // end getExceptionData |
||||||
128 | |||||||
129 | /** |
||||||
130 | * Set the value of specified fields to ***** |
||||||
131 | * |
||||||
132 | * @param string $value |
||||||
133 | * @param string $key |
||||||
134 | * @return void |
||||||
135 | */ |
||||||
136 | public function censorSensitiveFields(&$value, $key) |
||||||
137 | { |
||||||
138 | if (in_array($key, $this->config['censored_fields'], true)) { |
||||||
139 | $value = '*****'; |
||||||
140 | } |
||||||
141 | } |
||||||
142 | |||||||
143 | /** |
||||||
144 | * @param SplFileObject $file |
||||||
145 | */ |
||||||
146 | private function getLineInfo($file, $line, $i) |
||||||
147 | { |
||||||
148 | $currentLine = $line + $i; |
||||||
149 | // cuz array starts with 0, when file lines start count from 1 |
||||||
150 | $index = $currentLine - 1; |
||||||
151 | if ($index < 0) { |
||||||
152 | return [false, false]; |
||||||
153 | } |
||||||
154 | $file->seek($index); |
||||||
155 | |||||||
156 | if ($file->eof()) { |
||||||
157 | return [false, false]; |
||||||
158 | } |
||||||
159 | |||||||
160 | return [ |
||||||
161 | $file->current(), |
||||||
162 | [ |
||||||
163 | 'line' => '<span style="color:#aaaaaa;">' . $currentLine . '.</span> ' . SyntaxHighlight::process($file->current()), |
||||||
164 | 'wrap_left' => $i ? '' : '<span style="color: #F5F5F5; background-color: #5A3E3E; width: 100%; display: block;">', |
||||||
165 | 'wrap_right' => $i ? '' : '</span>', |
||||||
166 | ] |
||||||
167 | ]; |
||||||
168 | } // end getLineInfo |
||||||
169 | } |
||||||
170 |