<commit_before><?php
namespace Asgard\Debug;

/**
 * Error handler.
 * @author <NAME> <<EMAIL>>
 */
class ErrorHandler {
	/**
	 * Reserved memory.
	 * @var string
	 */
	protected static $reservedMemory;
	/**
	 * Error at startup.
	 * @var array
	 */
	protected static $errorAtStart;
	/**
	 * Ignore directories.
	 * @var array
	 */
	protected $ignoreDirs = [];
	/**
	 * Log PHP errors flag.
	 * @var boolean
	 */
	protected $logPHPErrors = false;
	/**
	 * Logger
	 * @var \Psr\Log\LoggerInterface
	 */
	protected $logger;
	/**
	 * Debug flag.
	 * @var boolean
	 */
	protected $debug;

	public function __construct() {
		$this->debug = true;
	}

	/**
	 * Set debug flag.
	 * @param  boolean $debug
	 * @return ErrorHandler $this
	 */
	public function setDebug($debug) {
		$this->debug = $debug;
		return $this;
	}

	/**
	 * Register the PHP error handler.
	 * @return ErrorHandler
	 */
	public static function register() {
		static::$reservedMemory = str_repeat('a', 10240);
		static::$errorAtStart = error_get_last();

		$errorHandler = new static();
		set_error_handler([$errorHandler, 'phpErrorHandler']);
		set_exception_handler([$errorHandler, 'exceptionHandler']);
		register_shutdown_function([$errorHandler, 'shutdownFunction']);
		return $errorHandler;
	}

	/**
	 * Called on shutdown.
	 */
	public function shutdownFunction() {
		if(($e=error_get_last()) && $e !== static::$errorAtStart) {
			foreach($this->ignoreDirs as $dir) {
				if(strpos($e['file'], $dir) === 0)
					return;
			}

			while(ob_get_level()) { ob_end_clean(); }
			$exceptionHandler = set_exception_handler(function() {});
			restore_exception_handler();
			$exception = new FatalErrorException($e['message'], $e['type'], 0, $e['file'], $e['line']);
			call_user_func_array($exceptionHandler, [$exception]);
		}
	}

	/**
	 * Ignore PHP errors from a directory.
	 * @param  string $dir
	 * @return ErrorHandler $this
	 */
	public function ignoreDir($dir) {
		$this->ignoreDirs[] = realpath($dir);
		return $this;
	}

	/**
	 * Return backtrace from an exception.
	 * @param  \Exception $e
	 * @return array
	 */
	public function getBacktraceFromException(\Exception $e) {
		$trace = $e->getTrace();

		if($e instanceof FatalErrorException) {
			#Credit to Symfony
			if(function_exists('xdebug_get_function_stack')) {
				$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4);
				foreach($trace as $i => $frame) {
					if(!isset($frame['type']))
						$trace[$i]['type'] = '?';
					elseif($trace[$i]['type'] === 'dynamic')
						$trace[$i]['type'] = '->';
					elseif($trace[$i]['type'] === 'static')
						$trace[$i]['type'] = '::';

					if(isset($frame['params']) && !isset($frame['args'])) {
						$trace[$i]['args'] = $frame['params'];
						unset($trace[$i]['params']);
					}
				}
				$lastStep = [
					'line' => $e->getLine(),
					'file' => $e->getFile(),
				];
				array_unshift($trace, $lastStep);
			}
			else {
				$trace = [[
					'line' => $e->getLine(),
					'file' => $e->getFile(),
				]];
			}
		}

