PHP에서 디렉토리와 그 전체 내용 (파일 + 하위 디렉토리)을 재귀 적으로 삭제하려면 어떻게합니까?


답변:


207

매뉴얼 페이지의 사용자 제공 섹션 rmdir에는 적절한 구현 이 포함되어 있습니다.

 function rrmdir($dir) { 
   if (is_dir($dir)) { 
     $objects = scandir($dir);
     foreach ($objects as $object) { 
       if ($object != "." && $object != "..") { 
         if (is_dir($dir. DIRECTORY_SEPARATOR .$object) && !is_link($dir."/".$object))
           rrmdir($dir. DIRECTORY_SEPARATOR .$object);
         else
           unlink($dir. DIRECTORY_SEPARATOR .$object); 
       } 
     }
     rmdir($dir); 
   } 
 }

1
@The Pixel Developer-나는 그것을 보여주는 답변 을 추가 했습니다 .
salathe

2
누군가가 같은 질문에 대해 나에게 준 솔루션을 확인하십시오. glob가 더 잘 작동하는 것 같습니다 : stackoverflow.com/questions/11267086/…
NoodleOfDeath 17:09에

is_dir재귀 된 각 디렉토리마다 두 번 호출합니다 . 인수가 심볼릭 링크 인 경우, 심볼릭 링크를 삭제하는 대신 원하는대로 이어질 수도 있습니다. 어쨌든 그것은 그렇지 rm -rf않습니다.
블라디미르 판 텔레 예프

116

Pixel 개발자의 의견을 바탕으로 SPL을 사용하는 스 니펫은 다음과 같습니다.

$files = new RecursiveIteratorIterator(
    new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
    RecursiveIteratorIterator::CHILD_FIRST
);

foreach ($files as $fileinfo) {
    $todo = ($fileinfo->isDir() ? 'rmdir' : 'unlink');
    $todo($fileinfo->getRealPath());
}

rmdir($dir);

참고 : 온 전성 검사 는 없으며 PHP 5.3.0의 FilesystemIterator에 도입 된 SKIP_DOTS 플래그를 사용합니다. 물론 / 일 $todo수 있습니다 . 중요한 점은 부모 (폴더)보다 먼저 자식 (파일)을 반복하는 데 사용됩니다.ifelseCHILD_FIRST


SKIP_DOTSPHP 5.3에서만 소개 되었습니까? 어디서 봤어?
Alix Axel

감사합니다. 또한 : getPathname()대신 메소드를 사용해서는 안됩니다 getRealPath().
Alix Axel

3
이 솔루션은 잘 작동하지만 디렉토리를 제외한 모든 것을 삭제합니다 (빈 여부에 관계없이). rmdir($dir)스크립트 끝에 가 있어야합니다 .
laurent

3
여기서 동일한 기능이며 , 풀린 문서 차단과 부합 제작 rmdir()하고 unlink(), 예와 중단 및 E_WARNING반환 true하거나 false나타내는 성공.
mindplay.dk

2
@dbf 아니오 FilesystemIterator, 재귀 반복자가 아닙니다.
salathe

17

경로의 모든 파일과 폴더를 삭제합니다.

function recurseRmdir($dir) {
  $files = array_diff(scandir($dir), array('.','..'));
  foreach ($files as $file) {
    (is_dir("$dir/$file")) ? recurseRmdir("$dir/$file") : unlink("$dir/$file");
  }
  return rmdir($dir);
}

1
rm -rf /== recurseRmdir('/'):)
Aaron Esau

5
이것은 symlink 안전하지 않습니다! is_dir 후에도 isis_link인지 확인하기 위해 온 전성 검사가 필요합니다. 그렇지 않으면 외부 폴더로 심볼릭 링크되어 삭제되고 이것이 보안 허점으로 간주 될 수 있기 때문입니다. 그래서 당신은 변경해야합니다 is_dir("$dir/$file")is_dir("$dir/$file") && !is_link("$dir/$file")
키라 M. Backes

13

* nix의 경우 shell_execfor rm -R또는 DEL /S folder_nameWindows 를 사용할 수 있습니다 .


2
방법에 대한 DEL /S folder_nameWindows 용
ankitjaininfo

