PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
← All changes | telemetry/wordpress-error-handler.php +20 -5 2.6.24 → 2.7.2 View file →
@@ -89,9 +89,9 @@
89 89 * Setup WordPress error handlers - Only for plugin-specific errors
90 90 */
91 91 private function setup_error_handlers() {
92 92 // Store previous handlers to chain them properly
93 - $this->previous_error_handler = set_error_handler(array($this, 'capture_php_error'), E_ALL);
93 + $this->previous_error_handler = set_error_handler(array($this, 'capture_php_error'), E_ALL); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_set_error_handler -- plugin logger sink / last-resort fallback
94 94 $this->previous_exception_handler = set_exception_handler(array($this, 'capture_exception'));
95 95
96 96 // Hook into WordPress fatal error handler (only for plugin errors)
97 97 add_filter('wp_fatal_error_handler', array($this, 'capture_fatal_error'));
@@ -123,8 +123,14 @@
123 123 if ($this->previous_error_handler && is_callable($this->previous_error_handler)) {
124 124 $handled = call_user_func($this->previous_error_handler, $severity, $message, $file, $line);
125 125 }
126 126
127 + // Respect error_reporting() and the @ suppression operator — never capture masked errors
128 + // phpcs:ignore WordPress.PHP.DevelopmentFunctions.prevent_path_disclosure_error_reporting, PluginCheck.CodeAnalysis.PHPErrorReporting.DirectErrorReportingCall -- reads the current mask, does not print paths; reading the mask is the only way a custom handler can respect the @ operator
129 + if (!(error_reporting() & $severity)) {
130 + return $handled;
131 + }
132 +
127 133 // Only capture fatal-level errors — skip warnings, notices, deprecated, strict
128 134 $fatal_severities = [E_USER_ERROR, E_RECOVERABLE_ERROR];
129 135 if (!in_array($severity, $fatal_severities, true)) {
130 136 return $handled;
@@ -137,9 +143,9 @@
137 143 'severity' => $severity,
138 144 'file' => $file,
139 145 'line' => $line,
140 146 'error_level' => $this->get_error_level($severity),
141 - 'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10)
147 + 'backtrace' => debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 10) // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_debug_backtrace -- genuine failure path, bounded, no secrets
142 148 ));
143 149 }
144 150
145 151 // Return the result from the previous handler, or false to continue normal error handling
@@ -150,10 +156,12 @@
150 156 * Capture uncaught exceptions - Only plugin-specific exceptions
151 157 */
152 158 public function capture_exception($exception) {
153 159 // First, call the previous exception handler if it exists
160 + $chained = false;
154 161 if ($this->previous_exception_handler && is_callable($this->previous_exception_handler)) {
155 162 call_user_func($this->previous_exception_handler, $exception);
163 + $chained = true;
156 164 }
157 165
158 166 // Only capture exceptions from our plugin or directly related to our plugin
159 167 if ($this->should_capture_error($exception->getFile())) {
@@ -164,9 +172,16 @@
164 172 'line' => $exception->getLine(),
165 173 'trace' => $exception->getTraceAsString(),
166 174 'exception_object' => $exception
167 175 ));
176 + return;
168 177 }
178 +
179 + // Not our exception and nothing else handled it: restore PHP's default
180 + // uncaught-exception handling instead of swallowing it silently.
181 + if (!$chained) {
182 + throw $exception;
183 + }
169 184 }
170 185
171 186 /**
172 187 * Capture fatal errors
@@ -269,9 +284,9 @@
269 284 /**
270 285 * Check if the current environment is localhost/development
271 286 */
272 287 private function is_localhost() {
273 - $host = parse_url(home_url(), PHP_URL_HOST);
288 + $host = wp_parse_url(home_url(), PHP_URL_HOST);
274 289
275 290 // Check for common localhost patterns
276 291 $localhost_patterns = [
277 292 'localhost',
@@ -284,9 +299,9 @@
284 299 '.localhost'
285 300 ];
286 301
287 302 foreach ($localhost_patterns as $pattern) {
288 - if (strpos($host, $pattern) !== false) {
303 + if ($host !== false && $host !== null && strpos($host, $pattern) !== false) {
289 304 return true;
290 305 }
291 306 }
292 307
@@ -327,9 +342,9 @@
327 342 $context = array_merge($context, array(
328 343 'wp_url' => home_url(),
329 344 'plugin_version' => defined('METASYNC_VERSION') ? METASYNC_VERSION : '1.0.0',
330 345 'plugin_name' => 'Search Engine Labs SEO (MetaSync)',
331 - 'error_timestamp' => date('Y-m-d H:i:s'),
346 + 'error_timestamp' => gmdate('Y-m-d H:i:s'),
332 347 'site_info' => array(
333 348 'site_title' => get_bloginfo('name'),
334 349 'wp_version' => get_bloginfo('version'),
335 350 'admin_email' => get_bloginfo('admin_email'),