用PHP實現檔案管理系統_PHP教程

來源:互聯網
上載者:User

用PHP實現檔案管理系統


  

  /**

  * @]Class Name[= IO

  * @]Class URI[= System.IO

  * @]Purpose[=

  * 本類用於對檔案系統的處理

  * @]Author[= SNakeVil <51JS,BU,PHPx> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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[=

  * 根據Regex條件,在相應目錄及給定層次的子目錄中搜尋匹配的檔案、目錄

  * @]Parameter[=

  * string $pattern 相容 PERL 標準的Regex指明搜尋匹配要求,會添加 /^ $/,預設為 .*

  * 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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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> (snakevil@qq.com)

  * @]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=="\r\n")

  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

  *

  */

  ?>

http://www.bkjia.com/PHPjc/845142.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/845142.htmlTechArticle用PHP實現檔案管理系統 /** * @]Class Name[= IO * @]Class URI[= System.IO * @]Purpose[= * 本類用於對檔案系統的處理 * @]Author[= SNakeVil 51JS,BU,PHPx (snakevil@q...

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.