/server/vpn.51sync.com/library/helper/filesys.php
PHP | 351 lines | 227 code | 12 blank | 112 comment | 23 complexity | c2b30413444049914184f04e11a7bbc6 MD5 | raw file
Possible License(s): BSD-3-Clause
- <?php
- // $Id: filesys.php 2212 2009-02-06 00:51:32Z dualface $
- /**
- * 定义 Helper_Filesys 类
- *
- * @link http://qeephp.com/
- * @copyright Copyright (c) 2006-2009 Qeeyuan Inc. {@link http://www.qeeyuan.com}
- * @license New BSD License {@link http://qeephp.com/license/}
- * @version $Id: filesys.php 2212 2009-02-06 00:51:32Z dualface $
- * @package helper
- */
- /**
- * Helper_Filesys 类提供了一组简化文件系统操作的方法
- *
- * 部分方法来自 Yii Framework 框架的 CFileHelper 类,并作了修改。
- *
- * @author YuLei Liao <liaoyulei@qeeyuan.com>
- * @version $Id: filesys.php 2212 2009-02-06 00:51:32Z dualface $
- * @package helper
- */
- abstract class Helper_Filesys
- {
- /**
- * 遍历指定目录及子目录下的文件,返回所有与匹配模式符合的文件名
- *
- * @param string $dir
- * @param string $pattern
- *
- * @return array
- */
- static function recursionGlob($dir, $pattern)
- {
- $dir = rtrim($dir, '/\\') . DS;
- $files = array();
- // 遍历目录,删除所有文件和子目录
- $dh = opendir($dir);
- if (!$dh) return $files;
- $items = (array)glob($dir . $pattern);
- foreach ($items as $item)
- {
- if (is_file($item)) $files[] = $item;
- }
- while (($file = readdir($dh)))
- {
- if ($file == '.' || $file == '..') continue;
- $path = $dir . $file;
- if (is_dir($path))
- {
- $files = array_merge($files, self::recursionGlob($path, $pattern));
- }
- }
- closedir($dh);
- return $files;
- }
- /**
- * 创建一个目录树,失败抛出异常
- *
- * 用法:
- * @code php
- * Helper_Filesys::mkdirs('/top/second/3rd');
- * @endcode
- *
- * @param string $dir 要创建的目录
- * @param int $mode 新建目录的权限
- *
- * @throw Q_CreateDirFailedException
- */
- static function mkdirs($dir, $mode = 0777)
- {
- if (!is_dir($dir))
- {
- $oldumask = umask(0);
- $ret = @mkdir($dir, $mode, true);
- umask($oldumask);
- if (!$ret)
- {
- throw new Q_CreateDirFailedException($dir);
- }
- }
- return true;
- }
- /**
- * 删除指定目录及其下的所有文件和子目录,失败抛出异常
- *
- * 用法:
- * @code php
- * // 删除 my_dir 目录及其下的所有文件和子目录
- * Helper_Filesys::rmdirs('/path/to/my_dir');
- * @endcode
- *
- * 注意:使用该函数要非常非常小心,避免意外删除重要文件。
- *
- * @param string $dir 要删除的目录
- *
- * @throw Q_RemoveDirFailedException
- */
- static function rmdirs($dir)
- {
- $dir = realpath($dir);
- if ($dir == '' || $dir == '/' || (strlen($dir) == 3 && substr($dir, 1) == ':\\'))
- {
- // 禁止删除根目录
- throw new Q_RemoveDirFailedException($dir);
- }
- // 遍历目录,删除所有文件和子目录
- if(false !== ($dh = opendir($dir)))
- {
- while(false !== ($file = readdir($dh)))
- {
- if($file == '.' || $file == '..')
- {
- continue;
- }
- $path = $dir . DIRECTORY_SEPARATOR . $file;
- if (is_dir($path))
- {
- self::rmdirs($path);
- }
- else
- {
- unlink($path);
- }
- }
- closedir($dh);
- if (@rmdir($dir) == false)
- {
- throw new Q_RemoveDirFailedException($dir);
- }
- }
- else
- {
- throw new Q_RemoveDirFailedException($dir);
- }
- }
- /**
- * 复制一个目录及其子目录的文件到目的地
- *
- * 用法:
- * @code
- * Helper_Filesys::copyDir($src, $dst);
- * @endcode
- *
- * 如果目的地目录不存在,则会创建需要的目录。
- *
- * 可以通过 $options 参数控制要复制的文件,以及复制的深度。
- *
- * $options 参数可用的选项有:
- *
- * - extnames: 只有指定扩展名的文件被复制
- * 如果不指定该参数,则查找所有扩展名的文件。
- *
- * - excludes: 排除指定的目录或文件
- * "upload/avatars" 表示排除 "$dir/upload/avatars" 目录。
- *
- * - levels: 整数,指定查找的目录深度,默认为 -1。
- * 如果为 0 表示不查找子目录。
- *
- * 注意:copyDirs() 总是会排除所有以“.”开头的目录和文件。
- */
- static function copyDir($src, $dst, $options=array())
- {
- $extnames = !empty($options['extnames'])
- ? Q::normalize($options['extnames'])
- : array();
- foreach ($extnames as $offset => $extname)
- {
- if ($extname[0] == '.')
- {
- $extnames[$offset] = substr($extname, 1);
- }
- }
- $excludes = !empty($options['excludes'])
- ? Q::normalize($options['excludes'])
- : array();
- $level = isset($options['level'])
- ? intval($options['level'])
- : -1;
- self::_copyDirectoryRecursive($src, $dst, '', $extnames, $excludes, $level);
- }
- /**
- * 在指定目录及其子目录中查找文件
- *
- * 用法:
- * @code php
- * $files = Helper_FileSys::findFiles($dir, array(
- * // 只查找扩展名为 .jpg, .jpeg, .png 和 .gif 的文件
- * 'extnames' => 'jpg, jpeg, png, gif',
- * // 排除 .svn 目录和 upload/avatars 目录
- * 'excludes' => '.svn, upload/avatars',
- * // 只查找 2 层子目录
- * 'level' => 2,
- * ));
- * @endcode
- *
- * findFiles() 的 $options 参数支持下列选项:
- *
- * - extnames: 字符串或数组,指定查找文件时有效的文件扩展名。
- * 如果不指定该参数,则查找所有扩展名的文件。
- *
- * - excludes: 字符串或数组,指定查找文件时要排除的目录或文件。
- * "upload/avatars" 表示排除 "$dir/upload/avatars" 目录。
- *
- * - levels: 整数,指定查找的目录深度,默认为 -1。
- * 如果为 0 表示不查找子目录。
- *
- * findFiles() 返回一个数组,包含了排序后的文件完整路径。
- *
- * @param string|array $dir 要查找文件的目录
- * @param array $options 查找选项
- *
- * @return array 包含有效文件名的数组
- */
- static function findFiles($dir, $options=array())
- {
- $extnames = !empty($options['extnames'])
- ? Q::normalize($options['extnames'])
- : array();
- foreach ($extnames as $offset => $extname)
- {
- if ($extname[0] == '.')
- {
- $extnames[$offset] = substr($extname, 1);
- }
- }
- $excludes = !empty($options['excludes'])
- ? Q::normalize($options['excludes'])
- : array();
- $level = isset($options['level'])
- ? intval($options['level'])
- : -1;
- $list = self::_findFilesRecursive($dir, '', $extnames, $excludes, $level);
- sort($list);
- return $list;
- }
- /**
- * 内部使用
- */
- private static function _copyDirectoryRecursive($src, $dst, $base, $extnames, $excludes, $level)
- {
- @mkdir($dst);
- @chmod($dst,0777);
- $folder = opendir($src);
- while (($file = readdir($folder)))
- {
- if ($file{0} == '.') continue;
- $path = $src . DIRECTORY_SEPARATOR . $file;
- $is_file = is_file($path);
- if(self::_validatePath($base, $file, $is_file, $extnames, $excludes))
- {
- if($is_file)
- {
- copy($path, $dst . DIRECTORY_SEPARATOR . $file);
- }
- elseif($level)
- {
- self::_copyDirectoryRecursive($path, $dst . DIRECTORY_SEPARATOR . $file,
- $base . '/' . $file, $extnames, $excludes, $level - 1);
- }
- }
- }
- closedir($folder);
- }
- /**
- * 递归查找文件,用于 {@link Helper_FileSys::findFiles()}
- *
- * @param string $dir 要查找的源目录
- * @param string $base 与源目录的相对路径
- * @param array $extnames 有效的扩展名
- * @param array $excludes 要排除的文件或目录
- * @param integer $level 要查找的目录深度
- *
- * @return 包含有效文件名的数组
- */
- private static function _findFilesRecursive($dir, $base, $extnames,
- $excludes, $level)
- {
- $list = array();
- $handle = opendir($dir);
- while(($file = readdir($handle)))
- {
- if($file == '.' || $file == '..') continue;
- $path = $dir . DIRECTORY_SEPARATOR . $file;
- $is_file = is_file($path);
- if (self::_validatePath($base, $file, $is_file, $extnames, $excludes))
- {
- if ($is_file)
- {
- $list[] = $path;
- }
- elseif ($level)
- {
- $list = array_merge($list, self::_findFilesRecursive($path,
- $base . '/' . $file, $extnames, $excludes, $level - 1));
- }
- }
- }
- closedir($handle);
- return $list;
- }
- /**
- * 验证文件或目录,返回验证结果
- *
- * @param string $base 与源目录相对路径
- * @param string $file 文件名或目录名
- * @param boolean $is_file 是否是文件
- * @param array $extnames 有效的文件扩展名
- * @param array $excludes 要排除的文件名或目录
- *
- * @return boolean 该文件是否通过验证
- */
- private static function _validatePath($base, $file, $is_file,
- array $extnames, array $excludes)
- {
- $test = ltrim(str_replace('\\', '/', "/{$base}/{$file}"), '/');
- foreach($excludes as $e)
- {
- if ($file == $e || $test == $e) return false;
- }
- if(!$is_file || empty($extnames)) return true;
- if(($pos = strrpos($file, '.')) !==false)
- {
- $type = substr($file, $pos + 1);
- return in_array($type, $extnames);
- }
- else
- {
- return false;
- }
- }
- }