Supprimer le répertoire contenant des fichiers?


246

Je me demande, quelle est la façon la plus simple de supprimer un répertoire contenant tous ses fichiers?

J'utilise rmdir(PATH . '/' . $value);pour supprimer un dossier, cependant, s'il y a des fichiers à l'intérieur, je ne peux tout simplement pas le supprimer.



2
yup, a répondu exactement à cette question.
timdev

Je veux juste noter. J'ai créé plusieurs fichiers et si, au cours du processus, j'obtiens une erreur, je dois supprimer les fichiers créés précédemment. Lorsque vous avez créé des fichiers, oublié d'utiliser fclose($create_file);et lors de la suppression, obtenu Warning: unlink(created_file.xml): Permission denied in.... Donc, pour éviter de telles erreurs, vous devez fermer les fichiers créés.
Andris

Réponses:


382

Il y a au moins deux options disponibles de nos jours.

  1. Avant de supprimer le dossier, supprimez tous ses fichiers et dossiers (et cela signifie récursivité!). Voici un exemple:

    public static function deleteDir($dirPath) {
        if (! is_dir($dirPath)) {
            throw new InvalidArgumentException("$dirPath must be a directory");
        }
        if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
            $dirPath .= '/';
        }
        $files = glob($dirPath . '*', GLOB_MARK);
        foreach ($files as $file) {
            if (is_dir($file)) {
                self::deleteDir($file);
            } else {
                unlink($file);
            }
        }
        rmdir($dirPath);
    }
  2. Et si vous utilisez 5.2+, vous pouvez utiliser un RecursiveIterator pour le faire sans implémenter la récursivité vous-même:

    $dir = 'samples' . DIRECTORY_SEPARATOR . 'sampledirtree';
    $it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
    $files = new RecursiveIteratorIterator($it,
                 RecursiveIteratorIterator::CHILD_FIRST);
    foreach($files as $file) {
        if ($file->isDir()){
            rmdir($file->getRealPath());
        } else {
            unlink($file->getRealPath());
        }
    }
    rmdir($dir);

11
Votre deuxième implémentation est quelque peu dangereuse: elle ne vérifie pas les points ( .et ..) et elle supprime le chemin résolu, pas le chemin réel.
Alix Axel

9
petit module complémentaire :-) glob () ne prend pas en charge les fichiers comme .htaccess. J'ai utilisé la fonction pour effacer les répertoires créés par KCFinder (plugin CKEditor) qui génère à la fois .htaccess et .thumbs (fichier + dossier). Au lieu de cela, j'ai utilisé la scandirfonction pour obtenir la liste des dossiers. Assurez-vous simplement de filtrer le '.' et les fichiers «..» de la liste des résultats.
Joshua - Pendo

25
DIRECTORY_SEPARATOR n'est pas nécessaire lorsque vous créez des chemins à envoyer au système d' exploitation. Windows accepte également les barres obliques. Son principalement utile pour explode()ing un chemin emprunté à l'OS. alanhogan.com/tips/php/directory-separator-not-necessary
ReactiveRaven

5
En plus de @Alix Axel Utiliser ici le [SplFileInfo :: getRealPath ()] ( php.net/manual/en/splfileinfo.getrealpath.php ) n'est pas une bonne idée. Cette méthode étend tous les liens symboliques, ce qui signifie, sera supprimé un vrai fichier de quelque part au lieu d'un lien symbolique du répertoire cible. Vous devez utiliser SplFileInfo :: getPathname () à la place.
Vijit

2
Je suis d'accord avec @Vijit, utilisez getPathname () au lieu de getRealPath (). Il fait la même chose sans supprimer plus que ce à quoi vous vous attendez si des liens symboliques sont trouvés.
JoeMoe1984

196

Je l'utilise généralement pour supprimer tous les fichiers d'un dossier:

array_map('unlink', glob("$dirname/*.*"));

Et puis vous pouvez faire

rmdir($dirname);

26
Cela ne supprime pas les dossiers récursivement; cela ne fonctionne que si le dossier ne contient que des fichiers normaux, qui ont tous des extensions de fichier.
mgnb

5
Si aucune récursivité n'est nécessaire, c'est la meilleure et la plus simple réponse à ce jour. Merci!
eisbehr

2
Afin de supprimer tous les fichiers d'un dossier, pas seulement ceux avec des extensions, utilisez glob de la manière suivante: array_map('unlink', glob("$dirname/*"));Cela ne vous permet toujours pas de supprimer les répertoires imbriqués dans le dossier.
kremuwa