		return $trace;
	}

	/**
	 * To log PHP errors.
	 * @param boolean $log
	 */
	public function setLogPHPErrors($log) {
		$this->logPHPErrors = $log;
		return $this;
	}

	/**
	 * PHP Error handler.
	 * @param  integer $errno
	 * @param  string  $errstr
	 * @param  string  $errfile
	 * @param  integer $errline
	 * @throws \ErrorException For all PHP errors.
	 */
	public function phpErrorHandler($errno, $errstr, $errfile, $errline) {
		foreach($this->ignoreDirs as $dir) {
			if(strpos($errfile, $dir) === 0)
				return;
		}

		if($this->isLogging() && $this->logPHPErrors)
			$this->log(\Psr\Log\LogLevel::NOTICE, 'PHP ('.static::getPHPError($errno).'): '.$errstr, $errfile, $errline);
		throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
	}

	/**
	 * Exception handler.
	 * @param  \Exception $e
	 * @param  boolean   $kill kill the process
	 */
	public function exceptionHandler(\Exception $e, $kill=true) {
		static::$reservedMemory = null;

		$this->logException($e);

		if($kill) {
			if(!headers_sent())
				header(isset($_SERVER['SERVER_PROTOCOL']) ? $_SERVER['SERVER_PROTOCOL']:''.' 500 Internal Server Error', true, 500);
			if(php_sapi_name() === 'cli' || $this->debug) {
				$trace = $this->getBacktraceFromException($e);

				if($e instanceof PSRException)
					$msg = $e->getMessage();
				elseif($e instanceof \ErrorException)
					$msg = 'PHP ('.static::getPHPError($e->getCode()).'): '.$e->getMessage();
				else
					$msg = get_class($e).': '.$e->getMessage();

				$result = '';
				if($msg)
					$result .= $msg."\n\n";<commit_msg>fix fatal error http status code<commit_after><?php
namespace Asgard\Debug;

/**
 * Error handler.
 * @author <NAME> <<EMAIL>>
 */
class ErrorHandler {
	/**
	 * Reserved memory.
	 * @var string
	 */
	protected static $reservedMemory;
	/**
	 * Error at startup.
	 * @var array
	 */
	protected static $errorAtStart;
	/**
	 * Ignore directories.
	 * @var array
	 */
	protected $ignoreDirs = [];
	/**
	 * Log PHP errors flag.
	 * @var boolean
	 */
	protected $logPHPErrors = false;
	/**
	 * Logger
	 * @var \Psr\Log\LoggerInterface
	 */
	protected $logger;
	/**
	 * Debug flag.
	 * @var boolean
	 */
	protected $debug;

	public function __construct() {
		$this->debug = true;
	}

	/**
	 * Set debug flag.
	 * @param  boolean $debug
	 * @return ErrorHandler $this
	 */
	public function setDebug($debug) {
		$this->debug = $debug;
		return $this;
	}

	/**
	 * Register the PHP error handler.
	 * @return ErrorHandler
	 */
	public static function register() {
		static::$reservedMemory = str_repeat('a', 10240);
		static::$errorAtStart = error_get_last();

		$errorHandler = new static();
		set_error_handler([$errorHandler, 'phpErrorHandler']);
		set_exception_handler([$errorHandler, 'exceptionHandler']);
		register_shutdown_function([$errorHandler, 'shutdownFunction']);
		return $errorHandler;
	}

	/**
	 * Called on shutdown.
	 */
	public function shutdownFunction() {
		if(($e=error_get_last()) && $e !== static::$errorAtStart) {
			foreach($this->ignoreDirs as $dir) {
				if(strpos($e['file'], $dir) === 0)
					return;
			}

			while(ob_get_level()) { ob_end_clean(); }
			$exceptionHandler = set_exception_handler(function() {});
			restore_exception_handler();
			$exception = new FatalErrorException($e['message'], $e['type'], 0, $e['file'], $e['line']);
			call_user_func_array($exceptionHandler, [$exception]);
		}
	}

	/**
	 * Ignore PHP errors from a directory.
	 * @param  string $dir
	 * @return ErrorHandler $this
	 */
	public function ignoreDir($dir) {
		$this->ignoreDirs[] = realpath($dir);
		return $this;
	}

	/**
	 * Return backtrace from an exception.
	 * @param  \Exception $e
	 * @return array
	 */
	public function getBacktraceFromException(\Exception $e) {
		$trace = $e->getTrace();

		if($e instanceof FatalErrorException) {
			#Credit to Symfony
			if(function_exists('xdebug_get_function_stack')) {
				$trace = array_slice(array_reverse(xdebug_get_function_stack()), 4);
				foreach($trace as $i => $frame) {
					if(!isset($frame['type']))
						$trace[$i]['type'] = '?';
					elseif($trace[$i]['type'] === 'dynamic')
						$trace[$i]['type'] = '->';
					elseif($trace[$i]['type'] === 'static')
						$trace[$i]['type'] = '::';

					if(isset($frame['params']) && !isset($frame['args'])) {
						$trace[$i]['args'] = $frame['params'];
						unset($trace[$i]['params']);
					}
				}
				$lastStep = [
					'line' => $e->getLine(),
					'file' => $e->getFile(),
				];
				array_unshift($trace, $lastStep);
			}
			else {
				$trace = [[
					'line' => $e->getLine(),
					'file' => $e->getFile(),
				]];
			}
		}

		return $trace;
	}

	/**
	 * To log PHP errors.
	 * @param boolean $log
	 */
	public function setLogPHPErrors($log) {
		$this->logPHPErrors = $log;
		return $this;
	}

	/**
	 * PHP Error handler.
	 * @param  integer $errno
	 * @param  string  $errstr
	 * @param  string  $errfile
	 * @param  integer $errline
	 * @throws \ErrorException For all PHP errors.
	 */
	public function phpErrorHandler($errno, $errstr, $errfile, $errline) {
		foreach($this->ignoreDirs as $dir) {
			if(strpos($errfile, $dir) === 0)
				return;
		}

		if($this->isLogging() && $this->logPHPErrors)
			$this->log(\Psr\Log\LogLevel::NOTICE, 'PHP ('.static::getPHPError($errno).'): '.$errstr, $errfile, $errline);
		throw new \ErrorException($errstr, $errno, 0, $errfile, $errline);
	}

	/**
	 * Exception handler.
	 * @param  \Exception $e
	 * @param  boolean   $kill kill the process
	 */
	public function exceptionHandler(\Exception $e, $kill=true) {
		static::$reservedMemory = null;

		$this->logException($e);

		if($kill) {
			if(!headers_sent())
				http_response_code(500);

			if(php_sapi_name() === 'cli' || $this->debug) {
				$trace = $this->getBacktraceFromException($e);

				if($e instanceof PSRException)
					$msg = $e->getMessage();
				elseif($e instanceof \ErrorException)
					$msg = 'PHP ('.static::getPHPError($e->getCode()).'): '.$e->getMessage();
				else
					$msg = get_class($e).': '.$e->getMessage();

				$result = '';
				if($msg)
					$result .= $msg."\n\n";
{'fraction_non_alphanumeric': 0.19210468440730152, 'fraction_numerical': 0.0031889157686386628, 'mean_word_length': 3.4891411648568607, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 63, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '77895', 'n_tokens_mistral': 3573, 'n_tokens_neox': 3045, 'n_words': 643}