Eliminare la directory con i file in essa contenuti?


246

Mi chiedo, qual è il modo più semplice per eliminare una directory con tutti i suoi file?

Sto usando rmdir(PATH . '/' . $value);per eliminare una cartella, tuttavia, se ci sono file al suo interno, semplicemente non posso eliminarlo.



2
sì, ho risposto esattamente a quella domanda.
— timdev,

Voglio solo notare. Ho creato più file e se durante il processo ottengono alcuni errori, è necessario eliminare i file precedentemente creati. Quando fclose($create_file);hai creato i file , hai dimenticato di usare e quando cancellati, ho ottenuto Warning: unlink(created_file.xml): Permission denied in.... Quindi per evitare tali errori è necessario chiudere i file creati.
— Andris,

Risposte:


382

Ci sono almeno due opzioni disponibili al giorno d'oggi.

  1. Prima di eliminare la cartella, eliminare tutti i suoi file e cartelle (e questo significa ricorsione!). Ecco un esempio:

    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. E se stai usando 5.2+ puoi usare un RecursiveIterator per farlo senza implementare tu stesso la ricorsione:

    $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
La tua seconda implementazione è alquanto pericolosa: non verifica la presenza di punti ( .e ..) ed elimina il percorso risolto, non quello effettivo.
— Alix Axel,

9
piccolo componente aggiuntivo :-) glob () non supporta file come .htaccess. Ho usato la funzione per cancellare le directory create da KCFinder (plugin CKEditor) che genera sia .htaccess che .thumbs (file + cartella). Invece ho usato la scandirfunzione per ottenere l'elenco delle cartelle. Assicurati di filtrare il '.' e '..' dall'elenco dei risultati.
— Joshua - Pendo,

25
DIRECTORY_SEPARATOR non è necessario quando si creano percorsi da inviare al sistema operativo. Windows accetterà anche barre. È utile soprattutto per explode()creare un percorso preso dal sistema operativo. alanhogan.com/tips/php/directory-separator-not-necessary
— ReactiveRaven

5
Oltre a @Alix Axel Usando qui [SplFileInfo :: getRealPath ()] ( php.net/manual/en/splfileinfo.getrealpath.php ) non è una buona idea. Questo metodo espande tutti i collegamenti simbolici, ciò significa che verrà eliminato un file reale da qualche parte anziché un collegamento simbolico dalla directory di destinazione. In alternativa, è necessario utilizzare SplFileInfo :: getPathname ().
— Vijit,

2
Sono d'accordo con @Vijit, utilizzare getPathname () invece di getRealPath (). Fa la stessa cosa senza cancellare più di quello che ti aspetti se vengono trovati collegamenti simbolici.
— JoeMoe1984,

196

In genere lo uso per eliminare tutti i file in una cartella:

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

E poi puoi farlo

rmdir($dirname);

27
Questo non elimina le cartelle in modo ricorsivo; funziona solo se la cartella contiene solo file regolari, tutti con estensioni di file.
— mgnb,

5
Se non è necessaria alcuna ricorsione, questa è la risposta migliore e più semplice finora. Grazie!
— Eisbehr,

2
Per rimuovere tutti i file da una cartella, non solo quelli con estensioni, utilizzare glob nel modo seguente: array_map('unlink', glob("$dirname/*"));Ciò non consente comunque di eliminare le directory nidificate nella cartella.
— kremuwa,

Nota che questo rimuoverà anche i file punto (nascosti).
— BadHorsie,

84

qual è il modo più semplice per eliminare una directory con tutti i suoi file?

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

33
Spero tu non sia serio. Cosa succede se $ dir è /
— The Pixel Developer il

108
@ Lo stesso identico a uno dei codici sopra. No?
— Il tuo senso comune,

7
Si noti che, a seconda di come $dirviene generato / fornito, potrebbe essere necessario eseguire alcune pre-elaborazioni aggiuntive per essere sicuri ed evitare bug. Ad esempio, se $dirpotrebbe contenere uno spazio senza punti o punto e virgola, potrebbero esserci effetti collaterali indesiderati. Questo non è il caso delle risposte che usano cose come rmdir()perché gestirà i caratteri speciali per te.
— Trott

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

2
@ThePixelDeveloper non dovresti preoccuparti di cancellare /, questo funzionerebbe solo se lounch lo script nella riga di comando come root, perché nel web tutto accade come utente apache
— Ben

49

Breve funzione che fa il lavoro:

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

Lo uso in una classe Utils come questa:

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);
    }
}

Da una grande potenza derivano grandi responsabilità : quando si chiama questa funzione con un valore vuoto, verranno eliminati i file a partire da root ( /). Come salvaguardia puoi verificare se il percorso è vuoto:

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

1
Quello statico non funziona perché $ this === NULL quando si chiama una funzione statica su una classe. Funzionerebbe se$this_func = array(__CLASS__, __FUNCTION__);
— Matt Connolly il

2
Qualcuno può spiegare la linea array_map($class_func, glob($path.'/*')) == @rmdir($path)? Immagino che ricorra attraverso le sottocartelle, ma cosa fa la parte == @rmdir? In che modo <array of booleans> == <boolean> restituisce la risposta? Verifica se ciascun valore di ritorno della ricorsione è uguale al valore booleano sulla destra?
— Arviman,

2
È un trucco unire due affermazioni in un'unica affermazione. Questo perché gli operatori ternari consentono una sola istruzione per argomento. array_map(...)rimuove tutti i file all'interno della directory, @rmdir(...)rimuove la directory stessa.
— Blaise,