Notez que cela supprimera également les fichiers de points (masqués).
BadHorsie

84

quelle est la façon la plus simple de supprimer un répertoire contenant tous ses fichiers?

system("rm -rf ".escapeshellarg($dir));

33
J'espère que tu n'es pas sérieux. Que se passe-t-il si $ dir est /
Le développeur de pixels

108
@Le exactement le même que pour n'importe lequel des codes ci-dessus. N'est-ce pas?
Your Common Sense

7
Notez que, selon la façon dont il $direst généré / fourni, vous devrez peut-être effectuer un prétraitement supplémentaire pour être sûr et éviter les bogues. Par exemple, s'il $dirpeut y avoir un espace non échappé ou un point-virgule, il peut y avoir des effets secondaires indésirables. Ce n'est pas le cas avec les réponses qui utilisent des choses comme rmdir()parce qu'il gérera les caractères spéciaux pour vous.
Trott

5
Version Windows:system('rmdir '.escapeshellarg($path).' /s /q');
Cypher

2
@ThePixelDeveloper vous ne devriez pas vous soucier de supprimer /, cela ne fonctionnerait que si vous lounchiez le script en ligne de commande en tant que root, car sur le Web, tout se passe en tant qu'utilisateur apache
Ben

49

Fonction courte qui fait le travail:

