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.

mat
la source
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);
alcuadrado
la source
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);
user3033886
la source
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));
Votre bon sens
la source
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);
}
Blaise
la source
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); 
    } 
?>
Latorre allemand
la source
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);
    }
}
Playnox
la source
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);
}
Gras Double
la source
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

Tommz
la source
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 !!)

T.Todua
la source
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);
}
adrian
la source
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);
  }
?>
bougeoir
la source
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);
        }
    }
}
Bablu Ahmed
la source
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);
}
Matt Connolly
la source
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);
user701152
la source
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);
}
Alan Trewartha
la source
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;
}
Christopher Smit
la source
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);
        }
    }
}
K-Gun
la source
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);
}
police du karma
la source
2

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

realmag777
la source
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)

PP2000
la source
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()
Phil Meadows
la source
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;
}
Tarik
la source
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);
    }
}
José Veríssimo
la source
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

Gaurang
la source
0

Pour les fenêtres:

system("rmdir ".escapeshellarg($path) . " /s /q");
Mylo
la source
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!');
  }
 }
Matthew Slyman
la source
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);
    }
}
dav
la source
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);
}
Newtron
la source
0

Et ça?

function Delete_Directory($Dir) 
{
  if(is_dir($Dir))
  {
      $files = glob( $Dir . '*', GLOB_MARK ); //GLOB_MARK adds a slash to directories returned

      foreach( $files as $file )
      {
          Delete_Directory( $file );      
      }
      if(file_exists($Dir))
      {
          rmdir($Dir);
      }
  } 
  elseif(is_file($Dir)) 
  {
     unlink( $Dir );  
  }
}

Réfrence: https://paulund.co.uk/php-delete-directory-and-files-in-directory

Mohamad Hamouday
la source
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;
        }
}
Jay padaliya
la source