Hapus direktori dengan file di dalamnya?


246

Saya bertanya-tanya, apa cara termudah untuk menghapus direktori dengan semua file di dalamnya?

Saya menggunakan rmdir(PATH . '/' . $value);untuk menghapus folder, namun, jika ada file di dalamnya, saya tidak bisa menghapusnya.



2
ya, dijawab persis di pertanyaan itu.
timdev

Hanya ingin diperhatikan. Saya membuat banyak file dan jika selama proses mendapatkan beberapa kesalahan, maka perlu menghapus file yang dibuat sebelumnya. Saat membuat file, lupa menggunakan fclose($create_file);dan ketika menghapus, didapat Warning: unlink(created_file.xml): Permission denied in.... Jadi untuk menghindari kesalahan tersebut harus menutup file yang dibuat.
Andris

Jawaban:


382

Setidaknya ada dua opsi yang tersedia saat ini.

  1. Sebelum menghapus folder, hapus semua file dan foldernya (dan ini berarti rekursi!). Berikut ini sebuah contoh:

    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. Dan jika Anda menggunakan 5.2+ Anda dapat menggunakan RecursiveIterator untuk melakukannya tanpa menerapkan rekursi sendiri:

    $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
Implementasi kedua Anda agak berbahaya: tidak memeriksa titik ( .dan ..) dan menghapus jalur yang diselesaikan, bukan yang sebenarnya.
Alix Axel

9
sedikit add-on :-) glob () tidak mendukung file seperti .htaccess. Saya menggunakan fungsi ini untuk menghapus direktori yang dibuat oleh KCFinder (plugin CKEditor) yang menghasilkan .htaccess dan .thumbs (file + folder). Sebaliknya saya menggunakan scandirfungsi untuk mendapatkan daftar folder. Pastikan Anda memfilter '.' dan file '..' dari daftar hasil.
Joshua - Pendo

25
DIRECTORY_SEPARATOR tidak diperlukan saat Anda sedang membangun jalur untuk dikirim ke os. Windows akan menerima garis miring juga. Ini terutama berguna untuk explode()jalur yang diambil dari OS. alanhogan.com/tips/php/directory-separator-not-n perlu
ReactiveRaven

5
Selain @Alix Axel Menggunakan di sini [SplFileInfo :: getRealPath ()] ( php.net/manual/en/splfileinfo.getrealpath.php ) bukan ide yang baik. Metode ini memperluas semua tautan simbolik, yang berarti, akan menghapus file asli dari suatu tempat, bukan symlink dari direktori target. Anda harus menggunakan SplFileInfo :: getPathname () sebagai gantinya.
Vijit

2
Saya setuju dengan @Vijit, gunakan getPathname () alih-alih getRealPath (). Ia melakukan hal yang sama tanpa menghapus lebih dari yang Anda harapkan jika symlink ditemukan.
JoeMoe1984

196

Saya biasanya menggunakan ini untuk menghapus semua file dalam folder:

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

Dan kemudian Anda bisa melakukannya

rmdir($dirname);

26
Ini tidak menghapus folder secara rekursif; itu hanya berfungsi jika folder hanya memiliki file biasa di dalamnya, yang semuanya memiliki ekstensi file.
mgnb

5
Jika tidak diperlukan rekursi, ini adalah jawaban terbaik dan paling sederhana sejauh ini. Terima kasih!
eisbehr

2
Untuk menghapus semua file dari folder, tidak hanya yang memiliki ekstensi, gunakan glob dengan cara berikut: array_map('unlink', glob("$dirname/*"));Ini masih tidak memungkinkan Anda untuk menghapus direktori yang bersarang di folder.
kremuwa

Perhatikan bahwa ini juga akan menghapus file titik (tersembunyi).
BadHorsie

85

apa cara termudah untuk menghapus direktori dengan semua file di dalamnya?

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

33
Saya harap kamu tidak serius. Apa yang terjadi jika $ dir adalah /
Pengembang Pixel

108
@ Sama persis dengan salah satu kode di atas. Bukan?
Akal Sehat Anda