@Gordon RMDIR /S /Q folder_name은 나를 위해 일한 것입니다
Brian Leishman

2
exec 명령에 사용자 입력이없는 한 @ WiR3D가 좋습니다. 예 :exec('rm -rf ' . __DIR__ . '/output/*.log');
Brian Hannay

5
<?php

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use SplFileInfo;

# http://stackoverflow.com/a/3352564/283851
# https://gist.github.com/XzaR90/48c6b615be12fa765898

# Forked from https://gist.github.com/mindplay-dk/a4aad91f5a4f1283a5e2

/**
 * Recursively delete a directory and all of it's contents - e.g.the equivalent of `rm -r` on the command-line.
 * Consistent with `rmdir()` and `unlink()`, an E_WARNING level error will be generated on failure.
 *
 * @param string $source absolute path to directory or file to delete.
 * @param bool   $removeOnlyChildren set to true will only remove content inside directory.
 *
 * @return bool true on success; false on failure
 */
function rrmdir($source, $removeOnlyChildren = false)
{
    if(empty($source) || file_exists($source) === false)
    {
        return false;
    }

    if(is_file($source) || is_link($source))
    {
        return unlink($source);
    }

    $files = new RecursiveIteratorIterator
    (
        new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    //$fileinfo as SplFileInfo
    foreach($files as $fileinfo)
    {
        if($fileinfo->isDir())
        {
            if(rrmdir($fileinfo->getRealPath()) === false)
            {
                return false;
            }
        }
        else
        {
            if(unlink($fileinfo->getRealPath()) === false)
            {
                return false;
            }
        }
    }

    if($removeOnlyChildren === false)
    {
        return rmdir($source);
    }

    return true;
}

상당히 복잡한 제안 ;-)
Philipp

@ 필립 그래. 글쎄, 나는 그것이 작동하지 않기 때문에 gist.github.com/mindplay-dk/a4aad91f5a4f1283a5e2 에서 포크를 만들었 으므로 공유 할 수도 있다고 생각했습니다.
XzaR

문제가 있습니다. 모든 파일을 제거한 후에는 빈 폴더를 삭제하지 않습니다. 아래 답변으로 약간 수정 된 버전을 게시하십시오.
Vladislav Rastrusny 2016 년

@Vladislav Rastrusny 정말? 그것은 나를 위해 작동합니다. 읽기 전용 또는 다른 폴더가있을 수 있습니다.
XzaR


1

작동하고 열 살짜리가 읽을 수있는 '간단한'코드 :

function deleteNonEmptyDir($dir) 
{
   if (is_dir($dir)) 
   {
        $objects = scandir($dir);

        foreach ($objects as $object) 
        {
            if ($object != "." && $object != "..") 
            {
                if (filetype($dir . "/" . $object) == "dir")
                {
                    deleteNonEmptyDir($dir . "/" . $object); 
                }
                else
                {
                    unlink($dir . "/" . $object);
                }
            }
        }

        reset($objects);
        rmdir($dir);
    }
}

내가 한 모든 것은 확장 / 단순화 및 수정 (빈 디렉토리가 아닌 경우 작동하지 않음)입니다 .PHP에서 비어 있지 않은 모든 폴더를 재귀 적으로 제거하는 방법은 무엇입니까?


1

@Artefacto의 솔루션 수정 된 오타 수정 및 코드가 비어 있고 비어 있지 않은 디렉토리와 비어 있지 않은 디렉토리 모두에서 작동합니다.

  function recursive_rmdir($dir) { 
    if( is_dir($dir) ) { 
      $objects = array_diff( scandir($dir), array('..', '.') );
      foreach ($objects as $object) { 
        $objectPath = $dir."/".$object;
        if( is_dir($objectPath) )
          recursive_rmdir($objectPath);
        else
          unlink($objectPath); 
      } 
      rmdir($dir); 
    } 
  }

1

100 % 작업 솔루션

public static function rmdir_recursive($directory, $delete_parent = null)
  {
    $files = glob($directory . '/{,.}[!.,!..]*',GLOB_MARK|GLOB_BRACE);
    foreach ($files as $file) {
      if (is_dir($file)) {
        self::rmdir_recursive($file, 1);
      } else {
        unlink($file);
      }
    }
    if ($delete_parent) {
      rmdir($directory);
    }
  }

