559 lines
17 KiB
PHP
559 lines
17 KiB
PHP
<?php
|
||
// Wichtig: echten 404-Status setzen
|
||
http_response_code(404);
|
||
|
||
// Request-Daten absichern
|
||
$requestUri = htmlspecialchars($_SERVER['REQUEST_URI'] ?? '', ENT_QUOTES, 'UTF-8');
|
||
$method = htmlspecialchars($_SERVER['REQUEST_METHOD'] ?? '', ENT_QUOTES, 'UTF-8');
|
||
$ip = htmlspecialchars($_SERVER['REMOTE_ADDR'] ?? '', ENT_QUOTES, 'UTF-8');
|
||
|
||
// Optional: einfaches Logging
|
||
error_log("[404] $ip $method $requestUri");
|
||
?>
|
||
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||
<link rel="icon" href="assets/images/favicon.ico" sizes="any">
|
||
<link rel="shortcut icon" href="assets/images/favicon.ico">
|
||
<title>404 – Seite nicht gefunden | Geizkragen</title>
|
||
|
||
<style>
|
||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;600;800;900&display=swap');
|
||
|
||
:root {
|
||
--bg-main: #151923;
|
||
--bg-header: #1f2937;
|
||
--color-primary: #2563eb;
|
||
--color-primary-hover: #1d4ed8;
|
||
--color-accent: #10b981;
|
||
--text-invert: #ffffff;
|
||
--text-muted: #94a3b8;
|
||
--card-bg: rgba(31, 41, 55, 0.65);
|
||
--card-border: rgba(255,255,255,0.06);
|
||
--glow: rgba(37, 99, 235, 0.25);
|
||
}
|
||
|
||
*, *::before, *::after {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
body {
|
||
font-family: 'Inter', system-ui, -apple-system, sans-serif;
|
||
background: var(--bg-main);
|
||
color: var(--text-invert);
|
||
min-height: 100vh;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
overflow: hidden;
|
||
position: relative;
|
||
}
|
||
|
||
/* ===== ANIMATED BACKGROUND ===== */
|
||
.bg-grid {
|
||
position: fixed;
|
||
inset: 0;
|
||
background-image:
|
||
linear-gradient(rgba(255,255,255,0.03) 1px, transparent 1px),
|
||
linear-gradient(90deg, rgba(255,255,255,0.03) 1px, transparent 1px);
|
||
background-size: 60px 60px;
|
||
animation: gridMove 20s linear infinite;
|
||
z-index: 0;
|
||
}
|
||
|
||
@keyframes gridMove {
|
||
0% { transform: translate(0, 0); }
|
||
100% { transform: translate(60px, 60px); }
|
||
}
|
||
|
||
.bg-glow {
|
||
position: fixed;
|
||
width: 600px;
|
||
height: 600px;
|
||
border-radius: 50%;
|
||
filter: blur(120px);
|
||
opacity: 0.15;
|
||
z-index: 0;
|
||
animation: float 8s ease-in-out infinite;
|
||
}
|
||
|
||
.bg-glow--blue {
|
||
background: var(--color-primary);
|
||
top: -200px;
|
||
right: -100px;
|
||
}
|
||
|
||
.bg-glow--green {
|
||
background: var(--color-accent);
|
||
bottom: -200px;
|
||
left: -100px;
|
||
animation-delay: -4s;
|
||
}
|
||
|
||
.bg-glow--purple {
|
||
background: #8b5cf6;
|
||
top: 50%;
|
||
left: 50%;
|
||
transform: translate(-50%, -50%);
|
||
width: 400px;
|
||
height: 400px;
|
||
opacity: 0.08;
|
||
animation-delay: -2s;
|
||
}
|
||
|
||
@keyframes float {
|
||
0%, 100% { transform: translateY(0); }
|
||
50% { transform: translateY(-40px); }
|
||
}
|
||
|
||
/* ===== PARTICLES ===== */
|
||
.particles {
|
||
position: fixed;
|
||
inset: 0;
|
||
z-index: 0;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.particle {
|
||
position: absolute;
|
||
width: 4px;
|
||
height: 4px;
|
||
background: var(--color-primary);
|
||
border-radius: 50%;
|
||
opacity: 0;
|
||
animation: particleFloat linear infinite;
|
||
}
|
||
|
||
@keyframes particleFloat {
|
||
0% {
|
||
opacity: 0;
|
||
transform: translateY(100vh) scale(0);
|
||
}
|
||
10% { opacity: 0.7; }
|
||
90% { opacity: 0.7; }
|
||
100% {
|
||
opacity: 0;
|
||
transform: translateY(-10vh) scale(1);
|
||
}
|
||
}
|
||
|
||
/* ===== MAIN CONTENT ===== */
|
||
.error-container {
|
||
position: relative;
|
||
z-index: 10;
|
||
text-align: center;
|
||
padding: 2rem;
|
||
max-width: 650px;
|
||
width: 95%;
|
||
animation: fadeInUp 0.8s ease-out;
|
||
}
|
||
|
||
@keyframes fadeInUp {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(40px);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
/* ===== GLITCH 404 ===== */
|
||
.error-code {
|
||
font-size: clamp(8rem, 20vw, 14rem);
|
||
font-weight: 900;
|
||
line-height: 1;
|
||
letter-spacing: -0.04em;
|
||
position: relative;
|
||
display: inline-block;
|
||
background: linear-gradient(135deg, var(--color-primary), #8b5cf6, var(--color-accent));
|
||
background-size: 200% 200%;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
animation: gradientShift 4s ease-in-out infinite;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.error-code::before,
|
||
.error-code::after {
|
||
content: '404';
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
overflow: hidden;
|
||
background: linear-gradient(135deg, var(--color-primary), #8b5cf6, var(--color-accent));
|
||
background-size: 200% 200%;
|
||
-webkit-background-clip: text;
|
||
-webkit-text-fill-color: transparent;
|
||
background-clip: text;
|
||
}
|
||
|
||
.error-code::before {
|
||
animation: glitch1 3s infinite linear alternate-reverse, gradientShift 4s ease-in-out infinite;
|
||
clip-path: inset(0 0 65% 0);
|
||
}
|
||
|
||
.error-code::after {
|
||
animation: glitch2 3s infinite linear alternate-reverse, gradientShift 4s ease-in-out infinite;
|
||
clip-path: inset(65% 0 0 0);
|
||
}
|
||
|
||
@keyframes gradientShift {
|
||
0%, 100% { background-position: 0% 50%; }
|
||
50% { background-position: 100% 50%; }
|
||
}
|
||
|
||
@keyframes glitch1 {
|
||
0%, 92% { transform: translate(0); }
|
||
93% { transform: translate(-8px, -2px); }
|
||
94% { transform: translate(4px, 1px); }
|
||
95% { transform: translate(-3px, 2px); }
|
||
96%, 100% { transform: translate(0); }
|
||
}
|
||
|
||
@keyframes glitch2 {
|
||
0%, 90% { transform: translate(0); }
|
||
91% { transform: translate(5px, 2px); }
|
||
92% { transform: translate(-6px, -1px); }
|
||
93% { transform: translate(3px, -2px); }
|
||
94%, 100% { transform: translate(0); }
|
||
}
|
||
|
||
/* ===== CARD ===== */
|
||
.error-card {
|
||
background: var(--card-bg);
|
||
backdrop-filter: blur(24px);
|
||
-webkit-backdrop-filter: blur(24px);
|
||
border: 1px solid var(--card-border);
|
||
border-radius: 24px;
|
||
padding: 2.5rem 2.5rem 2rem;
|
||
box-shadow:
|
||
0 25px 60px rgba(0,0,0,0.4),
|
||
0 0 80px var(--glow);
|
||
animation: fadeInUp 0.8s ease-out 0.2s both;
|
||
}
|
||
|
||
.error-card__icon {
|
||
width: 64px;
|
||
height: 64px;
|
||
margin: 0 auto 1.5rem;
|
||
background: linear-gradient(135deg, rgba(37,99,235,0.15), rgba(139,92,246,0.15));
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
animation: pulse 3s ease-in-out infinite;
|
||
}
|
||
|
||
.error-card__icon svg {
|
||
width: 30px;
|
||
height: 30px;
|
||
stroke: var(--color-primary);
|
||
}
|
||
|
||
@keyframes pulse {
|
||
0%, 100% { box-shadow: 0 0 0 0 rgba(37,99,235,0.3); }
|
||
50% { box-shadow: 0 0 0 16px rgba(37,99,235,0); }
|
||
}
|
||
|
||
.error-card__title {
|
||
font-size: 1.5rem;
|
||
font-weight: 800;
|
||
margin-bottom: 0.75rem;
|
||
color: var(--text-invert);
|
||
}
|
||
|
||
.error-card__text {
|
||
color: var(--text-muted);
|
||
font-size: 1rem;
|
||
line-height: 1.6;
|
||
margin-bottom: 0.5rem;
|
||
}
|
||
|
||
.error-card__path {
|
||
display: inline-block;
|
||
background: rgba(37,99,235,0.1);
|
||
border: 1px solid rgba(37,99,235,0.2);
|
||
color: var(--color-primary);
|
||
font-family: 'Courier New', Courier, monospace;
|
||
font-size: 0.85rem;
|
||
font-weight: 600;
|
||
padding: 0.4rem 1rem;
|
||
border-radius: 8px;
|
||
margin: 1rem 0 1.5rem;
|
||
word-break: break-all;
|
||
max-width: 100%;
|
||
}
|
||
|
||
/* ===== BUTTONS ===== */
|
||
.error-card__actions {
|
||
display: flex;
|
||
gap: 0.75rem;
|
||
justify-content: center;
|
||
flex-wrap: wrap;
|
||
margin-top: 1.5rem;
|
||
}
|
||
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 0.5rem;
|
||
padding: 0.8rem 1.6rem;
|
||
border-radius: 12px;
|
||
font-size: 0.95rem;
|
||
font-weight: 600;
|
||
text-decoration: none;
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
cursor: pointer;
|
||
border: none;
|
||
font-family: inherit;
|
||
}
|
||
|
||
.btn--primary {
|
||
background: linear-gradient(135deg, var(--color-primary), #4f46e5);
|
||
color: white;
|
||
box-shadow: 0 4px 15px rgba(37,99,235,0.35);
|
||
}
|
||
|
||
.btn--primary:hover {
|
||
transform: translateY(-3px);
|
||
box-shadow: 0 8px 25px rgba(37,99,235,0.5);
|
||
}
|
||
|
||
.btn--primary:active {
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
.btn--ghost {
|
||
background: rgba(255,255,255,0.05);
|
||
color: var(--text-muted);
|
||
border: 1px solid rgba(255,255,255,0.1);
|
||
}
|
||
|
||
.btn--ghost:hover {
|
||
background: rgba(255,255,255,0.1);
|
||
color: var(--text-invert);
|
||
transform: translateY(-3px);
|
||
}
|
||
|
||
.btn svg {
|
||
width: 18px;
|
||
height: 18px;
|
||
}
|
||
|
||
/* ===== DIVIDER ===== */
|
||
.error-card__divider {
|
||
height: 1px;
|
||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.08), transparent);
|
||
margin: 1.5rem 0 1rem;
|
||
}
|
||
|
||
/* ===== FOOTER INFO ===== */
|
||
.error-card__meta {
|
||
display: flex;
|
||
justify-content: center;
|
||
gap: 2rem;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.error-card__meta-item {
|
||
font-size: 0.75rem;
|
||
color: #475569;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 0.35rem;
|
||
}
|
||
|
||
.error-card__meta-item span {
|
||
color: #64748b;
|
||
}
|
||
|
||
/* ===== BROKEN LINK ICON ===== */
|
||
.error-icon-top {
|
||
margin-bottom: 1.5rem;
|
||
animation: fadeInUp 0.8s ease-out 0.1s both;
|
||
display: flex;
|
||
justify-content: center;
|
||
}
|
||
|
||
.error-icon-top__circle {
|
||
width: 72px;
|
||
height: 72px;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, rgba(37,99,235,0.12), rgba(139,92,246,0.12));
|
||
border: 1px solid rgba(255,255,255,0.06);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
position: relative;
|
||
}
|
||
|
||
.error-icon-top__circle::before {
|
||
content: '';
|
||
position: absolute;
|
||
inset: -4px;
|
||
border-radius: 50%;
|
||
border: 2px dashed rgba(37,99,235,0.2);
|
||
animation: spinSlow 12s linear infinite;
|
||
}
|
||
|
||
@keyframes spinSlow {
|
||
to { transform: rotate(360deg); }
|
||
}
|
||
|
||
.error-icon-top__circle svg {
|
||
width: 32px;
|
||
height: 32px;
|
||
stroke: #8b5cf6;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* ===== RESPONSIVE ===== */
|
||
@media (max-width: 480px) {
|
||
.error-card {
|
||
padding: 1.8rem 1.5rem 1.5rem;
|
||
border-radius: 18px;
|
||
}
|
||
|
||
.error-card__actions {
|
||
flex-direction: column;
|
||
}
|
||
|
||
.btn {
|
||
justify-content: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.error-card__meta {
|
||
flex-direction: column;
|
||
gap: 0.5rem;
|
||
align-items: center;
|
||
}
|
||
}
|
||
</style>
|
||
</head>
|
||
|
||
<body>
|
||
|
||
<!-- Animated background elements -->
|
||
<div class="bg-grid"></div>
|
||
<div class="bg-glow bg-glow--blue"></div>
|
||
<div class="bg-glow bg-glow--green"></div>
|
||
<div class="bg-glow bg-glow--purple"></div>
|
||
<div class="particles" id="particles"></div>
|
||
|
||
<div class="error-container">
|
||
|
||
<!-- Broken Link Icon -->
|
||
<div class="error-icon-top">
|
||
<div class="error-icon-top__circle">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M15 7h3a5 5 0 0 1 5 5 5 5 0 0 1-5 5h-3m-6 0H6a5 5 0 0 1-5-5 5 5 0 0 1 5-5h3"/>
|
||
<line x1="8" y1="12" x2="16" y2="12"/>
|
||
</svg>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Glitch 404 Code -->
|
||
<div class="error-code" aria-hidden="true">404</div>
|
||
|
||
<!-- Main Card -->
|
||
<div class="error-card">
|
||
|
||
<div class="error-card__icon">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<circle cx="11" cy="11" r="8"/>
|
||
<path d="M21 21l-4.35-4.35"/>
|
||
<line x1="8" y1="11" x2="14" y2="11"/>
|
||
</svg>
|
||
</div>
|
||
|
||
<h1 class="error-card__title">Seite nicht gefunden</h1>
|
||
<p class="error-card__text">
|
||
Die Seite, die du suchst, existiert leider nicht oder wurde verschoben.
|
||
</p>
|
||
|
||
<div class="error-card__path"><?php echo $requestUri; ?></div>
|
||
|
||
<div class="error-card__actions">
|
||
<a href="/" class="btn btn--primary">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
|
||
<polyline points="9 22 9 12 15 12 15 22"/>
|
||
</svg>
|
||
Zur Startseite
|
||
</a>
|
||
<button onclick="history.back()" class="btn btn--ghost">
|
||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<line x1="19" y1="12" x2="5" y2="12"/>
|
||
<polyline points="12 19 5 12 12 5"/>
|
||
</svg>
|
||
Zurück
|
||
</button>
|
||
</div>
|
||
|
||
<div class="error-card__divider"></div>
|
||
|
||
<div class="error-card__meta">
|
||
<div class="error-card__meta-item">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#475569" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72c.127.96.361 1.903.7 2.81a2 2 0 0 1-.45 2.11L8.09 9.91"/>
|
||
</svg>
|
||
<span><?php echo $method; ?> Request</span>
|
||
</div>
|
||
<div class="error-card__meta-item">
|
||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="#475569" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||
<rect x="2" y="2" width="20" height="20" rx="5" ry="5"/>
|
||
<path d="M16 11.37A4 4 0 1 1 12.63 8 4 4 0 0 1 16 11.37z"/>
|
||
<line x1="17.5" y1="6.5" x2="17.51" y2="6.5"/>
|
||
</svg>
|
||
<span>geizkragen.store</span>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<script>
|
||
// Create floating particles
|
||
const container = document.getElementById('particles');
|
||
const count = 30;
|
||
|
||
for (let i = 0; i < count; i++) {
|
||
const p = document.createElement('div');
|
||
p.classList.add('particle');
|
||
|
||
const size = Math.random() * 4 + 2;
|
||
p.style.width = size + 'px';
|
||
p.style.height = size + 'px';
|
||
p.style.left = Math.random() * 100 + '%';
|
||
p.style.animationDuration = (Math.random() * 8 + 6) + 's';
|
||
p.style.animationDelay = (Math.random() * 10) + 's';
|
||
|
||
// Random color between primary, accent, and purple
|
||
const colors = ['#2563eb', '#10b981', '#8b5cf6', '#3b82f6', '#6366f1'];
|
||
p.style.background = colors[Math.floor(Math.random() * colors.length)];
|
||
|
||
container.appendChild(p);
|
||
}
|
||
|
||
// Subtle mouse parallax on the error code
|
||
const code = document.querySelector('.error-code');
|
||
document.addEventListener('mousemove', (e) => {
|
||
const x = (e.clientX / window.innerWidth - 0.5) * 10;
|
||
const y = (e.clientY / window.innerHeight - 0.5) * 10;
|
||
code.style.transform = `translate(${x}px, ${y}px)`;
|
||
});
|
||
</script>
|
||
|
||
</body>
|
||
</html>
|
||
|