7
Perhatikan bahwa, tergantung bagaimana $dirdihasilkan / disediakan, Anda mungkin perlu melakukan beberapa pra-pemrosesan tambahan agar aman dan menghindari bug. Misalnya, jika $dirmungkin memiliki ruang yang tidak luput atau semi-kolon di dalamnya, maka mungkin ada efek samping yang tidak diinginkan. Ini tidak terjadi dengan jawaban yang menggunakan hal-hal seperti rmdir()karena itu akan menangani karakter khusus untuk Anda.
Trott

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

2
@ThePixelDeveloper Anda tidak perlu khawatir tentang menghapus /, ini hanya akan bekerja jika Anda akan lounch script di command line sebagai root, karena di web semuanya terjadi sebagai pengguna apache
Ben

49

Fungsi pendek yang melakukan pekerjaan:

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

Saya menggunakannya di kelas Utils seperti ini:

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

Dengan kekuatan besar datang tanggung jawab besar : Ketika Anda memanggil fungsi ini dengan nilai kosong, itu akan menghapus file mulai dari root ( /). Sebagai perlindungan, Anda dapat memeriksa apakah path kosong:

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

1
Yang statis tidak berfungsi karena $ this === NULL ketika Anda memanggil fungsi statis di kelas. Ini akan berhasil jika$this_func = array(__CLASS__, __FUNCTION__);
Matt Connolly

2
Bisakah seseorang menjelaskan kalimatnya array_map($class_func, glob($path.'/*')) == @rmdir($path)? Saya kira dia berulang melalui subfolder, tapi apa yang dilakukan bagian == @rmdir? Bagaimana <array booleans> == <boolean> mengembalikan jawabannya? Apakah ini memeriksa apakah setiap nilai pengembalian rekursi sama dengan boolean di sebelah kanan?
arviman

2
Ini adalah trik untuk menggabungkan dua pernyataan menjadi satu pernyataan. Ini karena operator ternary hanya mengizinkan satu pernyataan per argumen. array_map(...)menghapus semua file dalam direktori, @rmdir(...)menghapus direktori itu sendiri.
Blaise

3
Hati-hati! Fungsi ini tidak memeriksa apakah path benar-benar ada. Jika Anda melewatkan argumen kosong, fungsi akan mulai menghapus file mulai dari root! Tambahkan cek kewarasan ke jalur Anda sebelum Anda menjalankan fungsi ini.
Tatu Ulmanen

3
Beberapa orang tidak melihat komentar Tatu dan dihapus secara rekursif /, jadi saya menambahkan versi yang dilindungi ke posting saya.
Blaise

22

Seperti yang terlihat di komentar paling banyak pada halaman manual PHP tentang rmdir()(lihat http://php.net/manual/es/function.rmdir.php ), glob()fungsi tidak mengembalikan file tersembunyi. scandir()disediakan sebagai alternatif yang memecahkan masalah itu.

Algoritma yang dijelaskan di sana (yang bekerja seperti mantra dalam kasus saya) adalah:

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

bisakah Anda jelaskan is_dir ("$ dir / $ file") - tidak memenuhi parameter "$ dir / $ file"
Igor L.

Maksud kamu apa? Ia memeriksa apakah entri yang ditemukan di direktori ( $file) adalah direktori atau file. "$dir/$file"sama dengan $dir . "/" . $file.
Latorre Jerman

Jujur saya tidak tahu Anda dapat menggabungkan variabel seperti ini :) thx
Igor L.

18

Ini adalah versi yang lebih pendek

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

Anda dapat menggunakan Filesystem ( kode ) Symfony :

// composer require symfony/filesystem

use Symfony\Component\Filesystem\Filesystem;

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

Namun saya tidak bisa menghapus beberapa struktur direktori kompleks dengan metode ini, jadi pertama-tama Anda harus mencobanya untuk memastikan itu berfungsi dengan baik.


Saya bisa menghapus struktur direktori tersebut menggunakan implementasi spesifik Windows:

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


Dan hanya demi kelengkapan, berikut ini adalah kode lama saya:

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

Terima kasih banyak. Anda menghemat waktu saya.
zarif khan

