Die professionelle Lösung für den regionalen Sprit Preisvergleich. Unser Php Script bietet eine lückenlose Live Abfrage der aktuellen Kraftstoffpreise direkt über die Markttransparenzstelle (MTS-K). Integriert in eine interaktive Google Maps Umgebung, ermöglicht das Script einen präzisen Vergleich von Super E5, E10 und Diesel im gewählten Umkreis. Mit Fokus auf Usability und technischer Substanz bietet das Tool automatische Standorterkennung, Preis Sortierung und ein schickes Interface für höchste Ansprüche. API Keys für Google und Tankerkönig werden benötigt.
Code als Setup.php abspeichern. Nach einmaligem Aufruf wird die index, Api, Script.js und Style.css automatisch erstellt und die Setup Datei gelöscht.
<?php
$tanker_key = "DEIN_TANKERKOENIG_API_KEY";
$google_key = "DEIN_GOOGLE_MAPS_API_KEY";
if (!is_dir('fonts')) mkdir('fonts', 0755);
$font_sources = ['outfit-reg.woff2' => 'https://fonts.gstatic.com/s/outfit/v11/QGYsz_O5rkz2mS4_OTuSfA.woff2', 'outfit-bold.woff2' => 'https://fonts.gstatic.com/s/outfit/v11/QGYsz_O5rkz2mS4_ObeSfA.woff2'];
foreach ($font_sources as $name => $url) {
if (!file_exists("fonts/$name")) {
$ch = curl_init($url); $fp = fopen("fonts/$name", 'wb');
curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_HEADER, 0); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_exec($ch); curl_close($ch); fclose($fp);
}
}
$css_content = <<<EOD
@font-face { font-family: 'Outfit'; src: url('fonts/outfit-reg.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Outfit'; src: url('fonts/outfit-bold.woff2') format('woff2'); font-weight: 900; font-style: normal; font-display: swap; }
:root { --accent: #d4af37; --bg: #0a0a0b; --glass: rgba(255, 255, 255, 0.03); --border: rgba(255, 255, 255, 0.08); }
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Outfit', sans-serif; background: var(--bg); color: #fff; overflow-x: hidden; padding: 2rem; min-height: 100vh; display: flex; flex-direction: column; }
.container { max-width: 1200px; margin: 0 auto; flex: 1; width: 100%; }
header { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 3rem; }
.brand-box h1 { font-size: clamp(1.5rem, 4vw, 3rem); font-weight: 900; text-transform: uppercase; letter-spacing: -1px; background: linear-gradient(135deg, #d4af37 0%, #f9e29c 50%, #b38728 100%); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.subtitle { color: #666; text-transform: uppercase; letter-spacing: 2px; font-size: 0.7rem; margin-top: 0.5rem; line-height: 1.4; max-width: 400px; }
.clock-box { text-align: right; }
#clock { font-size: 1.5rem; color: #444; font-family: monospace; }
.status-tag { font-size: 9px; color: var(--accent); letter-spacing: 2px; }
.main-grid { display: grid; grid-template-columns: 1.5fr 1fr; gap: 2rem; margin-bottom: 4rem; }
@media (max-width: 900px) { .main-grid { grid-template-columns: 1fr; } .clock-box { display: none; } }
.glass-panel { background: var(--glass); backdrop-filter: blur(20px); border: 1px solid var(--border); border-radius: 24px; position: relative; overflow: hidden; }
#map { height: 500px; background: #111; filter: grayscale(1) invert(0.9) contrast(1.1); }
.feed { height: 500px; overflow-y: auto; padding-right: 10px; }
.feed::-webkit-scrollbar { width: 4px; }
.feed::-webkit-scrollbar-thumb { background: var(--accent); border-radius: 10px; }
.feed-loading { text-align: center; margin-top: 100px; color: #444; }
.price-card { background: var(--glass); border: 1px solid var(--border); border-radius: 20px; padding: 1.5rem; display: flex; justify-content: space-between; align-items: center; margin-bottom: 1rem; transition: 0.3s ease; opacity: 0; transform: translateY(20px); }
.price-card.show { opacity: 1; transform: translateY(0); }
.price-card:hover { transform: translateX(10px); border-color: var(--accent); background: rgba(255,255,255,0.06); }
.station-info h2 { font-weight: 800; font-size: 1.2rem; }
.station-addr { color: #666; font-size: 0.7rem; margin-top: 4px; text-transform: uppercase; }
.station-dist { color: #444; font-size: 9px; margin-top: 8px; font-family: monospace; }
.price-box { text-align: right; }
.price-val { font-size: 2.2rem; font-weight: 900; }
.gold-text { background: linear-gradient(135deg, #d4af37, #f9e29c); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
.btn-group { position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%); display: flex; gap: 10px; padding: 8px; background: rgba(0,0,0,0.5); backdrop-filter: blur(10px); border-radius: 16px; border: 1px solid var(--border); z-index: 10; }
button { padding: 10px 20px; border-radius: 12px; border: none; font-weight: 700; cursor: pointer; transition: 0.3s; background: transparent; color: #888; }
button.active { background: #fff; color: #000; }
.best-label { font-size: 9px; border: 1px solid var(--accent); color: var(--accent); padding: 2px 8px; text-transform: uppercase; margin-left: 10px; border-radius: 10px; }
.nav-link { color: var(--accent); text-decoration: none; font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 1px; }
.pulse { animation: pulse 2s infinite; }
@keyframes pulse { 0% { box-shadow: 0 0 0 0 rgba(212, 175, 55, 0.4); } 70% { box-shadow: 0 0 0 10px rgba(212, 175, 55, 0); } 100% { box-shadow: 0 0 0 0 rgba(212, 175, 55, 0); } }
footer { padding: 2rem 0; border-top: 1px solid var(--border); text-align: center; margin-top: auto; }
.footer-link { color: #555; text-decoration: none; font-size: 0.7rem; letter-spacing: 2px; text-transform: uppercase; transition: 0.3s; }
.footer-link:hover { color: var(--accent); }
.footer-link span { font-weight: 900; }
.install-ui { height: 100vh; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; }
.timer-circle { width: 120px; height: 120px; border-radius: 50%; border: 2px solid var(--border); display: flex; align-items: center; justify-content: center; font-size: 3rem; font-weight: 900; color: var(--accent); margin: 2rem 0; position: relative; }
.timer-circle::after { content: ''; position: absolute; top: -5px; left: -5px; right: -5px; bottom: -5px; border: 2px solid var(--accent); border-radius: 50%; border-left-color: transparent; animation: spin 1s linear infinite; }
@keyframes spin { 100% { transform: rotate(360deg); } }
EOD;
file_put_contents('style.css', $css_content);
$js_content = <<<EOD
let map, markers = [], fType = 'e5', acc = '#d4af37';
const $ = id => document.getElementById(id);
async function initMap() {
map = new google.maps.Map($("map"), { zoom: 14, center: { lat: 52.52, lng: 13.4 }, disableDefaultUI: true, styles: [{elementType: "geometry", stylers: [{color: "#212121"}]}, {elementType: "labels.text.fill", stylers: [{color: "#757575"}]}, {featureType: "road", elementType: "geometry", stylers: [{color: "#303030"}]}] });
navigator.geolocation?.getCurrentPosition(p => { const loc = {lat: p.coords.latitude, lng: p.coords.longitude}; map.setCenter(loc); load(loc); }, () => load({lat: 52.52, lng: 13.4}));
}
const load = async l => { const r = await fetch(`api.php?lat=\${l.lat}&lng=\${l.lng}`), d = await r.json(); if (d.status === "ok") render(d.stations); };
const render = sts => {
const list = $("station-feed"); list.innerHTML = ""; markers.forEach(m => m.setMap(null)); markers = [];
sts.sort((a, b) => (a[fType] || 99) - (b[fType] || 99)).forEach((s, i) => {
const isB = i === 0 && s[fType] > 0, pr = s[fType] ? s[fType].toFixed(2) + '<span style="font-size:0.5em">9</span>' : 'N/A';
const m = new google.maps.Marker({ position: {lat: s.lat, lng: s.lng}, map, icon: {path: google.maps.SymbolPath.CIRCLE, fillColor: isB ? acc : '#fff', fillOpacity: 1, strokeWeight: 0, scale: isB ? 10 : 6} }); markers.push(m);
const c = document.createElement('div'); c.className = `price-card \${isB ? 'pulse' : ''}`;
c.innerHTML = `<div class="station-info"><div style="display:flex;align-items:center;"><h2>\${s.brand||'Station'}</h2>\${isB?'<span class="best-label">Bestpreis</span>':''}</div><div class="station-addr">\${s.street}, \${s.place}</div><div class="station-dist">\${s.dist} KM DISTANCE</div></div><div class="price-box"><div class="price-val \${isB?'gold-text':''}">\${pr}€</div><a href="http://googleusercontent.com/maps.google.com/7{s.lat},\${s.lng}" target="_blank" class="nav-link">Navigate →</a></div>`;
list.appendChild(c); setTimeout(() => c.classList.add('show'), i * 40);
});
};
const changeFuel = (t, b) => { fType = t; document.querySelectorAll('button').forEach(btn => btn.classList.remove('active')); b.classList.add('active'); navigator.geolocation.getCurrentPosition(p => load({lat: p.coords.latitude, lng: p.coords.longitude})); };
setInterval(() => $("clock") && ($("clock").innerText = new Date().toLocaleTimeString('de-DE')), 1000);
EOD;
file_put_contents('script.js', $js_content);
file_put_contents('api.php', "<?php header('Content-Type: application/json'); \$lat = \$_GET['lat']; \$lng = \$_GET['lng']; \$url = \"https://creativecommons.tankerkoenig.de/json/list.php?lat=\$lat&lng=\$lng&rad=10&sort=dist&type=all&apikey=$tanker_key\"; echo @file_get_contents(\$url); ?>");
$index_content = <<<EOD
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Sprit Monitor Pro | Preisvergleich</title><link rel="stylesheet" href="style.css"></head>
<body>
<div class="container">
<header><div class="brand-box"><h1>Sprit Monitor Pro</h1><div class="subtitle">Benzin und Diesel Preisvergleich mit Maps Integration</div></div><div class="clock-box"><div id="clock">00:00:00</div><div class="status-tag">SYSTEM ONLINE</div></div></header>
<div class="main-grid"><div class="glass-panel"><div id="map"></div><div class="btn-group"><button onclick="changeFuel('e5', this)" class="active">E5</button><button onclick="changeFuel('e10', this)">E10</button><button onclick="changeFuel('diesel', this)">Diesel</button></div></div><div class="feed" id="station-feed"><div class="feed-loading">Initialisiere Sensoren...</div></div></div>
</div>
<footer><a href="https://www.dreamcodes.net" target="_blank" class="footer-link">Powered by <span>Dreamcodes</span></a></footer>
<script src="https://maps.googleapis.com/maps/api/js?key=$google_key&callback=initMap" async defer></script><script src="script.js"></script>
</body>
</html>
EOD;
file_put_contents('index.php', $index_content);
unlink(__FILE__);
?>
<!DOCTYPE html>
<html lang="de">
<head><meta charset="UTF-8"><title>Setup abgeschlossen</title><link rel="stylesheet" href="style.css"></head>
<body>
<div class="install-ui"><h1 class="gold-text" style="font-size: 3rem; font-weight: 900;">SYSTEM BEREIT</h1><p style="color: #666; letter-spacing: 2px;">INSTALLER GELÖSCHT. WEITERLEITUNG IN...</p><div class="timer-circle" id="timer">10</div><p style="color: #444; font-size: 0.8rem;">Initialisiere Dashboard & API Schnittstellen</p></div>
<script>let timeLeft = 10; const timerEl = document.getElementById('timer'); const countdown = setInterval(() => { timeLeft--; timerEl.innerText = timeLeft; if(timeLeft <= 0) { clearInterval(countdown); window.location.href = 'index.php'; } }, 1000);</script>
</body>
</html>
