diff --git a/CHANGELOG.md b/CHANGELOG.md index ca3793b..458fc9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,16 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag --- +## [1.6.10] - 2026-05-15 + +### Corrigé +- Suppression d'article échouait silencieusement quand le répertoire UUID appartenait à un autre utilisateur que `www-data` (permissions `2755` → groupe sans écriture) — `removeDir()` échouait sans erreur visible et l'article restait accessible +- `ArticleManager::delete()` retourne maintenant `bool` : si le répertoire existe encore après tentative de suppression, les index ne sont pas reconstruits et l'utilisateur est redirigé vers l'article avec un message d'erreur +- `removeDir()` : erreurs PHP supprimées silencieusement (`@unlink`, `@rmdir`, `@scandir`) pour éviter les warnings qui cassaient les redirects +- `mkArticleDir()` : nouvelle méthode privée qui crée les répertoires d'articles avec `chmod 0775` explicite (contourne le umask), garantissant que `www-data` (groupe) a toujours les droits d'écriture + +--- + ## [Unreleased] --- diff --git a/public/index.php b/public/index.php index 40e6c78..dd7674f 100644 --- a/public/index.php +++ b/public/index.php @@ -1114,7 +1114,13 @@ switch ($action) { case 'delete': requireAuth(); if ($uuid !== '') { - $articles->delete($uuid); + if (!$articles->delete($uuid)) { + $failedArt = $articles->getByUuid($uuid); + $failedSlug = $failedArt['slug'] ?? ''; + $back = $failedSlug !== '' ? '/post/' . rawurlencode($failedSlug) : '/'; + header('Location: ' . $back . '?delete_failed=1'); + exit; + } } header('Location: /'); exit; diff --git a/public/version.txt b/public/version.txt index 15d45d4..1df3b82 100644 --- a/public/version.txt +++ b/public/version.txt @@ -1 +1 @@ -1.6.9 +1.6.10 diff --git a/src/ArticleManager.php b/src/ArticleManager.php index a69cbe7..36a2f4b 100644 --- a/src/ArticleManager.php +++ b/src/ArticleManager.php @@ -105,8 +105,8 @@ class ArticleManager $publishedAt = $publishedAt !== '' ? $publishedAt : $now; $dir = $this->dataDir . '/' . $uuid; - mkdir($dir, 0755, true); - mkdir($dir . '/files', 0755, true); + $this->mkArticleDir($dir); + $this->mkArticleDir($dir . '/files'); $meta = [ 'uuid' => $uuid, @@ -155,7 +155,7 @@ class ArticleManager if ($contentChanged || $titleChanged) { $revDir = $this->dataDir . '/' . $uuid . '/revisions'; if (!is_dir($revDir)) { - mkdir($revDir, 0755, true); + $this->mkArticleDir($revDir); } $n = count($revisions) + 1; $revFile = sprintf('%s/%04d.md', $revDir, $n); @@ -482,7 +482,7 @@ class ArticleManager $isImage = str_starts_with($mime, 'image/'); $filesDir = $this->dataDir . '/' . $uuid . '/files'; if (!is_dir($filesDir)) { - mkdir($filesDir, 0755, true); + $this->mkArticleDir($filesDir); } if ($isImage) { @@ -806,10 +806,10 @@ class ArticleManager $this->git?->commit("featured: " . ($meta['title'] ?? $uuid) . " (" . ($featured ? 'on' : 'off') . ")"); } - public function delete(string $uuid): void + public function delete(string $uuid): bool { if (!$this->isValidUuid($uuid)) { - return; + return false; } $dir = $this->dataDir . '/' . $uuid; $title = null; @@ -823,9 +823,13 @@ class ArticleManager @unlink($this->slugIndexPath()); $this->removeDir($dir); } + if (is_dir($dir)) { + return false; + } $this->rebuildSearchIndex(); $this->rebuildBacklinksCache(); $this->git?->commit("delete: " . ($title ?? $uuid)); + return true; } // ------------------------------------------------------------------ // @@ -1110,7 +1114,7 @@ class ArticleManager } $dir = $this->dataDir . '/' . $uuid . '/files'; if (!is_dir($dir)) { - mkdir($dir, 0755, true); + $this->mkArticleDir($dir); } $mime = mime_content_type($uploadedFile['tmp_name']) ?: 'application/octet-stream'; @@ -1370,13 +1374,19 @@ class ArticleManager */ private function removeDir(string $dir): void { - foreach (scandir($dir) as $entry) { + foreach (@scandir($dir) ?: [] as $entry) { if ($entry === '.' || $entry === '..') { continue; } $path = $dir . '/' . $entry; - is_dir($path) ? $this->removeDir($path) : unlink($path); + is_dir($path) ? $this->removeDir($path) : @unlink($path); } - rmdir($dir); + @rmdir($dir); + } + + private function mkArticleDir(string $path): void + { + mkdir($path, 0777, true); + chmod($path, 0775); } } diff --git a/templates/post_view.php b/templates/post_view.php index 1d0a043..e47f181 100644 --- a/templates/post_view.php +++ b/templates/post_view.php @@ -173,6 +173,12 @@ $hasSources = (!empty($externalLinks) || !empty($files))
+ +
+ Suppression impossible — droits insuffisants sur le répertoire de données. + +
+