Files
Simple-Wishlist/include/delete_unused.php
2025-08-18 20:39:36 +02:00

117 lines
2.7 KiB
PHP

<?php
declare(strict_types=1);
/**
* delete_unused.php
*
* Löscht Bilddateien aus $imagedir, die in der DB nicht referenziert sind.
* Sicherheit:
* - CLI-only (kein Webzugriff)
* - Pfad-Härtung via realpath()
* - Dry-Run optional (default)
*
* Aufruf:
* php delete_unused.php # Dry-Run (zeigt nur an)
* php delete_unused.php --apply # wirklich löschen
*/
if (PHP_SAPI !== 'cli') {
http_response_code(403);
exit('Forbidden');
}
require_once __DIR__ . '/../config/config.php';
function out(string $msg): void
{
fwrite(STDOUT, $msg . PHP_EOL);
}
function err(string $msg): void
{
fwrite(STDERR, "ERROR: " . $msg . PHP_EOL);
exit(1);
}
// Flags
$apply = in_array('--apply', $argv, true);
// DB verbinden
$conn = @new mysqli($GLOBALS['servername'], $GLOBALS['username'], $GLOBALS['password'], $GLOBALS['db']);
if ($conn->connect_error)
err('DB-Verbindung fehlgeschlagen');
// Bildverzeichnis prüfen/härten
$baseDir = realpath(__DIR__ . '/..');
if ($baseDir === false)
err('BaseDir nicht gefunden');
$imgDirCfg = rtrim((string) $GLOBALS['imagedir'], '/');
$imgDir = realpath(__DIR__ . '/../' . $imgDirCfg);
if ($imgDir === false)
err('imagedir nicht gefunden: ' . $imgDirCfg);
// Verhindere, dass außerhalb des Projekts gelöscht wird
if (strpos($imgDir, $baseDir) !== 0)
err('imagedir liegt außerhalb des Projekts: ' . $imgDir);
// Aus DB: genutzte Dateien (NULL/"" filtern)
$used = [];
$sql = 'SELECT image FROM wishes WHERE image IS NOT NULL AND image <> ""';
$res = $conn->query($sql);
if ($res === false)
err('Query fehlgeschlagen');
while ($row = $res->fetch_assoc()) {
$used[] = (string) $row['image'];
}
$res->free();
$conn->close();
// In ein Set packen
$usedSet = array_flip($used);
$deleted = 0;
$kept = 0;
$skipped = 0;
$it = new DirectoryIterator($imgDir);
foreach ($it as $fileinfo) {
if ($fileinfo->isDot())
continue;
$path = $fileinfo->getPathname();
if ($fileinfo->isDir()) {
$skipped++;
out("[skip-dir] " . $path);
continue;
}
$name = $fileinfo->getFilename();
if (isset($usedSet[$name])) {
$kept++;
out("[keep] " . $name);
continue;
}
// Nicht referenziert -> löschen (oder dry-run)
if ($apply) {
if (@unlink($path)) {
$deleted++;
out("[delete] " . $name);
} else {
err('Konnte Datei nicht löschen: ' . $path);
}
} else {
out("[dry-run] " . $name . " (würde gelöscht)");
}
}
out("");
out("Summary:");
out(" kept: {$kept}");
out(" skipped: {$skipped}");
out(" deleted: {$deleted}" . ($apply ? "" : " (dry-run)"));
exit(0);