Verzeichnis mit darin enthaltenen Dateien löschen?


245

Ich frage mich, wie man ein Verzeichnis mit all seinen Dateien am einfachsten löscht.

Ich verwende rmdir(PATH . '/' . $value);, um einen Ordner zu löschen. Wenn sich jedoch Dateien darin befinden, kann ich ihn einfach nicht löschen.



2
Ja, genau in dieser Frage beantwortet.
Timdev

Ich möchte nur zur Kenntnis nehmen. Ich habe mehrere Dateien erstellt. Wenn während des Vorgangs ein Fehler auftritt, müssen die zuvor erstellten Dateien gelöscht werden. Beim Erstellen von Dateien, vergessen zu verwenden fclose($create_file);und beim Löschen, bekam Warning: unlink(created_file.xml): Permission denied in.... Um solche Fehler zu vermeiden, müssen die erstellten Dateien geschlossen werden.
Andris

Antworten:


381

Heutzutage stehen mindestens zwei Optionen zur Verfügung.

  1. Löschen Sie vor dem Löschen des Ordners alle Dateien und Ordner (und dies bedeutet Rekursion!). Hier ist ein Beispiel:

    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. Und wenn Sie 5.2+ verwenden, können Sie einen RecursiveIterator verwenden, ohne die Rekursion selbst zu implementieren:

    $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
Ihre zweite Implementierung ist etwas gefährlich: Sie sucht nicht nach Punkten ( .und ..) und löscht den aufgelösten Pfad, nicht den tatsächlichen.
Alix Axel

9
kleines Add-On :-) glob () unterstützt keine Dateien wie .htaccess. Ich habe die Funktion verwendet, um Verzeichnisse zu löschen, die von KCFinder (CKEditor-Plugin) erstellt wurden und sowohl .htaccess als auch .thumbs (Datei + Ordner) generieren. Stattdessen habe ich die scandirFunktion verwendet, um die Ordnerliste zu erhalten. Stellen Sie einfach sicher, dass Sie das '.' und '..' Dateien aus der Ergebnisliste.
Joshua - Pendo

25
DIRECTORY_SEPARATOR ist nicht erforderlich, wenn Sie Pfade zum Senden an das Betriebssystem erstellen. Windows akzeptiert auch Schrägstriche. Es ist hauptsächlich nützlich, um explode()einen Pfad vom Betriebssystem aus zu finden. alanhogan.com/tips/php/directory-separator-not-necessary
ReactiveRaven

5
Zusätzlich zu @Alix Axel Die Verwendung von [SplFileInfo :: getRealPath ()] ( php.net/manual/en/splfileinfo.getrealpath.php ) ist hier keine gute Idee. Diese Methode erweitert alle symbolischen Links, dh es wird eine echte Datei von irgendwoher gelöscht, anstatt ein Symlink aus dem Zielverzeichnis. Sie sollten stattdessen SplFileInfo :: getPathname () verwenden.
Vijit

2
Ich stimme @Vijit zu, benutze getPathname () anstelle von getRealPath (). Es macht dasselbe, ohne mehr zu löschen, als Sie erwarten, wenn Symlinks gefunden werden.
JoeMoe1984

196

Ich benutze dies im Allgemeinen, um alle Dateien in einem Ordner zu löschen:

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

Und dann kannst du es tun

rmdir($dirname);

26
Dadurch werden Ordner nicht rekursiv gelöscht. Es funktioniert nur, wenn der Ordner nur reguläre Dateien enthält, die alle Dateierweiterungen haben.
mgnb

5
Wenn keine Rekursion erforderlich ist, ist dies die bisher beste und einfachste Antwort. Vielen Dank!
Eisbehr

2
Verwenden Sie glob folgendermaßen , um alle Dateien aus einem Ordner zu entfernen , nicht nur diejenigen mit Erweiterungen: Auf array_map('unlink', glob("$dirname/*"));diese Weise können Sie immer noch keine im Ordner verschachtelten Verzeichnisse löschen.
Kremuwa

Beachten Sie, dass dadurch auch (versteckte) Punktdateien entfernt werden.
BadHorsie

85

Was ist der einfachste Weg, ein Verzeichnis mit all seinen Dateien zu löschen?

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

33
Ich hoffe du meinst es nicht ernst. Was passiert, wenn $ dir /
The Pixel Developer

108
@Das gleiche wie bei jedem der oben genannten Codes. Ist es nicht?
Ihr gesunder Menschenverstand

