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.