Bagaimana cara menghapus direktori dan seluruh isinya secara rekursif (file + sub dir) di PHP?


Jawaban:


207

Bagian kontribusi pengguna di halaman manual rmdirberisi implementasi yang layak:

 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 - Saya menambahkan jawaban yang menunjukkan itu.
salathe

2
lihat solusi yang seseorang berikan kepada saya untuk pertanyaan yang sama: glob tampaknya bekerja lebih baik: stackoverflow.com/questions/11267086/…
NoodleOfDeath

Ini panggilan is_dirdua kali untuk setiap direktori berulang. Jika argumennya adalah symlink, ia juga mengikutinya alih-alih menghapus symlink, yang mungkin atau mungkin bukan yang Anda inginkan. Bagaimanapun, bukan itu yang rm -rfterjadi.
Vladimir Panteleev

116

Berdasarkan komentar Pengembang Pixel , cuplikan menggunakan SPL mungkin terlihat seperti:

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

Catatan: Itu tidak ada pengecekan kewarasan dan membuat penggunaan bendera SKIP_DOTS diperkenalkan dengan FilesystemIterator di PHP 5.3.0. Tentu saja, itu $todobisa menjadi if/ else. Poin penting adalah yang CHILD_FIRSTdigunakan untuk beralih pada anak-anak (file) terlebih dahulu sebelum orang tua mereka (folder).


SKIP_DOTShanya diperkenalkan di PHP 5.3? Di mana Anda melihat itu?
Alix Axel

Terima kasih. Juga: bukankah seharusnya Anda menggunakan getPathname()metode ini alih-alih getRealPath()?
Alix Axel

3
Solusi ini berfungsi dengan baik, namun menghapus semuanya ... kecuali direktori (apakah kosong atau tidak). Seharusnya ada rmdir($dir)di akhir skrip.
laurent

3
Berikut adalah fungsi yang sama yang terbuka, diblokir doc, dan dibuat konsisten dengan rmdir()dan unlink(), misalnya dibatalkan dengan E_WARNINGdan kembali trueatau falsemenunjukkan keberhasilan.
mindplay.dk

2
@ dbf tidak itu tidak akan, FilesystemIteratoritu bukan iterator rekursif.
salathe

17

Menghapus semua file dan folder di jalur.

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
Harap perhatikan bahwa ini bukan symlink safe! Anda memerlukan pemeriksaan kewarasan setelah is_dir juga untuk memeriksa apakah itu! Is_link, karena jika tidak, Anda dapat symlink ke folder eksternal yang kemudian dihapus dan ini dapat dianggap sebagai lubang keamanan. Jadi, Anda harus beralih is_dir("$dir/$file")keis_dir("$dir/$file") && !is_link("$dir/$file")
Kira M. Backes

13

Untuk * nix Anda dapat menggunakan shell_execfor rm -Ratau DEL /S folder_nameuntuk Windows.


2
bagaimana dengan DEL /S folder_nameuntuk Windows
ankitjaininfo

@ Gordon RMDIR /S /Q folder_nameadalah yang bekerja untuk saya
Brian Leishman

2
@ WiR3D selama perintah exec tidak mengandung input pengguna, Anda harus baik. Contoh: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;
}

Saran yang cukup rumit ;-)
Philipp

@ Pilip ya saya kira. Yah saya membuat garpu dari gist.github.com/mindplay-dk/a4aad91f5a4f1283a5e2 karena saya tidak membuatnya berfungsi jadi saya hanya berpikir saya mungkin juga membagikannya.
XzaR

Ada masalah. Itu tidak menghapus folder kosong setelah semua file dihapus. Posting versi yang sedikit dimodifikasi sebagai jawaban di bawah ini.
Vladislav Rastrusny

@Vladislav Rastrusny benar-benar? Ini bekerja untuk saya. Mungkin Anda memiliki folder dengan read-only atau sesuatu.
XzaR


1

kode 'sederhana' yang berfungsi dan dapat dibaca oleh anak berumur sepuluh tahun:

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

Harap dicatat bahwa semua yang saya lakukan adalah memperluas / menyederhanakan dan memperbaiki (tidak berfungsi untuk direktori yang tidak kosong) solusinya di sini: Di PHP bagaimana cara menghapus semua folder yang tidak kosong secara rekursif?


1

Solusi @Artefacto yang disempurnakan - kesalahan ketik yang diperbaiki dan kode yang disederhanakan, bekerja untuk direktori kosong && tidak kosong.

  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

Solusi kerja 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

Sesuatu seperti ini?

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

Saya tidak bisa menjelaskan mengapa tetapi itu tidak berhasil bagi saya. Itu terus berusaha menghapus folder yang tidak kosong. Jawaban kedua di atas bekerja dengan baik.
laurent

1
@ buggy3 Kode spesifik apa yang Anda maksud? Tautan ini hanya menghubungkan ke halaman pertanyaan ini.
cgogolin

0

Contoh dengan fungsi glob () . Ini akan menghapus semua file dan folder secara rekursif, termasuk file yang dimulai dengan titik.

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

Saya pergi dengansystem('rm -fr folder')
Itay Moav -Malimovka

0

fungsi unlinkr menghapus semua folder dan file di jalur yang diberikan secara rekursif dengan memastikan tidak menghapus skrip itu sendiri.

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

jika Anda ingin menghapus semua file dan folder tempat Anda menempatkan skrip ini, panggil sebagai berikut

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

jika Anda hanya ingin menghapus hanya file php lalu panggil sebagai berikut

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

Anda dapat menggunakan jalur lain untuk menghapus file juga

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

Ini akan menghapus semua file di direktori home / user / temp.


0

Saya menggunakan kode ini ...

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

atau yang ini ...

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

Apakah ini rekursif?
Martin Tournoij

0

Setelah Anda selesai menjalankan tes, hapus # dari #unlink dan #rmdir di kelas.

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

Tampaknya semua jawaban lain menganggap jalur yang diberikan ke fungsi selalu berupa direktori. Varian ini berfungsi untuk menghapus direktori dan juga file tunggal:

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

Menggunakan DirectoryIterator dan rekursi dengan benar:

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

Saya baru saja membuat kode ini, dari beberapa diskusi StackOverflow. Saya belum menguji lingkungan Linux. Itu dibuat untuk menghapus file atau direktori, sepenuhnya:

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

Varian yang dimodifikasi dari solusi @XzaR. Itu menghapus folder kosong, ketika semua file dihapus dari mereka dan itu melempar pengecualian daripada mengembalikan kesalahan palsu.

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
Jika Anda menjawab pertanyaan lama yang sudah memiliki sejumlah jawaban termasuk yang diterima, Anda perlu memposting penjelasan tentang nilai apa yang ditambahkan jawaban Anda, bukan hanya kode. Jawaban hanya kode disukai secara umum, tetapi terutama kasus ini.
Jared Smith

Saya memilih jawaban ini dan menerima jawaban. Ini tidak buruk, dari pemeriksaan benchmark saya (tanpa unlink, rmdir) opendir+ readdirbekerja lebih cepat scandirdan RecursiveDirectoryIteratorjuga menggunakan lebih sedikit memori daripada semua. Untuk menghapus folder saya harus closedirterlebih dahulu, saya terjebak pada ini. Terima kasih atas jawaban ini.
vee
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.