Geizkragen/404.php

556 lines
17 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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">
<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>