"Jangan menemukan kembali roda" . Terima kasih
Kamafeather

9

Di sini Anda memiliki satu rekursi yang bagus dan sederhana untuk menghapus semua file dalam direktori sumber termasuk direktori itu:

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

}

Fungsi didasarkan pada rekursi yang dibuat untuk menyalin direktori. Anda dapat menemukan fungsi itu di sini: Salin seluruh isi direktori ke direktori lain menggunakan php


4

Solusi Terbaik untuk saya

my_folder_delete("../path/folder");

kode:

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 INGAT!
jangan berikan NILAI KOSONG ke fungsi penghapusan Direktori apa pun !!! (Cadangkan selalu, jika tidak suatu hari Anda mungkin akan BENCANA !!)


4

Bagaimana dengan ini:

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

Fungsi Glob tidak mengembalikan file yang disembunyikan, oleh karena itu scandir dapat lebih berguna, ketika mencoba menghapus pohon secara rekursif.

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

Anda dapat mencoba sebagai berikut:

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

Saya lebih suka ini karena masih mengembalikan BENAR ketika berhasil dan SALAH ketika gagal, dan itu juga mencegah bug di mana jalan kosong mungkin mencoba dan menghapus semuanya dari '/ *' !!:

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

Saya ingin memperluas jawaban oleh @alcuadrado dengan komentar oleh @Vijit untuk menangani symlink. Pertama, gunakan getRealPath (). Tetapi kemudian, jika Anda memiliki symlink yang merupakan folder, ia akan gagal karena akan mencoba dan memanggil rmdir pada tautan - jadi Anda perlu pemeriksaan tambahan.

$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
Saya tidak punya cukup perwakilan untuk mengomentari jawaban secara langsung.
user701152

3

Menggunakan DirectoryIterator setara dengan jawaban sebelumnya ...

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

Yang ini bekerja untuk saya:

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

2

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

2

Sedikit litle memodifikasi kode alcuadrado - globjangan melihat file dengan nama dari titik seperti .htaccessjadi saya menggunakan skandir dan skrip menghapus sendiri - centang __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

Contoh untuk server Linux: exec('rm -f -r ' . $cache_folder . '/*');


Saya biasanya ingin menambahkan cek kewarasan pada $ cache_folder sebelum menjalankan rm -rf untuk menghindari kesalahan yang mahal
glyph

1

Hapus semua file di Folder
array_map('unlink', glob("$directory/*.*"));
Hapus semua. * - File di Folder (tanpa: "." Dan "..")
array_map('unlink', array_diff(glob("$directory/.*),array("$directory/.","$directory/..")))
Sekarang hapus Folder itu sendiri
rmdir($directory)


1

2 sen untuk ditambahkan ke jawaban INI di atas, yang merupakan BTW yang bagus

Setelah fungsi gumpalan Anda (atau yang serupa) memindai / membaca direktori, tambahkan persyaratan untuk memeriksa respons tidak kosong, atau invalid argument supplied for foreach()peringatan akan dilemparkan. Begitu...

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

Fungsi lengkap saya (sebagai metode objek):

    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

Inilah solusi yang berfungsi sempurna:

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

Anda bisa menyalin pembantu YII

$ direktori (string) - untuk dihapus secara rekursif.

$ options (array) - untuk penghapusan direktori. Opsi yang valid adalah: traverseSymlinks: boolean, apakah symlink ke direktori juga harus dilalui. Defaults to false, artinya konten direktori yang disinkronkan tidak akan dihapus. Hanya symlink yang akan dihapus dalam kasus default itu.

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

Sudahkah Anda mencoba kode obove dari php.net

Bekerja untukku baik-baik saja


0

Untuk windows:

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

0

Seperti solusi Playnox, tetapi dengan DirectoryIterator bawaan yang elegan:

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

Saya tidak ingat dari mana saya menyalin fungsi ini, tetapi sepertinya itu tidak terdaftar dan berfungsi untuk saya

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

Sederhana dan Mudah ...

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


0

Jika Anda tidak yakin, Jalur yang diberikan adalah direktori atau file, maka Anda dapat menggunakan fungsi ini untuk menghapus jalur

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