Dienstag, 24 März 2026

Diese Woche am beliebtesten

Vertiefendes Material

CoreNews RSS Newsbot

Unser PHP Script CoreNews ist ein minimalistischer, Dashboard RSS Reader mit Fokus auf Design und einfachster Handhabung. Quellen können direkt im Dashboard hinzugefügt, kategorisiert (Tech, Politik, Sport etc.) oder gelöscht werden. Via Cronjob wäre das Script via zB. index.php?sync=1 aufrufbar.

<?php
$cssPath = 'css/style.css';
$jsPath  = 'js/script.js';
$dbPath  = 'data/news_ultra.sqlite';
$error   = null;
try {
    if (!is_dir('css'))  mkdir('css', 0755, true);
    if (!is_dir('js'))   mkdir('js', 0755, true);
    if (!is_dir('data')) mkdir('data', 0755, true);

    if (!file_exists($cssPath) || filemtime(__FILE__) > filemtime($cssPath)) {
        $css = "
        :root { 
            --bg: #030712; --sidebar-bg: rgba(0, 0, 0, 0.4); --card-bg: rgba(17, 24, 39, 0.7); 
            --accent: #4f46e5; --accent-glow: rgba(79, 70, 229, 0.4); --text-main: #cbd5e1; 
            --text-bright: #ffffff; --text-dim: #475569; --border: rgba(255, 255, 255, 0.05);
            --error: #ef4444;
        }
        * { box-sizing: border-box; }
        body { font-family: 'Plus Jakarta Sans', sans-serif; background: var(--bg); margin: 0; color: var(--text-main); display: flex; height: 100vh; overflow: hidden; }
        .sidebar { width: 320px; background: var(--sidebar-bg); backdrop-filter: blur(20px); border-right: 1px solid var(--border); padding: 40px; display: flex; flex-direction: column; height: 100vh; flex-shrink: 0; }
        .content-area { flex: 1; overflow-y: auto; padding: 60px 80px; }
        .alert { background: rgba(239, 68, 68, 0.1); border: 1px solid var(--error); color: var(--error); padding: 15px; border-radius: 12px; margin-bottom: 30px; font-size: 13px; font-weight: 600; }
        .logo-container { display: flex; align-items: center; gap: 15px; margin-bottom: 50px; }
        .logo-icon { width: 45px; height: 45px; background: var(--accent); border-radius: 15px; display: flex; align-items: center; justify-content: center; box-shadow: 0 0 25px var(--accent-glow); transform: rotate(12deg); }
        .logo-icon svg { transform: rotate(-12deg); }
        .logo-text h1 { margin: 0; font-size: 20px; color: var(--text-bright); letter-spacing: -1px; }
        .logo-text span { font-size: 8px; font-weight: 800; color: var(--text-dim); letter-spacing: 2px; text-transform: uppercase; display: block; }
        .content-header { display: flex; justify-content: space-between; align-items: flex-end; margin-bottom: 60px; }
        .headline-group p { color: var(--text-dim); font-weight: 600; margin: 10px 0 0 0; }
        .headline { font-size: 42px; font-weight: 800; margin: 0; letter-spacing: -2px; }
        .gradient-text { background: linear-gradient(to right, #818cf8, #c084fc); -webkit-background-clip: text; -webkit-text-fill-color: transparent; }
        .section-title { font-size: 10px; font-weight: 900; color: #64748b; text-transform: uppercase; margin-bottom: 15px; letter-spacing: 1px; }
        .input-field { width: 100%; background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(255, 255, 255, 0.1); border-radius: 12px; padding: 12px; color: white; margin-bottom: 12px; outline: none; transition: 0.3s; }
        .btn-primary { background: var(--accent); color: white; border: none; padding: 14px; border-radius: 12px; font-weight: 800; cursor: pointer; text-transform: uppercase; font-size: 11px; letter-spacing: 1px; transition: 0.3s; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; }
        .btn-primary:hover { background: #4338ca; transform: translateY(-2px); box-shadow: 0 10px 20px rgba(79, 70, 229, 0.3); }
        .btn-sidebar { width: 100%; }
        .feed-list { margin-top: 30px; overflow-y: auto; flex-grow: 1; }
        .feed-item { display: flex; justify-content: space-between; align-items: center; padding: 12px; background: rgba(255, 255, 255, 0.03); border-radius: 12px; margin-bottom: 8px; font-size: 12px; }
        .news-grid { column-count: 3; column-gap: 24px; }
        @media (max-width: 1400px) { .news-grid { column-count: 2; } }
        @media (max-width: 900px) { .news-grid { column-count: 1; } }
        .news-card { break-inside: avoid; background: var(--card-bg); backdrop-filter: blur(12px); border: 1px solid var(--border); border-radius: 2.5rem; padding: 30px; margin-bottom: 24px; transition: 0.5s ease; }
        .news-card:hover { border-color: var(--accent); box-shadow: 0 0 25px rgba(99, 102, 241, 0.2); }
        .card-meta { display: flex; justify-content: space-between; align-items: center; margin-bottom: 25px; }
        .category-tag { font-size: 9px; font-weight: 900; padding: 4px 12px; background: rgba(99, 102, 241, 0.1); color: #818cf8; border: 1px solid rgba(99, 102, 241, 0.2); border-radius: 10px; text-transform: uppercase; font-style: italic; }
        .news-title { font-size: 19px; font-weight: 700; line-height: 1.35; margin-bottom: 15px; }
        .news-title a { color: var(--text-bright); text-decoration: none; }
        .news-excerpt { font-size: 13px; color: #94a3b8; line-height: 1.6; margin-bottom: 30px; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
        .card-footer { display: flex; justify-content: space-between; align-items: center; padding-top: 20px; border-top: 1px solid var(--border); }
        .btn-delete { color: #ef4444; text-decoration: none; font-size: 10px; font-weight: 900; opacity: 0.4; transition: 0.3s; }
        .btn-delete:hover { opacity: 1; }
        ::-webkit-scrollbar { width: 5px; }
        ::-webkit-scrollbar-thumb { background: #1f2937; border-radius: 10px; }
        ";
        file_put_contents($cssPath, $css);
    }
} catch (Exception $e) { $error = "Dateisystem-Fehler: " . $e->getMessage(); }

try {
    $db = new PDO("sqlite:$dbPath");
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $db->exec("CREATE TABLE IF NOT EXISTS feeds (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, url TEXT UNIQUE, cat TEXT)");
    $db->exec("CREATE TABLE IF NOT EXISTS news (id INTEGER PRIMARY KEY AUTOINCREMENT, fid INTEGER, title TEXT, link TEXT UNIQUE, txt TEXT, date DATETIME)");
    if (isset($_POST['add'])) {
        $url = filter_var($_POST['u'], FILTER_VALIDATE_URL);
        if ($url) {
            $s = $db->prepare("INSERT OR IGNORE INTO feeds (name, url, cat) VALUES (?, ?, ?)");
            $s->execute([htmlspecialchars($_POST['n']), $url, htmlspecialchars($_POST['c'])]);
            header("Location: ?"); exit;
        } else { $error = "Ungültige URL angegeben."; }
    }
    if (isset($_GET['del'])) {
        $db->prepare("DELETE FROM feeds WHERE id = ?")->execute([$_GET['del']]);
        header("Location: ?"); exit;
    }
    if (isset($_GET['sync'])) {
        $res = $db->query("SELECT * FROM feeds");
        while ($f = $res->fetch(PDO::FETCH_ASSOC)) {
            libxml_use_internal_errors(true);
            $xml = @simplexml_load_file($f['url']);
            if ($xml === false) { continue; /* Stillschweigend überspringen */ }
            
            foreach ($xml->channel->item as $i) {
                $s = $db->prepare("INSERT OR IGNORE INTO news (fid, title, link, txt, date) VALUES (?, ?, ?, ?, ?)");
                $s->execute([$f['id'], (string)$i->title, (string)$i->link, strip_tags((string)$i->description), date('Y-m-d H:i:s', strtotime((string)$i->pubDate))]);
            }
        }
        header("Location: ?"); exit;
    }
} catch (PDOException $e) { $error = "Datenbank-Fehler: " . $e->getMessage(); }
?>
<!DOCTYPE html>
<html lang="de">
<head>
    <meta charset="UTF-8">
    <title>CoreNews RSS</title>
    <link rel="stylesheet" href="<?= $cssPath ?>">
    <link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;600;800&display=swap" rel="stylesheet">
</head>
<body>
    <aside class="sidebar">
        <div class="logo-container">
            <div class="logo-icon">
                <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="3"><path d="M13 10V3L4 14h7v7l9-11h-7z"/></svg>
            </div>
            <div class="logo-text">
                <h1>CORE<span class="gradient-text">NEWS</span></h1>
                <span>RSS</span>
            </div>
        </div>
        <form method="POST">
            <p class="section-title">Quelle hinzufügen</p>
            <input type="text" name="n" placeholder="Name" required class="input-field">
            <input type="url" name="u" placeholder="RSS Link" required class="input-field">
            <select name="c" class="input-field">
                <option>Technologie</option><option>Wirtschaft</option><option>Politik</option><option>Wissenschaft</option>
            </select>
            <button name="add" class="btn-primary btn-sidebar">Add Channel</button>
        </form>
        <div class="feed-list">
            <p class="section-title">Aktive Kanäle</p>
            <?php 
            try {
                $fl = $db->query("SELECT * FROM feeds ORDER BY name ASC")->fetchAll(PDO::FETCH_ASSOC);
                foreach($fl as $f): ?>
                    <div class="feed-item">
                        <span><?= htmlspecialchars($f['name']) ?></span>
                        <a href="?del=<?= $f['id'] ?>" class="btn-delete">LÖSCHEN</a>
                    </div>
            <?php endforeach; } catch(Exception $e) {} ?>
        </div>
    </aside>
    <main class="content-area">
        <?php if ($error): ?>
            <div class="alert">⚠️ <?= htmlspecialchars($error) ?></div>
        <?php endif; ?>
        <div class="content-header">
            <div class="headline-group">
                <h2 class="headline">Latest <span class="gradient-text">Intelligence</span></h2>
                <p>Status: System online & gesichert.</p>
            </div>
            <a href="?sync=1" class="btn-primary">Sync Starten</a>
        </div>
        <div class="news-grid">
            <?php 
            try {
                $news = $db->query("SELECT n.*, f.name as fn, f.cat as fc FROM news n JOIN feeds f ON n.fid = f.id ORDER BY n.date DESC LIMIT 45");
                while($n = $news->fetch(PDO::FETCH_ASSOC)): ?>
                    <article class="news-card">
                        <div class="card-meta">
                            <span class="category-tag"><?= htmlspecialchars($n['fc']) ?></span>
                            <span class="card-time"><?= date('H:i', strtotime($n['date'])) ?> Uhr</span>
                        </div>
                        <h3 class="news-title"><a href="<?= htmlspecialchars($n['link']) ?>" target="_blank"><?= htmlspecialchars($n['title']) ?></a></h3>
                        <p class="news-excerpt"><?= htmlspecialchars($n['txt']) ?></p>
                        <div class="card-footer">
                            <span class="source-name"><?= htmlspecialchars($n['fn']) ?></span>
                            <a href="<?= htmlspecialchars($n['link']) ?>" target="_blank" class="read-more">QUELLE →</a>
                        </div>
                    </article>
            <?php endwhile; } catch(Exception $e) { echo "<p>Noch keine Nachrichten vorhanden. Bitte synchronisieren.</p>"; } ?>
        </div>
    </main>
</body>
</html>
Dreamcodes Redaktion
Dreamcodes Redaktion
Qualität als Standard. Verantwortung als Prinzip. Jede Ressource auf Dreamcodes basiert auf geprüften Best Practices und fundierter Praxiserfahrung. Unser Anspruch ist ein belastbares Fundament statt experimenteller Lösungen. Die Integration und Absicherung der Inhalte liegt in Ihrem Ermessen. Wir liefern die fachliche Basis, die Verantwortung für den produktiven Einsatz verbleibt bei Ihnen.
Vorheriges Tutorial

Vielleicht einen Blick WERT?