From 6039f5de53634469ce6c50ff12c97105b99965e8 Mon Sep 17 00:00:00 2001 From: prasad <prasad@vtiger.com> Date: Sat, 4 May 2024 14:17:03 +0530 Subject: [PATCH] Added PhpLogHandler helper class to vtlib --- vtlib/Vtiger/Utils/PhpLogHandler.php | 133 +++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 vtlib/Vtiger/Utils/PhpLogHandler.php diff --git a/vtlib/Vtiger/Utils/PhpLogHandler.php b/vtlib/Vtiger/Utils/PhpLogHandler.php new file mode 100644 index 000000000..cfad35f71 --- /dev/null +++ b/vtlib/Vtiger/Utils/PhpLogHandler.php @@ -0,0 +1,133 @@ +<?php +/*+*********************************************************************************** + * The contents of this file are subject to the vtiger CRM Public License Version 1.0 + * ("License"); You may not use this file except in compliance with the License + * The Original Code is: vtiger CRM Open Source + * The Initial Developer of the Original Code is vtiger. + * Portions created by vtiger are Copyright (C) vtiger. + * All Rights Reserved. + *************************************************************************************/ + +/** + * USAGE: For E_ALL strict development - create (config_override.php) with code below. + * + * ini_set("display_errors", "off"); + * error_reporting(E_ALL); + * ini_set("log_errors", "on"); + * ini_set("error_log", "logs/phperr.log"); + * require_once "vtlib/Vtiger/Utils/PhpLogHandler.php"; + * set_error_handler(Vtiger_PhpLogHandler::getErrorHandler(__DIR__)); + * set_exception_handler(Vtiger_PhpLogHandler::getExceptionHandler(__DIR__)); + */ + +class Vtiger_PhpLogHandler { + + /** + * Capture context of request in Log to review later. + */ + public static function getRequestContextToLog() { + $ctx = ""; + if (isset($_SERVER)) { + $ctx = $_SERVER["REQUEST_METHOD"] . " " . str_replace("?" . $_SERVER["QUERY_STRING"], "", $_SERVER["REQUEST_URI"]); + $params = []; + foreach (["module", "view", "action", "mode"] as $key) { + if (isset($_REQUEST[$key])) $params[$key] = $_REQUEST[$key]; + } + $ctx .= "?" . http_build_query($params); + } + return $ctx; + } + + /** + * Redacted PHP error handler. + * - Retains only relative reference to the source file. + * - Logs to file if provided always (or) displays to console only when display_errors is on. + */ + public static function getErrorHandler($basedir, $logfile = null) { + $display_errors = filter_var(ini_get('display_errors'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + $log_errors = filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + if (!$logfile) $logfile = ini_get('error_log'); + + $logctx = Vtiger_PhpLogHandler::getRequestContextToLog(); + + return function($errno, $errstr, $errfile, $errline) use ($display_errors, $log_errors, $basedir, $logfile, $logctx) { + // nothing todo return early. + if (!$display_errors && !$log_errors && ($log_errors && !$logfile)) { + return; + } + + $errtype = $errno; + switch($errno){ + case E_DEPRECATED: $errtype = "Deprecated"; break; + case E_ERROR: $errtype = "Error"; break; + case E_WARNING: $errtype = "Warning"; break; + case E_PARSE: $errtype = "Parse Error"; break; + case E_NOTICE: $errtype = "Notice"; break; + case E_CORE_ERROR: $errtype = "Core Error"; break; + case E_CORE_WARNING: $errtype = "Core Warning"; break; + case E_COMPILE_ERROR: $errtype = "Compile Error"; break; + case E_COMPILE_WARNING: $errtype = "Compile Warning"; break; + case E_USER_ERROR: $errtype = "User Error"; break; + case E_USER_WARNING: $errtype = "User Warning"; break; + case E_USER_NOTICE: $errtype = "User Notice"; break; + case E_STRICT: $errtype = "Strict Notice"; break; + case E_RECOVERABLE_ERROR: $errtype = "Recoverable Error"; break; + default: $errtype = "Unknown error ($errno)"; break; + } + $errfilerel = str_replace(rtrim($basedir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR, "", $errfile); + + // format message same as default PHP + $msg = sprintf("%s: %s in %s on line %s\n", $errtype, $errstr, $errfilerel, $errline); + if ($logfile) { + $tmstamp = date("[Y-m-d H:i:s]"); + $fullmsg = $tmstamp . " ". $logctx . "\n" . $tmstamp . " " . $msg; + file_put_contents($logfile, $fullmsg, FILE_APPEND | LOCK_EX); + } + + // if errors are logged then don't display even when asked for security. + // php does not enforce this and when mis-configured leaks info to user/attacker. + if (!$log_errors && $display_errors) { + echo "\n$msg"; + } + }; + } + + /** + * Redacted PHP exception handler. + * - Retains only relative reference to the source file. + * - Logs to file if provided always (or) displays to console only when display_errors is on. + */ + public static function getExceptionHandler($basedir, $logfile = null) { + $display_errors = filter_var(ini_get('display_errors'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + $log_errors = filter_var(ini_get('log_errors'), FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE); + if (!$logfile) $logfile = ini_get('error_log'); + + $logctx = Vtiger_PhpLogHandler::getRequestContextToLog(); + + return function(Throwable $e) use ($display_errors, $log_errors, $basedir, $logfile, $logctx) { + // nothing todo return early. + if (!$display_errors && !$log_errors && ($log_errors && !$logfile)) { + return; + } + + $basedir = rtrim($basedir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + $errfile = str_replace($basedir, "", $e->getFile()); + $errstack= str_replace($basedir, "", $e->getTraceAsString()); + + // format message same as default PHP + $msg = sprintf("Fatal error: %s in %s:%d\nStack trace:\n%s\n thrown in %s on line %d\n", $e->getMessage(), $errfile, $e->getLine(), $errstack, $errfile, $e->getLine()); + if ($logfile) { + $tmstamp = date("[Y-m-d H:i:s]"); + $fullmsg = $tmstamp . " ". $logctx . "\n" . $tmstamp . " " . $msg; + file_put_contents($logfile, $fullmsg, FILE_APPEND | LOCK_EX); + } + + // if errors are logged then don't display even when asked for security. + // php does not enforce this and when mis-configured leaks info to user/attacker. + if (!$log_errors && $display_errors) { + echo "\n$msg"; + } + }; + } + +} \ No newline at end of file -- GitLab