Text per pdftotext (Poppler) */ function pdfToText($pdfFullPath) { $bin = trim(shell_exec('command -v pdftotext')); if ($bin === '') { $_SESSION['meldung_gottesdienst'] = "Fehler: 'pdftotext' nicht gefunden."; return false; } $tmpTxt = tempnam(sys_get_temp_dir(), 'lg_').'.txt'; $cmd = escapeshellcmd($bin).' -layout -enc UTF-8 '.escapeshellarg($pdfFullPath).' '.escapeshellarg($tmpTxt).' 2>&1'; exec($cmd, $out, $ret); if ($ret !== 0) { @unlink($tmpTxt); $_SESSION['meldung_gottesdienst'] = "Fehler beim PDF-Import:\n".htmlspecialchars(implode("\n", $out)); return false; } $txt = file_get_contents($tmpTxt); @unlink($tmpTxt); return $txt; } function parseLeitgedanken($textRaw) { // Zeilenenden normalisieren + Silbentrennungen (…-\n…) zusammenziehen $text = preg_replace("/\r\n?/", "\n", $textRaw); $text = preg_replace("/(?<=\p{L})-\n(?=\p{L})/u", "", $text); $lines = explode("\n", $text); // Abschnittsüberschriften mit Datum am Zeilenende $dateHeaderRegex = '/(?P.*?)(?P\d{1,2})(?:\.\s*\/\s*(?P\d{1,2}))?\.(?P\d{1,2})\.(?P\d{4})\s*$/u'; // Whitelist der (deutschen) Buchkürzel $BOOKS = '(?:Mo|Sam|Kön|Chr|Dan|Ps|Spr|Pred|Hld|Hi|Jes|Jer|Klgl|Hes|Ez|Hos|Joel|Am|Ob|Mi|Nah|Hab|Zef|Hag|Sach|Mal|Rut|Ri|Jos|Esra|Neh|Est|' . 'Mt|Mk|Lk|Joh|Apg|Röm|Kor|Gal|Eph|Phil|Kol|Thess|Tim|Tit|Phlm|Hebr|Jak|Petr|Joh|Jud|Offb)'; // Referenz am Zeilenende $refRegex = '/(?P(?:[1-3]\.?\s*)?' . $BOOKS . '\s*\d{1,3}\s*,\s*\d{1,3}(?:[–\-]\d{1,3}(?:[a-z])?|(?:\.\d{1,3})+(?:[a-z])?|[a-z])?)\s*$/u'; // Abschnittsgrenzen sammeln $sections = []; for ($i = 0; $i < count($lines); $i++) { if (preg_match($dateHeaderRegex, $lines[$i], $m)) { $d = str_pad((int)$m['d1'], 2, '0', STR_PAD_LEFT); $mn = str_pad((int)$m['m'], 2, '0', STR_PAD_LEFT); $y = (int)$m['y']; $sections[] = ['start'=>$i, 'date'=>sprintf('%04d-%02d-%02d',$y,$mn,$d)]; } } if (empty($sections)) return []; $sections[array_key_last($sections)]['end'] = count($lines); for ($s = 0; $s < count($sections)-1; $s++) { $sections[$s]['end'] = $sections[$s+1]['start']; } $out = []; foreach ($sections as $sec) { for ($i = $sec['start']; $i < $sec['end']; $i++) { $line = rtrim($lines[$i]); if ($line === '') continue; if (preg_match($refRegex, $line, $mRef)) { $beforeRef = trim(preg_replace($refRegex, '', $line)); $blkPrev = []; for ($k = $i - 1; $k >= $sec['start'] && $k >= $i - 15; $k--) { $pl = rtrim($lines[$k]); if ($pl === '') break; if (preg_match($refRegex, $pl)) break; $blkPrev[] = $pl; } $block = array_reverse($blkPrev); if ($beforeRef !== '') $block[] = $beforeRef; $vers = trim(preg_replace('/\s+/', ' ', implode(' ', $block))); if ($vers !== '') { $out[] = ['bibeldatum'=>$sec['date'], 'bibelwort'=>trim($mRef['ref']), 'bibelvers'=>$vers]; break; // pro Abschnitt nur das erste Bibelwort } } } } // Dubletten raus $uniq=[]; $final=[]; foreach ($out as $e) { $key=$e['bibeldatum'].'|'.$e['bibelwort']; if (!isset($uniq[$key])) { $uniq[$key]=1; $final[]=$e; } } return $final; } // Hilfsfunktion, um PDF in PNG umzuwandeln function convertPDFtoPNG($pdfFilePath, $outputDirectory, $baseFileName) { if (!is_file($pdfFilePath)) { error_log('PDF-Datei nicht gefunden: ' . $pdfFilePath); return false; } $outputFilePath = $outputDirectory . '/' . $baseFileName . '_page_%d.png'; $command = 'gs -dSAFER -dBATCH -dNOPAUSE ' . '-sDEVICE=png16m -r300 ' . '-sOutputFile=' . escapeshellarg($outputFilePath) . ' ' . escapeshellarg($pdfFilePath) . ' 2>&1'; $output = []; $returnCode = 0; exec($command, $output, $returnCode); if ($returnCode !== 0) { error_log( 'Ghostscript-Konvertierung fehlgeschlagen: ' . implode("\n", $output) ); return false; } return true; } // LG-PDF importieren -> direkt alles in DB if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['leitgedanken_pdf'])) { if ($_FILES['leitgedanken_pdf']['error'] !== UPLOAD_ERR_OK) { $_SESSION['meldung_gottesdienst'] = 'Fehler beim Upload der Leitgedanken-PDF.'; } else { $ext = strtolower(pathinfo($_FILES['leitgedanken_pdf']['name'], PATHINFO_EXTENSION)); if ($ext !== 'pdf') { $_SESSION['meldung_gottesdienst'] = 'Nur PDF-Dateien sind für den Import erlaubt.'; } else { $txt = pdfToText($_FILES['leitgedanken_pdf']['tmp_name']); if ($txt !== false) { $items = parseLeitgedanken($txt); // vorbereitete Statements $stmtExists = $pdo->prepare("SELECT 1 FROM gottesdienst WHERE bibeldatum = ? AND bibelwort = ? LIMIT 1"); $stmtInsert = $pdo->prepare("INSERT INTO gottesdienst (bibelwort, bibelvers, bibeldatum) VALUES (?, ?, ?)"); $ok=0; $dup=0; foreach ($items as $it) { $stmtExists->execute([$it['bibeldatum'], $it['bibelwort']]); if ($stmtExists->fetchColumn() !== false) { $dup++; continue; } $stmtInsert->execute([$it['bibelwort'], $it['bibelvers'], $it['bibeldatum']]); $ok++; } if ($ok > 0) { $_SESSION['meldung_gottesdienst'] = "Leitgedanken importiert: $ok Einträge angelegt".($dup?(", $dup dupliziert übersprungen"):"")."."; } else { $_SESSION['meldung_gottesdienst'] = "Keine neuen Einträge erkannt.".($dup?(" ($dup Duplikate)"):""); } } } } header("Location: ".$_SERVER['PHP_SELF']); exit(); } // Aushang manuell löschen if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['delete_file_base']) ) { $fileBase = (string) $_POST['delete_file_base']; if (!isValidNewsFileBase($fileBase)) { $_SESSION['meldung_dateien'] = 'Ungültiger Dateiname.'; } elseif (deleteNewsFiles($fileBase)) { $_SESSION['meldung_dateien'] = 'Aushang wurde vollständig gelöscht.'; } else { $_SESSION['meldung_dateien'] = 'Aushang konnte nicht vollständig gelöscht werden. Bitte Logs prüfen.'; } header('Location: insert.php#dateien'); exit(); } // Neuen Aushang hochladen und direkt in PNG-Seiten umwandeln if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) { $date = (string) ($_POST['date'] ?? ''); $dateObject = DateTimeImmutable::createFromFormat('!Y-m-d', $date); if ($dateObject === false || $dateObject->format('Y-m-d') !== $date) { $_SESSION['meldung_dateien'] = 'Ungültiges Verfallsdatum.'; header('Location: insert.php#dateien'); exit(); } $name = trim(sanitizeFileName((string) ($_POST['name'] ?? '')), '_-'); if ($name === '') { $_SESSION['meldung_dateien'] = 'Bitte einen gültigen Titel eingeben.'; header('Location: insert.php#dateien'); exit(); } if ( $_FILES['fileToUpload']['error'] !== UPLOAD_ERR_OK || strtolower(pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION)) !== 'pdf' ) { $_SESSION['meldung_dateien'] = 'Bitte eine gültige PDF-Datei hochladen.'; header('Location: insert.php#dateien'); exit(); } $baseFileName = $date . '-' . $name; if (!is_dir(NEWS_PNG_DIRECTORY) && !mkdir(NEWS_PNG_DIRECTORY, 0755, true)) { $_SESSION['meldung_dateien'] = 'Das Aushang-Verzeichnis konnte nicht angelegt werden.'; header('Location: insert.php#dateien'); exit(); } if (!convertPDFtoPNG( $_FILES['fileToUpload']['tmp_name'], NEWS_PNG_DIRECTORY, $baseFileName )) { deleteNewsFiles($baseFileName); $_SESSION['meldung_dateien'] = 'Fehler bei der Umwandlung der PDF.'; header('Location: insert.php#dateien'); exit(); } $_SESSION['meldung_dateien'] = 'Aushang wurde erfolgreich hochgeladen.'; header('Location: insert.php#dateien'); exit(); } // Löschen eines Gottesdienstes if (isset($_POST['delete_id'])) { $delete_id = $_POST['delete_id']; // Löschanfrage vorbereiten try { $sql_delete = "DELETE FROM gottesdienst WHERE id = ?"; $stmt = $pdo->prepare($sql_delete); $stmt->execute([$delete_id]); $_SESSION['meldung_gottesdienst'] = "Eintrag erfolgreich gelöscht!"; header("Location: " . $_SERVER['PHP_SELF']); // Seite neu laden exit(); // Skript nach dem Redirect beenden } catch (Exception $e) { $_SESSION['meldung_gottesdienst'] = "Fehler beim Löschen: " . $e->getMessage(); } } // Gottesdienst anlegen (ohne EL) if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['bibelwort']) && isset($_POST['bibelvers']) && isset($_POST['bibeldatum'])) { $bibelwort = $_POST['bibelwort']; $bibelvers = $_POST['bibelvers']; $bibeldatum = $_POST['bibeldatum']; try { $sql = "INSERT INTO gottesdienst (bibelwort, bibelvers, bibeldatum) VALUES (?, ?, ?)"; $stmt = $pdo->prepare($sql); $stmt->execute([$bibelwort, $bibelvers, $bibeldatum]); setlocale(LC_TIME, 'de_DE.UTF-8'); $formattedDate = strftime('%d. %B', strtotime($bibeldatum)); $_SESSION['meldung_gottesdienst'] = "Gottesdienst am " . $formattedDate . " erfolgreich angelegt!"; header("Location: " . $_SERVER['PHP_SELF']); exit(); } catch (Exception $e) { $_SESSION['meldung_gottesdienst'] = "Fehler beim Einfügen: " . $e->getMessage(); } } // Ansage anlegen if ($_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['ansage_datum_von'])) { $ansage_datum_von = $_POST['ansage_datum_von']; $ansage_datum_bis = !empty($_POST['ansage_datum_bis']) ? $_POST['ansage_datum_bis'] : NULL; $ansage_uhrzeit = !empty($_POST['ansage_uhrzeit']) ? $_POST['ansage_uhrzeit'] : NULL; $ansage_ort = $_POST['ansage_ort']; $ansage_titel = $_POST['ansage_titel']; $ansage_untertitel = $_POST['ansage_untertitel']; try { // SQL-Anweisung $sql = "INSERT INTO ansagen (ansage_datum_von, ansage_datum_bis, ansage_uhrzeit, ansage_ort, ansage_titel, ansage_untertitel) VALUES (?, ?, ?, ?, ?, ?)"; // Statement vorbereiten $stmt = $pdo->prepare($sql); // Statement ausführen $stmt->execute([$ansage_datum_von, $ansage_datum_bis, $ansage_uhrzeit, $ansage_ort, $ansage_titel, $ansage_untertitel]); setlocale(LC_TIME, 'de_DE.UTF-8'); $formattedDate = strftime('%d. %B', strtotime($ansage_datum_von)); $_SESSION['meldung_ansage'] = $ansage_titel . " am " . $formattedDate . " erfolgreich angelegt!"; header("Location: " . $_SERVER['PHP_SELF']); exit(); } catch (Exception $e) { $_SESSION['meldung_ansage'] = "Fehler beim Einfügen: " . $e->getMessage(); } } // Löschen einer Ansage if (isset($_POST['delete_ansage_id'])) { $delete_ansage_id = $_POST['delete_ansage_id']; // Löschanfrage vorbereiten try { $sql_delete_ansage = "DELETE FROM ansagen WHERE id = ?"; $stmt = $pdo->prepare($sql_delete_ansage); $stmt->execute([$delete_ansage_id]); $_SESSION['meldung_ansage'] = "Ansage erfolgreich gelöscht!"; header("Location: " . $_SERVER['PHP_SELF']); exit(); } catch (Exception $e) { $_SESSION['meldung_ansage'] = "Fehler beim Löschen: " . $e->getMessage(); } } // Meldungen aus der Session übernehmen if (isset($_SESSION['meldung_gottesdienst'])) { $meldung_gottesdienst = $_SESSION['meldung_gottesdienst']; unset($_SESSION['meldung_gottesdienst']); } if (isset($_SESSION['meldung_ansage'])) { $meldung_ansage = $_SESSION['meldung_ansage']; unset($_SESSION['meldung_ansage']); } if (isset($_SESSION['meldung_dateien'])) { $meldung_dateien = $_SESSION['meldung_dateien']; unset($_SESSION['meldung_dateien']); } $heute = date('Y-m-d'); // Gottesdienste aus der Datenbank abrufen $sql_fetch_gottesdienste = "SELECT id, bibelwort, bibelvers, TO_CHAR(bibeldatum, 'DD.MM.YYYY') AS datum FROM gottesdienst WHERE bibeldatum >= ? ORDER BY bibeldatum ASC"; $stmt = $pdo->prepare($sql_fetch_gottesdienste); $stmt->execute([$heute]); $planung_gottesdienste = $stmt->fetchAll(PDO::FETCH_ASSOC); // Ansagen aus der Datenbank abrufen $sql_fetch_ansagen = "SELECT id, ansage_untertitel, ansage_titel, ansage_ort, ansage_uhrzeit, TO_CHAR(ansage_datum_von, 'DD.MM.YYYY') AS datum_von, TO_CHAR(ansage_datum_bis, 'DD.MM.YYYY') AS datum_bis FROM ansagen WHERE ansage_datum_von >= ? OR ansage_datum_bis >= ? ORDER BY ansage_datum_von ASC"; $stmt = $pdo->prepare($sql_fetch_ansagen); $stmt->execute([$heute, $heute]); $planung_ansagen = $stmt->fetchAll(PDO::FETCH_ASSOC); // Schließe die Datenbankverbindung $pdo = null; ?>
Schwarzes Brett
Gottesdienst
Ansagen
Dateiverwaltung
Geplante Gottesdienste
0) : ?>
Leitgedanken importieren
Neuen Gottesdienst planen
Geplante Ansagen
0) : ?>
Neue Ansage planen
Aktuelle Aushänge
Keine Aushänge vorhanden.

'; } else { foreach ($aushangFiles as $file) { $baseFileName = basename($file, '_page_1.png'); $expiryDate = substr($baseFileName, 0, 10); $title = substr($baseFileName, 11); $numPages = count(glob(NEWS_PNG_DIRECTORY . '/' . $baseFileName . '_page_*.png') ?: []); $formattedExpiryDate = DateTime::createFromFormat('!Y-m-d', $expiryDate)?->format('d.m.Y') ?? $expiryDate; $safeBase = htmlspecialchars($baseFileName, ENT_QUOTES, 'UTF-8'); echo '
'; echo 'Aushang'; echo '
' . htmlspecialchars($title) . '
'; echo '
' . $numPages . ($numPages === 1 ? ' Seite' : ' Seiten') . ' · Verfällt ' . $formattedExpiryDate . '
'; echo '
'; echo ''; echo ''; echo '
'; echo '
'; } } ?>
Neuen Aushang hochladen