117 lines
2.7 KiB
PHP
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);
|