PHP技巧:PHP文件系統(tǒng)基本操作類_PHP教程

      編輯Tag賺U幣
      教程Tag:暫無Tag,歡迎添加,賺取U幣!

      推薦:PHP應(yīng)用:PHP在linxu下的安裝與配置
      環(huán)境需求與準(zhǔn)備工作 在安裝 PHP 做為 WWW 服務(wù)器的一部份時,我們可以考慮用 UNIX 操作系統(tǒng);或者是 Windows NT/95 等 Win32 API 的平臺。當(dāng)然,大部份的人都會使用 UNIX 來當(dāng)作 PHP 的執(zhí)行平臺 (在 Windows NT 的用戶大多數(shù)都會選擇 IIS ASP),因此,本書的

      /*
      *
      * ===========Z=================
      * QQ:118824
      * MSN:snakevil_@hotmail.com
      * HP:http://www.snakevil.com/
      * ===========Z=================
      *
      */

      /**
      * @]Class Name[= IO
      * @]Class URI[= System.IO
      * @]Purpose[=
      * 本類用于對文件系統(tǒng)的處理
      * @]Author[= SNakeVil <51JS,BU,PHPx> (snakevil@qq.com)
      * @]Version[= 1.1.1
      * @]Create[= 17:13 2004-3-25
      * @]Modifications[=
      * 4:04 2004-3-30
      * 修復(fù) generate_path() 方法中存在的一些 BUG
      * 重新設(shè)計方法 no_comment()
      * 4:32 2004-3-29
      * 簡化方法 list_dir() 的返回值
      * 增加方法 file_info() 獲取文件或目錄信息
      * 5:35 2004-3-28
      * 整理優(yōu)化算法
      * 7:31 2004-3-27
      * 將錯誤處理抽象為基類
      * 增加方法 no_comment() 刪除文件中 C 規(guī)范注釋
      * @]See[=
      */
      class IO extends SnkClass {
      var result; // 操作返回結(jié)果,如方法返回值為 mixed,則成功操作結(jié)果可在此獲得
      var exec_cmd; // 執(zhí)行方法,暫時沒應(yīng)用到
      var exist_dir; // 創(chuàng)建目錄時最后存在的目錄,現(xiàn)用于 copy() 和 move()
      var buffer_size; // 文件讀取緩沖區(qū)大小,根據(jù)服務(wù)應(yīng)用規(guī)模和服務(wù)器配置修改,建議默認值

      function IO() {
      parent::SnkClass();
      this->result = array();
      this->exec_cmd = "";
      this->exist_dir = "";
      this->buffer_size = 8192;
      return this;
      }

      /**
      * @]Method Name[= list_dir()
      * @]Purpose[=
      * 讀取指定目錄內(nèi)容,返回內(nèi)容數(shù)組
      * @]Parameter[=
      * string dir_path 指定目錄路徑,默認為當(dāng)前目錄
      * @]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; // 忽略系統(tǒng)特定文件夾
      i = path.fh; // 獲取絕對地址
      t = array(
      "name" => fh,
      "location" => i,
      "type" => is_file(i) ? 1 : (is_dir(i) ? 0 : -1)
      );
      result[] = t;
      }
      closedir(dh);
      unset(dh, fh, t, i);
      clearstatcache(); // 清除文件系統(tǒng)緩存
      return this->result = result;
      }

      /**
      * @]Method Name[= file_info()
      * @]Purpose[=
      * 獲取指定文件或目錄的屬性
      * @]Parameter[=
      * string dir_path 指定目錄路徑,默認為當(dāng)前目錄
      * @]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,
      "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[=
      * 根據(jù)正則表達式條件,在相應(yīng)目錄及給定層次的子目錄中搜索匹配的文件、目錄
      * @]Parameter[=
      * string pattern 兼容 PERL 標(biāo)準(zhǔn)的正則表達式指明搜索匹配要求,會添加 /^ /,默認為 .*
      * string path 進行搜索的目錄路徑,默認為當(dāng)前路徑
      * enum seesk_type 有 -1 0 1 三種可能值,0 僅文件夾,1 僅文件,-1 兩者都包括,默認為 1
      * int sub_dir 搜索的子目錄深度,指定目錄不算,建議不要超過 5,默認為 0
      * limit limit 搜索結(jié)果限制,避免過度浪費系統(tǒng)資源,默認為 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) {
      /* 檢查參數(shù)值 */
      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); // 將下層目錄搜索結(jié)果添加
      }
      if (seek_type i[j]["type"]==1||!preg_match("/^".pattern."/", i[j]["name"])) continue; // 如果不搜索當(dāng)前類型,跳過
      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[=
      * 刪除指定對象,文件或文件夾——包括內(nèi)含子目錄和文件的非空文件夾
      * @]Parameter[=
      * string path 指定要刪除的內(nèi)容路徑,文件或目錄均可
      * @]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; // 刪除目錄內(nèi)容出錯
      unset(i, j, k);
      return TRUE;
      }
      }

      /**
      * @]Method Name[= generate_path()
      * @]Purpose[=
      * 獲取現(xiàn)有或不存在文件、目錄的絕對地址
      * @]Parameter[=
      * string path 要獲取地址的文件、目錄現(xiàn)有相對、絕對地址
      * @]Return[= string 獲得的地址
      * @]Author[= SNakeVil <51JS,BU,PHPx> (snakevil@qq.com)
      * @]See[=
      */
      function generate_path(path="") {
      i = "/"==DIRECTORY_SEPARATOR ? "\\" : "/"; // 統(tǒng)一目錄分割符
      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)) { // 對剩余內(nèi)容處理
      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 目標(biāo)文件路徑
      * boolean interal 對于超過 1MB 文件,設(shè)置 FALSE 省去 MD5 檢驗步驟,減輕服務(wù)器負擔(dān)
      * @]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 效驗不符合,內(nèi)容不相同
      return TRUE;
      }

      /**
      * @]Method Name[= copy()
      * @]Purpose[=
      * 對任意文件夾、文件進行復(fù)制,相對或絕對路徑皆可,文件復(fù)制完成后會進行效驗,檢查是否出錯數(shù)據(jù)錯誤
      * @]Parameter[=
      * string src_path 指定要復(fù)制的源內(nèi)容路徑,文件或目錄均可
      * string dst_path 指定要復(fù)制的目標(biāo)內(nèi)容路徑,文件或目錄均可,性質(zhì)由 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)) { // 處理目錄
      /*
      * 關(guān)于算法的說明:
      * 本來打算使用很簡單的遞歸算法,遇神殺神,遇魔斬魔的,后來發(fā)現(xiàn)一個問題:如果目標(biāo)路徑
      * 為源路徑的后代路徑怎么辦?這樣算法會不停的探測下去…
      * 于是添加了 this->exist_dir 屬性,用來記錄這一情況下目標(biāo)路徑中存在的部分。于是新的問
      * 題出來了:如何保存這一屬性?
      * 將整個功能整合到 this->copy() 方法中,那么必然需要在這個函數(shù)中記錄 this->exist_dir
      * 的變化,于是乎需要另外的一個有效的方法來阻止每一次操作中對其的更改。
      * 作為變通,我使用的隱藏參數(shù) sub,這個參數(shù)無論如何,只要算法不變,永遠在參數(shù)表的最
      * 后一個。因此,方法開始變得不穩(wěn)定,但這也沒有辦法,只能希望程序員自己不要故意破壞。
      * 在外部調(diào)用時,因為默認 FALSE,所以對 this->exist_dir 寫。內(nèi)部遞歸時,顯性 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; // 源路徑為記錄的目標(biāo)路徑
      if (TRUE!==sub) this->exist_dir = ""; // 記錄創(chuàng)建目錄前目標(biāo)目錄路徑中存在的目錄路徑
      if (!this->make_dir(dst)) return FALSE; // 創(chuàng)建目錄
      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); // 復(fù)制文件失敗刪除新文件
      return this->error_occur(0x0007, dst);
      }
      return TRUE;
      }
      }

      /**
      * @]Method Name[= move()
      * @]Purpose[=
      * 對任意文件夾、文件進行移動,相對或絕對路徑皆可,文件移動完成后會進行效驗,檢查是否出錯數(shù)據(jù)錯誤
      * @]Parameter[=
      * string src_path 指定要移動的源內(nèi)容路徑,文件或目錄均可
      * string dst_path 指定要移動的目標(biāo)內(nèi)容路徑,文件或目錄均可,性質(zhì)由 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); // 對非目標(biāo)目錄的上層目錄,刪除
      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);
      }
      if (!@unlink(src)) return this->error_occur(0x0006, src); // 刪除源文件
      return TRUE;
      }
      }

      /**
      * @]Method Name[= no_comment()
      * @]Purpose[=
      * 清除文件中 C 規(guī)范的注釋
      * @]Parameter[=
      * string path 指定要執(zhí)行操作的文件
      * @]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); // 創(chuàng)建臨時文件
      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); // 文件讀取緩沖區(qū)
      tbuffer = ""; // 臨時文件緩沖區(qū)
      in_dq = in_sq = in_lc = in_bc = FALSE;
      while (fblen=strlen(fbuffer)) { // 處理原始數(shù)據(jù)
      fstats = feof(fh);
      for (i=0;i<fblen;i ) { // 分析文件內(nèi)容
      if (!fstats&&i 5>fblen) break; // 文件未完全讀取時臨近緩沖區(qū)讀取完成讀取下一塊文件內(nèi)容
      j = substr(fbuffer, i, 2);
      k = j[0];
      if (j=="/*"&&!in_dq&&!in_sq&&!in_lc) { // 不在字符串和行注釋中,塊注釋開始
      in_bc = TRUE;
      i ;
      } elseif (j=="*/"&&in_bc) { // 塊注釋結(jié)束
      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; // 行注釋結(jié)束
      elseif (j=="\\\\"||j=="\\\""||j=="\\'") { // 轉(zhuǎn)義字符
      tbuffer .= j;
      i ;
      continue;
      } elseif (k=="\""&&!in_sq&&!in_bc&&!in_lc) in_dq = !in_dq; // 雙引號字符串開始、結(jié)束
      elseif (k=="'"&&!in_dq&&!in_bc&&!in_lc) in_sq = !in_sq; // 單引號字符串開始、結(jié)束
      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) { // 寫入合法數(shù)據(jù)到臨時文件
      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)) { // 將臨時文件數(shù)據(jù)寫回源文件
      i = fgets(th, this->buffer_size);
      if (j=="") { // 獲得文件系統(tǒng)的換行符
      j= substr(i, -2);
      if (j=="\r\n") k = 2;
      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); // 保存、關(guān)閉文件
      ftruncate(fh, ftell(fh));
      fclose(th);
      flock(fh, LOCK_UN);
      fclose(fh);
      unset(i, j, k, fh, th);
      return TRUE;
      }
      }

      /**
      * @]Error List[=
      * 0x0001 指定目錄不存在
      * 0x0002 指定目錄無讀取權(quán)限
      * 0x0003 指定目錄無寫入權(quán)限
      * 0x0004 指定目錄無刪除權(quán)限
      * 0x0005 指定文件不存在
      * 0x0006 指定文件無讀取權(quán)限
      * 0x0007 指定文件無寫入權(quán)限
      * 0x0008 指定文件無刪除權(quán)限
      * 0x0009 指定文件無法鎖定
      * 0x000A 指定對象不存在
      * 0x000B 方法指定參數(shù)不正確
      * 0x000C 無法創(chuàng)建臨時文件
      * 0x000D 磁盤空間不足
      * 0x000E
      * 0x000F
      * 0x0010
      * 0x0011
      *
      */
      ?>

      分享:PHP廣告輪播效果詳細代碼
      網(wǎng)路廣告,變成了 Internet 上的熱門學(xué)問。而 468x60 更變成了廣告人員絞盡腦汁的尺寸。 在處理廣告時,若能直接使用瀏覽器將廣告的 468x60 圖檔送到處理廣告的伺服器中,相信是件很舒服的事,不用再開 FTP 程式,搞大半天只為了 upload。 這個問題,是所有 W

      來源:模板無憂//所屬分類:PHP教程/更新時間:2012-06-09
      相關(guān)PHP教程