前端學PHP之文件操做

前面的話

  在程序運行時,程序自己和數據通常都存在內存中,當程序運行結束後,存放在內存中的數據被釋放。若是須要長期保存程序運行所需的原始數據,或程序運行產生的結果,就須要把數據存儲在文件或數據庫。通常地,小型數據存儲在文件中,海量數據存儲在數據庫中。本文主要介紹php中目錄和文件的基本操做php

 

文件類型

  文件通常指存儲在外部介質上具備名字(文件名)的一組相關數據集合。用文件可長期保存數據,並實現數據共享html

  PHP是以UNIX的文件系統爲模型的。所以在Windows系統中咱們只能得到」file」、」dir」或者「unknown」三種文件類型。而在UNIX系統中,咱們能夠得到block、char、dir、fifo、file、link和unknown七種類型web

  可使用函數filetype()獲取文件的具體類型,可能的值有fifo,char,dir,block,link,file 和 unknown數據庫

string filetype ( string filename ) 

  若是出錯則返回 FALSE。若是調用失敗或者文件類型未知的話 filetype() 還會產生一個 E_NOTICE 消息windows

  在服務器中新建一個目錄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的文件內容改成每一行一個數字,分別是一、二、三、四、五、六、七、八、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成功地管理上傳文件,須要經過如下三方面信息:

  一、設置PHP配置文件中的指令:用於精細地調節PHP的文件上傳功能

  

  二、$_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)

  三、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'); ?>
相關文章
相關標籤/搜索