499 lines
14 KiB
PHP
499 lines
14 KiB
PHP
|
|
<!DOCTYPE html>
|
||
|
|
<html lang='en'>
|
||
|
|
<head>
|
||
|
|
<meta charset='UTF-8'>
|
||
|
|
<meta name='viewport' content='width=device-width, initial-scale=1.0'>
|
||
|
|
<title>Error: <?= htmlspecialchars($errorData['type']) ?></title>
|
||
|
|
<style>
|
||
|
|
* {
|
||
|
|
margin: 0;
|
||
|
|
padding: 0;
|
||
|
|
box-sizing: border-box;
|
||
|
|
}
|
||
|
|
|
||
|
|
body {
|
||
|
|
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||
|
|
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||
|
|
color: #333;
|
||
|
|
line-height: 1.6;
|
||
|
|
min-height: 100vh;
|
||
|
|
padding: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-container {
|
||
|
|
max-width: 1200px;
|
||
|
|
margin: 0 auto;
|
||
|
|
background: white;
|
||
|
|
border-radius: 10px;
|
||
|
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-header {
|
||
|
|
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
||
|
|
color: white;
|
||
|
|
padding: 20px 30px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-title {
|
||
|
|
font-size: 24px;
|
||
|
|
margin-bottom: 5px;
|
||
|
|
display: flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 10px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-title i {
|
||
|
|
font-size: 28px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-subtitle {
|
||
|
|
font-size: 14px;
|
||
|
|
opacity: 0.9;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-content {
|
||
|
|
padding: 30px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-section {
|
||
|
|
margin-bottom: 30px;
|
||
|
|
border: 1px solid #e0e0e0;
|
||
|
|
border-radius: 8px;
|
||
|
|
overflow: hidden;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-header {
|
||
|
|
background: #f5f5f5;
|
||
|
|
padding: 15px 20px;
|
||
|
|
border-bottom: 1px solid #e0e0e0;
|
||
|
|
display: flex;
|
||
|
|
justify-content: space-between;
|
||
|
|
align-items: center;
|
||
|
|
cursor: pointer;
|
||
|
|
transition: background 0.3s;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-header:hover {
|
||
|
|
background: #e8e8e8;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-title {
|
||
|
|
font-weight: bold;
|
||
|
|
color: #333;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-toggle {
|
||
|
|
color: #666;
|
||
|
|
font-size: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.section-content {
|
||
|
|
padding: 20px;
|
||
|
|
background: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.code-block {
|
||
|
|
background: #282c34;
|
||
|
|
color: #abb2bf;
|
||
|
|
padding: 15px;
|
||
|
|
border-radius: 5px;
|
||
|
|
overflow-x: auto;
|
||
|
|
font-size: 14px;
|
||
|
|
margin: 10px 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.file-path {
|
||
|
|
color: #61afef;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
.line-number {
|
||
|
|
color: #98c379;
|
||
|
|
}
|
||
|
|
|
||
|
|
.error-message {
|
||
|
|
color: #e06c75;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
table {
|
||
|
|
width: 100%;
|
||
|
|
border-collapse: collapse;
|
||
|
|
margin: 10px 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
th, td {
|
||
|
|
padding: 10px;
|
||
|
|
text-align: left;
|
||
|
|
border-bottom: 1px solid #e0e0e0;
|
||
|
|
}
|
||
|
|
|
||
|
|
th {
|
||
|
|
background: #f5f5f5;
|
||
|
|
font-weight: bold;
|
||
|
|
}
|
||
|
|
|
||
|
|
tr:hover {
|
||
|
|
background: #f9f9f9;
|
||
|
|
}
|
||
|
|
|
||
|
|
.trace-item {
|
||
|
|
margin-bottom: 15px;
|
||
|
|
padding: 10px;
|
||
|
|
background: #f8f9fa;
|
||
|
|
border-left: 4px solid #667eea;
|
||
|
|
border-radius: 0 4px 4px 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.trace-header {
|
||
|
|
font-weight: bold;
|
||
|
|
color: #333;
|
||
|
|
margin-bottom: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.trace-location {
|
||
|
|
color: #666;
|
||
|
|
font-size: 12px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge {
|
||
|
|
display: inline-block;
|
||
|
|
padding: 4px 8px;
|
||
|
|
border-radius: 4px;
|
||
|
|
font-size: 12px;
|
||
|
|
font-weight: bold;
|
||
|
|
margin-right: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge-error {
|
||
|
|
background: #f44336;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge-warning {
|
||
|
|
background: #ff9800;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge-info {
|
||
|
|
background: #2196f3;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.badge-success {
|
||
|
|
background: #4caf50;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.environment-info {
|
||
|
|
display: grid;
|
||
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
||
|
|
gap: 15px;
|
||
|
|
margin-top: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.info-item {
|
||
|
|
background: #f8f9fa;
|
||
|
|
padding: 15px;
|
||
|
|
border-radius: 5px;
|
||
|
|
border-left: 4px solid #667eea;
|
||
|
|
}
|
||
|
|
|
||
|
|
.info-label {
|
||
|
|
font-size: 12px;
|
||
|
|
color: #666;
|
||
|
|
text-transform: uppercase;
|
||
|
|
margin-bottom: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.info-value {
|
||
|
|
font-weight: bold;
|
||
|
|
color: #333;
|
||
|
|
}
|
||
|
|
|
||
|
|
.actions {
|
||
|
|
display: flex;
|
||
|
|
gap: 10px;
|
||
|
|
margin-top: 20px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn {
|
||
|
|
padding: 10px 20px;
|
||
|
|
border: none;
|
||
|
|
border-radius: 5px;
|
||
|
|
cursor: pointer;
|
||
|
|
font-weight: bold;
|
||
|
|
transition: all 0.3s;
|
||
|
|
text-decoration: none;
|
||
|
|
display: inline-flex;
|
||
|
|
align-items: center;
|
||
|
|
gap: 5px;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-primary {
|
||
|
|
background: #667eea;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-primary:hover {
|
||
|
|
background: #5a6fd8;
|
||
|
|
transform: translateY(-2px);
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-secondary {
|
||
|
|
background: #6c757d;
|
||
|
|
color: white;
|
||
|
|
}
|
||
|
|
|
||
|
|
.btn-secondary:hover {
|
||
|
|
background: #5a6268;
|
||
|
|
transform: translateY(-2px);
|
||
|
|
}
|
||
|
|
|
||
|
|
@media (max-width: 768px) {
|
||
|
|
.error-container {
|
||
|
|
border-radius: 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
.environment-info {
|
||
|
|
grid-template-columns: 1fr;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
.hidden {
|
||
|
|
display: none;
|
||
|
|
}
|
||
|
|
</style>
|
||
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
||
|
|
</head>
|
||
|
|
<body>
|
||
|
|
<div class="error-container">
|
||
|
|
<div class="error-header">
|
||
|
|
<h1 class="error-title">
|
||
|
|
<i class="fas fa-exclamation-triangle"></i>
|
||
|
|
<?= htmlspecialchars($errorData['type']) ?>
|
||
|
|
</h1>
|
||
|
|
<div class="error-subtitle">
|
||
|
|
<?= htmlspecialchars($errorData['message']) ?>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="error-content">
|
||
|
|
<!-- Error Details -->
|
||
|
|
<div class="error-section">
|
||
|
|
<div class="section-header" onclick="toggleSection('details')">
|
||
|
|
<span class="section-title">Error Details</span>
|
||
|
|
<span class="section-toggle" id="toggle-details">▼</span>
|
||
|
|
</div>
|
||
|
|
<div class="section-content" id="section-details">
|
||
|
|
<div class="code-block">
|
||
|
|
<span class="file-path"><?= htmlspecialchars($errorData['file']) ?></span>
|
||
|
|
<span class="line-number">:<?= $errorData['line'] ?></span>
|
||
|
|
<br><br>
|
||
|
|
<span class="error-message"><?= htmlspecialchars($errorData['message']) ?></span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<table>
|
||
|
|
<tr>
|
||
|
|
<th>Type</th>
|
||
|
|
<td><span class="badge badge-error"><?= htmlspecialchars($errorData['type']) ?></span></td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<th>Code</th>
|
||
|
|
<td><?= $errorData['code'] ?></td>
|
||
|
|
</tr>
|
||
|
|
<tr>
|
||
|
|
<th>Timestamp</th>
|
||
|
|
<td><?= $errorData['timestamp'] ?></td>
|
||
|
|
</tr>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Stack Trace -->
|
||
|
|
<div class="error-section">
|
||
|
|
<div class="section-header" onclick="toggleSection('trace')">
|
||
|
|
<span class="section-title">Stack Trace</span>
|
||
|
|
<span class="section-toggle" id="toggle-trace">▼</span>
|
||
|
|
</div>
|
||
|
|
<div class="section-content" id="section-trace">
|
||
|
|
<?php
|
||
|
|
foreach ($errorData['trace'] as $index => $trace): ?>
|
||
|
|
<div class="trace-item">
|
||
|
|
<div class="trace-header">
|
||
|
|
#<?= $index ?>:
|
||
|
|
<?= $trace['class'] ?? '' ?><?= $trace['type'] ?? '' ?><?= $trace['function'] ?>()
|
||
|
|
</div>
|
||
|
|
<div class="trace-location">
|
||
|
|
<?= $trace['file'] ?? 'internal' ?><?= isset($trace['line']) ? ':' . $trace['line'] : '' ?>
|
||
|
|
</div>
|
||
|
|
<?php
|
||
|
|
if (!empty($trace['args'])): ?>
|
||
|
|
<div style="margin-top: 5px; font-size: 12px; color: #666;">
|
||
|
|
Arguments: <?= implode(', ', $trace['args']) ?>
|
||
|
|
</div>
|
||
|
|
<?php
|
||
|
|
endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php
|
||
|
|
endforeach; ?>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Server Information -->
|
||
|
|
<div class="error-section">
|
||
|
|
<div class="section-header" onclick="toggleSection('server')">
|
||
|
|
<span class="section-title">Server Information</span>
|
||
|
|
<span class="section-toggle" id="toggle-server">▼</span>
|
||
|
|
</div>
|
||
|
|
<div class="section-content hidden" id="section-server">
|
||
|
|
<table>
|
||
|
|
<?php
|
||
|
|
foreach ($errorData['server'] as $key => $value): ?>
|
||
|
|
<tr>
|
||
|
|
<th><?= htmlspecialchars($key) ?></th>
|
||
|
|
<td><?= htmlspecialchars($value) ?></td>
|
||
|
|
</tr>
|
||
|
|
<?php
|
||
|
|
endforeach; ?>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Request Information -->
|
||
|
|
<div class="error-section">
|
||
|
|
<div class="section-header" onclick="toggleSection('request')">
|
||
|
|
<span class="section-title">Request Information</span>
|
||
|
|
<span class="section-toggle" id="toggle-request">▼</span>
|
||
|
|
</div>
|
||
|
|
<div class="section-content hidden" id="section-request">
|
||
|
|
<h4>GET Parameters</h4>
|
||
|
|
<?php
|
||
|
|
if (!empty($errorData['request']['GET'])): ?>
|
||
|
|
<table>
|
||
|
|
<?php
|
||
|
|
foreach ($errorData['request']['GET'] as $key => $value): ?>
|
||
|
|
<tr>
|
||
|
|
<th><?= htmlspecialchars($key) ?></th>
|
||
|
|
<td><?= htmlspecialchars(is_array($value) ? json_encode($value) : $value) ?></td>
|
||
|
|
</tr>
|
||
|
|
<?php
|
||
|
|
endforeach; ?>
|
||
|
|
</table>
|
||
|
|
<?php
|
||
|
|
else: ?>
|
||
|
|
<p>No GET parameters</p>
|
||
|
|
<?php
|
||
|
|
endif; ?>
|
||
|
|
|
||
|
|
<h4>POST Parameters</h4>
|
||
|
|
<?php
|
||
|
|
if (!empty($errorData['request']['POST'])): ?>
|
||
|
|
<table>
|
||
|
|
<?php
|
||
|
|
foreach ($errorData['request']['POST'] as $key => $value): ?>
|
||
|
|
<tr>
|
||
|
|
<th><?= htmlspecialchars($key) ?></th>
|
||
|
|
<td><?= htmlspecialchars(is_array($value) ? json_encode($value) : $value) ?></td>
|
||
|
|
</tr>
|
||
|
|
<?php
|
||
|
|
endforeach; ?>
|
||
|
|
</table>
|
||
|
|
<?php
|
||
|
|
else: ?>
|
||
|
|
<p>No POST parameters</p>
|
||
|
|
<?php
|
||
|
|
endif; ?>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Environment Info -->
|
||
|
|
<div class="environment-info">
|
||
|
|
<div class="info-item">
|
||
|
|
<div class="info-label">Memory Usage</div>
|
||
|
|
<div class="info-value"><?= $errorData['memory_usage'] ?></div>
|
||
|
|
</div>
|
||
|
|
<div class="info-item">
|
||
|
|
<div class="info-label">Peak Memory</div>
|
||
|
|
<div class="info-value"><?= $errorData['peak_memory'] ?></div>
|
||
|
|
</div>
|
||
|
|
<div class="info-item">
|
||
|
|
<div class="info-label">Execution Time</div>
|
||
|
|
<div class="info-value"><?= round($errorData['execution_time'], 4) ?> seconds</div>
|
||
|
|
</div>
|
||
|
|
<div class="info-item">
|
||
|
|
<div class="info-label">PHP Version</div>
|
||
|
|
<div class="info-value"><?= PHP_VERSION ?></div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<!-- Actions -->
|
||
|
|
<div class="actions">
|
||
|
|
<button class="btn btn-primary" onclick="window.location.reload()">
|
||
|
|
<i class="fas fa-redo"></i> Reload Page
|
||
|
|
</button>
|
||
|
|
<button class="btn btn-secondary" onclick="window.history.back()">
|
||
|
|
<i class="fas fa-arrow-left"></i> Go Back
|
||
|
|
</button>
|
||
|
|
<a href="/" class="btn btn-secondary">
|
||
|
|
<i class="fas fa-home"></i> Go Home
|
||
|
|
</a>
|
||
|
|
<button class="btn btn-secondary" onclick="copyErrorDetails()">
|
||
|
|
<i class="fas fa-copy"></i> Copy Error Details
|
||
|
|
</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
function toggleSection(sectionId) {
|
||
|
|
const section = document.getElementById(`section-${sectionId}`);
|
||
|
|
const toggle = document.getElementById(`toggle-${sectionId}`);
|
||
|
|
|
||
|
|
if (section.classList.contains('hidden')) {
|
||
|
|
section.classList.remove('hidden');
|
||
|
|
toggle.textContent = '▲';
|
||
|
|
} else {
|
||
|
|
section.classList.add('hidden');
|
||
|
|
toggle.textContent = '▼';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function copyErrorDetails() {
|
||
|
|
const errorDetails = {
|
||
|
|
type: '<?= addslashes($errorData['type']) ?>',
|
||
|
|
message: '<?= addslashes($errorData['message']) ?>',
|
||
|
|
file: '<?= addslashes($errorData['file']) ?>',
|
||
|
|
line: <?= $errorData['line'] ?>,
|
||
|
|
timestamp: '<?= $errorData['timestamp'] ?>',
|
||
|
|
trace: <?= json_encode($errorData['trace']) ?>
|
||
|
|
};
|
||
|
|
|
||
|
|
const text = `Error Details:
|
||
|
|
Type: ${errorDetails.type}
|
||
|
|
Message: ${errorDetails.message}
|
||
|
|
File: ${errorDetails.file}
|
||
|
|
Line: ${errorDetails.line}
|
||
|
|
Timestamp: ${errorDetails.timestamp}
|
||
|
|
|
||
|
|
Stack Trace:
|
||
|
|
${JSON.stringify(errorDetails.trace, null, 2)}`;
|
||
|
|
|
||
|
|
navigator.clipboard.writeText(text).then(() => {
|
||
|
|
alert('Error details copied to clipboard!');
|
||
|
|
}).catch(err => {
|
||
|
|
console.error('Failed to copy: ', err);
|
||
|
|
alert('Failed to copy error details');
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Auto-expand first section
|
||
|
|
document.addEventListener('DOMContentLoaded', () => {
|
||
|
|
toggleSection('details');
|
||
|
|
toggleSection('trace');
|
||
|
|
});
|
||
|
|
</script>
|
||
|
|
</body>
|
||
|
|
</html>
|