add trashes
This commit is contained in:
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* This file is part of CodeIgniter 4 framework.
|
||||
*
|
||||
* (c) CodeIgniter Foundation <admin@codeigniter.com>
|
||||
*
|
||||
* For the full copyright and license information, please view
|
||||
* the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace CodeIgniter\Debug;
|
||||
|
||||
use CodeIgniter\HTTP\RequestInterface;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Exceptions as ExceptionsConfig;
|
||||
use Throwable;
|
||||
|
||||
/**
|
||||
* Provides common functions for exception handlers,
|
||||
* especially around displaying the output.
|
||||
*/
|
||||
abstract class BaseExceptionHandler
|
||||
{
|
||||
/**
|
||||
* Config for debug exceptions.
|
||||
*/
|
||||
protected ExceptionsConfig $config;
|
||||
|
||||
/**
|
||||
* Nesting level of the output buffering mechanism
|
||||
*/
|
||||
protected int $obLevel;
|
||||
|
||||
/**
|
||||
* The path to the directory containing the
|
||||
* cli and html error view directories.
|
||||
*/
|
||||
protected ?string $viewPath = null;
|
||||
|
||||
public function __construct(ExceptionsConfig $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
$this->obLevel = ob_get_level();
|
||||
|
||||
if ($this->viewPath === null) {
|
||||
$this->viewPath = rtrim($this->config->errorViewPath, '\\/ ') . DIRECTORY_SEPARATOR;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main entry point into the handler.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
abstract public function handle(
|
||||
Throwable $exception,
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
int $statusCode,
|
||||
int $exitCode,
|
||||
);
|
||||
|
||||
/**
|
||||
* Gathers the variables that will be made available to the view.
|
||||
*/
|
||||
protected function collectVars(Throwable $exception, int $statusCode): array
|
||||
{
|
||||
// Get the first exception.
|
||||
$firstException = $exception;
|
||||
|
||||
while ($prevException = $firstException->getPrevious()) {
|
||||
$firstException = $prevException;
|
||||
}
|
||||
|
||||
$trace = $firstException->getTrace();
|
||||
|
||||
if ($this->config->sensitiveDataInTrace !== []) {
|
||||
$trace = $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace);
|
||||
}
|
||||
|
||||
return [
|
||||
'title' => $exception::class,
|
||||
'type' => $exception::class,
|
||||
'code' => $statusCode,
|
||||
'message' => $exception->getMessage(),
|
||||
'file' => $exception->getFile(),
|
||||
'line' => $exception->getLine(),
|
||||
'trace' => $trace,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mask sensitive data in the trace.
|
||||
*/
|
||||
protected function maskSensitiveData(array $trace, array $keysToMask, string $path = ''): array
|
||||
{
|
||||
foreach ($trace as $i => $line) {
|
||||
$trace[$i]['args'] = $this->maskData($line['args'], $keysToMask);
|
||||
}
|
||||
|
||||
return $trace;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|object $args
|
||||
*
|
||||
* @return array|object
|
||||
*/
|
||||
private function maskData($args, array $keysToMask, string $path = '')
|
||||
{
|
||||
foreach ($keysToMask as $keyToMask) {
|
||||
$explode = explode('/', $keyToMask);
|
||||
$index = end($explode);
|
||||
|
||||
if (str_starts_with(strrev($path . '/' . $index), strrev($keyToMask))) {
|
||||
if (is_array($args) && array_key_exists($index, $args)) {
|
||||
$args[$index] = '******************';
|
||||
} elseif (
|
||||
is_object($args) && property_exists($args, $index)
|
||||
&& isset($args->{$index}) && is_scalar($args->{$index})
|
||||
) {
|
||||
$args->{$index} = '******************';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_array($args)) {
|
||||
foreach ($args as $pathKey => $subarray) {
|
||||
$args[$pathKey] = $this->maskData($subarray, $keysToMask, $path . '/' . $pathKey);
|
||||
}
|
||||
} elseif (is_object($args)) {
|
||||
foreach ($args as $pathKey => $subarray) {
|
||||
$args->{$pathKey} = $this->maskData($subarray, $keysToMask, $path . '/' . $pathKey);
|
||||
}
|
||||
}
|
||||
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes memory usage in real-world units. Intended for use
|
||||
* with memory_get_usage, etc.
|
||||
*
|
||||
* @used-by app/Views/errors/html/error_exception.php
|
||||
*/
|
||||
protected static function describeMemory(int $bytes): string
|
||||
{
|
||||
helper('number');
|
||||
|
||||
return number_to_size($bytes, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a syntax-highlighted version of a PHP file.
|
||||
*
|
||||
* @used-by app/Views/errors/html/error_exception.php
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
protected static function highlightFile(string $file, int $lineNumber, int $lines = 15)
|
||||
{
|
||||
if ($file === '' || ! is_readable($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set our highlight colors:
|
||||
if (function_exists('ini_set')) {
|
||||
ini_set('highlight.comment', '#767a7e; font-style: italic');
|
||||
ini_set('highlight.default', '#c7c7c7');
|
||||
ini_set('highlight.html', '#06B');
|
||||
ini_set('highlight.keyword', '#f1ce61;');
|
||||
ini_set('highlight.string', '#869d6a');
|
||||
}
|
||||
|
||||
try {
|
||||
$source = file_get_contents($file);
|
||||
} catch (Throwable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$source = str_replace(["\r\n", "\r"], "\n", $source);
|
||||
$source = explode("\n", highlight_string($source, true));
|
||||
|
||||
if (PHP_VERSION_ID < 80300) {
|
||||
$source = str_replace('<br />', "\n", $source[1]);
|
||||
$source = explode("\n", str_replace("\r\n", "\n", $source));
|
||||
} else {
|
||||
// We have to remove these tags since we're preparing the result
|
||||
// ourselves and these tags are added manually at the end.
|
||||
$source = str_replace(['<pre><code>', '</code></pre>'], '', $source);
|
||||
}
|
||||
|
||||
// Get just the part to show
|
||||
$start = max($lineNumber - (int) round($lines / 2), 0);
|
||||
|
||||
// Get just the lines we need to display, while keeping line numbers...
|
||||
$source = array_splice($source, $start, $lines, true);
|
||||
|
||||
// Used to format the line number in the source
|
||||
$format = '% ' . strlen((string) ($start + $lines)) . 'd';
|
||||
|
||||
$out = '';
|
||||
// Because the highlighting may have an uneven number
|
||||
// of open and close span tags on one line, we need
|
||||
// to ensure we can close them all to get the lines
|
||||
// showing correctly.
|
||||
$spans = 0;
|
||||
|
||||
foreach ($source as $n => $row) {
|
||||
$spans += substr_count($row, '<span') - substr_count($row, '</span');
|
||||
$row = str_replace(["\r", "\n"], ['', ''], $row);
|
||||
|
||||
if (($n + $start + 1) === $lineNumber) {
|
||||
preg_match_all('#<[^>]+>#', $row, $tags);
|
||||
|
||||
$out .= sprintf(
|
||||
"<span class='line highlight'><span class='number'>{$format}</span> %s\n</span>%s",
|
||||
$n + $start + 1,
|
||||
strip_tags($row),
|
||||
implode('', $tags[0]),
|
||||
);
|
||||
} else {
|
||||
$out .= sprintf('<span class="line"><span class="number">' . $format . '</span> %s', $n + $start + 1, $row) . "\n";
|
||||
// We're closing only one span tag we added manually line before,
|
||||
// so we have to increment $spans count to close this tag later.
|
||||
$spans++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($spans > 0) {
|
||||
$out .= str_repeat('</span>', $spans);
|
||||
}
|
||||
|
||||
return '<pre><code>' . $out . '</code></pre>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an exception and status code will display the error to the client.
|
||||
*
|
||||
* @param string|null $viewFile
|
||||
*/
|
||||
protected function render(Throwable $exception, int $statusCode, $viewFile = null): void
|
||||
{
|
||||
if ($viewFile === null) {
|
||||
echo 'The error view file was not specified. Cannot display error view.';
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (! is_file($viewFile)) {
|
||||
echo 'The error view file "' . $viewFile . '" was not found. Cannot display error view.';
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo (function () use ($exception, $statusCode, $viewFile): string {
|
||||
$vars = $this->collectVars($exception, $statusCode);
|
||||
extract($vars, EXTR_SKIP);
|
||||
|
||||
// CLI error views output to STDERR/STDOUT, so ob_start() does not work.
|
||||
ob_start();
|
||||
include $viewFile;
|
||||
|
||||
return ob_get_clean();
|
||||
})();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user