function deleteDir($path) {
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

Je l'utilise dans une classe Utils comme celle-ci:

class Utils {
    public static function deleteDir($path) {
        $class_func = array(__CLASS__, __FUNCTION__);
        return is_file($path) ?
                @unlink($path) :
                array_map($class_func, glob($path.'/*')) == @rmdir($path);
    }
}

Une grande puissance s'accompagne d'une grande responsabilité : lorsque vous appelez cette fonction avec une valeur vide, elle supprimera les fichiers commençant par root ( /). Par mesure de sécurité, vous pouvez vérifier si le chemin est vide:

function deleteDir($path) {
    if (empty($path)) { 
        return false;
    }
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}

1
La fonction statique ne fonctionne pas car $ this === NULL lorsque vous appelez une fonction statique sur une classe. Cela fonctionnerait si$this_func = array(__CLASS__, __FUNCTION__);
Matt Connolly

2
Quelqu'un peut-il expliquer la ligne array_map($class_func, glob($path.'/*')) == @rmdir($path)? Je suppose qu'il revient dans les sous-dossiers, mais que fait la partie == @rmdir? Comment le <tableau de booléens> == <booléen> renvoie-t-il la réponse? Vérifie-t-il si chaque valeur de retour de la récursivité est identique à la valeur booléenne de droite?
arviman

2
C'est une astuce pour fusionner deux instructions en une seule instruction. En effet, les opérateurs ternaires n'autorisent qu'une seule instruction par argument. array_map(...)supprime tous les fichiers du répertoire, @rmdir(...)supprime le répertoire lui-même.
Blaise

3
Faites attention! Cette fonction ne vérifie pas si le chemin existe réellement. Si vous passez un argument vide, la fonction commencera à supprimer les fichiers à partir de la racine! Ajoutez un contrôle d'intégrité à votre chemin avant d'exécuter cette fonction.
Tatu Ulmanen

3
Certaines personnes n'ont pas vu le commentaire de Tatu et ont été récursivement supprimées /, j'ai donc ajouté une version protégée à mon message.
Blaise

22

Comme vu dans la plupart des commentaires votés sur la page de manuel PHP concernant rmdir()(voir http://php.net/manual/es/function.rmdir.php ), la glob()fonction ne retourne pas les fichiers cachés. scandir()est fourni comme une alternative qui résout ce problème.

L'algorithme décrit ici (qui fonctionnait comme un charme dans mon cas) est:

<?php 
    function delTree($dir)
    { 
        $files = array_diff(scandir($dir), array('.', '..')); 

        foreach ($files as $file) { 
            (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file"); 
        }

        return rmdir($dir); 
    } 
?>

pouvez-vous expliquer is_dir ("$ dir / $ file") - n'a pas rencontré le paramètre "$ dir / $ file"
Igor L.

Que voulez-vous dire? Il vérifie si l'entrée trouvée dans un répertoire ( $file) est un répertoire ou un fichier. "$dir/$file"est le même que $dir . "/" . $file.
Latorre allemand

Honnêtement, je ne savais pas que vous pouvez concaténer des variables comme celle-ci :) thx
Igor L.

18

Il s'agit d'une version plus courte qui fonctionne très bien pour moi

function deleteDirectory($dirPath) {
    if (is_dir($dirPath)) {
        $objects = scandir($dirPath);
        foreach ($objects as $object) {
            if ($object != "." && $object !="..") {
                if (filetype($dirPath . DIRECTORY_SEPARATOR . $object) == "dir") {
                    deleteDirectory($dirPath . DIRECTORY_SEPARATOR . $object);
                } else {
                    unlink($dirPath . DIRECTORY_SEPARATOR . $object);
                }
            }
        }
    reset($objects);
    rmdir($dirPath);
    }
}

15

Vous pouvez utiliser le système de fichiers de Symfony ( code ):

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

(new Filesystem)->remove($dir);

Cependant, je ne pouvais pas supprimer certaines structures de répertoires complexes avec cette méthode, donc vous devez d'abord l'essayer pour vous assurer qu'elle fonctionne correctement.


Je pourrais supprimer ladite structure de répertoires en utilisant une implémentation spécifique de Windows:

$dir = strtr($dir, '/', '\\');
// quotes are important, otherwise one could
// delete "foo" instead of "foo bar"
system('RMDIR /S /Q "'.$dir.'"');


Et juste pour être complet, voici un ancien code à moi:

function xrmdir($dir) {
    $items = scandir($dir);
    foreach ($items as $item) {
        if ($item === '.' || $item === '..') {
            continue;
        }
        $path = $dir.'/'.$item;
        if (is_dir($path)) {
            xrmdir($path);
        } else {
            unlink($path);
        }
    }
    rmdir($dir);
}

Merci beaucoup. Vous économisez mon temps.
zarif khan

"Ne réinventez pas la roue" . Merci
Kamafeather

9

Ici, vous avez une récursion agréable et simple pour supprimer tous les fichiers du répertoire source, y compris ce répertoire:

function delete_dir($src) { 
    $dir = opendir($src);
    while(false !== ( $file = readdir($dir)) ) { 
        if (( $file != '.' ) && ( $file != '..' )) { 
            if ( is_dir($src . '/' . $file) ) { 
                delete_dir($src . '/' . $file); 
            } 
            else { 
                unlink($src . '/' . $file); 
            } 
        } 
    } 
    closedir($dir); 
    rmdir($src);

}

La fonction est basée sur la récursivité effectuée pour copier le répertoire. Vous pouvez trouver cette fonction ici: Copiez le contenu entier d'un répertoire dans un autre en utilisant php


4

La meilleure solution pour moi

my_folder_delete("../path/folder");

code:

function my_folder_delete($path) {
    if(!empty($path) && is_dir($path) ){
        $dir  = new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS); //upper dirs are not included,otherwise DISASTER HAPPENS :)
        $files = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($files as $f) {if (is_file($f)) {unlink($f);} else {$empty_dirs[] = $f;} } if (!empty($empty_dirs)) {foreach ($empty_dirs as $eachDir) {rmdir($eachDir);}} rmdir($path);
    }
}

ps N'OUBLIEZ PAS!
ne transmettez pas de VALEURS VIDE à toutes les fonctions de suppression de répertoire !!! (sauvegardez-les toujours, sinon un jour vous pourriez avoir une CATASTROPHE !!)


4

Et ça:

function recursiveDelete($dirPath, $deleteParent = true){
    foreach(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dirPath, FilesystemIterator::SKIP_DOTS), RecursiveIteratorIterator::CHILD_FIRST) as $path) {
        $path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname());
    }
    if($deleteParent) rmdir($dirPath);
}

4

La fonction Glob ne renvoie pas les fichiers cachés, donc scandir peut être plus utile lorsque vous essayez de supprimer récursivement une arborescence.

<?php
public static function delTree($dir) {
   $files = array_diff(scandir($dir), array('.','..'));
    foreach ($files as $file) {
      (is_dir("$dir/$file")) ? delTree("$dir/$file") : unlink("$dir/$file");
    }
    return rmdir($dir);
  }
?>

4

Vous pouvez essayer comme suit:

/*
 * Remove the directory and its content (all files and subdirectories).
 * @param string $dir the directory name
 */
function rmrf($dir) {
    foreach (glob($dir) as $file) {
        if (is_dir($file)) { 
            rmrf("$file/*");
            rmdir($file);
        } else {
            unlink($file);
        }
    }
}

3

Je préfère cela car il retourne toujours TRUE quand il réussit et FALSE quand il échoue, et il empêche également un bug où un chemin vide pourrait essayer de tout supprimer de '/ *' !!:

function deleteDir($path)
{
    return !empty($path) && is_file($path) ?
        @unlink($path) :
        (array_reduce(glob($path.'/*'), function ($r, $i) { return $r && deleteDir($i); }, TRUE)) && @rmdir($path);
}

3

Je veux développer la réponse de @alcuadrado avec le commentaire de @Vijit pour la gestion des liens symboliques. Tout d'abord, utilisez getRealPath (). Mais alors, si vous avez des liens symboliques qui sont des dossiers, cela échouera car il essaiera d'appeler rmdir sur un lien - vous avez donc besoin d'une vérification supplémentaire.

$it = new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS);
$files = new RecursiveIteratorIterator($it, RecursiveIteratorIterator::CHILD_FIRST);
foreach($files as $file) {
    if ($file->isLink()) {
        unlink($file->getPathname());
    } else if ($file->isDir()){
        rmdir($file->getPathname());
    } else {
        unlink($file->getPathname());
    }
}
rmdir($dir);

