前面的話
在程序運行時,程序本身和數據一般都存在內存中,當程序運行結束后,存放在內存中的數據被釋放。如果需要長期保存程序運行所需的原始數據,或程序運行產生的結果,就需要把數據存儲在文件或數據庫。一般地,小型數據存儲在文件中,海量數據存儲在數據庫中。本文主要介紹php中目錄和文件的基本操作
文件類型
文件一般指存儲在外部介質上具有名字(文件名)的一組相關數據集合。用文件可長期保存數據,並實現數據共享
PHP是以UNIX的文件系統為模型的。因此在Windows系統中我們只能獲得”file”、”dir”或者“unknown”三種文件類型。而在UNIX系統中,我們可以獲得block、char、dir、fifo、file、link和unknown七種類型

可以使用函數filetype()獲取文件的具體類型,可能的值有fifo,char,dir,block,link,file 和 unknown
string filetype ( string filename )
如果出錯則返回 FALSE。如果調用失敗或者文件類型未知的話 filetype() 還會產生一個 E_NOTICE 消息
在服務器中新建一個目錄test,並在目錄中新建一個文件a.txt

<?php echo filetype('test/a.txt'); // file echo filetype('test/'); // dir echo filetype('test/b.txt'); // Warning: filetype(): Lstat failed for test/b.txt ?>
在這7種文件類型中,window系統常用的是'file'和'dir'這兩種,它們配套的類型檢測函數分別是is_dir( )和is_file( )
is_dir( )
判斷給定文件名是否是一個目錄。如果文件名存在並且是一個目錄則返回 true,否則返回 false
bool is_dir(_name)
is_file( )
判斷給定文件名是否為一個正常的文件,如果文件存在且為正常的文件則返回 true
bool is_file(_name)
<?php var_dump (is_file('test/a.txt')); //boolean true var_dump (is_dir('test/')); //boolean true ?>
文件屬性
一般地,在文件或目錄右鍵菜單中,選擇屬性,即可查看文件的屬性

下表中列出了php中關於文件屬性的常用函數

<?php var_dump (file_exists('test/a.txt')); //boolean true var_dump (filesize('test/a.txt')); // int 0 var_dump (is_readable('test/a.txt')); //boolean true var_dump (is_writeable('test/a.txt')); //boolean true var_dump (is_executable('test/a.txt')); //boolean false var_dump (date("Y-m-d H:i:s",(filectime('test/a.txt'))));//string '2016-11-22 06:47:54' (length=19) var_dump (date("Y-m-d H:i:s",(filemtime('test/a.txt'))));//string '2016-11-22 06:47:54' (length=19) var_dump (date("Y-m-d H:i:s",(fileatime('test/a.txt'))));//string '2016-11-22 06:47:54' (length=19) ?>
目錄路徑
windows下的目錄路徑使用是正斜杠(\),而unix下的目錄路徑使用是反斜杠(/)
$unixPath="/var/www/html/index.php"; //在UNIX系統中的絕對路徑,必須使用"/"分隔 $winPath="C:\\Appserv\\www\\index.php"; //在Windows系統的絕對路徑,默認使用"\"分隔 $winPath2="C:/Appserv/www/index.php"; //在Windows系統中也可使用“/”分隔
因為在Windows系統中也可使用(/)分隔。所以,在PHP中,不論是什么操作系統,全部都使用反斜杠(/)代表路徑分隔符號
在PHP中,還提供了一個常量DIRECTORY_SEPARATOR,以此來代表目錄分隔符,但寫起來較麻煩
<?php echo "c:".DIRECTORY_SEPARATOR."a".DIRECTORY_SEPARATOR."b".DIRECTORY_SEPARATOR."c"; //c:\a\b\c ?>
在windows下多個路徑的分隔符使用分號(;)分隔,而unix下使用冒號(:)分隔