0

이 같은?

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

왜 그런지 설명 할 수는 없지만 저에게는 효과가 없었습니다. 비어 있지 않은 폴더를 계속 삭제하려고했습니다. 위의 두 번째 대답은 잘 작동했습니다.
laurent

1
@ buggy3 어떤 코드를 언급하고 있습니까? 링크는 단순히이 질문 페이지로 연결됩니다.
cgogolin

0

glob () 함수를 사용한 예제입니다 . 도트로 시작하는 파일을 포함하여 모든 파일과 폴더를 재귀 적으로 삭제합니다.

delete_all( 'folder' );

function delete_all( $item ) {
    if ( is_dir( $item ) ) {
        array_map( 'delete_all', array_diff( glob( "$item/{,.}*", GLOB_BRACE ), array( "$item/.", "$item/.." ) ) );
        rmdir( $item );
    } else {
        unlink( $item );
    }
};

나는 함께 갔다system('rm -fr folder')
Itay Moav -Malimovka

0

unlinkr 함수는 스크립트 자체를 삭제하지 않도록하여 지정된 경로의 모든 폴더와 파일을 재귀 적으로 삭제합니다.

function unlinkr($dir, $pattern = "*") {
    // find all files and folders matching pattern
    $files = glob($dir . "/$pattern"); 

    //interate thorugh the files and folders
    foreach($files as $file){ 
    //if it is a directory then re-call unlinkr function to delete files inside this directory     
        if (is_dir($file) and !in_array($file, array('..', '.')))  {
            echo "<p>opening directory $file </p>";
            unlinkr($file, $pattern);
            //remove the directory itself
            echo "<p> deleting directory $file </p>";
            rmdir($file);
        } else if(is_file($file) and ($file != __FILE__)) {
            // make sure you don't delete the current script
            echo "<p>deleting file $file </p>";
            unlink($file); 
        }
    }
}

이 스크립트를 배치 한 모든 파일과 폴더를 삭제하려면 다음과 같이 호출하십시오.

//get current working directory
$dir = getcwd();
unlinkr($dir);

PHP 파일 만 삭제하려면 다음과 같이 호출하십시오.

unlinkr($dir, "*.php");

다른 경로를 사용하여 파일을 삭제할 수도 있습니다

unlinkr("/home/user/temp");

home / user / temp 디렉토리의 모든 파일이 삭제됩니다.


0

이 코드를 사용합니다 ...

 function rmDirectory($dir) {
        foreach(glob($dir . '/*') as $file) {
            if(is_dir($file))
                rrmdir($file);
            else
                unlink($file);
        }
        rmdir($dir);
    }

이건 ...

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

재귀입니까?
Martin Tournoij

0

테스트 실행을 마치면 클래스 의 #unlink#rmdir 에서 #제거하십시오 .

<?php 
class RMRFiles {

        function __construct(){
        }

    public function recScan( $mainDir, $allData = array() )
    {

    // hide files
    $hidefiles = array(
    ".",
    "..") ;

    //start reading directory
    $dirContent = scandir( $mainDir ) ;

        //cycle through
        foreach ( $dirContent as $key => $content )
        {
            $path = $mainDir . '/' . $content ;

            // if is readable / file
            if ( ! in_array( $content, $hidefiles ) )
            {
            if ( is_file( $path ) && is_readable( $path ) )
            {
            #delete files within directory
            #unlink($path);
            $allData['unlink'][] = $path ;
            }

            // if is readable / directory
            else
            if ( is_dir( $path ) && is_readable( $path ) )
            {
            /*recursive*/
            $allData = $this->recScan( $path, $allData ) ;

            #finally remove directory
            $allData['rmdir'][]=$path;
            #rmdir($path);
            }
            }
        }

    return $allData ;

    }

}

header("Content-Type: text/plain");

/* Get absolute path of the running script 
Ex : /home/user/public_html/   */
define('ABPATH', dirname(__file__) . '/'); 