7
Beachten Sie, dass Sie je $dirnach Generierung / Bereitstellung möglicherweise eine zusätzliche Vorverarbeitung durchführen müssen, um die Sicherheit zu gewährleisten und Fehler zu vermeiden. Wenn sich beispielsweise $direin nicht entkoppelter Raum oder ein Semikolon darin befindet, können unerwünschte Nebenwirkungen auftreten. Dies ist bei Antworten, die Dinge wie verwenden, nicht der Fall, rmdir()da sie die Sonderzeichen für Sie behandeln.
Trott

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

2
@ThePixelDeveloper Sie sollten sich keine Gedanken über das Löschen von / machen, dies würde nur funktionieren, wenn Sie das Skript in der Befehlszeile als root starten würden, da im Web alles als Apache-Benutzer geschieht
Ben

49

Kurze Funktion, die den Job macht:

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

Ich benutze es in einer Utils-Klasse wie dieser:

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

Mit großer Kraft geht eine große Verantwortung einher : Wenn Sie diese Funktion mit einem leeren Wert aufrufen, werden Dateien gelöscht, die mit root ( /) beginnen. Als Schutz können Sie überprüfen, ob der Pfad leer ist:

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

1
Die statische Funktion funktioniert nicht, weil $ this === NULL, wenn Sie eine statische Funktion für eine Klasse aufrufen. Es würde funktionieren, wenn$this_func = array(__CLASS__, __FUNCTION__);
Matt Connolly

2
Kann jemand die Zeile erklären array_map($class_func, glob($path.'/*')) == @rmdir($path)? Ich denke, er rekursiert durch die Unterordner, aber was macht der == @ rmdir-Teil? Wie gibt das <Array von Booleschen Werten> == <Boolescher Wert> die Antwort zurück? Prüft es, ob jeder Rückgabewert der Rekursion mit dem Booleschen Wert rechts übereinstimmt?
Arviman

2
Es ist ein Trick, zwei Anweisungen zu einer Anweisung zusammenzuführen. Dies liegt daran, dass ternäre Operatoren nur eine Anweisung pro Argument zulassen. array_map(...)Entfernt alle Dateien im Verzeichnis und @rmdir(...)das Verzeichnis selbst.
Blaise

3
Achtung! Diese Funktion prüft nicht, ob der Pfad wirklich existiert. Wenn Sie ein leeres Argument übergeben, beginnt die Funktion, Dateien ab dem Stammverzeichnis zu löschen! Fügen Sie Ihrem Pfad eine Überprüfung der Integrität hinzu, bevor Sie diese Funktion ausführen.
Tatu Ulmanen

3
Einige Leute haben Tatus Kommentar nicht gesehen und rekursiv gelöscht /, deshalb habe ich meinem Beitrag eine geschützte Version angehängt.
Blaise

22

Wie in den meisten Stimmen auf der PHP-Handbuchseite zu rmdir()(siehe http://php.net/manual/es/function.rmdir.php ) zu sehen ist, gibt die glob()Funktion keine versteckten Dateien zurück. scandir()wird als Alternative bereitgestellt, um dieses Problem zu lösen.

Der dort beschriebene Algorithmus (der in meinem Fall wie ein Zauber wirkte) ist:

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

Kannst du bitte erklären, dass is_dir ("$ dir / $ file") - nicht mit dem Parameter "$ dir / $ file" übereinstimmt
Igor L.

Was meinst du? Es wird geprüft, ob der in einem Verzeichnis ( $file) gefundene Eintrag ein Verzeichnis oder eine Datei ist. "$dir/$file"ist das gleiche wie $dir . "/" . $file.
Deutscher Latorre

Ich wusste ehrlich gesagt nicht, dass Sie Variablen wie diese verketten können :) thx
Igor L.

18

Dies ist eine kürzere Version, die für mich großartig funktioniert

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

Sie können das Dateisystem ( Code ) von Symfony verwenden :

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

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

Ich konnte jedoch einige komplexe Verzeichnisstrukturen mit dieser Methode nicht löschen. Versuchen Sie es daher zunächst, um sicherzustellen, dass sie ordnungsgemäß funktioniert.


Ich könnte diese Verzeichnisstruktur mit einer Windows-spezifischen Implementierung löschen:

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


Und der Vollständigkeit halber hier ein alter Code von mir:

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

Vielen Dank. Sie sparen meine Zeit.
Zarif Khan