3
Stai attento! Questa funzione non controlla se il percorso esiste davvero. Se passi un argomento vuoto, la funzione inizierà a eliminare i file a partire dalla radice! Aggiungi un controllo di integrità al tuo percorso prima di eseguire questa funzione.
— Tatu Ulmanen,

3
Alcune persone non hanno visto il commento di Tatu e sono state cancellate in /modo ricorsivo , quindi ho aggiunto una versione protetta al mio post.
— Blaise,

22

Come visto nel commento più votato sulla pagina di manuale di PHP su rmdir()(vedi http://php.net/manual/es/function.rmdir.php ), la glob()funzione non restituisce file nascosti. scandir()viene fornito come alternativa che risolve tale problema.

L'algoritmo qui descritto (che nel mio caso ha funzionato come un incantesimo) è:

<?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); 
    } 
?>

puoi spiegare is_dir ("$ dir / $ file") - non ha soddisfatto il parametro "$ dir / $ file"
— Igor L.

Cosa intendi? Verifica se la voce trovata in una directory ( $file) è una directory o un file. "$dir/$file"è lo stesso di $dir . "/" . $file.
— Latorre tedesco,

Onestamente non sapevo che potessi concatenare variabili come questa :) grazie
— Igor L.

18

Questa è una versione più breve funziona benissimo per me

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

Puoi usare il filesystem di Symfony ( codice ):

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

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

Tuttavia non sono riuscito a eliminare alcune strutture di directory complesse con questo metodo, quindi prima dovresti provarlo per assicurarti che funzioni correttamente.


Potrei eliminare la suddetta struttura di directory usando un'implementazione specifica di Windows:

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


E solo per completezza, ecco un mio vecchio codice:

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);
}

Grazie mille. Mi risparmia tempo.
— zarif khan,

"Non reinventare la ruota" . Grazie
— Kamafeather il

9

Qui hai una ricorsione piacevole e semplice per eliminare tutti i file nella directory di origine inclusa quella directory:

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 funzione si basa sulla ricorsione effettuata per la copia della directory. Puoi trovare quella funzione qui: copia l'intero contenuto di una directory in un'altra usando php


4

La migliore soluzione per me

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

codice:

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 RICORDA!
non passare VALORI VUOTI a qualsiasi funzione di eliminazione della directory !!! (esegui il backup sempre, altrimenti un giorno potresti avere DISASTER !!)


4

Che dire di questo:

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 funzione Glob non restituisce i file nascosti, quindi scandir può essere più utile quando si tenta di eliminare ricorsivamente un albero.

<?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

Puoi provare come segue:

/*
 * 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

Preferisco questo perché restituisce ancora VERO quando riesce e FALSO quando fallisce, e impedisce anche un bug in cui un percorso vuoto potrebbe tentare di eliminare tutto da '/ *' !!:

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

Voglio espandere la risposta di @alcuadrado con il commento di @Vijit per la gestione dei link simbolici. Innanzitutto, utilizza getRealPath (). Ma poi, se hai collegamenti simbolici che sono cartelle, fallirà perché proverà a chiamare rmdir su un collegamento, quindi hai bisogno di un controllo extra.

$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
Non ho abbastanza rappresentante per commentare direttamente la risposta.
— user701152

3

Utilizzando DirectoryIterator un equivalente di una risposta precedente ...

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

Questo funziona per me:

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

2

Qualcosa come questo?

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

2

Modifiche un po 'ridotte del codice di alcuadrado - globnon vedo i file con nome da punti come quelli, .htaccessquindi uso scandir e lo script si elimina da solo - controlla __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

Esempio per il server Linux: exec('rm -f -r ' . $cache_folder . '/*');


Di solito mi piace aggiungere un controllo di integrità su $ cache_folder prima di eseguire rm -rf per evitare costosi errori
— glifo

1

Elimina tutti i file nella cartella
array_map('unlink', glob("$directory/*.*"));
Elimina tutto. * - File nella cartella (senza: "." E "..")
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
Ora elimina la cartella stessa
rmdir($directory)


1

2 centesimi da aggiungere a QUESTA risposta sopra, il che è ottimo BTW

Dopo che la funzione glob (o simile) ha scansionato / letto la directory, aggiungi un condizionale per verificare che la risposta non sia vuota o invalid argument supplied for foreach()verrà lanciato un avviso. Così...

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

La mia funzione completa (come metodo oggetto):

    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

Ecco la soluzione che funziona perfettamente:

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

È possibile copiare gli helper YII

$ directory (stringa) - da eliminare in modo ricorsivo.

$ options (array) - per la rimozione della directory. Le opzioni valide sono: traverseSymlink: booleano, se anche i collegamenti simbolici alle directory devono essere attraversati. L' falseimpostazione predefinita è , il che significa che il contenuto della directory con collegamento simbolico non verrà eliminato. In quel caso predefinito verrà rimosso solo il collegamento simbolico.

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);
  }
 }
?>

Hai provato il codice obove da php.net

Lavora per me bene


0

Per windows:

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

0

Come la soluzione di Playnox, ma con l'elegante DirectoryIterator integrato:

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

Non ricordo da dove ho copiato questa funzione, ma sembra che non sia elencato e funzioni per me

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

Semplice e facile ...

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


0

Se non si è sicuri, Dato percorso è directory o file, è possibile utilizzare questa funzione per eliminare il percorso

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;
        }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.