/* The folder where we store cache files 
Ex: /home/user/public_html/var/cache   */
define('STOREDIR','var/cache'); 

$rmrf = new RMRFiles();
#here we delete folder content files & directories
print_r($rmrf->recScan(ABPATH.STOREDIR));
#finally delete scanned directory ? 
#rmdir(ABPATH.STOREDIR);

?>

0
<?php

/**
 * code by Nk (nk.have.a@gmail.com)
 */

class filesystem
{
    public static function remove($path)
    {
        return is_dir($path) ? rmdir($path) : unlink($path);
    }

    public static function normalizePath($path)
    {
        return $path.(is_dir($path) && !preg_match('@/$@', $path) ? '/' : '');      
    }

    public static function rscandir($dir, $sort = SCANDIR_SORT_ASCENDING)
    {
        $results = array();

        if(!is_dir($dir))
        return $results;

        $dir = self::normalizePath($dir);

        $objects = scandir($dir, $sort);

        foreach($objects as $object)
        if($object != '.' && $object != '..')
        {
            if(is_dir($dir.$object))
            $results = array_merge($results, self::rscandir($dir.$object, $sort));
            else
            array_push($results, $dir.$object);
        }

        array_push($results, $dir);

        return $results;
    }

    public static function rrmdir($dir)
    {
        $files = self::rscandir($dir);

        foreach($files as $file)
        self::remove($file);

        return !file_exists($dir);
    }
}

?>

cleanup.php :

<?php

/* include.. */

filesystem::rrmdir('/var/log');
filesystem::rrmdir('./cache');

?>

0

다른 모든 답변은 함수에 주어진 경로가 항상 디렉토리라고 가정합니다. 이 변종은 단일 파일뿐만 아니라 디렉토리를 제거합니다.

/**
 * Recursively delete a file or directory.  Use with care!
 *
 * @param string $path
 */
function recursiveRemove($path) {
    if (is_dir($path)) {
        foreach (scandir($path) as $entry) {
            if (!in_array($entry, ['.', '..'])) {
                recursiveRemove($path . DIRECTORY_SEPARATOR . $entry);
            }
        }
        rmdir($path);
    } else {
        unlink($path);
    }
}

0

DirectoryIterator 및 재귀를 올바르게 사용 :

function deleteFilesThenSelf($folder) {
    foreach(new DirectoryIterator($folder) as $f) {
        if($f->isDot()) continue; // skip . and ..
        if ($f->isFile()) {
            unlink($f->getPathname());
        } else if($f->isDir()) {
            deleteFilesThenSelf($f->getPathname());
        }
    }
    rmdir($folder);
}

-1

방금 StackOverflow 토론 에서이 코드를 만들었습니다. 아직 Linux 환경에서 테스트하지 않았습니다. 파일이나 디렉토리를 완전히 삭제하기 위해 만들어졌습니다.

function splRm(SplFileInfo $i)
{
    $path = $i->getRealPath();

    if ($i->isDir()) {
        echo 'D - ' . $path . '<br />';
        rmdir($path);
    } elseif($i->isFile()) {
        echo 'F - ' . $path . '<br />';
        unlink($path);
    }
}

function splRrm(SplFileInfo $j)
{
    $path = $j->getRealPath();

    if ($j->isDir()) {
        $rdi = new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS);
        $rii = new RecursiveIteratorIterator($rdi, RecursiveIteratorIterator::CHILD_FIRST);
        foreach ($rii as $i) {
            splRm($i);
        }
    }
    splRm($j);

}

splRrm(new SplFileInfo(__DIR__.'/../dirOrFileName'));

