Удалить каталог с файлами в нем? - PullRequest
211 голосов
/ 28 июля 2010

Интересно, как проще всего удалить каталог со всеми его файлами?

Я использую rmdir(PATH . '/' . $value); для удаления папки, однако, если в ней есть файлы, я просто не могу удалить ее.

Ответы [ 31 ]

332 голосов
/ 28 июля 2010

В настоящее время доступно как минимум два варианта.

  1. Перед удалением папки удалите все ее файлы и папки (а это означает рекурсию!). Вот пример:

    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. И если вы используете 5.2+, вы можете использовать RecursiveIterator, чтобы сделать это без необходимости делать рекурсию самостоятельно:

    $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);
    
174 голосов
/ 17 октября 2014

Я обычно использую это для удаления всех файлов в папке:

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

И тогда вы можете сделать

rmdir($dirname);
75 голосов
/ 28 июля 2010

Какой самый простой способ удалить каталог со всеми его файлами в нем?

system("rm -rf ".escapeshellarg($dir));
46 голосов
/ 31 декабря 2011

Короткая функция, которая выполняет работу:

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

Я использую ее в классе Utils следующим образом:

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

С большой силой приходит большая ответственность: Когда вы вызываете эту функцию с пустым значением, она удалит файлы, начинающиеся с root (/).В качестве гарантии вы можете проверить, если путь пуст:

function deleteDir($path) {
    if (empty($path)) { 
        return false;
    }
    return is_file($path) ?
            @unlink($path) :
            array_map(__FUNCTION__, glob($path.'/*')) == @rmdir($path);
}
19 голосов
/ 22 ноября 2012

Это более короткая версия прекрасно работает для меня

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 голосов
/ 26 января 2013

Как видно из наиболее популярных комментариев на странице руководства PHP о rmdir() (см. http://php.net/manual/es/function.rmdir.php), glob(), функция не возвращает скрытые файлы. scandir() предоставляется в качестве альтернативы, решающей эту проблему.*

Алгоритм, описанный там (который работал как брелок в моем случае):

<?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); 
    } 
?>
13 голосов
/ 18 мая 2015

Вы можете использовать Файловую систему Symfony ( код ):

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

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

Однако я не смог удалить некоторые сложные структуры каталогов с помощью этого метода, поэтому сначала вы должны попробовать его, чтобы убедиться, что он работает правильно.


Я мог бы удалить указанную структуру каталогов, используя конкретную реализацию Windows:

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


И просто для полноты, вот мой старый код:

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);
}
8 голосов
/ 23 февраля 2013

Здесь у вас есть одна приятная и простая рекурсия для удаления всех файлов в исходной папке, включая эту:

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

}

Функция основана на рекурсии, выполненной для копирования каталога. Вы можете найти эту функцию здесь: Скопируйте все содержимое одного каталога в другой, используя php

4 голосов
/ 04 января 2017

Функция Glob не возвращает скрытые файлы, поэтому scandir может быть более полезен при попытке рекурсивного удаления дерева.

<?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);
  }
?>
3 голосов
/ 26 июля 2012

Я предпочитаю это, потому что он по-прежнему возвращает TRUE, если он успешен, и FALSE, если он терпит неудачу, а также предотвращает ошибку, при которой пустой путь может попытаться удалить все из '/ *' !!:

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