fix(core): el borrado recursivo se dejaba los ficheros ocultos

`_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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HPL66q9F33YZxbLPUT7KW8
This commit is contained in:
Jordan Diaz
2026-09-13 18:08:02 +00:00
co-authored by Claude Opus 5
parent b1c9ffa461
commit 0bbf053703
+15 -8
View File
@@ -324,17 +324,24 @@ function _removeFile() {
} }
function _deleteAll($str) { function _deleteAll($str) {
if (!file_exists($str)) return false; if (!file_exists($str) && !is_link($str)) return false;
if (is_file($str)) { // 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); return unlink($str);
} }
elseif (is_dir($str)) { elseif (is_dir($str)) {
//Get a list of the files in this directory. // `scandir` y no `glob`: glob NO devuelve los ficheros ocultos, asi que
$scan = glob(rtrim($str,'/').'/*'); // un `.htaccess` sobrevivia al borrado, la carpeta no quedaba vacia y el
//Loop through the list of files. // rmdir de abajo fallaba en silencio. Con eso, desinstalar en produccion
foreach($scan as $index=>$path) { // un plugin con .htaccess —5 de 14 en una web real— borraba su codigo,
//Call our recursive function. // devolvia "no se ha podido desinstalar" y dejaba la operacion a medias:
_deleteAll($path); // 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. //Remove the directory itself.
return @rmdir($str); return @rmdir($str);