程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 網頁編程 >> PHP編程 >> 關於PHP編程 >> 用PHP實現文件管理系統

用PHP實現文件管理系統

編輯:關於PHP編程

       

      /**

      * @]Class Name[= IO

      * @]Class URI[= System.IO

      * @]Purpose[=

      * 本類用於對文件系統的處理

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]Version[= 1.1.1

      * @]Create[= 17:13 2004-3-25

      * @]Modifications[=

      * 4:04 2004-3-30 "

      * + 修復 generate_path() 方法中存在的一些 BUG

      * + 重新設計方法 no_comment()

      * 4:32 2004-3-29

      * + 簡化方法 list_dir() 的返回值[

      * + 增加方法 file_info() 獲取文件或目錄信息

      * 5:35 2004-3-28

      * + 整理優化算法

      * 7:31 2004-3-27

      * + 將錯誤處理抽象為基類 pB

      * + 增加方法 no_comment() 刪除文件中 C 規范注釋

      * @]See[=

      */

      class IO extends SnkClass

      var $result; // 操作返回結果,如方法返回值為 mixed,則成功操作結果可在此獲得

      var $exec_cmd; // 執行方法,暫時沒應用到

      var $exist_dir; // 創建目錄時最後存在的目錄,現用於 copy() 和 move()

      var $buffer_size; // 文件讀取緩沖區大小,根據服務應用規模和服務器配置修改,建議默認值

      function IO()

      parent::SnkClass();

      $this->result = array();

      $this->exec_cmd = "";

      $this->exist_dir = "";

      $this->buffer_size = 8192;

      return $this;

      }

      /**

      * @]Method Name[= list_dir()

      * @]Purpose[=

      * 讀取指定目錄內容,返回內容數組

      * @]Parameter[=

      * string $dir_path 指定目錄路徑,默認為當前目錄

      * @]Return[= mixed 錯誤返回 FALSE,否則返回

      * array(

      * array("name","location","type"),

      * ......

      * )

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function list_dir($path=".")

      if (!is_dir($path)) return $this->error_occur(0x000B, __FUNCTION__);

      if (!is_readable($path)) return $this->error_occur(0x0002, $path);

      $dh = @opendir($path);

      $result = array();

      $path = realpath($path);

      if ($path[strlen($path)-1]!=DIRECTORY_SEPARATOR) $path .= DIRECTORY_SEPARATOR; // 保證目錄絕對地址後帶目錄分隔符

      while (FALSE!==($fh=readdir($dh))) { // 使用 !== 防止處理名稱為 0 或 FALSE 的文件、目錄

      if ($fh=="."||$fh=="..") continue; // 忽略系統特定文件夾

      $i = $path.$fh; // 獲取絕對地址

      $t = array(

      "name" => $fh, V u,

      "location" => $i,

      "type" => is_file($i) ? 1 : (is_dir($i) ? 0 : -1)

      );

      $result[] = $t;

      }

      closedir($dh);

      unset($dh, $fh, $t, $i);

      clearstatcache(); // 清除文件系統緩存

      return $this->result = $result;

      }

      /**

      * @]Method Name[= file_info()

      * @]Purpose[=

      * 獲取指定文件或目錄的屬性

      * @]Parameter[=

      * string $dir_path 指定目錄路徑,默認為當前目錄

      * @]Return[= mixed 錯誤返回 FALSE,否則返回

      * array("name","location","type","size","access","change","modify","read","write"),

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function file_info($path=".")

      $path = realpath($path);

      if (!$path) return $this->error_occur(0x000A, __FUNCTION__);

      $result = array(

      "name" => substr($path, strrpos($path, DIRECTORY_SEPARATOR)+1),

      "location" => $path, FHHC,~|5

      "type" => is_file($path) ? 1 : (is_dir($path) ? 0 : -1),

      "size" => filesize($path),

      "access" => fileatime($path),

      "modify" => filemtime($path),

      "change" => filectime($path),

      "read" => is_readable($path),

      "write" => is_writeable($path)

      );

      clearstatcache();

      return $this->result = $result;

      }

      /**

      * @]Method Name[= seek file()

      * @]Purpose[=

      * 根據正則表達式條件,在相應目錄及給定層次的子目錄中搜索匹配的文件、目錄

      * @]Parameter[=

      * string $pattern 兼容 PERL 標准的正則表達式指明搜索匹配要求,會添加 /^ $/,默認為 .*

      * string $path 進行搜索的目錄路徑,默認為當前路徑

      * enum $seesk_type 有 -1 0 1 三種可能值,0 僅文件夾,1 僅文件,-1 兩者都包括,默認為 1

      * int $sub_dir 搜索的子目錄深度,指定目錄不算,建議不要超過 5,默認為

      * limit $limit 搜索結果限制,避免過度浪費系統資源,默認為 100

      * @]Return[= mixed 錯誤返回 FALSE,否則

      * array(

      * array(

      * "name","locate","type"

      * ),

      * ......

      * )

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function seek_file($pattern=".*", $path=".", $seek_type=1, $sub_dir_level=0, $limit=100)

      /* 檢查參數值 */

      $is_error = $seek_type!=1 && $seek_type!=0 && $seek_type!=-1;

      $is_error = $is_error && (!is_int($sub_dir_level) || $sub_dir_level < 0);

      $is_error = $is_error && (!is_int($limit) || $limit < 1);

      if ($is_error) return $this->error_occur(0x000B, __FUNCTION__);

      unset($is_error);

      $result = array();

      /* array() == FALSE,所以需要使用 === */

      if (FALSE===$i=$this->list_dir($path)) return FALSE; // 如果不能列舉目錄,返回

      for ($j=0,$k=count($i);$j<$k;$j++) {

      if ($i[$j]["type"]==-1) continue; // 對於非目錄非文件項目,跳過

      if ($i[$j]["type"]==0&&$sub_dir_level) { // 如果需要搜索下層目錄

      if (FALSE===$l=$this->seek_file($pattern,$i[$j]["location"],$seek_type,($sub_dir_level - 1),$limit)) return FALSE;

      $result = array_merge($result, $l); // 將下層目錄搜索結果添加

      }

      if ($seek_type+$i[$j]["type"]==1||!preg_match("/^".$pattern."$/", $i[$j]["name"])) continue; // 如果不搜索當前類型,跳過

      $result[] = $i[$j];

      if (count($result)>=$limit) { // 截去超過要求的長度,離開列舉

      array_splice($result, $limit);

      break;

      }

      }

      unset($i, $j, $k, $l);

      return $this->result = $result;

      }

      /**

      * @]Method Name[= delete()

      * @]Purpose[=

      * 刪除指定對象,文件或文件夾——包括內含子目錄和文件的非空文件夾

      * @]Parameter[=

      * string $path 指定要刪除的內容路徑,文件或目錄均可

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function delete($path="") {

      $path = realpath($path);

      if (!$path) return $this->error_occur(0x000A, __FUNCTION__);

      if (!is_dir($path)) {

      if (@unlink($path)) return TRUE; // 文件刪除成功

      return $this->error_occur(0x0004, $path);

      } else {

      if (FALSE===$i=$this->list_dir($path)) return FALSE; // 不能列舉目錄

      for ($j=0,$k=count($i);$j<$k;$j++)

      if (!$this->delete($i[$j]["location"])) return FALSE; // 刪除目錄內容出錯

      unset($i, $j, $k);

      return TRUE;

      }

      }

      /**

      * @]Method Name[= generate_path() =l

      * @]Purpose[=

      * 獲取現有或不存在文件、目錄的絕對地址

      * @]Parameter[=

      * string $path 要獲取地址的文件、目錄現有相對、絕對地址

      * @]Return[= string 獲得的地址

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function generate_path($path="") {

      $i = "/"==DIRECTORY_SEPARATOR ? "" : "/"; // 統一目錄分割符

      $path = str_replace($i, DIRECTORY_SEPARATOR, strval($path));

      if ($path[strlen($path)-1]!=DIRECTORY_SEPARATOR) $path .= DIRECTORY_SEPARATOR;

      $i = strpos($path, DIRECTORY_SEPARATOR); // 獲得路徑中首個目錄分割符的位置

      $ext = substr($path, $i+1);

      $path = substr($path, 0, $i+1);

      if ($i=realpath($path)) $path = $i; // 得到基本路徑

      else {

      $ext = $path.$ext;

      $path = realpath(".");

      }

      if (strlen($ext)) { // 對剩余內容處理

      $ext = preg_replace("/[:*?"<>|]/", "", explode(DIRECTORY_SEPARATOR, $ext));

      array_pop($ext);

      $path = explode(DIRECTORY_SEPARATOR, $path); // 建立目錄層軸

      if ($path[count($path)-1]=="") array_pop($path);

      while (count($ext)) {

      $i = array_shift($ext);

      if ($i==".."&&count($path)>1) array_pop($path);

      elseif (""!=str_replace(".", "", $i)) $path[] = $i;

      }

      $path = implode(DIRECTORY_SEPARATOR, $path);

      }

      unset($ext, $i);

      return $path;

      }

      /**

      * @]Method Name[= make_dir()

      * @]Purpose[=

      * 建立任意文件夾,相對或絕對路徑皆可,深層建立亦可

      * @]Parameter[=

      * string $path 要建立的最終目錄路徑

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */ )

      function make_dir($path="") {

      $i = explode(DIRECTORY_SEPARATOR, $this->generate_path($path)); // 生成目錄路徑

      $path = array_shift($i);

      for ($j=0,$k=count($i);$j<$k;$j++) {

      $path .= DIRECTORY_SEPARATOR.$i[$j];

      if (!is_dir($path)) {

      if ($this->exist_dir=="") $this->exist_dir = $path; // 記錄最後存在的目錄路徑

      if (!@mkdir($path)) return $this->error_occur(0x0003, substr($path, 0, strrpos($path, DIRECTORY_SEPARATOR)));

      }

      }

      if ($this->exist_dir=="") $this->exist_dir = $path;

      return TRUE;

      }

      /**

      * @]Method Name[= verify_file()

      * @]Purpose[=

      * 使用 MD5 算法比較兩個文件是否相同

      * @]Parameter[=

      * string $src 源文件路徑

      * string $dst 目標文件路徑

      * boolean $interal 對於超過 1MB 文件,設置 FALSE 省去 MD5 檢驗步驟,減輕服務器負擔

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function verify_file($src="", $dst="", $interal=TRUE) {

      if (!is_file($src)||!is_file($dst)) return $this->error_occur(0x000B, __FUNCTION__);

      if (!is_readable($src)) return $this->error_occur(0x0006, $src);

      if (!is_readable($dst)) return $this->error_occur(0x0006, $dst);

      $i = filesize($src);

      if (filesize($dst)!=$i) { // 文件大小不等

      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; // 文件 MD5 效驗不符合,內容不相同

      return TRUE;

      }

      /**

      * @]Method Name[= copy()

      * @]Purpose[=

      * 對任意文件夾、文件進行復制,相對或絕對路徑皆可,文件復制完成後會進行效驗,檢查是否出錯數據錯誤

      * @]Parameter[=

      * string $src_path 指定要復制的源內容路徑,文件或目錄均可

      * string $dst_path 指定要復制的目標內容路徑,文件或目錄均可,性質由 $src_path 決定,可為 $src_path 下層目錄

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function copy($src="", $dst="", $sub=FALSE) {

      if (!$src=realpath($src)) return $this->error_occur(0x000B, __FUNCTION__);

      $dst = $this->generate_path($dst);

      if (is_dir($src)) { // 處理目錄

      /*

      * 關於算法的說明:

      * 本來打算使用很簡單的遞歸算法,遇神殺神,遇魔斬魔的,後來發現一個問題:如果目標路徑

      * 為源路徑的後代路徑怎麼辦?這樣算法會不停的探測下去…

      * 於是添加了 $this->exist_dir 屬性,用來記錄這一情況下目標路徑中存在的部分。於是新的問

      * 題出來了:如何保存這一屬性?

      * 將整個功能整合到 $this->copy() 方法中,那麼必然需要在這個函數中記錄

      * 的變化,於是乎需要另外的一個有效的方法來阻止每一次操作中對其的更改。

      * 作為變通,我使用的隱藏參數 $sub,這個參數無論如何,只要算法不變,永遠在參數表的最

      * 後一個。因此,方法開始變得不穩定,但這也沒有辦法,只能希望程序員自己不要故意破壞。

      * 在外部調用時,因為默認 FALSE,所以對 $this->exist_dir 寫。內部遞歸時,顯性 TRUE,

      * 該屬性,保證有效性。

      */

      if (!is_readable($src)) return $this->error_occur(0x0002, $src);

      if ($dst[strlen($dst)-1]!=DIRECTORY_SEPARATOR) $dst .= DIRECTORY_SEPARATOR;

      if (TRUE===$sub&&$src==$this->exist_dir) return TRUE; // 源路徑為記錄的目標路徑

      if (TRUE!==$sub) $this->exist_dir = ""; // 記錄創建目錄前目標目錄路徑中存在的目錄路徑

      if (!$this->make_dir($dst)) return FALSE; // 創建目錄

      if (FALSE===$i=$this->list_dir($src)) return FALSE; // 讀取目錄出錯

      for ($j=0,$k=count($i);$j<$k;$j++) if (!$this->copy($i[$j]["location"], $dst.$i[$j]["name"],TRUE)) return FALSE;

      unset($i, $j, $k);

      RETURN TRUE;

      } else {

      if (!is_readable($src)) return $this->error_occur(0x0006, $src);

      if ($this->verify_file($src,$dst)) return TRUE;

      if (!copy($src,$dst)) return $this->error_occur(0x0007, $dst);

      if (!$this->verify_file($src,$dst)) {

      @unlink($dst); // 復制文件失敗刪除新文件

      return $this->error_occur(0x0007, $dst);

      }

      return TRUE;

      }

      }

      /**

      * @]Method Name[= move()

      * @]Purpose[=

      * 對任意文件夾、文件進行移動,相對或絕對路徑皆可,文件移動完成後會進行效驗,檢查是否出錯數據錯誤www.hidianying.cn

      * @]Parameter[=

      * string $src_path 指定要移動的源內容路徑,文件或目錄均可

      * string $dst_path 指定要移動的目標內容路徑,文件或目錄均可,性質由 $src_path 決定,可為 $src_path 下層目錄

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function move($src="", $dst="", $sub=FALSE) {

      if (!$src=realpath($src)) return $this->error_occur(0x000B, __FUNCTION__);

      $dst = $this->generate_path($dst);

      if (is_dir($src)) { // 處理目錄

      if (!is_readable($src)) return $this->error_occur(0x0002, $src);

      if ($dst[strlen($dst)-1]!=DIRECTORY_SEPARATOR) $dst .= DIRECTORY_SEPARATOR;

      if (TRUE===$sub&&$src==$this->exist_dir) return TRUE;

      if (TRUE!==$sub) $this->exist_dir = "";

      if (!$this->make_dir($dst)) return FALSE;

      if (FALSE===$i=$this->list_dir($src)) return FALSE;

      for ($j=0,$k=count($i);$j<$k;$j++) if (!$this->move($i[$j]["location"], $dst.$i[$j]["name"],TRUE)) return FALSE;

      unset($i, $j, $k);

      if (FALSE===strpos($this->exist_dir,$src))

      if (!@rmdir($src)) return $this->error_occur(0x0004, $src); // 對非目標目錄的上層目錄,刪除

      return TRUE;

      } else {

      if (!is_readable($src)) return $this->error_occur(0x0006, $src);

      if ($this->verify_file($src,$dst)) return TRUE;

      if (!copy($src,$dst)) return $this->error_occur(0x0007, $dst);

      if (!$this->verify_file($src,$dst)) {M

      @unlink($dst);

      return $this->error_occur(0x0007, $dst);

      }

      if (!@unlink($src)) return $this->error_occur(0x0006, $src); // 刪除源文件

      return TRUE;

      }

      }

      /**

      * @]Method Name[= no_comment()

      * @]Purpose[=

      * 清除文件中 C 規范的注釋

      //此教程來源於97xxoo教程網(www.97xxoo.org)查看完整的教程請點:http://www.97xxoo.org/article/1/2008/20081018053.shtml

      * @]Parameter[=

      * string $path 指定要執行操作的文件

      * @]Return[= boolean 錯誤返回 FALSE,否則 TRUE

      * @]Author[= SNakeVil <51JS,BU,PHPx> ([email protected])

      * @]See[=

      */

      function no_comment($path="") {

      if (!is_file($path)) return $this->error_occur(0x000B, __FUNCTION__);

      if (!is_readable($path)) return $this->error_occur(0x0006, $path);

      if (!is_writeable($path)) return $this->error_occur(0x0007, $path);

      if (!$th=tmpfile()) return $this->error_occur(0x000C, $path); // 創建臨時文件

      $fh = fopen($path, "r+b");

      if (!flock($fh,LOCK_EX)) { // 鎖定文件

      fclose($fh);

      unset($fh);

      return $this->error_occur(0x0009, $path);

      }

      $fbuffer = fread($fh, $this->buffer_size*2); // 文件讀取緩沖區

      $tbuffer = ""; // 臨時文件緩沖區<

      $in_dq = $in_sq = $in_lc = $in_bc = FALSE;

      while ($fblen=strlen($fbuffer)) { // 處理原始數據

      $fstats = feof($fh);

      for ($i=0;$i<$fblen;$i++) { // 分析文件內容

      if (!$fstats&&$i+5>$fblen) break; // 文件未完全讀取時臨近緩沖區讀取完成讀取下一塊文件內容

      $j = substr($fbuffer, $i, 2);

      $k = $j[0];

      if ($j=="/*"&&!$in_dq&&!$in_sq&&!$in_lc) { // 不在字符串和行注釋中,塊注釋開始

      $in_bc = TRUE;

      $i++;

      } elseif ($j=="*/"&&$in_bc) { // 塊注釋結束

      $in_bc = FALSE;

      $i+=2;

      } elseif ($j=="//"&&!$in_dq&&!$in_sq&&!$in_bc) { // 行注釋開始

      $in_lc = TRUE;

      $i++;

      } elseif ($in_lc&&($k=="r"||$k=="n")) $in_lc = FALSE; // 行注釋結束

      elseif ($j==""||$j=="""||$j=="'") { // 轉義字符 )

      $tbuffer .= $j;

      $i++;

      continue;

      } elseif ($k=="""&&!$in_sq&&!$in_bc&&!$in_lc) $in_dq = !$in_dq; // 雙引號字符串開始、結束

      elseif ($k=="'"&&!$in_dq&&!$in_bc&&!$in_lc) $in_sq = !$in_sq; // 單引號字符串開始、結束

      if ($in_lc||$in_bc) continue; // 在注釋中,跳過

      $tbuffer .= $fbuffer[$i];

      }

      $fbuffer = substr($fbuffer, $i); // 拋棄讀取過的部分

      unset($i, $j, $k);

      if (!$fstats) $fbuffer .= fread($fh, $this->buffer_size);

      if ($fstats||strlen($tbuffer)>=$this->buffer_size) { // 寫入合法數據到臨時文件

      if (!fwrite($th,$tbuffer)) { // 寫入失敗,空間不足

      fclose($th);

      flock($fh, LOCK_UN);

      fclose($fh);

      unset($th, $fh, $in_dq, $in_sq, $in_lc, $in_bc, $i, $j, $k);

      return $this->error_occur(0x000D, "");

      }

      $tbuffer = "";

      }

      }

      unset($fbuffer, $tbuffer, $fstats, $in_dq, $in_sq, $in_lc, $in_bc);

      rewind($fh); // 回移文件指針到文件首

      rewind($th);

      $i = $j = "";

      $k = 0;

      while (!feof($th)) { // 將臨時文件數據寫回源文件

      $i = fgets($th, $this->buffer_size);

      if ($j=="") { // 獲得文件系統的換行符

      $j= substr($i, -2);

      if ($j=="rn")

      elseif ($j[1]=="r"||$j[1]=="n")

      $k = 1;

      $j = $j[1];

      } else $j = "";

      }

      if (substr($i, -$k)==$j) {

      $i = rtrim(substr($i, 0, -$k), " t");

      if (strlen($i)) fwrite($fh, $i.$j); // 清除右方空格

      else continue;

      } else fwrite($fh, rtrim($i, " t"));

      }

      fflush($fh); // 保存、關閉文件

      ftruncate($fh, ftell($fh));

      fclose($th);

      flock($fh, LOCK_UN);

      fclose($fh);

      unset($i, $j, $k, $fh, $th);

      return TRUE;

      }

      }

      /**

      * @]Error List[=

      * 0x0001 指定目錄不存在

      * 0x0002 指定目錄無讀取權限

      * 0x0003 指定目錄無寫入權限

      * 0x0004 指定目錄無刪除權限

      * 0x0005 指定文件不存在

      * 0x0006 指定文件無讀取權限

      * 0x0007 指定文件無寫入權限

      * 0x0008 指定文件無刪除權限

      * 0x0009 指定文件無法鎖定

      * 0x000A 指定對象不存在

      * 0x000B 方法指定參數不正確

      * 0x000C 無法創建臨時文件

      * 0x000D 磁盤空間不足

      * 0x000E

      * 0x000F

      * 0x0010

      * 0x0011

      *

      */

      ?>

    1. 上一頁:
    2. 下一頁:
    Copyright © 程式師世界 All Rights Reserved