在PHP中,提供了一個常量PATH_SEPARATOR,用來在跨平台的情況下,表示多個路徑之間的分隔符
<?php echo "aaa/ccc/ddd".PATH_SEPARATOR."/www/yyyy";//aaa/ccc/ddd;/www/yyyy ?>
換行
在window下,換行是\r\n,而在unix下,換行是\n。通常在寫程序中,換行就以unix為准,寫作\n
同樣地,PHP提供了一個常量PHP_EOL,用來在跨平台的情況下,表示換行
.和..
在PHP中,.表示當前目錄,..表示上一級目錄
<?php var_dump (file_exists('test/a.txt'));//boolean true var_dump (file_exists('./test/a.txt'));//boolean true var_dump (file_exists('../www/test/a.txt'));//boolean true ?>
根路徑
有兩種根路徑需要進行區分,一種是客戶端根路徑,一種是服務器根路徑
以我自己在d盤安裝的wamp為例,客戶端根路徑指'd:\wamp\www\',而服務器根路徑為為'd:\'
<?php echo '<img src="/a.jpg">';//客戶端根路徑,相當於d:\wamp\www\a.jpg mkdir('/hello');//服務器根路徑,相當於d:\hello ?>
路徑解析函數
【basename()】
basename()函數用於返回路徑中的文件名部分
<?php echo "1) ".basename("/etc/sudoers.d", ".d");//1) sudoers echo "2) ".basename("/etc/passwd").PHP_EOL;//2) passwd echo "3) ".basename("/etc/").PHP_EOL;//3) etc echo "4) ".basename(".").PHP_EOL;//4) . echo "5) ".basename("/");//5) ?>
【dirname()】
dirname()函數用於返回路徑中的目錄部分
<?php echo "1) " . dirname("/etc/passwd") . PHP_EOL; // 1) /etc echo "2) " . dirname("/etc/") . PHP_EOL; // 2) \ echo "3) " . dirname("."); // 3) . ?>
【pathinfo()】
pathinfo()函數用於返回文件路徑的信息
<?php $path_parts = pathinfo('/www/htdocs/inc/lib.inc.php'); echo $path_parts['dirname'], "\n";// '/www/htdocs/inc' 目錄名 echo $path_parts['basename'], "\n";// 'lib.inc.php' 文件名 echo $path_parts['extension'], "\n";// 'php' 文件后綴 echo $path_parts['filename'], "\n"; // 'lib.inc' 文件名不帶后綴 ?>
【realpath()】
realpath()函數用於返回規范化的絕對路徑名
在Windows上,realpath()會將unix風格的路徑改成Windows風格的
<?php echo realpath('/wamp');// 'D:\wamp' ?>
目錄遍歷
glob()
glob()函數用於尋找與模式匹配的文件路徑
array glob ( string $pattern [, int $flags = 0 ] )
在www目錄下新建a.txt和b.txt文件
<?php foreach (glob("*.txt") as $filename) { //a.txt size 1050 b.txt size 73 echo "$filename size " . filesize($filename) . "\n"; } ?>
opendir()
opendir()函數用於打開目錄句柄。如果成功則返回目錄句柄的resource,失敗則返回 FALSE
resource opendir ( string $path [, resource $context ] )
<?php var_dump(opendir('test'))//resource(3, stream) ?>
closedir()
closedir()函數用於關閉目錄句柄
void closedir ([ resource $dir_handle ] )
參數dir_handle表示目錄句柄的 resource,之前由 opendir()所打開的。如果目錄句柄沒有指定,那么會假定為是opendir()所打開的最后一個句柄
<?php $dir = opendir('test'); closedir($dir); ?>
readdir()
readdir()函數用於從目錄句柄中讀取條目,返回目錄中下一個文件的文件名。文件名以在文件系統中的排序返回,失敗時返回 FALSE
string readdir ([ resource $dir_handle ] )
在www目錄下新建目錄test,並在目錄test下新建a.txt和b.txt文件
<?php $dir = opendir('test'); echo readdir($dir)."<br>";//. echo readdir($dir)."<br>";//.. echo readdir($dir)."<br>";//a.txt echo readdir($dir)."<br>";//b.txt echo readdir($dir)."<br>";// closedir($dir); ?>
在遍歷目錄時,每個目錄的前兩個返回值都是.和..,.代表當前目錄,..代表上一級目錄
所以,一般地,列出當前目錄的所有文件並去掉 . 和 ..,常采用下面的代碼
<?php if ($handle = opendir('test')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { echo "$file\n"; } } closedir($handle); } ?>
接下來,在test目錄下,新建一個目錄in,並在in目錄中新建文件c.txt。然后,目錄和文件區分顯示
[注意]通過is_dir()函數判斷目錄時,需要加入路徑
<?php if ($handle = opendir('test')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file = "test/".$file; if(is_dir($file)){ echo "目錄:".$file."<br>"; }else{ echo "文件:".$file."<br>"; } } } closedir($handle); } /* 文件:test/a.txt 文件:test/b.txt 目錄:test/in */ ?>
rewinddir()
rewinddir()函數用於倒回目錄句柄,將參數dir_handle指定的目錄流重置到目錄的開頭
void rewinddir ( resource $dir_handle )
如果不使用rewinddir()函數,則文件只能遍歷一次
<?php if ($handle = opendir('test')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file = "test/".$file; if(is_dir($file)){ echo "目錄:".$file."<br>"; }else{ echo "文件:".$file."<br>"; } } } while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file = "test/".$file; if(is_dir($file)){ echo "目錄:".$file."<br>"; }else{ echo "文件:".$file."<br>"; } } } closedir($handle); } /* 文件:test/a.txt 文件:test/b.txt 目錄:test/in */ ?>
使用rewinddir()函數,可以把目錄句柄返回到第一個文件,從而實現重新遍歷
<?php if ($handle = opendir('test')) { while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file = "test/".$file; if(is_dir($file)){ echo "目錄:".$file."<br>"; }else{ echo "文件:".$file."<br>"; } } } rewinddir($handle); while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { $file = "test/".$file; if(is_dir($file)){ echo "目錄:".$file."<br>"; }else{ echo "文件:".$file."<br>"; } } } closedir($handle); } /* 文件:test/a.txt 文件:test/b.txt 目錄:test/in 文件:test/a.txt 文件:test/b.txt 目錄:test/in */ ?>
目錄統計
disk_total_space()
disk_total_space()函數返回一個目錄的磁盤總大小
float disk_total_space ( string $directory )
<?php $ds = disk_total_space("C:"); echo $ds."<br>";//126652637184 $ds = disk_total_space("D:"); echo $ds;//1000202240000 ?>
disk_free_space()
disk_free_space()函數返回目錄中的可用空間
float disk_free_space ( string $directory )
<?php $ds = disk_free_space("C:"); echo $ds."<br>";//86087041024 $ds = disk_free_space("D:"); echo $ds;//481647472640 ?>
下面來統計在www文件夾下新建的test目錄的個數
<?php $dirn = 0; //目錄數 $filen = 0; //文件數 //統計一個目錄下的文件和目錄的個數 function getdirnum($file) { global $dirn; global $filen; $dir = opendir($file); while (false !== ($filename = readdir($dir))) { if($filename!="." && $filename !="..") { $filename = $file."/".$filename; //更新路徑 if(is_dir($filename)) { $dirn++; getdirnum($filename); //遞歸,就可以查看所有子目錄 } else { $filen++; } } } closedir($dir); } getdirnum("test"); echo "目錄數為:{$dirn}<br>";//目錄數為:1 echo "文件數為:{$filen}<br>";//文件數為:3 ?>
下面來統計在www文件夾下新建的test目錄的大小
<?php //統計目錄大小 function dirsize($file) { $size = 0; $dir = opendir($file); while(false !== ($filename = readdir($dir))) { if($filename!="." && $filename !="..") { $filename = $file."/".$filename; if(is_dir($filename)) { $size += dirsize($filename);//使用遞歸 } else { $size += filesize($filename); } } } closedir($dir); return $size; } echo "test目錄大小為:".dirsize("test")."<br>";//test目錄大小為:302 ?>

