PluginProbe
Activity Logs, User Activity Tracking, Multisite Activity Log from Logtivity / 3.3.2
Activity Logs, User Activity Tracking, Multisite Activity Log from Logtivity v3.3.2
3.3.8 trunk 1.0 1.1.0 1.10.0 1.11.0 1.11.1 1.12.0 1.13.0 1.14.0 1.15.0 1.16.0 1.17.0 1.17.1 1.18.0 1.19.0 1.2.0 1.20.0 1.20.1 1.3.0 1.3.1 1.4.0 1.5.0 1.6.0 1.6.1 All 66 releases
logtivity / Core / Errors / Logtivity_Error_Log.php

Logtivity_Error_Log.php in Activity Logs, User Activity Tracking, Multisite Activity Log from Logtivity 3.3.2, at Core/Errors/Logtivity_Error_Log.php

225 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * @package Logtivity
5 * @contact logtivity.io, hello@logtivity.io
6 * @copyright 2024-2025 Logtivity. All rights reserved
7 * @license https://www.gnu.org/licenses/gpl.html GNU/GPL
8 *
9 * This file is part of Logtivity.
10 *
11 * Logtivity is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * Logtivity is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with Logtivity. If not, see <https://www.gnu.org/licenses/>.
23 */
24
25 class Logtivity_Error_Log
26 {
27 /**
28 * @var ?callable
29 */
30 private $errorHandler;
31
32 /**
33 * @var ?callable
34 */
35 private $exceptionHandler;
36
37 public function __construct()
38 {
39 $this->errorHandler = set_error_handler([$this, 'errorHandler']);
40
41 $this->exceptionHandler = set_exception_handler([$this, 'exceptionHandler']);
42 }
43
44 /**
45 * @return self
46 */
47 public static function init(): self
48 {
49 return new static();
50 }
51
52 /**
53 * @param int $code
54 * @param string $message
55 * @param ?string $file
56 * @param ?int $line
57 *
58 * @return mixed
59 */
60 public function errorHandler(
61 int $code,
62 string $message,
63 ?string $file = null,
64 ?int $line = null
65 ) {
66 try {
67 if (isset($_SERVER['HTTP_HOST'])) {
68 $stackTrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS & ~DEBUG_BACKTRACE_PROVIDE_OBJECT);
69 } else {
70 $stackTrace = [
71 [
72 'line' => $file,
73 'file' => $line,
74 ],
75 ];
76 }
77
78 $error = [
79 'type' => $code,
80 'message' => $message,
81 'file' => $file,
82 'line' => $line,
83 'stack_trace' => $stackTrace,
84 'level' => 'warning',
85 ];
86
87 if ($this->shouldIgnore($error, 'warnings')) {
88 return false;
89 }
90
91 Logtivity::logError($error)->send();
92
93 } catch (Throwable $e) {
94 // Ignore
95 }
96
97 if ($this->errorHandler) {
98 return ($this->errorHandler)($code, $message, $file, $line);
99 }
100
101 return false;
102 }
103
104 /**
105 * @param Throwable $throwable
106 *
107 * @return void
108 */
109 public function exceptionHandler(Throwable $throwable): void
110 {
111 try {
112 if (isset($_SERVER['HTTP_HOST'])) {
113 $stackTrace = array_merge(
114 [
115 [
116 'line' => $throwable->getLine(),
117 'file' => $throwable->getFile(),
118 ],
119 ],
120 $throwable->getTrace()
121 );
122 } else {
123 $stackTrace = [
124 [
125 'line' => $throwable->getLine(),
126 'file' => $throwable->getFile(),
127 ],
128 ];
129 }
130
131 $error = [
132 'type' => get_class($throwable),
133 'message' => $throwable->getMessage(),
134 'file' => $throwable->getFile(),
135 'line' => $throwable->getLine(),
136 'stack_trace' => $stackTrace,
137 'level' => 'error',
138 ];
139
140 if ($this->shouldIgnore($error, 'errors')) {
141 return;
142 }
143
144 Logtivity::logError($error)->send();
145
146 } catch (Throwable $e) {
147 // Ignore
148 }
149
150 if ($this->exceptionHandler) {
151 ($this->exceptionHandler)($throwable);
152 }
153 }
154
155 /**
156 * @param array $error
157 * @param string $type
158 *
159 * @return bool
160 */
161 private function shouldIgnore(array $error, string $type): bool
162 {
163 $errorType = $error['type'] ?? null;
164 $errorMessage = $error['message'] ?? null;
165
166 if (
167 ($errorType == E_WARNING && strpos($errorMessage, 'unlink') !== false)
168 || $this->loggingDisabled()
169 || $this->isErrorTypeDisabled($type)
170 || $this->maybeRateLimit($error)
171 ) {
172 return true;
173 }
174
175 return apply_filters('logtivity_should_ignore_error', false, $error);
176 }
177
178 /**
179 * @param array $error
180 *
181 * @return bool
182 */
183 public function maybeRateLimit(array $error): bool
184 {
185 $errorType = $error['type'] ?? null;
186
187 if (
188 is_int($errorType)
189 && in_array($errorType, [E_ERROR, E_PARSE]) == false
190 ) {
191 // Most error types are rate limited to once/24 hours
192 $hash = md5($error['message']);
193
194 if (get_transient('logtivity_' . $hash) === false) {
195 set_transient('logtivity_' . $hash, true, 24 * HOUR_IN_SECONDS);
196
197 return false;
198 }
199 }
200
201 return true;
202 }
203
204 /**
205 * @param string $type
206 *
207 * @return bool
208 */
209 public function isErrorTypeDisabled(string $type): bool
210 {
211 return in_array(
212 $type,
213 (new Logtivity_Options())->disabledErrorLevels()
214 );
215 }
216
217 /**
218 * @return bool
219 */
220 public function loggingDisabled(): bool
221 {
222 return (bool)(new Logtivity_Options())->getOption('logtivity_disable_error_logging');
223 }
224 }
225