PHP技巧:PHP文件系統(tǒng)基本操作類_PHP教程
教程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
相關(guān)PHP教程:
- 相關(guān)鏈接:
- 教程說明:
PHP教程-PHP技巧:PHP文件系統(tǒng)基本操作類。