目錄增刪
mkdir()
mkdir()函數用於新建目錄
bool mkdir ( string $pathname [, int $mode = 0777 [, bool $recursive = false [, resource $context ]]] )
rmdir()
rmdir()函數用於刪除目錄
bool rmdir ( string $dirname [, resource $context ] )
[注意]該目錄必須是空的,而且要有相應的權限。失敗時會產生一個 E_WARNING 級別的錯誤
unlink()
unlink()函數用於刪除文件
bool unlink ( string $filename [, resource $context ] )
下面來清空test目錄
<?php function deldir($dirname) { //如果是文件,直接刪除即可 if(is_file($dirname)) { unlink($dirname); } $dir = opendir($dirname); while(FALSE !== ($filename = readdir($dir))) { if($filename !="." && $filename!="..") { $filename = $dirname."/".$filename; if(is_dir($filename)) { deldir($filename);//遞歸 }else { unlink($filename);//刪除文件 } } } closedir($dir); if($dirname != 'test'){ rmdir($dirname);//刪除目錄 } } deldir("test"); ?>
目錄復制
copy()
copy()函數用於拷貝文件
bool copy ( string $source , string $dest [, resource $context ] )
[注意]copy()函數不能用於復制目錄
<?php $file = 'a.txt'; $newfile = 'a.bak'; copy($file, $newfile); ?>
rename()
rename()函數用於重命名一個文件或目錄
bool rename ( string $oldname , string $newname [, resource $context ] )
[注意]rename()函數具有移動文件或目錄的功能
下面把www目錄下的test目錄剪貼,命名為t,並移動到d盤目錄下
<?php rename("test", "d:/t"); ?>
使用rename()只能實現剪切的操作,使用copy()只能復制文件。如果要復制目錄,則需要使用循環和遍歷
<?php /** * $dirsrc 原目錄 * $dirto 目標目錄 */ function copydir($dirsrc, $dirto) { //如果目錄不存在,則新建一個目錄 if(!file_exists($dirto)) { mkdir($dirto); } $dir = opendir($dirsrc); while(FALSE !== ($filename = readdir($dir))) { if($filename != "." && $filename !="..") { $srcfile = $dirsrc."/".$filename; //原文件 $tofile = $dirto."/".$filename; //目標文件 if(is_dir($srcfile)) { copydir($srcfile, $tofile); //遞歸處理所有子目錄 }else{ copy($srcfile, $tofile);//復制文件 } } } } copydir("test", "d:/t"); ?>
文件操作
touch()
touch()函數用來設定文件的訪問和修改時間。如果文件不存在,則會被創建。成功時返回 TRUE, 或者在失敗時返回 FALSE
bool touch ( string $filename [, int $time = time() [, int $atime ]] )
參數filename表示要設定的文件名,time表示要設定的時間。如果沒有提供參數 time 則會使用當前系統的時間;atime表示如果給出了這個參數,則給定文件的訪問時間會被設為atime,否則會設置為time。如果沒有給出這兩個參數,則使用當前系統時間
<?php touch('abc.txt') ?>
copy()
copy()函數用於拷貝文件
bool copy ( string $source , string $dest [, resource $context ] )
[注意]copy()函數不能用於復制目錄
<?php $file = 'a.txt'; $newfile = 'a.bak'; copy($file, $newfile); ?>
rename()
rename()函數用於重命名一個文件或目錄
bool rename ( string $oldname , string $newname [, resource $context ] )
[注意]rename()函數具有移動文件或目錄的功能
<?php rename("abc.txt", "d:/cba.txt"); ?>
unlink()
unlink()函數用於刪除文件
bool unlink ( string $filename [, resource $context ] )
<?php unlink("d:/cba.txt"); ?>
文件內容
fopen()
fopen()函數用於打開文件或者URL,fopen()將 filename 指定的名字資源綁定到一個流上
[注意]如果文件不存在,將新建並打開文件
fopen('test.png',w);
fopen() 中 mode 的可能值列表
mode 說明 'r' 只讀方式打開,將文件指針指向文件頭。 'r+' 讀寫方式打開,將文件指針指向文件頭。 'w' 寫入方式打開,將文件指針指向文件頭並將文件大小截為零。如果文件不存在則嘗試創建之。 'w+' 讀寫方式打開,將文件指針指向文件頭並將文件大小截為零。如果文件不存在則嘗試創建之。 'a' 寫入方式打開,將文件指針指向文件末尾。如果文件不存在則嘗試創建之。 'a+' 讀寫方式打開,將文件指針指向文件末尾。如果文件不存在則嘗試創建之。
<?php //使用絕對路徑打開file.txt文件,選擇只讀模式,並返回資源$handle $handle = fopen("/home/rasmus/file.txt", "r"); //訪問文檔根目錄下的文件,也以只讀模式打開 $handle = fopen(“{$_SERVER['DOCUMENT_ROOT']}/data/info.txt", "r"); //在 Windows 平台上,轉義文件路徑中的每個反斜線,或者用斜線, 以二進制和只寫模式組合 $handle = fopen("c:\\data\\file.gif", "wb"); //使用相對路徑打開file.txt文件,選擇只讀模式,並返回資源$handle $handle = fopen("../data/info.txt", "r"); //打開遠程文件, 使用HTTP協議只能以只讀的模式打開 $handle = fopen("http://www.example.com/", "r"); //使用FTP協議打開遠程文件,如果FTP服務器可寫,則可以以寫的模式打開 $handle = fopen("ftp://user:password@example.com/somefile.txt", "w"); ?>
fclose()
fclose()函數用於關閉一個已打開的文件指針
bool fclose ( resource $handle )
<?php $handle = fopen('test/a.txt', 'r'); fclose($handle); ?>
fwrite()
fwrite()函數用於寫入文件(可安全用於二進制文件),返回寫入的字符數,出現錯誤時則返回 FALSE
int fwrite ( resource $handle , string $string [, int $length ] )
當打開方式為只讀模式時,無法向文件寫入字符
<?php $fp = fopen('test/a.txt', 'r'); echo fwrite($fp, '1');//0 echo "<br>"; echo fwrite($fp, '23');//0 echo "<br>"; fclose($fp); ?>
當打開方式為寫模式時,可以向文件寫入字符
<?php $fp = fopen('test/a.txt', 'w'); echo fwrite($fp, '1');//1 echo "<br>"; echo fwrite($fp, '23');//2 echo "<br>"; fclose($fp); /* 文件內容為123 */ ?>
當打開方式為追加模式時,將向文件的尾部追加新的字符
<?php $fp = fopen('test/a.txt', 'a'); echo fwrite($fp, '1');//1 echo "<br>"; echo fwrite($fp, '23');//2 echo "<br>"; fclose($fp); /* 刷新兩次時,文件內容為123123 */ ?>
fgetc()
fgetc()函數用於從文件指針中讀取字符
[注意]使用fgetc()函數時,需要在fopen()函數中使用讀模式
string fgetc ( resource $handle )
<?php $fp = fopen('test/a.txt', 'r'); echo fgetc($fp);//1 echo fgetc($fp);//2 echo fgetc($fp);//3 fclose($fp); ?>
feof()
feof()函數用於測試文件指針是否到了文件結束的位置
bool feof ( resource $handle )
<?php $fp = fopen('test/a.txt', 'r'); while(!feof($fp)){ echo fgetc($fp);//123123 } fclose($fp); ?>
fgets()
fgets()函數用於從文件指針中讀取一行
string fgets ( resource $handle [, int $length ] )
將test目錄下的a.txt文件內容修改為
aa
bbb
<?php $fp = fopen('test/a.txt', 'r'); echo fgets($fp);//'aa' echo fgets($fp);//'bbb' echo fgets($fp);//'' fclose($fp); ?>
fread()
fread()函數用於讀取文件(可安全用於二進制文件)。fread()從文件指針handle讀取最多length個字節。該函數在讀取了length個字節或到達了文件末尾(EOF)時將停止讀取文件
string fread ( resource $handle , int $length )
<?php $fp = fopen('test/a.txt', 'r'); echo fread($fp,3);//'aa ' fclose($fp); $fp = fopen('test/a.txt', 'r'); echo fread($fp,filesize('test/a.txt'));//'aa bbb' fclose($fp); ?>
fseek()
fseek()函數用於在文件指針中定位,成功則返回 0;否則返回 -1
int fseek ( resource $handle , int $offset [, int $whence = SEEK_SET ] )
將test目錄下的a.txt文件內容修改為'12345'
<?php $fp = fopen('test/a.txt', 'r'); echo fgetc($fp);//'1' fseek($fp,4); echo fgetc($fp);//'5' fclose($fp); ?>
<?php $fp = fopen('test/a.txt', 'r'); echo fread($fp,2)."<br>";//12 fseek($fp,4); echo fread($fp,2)."<br>";//5 fseek($fp,-3,SEEK_END); echo fread($fp,2)."<br>";//34 fclose($fp); ?>
ftell()
ftell()函數用於返回文件指針讀/寫的位置
int ftell ( resource $handle )
<?php $fp = fopen('test/a.txt', 'r'); echo ftell($fp);//0 fgetc($fp); echo ftell($fp);//1 fseek($fp,4); echo ftell($fp);//4 fclose($fp); ?>
rewind()
rewind()函數用於倒回文件指針的位置,將handle的文件位置指針設為文件流的開頭
bool rewind ( resource $handle )
<?php $fp = fopen('test/a.txt', 'r'); fseek($fp,2); echo ftell($fp);//2 rewind($fp); echo ftell($fp);//0 ?>
file_get_contents()
file_get_contents()函數用於將整個文件讀入一個字符串
string file_get_contents ( string $filename [, bool $use_include_path = false [, resource $context [, int $offset = -1 [, int $maxlen ]]]] )
<?php $homepage = file_get_contents('test/a.txt'); echo $homepage;//'12345' ?>
頁面變為百度首頁
<?php $homepage = file_get_contents('http://www.baidu.com/'); echo $homepage; ?>
file_put_contents()
file_put_contents()函數用於將一個字符串寫入文件
int file_put_contents ( string $filename , mixed $data [, int $flags = 0 [, resource $context ]] )
使用該函數和依次調用 fopen(),fwrite() 以及 fclose() 功能一樣
[注意]默認為寫模式,若設置第三個參數為FILE_APPEND,則變為追加模式
<?php file_put_contents('test/a.txt','abc'); ?>
readfile()
readfile()函數用於讀取文件並寫入到輸出緩沖
int readfile ( string $filename [, bool $use_include_path = false [, resource $context ]] )
<?php readfile('http://www.baidu.com/');//頁面中顯示百度首頁 ?> <?php readfile('test/a.txt');//頁面中顯示abc ?>
file()
file()函數用於把整個文件讀入一個數組中,每一行作為一個數組的元素
array file ( string $filename [, int $flags = 0 [, resource $context ]] )
將a.txt的文件內容改為每一行一個數字,分別是1、2、3、4、5、6、7、8、9
<?php $arr = file('test/a.txt',0); echo $arr[0]."<br>";//1 echo count($arr);//9 ?>
ftruncate()
ftruncate()函數用於將文件截斷到給定的長度
bool ftruncate ( resource $handle , int $size )
[注意]使用ftruncate()函數時,需要使用追加模式。經測試,使用讀模式時無效,使用寫模式時,文件內容被清空
<?php $fp = fopen("test/a.txt","a"); ftruncate($fp,100); ?>
【新建文件】
php中並沒有專門的新建一個空文件的函數,但是可以利用fopen()和touch()方法實現
$file = fopen('a.png',w);
fclose($file);
touchu('a.png');
文件鎖定
文件操作是在網絡環境下完成的,可能有多個客戶端用戶在同一時刻對服務器上的同一個文件訪問。當這種並發訪問發生時,很可能會破壞文件中的數據。例如,一個用戶正向文件中寫入數據,還沒有寫完時,其他用戶在這一時刻也向這個文件寫入數據,就會造成數據寫入混亂。還有,當用戶沒有將數據寫完時,其他用戶就去獲取這個文件中的內容,也會得到殘缺的數據
在PHP中提供了flock()函數,可以對文件使用鎖定機制(鎖定或釋放文件)。當一個進程在訪問文件時加上鎖,其他進程想對該文件進行訪問,則必須等到鎖定被釋放以后。這樣就可以避免在並發訪問同一個文件時破壞數據
語法: bool flock ( int handle, int operation [, int &wouldblock] )
PHP支持以咨詢方式(也就是說所有訪問程序必須使用同一方式鎖定,否則它不會工作)鎖定全部文件的一種輕便方法
handle 必須是一個已經打開的文件指針
operation 可以是以下值之一:
要取得共享鎖定(讀取程序),將 operation 設為 LOCK_SH
要取得獨占鎖定(寫入程序),將 operation 設為 LOCK_EX
要釋放鎖定(無論共享或獨占),將 operation 設為 LOCK_UN
如果不希望flock()在鎖定時堵塞,則給 operation 加上 LOCK_NB
如果成功則返回 TRUE,失敗則返回 FALSE
下面是一個網絡留言本的示例,一方面應用鎖機制,另一方面綜合地使用PHP中文件操作的內容
<?php header("Content-Type:text/html;charset=utf8"); //功能類似於數據庫的文件 $filename = "message.txt"; //檢查函數 function test_input($data) { $data = trim($data); $data = stripslashes($data); $data = htmlspecialchars($data); return $data; } //如果用戶提交了,就按一定格式寫入文件 if(isset($_POST['dosubmit'])) { $name = test_input($_POST['username']); $content = test_input($_POST['content']); //字段的分隔使用||,行的分隔使用[n] $mess = "$name||$content||".time()."[n]"; //調用寫信息函數 writemessage($filename, $mess); } //如果文件存在,則讀文件內容 if(file_exists($filename)) { readmessage($filename); } //寫函數 function writemessage($filename, $mess) { global $name,$content; //以追加模式打開文件 $fp = fopen($filename, "a"); //如果鎖定成功 if(flock($fp, LOCK_EX+LOCK_NB)) { //將數據寫入文件 if($name && $content){ fwrite($fp, $mess); } //釋放鎖定 flock($fp, LOCK_UN+LOCK_NB); }else{ echo "寫入鎖定失敗!"; } //關閉文件 fclose($fp); } //讀函數 function readmessage($filename) { //以只讀模式打開文件 $fp = fopen($filename, "r"); //讀鎖定 flock($fp, LOCK_SH+LOCK_NB); $mess = ""; //將數據遍歷到$mess中 while(!feof($fp)) { $mess.=fread($fp, 1024); } //釋放鎖定 flock($fp, LOCK_UN+LOCK_NB); if(!empty($mess)){ $mess = rtrim($mess, "[n]"); //通過[n]將每行留言分割並存入數組中 $arrmess = explode("[n]", $mess); foreach($arrmess as $m) { //將每行數據使用'||'分割 list($username,$content,$t) = explode("||", $m); date_default_timezone_set('PRC'); echo "<b>{$username}</b>說:<u>{$content}</u>(".date('Y-m-d H:i:s',$t).")<hr><br>"; } } //關閉文件 fclose($fp); } ?> <form action="message.php" method="post"> 用戶:<input type="text" name="username" value="" /><br> 內容:<textarea name="content" cols="22" rows="3"></textarea><br> <input type="submit" name="dosubmit" value="留言" /><br> </form>
文件上傳
要想通過PHP成功地管理上傳文件,需要通過以下三方面信息:
1、設置PHP配置文件中的指令:用於精細地調節PHP的文件上傳功能
2、$_FILES多維數組:用於存儲各種與上傳文件有關的信息,其他數據還使用$_POST去接收
$_FILES["myfile"]["name"]中的值是:客戶端文件系統的文件的名稱
$_FILES["myfile"]["type"]中的值是:客戶端傳遞的文件的類型
$_FILES["myfile"]["size"]中的值是:文件的字節的大小
$_FILES["myfile"]["tmp_name"]中的值是:文件被上傳后在服務器存儲的臨時全路徑
$_FILES["myfile"]["error"]中的值是:文件上傳的錯誤代碼(php 4.2以后增加的功能)
伴隨文件上傳時產生的錯誤信息代碼具體如下:
值為0(UPLOAD_ERR_OK):表示沒有發生任何錯誤
值為1(UPLOAD_ERR_INI_SIZE):表示上傳文件的大小超出了約定值。文件大小的最大值是在PHP配置文件中指定的,該指令是:upload_max_filesize
值為2(UPLOAD_ERR_FORM_SIZE):表示上傳文件大小超出了HTML表單隱藏域屬性的MAX_FILE_SIZE元素所指定的最大值
值為3(UPLOAD_ERR_PARTIAL):表示文件只被部分上傳
值為4(UPLOAD_ERR_NO_FILE):表示沒有上傳任何文件
值為6(UPLOAD_ERR_NO_TMP_DIR):表示找不到臨時文件夾(PHP4.3.10和PHP5.0.3)
值為7(UPLOAD_ERR_CANT_WRITE):表示文件寫入失敗(PHP 5.1.0)
3、PHP的文件上傳處理函數:用於上傳文件的后續處理
只要把臨時目錄下的上傳的文件,復制到指定目錄下指定的名字就可以完成上傳
PHP提供了專門用於文件上傳所使用的is_uploaded_file()和move_uploaded_file()函數
【is_uploaded_file()】
is_uploaded_file()判斷文件是否是通過 HTTP POST 上傳的
bool is_uploaded_file ( string $filename )
如果filename
所給出的文件是通過 HTTP POST 上傳的則返回 TRUE
。這可以用來確保惡意的用戶無法欺騙腳本去訪問本不能訪問的文件
[注意]為了能使is_uploaded_file() 函數正常工作,必須使用$_FILES['userfile']['tmp_name'],而在從客戶端上傳的文件名$_FILES['userfile']['name']不能正常運作
【move_uploaded_file()】
move_uploaded_file()方法用於將上傳的文件移動到新位置
bool move_uploaded_file ( string $filename , string $destination )
本函數檢查並確保由 filename
指定的文件是合法的上傳文件(即通過 PHP 的 HTTP POST 上傳機制所上傳的)。如果文件合法,則將其移動為由 destination
指定的文件
該函數成功時返回TRUE;
如果filename
不是合法的上傳文件,不會出現任何操作,move_uploaded_file()將返回 FALSE;
如果 filename
是合法的上傳文件,但出於某些原因無法移動,不會出現任何操作,move_uploaded_file()將返回 FALSE
。此外還會發出一條警告
<?php header("Content-Type:text/plain;charset=utf-8"); //判斷錯誤 if($_FILES['file1']['error'] > 0) { switch($_FILES['file1']['error']) { case 1: case 2: echo "上傳文件太大"; break; case 3: echo "文件只被部分上傳"; break; case 4: echo "沒有上傳任何文件"; break; default: echo "末知錯誤"; } exit; } //判斷類型 $arr = explode(".", basename($_FILES['file1']['name'])); $hz = array_pop($arr); $allowtype =array("gif", "png", "jpg", "jpeg"); if(!in_array($hz, $allowtype)) { echo "上傳的類型不合法"; exit; } //判斷大小 $maxsize= 1000000; if($_FILES['file1']['size'] > $maxsize) { echo "上傳的文件超過了{$maxsize}字節!"; exit; } //隨機文件名 $tmp_name = $_FILES['file1']['tmp_name']; $src_name = "./uploads/".date("YmdHis").rand(100, 999).".".$hz; if(move_uploaded_file($tmp_name, "$src_name")){ echo '上傳成功'; }else{ echo '上傳失敗'; } ?>
文件下載
簡單的文件下載只需要使用HTML的鏈接標記<a>,並將屬性href的URL值指定為下載的文件即可
<a href="http://baidu.com/test/book.rar">下載</a>
如果通過上面的代碼實現文件下載,只能處理一些瀏覽器不能默認識別的MIME類型文件,如訪問book.rar時,瀏覽器沒有直接打開,而是彈出一個下載提示框,提示用戶下載還是打開。如果需要下載'.html'、圖片文件等瀏覽器識別的MIME類型文件時,瀏覽器將直接打開該文件
常見數據格式(MIME)如下
為了提高文件的安全性,不希望在<a>標簽中給出文件的鏈接,則必須向瀏覽器發送必要的頭信息,以通知瀏覽器將要進行下載文件的處理
【header()】
PHP使用header()函數發送網頁的HTTP頭部信息
void header ( string $string [, bool $replace = true [, int $http_response_code ]] )
[注意]header() 必須在任何實際輸出之前調用
<?php
//該行不是必須的
header('Content-type: image/png');
//將文件設置為附件格式(瀏覽器只會下載而不會打開附件格式),設置下載時顯示的文件名
header('Content-Disposition: attachment; filename="downloaded.png"');
//讀取文件並寫入到輸出緩沖
readfile('./uploads/20170315085246943.png'); ?>