-1
function rmdir_recursive( $dirname ) {

    /**
     * FilesystemIterator and SKIP_DOTS
     */

    if ( class_exists( 'FilesystemIterator' ) && defined( 'FilesystemIterator::SKIP_DOTS' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname, FilesystemIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * RecursiveDirectoryIterator and SKIP_DOTS
     */

    if ( class_exists( 'RecursiveDirectoryIterator' ) && defined( 'RecursiveDirectoryIterator::SKIP_DOTS' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname, RecursiveDirectoryIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * RecursiveIteratorIterator and RecursiveDirectoryIterator
     */

    if ( class_exists( 'RecursiveIteratorIterator' ) && class_exists( 'RecursiveDirectoryIterator' ) ) {

        if ( !is_dir( $dirname ) ) {
            return false;
        }

        foreach( new RecursiveIteratorIterator( new RecursiveDirectoryIterator( $dirname ), RecursiveIteratorIterator::CHILD_FIRST ) as $path ) {
            if ( in_array( $path->getFilename(), array( '.', '..' ) ) ) {
                continue;
            }
            $path->isDir() ? rmdir( $path->getPathname() ) : unlink( $path->getRealPath() );
        }

        return rmdir( $dirname );

    }

    /**
     * Scandir Recursive
     */

    if ( !is_dir( $dirname ) ) {
        return false;
    }

    $objects = scandir( $dirname );

    foreach ( $objects as $object ) {
        if ( $object === '.' || $object === '..' ) {
            continue;
        }
        filetype( $dirname . DIRECTORY_SEPARATOR . $object ) === 'dir' ? rmdir_recursive( $dirname . DIRECTORY_SEPARATOR . $object ) : unlink( $dirname . DIRECTORY_SEPARATOR . $object );
    }

    reset( $objects );
    rmdir( $dirname );

    return !is_dir( $dirname );

}

-1

@XzaR 솔루션의 수정 된 변형. 모든 파일이 폴더에서 삭제되면 빈 폴더를 제거하고 오류시 false를 반환하는 대신 예외를 발생시킵니다.

function recursivelyRemoveDirectory($source, $removeOnlyChildren = true)
{
    if (empty($source) || file_exists($source) === false) {
        throw new Exception("File does not exist: '$source'");
    }

    if (is_file($source) || is_link($source)) {
        if (false === unlink($source)) {
            throw new Exception("Cannot delete file '$source'");
        }
    }

    $files = new RecursiveIteratorIterator(
        new RecursiveDirectoryIterator($source, RecursiveDirectoryIterator::SKIP_DOTS),
        RecursiveIteratorIterator::CHILD_FIRST
    );

    foreach ($files as $fileInfo) {
        /** @var SplFileInfo $fileInfo */
        if ($fileInfo->isDir()) {
            if ($this->recursivelyRemoveDirectory($fileInfo->getRealPath()) === false) {
                throw new Exception("Failed to remove directory '{$fileInfo->getRealPath()}'");
            }
            if (false === rmdir($fileInfo->getRealPath())) {
                throw new Exception("Failed to remove empty directory '{$fileInfo->getRealPath()}'");
            }
        } else {
            if (unlink($fileInfo->getRealPath()) === false) {
                throw new Exception("Failed to remove file '{$fileInfo->getRealPath()}'");
            }
        }
    }

    if ($removeOnlyChildren === false) {
        if (false === rmdir($source)) {
            throw new Exception("Cannot remove directory '$source'");
        }
    }
}

-1
function deltree_cat($folder)
{
    if (is_dir($folder))
    {
             $handle = opendir($folder);
             while ($subfile = readdir($handle))
             {
                     if ($subfile == '.' or $subfile == '..') continue;
                     if (is_file($subfile)) unlink("{$folder}/{$subfile}");
                     else deltree_cat("{$folder}/{$subfile}");
             }
             closedir($handle);
             rmdir ($folder);
     }
     else
     {
        unlink($folder);
     }
}

1
이미 수락 된 질문을 포함하여 많은 답변이있는 이전 질문에 답변하는 경우 코드뿐만 아니라 답변에 어떤 가치가 추가되는지에 대한 설명을 게시해야합니다. 코드 전용 답변은 일반적으로 눈에 띄지 만 특히이 경우에는 찡그립니다.
자레드 스미스

이 답변에 투표하고 답변을 수락했습니다. 이것은 내 벤치 마크 체크에서 (하지 않고, 나쁘지 않다 unlink, rmdir) opendir+의 readdir작업을 더 빨리 scandir그리고 RecursiveDirectoryIterator이 모든 것보다 적은 메모리를 사용한다. 먼저 폴더를 제거하려면 closedir이 문제가 발생했습니다. 이 답변에 감사드립니다.
vee
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.