Merge pull request 'web/contentpanel - refactor Aushang-Upload to store PNGs only' (#1) from refactor/contentpanel/aushang-upload into dev
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
@@ -8,7 +8,7 @@ if (!isset($groups["Allgemein"]) || $groups["Allgemein"] != 1) {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abgelaufene News samt PDF und PNGs entfernen
|
// Abgelaufene Aushänge entfernen
|
||||||
cleanupExpiredNews();
|
cleanupExpiredNews();
|
||||||
|
|
||||||
|
|
||||||
@@ -22,11 +22,6 @@ function sanitizeFileName($fileName) {
|
|||||||
return preg_replace('/[^A-Za-z0-9_\-]/', '_', str_replace(' ', '_', $fileName));
|
return preg_replace('/[^A-Za-z0-9_\-]/', '_', str_replace(' ', '_', $fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hilfsfunktion, um den Dateinamen zu generieren
|
|
||||||
function generateFileName($date, $name, $extension) {
|
|
||||||
return $date . '-' . $name . '.' . $extension;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** PDF -> Text per pdftotext (Poppler) */
|
/** PDF -> Text per pdftotext (Poppler) */
|
||||||
function pdfToText($pdfFullPath) {
|
function pdfToText($pdfFullPath) {
|
||||||
$bin = trim(shell_exec('command -v pdftotext'));
|
$bin = trim(shell_exec('command -v pdftotext'));
|
||||||
@@ -186,23 +181,18 @@ if (
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Neuen Aushang als PDF hochladen und in PNG-Seiten umwandeln
|
// Neuen Aushang hochladen und direkt in PNG-Seiten umwandeln
|
||||||
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
|
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
|
||||||
$date = (string) ($_POST['date'] ?? '');
|
$date = (string) ($_POST['date'] ?? '');
|
||||||
$dateObject = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
|
$dateObject = DateTimeImmutable::createFromFormat('!Y-m-d', $date);
|
||||||
|
|
||||||
if (
|
if ($dateObject === false || $dateObject->format('Y-m-d') !== $date) {
|
||||||
$dateObject === false ||
|
|
||||||
$dateObject->format('Y-m-d') !== $date
|
|
||||||
) {
|
|
||||||
$_SESSION['meldung_dateien'] = 'Ungültiges Verfallsdatum.';
|
$_SESSION['meldung_dateien'] = 'Ungültiges Verfallsdatum.';
|
||||||
header('Location: insert.php#dateien');
|
header('Location: insert.php#dateien');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bereinige den eingegebenen Namen.
|
$name = trim(sanitizeFileName((string) ($_POST['name'] ?? '')), '_-');
|
||||||
$name = sanitizeFileName((string) ($_POST['name'] ?? ''));
|
|
||||||
$name = trim($name, '_-');
|
|
||||||
|
|
||||||
if ($name === '') {
|
if ($name === '') {
|
||||||
$_SESSION['meldung_dateien'] = 'Bitte einen gültigen Titel eingeben.';
|
$_SESSION['meldung_dateien'] = 'Bitte einen gültigen Titel eingeben.';
|
||||||
@@ -210,68 +200,30 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($_FILES['fileToUpload']['error'] !== UPLOAD_ERR_OK) {
|
|
||||||
$_SESSION['meldung_dateien'] = 'Fehler beim Upload der PDF-Datei.';
|
|
||||||
header('Location: insert.php#dateien');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$fileExtension = strtolower(
|
|
||||||
pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION)
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($fileExtension !== 'pdf') {
|
|
||||||
$_SESSION['meldung_dateien'] = 'Nur PDF-Dateien sind erlaubt.';
|
|
||||||
header('Location: insert.php#dateien');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
$directoryPath =
|
|
||||||
'/var/www/html/intranet_repo/projects/contentpanel/insertion/news/';
|
|
||||||
$imageOutputDirectory = $directoryPath . 'png/';
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!is_dir($imageOutputDirectory) &&
|
$_FILES['fileToUpload']['error'] !== UPLOAD_ERR_OK ||
|
||||||
!mkdir($imageOutputDirectory, 0755, true) &&
|
strtolower(pathinfo($_FILES['fileToUpload']['name'], PATHINFO_EXTENSION)) !== 'pdf'
|
||||||
!is_dir($imageOutputDirectory)
|
|
||||||
) {
|
) {
|
||||||
$_SESSION['meldung_dateien'] =
|
$_SESSION['meldung_dateien'] = 'Bitte eine gültige PDF-Datei hochladen.';
|
||||||
'Das Aushang-Verzeichnis konnte nicht angelegt werden.';
|
|
||||||
header('Location: insert.php#dateien');
|
header('Location: insert.php#dateien');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileName = generateFileName($date, $name, 'pdf');
|
$baseFileName = $date . '-' . $name;
|
||||||
$targetFilePath = $directoryPath . $fileName;
|
|
||||||
$baseFileName = pathinfo($fileName, PATHINFO_FILENAME);
|
|
||||||
|
|
||||||
if (!isValidNewsFileBase($baseFileName)) {
|
if (!is_dir(NEWS_PNG_DIRECTORY) && !mkdir(NEWS_PNG_DIRECTORY, 0755, true)) {
|
||||||
$_SESSION['meldung_dateien'] = 'Ungültiger Dateiname.';
|
$_SESSION['meldung_dateien'] = 'Das Aushang-Verzeichnis konnte nicht angelegt werden.';
|
||||||
header('Location: insert.php#dateien');
|
|
||||||
exit();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!move_uploaded_file(
|
|
||||||
$_FILES['fileToUpload']['tmp_name'],
|
|
||||||
$targetFilePath
|
|
||||||
)) {
|
|
||||||
$_SESSION['meldung_dateien'] = 'Fehler beim Speichern der PDF-Datei.';
|
|
||||||
header('Location: insert.php#dateien');
|
header('Location: insert.php#dateien');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!convertPDFtoPNG(
|
if (!convertPDFtoPNG(
|
||||||
$targetFilePath,
|
$_FILES['fileToUpload']['tmp_name'],
|
||||||
$imageOutputDirectory,
|
NEWS_PNG_DIRECTORY,
|
||||||
$baseFileName
|
$baseFileName
|
||||||
)) {
|
)) {
|
||||||
// Fehlgeschlagenen Upload vollständig aufräumen.
|
|
||||||
deleteNewsFiles($baseFileName);
|
deleteNewsFiles($baseFileName);
|
||||||
|
$_SESSION['meldung_dateien'] = 'Fehler bei der Umwandlung der PDF.';
|
||||||
$_SESSION['meldung_dateien'] =
|
|
||||||
'Fehler bei der Umwandlung der PDF. '
|
|
||||||
. 'Die unvollständigen Dateien wurden entfernt.';
|
|
||||||
|
|
||||||
header('Location: insert.php#dateien');
|
header('Location: insert.php#dateien');
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -281,6 +233,7 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['fileToUpload'])) {
|
|||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Löschen eines Gottesdienstes
|
// Löschen eines Gottesdienstes
|
||||||
if (isset($_POST['delete_id'])) {
|
if (isset($_POST['delete_id'])) {
|
||||||
$delete_id = $_POST['delete_id'];
|
$delete_id = $_POST['delete_id'];
|
||||||
@@ -898,51 +851,29 @@ $pdo = null;
|
|||||||
</div>
|
</div>
|
||||||
<div class="sb-aushang-grid">
|
<div class="sb-aushang-grid">
|
||||||
<?php
|
<?php
|
||||||
$pngDirectoryPath = '/var/www/html/intranet_repo/projects/contentpanel/insertion/news/png/';
|
$aushangFiles = glob(NEWS_PNG_DIRECTORY . '/*_page_1.png') ?: [];
|
||||||
if (is_dir($pngDirectoryPath)) {
|
|
||||||
$pngFiles = scandir($pngDirectoryPath);
|
|
||||||
$aushangData = [];
|
|
||||||
|
|
||||||
foreach ($pngFiles as $file) {
|
if (!$aushangFiles) {
|
||||||
if (strpos($file, '_page_1.png') !== false) {
|
echo '<p style="color:var(--gray-500);font-size:var(--font-size-sm);grid-column:1/-1;text-align:center;padding:var(--space-lg) 0;">Keine Aushänge vorhanden.</p>';
|
||||||
$baseFileName = substr($file, 0, strpos($file, '_page_1.png'));
|
|
||||||
$fileParts = explode('-', $baseFileName);
|
|
||||||
$expiryDate = implode('-', array_slice($fileParts, 0, 3));
|
|
||||||
$title = implode('-', array_slice($fileParts, 3));
|
|
||||||
$date = DateTime::createFromFormat('Y-m-d', $expiryDate);
|
|
||||||
$formattedExpiryDate = $date !== false ? $date->format('d.m.Y') : $expiryDate;
|
|
||||||
|
|
||||||
$numPages = 0;
|
|
||||||
foreach ($pngFiles as $png) {
|
|
||||||
if (strpos($png, $baseFileName . '_page_') !== false) $numPages++;
|
|
||||||
}
|
|
||||||
|
|
||||||
$aushangData[] = [
|
|
||||||
'fileBase' => $baseFileName,
|
|
||||||
'formattedExpiry' => $formattedExpiryDate,
|
|
||||||
'title' => $title,
|
|
||||||
'numPages' => $numPages,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (empty($aushangData)) {
|
|
||||||
echo '<p style="color:var(--gray-500);font-size:var(--font-size-sm);grid-column:1/-1;text-align:center;padding:var(--space-lg) 0;">Keine Aushänge vorhanden.</p>';
|
|
||||||
} else {
|
|
||||||
foreach ($aushangData as $aushang) {
|
|
||||||
echo '<div class="sb-aushang-card">';
|
|
||||||
echo '<img src="/intranet_repo/projects/contentpanel/insertion/news/png/' . $aushang['fileBase'] . '_page_1.png" alt="Aushang">';
|
|
||||||
echo '<div class="sb-aushang-title">' . htmlspecialchars($aushang['title']) . '</div>';
|
|
||||||
echo '<div class="sb-aushang-meta">' . $aushang['numPages'] . ($aushang['numPages'] == 1 ? ' Seite' : ' Seiten') . ' · Verfällt ' . $aushang['formattedExpiry'] . '</div>';
|
|
||||||
echo '<form method="POST" action="" style="width:100%;text-align:center;">';
|
|
||||||
echo '<input type="hidden" name="delete_file_base" value="' . $aushang['fileBase'] . '">';
|
|
||||||
echo '<button type="submit" class="sb-btn sb-btn-danger" onclick="return confirm(\'Aushang wirklich löschen?\')">Löschen</button>';
|
|
||||||
echo '</form>';
|
|
||||||
echo '</div>';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
echo '<p style="color:var(--gray-500);font-size:var(--font-size-sm);grid-column:1/-1;text-align:center;">Verzeichnis nicht gefunden.</p>';
|
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 '<div class="sb-aushang-card">';
|
||||||
|
echo '<img src="/intranet_repo/projects/contentpanel/insertion/news/png/' . rawurlencode($baseFileName) . '_page_1.png" alt="Aushang">';
|
||||||
|
echo '<div class="sb-aushang-title">' . htmlspecialchars($title) . '</div>';
|
||||||
|
echo '<div class="sb-aushang-meta">' . $numPages . ($numPages === 1 ? ' Seite' : ' Seiten') . ' · Verfällt ' . $formattedExpiryDate . '</div>';
|
||||||
|
echo '<form method="POST" action="" style="width:100%;text-align:center;">';
|
||||||
|
echo '<input type="hidden" name="delete_file_base" value="' . $safeBase . '">';
|
||||||
|
echo '<button type="submit" class="sb-btn sb-btn-danger" onclick="return confirm(\'Aushang wirklich löschen?\')">Löschen</button>';
|
||||||
|
echo '</form>';
|
||||||
|
echo '</div>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,133 +1,49 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Prüft, ob ein Basisname dem von der Anwendung erzeugten Format entspricht.
|
const NEWS_PNG_DIRECTORY = __DIR__ . '/news/png';
|
||||||
|
|
||||||
function isValidNewsFileBase(string $fileBase): bool
|
function isValidNewsFileBase(string $fileBase): bool
|
||||||
{
|
{
|
||||||
return preg_match(
|
return preg_match('/^\d{4}-\d{2}-\d{2}-[A-Za-z0-9_-]+$/D', $fileBase) === 1;
|
||||||
'/^\d{4}-\d{2}-\d{2}-[A-Za-z0-9_-]+$/D',
|
|
||||||
$fileBase
|
|
||||||
) === 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Löscht eine News vollständig:
|
|
||||||
*
|
|
||||||
* - Original-PDF
|
|
||||||
* - alle daraus erzeugten PNG-Seiten
|
|
||||||
*/
|
|
||||||
function deleteNewsFiles(string $fileBase): bool
|
function deleteNewsFiles(string $fileBase): bool
|
||||||
{
|
{
|
||||||
if (!isValidNewsFileBase($fileBase)) {
|
if (!isValidNewsFileBase($fileBase)) {
|
||||||
error_log('Ungültiger News-Dateiname beim Löschen: ' . $fileBase);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$newsDirectory = __DIR__ . '/news';
|
|
||||||
$pngDirectory = $newsDirectory . '/png';
|
|
||||||
|
|
||||||
$success = true;
|
$success = true;
|
||||||
|
|
||||||
// Alle erzeugten PNG-Seiten löschen
|
foreach (glob(NEWS_PNG_DIRECTORY . '/' . $fileBase . '_page_*.png') ?: [] as $file) {
|
||||||
$pngFiles = glob(
|
if (!unlink($file)) {
|
||||||
$pngDirectory . '/' . $fileBase . '_page_*.png'
|
|
||||||
) ?: [];
|
|
||||||
|
|
||||||
foreach ($pngFiles as $pngFile) {
|
|
||||||
if (is_file($pngFile) && !unlink($pngFile)) {
|
|
||||||
error_log('News-PNG konnte nicht gelöscht werden: ' . $pngFile);
|
|
||||||
$success = false;
|
$success = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Original-PDF löschen
|
|
||||||
$pdfFile = $newsDirectory . '/' . $fileBase . '.pdf';
|
|
||||||
|
|
||||||
if (is_file($pdfFile) && !unlink($pdfFile)) {
|
|
||||||
error_log('News-PDF konnte nicht gelöscht werden: ' . $pdfFile);
|
|
||||||
$success = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $success;
|
return $success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Löscht alle abgelaufenen News.
|
|
||||||
*
|
|
||||||
* Wichtig:
|
|
||||||
* Es werden sowohl vorhandene PDFs als auch page_1-PNGs betrachtet.
|
|
||||||
* Dadurch werden auch verwaiste PDFs ohne PNG zuverlässig gefunden.
|
|
||||||
*/
|
|
||||||
function cleanupExpiredNews(): void
|
function cleanupExpiredNews(): void
|
||||||
{
|
{
|
||||||
$newsDirectory = __DIR__ . '/news';
|
$today = new DateTimeImmutable('today');
|
||||||
$pngDirectory = $newsDirectory . '/png';
|
|
||||||
|
|
||||||
$fileBases = [];
|
foreach (glob(NEWS_PNG_DIRECTORY . '/*_page_1.png') ?: [] as $file) {
|
||||||
|
$fileBase = basename($file, '_page_1.png');
|
||||||
|
|
||||||
// PDFs erfassen
|
if (!isValidNewsFileBase($fileBase)) {
|
||||||
foreach (glob($newsDirectory . '/*.pdf') ?: [] as $pdfFile) {
|
|
||||||
$fileBase = pathinfo($pdfFile, PATHINFO_FILENAME);
|
|
||||||
|
|
||||||
if (isValidNewsFileBase($fileBase)) {
|
|
||||||
$fileBases[$fileBase] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Zusätzlich PNGs erfassen.
|
|
||||||
// Damit funktioniert die Bereinigung auch, falls die PDF bereits fehlt.
|
|
||||||
foreach (glob($pngDirectory . '/*_page_1.png') ?: [] as $pngFile) {
|
|
||||||
$fileName = basename($pngFile);
|
|
||||||
$suffix = '_page_1.png';
|
|
||||||
|
|
||||||
if (!str_ends_with($fileName, $suffix)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$fileBase = substr($fileName, 0, -strlen($suffix));
|
$dateString = substr($fileBase, 0, 10);
|
||||||
|
$expiryDate = DateTimeImmutable::createFromFormat('!Y-m-d', $dateString);
|
||||||
|
|
||||||
if (isValidNewsFileBase($fileBase)) {
|
|
||||||
$fileBases[$fileBase] = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$now = new DateTimeImmutable();
|
|
||||||
|
|
||||||
foreach (array_keys($fileBases) as $fileBase) {
|
|
||||||
// YYYY-MM-DD aus dem Dateinamen holen
|
|
||||||
$expiryDateString = substr($fileBase, 0, 10);
|
|
||||||
|
|
||||||
$expiryDate = DateTimeImmutable::createFromFormat(
|
|
||||||
'!Y-m-d',
|
|
||||||
$expiryDateString
|
|
||||||
);
|
|
||||||
|
|
||||||
// Zusätzlich prüfen, ob wirklich ein gültiges Datum entstanden ist
|
|
||||||
if (
|
if (
|
||||||
$expiryDate === false ||
|
$expiryDate !== false &&
|
||||||
$expiryDate->format('Y-m-d') !== $expiryDateString
|
$expiryDate->format('Y-m-d') === $dateString &&
|
||||||
|
$today > $expiryDate
|
||||||
) {
|
) {
|
||||||
error_log(
|
deleteNewsFiles($fileBase);
|
||||||
'Ungültiges Ablaufdatum bei News-Datei: ' . $fileBase
|
|
||||||
);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Aushang bleibt den gesamten angegebenen Tag sichtbar.
|
|
||||||
* Beispiel Ablaufdatum 2026-09-05:
|
|
||||||
* Löschung ab 2026-09-06 00:00 Uhr.
|
|
||||||
*/
|
|
||||||
$deleteFrom = $expiryDate->modify('+1 day');
|
|
||||||
|
|
||||||
if ($now >= $deleteFrom) {
|
|
||||||
if (!deleteNewsFiles($fileBase)) {
|
|
||||||
error_log(
|
|
||||||
'Abgelaufene News konnte nicht vollständig gelöscht werden: '
|
|
||||||
. $fileBase
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user