Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions app/Views/errors/html/debug.css
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,16 @@ p.lead {
.header .container {
padding: 1rem;
}
.header-title {
align-items: flex-start;
display: flex;
gap: 1rem;
justify-content: space-between;
}
.header h1 {
font-size: 2.5rem;
font-weight: 500;
min-width: 0;
}
.header p {
font-size: 1.2rem;
Expand All @@ -65,8 +72,58 @@ p.lead {
display: inline;
}

.error-report {
flex: 0 0 auto;
margin-top: 0.35rem;
}

.error-report-button {
align-items: center;
background: rgba(255,255,255,0.35);
border: 1px solid rgba(0,0,0,0.14);
border-radius: 5px;
box-sizing: border-box;
color: var(--main-text-color);
cursor: pointer;
display: inline-flex;
font-size: 0.82rem;
font-weight: 500;
gap: 0.35rem;
height: 1.875rem;
justify-content: center;
line-height: 1;
padding: 0 0.65rem;
transition: background-color 160ms ease-in-out, border-color 160ms ease-in-out, color 160ms ease-in-out, box-shadow 160ms ease-in-out;
white-space: nowrap;
width: 7.15rem;
}

.error-report-button:hover {
background: rgba(255,255,255,0.6);
border-color: rgba(0,0,0,0.22);
color: var(--dark-text-color);
box-shadow: 0 1px 2px rgba(0,0,0,0.04);
}

.error-report-button:focus-visible {
border-color: rgba(0,0,0,0.35);
outline: 0;
box-shadow: 0 0 0 2px rgba(220,72,20,0.16);
}

.error-report-button:active {
background: rgba(255,255,255,0.75);
}

.error-report-icon {
flex: 0 0 auto;
height: 0.72rem;
width: 0.72rem;
}

.environment {
background: var(--brand-primary-color);
box-sizing: border-box;
color: var(--main-bg-color);
text-align: center;
padding: calc(4px + 0.2083vw);
Expand All @@ -75,6 +132,26 @@ p.lead {
position: fixed;
}

@media (max-width: 40rem) {
.header {
margin-top: 0;
}

.header p {
font-size: 1.1rem;
line-height: 1.45;
margin-top: 0.35rem;
overflow-wrap: anywhere;
}

.environment {
font-size: 0.9rem;
line-height: 1.25;
padding: 0.45rem 0.75rem;
position: static;
}
}

.source {
background: #343434;
color: var(--light-text-color);
Expand Down
50 changes: 50 additions & 0 deletions app/Views/errors/html/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,53 @@ function toggle(elem)

return false;
}

function copyErrorReport(reportId, button)
{
var report = document.getElementById(reportId);

if (navigator.clipboard && window.isSecureContext)
{
navigator.clipboard
.writeText(report.value)
.then(() => showCopiedButton(button))
.catch(() => copyErrorReportWithFallback(report.value, button));

return false;
}

copyErrorReportWithFallback(report.value, button);

return false;
}

function copyErrorReportWithFallback(text, button)
{
var textarea = document.createElement('textarea');
textarea.value = text;
textarea.setAttribute('readonly', '');
textarea.style.position = 'fixed';
textarea.style.top = '-1000px';
textarea.style.left = '-1000px';

document.body.appendChild(textarea);
textarea.select();

if (document.execCommand('copy'))
{
showCopiedButton(button);
}

document.body.removeChild(textarea);
}

function showCopiedButton(button)
{
button.defaultHtml = button.defaultHtml || button.innerHTML;
button.innerHTML = 'Copied!';

window.clearTimeout(button.copyResetTimer);
button.copyResetTimer = window.setTimeout(() => {
button.innerHTML = button.defaultHtml;
}, 1500);
}
39 changes: 36 additions & 3 deletions app/Views/errors/html/error_exception.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
use CodeIgniter\CodeIgniter;

$errorId = uniqid('error', true);
$copyableErrorReportId = $errorId . 'copyableErrorReport';
?>
<!doctype html>
<html>
Expand Down Expand Up @@ -30,7 +31,38 @@
Environment: <?= ENVIRONMENT ?>
</div>
<div class="container">
<h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
<div class="header-title">
<h1><?= esc($title), esc($exception->getCode() ? ' #' . $exception->getCode() : '') ?></h1>
<div class="error-report">
<button
class="error-report-button"
type="button"
aria-live="polite"
onclick="return copyErrorReport('<?= esc($copyableErrorReportId, 'attr') ?>', this);"
>
<svg
aria-hidden="true"
class="error-report-icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<rect width="14" height="14" x="8" y="8" rx="2" ry="2"></rect>
<path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"></path>
</svg>
<span class="error-report-label">Copy Details</span>
</button>
<textarea
id="<?= esc($copyableErrorReportId, 'attr') ?>"
readonly
hidden
><?php include __DIR__ . '/error_report.php'; ?></textarea>
</div>
</div>
<p>
<?= nl2br(esc($exception->getMessage())) ?>
<a href="https://www.duckduckgo.com/?q=<?= urlencode($title . ' ' . preg_replace('#\'.*\'|".*"#Us', '', $exception->getMessage())) ?>"
Expand Down Expand Up @@ -342,8 +374,9 @@

<!-- Response -->
<?php
$response = service('response');
$response->setStatusCode(http_response_code());
$response = service('response');
$responseStatusCode = http_response_code();
$response->setStatusCode($responseStatusCode === false || $responseStatusCode === 0 ? $code : $responseStatusCode);
?>
<div class="content" id="response">
<table>
Expand Down
127 changes: 127 additions & 0 deletions app/Views/errors/html/error_report.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
<?php

use CodeIgniter\CodeIgniter;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\URI;

$reportMessage = str_replace(["\r\n", "\r"], "\n", $message);
$reportTitle = trim($reportMessage);
$reportTitle = $reportTitle === '' ? $title : explode("\n", $reportTitle, 2)[0];
$messageLines = str_contains($reportMessage, "\n");

$reportResponse = service('response', null, false);
$reportResponse->setStatusCode($code);

$report = [
'# ' . $reportTitle,
'',
'## Exception',
'',
'- Type: ' . $type,
'- Status Code: ' . $code,
'- Status: ' . $reportResponse->getReasonPhrase(),
$messageLines ? '- Message:' : '- Message: ' . $reportMessage,
];

if ($messageLines) {
$report[] = '';
$report[] = '```text';
$report[] = $reportMessage;
$report[] = '```';
}

$report[] = '';
$report[] = '## Environment';
$report[] = '';
$report[] = '- PHP: ' . PHP_VERSION;
$report[] = '- CodeIgniter: ' . CodeIgniter::CI_VERSION;
$report[] = '- Environment: ' . ENVIRONMENT;
$report[] = '- SAPI: ' . PHP_SAPI;
$report[] = '- Time: ' . date('Y-m-d H:i:s e');
$report[] = '- Memory Usage: ' . number_format(memory_get_usage(true) / 1024 / 1024, 2) . ' MB';

$reportRequest = service('request');

if ($reportRequest instanceof IncomingRequest) {
$reportPath = '/' . ltrim($reportRequest->getPath(), '/');
$reportUri = $reportRequest->getUri();
$reportUrl = $reportPath;

if ($reportUri->getHost() !== '') {
$reportUrl = URI::createURIString(
$reportUri->getScheme(),
$reportUri->getHost() . ($reportUri->getPort() === null ? '' : ':' . $reportUri->getPort()),
$reportPath,
);
}

$report[] = '';
$report[] = '## Request';
$report[] = '';
$report[] = '- Method: ' . $reportRequest->getMethod();
$report[] = '- Path: ' . $reportPath;
$report[] = '- URL: ' . $reportUrl;
$report[] = '- User Agent: ' . $reportRequest->getUserAgent()->getAgentString();
}

$report[] = '';
$report[] = '## Source';
$report[] = '';
$report[] = '`' . clean_path($file) . ':' . $line . '`';

if (is_file($file) && is_readable($file)) {
$sourceLines = file($file, FILE_IGNORE_NEW_LINES);

if ($sourceLines !== false) {
$startLine = max($line - 5, 1);
$endLine = min($line + 5, count($sourceLines));

$report[] = '';
$report[] = '```php';

for ($sourceLine = $startLine; $sourceLine <= $endLine; $sourceLine++) {
$report[] = sprintf(
'%s%4d %s',
$sourceLine === $line ? '>' : ' ',
$sourceLine,
$sourceLines[$sourceLine - 1],
);
}

$report[] = '```';
}
}

$previousException = $exception->getPrevious();

if ($previousException instanceof Throwable) {
$report[] = '';
$report[] = '## Previous Exceptions';

while ($previousException instanceof Throwable) {
$report[] = '* ' . $previousException::class . ' - ' . $previousException->getMessage();
$report[] = ' ' . clean_path($previousException->getFile()) . ':' . $previousException->getLine();

$previousException = $previousException->getPrevious();
}
}

if ($trace !== []) {
$report[] = '';
$report[] = '## Stack Trace';
$report[] = '';
$report[] = '```text';

foreach (array_slice($trace, 0, 50) as $reportIndex => $reportRow) {
$reportLocation = isset($reportRow['file'], $reportRow['line'])
? clean_path($reportRow['file']) . ':' . $reportRow['line']
: '{PHP internal code}';
$reportCall = ($reportRow['class'] ?? '') . ($reportRow['type'] ?? '') . ($reportRow['function'] ?? '');

$report[] = $reportIndex . ' ' . $reportLocation . ($reportCall === '' ? '' : ' ' . $reportCall . '()');
}

$report[] = '```';
}

echo esc(implode("\n", $report)) . "\n";
Loading
Loading