From 4d47e8e3bcbb31435593de9d567723e5d87641bd Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 6 Jan 2014 20:20:15 +0100 Subject: added recursive delete function to io.php --- inc/io.php | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/inc/io.php b/inc/io.php index eff0279ac..30f34ad3c 100644 --- a/inc/io.php +++ b/inc/io.php @@ -400,6 +400,55 @@ function io_mkdir_p($target){ return 0; } +/** + * Recursively delete a directory + * + * @author Andreas Gohr + * @param string $path + * @param bool $removefiles defaults to false which will delete empty directories only + * @return bool + */ +function io_rmdir($path, $removefiles = false) { + if(!is_string($path) || $path == "") return false; + + if(is_dir($path) && !is_link($path)) { + $dirs = array(); + $files = array(); + + if(!$dh = @opendir($path)) return false; + while($f = readdir($dh)) { + if($f == '..' || $f == '.') continue; + + // collect dirs and files first + if(is_dir("$path/$f") && !is_link("$path/$f")) { + $dirs[] = "$path/$f"; + } else if($removefiles) { + $files[] = "$path/$f"; + } else { + return false; // abort when non empty + } + + } + closedir($dh); + + // now traverse into directories first + foreach($dirs as $dir) { + if(!io_rmdir($dir, $removefiles)) return false; // abort on any error + } + + // now delete files + foreach($files as $file) { + if(!@unlink($file)) return false; //abort on any error + } + + // remove self + return @rmdir($path); + } else if($removefiles) { + return @unlink($path); + } + return false; +} + /** * Creates a directory using FTP * -- cgit v1.2.3 From ebec603febbe7426fbb12cbb4fd3cb42128fcbf8 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 6 Jan 2014 20:58:38 +0100 Subject: added tests for io_rmdir --- _test/tests/inc/io_rmdir.test.php | 159 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 _test/tests/inc/io_rmdir.test.php diff --git a/_test/tests/inc/io_rmdir.test.php b/_test/tests/inc/io_rmdir.test.php new file mode 100644 index 000000000..9a122d111 --- /dev/null +++ b/_test/tests/inc/io_rmdir.test.php @@ -0,0 +1,159 @@ +assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + + // delete successfully + $this->assertTrue(io_rmdir($dir, false)); + + // check result + clearstatcache(); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + // same again with deletefiles + + // set up test dir + $dir = io_mktmpdir(); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + + // delete successfully + $this->assertTrue(io_rmdir($dir, true)); + + // check result + clearstatcache(); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + } + + + function test_empty_hierarchy(){ + // setup hierachy and test it exists + $dir = io_mktmpdir(); + $top = dirname($dir); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(io_mkdir_p("$dir/foo/bar/baz")); + $this->assertTrue(is_dir("$dir/foo/bar/baz")); + $this->assertTrue(io_mkdir_p("$dir/foobar/bar/baz")); + $this->assertTrue(is_dir("$dir/foobar/bar/baz")); + + // delete successfully + $this->assertTrue(io_rmdir($dir, false)); + + // check result + clearstatcache(); + $this->assertFalse(is_dir("$dir/foo/bar/baz")); + $this->assertFalse(is_dir("$dir/foobar/bar/baz")); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + // same again with deletefiles + + // setup hierachy and test it exists + $dir = io_mktmpdir(); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(io_mkdir_p("$dir/foo/bar/baz")); + $this->assertTrue(is_dir("$dir/foo/bar/baz")); + $this->assertTrue(io_mkdir_p("$dir/foobar/bar/baz")); + $this->assertTrue(is_dir("$dir/foobar/bar/baz")); + + // delete successfully + $this->assertTrue(io_rmdir($dir, true)); + + // check result + clearstatcache(); + $this->assertFalse(is_dir("$dir/foo/bar/baz")); + $this->assertFalse(is_dir("$dir/foobar/bar/baz")); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + } + + function test_full_single(){ + // set up test dir + $dir = io_mktmpdir(); + $top = dirname($dir); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + + // put file + $this->assertTrue(io_saveFile("$dir/testfile.txt", 'foobar')); + $this->assertFileExists("$dir/testfile.txt"); + + // delete unsuccessfully + $this->assertFalse(io_rmdir($dir, false)); + + // check result + clearstatcache(); + $this->assertFileExists("$dir/testfile.txt"); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + // same again with deletefiles + + // delete successfully + $this->assertTrue(io_rmdir($dir, true)); + + // check result + clearstatcache(); + $this->assertFileNotExists("$dir/testfile.txt"); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + } + + function test_full_hierarchy(){ + // setup hierachy and test it exists + $dir = io_mktmpdir(); + $top = dirname($dir); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(io_mkdir_p("$dir/foo/bar/baz")); + $this->assertTrue(is_dir("$dir/foo/bar/baz")); + $this->assertTrue(io_mkdir_p("$dir/foobar/bar/baz")); + $this->assertTrue(is_dir("$dir/foobar/bar/baz")); + + // put files + $this->assertTrue(io_saveFile("$dir/testfile.txt", 'foobar')); + $this->assertFileExists("$dir/testfile.txt"); + $this->assertTrue(io_saveFile("$dir/foo/testfile.txt", 'foobar')); + $this->assertFileExists("$dir/foo/testfile.txt"); + $this->assertTrue(io_saveFile("$dir/foo/bar/baz/testfile.txt", 'foobar')); + $this->assertFileExists("$dir/foo/bar/baz/testfile.txt"); + + // delete unsuccessfully + $this->assertFalse(io_rmdir($dir, false)); + + // check result + clearstatcache(); + $this->assertFileExists("$dir/testfile.txt"); + $this->assertFileExists("$dir/foo/testfile.txt"); + $this->assertFileExists("$dir/foo/bar/baz/testfile.txt"); + $this->assertTrue(is_dir("$dir/foo/bar/baz")); + $this->assertTrue(is_dir("$dir/foobar/bar/baz")); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + // delete successfully + $this->assertTrue(io_rmdir($dir, true)); + + // check result + clearstatcache(); + $this->assertFileNotExists("$dir/testfile.txt"); + $this->assertFileNotExists("$dir/foo/testfile.txt"); + $this->assertFileNotExists("$dir/foo/bar/baz/testfile.txt"); + $this->assertFalse(is_dir("$dir/foo/bar/baz")); + $this->assertFalse(is_dir("$dir/foobar/bar/baz")); + $this->assertFalse(is_dir($dir)); + $this->assertTrue(is_dir($top)); + } + +} \ No newline at end of file -- cgit v1.2.3 From d8cf4dd43ecd37c371acf9bc6c17998b65d42ba4 Mon Sep 17 00:00:00 2001 From: Andreas Gohr Date: Mon, 6 Jan 2014 21:15:50 +0100 Subject: treat non-existing files as success on delete --- _test/tests/inc/io_rmdir.test.php | 60 +++++++++++++++++++++++++++++++++++++++ inc/io.php | 1 + 2 files changed, 61 insertions(+) diff --git a/_test/tests/inc/io_rmdir.test.php b/_test/tests/inc/io_rmdir.test.php index 9a122d111..3de57fa86 100644 --- a/_test/tests/inc/io_rmdir.test.php +++ b/_test/tests/inc/io_rmdir.test.php @@ -2,6 +2,66 @@ class io_rmdir_test extends DokuWikiTest { + function test_nopes(){ + // set up test dir + $dir = io_mktmpdir(); + $top = dirname($dir); + $this->assertTrue($dir !== false); + $this->assertTrue(is_dir($dir)); + + // switch into it + $this->assertTrue(chdir($dir)); + $this->assertEquals($dir, getcwd()); + + + $this->assertFalse(io_rmdir('', false)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir('', true)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(null, false)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(null, true)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(false, false)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(false, true)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(array(), false)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFalse(io_rmdir(array(), true)); + clearstatcache(); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + + $this->assertFileNotExists("$dir/this/does/not/exist"); + $this->assertTrue(io_rmdir("$dir/this/does/not/exist")); + clearstatcache(); + $this->assertFileNotExists("$dir/this/does/not/exist"); + $this->assertTrue(is_dir($dir)); + $this->assertTrue(is_dir($top)); + } + function test_empty_single(){ // set up test dir diff --git a/inc/io.php b/inc/io.php index 30f34ad3c..892f93759 100644 --- a/inc/io.php +++ b/inc/io.php @@ -410,6 +410,7 @@ function io_mkdir_p($target){ */ function io_rmdir($path, $removefiles = false) { if(!is_string($path) || $path == "") return false; + if(!file_exists($path)) return true; // it's already gone or was never there, count as success if(is_dir($path) && !is_link($path)) { $dirs = array(); -- cgit v1.2.3