"Das Rad nicht neu erfinden" . Vielen Dank
Kamafeather

9

Hier haben Sie eine schöne und einfache Rekursion zum Löschen aller Dateien im Quellverzeichnis einschließlich dieses Verzeichnisses:

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

}

Die Funktion basiert auf einer Rekursion zum Kopieren des Verzeichnisses. Diese Funktion finden Sie hier: Kopieren Sie den gesamten Inhalt eines Verzeichnisses mit PHP in ein anderes


4

Die beste Lösung für mich

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 ERINNERN SIE SICH!
Übergeben Sie keine leeren Werte an Funktionen zum Löschen von Verzeichnissen !!! (Sichern Sie sie immer, sonst könnten Sie eines Tages DISASTER bekommen !!)


4

Was ist damit:

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

Die Glob-Funktion gibt die versteckten Dateien nicht zurück, daher kann scandir nützlicher sein, wenn Sie versuchen, einen Baum rekursiv zu löschen.

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

Sie können Folgendes versuchen:

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

Ich bevorzuge dies, weil es immer noch TRUE zurückgibt, wenn es erfolgreich ist, und FALSE, wenn es fehlschlägt, und es verhindert auch einen Fehler, bei dem ein leerer Pfad versuchen könnte, alles aus '/ *' zu löschen !!:

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

Ich möchte die Antwort von @alcuadrado mit dem Kommentar von @Vijit zum Umgang mit Symlinks erweitern. Verwenden Sie zunächst getRealPath (). Wenn Sie jedoch Symlinks haben, bei denen es sich um Ordner handelt, schlägt dies fehl, da versucht wird, rmdir für einen Link aufzurufen. Sie benötigen daher eine zusätzliche Überprüfung.

$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
Ich habe nicht genug Repräsentanten, um die Antwort direkt zu kommentieren.
user701152

3

Verwenden von DirectoryIterator entspricht einer vorherigen Antwort…

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

Dieser funktioniert für mich:

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

2

Etwas wie das?

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

2

Kleine Änderung des Codes von Alcuadrado - globkeine Dateien mit Namen von Punkten wie z. .htaccessB. Scandir verwenden und Skript löscht sich selbst - überprüfen __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

Beispiel für den Linux-Server: exec('rm -f -r ' . $cache_folder . '/*');


Normalerweise füge ich vor dem Ausführen von rm -rf eine Überprüfung der Integrität von $ cache_folder hinzu, um kostspielige Fehler zu vermeiden
Glyphe

1

Alle Dateien im Ordner
array_map('unlink', glob("$directory/*.*"));
löschen Alle
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
löschen . * - Dateien im Ordner (ohne: "." Und "..") Löschen Sie nun den Ordner selbst
rmdir($directory)


1

2 Cent zu dieser Antwort oben hinzufügen , was übrigens großartig ist

Nachdem Ihre Glob-Funktion (oder eine ähnliche Funktion) das Verzeichnis gescannt / gelesen hat, fügen Sie eine Bedingung hinzu, um zu überprüfen, ob die Antwort nicht leer ist. invalid argument supplied for foreach()Andernfalls wird eine Warnung ausgegeben. So...

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

Meine volle Funktion (als Objektmethode):

    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

Hier ist die Lösung, die perfekt funktioniert:

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

Sie könnten die YII-Helfer kopieren

$ directory (string) - wird rekursiv gelöscht.

$ options (Array) - zum Entfernen des Verzeichnisses. Gültige Optionen sind: traverseSymlinks: boolean, ob auch Symlinks zu den Verzeichnissen durchlaufen werden sollen. Der Standardwert ist false, dass der Inhalt des verknüpften Verzeichnisses nicht gelöscht wird. In diesem Standardfall wird nur der Symlink entfernt.

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

Lassen Sie den obigen Code von php.net ausprobieren

Arbeite gut für mich


0

Für Windows:

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

0

Wie die Lösung von Playnox, jedoch mit dem eleganten integrierten DirectoryIterator:

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

Ich erinnere mich nicht, woher ich diese Funktion kopiert habe, aber es sieht so aus, als ob sie nicht aufgeführt ist und für mich funktioniert

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

Simpel und einfach...

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


0

Wenn Sie sich nicht sicher sind, ob der angegebene Pfad ein Verzeichnis oder eine Datei ist, können Sie mit dieser Funktion den Pfad löschen

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;
        }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.