From 0bbf053703f1edd01cca6c7dbe791ee2ab2cbc57 Mon Sep 17 00:00:00 2001 From: Jordan Diaz Date: Sun, 13 Sep 2026 18:08:02 +0000 Subject: [PATCH] fix(core): el borrado recursivo se dejaba los ficheros ocultos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `_deleteAll` listaba con `glob`, que NO devuelve los ficheros que empiezan por punto. Un `.htaccess` sobrevivia al barrido, la carpeta no quedaba vacia y el `rmdir` de despues fallaba sin decir por que. Efecto real, encontrado desinstalando `variaciones` en produccion: se borra el codigo del plugin, se devuelve "No se ha podido desinstalar el plugin" y la operacion queda A MEDIAS — sin ficheros, pero con la carpeta en la web y con el alta todavia en el CMS central. El paso que falla es el segundo de cuatro, asi que los dos ultimos ni se intentan. En una web real son 5 de 14 los plugins con `.htaccess`, no un caso raro. Se cambia a `scandir`, que si los ve, saltando `.` y `..`. Y de paso el symlink, que con `glob` tampoco se trataba: ahora se QUITA el enlace en vez de seguirlo. Recorrerlo seria borrar lo que hay al otro lado, que vive fuera de la carpeta que se pidio borrar. Comprobado con un enlace a un directorio con un fichero dentro: el enlace desaparece, el fichero se queda. Verificado dentro del container, con carpeta anidada, dos ficheros ocultos y un symlink: la carpeta se borra entera y lo apuntado sobrevive. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01HPL66q9F33YZxbLPUT7KW8 --- cms/lib/handlers/handler_ws.php | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/cms/lib/handlers/handler_ws.php b/cms/lib/handlers/handler_ws.php index 458c55d..faaa35f 100755 --- a/cms/lib/handlers/handler_ws.php +++ b/cms/lib/handlers/handler_ws.php @@ -324,17 +324,24 @@ function _removeFile() { } function _deleteAll($str) { - if (!file_exists($str)) return false; - if (is_file($str)) { + if (!file_exists($str) && !is_link($str)) return false; + // Un symlink se quita, NUNCA se sigue: borrar su contenido seria borrar algo + // que vive fuera de la carpeta que se pidio borrar. + if (is_link($str) || is_file($str)) { return unlink($str); } elseif (is_dir($str)) { - //Get a list of the files in this directory. - $scan = glob(rtrim($str,'/').'/*'); - //Loop through the list of files. - foreach($scan as $index=>$path) { - //Call our recursive function. - _deleteAll($path); + // `scandir` y no `glob`: glob NO devuelve los ficheros ocultos, asi que + // un `.htaccess` sobrevivia al borrado, la carpeta no quedaba vacia y el + // rmdir de abajo fallaba en silencio. Con eso, desinstalar en produccion + // un plugin con .htaccess —5 de 14 en una web real— borraba su codigo, + // devolvia "no se ha podido desinstalar" y dejaba la operacion a medias: + // sin ficheros, pero con la carpeta y con el alta en el central. + $entradas = @scandir($str); + if ($entradas === false) return false; + foreach ($entradas as $nombre) { + if ($nombre === '.' || $nombre === '..') continue; + _deleteAll(rtrim($str, '/') . '/' . $nombre); } //Remove the directory itself. return @rmdir($str);