1
Je n'ai pas assez de représentants pour commenter directement la réponse.
user701152

3

Utiliser DirectoryIterator un équivalent d'une réponse précédente…

function deleteFolder($rootPath)
{   
    foreach(new DirectoryIterator($rootPath) as $fileToDelete)
    {
        if($fileToDelete->isDot()) continue;
        if ($fileToDelete->isFile())
            unlink($fileToDelete->getPathName());
        if ($fileToDelete->isDir())
            deleteFolder($fileToDelete->getPathName());
    }

    rmdir($rootPath);
}

3

Celui-ci fonctionne pour moi:

function removeDirectory($path) {
    $files = glob($path . '/*');
    foreach ($files as $file) {
        is_dir($file) ? removeDirectory($file) : unlink($file);
    }
    rmdir($path);
    return;
}

2

Quelque chose comme ça?

function delete_folder($folder) {
    $glob = glob($folder);
    foreach ($glob as $g) {
        if (!is_dir($g)) {
            unlink($g);
        } else {
            delete_folder("$g/*");
            rmdir($g);
        }
    }
}

2

Petite modification du code d'alcuadrado - globne voyez pas les fichiers avec le nom de points comme .htaccessj'utilise scandir et le script se supprime - vérifiez __FILE__.

function deleteDir($dirPath) {
    if (!is_dir($dirPath)) {
        throw new InvalidArgumentException("$dirPath must be a directory");
    }
    if (substr($dirPath, strlen($dirPath) - 1, 1) != '/') {
        $dirPath .= '/';
    }
    $files = scandir($dirPath); 
    foreach ($files as $file) {
        if ($file === '.' || $file === '..') continue;
        if (is_dir($dirPath.$file)) {
            deleteDir($dirPath.$file);
        } else {
            if ($dirPath.$file !== __FILE__) {
                unlink($dirPath.$file);
            }
        }
    }
    rmdir($dirPath);
}

2

Exemple pour le serveur Linux: exec('rm -f -r ' . $cache_folder . '/*');


J'aime généralement ajouter une vérification d'esprit sur $ cache_folder avant d'exécuter rm -rf pour éviter des erreurs coûteuses
glyphe

1

Supprimer tous les fichiers du dossier
array_map('unlink', glob("$directory/*.*"));
Supprimer tout. * - Fichiers du dossier (sans: "." Et "..")
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
Supprimez maintenant le dossier lui-même
rmdir($directory)


1

2 cents à ajouter à CETTE réponse ci-dessus, ce qui est génial BTW

Une fois que votre fonction glob (ou similaire) a analysé / lu le répertoire, ajoutez une condition pour vérifier que la réponse n'est pas vide, ou un invalid argument supplied for foreach()avertissement sera lancé. Alors...

if( ! empty( $files ) )
{
    foreach( $files as $file )
    {
        // do your stuff here...
    }
}

