PHP文件系统基本操作类
<?php error_reporting(2047); /* * Class IO (SNakeVil 完成 03.25.04) (v1.0.0.0) * * [说明] * 本类用于对文件系统的处理。 * * [功能] * **** list_dir($dir_path); * 读取指定目录内容,返回内容数组。 * $dir_path 字符串,指定目录路径 * 若有错误返回 FALSE,否则返回 * array( * "count"=>array("files","dirs","size"), * "list"=>array( * array("name","locate","type","size","last_access","last_change","last_modify"), * ...... * ) * ) * ******** * ******** * **** seek_file($pattern, $dir_path, $seek_type, $sub_dir, $interal, $limit); * 根据正则表达式条件,在相应目录及给定层次的子目录中搜索匹配的文件、目录。 * $pattern 符合 PERL 兼容标准的正则表达式,无须添加 //,系统自行添加 * $seek_type 有 -1 0 1 三种可能值,0 仅文件夹,1 仅文件,-1 两者都包括 * $sub_dir 数字值,搜索的子目录深度,指定目录不算,建议不要超过 5 * $interal 布尔值,为真则返回搜索结果的详细信息,否则只返回文件名、类型及所在目录 * $limit 数字值,搜索结果限制,避免过度浪费系统资源 * 若有错误返回 FALSE,否则返回 * array( * array( * "name","locate","type" * [,"size","last_access","last_change","last_modify"] * ), * ...... * ) * ******** * ******** * **** delete($path); * 删除指定对象,文件或文件夹——包括内含子目录和文件的非空文件夹。 * $path 字符串,指定要删除的内容路径,文件或目录均可 * 如有错误在错误处中断,返回 FALSE,否则返回 TRUE * ******** * ******** * **** make_dir($path); * 建立任意文件夹,相对或绝对路径皆可,深层建立亦可。 * $path 字符串,要建立的最终目录路径 * 如有错误返回 FALSE,否则返回 TRUE * ******** * ******** * **** verify_file($src, $dst, $interal); * 使用 MD5 算法比较两个文件是否相同。 * $src 字符串,源文件路径 * $dst 字符串,目标文件路径 * $interal 布尔值,对于大于 1M 文件,可以设置为 FALSE 以省去 MD5 检验步骤,减轻服务器负担 * 若有错误返回 FALSE,否则返回 TRUE * ******** * ******** * **** copy($src_path, $dst_path); * 对任意文件夹、文件进行复制,相对或绝对路径皆可,文件复制完成后会进行效验,检查是否出错数据错误。 * $src_path 字符串,指定要复制的源内容路径,文件或目录均可 * $dst_path 字符串,指定要复制的目标内容路径,文件或目录均可,性质由 $src_path 决定,可为 $src_path 下层目录 * 若有错误返回 FALSE,否则返回 TRUE * ******** * ******** * **** move($src_path, $dst_path); * 对任意文件夹、文件进行移动,相对或绝对路径皆可,文件移动完成后会进行效验,检查是否出错数据错误。 * $src_path 字符串,指定要移动的源内容路径,文件或目录均可 * $dst_path 字符串,指定要移动的目标内容路径,文件或目录均可,性质由 $src_path 决定,可为 $src_path 下层目录 * 若有错误返回 FALSE,否则返回 TRUE * * [版权] * 风雨明清(SNakeVil@51js, SNakeVil@BU)独立设计完成,保留一切权力。 * 随意使用,但请勿必保留下面的文本,谢谢! * * ===========Z================= * Class.IO.v1.0.0.0.build040325 * for.PHP.v4.20+ * by SNakeVil * (snakevil@51js, snakevil@BU) * --------+------ * QQ:118824 * MSN:snakevil_@hotmail.com * HP:<a href="http://www.snakevil.com/" target="_blank">http://www.snakevil.com/</a> * ===========Z================= * */ class IO { var $error_id; var $result; var $error_related; var $last_exist_dir; function IO() { $this->result = array(); $this->error_id = 0x0000; $this->error_related = ""; $this->last_exist_dir = ""; return $this; } function error_occur($error_id = 0xffff, $error_related = "") { // ----0xffff---- 发生错误,但错误原因未知 if (is_int($error_id)) $this->error_id = $error_id; // 获取错误号 $this->error_related = $error_related; return false; // 错误发生时返回 FALSE 方便进一步处理 } function list_dir($dir_path = ".") { if (!is_dir($dir_path)) return $this->error_occur(0x0001, $dir_path); // ----0x0001---- 指定目录不存在 if (!$dir_handle = @opendir($dir_path)) return $this->error_occur(0x0002, $dir_path); // ----0x0002---- 指定目录无权读取 $result = array( "count" => array("files" => 0, "dirs" => 0, "size" => 0), "list" => array() ); while (false !== ($file_handle = readdir($dir_handle))) { // 使用 !== 防止处理名称为 0 或 FALSE 的文件、目录 if ($file_handle == "." || $file_handle == "..") continue; // 忽略系统特定的两个文件夹 $temp = str_replace('\\', "/", realpath($dir_path)); $temp = substr($temp, -1) == "/" ? $temp : $temp . "/"; $temp = array($temp, $file_handle); $file_handle = $temp[0] . $temp[1]; // 获取绝对地址 $temp = array( "name" => $temp[1], "locate" => $temp[0], "type" => @filetype($file_handle), "size" => filesize($file_handle), "last_access" => fileatime($file_handle), "last_modify" => filemtime($file_handle), "last_change" => filectime($file_handle) ); switch ($temp["type"]) { case "file": $temp["type"] = 1; $result["count"]["files"]++; $result["count"]["size"] += $temp["size"]; break; case "dir": $temp["type"] = 0; $result["count"]["dirs"]++; break; default: // !!!! 鉴于 Win32 平台,对既非文件也非目录的内容忽略 $temp["type"] = -1; } $result["list"][] = $temp; } closedir($dir_handle); unset($dir_handle, $file_handle, $temp); clearstatcache(); // 清除文件系统缓存 return $this->result = $result; } function seek_file($pattern = ".*", $dir_path = ".", $seek_type = 1, $sub_dir = 0, $interal = false, $limit = 100) { /* 规范一切可能的参数值 */ $pattern = "/" . $pattern . "/"; $seek_type = intval($seek_type); $seek_type = $seek_type > 0 ? 1 : ($seek_type < 0 ? -1 : 0); $sub_dir = abs(intval($sub_dir)); $interal = (bool)$interal; $limit = abs(intval($limit)); if ($limit == 0) $limit = 100; $sub_dir_list = array(array($dir_path)); // 将查询目录作为子目录层次的第一层来对待 $result = array(); /* i 当前处理的子目录层次,0 为指定目录层,即仅处理一个目录 */ for ($i = 0; $i <= $sub_dir; $i++) { if (!isset($sub_dir_list[$i])) return $this->result = $result; // 如果某一层子目录没有设置,说明实际目录系统中再无目录,返回 /* k 每一子目录层次中子目录统计,j 当前处理序号 */ for ($j = 0, $k = count($sub_dir_list[$i]); $j < $k; $j++) { // 根据每一层子目录数量处理 $l = $this->list_dir($sub_dir_list[$i][$j]); if (!$l) return $this->result = $result; // 出现错误,则立即停止返回现有结果 $l = $l["list"]; /* n 每一子目录中文件、目录、其他项目统计,m 为当前处理序号 */ for ($m = 0, $n = count($l); $m < $n; $m++) { if (count($result) >= $limit) return $this->result = $result; // 如果要求数目已达到,返回 if ($l[$m]["type"] == 0) $sub_dir_list[$i + 1][] = $l[$m]["locate"] . $l[$m]["name"]; // 搜集下一层子目录信息 $o = $l[$m]["type"]; if ($o != $seek_type && ($seek_type == 1 || $seek_type == 0)) continue; // 忽略不符合要求的项目 elseif ($o == -1 && $seek_type == -1) continue; if (!preg_match($pattern, $l[$m]["name"])) continue; // 忽略不符合正则表达式的项目 $result[] = $interal ? $l[$m] : array("name" => $l[$m]["name"], "locate" => $l[$m]["locate"], "type" => $l[$m]["type"]); } } } unset($i, $j, $k, $l, $m, $n, $o, $sub_dir_list); return $this->result = $result; } function delete($path = "") { if (!file_exists($path)) return $this->error_occur(0x0003, $path); // ----0x0003---- 指定对象不存在 if (is_dir($path)) { $path = str_replace("", "/", realpath($path)); $path = substr($path, -1) == "/" ? $path : $path . "/"; $sub_list = array(array($path)); for ($i = 0; $i < count($sub_list); $i++) { // 使用 COUNT($SUB_LIST) 动态判断长度,从而有可能无定长循环 if (!isset($sub_list[$i])) break; // 探索到最尽头,获得该目录下所有子目录列表,方便文件删除后删除目录 for ($j = 0, $k = count($sub_list[$i]); $j < $k; $j++) { $l = $this->list_dir($sub_list[$i][$j]); if (!$l) return $this->error_occur("", $sub_list[$i][$j]); $l = $l["list"]; for ($m = 0, $n = count($l); $m < $n; $m++) { $o = $l[$m]["locate"] . $l[$m]["name"]; if ($l[$m]["type"] == 0) $sub_list[$i + 1][] = $o; elseif (!@unlink($o)) return $this->error_occur(0x0004, $o); // 删除目录下的每一个文件 } } } for ($i = count($sub_list) - 1; $i >= 0; $i--) // 逆回删除目录 for ($j = 0, $k = count($sub_list[$i]); $j < $k; $j++) // 删除每一个子目录直到指定目录 if (!@rmdir($sub_list[$i][$j])) return $this->error_occur(0x0005, $sub_list[$i][$j]); // ----0x0005---- 目录无权删除 unset($i, $j, $k, $l, $m, $n, $o, $sub_list); return true; } elseif (@unlink($path)) return true; else return $this->error_occur(0x0004, $path); // ----0x0004---- 文件无权删除 } function generate_realpath($path = "") { if ($path == "" || !is_string($path)) return $this->error_occur(0x0007, $path); // ----0x0007---- 路径参数错误 $path = preg_replace('/(?<!^w)[:*?"<>|]/', "", str_replace("\\", "/", $path)); // 规范路径中多可能性的符号 if (substr($path, 1, 1) == ":") return $path; // !!!! Win32 平台的绝对路径 elseif (substr($path, 0, 1) == " / ") return substr(realpath(" . "), 0, 2) . $path; // !!!! Win32 平台下的绝对路径转换 else { if (substr($path, -1) == " / ") $path = substr($path, 0, -1); // 清除结尾可能的 / 符号 $path = preg_replace("//{2,}/", "/", $path); // 将 /// 诸如类似的相连符号简化为一个 $path = explode("/", $path); // 分割路径 $cur_path = explode("/", str_replace("\\", " / ", realpath(" . "))); for ($i = 0, $j = count($path); $i < $j; $i++) { if ($path[$i] == " ..") array_pop($cur_path); elseif ($path[$i] == " . " || $path[$i] == str_repeat(" . ", strlen($path[$i]))) continue; // 忽略无用的相对路径地址 . 和 .... 等 else array_push($cur_path, $path[$i]); } $path = implode(" / ", $cur_path); unset($cur_path); return $path; } } function make_dir($path = "") { if (!$path = $this->generate_realpath($path)) return false; $path = explode(" / ", $path); $i = array($path[0]); for ($i = 0, $j = count($path), $k = array(), $l = ""; $i < $j; $i++) { array_push($k, $path[$i]); $l = implode(" / ", $k); if (!file_exists($l)) { if ($this->last_exist_dir == "") $this->last_exist_dir = $l; if (!@mkdir($l)) return $this->error_occur(0x0008, $l); // ----0x0008---- 无法创建目录 } } return true; } function verify_file($src = "", $dst = "", $interal = true) { if (!file_exists($src) || !is_file($src)) return $this->error_occur(0x000A, $src); // ----0x000A---- 指定对象非文件 if (!file_exists($dst) || !is_file($dst)) return $this->error_occur(0x000A, $dst); $i = filesize($src); if ($i != filesize($dst)) { unset($i); return false; } if ($i > 1024 * 1024 * 1024 && !$interal) { // 对于大于 1MB 的文件,如果不要求精确检查,跳过 unset($i); return true; } unset($i); if (md5_file($src) != md5_file($dst)) return false; return true; } function copy($src_path = "", $dst_path = "") { if (!file_exists($src_path)) return $this->error_occur(0x0003, $src_path); if (!$dst_path = $this->generate_realpath($dst_path)) return false; if (is_dir($src_path)) { $this->last_exist_dir = ""; // 记录现行实际存在的目录 if (!$this->make_dir($dst_path)) return false; // 建立目录失败 $src_path = str_replace("", " / ", realpath($src_path)); $src_path = substr($src_path, -1) == " / " ? $src_path : $src_path . " / "; $sub_list = array(array($src_path)); for ($i = 0; $i < count($sub_list); $i++) { if (!isset($sub_list[$i])) break; for ($j = 0, $k = count($sub_list[$i]); $j < $k; $j++) { $l = $this->list_dir($sub_list[$i][$j]); if (!$l) return $this->error_occur(0x0003, $sub_list[$i][$j]); $l = $l["list"]; for ($m = 0, $n = count($l); $m < $n; $m++) { $o = $l[$m]["locate"] . $l[$m]["name"]; if ($o == $this->last_exist_dir) continue; // 如果为上级目录向下级目录复制,防止死循环 $p = str_replace(substr($src_path, 0, -1), $dst_path, $o); if ($l[$m]["type"] == 0) { $sub_list[$i + 1][] = $o; if (!$this->make_dir($p)) return false; // 对每一个子目录都予以建立 } else { // 对每一个文件进行复制 if ($this->verify_file($o, $p)) continue; // 如果目标与源完全相同,不再复制 if (!copy($o, $p) || !$this->verify_file($o, $p)) return $this->error_occur(0x0009, $o); // ----0x0009---- 文件移动失败 } } } } unset($i, $j, $k, $l, $m, $n, $o, $p, $sub_list); return true; } else { if (!is_readable($src_path)) return $this->error_occur(0x0006, $src_path); // ----0x0006---- 源文件无权读取 if ($this->verify_file($src_path, $dst_path)) return true; $i = strrpos($dst_path, " / "); $dst_path = array(substr($dst_path, 0, $i), substr($dst_path, $i + 1)); unset($i); if (!$this->make_dir($dst_path[0])) return false; $dst_path = implode(" / ", $dst_path); if (!copy($src_path, $dst_path) || !$this->verify_file($src_path, $dst_path)) return $this->error_occur(0x0009, $src_path); return true; } } function move($src_path = "", $dst_path = "") { if (!file_exists($src_path)) return $this->error_occur(0x0003, $src_path); if (!$dst_path = $this->generate_realpath($dst_path)) return false; if (is_dir($src_path)) { $this->last_exist_dir = ""; if (!$this->make_dir($dst_path)) return false; $src_path = str_replace("", " / ", realpath($src_path)); $src_path = substr($src_path, -1) == " / " ? $src_path : $src_path . " / "; $sub_list = array(array($src_path)); for ($i = 0; $i < count($sub_list); $i++) { if (!isset($sub_list[$i])) break; for ($j = 0, $k = count($sub_list[$i]); $j < $k; $j++) { $l = $this->list_dir($sub_list[$i][$j]); if (!$l) return $this->error_occur(0x0003, $sub_list[$i][$j]); $l = $l["list"]; for ($m = 0, $n = count($l); $m < $n; $m++) { $o = $l[$m]["locate"] . $l[$m]["name"]; if ($o == $this->last_exist_dir) continue; $p = str_replace(substr($src_path, 0, -1), $dst_path, $o); if ($l[$m]["type"] == 0) { $sub_list[$i + 1][] = $o; if (!$this->make_dir($p)) return false; } else { if ($this->verify_file($o, $p)) continue; if (!copy($o, $p) || !$this->verify_file($o, $p)) return $this->error_occur(0x0009, $o); if (!@unlink($o)) return $this->error_occur(0x0004, $o); } } } } for ($i = count($sub_list) - 1; $i >= 0; $i--) for ($j = 0, $k = count($sub_list[$i]); $j < $k; $j++) if (strpos($this->last_exist_dir, $sub_list[$i][$j]) !== false) continue; // 对移动目标目录的上层目录,不予考虑删除 elseif (!@rmdir($sub_list[$i][$j])) return $this->error_occur(0x0005, $sub_list[$i][$j]); unset($i, $j, $k, $l, $m, $n, $o, $p, $sub_list); return true; } else { if (!is_readable($src_path)) return $this->error_occur(0x0006, $src_path); if ($this->verify_file($src_path, $dst_path)) return true; $i = strrpos($dst_path, " / "); $dst_path = array(substr($dst_path, 0, $i), substr($dst_path, $i + 1)); unset($i); if (!$this->make_dir($dst_path[0])) return false; $dst_path = implode(" / ", $dst_path); if (!copy($src_path, $dst_path) || !$this->verify_file($src_path, $dst_path)) return $this->error_occur(0x0009, $src_path); if (@unlink($src_path)) return true; else return $this->error_occur(0x0004, $src_path); } } } ?>