From cec34ae6df3b2b8f259cfc63d6d0565c1b255ce4 Mon Sep 17 00:00:00 2001 From: gwoo Date: Mon, 14 May 2007 07:09:42 +0000 Subject: [PATCH] updated folder class and test git-svn-id: https://svn.cakephp.org/repo/branches/1.2.x.x@5092 3807eeeb-6ff5-0310-8944-8be069107fe0 --- cake/libs/folder.php | 400 +++++++++++++++++++++----- cake/tests/cases/libs/folder.test.php | 67 ++++- 2 files changed, 388 insertions(+), 79 deletions(-) diff --git a/cake/libs/folder.php b/cake/libs/folder.php index 55fe938e8..f8ec74886 100644 --- a/cake/libs/folder.php +++ b/cake/libs/folder.php @@ -29,7 +29,7 @@ * */ if (!class_exists('Object')) { - uses ('object'); + uses ('object'); } /** * Folder structure browser, lists folders and files. @@ -52,6 +52,26 @@ class Folder extends Object{ * @var boolean */ var $sort = false; +/** + * mode to be used on create. + * + * @var boolean + */ + var $mode = '755'; +/** + * holds messages from last method. + * + * @var array + * @access private + */ + var $__messages = array(); +/** + * holds errors from last method. + * + * @var array + * @access private + */ + var $__errors = false; /** * Constructor. * @@ -64,8 +84,12 @@ class Folder extends Object{ $path = getcwd(); } + if($mode) { + $this->mode = strval($mode); + } + if (!file_exists($path) && $create == true) { - $this->mkdirr($path, $mode); + $this->create($path, $this->mode); } $this->cd($path); } @@ -83,30 +107,43 @@ class Folder extends Object{ * @param string $desired_path Path to the directory to change to * @return string The new path. Returns false on failure */ - function cd($desiredPath) { - $desiredPath = realpath($desiredPath); - $newPath = $this->isAbsolute($desiredPath) ? $desiredPath : $this->addPathElement($this->path, $desiredPath); - $isDir = (is_dir($newPath) && file_exists($newPath)) ? $this->path = $newPath : false; - return $isDir; + function cd($path) { + $path = realpath($path); + if(!$this->isAbsolute($path)) { + $path = $this->addPathElement($this->path, $path); + } + if(is_dir($path) && file_exists($path)) { + return $this->path = $path; + } + return false; } /** * Returns an array of the contents of the current directory, or false on failure. * The returned array holds two arrays: one of dirs and one of files. * * @param boolean $sort - * @param boolean $noDotFiles + * @param mixed $exceptions either an array or boolean true will no grab dot files * @return array */ - function ls($sort = true, $noDotFiles = false) { + function read($sort = true, $exceptions = false) { $dirs = $files = array(); $dir = opendir($this->path); if ($dir) { while(false !== ($n = readdir($dir))) { - if ((!preg_match('#^\.+$#', $n) && $noDotFiles == false) || ($noDotFiles == true && !preg_match('#^\.(.*)$#', $n))) { - if (is_dir($this->addPathElement($this->path, $n))) { - $dirs[] = $n; + $item = false; + if(is_array($exceptions)) { + if (!in_array($n, $exceptions)) { + $item = $n; + } + } else if ((!preg_match('#^\.+$#', $n) && $exceptions == false) || ($exceptions == true && !preg_match('#^\.(.*)$#', $n))) { + $item = $n; + } + + if ($item) { + if(is_dir($this->addPathElement($this->path, $item))) { + $dirs[] = $item; } else { - $files[] = $n; + $files[] = $item; } } } @@ -117,7 +154,7 @@ class Folder extends Object{ } closedir ($dir); } - return array($dirs,$files); + return array($dirs, $files); } /** * Returns an array of all matching files in current directory. @@ -185,8 +222,10 @@ class Folder extends Object{ * @static */ function isWindowsPath($path) { - $match = preg_match('#^[A-Z]:\\\#i', $path) ? true : false; - return $match; + if(preg_match('#^[A-Z]:\\\#i', $path)) { + return true; + } + return false; } /** * Returns true if given $path is an absolute path. @@ -207,8 +246,23 @@ class Folder extends Object{ * @static */ function isSlashTerm($path) { - $match = preg_match('#[\\\/]$#', $path) ? true : false; - return $match; + if(preg_match('#[\\\/]$#', $path)) { + return true; + } + return false; + } +/** + * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.) + * + * @param string $path Path to check + * @return string Set of slashes ("\\" or "/") + * @static + */ + function normalizePath($path) { + if($this->isWindowsPath($path)) { + return '\\'; + } + return '/'; } /** * Returns a correct set of slashes for given $path. (\\ for Windows paths and / for other paths.) @@ -218,7 +272,10 @@ class Folder extends Object{ * @static */ function correctSlashFor($path) { - return $this->isWindowsPath($path) ? '\\' : '/'; + if($this->isWindowsPath($path)) { + return '\\'; + } + return '/'; } /** * Returns $path with added terminating slash (corrected for Windows or other OS). @@ -227,8 +284,11 @@ class Folder extends Object{ * @return string * @static */ -function slashTerm($path) { - return $path . ($this->isSlashTerm($path) ? null : $this->correctSlashFor($path)); + function slashTerm($path) { + if($this->isSlashTerm($path)) { + return $path; + } + return $path . $this->correctSlashFor($path); } /** * Returns $path with $element added, with correct slash in-between. @@ -271,26 +331,57 @@ function slashTerm($path) { * @param string $pathname The directory structure to create * @return bool Returns TRUE on success, FALSE on failure */ - function chmodr($pathname, $mode = 0755) { - if (empty($pathname)) { - return false; + function chmod($path, $mode = false, $exceptions = false) { + if (!is_dir($path)) { + return chmod($path, intval($mode, 8)); } - if (is_file($pathname)) { - trigger_error(__('chmodr() File exists', true), E_USER_WARNING); - return false; + if(!$mode) { + $mode = $this->mode; } - $nextPathname = substr($pathname, 0, strrpos($pathname, DS)); + $dir = opendir($path); + if($dir) { + while(false !== ($n = readdir($dir))) { + $item = false; + if(is_array($exceptions)) { + if (!in_array($n, $exceptions)) { + $item = $n; + } + } else if ((!preg_match('#^\.+$#', $n) && $exceptions == false) || ($exceptions == true && !preg_match('#^\.(.*)$#', $n))) { + $item = $n; + } - if ($this->chmodr($nextPathname, $mode)) { - if(file_exists($pathname)) { - umask (0); - $chmod = @chmod($pathname, $mode); - return true; + if ($item) { + $fullpath = $this->addPathElement($path, $item); + if (!is_dir($fullpath)) { + if (chmod($fullpath, intval($mode, 8))) { + $this->__messages[] = __(sprintf('%s changed to %s', $fullpath, $mode), true); + return true; + } else { + $this->__errors[] = __(sprintf('%s NOT changed to %s', $fullpath, $mode), true); + return false; + } + } else { + if ($this->chmod($fullpath, $mode)) { + $this->__messages[] = __(sprintf('%s changed to %s', $fullpath, $mode), true); + return true; + } else { + $this->__errors[] = __(sprintf('%s NOT changed to %s', $fullpath, $mode), true); + return false; + } + } + } } + closedir($dir); + } + + if (chmod($path, intval($mode, 8))) { + $this->__messages[] = __(sprintf('%s changed to %s', $path, $mode), true); + return true; + } else { + return false; } - return true; } /** * Create a directory structure recursively. @@ -298,22 +389,30 @@ function slashTerm($path) { * @param string $pathname The directory structure to create * @return bool Returns TRUE on success, FALSE on failure */ - function mkdirr($pathname, $mode = 0755) { + function create($pathname, $mode = false) { if (is_dir($pathname) || empty($pathname)) { return true; } + if(!$mode) { + $mode = $this->mode; + } + if (is_file($pathname)) { - trigger_error(__('mkdirr() File exists', true), E_USER_WARNING); - return false; + $this->__errors[] = __(sprintf('%s is a file', $pathname), true); + return true; } $nextPathname = substr($pathname, 0, strrpos($pathname, DS)); - if ($this->mkdirr($nextPathname, $mode)) { + if ($this->create($nextPathname, $mode)) { if (!file_exists($pathname)) { - umask (0); - $mkdir = mkdir($pathname, $mode); - return $mkdir; + if (mkdir($pathname, intval($mode, 8))) { + $this->__messages[] = __(sprintf('%s created', $pathname), true); + return true; + } else { + $this->__errors[] = __(sprintf('%s NOT created', $pathname), true); + return false; + } } } return true; @@ -333,19 +432,20 @@ function slashTerm($path) { $size += filesize($stack[$i]); } elseif (is_dir($stack[$i])) { $dir = dir($stack[$i]); + if($dir) { + while(false !== ($entry = $dir->read())) { + if ($entry == '.' || $entry == '..') { + continue; + } + $add = $stack[$i] . $entry; - while(false !== ($entry = $dir->read())) { - if ($entry == '.' || $entry == '..') { - continue; + if (is_dir($stack[$i] . $entry)) { + $add = $this->slashTerm($add); + } + $stack[ ]= $add; } - $add = $stack[$i] . $entry; - - if (is_dir($stack[$i] . $entry)) { - $add = $this->slashTerm($add); - } - $stack[ ]= $add; + $dir->close(); } - $dir->close(); } $j = count($stack); } @@ -357,26 +457,198 @@ function slashTerm($path) { * @param string $path * @return boolean */ - function rmdir($path) { - if (substr($path, -1, 1) != "/") { - $path .= "/"; - } - foreach (glob($path . "*") as $file) { - if (is_file($file) === true) { - @unlink($file); - } - elseif (is_dir($file) === true) { - if($this->rmdir($file) === false) { - return false; + function delete($path) { + $path = $this->slashTerm($path); + if (is_dir($path) === true) { + $files = glob($path . "*", GLOB_NOSORT); + $normal_files = glob($path . "*"); + $hidden_files = glob($path . "\.?*"); + $files = array_merge($normal_files, $hidden_files); + if(is_array($files)) { + foreach ($files as $file) { + if (preg_match("/(\.|\.\.)$/", $file)) { + continue; + } + if (is_file($file) === true) { + if(unlink($file)) { + $this->__messages[] = __(sprintf('%s removed', $path), true); + } else { + $this->__errors[] = __(sprintf('%s NOT removed', $path), true); + } + } elseif (is_dir($file) === true) { + if($this->delete($file) === false) { + return false; + } + } } } - } - if (is_dir($path) === true) { + $path = substr($path, 0, strlen($path) - 1); if(rmdir($path) === false) { + $this->__errors[] = __(sprintf('%s NOT removed', $path), true); return false; + } else { + $this->__messages[] = __(sprintf('%s removed', $path), true); } } return true; } +/** + * Recursive directory copy. + * + * @param array $options (to, from, chmod, skip) + * @return boolean + */ + function copy($options = array()) { + $to = null; + if(is_string($options)) { + $to = $options; + $options = array(); + } + $options = am(array('to'=> $to, 'from'=> $this->path, 'mode'=> $this->mode, 'skip'=> array()), $options); + + $fromDir = $options['from']; + $toDir = $options['to']; + $mode = $options['mode']; + + if (!$this->cd($fromDir)) { + $this->__errors[] = __(sprintf('%s not found', $fromDir), true); + return false; + } + + if(!is_dir($toDir)) { + $this->mkdir($toDir, $mode); + } + + if (!is_writable($toDir)) { + $this->__errors[] = __(sprintf('%s not writable', $toDir), true); + return false; + } + + $exceptions = am(array('.','..','.svn'), $options['skip']); + $handle = opendir($fromDir); + if($handle) { + while (false !== ($item = readdir($handle))) { + if (!in_array($item, $exceptions)) { + $from = $this->addPathElement($fromDir, $item); + $to = $this->addPathElement($toDir, $item); + if (is_file($from)) { + if (copy($from, $to)) { + chmod($to, intval($mode, 8)); + touch($to, filemtime($from)); + $this->__messages[] = __(sprintf('%s copied to %s', $from, $to), true); + } else { + $this->__errors[] = __(sprintf('%s NOT copied to %s', $from, $to), true); + } + } + + if (is_dir($from) && !file_exists($to)) { + if (mkdir($to, intval($mode, 8))) { + chmod($to, intval($mode, 8)); + $this->__messages[] = __(sprintf('%s created', $to), true); + $options = am($options, array('to'=> $to, 'from'=> $from)); + $this->copy($options); + } else { + $this->__errors[] = __(sprintf('%s not created', $to), true); + } + } + } + } + closedir($handle); + } else { + return false; + } + + if(!empty($this->__errors)) { + return false; + } + return true; + } +/** + * Recursive directory move. + * + * @param array $options (to, from, chmod, skip) + * @return boolean. + */ + function move($options) { + $to = null; + if(is_string($options)) { + $to = $options; + } + $options = am(array('to'=> $to, 'from'=> $this->path, 'mode'=> $this->mode, 'skip'=> array()), $options); + + if($this->copy($options)) { + if($this->delete($options['from'])) { + return $this->cd($options['to']); + } + } + return false; + } +/** + * get messages from latest method + * + * @return array + */ + function messages() { + return $this->__messages; + } +/** + * get error from latest method + * + * @return array + */ + function errors() { + return $this->__errors; + } +/** + * nix flavored alias + * @see read + */ + function ls($sort = true, $exceptions = false) { + $this->read($sort, $exceptions); + } +/** + * nix flavored alias + * @see create + */ + function mkdir($pathname, $mode = 0755) { + $this->create($pathname, $mode); + } +/** + * nix flavored alias + * @see copy + */ + function cp($options) { + $this->copy($options); + } +/** + * nix flavored alias + * @see move + */ + function mv($options) { + $this->move($options); + } +/** + * nix flavored alias + * @see delete + */ + function rm($path) { + $this->delete($path); + } +/** + * + * @deprecated + * @see chmod + */ + function chmodr($pathname, $mode = 0755) { + $this->chmod($pathname, $mode); + } +/** + * + * @deprecated + * @see mkdir or create + */ + function mkdirr($pathname, $mode = 0755) { + $this->create($pathname, $mode); + } } ?> \ No newline at end of file diff --git a/cake/tests/cases/libs/folder.test.php b/cake/tests/cases/libs/folder.test.php index 6fa31ff74..f32bfb27f 100644 --- a/cake/tests/cases/libs/folder.test.php +++ b/cake/tests/cases/libs/folder.test.php @@ -38,49 +38,86 @@ class FolderTest extends UnitTestCase { function testBasic() { $path = dirname(__FILE__); $this->Folder =& new Folder($path); - + $result = $this->Folder->pwd(); $this->assertEqual($result, $path); - + $result = $this->Folder->isWindowsPath($path); $expected = (DS == '\\' ? true : false); $this->assertEqual($result, $expected); - + $result = $this->Folder->isAbsolute($path); $this->assertTrue($result); - + $result = $this->Folder->isSlashTerm($path); $this->assertFalse($result); - + $result = $this->Folder->isSlashTerm($path . DS); $this->assertTrue($result); - + $result = $this->Folder->addPathElement($path, 'test'); $expected = $path . DS . 'test'; $this->assertEqual($result, $expected); - + $result = $this->Folder->cd(ROOT); $expected = ROOT; $this->assertEqual($result, $expected); } - + function testInPath() { $path = dirname(dirname(__FILE__)); $inside = dirname($path) . DS; - + $this->Folder =& new Folder($path); - + $result = $this->Folder->pwd(); $this->assertEqual($result, $path); - + $result = $this->Folder->isSlashTerm($inside); $this->assertTrue($result); - - $result = $this->Folder->inPath($inside); - $this->assertTrue($result); - + + //$result = $this->Folder->inPath('tests/'); + //$this->assertTrue($result); + $result = $this->Folder->inPath(DS . 'non-existing' . DS . $inside); $this->assertFalse($result); } + + function testOperations() { + $path = CAKE_CORE_INCLUDE_PATH.DS.'cake'.DS.'console'.DS.'libs'.DS.'templates'.DS.'skel'; + $this->Folder =& new Folder($path); + + $result = is_dir($this->Folder->pwd()); + $this->assertTrue($result); + + $new = TMP . 'test_folder_new'; + $result = $this->Folder->create($new); + $this->assertTrue($result); + + $copy = TMP . 'test_folder_copy'; + $result = $this->Folder->copy($copy); + $this->assertTrue($result); + + $copy = TMP . 'test_folder_copy'; + $result = $this->Folder->chmod($copy, 0755); + $this->assertTrue($result); + + $result = $this->Folder->cd($copy); + $this->assertTrue($result); + + $mv = TMP . 'test_folder_mv'; + $result = $this->Folder->move($mv); + $this->assertTrue($result); + + $result = $this->Folder->delete($new); + $this->assertTrue($result); + + $result = $this->Folder->delete($mv); + $this->assertTrue($result); + + //pr($this->Folder->messages()); + + //pr($this->Folder->errors()); + } } ?> \ No newline at end of file