Ma fonction complète (comme méthode d'objet):

    private function recursiveRemoveDirectory( $directory )
    {
        if( ! is_dir( $directory ) )
        {
            throw new InvalidArgumentException( "$directory must be a directory" );
        }

        if( substr( $directory, strlen( $directory ) - 1, 1 ) != '/' )
        {
            $directory .= '/';
        }

        $files = glob( $directory . "*" );

        if( ! empty( $files ) )
        {
            foreach( $files as $file )
            {
                if( is_dir( $file ) )
                {
                    $this->recursiveRemoveDirectory( $file );
                }
                else
                {
                    unlink( $file );
                }
            }               
        }
        rmdir( $directory );

    } // END recursiveRemoveDirectory()

1

Voici la solution qui fonctionne parfaitement:

function unlink_r($from) {
    if (!file_exists($from)) {return false;}
    $dir = opendir($from);
    while (false !== ($file = readdir($dir))) {
        if ($file == '.' OR $file == '..') {continue;}

        if (is_dir($from . DIRECTORY_SEPARATOR . $file)) {
            unlink_r($from . DIRECTORY_SEPARATOR . $file);
        }
        else {
            unlink($from . DIRECTORY_SEPARATOR . $file);
        }
    }
    rmdir($from);
    closedir($dir);
    return true;
}

1

Vous pouvez copier les assistants YII

$ directory (string) - à supprimer récursivement.

$ options (array) - pour la suppression du répertoire. Les options valides sont: traverseSymlinks: booléen, si les liens symboliques vers les répertoires doivent également être parcourus. La valeur par défaut est false, ce qui signifie que le contenu du répertoire lié ne sera pas supprimé. Seul le lien symbolique serait supprimé dans ce cas par défaut.

public static function removeDirectory($directory,$options=array())
{
    if(!isset($options['traverseSymlinks']))
        $options['traverseSymlinks']=false;
    $items=glob($directory.DIRECTORY_SEPARATOR.'{,.}*',GLOB_MARK | GLOB_BRACE);
    foreach($items as $item)
    {
        if(basename($item)=='.' || basename($item)=='..')
            continue;
        if(substr($item,-1)==DIRECTORY_SEPARATOR)
        {
            if(!$options['traverseSymlinks'] && is_link(rtrim($item,DIRECTORY_SEPARATOR)))
                unlink(rtrim($item,DIRECTORY_SEPARATOR));
            else
                self::removeDirectory($item,$options);
        }
        else
            unlink($item);
    }
    if(is_dir($directory=rtrim($directory,'\\/')))
    {
        if(is_link($directory))
            unlink($directory);
        else
            rmdir($directory);
    }
}

0
<?php
  function rrmdir($dir) {
  if (is_dir($dir)) {
    $objects = scandir($dir);
    foreach ($objects as $object) {
      if ($object != "." && $object != "..") {
        if (filetype($dir."/".$object) == "dir") 
           rrmdir($dir."/".$object); 
        else unlink   ($dir."/".$object);
      }
    }
    reset($objects);
    rmdir($dir);
  }
 }
?>

Faites essayer le code ci-dessus sur php.net

Travaille bien pour moi


0

Pour les fenêtres:

system("rmdir ".escapeshellarg($path) . " /s /q");

0

Comme la solution de Playnox, mais avec l'élégant DirectoryIterator intégré:

function delete_directory($dirPath){
 if(is_dir($dirPath)){
  $objects=new DirectoryIterator($dirPath);
   foreach ($objects as $object){
    if(!$object->isDot()){
     if($object->isDir()){
      delete_directory($object->getPathname());
     }else{
      unlink($object->getPathname());
     }
    }
   }
   rmdir($dirPath);
  }else{
   throw new Exception(__FUNCTION__.'(dirPath): dirPath is not a directory!');
  }
 }

0

Je ne me souviens pas d'où j'ai copié cette fonction, mais il semble qu'elle ne soit pas répertoriée et qu'elle fonctionne pour moi

function rm_rf($path) {
    if (@is_dir($path) && is_writable($path)) {
        $dp = opendir($path);
        while ($ent = readdir($dp)) {
            if ($ent == '.' || $ent == '..') {
                continue;
            }
            $file = $path . DIRECTORY_SEPARATOR . $ent;
            if (@is_dir($file)) {
                rm_rf($file);
            } elseif (is_writable($file)) {
                unlink($file);
            } else {
                echo $file . "is not writable and cannot be removed. Please fix the permission or select a new path.\n";
            }
        }
        closedir($dp);
        return rmdir($path);
    } else {
        return @unlink($path);
    }
}

0

Simple et facile...

$dir ='pathtodir';
if (is_dir($dir)) {
  foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path)) as $filename) {
    if ($filename->isDir()) continue;
    unlink($filename);
  }
  rmdir($dir);
}


0

Si vous n'êtes pas sûr, étant donné que le chemin d'accès est un répertoire ou un fichier, vous pouvez utiliser cette fonction pour supprimer le chemin

function deletePath($path) {
        if(is_file($path)){
            unlink($path);
        } elseif(is_dir($path)){
            $path = (substr($path, -1) !== DIRECTORY_SEPARATOR) ? $path . DIRECTORY_SEPARATOR : $path;
            $files = glob($path . '*');
            foreach ($files as $file) {
                deleteDirPath($file);
            }
            rmdir($path);
        } else {
            return false;
        }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.