Рекурсивное удаление - PullRequest
       42

Рекурсивное удаление

4 голосов
/ 20 декабря 2010

У меня есть этот код для рекурсивного удаления файлов и каталогов. Работает нормально, но есть небольшая проблема. Если $ path = / var / www / foo /, он будет удалять все внутри foo, но не foo. Я тоже хочу удалить каталог foo. Любая идея?

public function delete($path) {
    if(!file_exists($path)) {
        throw new RecursiveDirectoryException('Directory doesn\'t exist.');
    }

    $directoryIterator = new DirectoryIterator($path);

    foreach($directoryIterator as $fileInfo) {
        $filePath = $fileInfo->getPathname();

        if(!$fileInfo->isDot()) {
            if($fileInfo->isFile()) {
                unlink($filePath);
            }
            else if($fileInfo->isDir()) {
                if($this->emptyDirectory($filePath)) {
                    rmdir($filePath);
                }
                else {
                    $this->delete($filePath);
                    rmdir($filePath);
                }
            }
        }
    }
}

Ответы [ 4 ]

12 голосов
/ 20 декабря 2010

Почему даже выполнять свои функции?

public function delete($path) {
    $it = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($path),
        RecursiveIteratorIterator::CHILD_FIRST
    );
    foreach ($it as $file) {
        if (in_array($file->getBasename(), array('.', '..'))) {
            continue;
        } elseif ($file->isDir()) {
            rmdir($file->getPathname());
        } elseif ($file->isFile() || $file->isLink()) {
            unlink($file->getPathname());
        }
    }
    rmdir($path);
}

Это работает, потому что RII::CHILD_FIRST перебирает дочерние элементы перед родительским элементом. Таким образом, к тому времени, когда он достигает каталога, он должен быть пустым.

Но настоящая ошибка связана с тем, где вы удаляете свои каталоги. Во внутренних каталогах вы делаете это в родительской итерации. Это означает, что ваш корневой каталог никогда не будет удален. Я бы предложил сделать это в локальной итерации удаления:

public function delete($path) {
    if(!file_exists($path)) {
        throw new RecursiveDirectoryException('Directory doesn\'t exist.');
    }

    $directoryIterator = new DirectoryIterator($path);

    foreach($directoryIterator as $fileInfo) {
        $filePath = $fileInfo->getPathname();
        if(!$fileInfo->isDot()) {
            if($fileInfo->isFile()) {
                unlink($filePath);
            } elseif($fileInfo->isDir()) {
                if($this->emptyDirectory($filePath)) {
                    rmdir($filePath);
                } else {
                    $this->delete($filePath);
                }
            }
        }
    }
    rmdir($path);
}

Обратите внимание на два изменения. Мы удаляем только пустые каталоги внутри итерации. Вызов $this->delete() для этого обработает удаление для вас. Второе изменение - это добавление окончательного rmdir в конце метода ...

3 голосов
/ 20 декабря 2010

Вам не хватает одного последнего rmdir.Вы можете либо позвонить после $this->delete($path) следующим образом:

$this->delete($path);
rmdir($path);

Или вы можете изменить foreach -loop следующим образом:

public function delete($path) {
    //snip

    foreach($directoryIterator as $fileInfo) {
        //snip
                else {
                    $this->delete($filePath);
                }
            }
        }
    }

    rmdir($path);
}

Кроме того, я надеюсь, что вы подтвердитекакие пути вы там получаете, если это видно пользователю (например, функция «Удалить все на моем веб-пространстве». Я имею в виду, вам будет очень весело, если кто-нибудь передаст туда /etc/.

0 голосов
/ 01 июля 2013

попробуйте

unset ($ directoryIterator);RmDir ($ Filepath);

0 голосов
/ 20 декабря 2010
function delete($path){
    if(!file_exists($path)) {
        throw new RecursiveDirectoryException('Directory doesn\'t exist.');
    }

    $directoryIterator = new DirectoryIterator($path);

    foreach($directoryIterator as $fileInfo) {
        $filePath = $fileInfo->getPathname();

        if(!$fileInfo->isDot()) {
            if($fileInfo->isFile()) {
                unlink($filePath);
            }
            else if($fileInfo->isDir()) {
                if($this->emptyDirectory($filePath)) {
                    rmdir($filePath);
                }
                else {
                    $this->delete($filePath);
                    rmdir($filePath);
                }
            }
        }
    }
    rmdir($path);
}

?

...