'Error', E_WARNING => 'Warning', E_PARSE => 'Parse Error', E_NOTICE => 'Notice', E_CORE_ERROR => 'Core Error', E_CORE_WARNING => 'Core Warning', E_COMPILE_ERROR => 'Compile Error', E_COMPILE_WARNING => 'Compile Warning', E_USER_ERROR => 'User Error', E_USER_WARNING => 'User Warning', E_USER_NOTICE => 'User Notice', E_STRICT => 'Strict Notice', E_RECOVERABLE_ERROR => 'Recoverable Error', E_DEPRECATED => 'Deprecated', E_USER_DEPRECATED => 'User Deprecated' ]; $errorType = $errorLevels[$errno] ?? 'Unknown Error'; $error = [ 'type' => 'php_error', 'level' => $errno, 'error_type' => $errorType, 'message' => $errstr, 'file' => $errfile, 'line' => $errline, 'context' => isset($errcontext['this']) ? get_class($errcontext['this']) : 'global', 'timestamp' => date('Y-m-d H:i:s'), 'request_uri' => $_SERVER['REQUEST_URI'] ?? '', 'remote_ip' => Security::getClientIP(), 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'session_id' => session_id(), 'backtrace' => self::getBacktrace() ]; // Log the error self::logError($error); // In development, show errors if (Config::isEnvironment('development')) { // Return error info for debugging without exposing sensitive data return [ 'error' => true, 'type' => $errorType, 'message' => $errstr, 'file' => basename($errfile), 'line' => $errline ]; } // In production, don't show errors if (Config::isEnvironment('production')) { return false; // Let PHP handle it } // For PHP's error handling, still need to return false for some errors return ($errno & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR)) ? false : true; } /** * Uncaught exception handler */ public static function exceptionHandler($exception) { $error = [ 'type' => 'uncaught_exception', 'class' => get_class($exception), 'message' => $exception->getMessage(), 'code' => $exception->getCode(), 'file' => $exception->getFile(), 'line' => $exception->getLine(), 'timestamp' => date('Y-m-d H:i:s'), 'request_uri' => $_SERVER['REQUEST_URI'] ?? '', 'remote_ip' => Security::getClientIP(), 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'session_id' => session_id(), 'backtrace' => self::getBacktrace(), 'previous' => $exception->getPrevious() ? $exception->getPrevious()->getMessage() : null ]; // Log the exception self::logError($error); // Handle display based on environment if (Config::isEnvironment('development')) { // Show detailed error page self::renderErrorPage($error, 500); exit; } else { // Show generic error page in production self::renderErrorPage([ 'message' => 'An unexpected error occurred. Please try again later.' ], 500); exit; } } /** * Shutdown handler for fatal errors */ public static function shutdownHandler() { $error = error_get_last(); if ($error !== null) { $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR]; if (in_array($error['type'], $fatalErrors)) { $error['type'] = 'fatal_error'; $error['timestamp'] = date('Y-m-d H:i:s'); $error['request_uri'] = $_SERVER['REQUEST_URI'] ?? ''; $error['remote_ip'] = Security::getClientIP(); $error['user_agent'] = $_SERVER['HTTP_USER_AGENT'] ?? ''; $error['session_id'] = session_id(); $error['backtrace'] = self::getBacktrace(); self::logError($error); if (Config::isEnvironment('development')) { echo "
" . htmlspecialchars(print_r($error, true)) . ""; } else { self::renderErrorPage([ 'message' => 'A critical error occurred. Our team has been notified.' ], 500); } } } // Clean up tasks (optional) self::performCleanup(); } /** * Log error to file and/or external service */ private static function logError($error) { $logMessage = sprintf( "[%s] %s: %s in %s:%d\nContext: %s\nIP: %s\nURI: %s\nBacktrace:\n%s\n---\n", $error['timestamp'], $error['type'] ?? 'unknown', $error['message'] ?? 'Unknown error', $error['file'] ?? 'unknown', $error['line'] ?? 0, $error['context'] ?? 'unknown', $error['remote_ip'] ?? 'unknown', $error['request_uri'] ?? 'unknown', implode("\n", $error['backtrace'] ?? []) ); // Write to log file if (self::$logFile) { $result = file_put_contents(self::$logFile, $logMessage, FILE_APPEND | LOCK_EX); if ($result === false) { error_log("Failed to write to error log: " . self::$logFile); } } // Also log via PHP's error_log if our file fails if (!self::$logFile || !file_exists(self::$logFile)) { error_log("ErrorHandler: " . json_encode($error)); } } /** * Get backtrace safely */ private static function getBacktrace() { try { $backtrace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); $formatted = []; foreach ($backtrace as $i => $trace) { $formatted[] = sprintf( "#%d %s(%s): %s(%s)", $i, $trace['file'] ?? 'unknown', $trace['line'] ?? 'unknown', isset($trace['class']) ? $trace['class'] . '::' . $trace['function'] : $trace['function'] ?? 'unknown', isset($trace['args']) ? json_encode(count($trace['args'])) . ' args' : 'unknown args' ); } return $formatted; } catch (Exception $e) { return ["Failed to generate backtrace: " . $e->getMessage()]; } } /** * Render error page */ private static function renderErrorPage($error, $httpCode = 500) { http_response_code($httpCode); if (!headers_sent()) { header('Content-Type: text/html; charset=UTF-8'); header('Cache-Control: no-cache, no-store, must-revalidate'); } $title = $httpCode === 404 ? 'Page Not Found' : 'Server Error'; $message = $error['message'] ?? 'An unexpected error occurred'; echo "
{$message}
"; if (Config::isEnvironment('development') && isset($error['file'])) { echo "