8.4文件的高级操作
8.4 文件的高级操作
除了对文件进行复制、删除、查找等常见操作外,利用PHP中的一些函数还可以对文件执行高级一点的操作,如修改文件的属性、锁定文件、包含文件等。
8.4.1 处理文件的锁定
或者都没有被保存?在实际应用中,经常会碰到两个或多个用户程序同时读写一个文件等类似的问题。如果一个文件被某个用户的程序打开写入一些内容,同时,另外一个用户也打开这个文件,向其中写入数据,那么文件的最终内容会是怎样的?哪个用户的程序写入的数据将被文件系统保存?还是两个写入的数据都会被保存?
为了解决这样的问题,保证文件中数据的完整有效,在操作文件时,需要对文件进行加锁操作。PHP通过函数flock完成对文件的锁定操作,语法如下。
bool flock($fp, int $operation [,int &wouldblock]);
该函数的第1个参数是文件的句柄;第2个参数表示锁定种类,它是一个常量;第3个参数是可选的,如果锁定会阻塞(即需要等待),该参数设置为TRUE。如果成功锁定了文件,该函数会返回TRUE,否则返回FALSE。下面重点介绍函数flock()的第2个参数,它代表了锁定文件的种类,表8-2列举了参数$operation的可能取值。
表8-2 函数flock()锁定种类参数$operation的取值

代码8-12是一个对文件进行锁定的示例小程序。
代码8-12 对文件进行锁定8-12.php
01 <?php
02 $fp = fopen($_SERVER["DOCUMENT_ROOT"]."/../data/lock_test.txt","w");
03
04 flock($fp,LOCK_EX); //
写锁定,独享锁定文件lock_test.txt
05 fwrite($fp,"Write Some Words....");
06 flock($fp,LOCK_UN); //
释放对文件lock_test.txt
的锁定
07
08 fclose($fp);
09 ?>
【代码解析】代码第04行使用参数LOCK_EX实现了对文件的独享锁定,使用锁定后,不要忘记再用参数LOCK_UN释放锁定,如第06行代码所示。
注意 如果在程序中,对某个文件操作时使用了函数flock()进行锁定,那么要对程序中所有对这个文件有操作的地方使用函数flock()进行锁定,否则锁定就无效。
8.4.2 更改文件的属性
更改文件的属性,主要涉及更改文件的模式、所有者和更改文件的组。通常,在UNIX系统下讨论这些问题才更有意义,相关函数如下。
·函数chgrp($filename,$group),用来将文件$filename所属的组改为$group(可以使用组名或组ID)。如果更改成功,函数返回TRUE,否则返回FALSE。
·函数chmod($filename,$mode),将文件$filename的模式改为$mode。这里的模式是指可读、可写和可执行。例如,在UNIX系统中,如果文件的模式为0777,表示所有用户对该文件可读、可写并且可执行。如下为该函数的一个示例代码。这行代码将文件/home/log/del.sh改为所有人可读、可写、可执行。
chmod( “/home/log/del.sh ”, 0777);
·函数chown($filename,$user),将文件$filename的所有者改为$user。如果更改成功,函数返回TRUE,否则函数返回FALSE。如下为该函数的一个示例代码。这行代码将文件/etc/passwd的所有者改为root。
chown( “/etc/passwd ”,”root ”);
8.4.3 获取文件时间属性
PHP提供了3个函数获取文件的时间属性,如文件的上次访问时间、文件的最后修改时间、取得文件的inode修改时间。这3个函数如下所述。
·函数fileatime(),返回文件上次被访问的时间,如果出错则返回FALSE,时间以UNIX时间戳的方式返回。
·函数filemtime(),返回文件上次被修改的时间,出错时返回FALSE,时间以UNIX时间戳的方式返回。
·函数filectime(),返回文件上次inode被修改的时间,如果出错则返回FALSE,时间以Unix时间戳的方式返回。inode是UNIX系统中的一个概念,其中文含义可以理解为索引节点,用来存放档案及目录的基本信息,包括时间、档案名、使用者及群组等。
代码8-13演示了这些函数的用法。
代码8-13 获取文件时间属性8-13.php
01 <?php
02 $last_access = fileatime("data.txt"); //
获取文件的上次访问时间
03 echo "
文件最后的访问时间是:";
04 echo date("l F d, Y", $last_access);
05 echo "<br>";
06 echo "<br>";
07
08 $last_modify = filemtime("data.txt"); //
获取文件的上次修改时间
09 echo "
文件最后的修改时间:";
10 echo date("l F d, Y", $last_modify);
11 echo "<br>";
12 echo "<br>";
13
14 $last_modify_inode = filectime("data.txt"); //
获取文件上次inode
被修改的时间
15 echo "
文件最后的改变时间:";
16 echo date("l F d, Y", $last_modify_inode);
17 echo "<br>";
18 echo "<br>";
19 ?>
【代码解析】代码8-13在当前目录下获取文件data.txt的时间属性,因为这些函数返回的时间值是UNIX时间戳,所以应先将时间戳格式化后再输出。代码8-13的执行结果如图8-14所示。

图8-14 获取文件的时间属性
8.4.4 通过HTTP协议打开文件
通过HTTP协议打开文件,就是使用函数fopen()打开一个远程文件,这和使用函数fopen()打开一个本地文件几乎没有区别。代码8-14说明了如何通过HTTP协议打开文件。
代码8-14 通过HTTP协议打开文件8-14.php
01 <?php
02 echo "<H3>
通过http
协议打开文件</H3>";
03 echo "<br/>";
04
05 if(!($file=fopen("http://localhost/ch06/server_data.txt","r")))//
通过HTTP
协议打开文件
06 {
07 echo "
文件不能打开";
08 exit;
09 }
10 while(!feof($file))
11 {
12 $line = fgetss($file, 255); //
按行读取文件中的内容
13 echo $line;
14 echo "<br/>";
15 }
16
17 fclose($file); //
关闭文件的句柄
18 ?>
【代码解析】代码首先通过函数fopen()打开本地HTTP服务路径下ch06目录中的server_data.txt文件,如代码第5行所示,这里也可以通过HTTP协议打开一个远程服务器的文件。如果找到该文件,则在没有达到文件末尾时,循环读出文件内容,如代码第10~15行所示。注意,这里使用函数fgetss()读取文件内容,该函数语法如下。
string fgetss(resource $handle)
函数fgetss()从参数$handle所指文件中读取一行内容,并将其中的HTML标记过滤掉,事实上,这也是它和函数fgets()的唯一不同之处。假如在程序所指目录下(代码第5行所示)存在一个名为server_data.txt的文件,其中内容如图8-15所示,那么8-14.php的执行结果就会如图8-16所示。
从图8-15和图8.16中可以看出,使用函数fopen()打开了一个文件,并且使用函数fgetss()获取文件内容后,原文件中的HTML标记都被删除。

图8-15 服务器上某文件内容

图8-16 通过HTTP协议打开文件后输出其内容
8.4.5 包含指定的文件到当前文件
这一小节要介绍两个比较重要的PHP语句——include()和require(),事实上,它们属于PHP流程控制方面的内容,之所以放在这里讲述,是因为它们涉及文件和函数的概念。
include()语句用来在当前文件中包含并运行指定文件。当一个文件被包含时,被包含文件中可用的任何变量、函数在被调用的文件中也都可用,所有在包含文件中定义的变量、函数或类都具有全局作用域。
下面举一个简单例子说明include()的用法,首先创建如代码8-15所示的PHP程序。
代码8-15 一个定义了变量和函数的PHP程序8-15.php
01 <?php
02 define(PI,3.14); //
定义PI
常量
03
04 $rad = 100;
05 $str = "include
的用法";
06
07 function cal_area($radius) //
定义计算面积的函数
08 {
09 $area = PI * $radius * $radius;
10 return $area;
11 }
12 ?>
【代码解析】程序8-15.php定义了一个常量PI、两个变量和一个函数,该PHP程序将被包含在另外一个PHP文件中。
接下来创建另外一个PHP程序,如代码8-16所示。
代码8-16 使用include()的PHP程序8-18.php
01 <?php
02 include("8-15.php"); //
包含进来指定的文件
03
04 echo $str;
05 echo "<br/>";
06 echo "<br/>";
07
08 $area = cal_area($rad); //
调用文件中的函数
09 echo "
在8-15.php
中计算半径为".$rad."
圆面积是:".$area;
10 ?>
【代码解析】代码首先使用include()语句,将此前创建的文件8-15.php包含在当前程序8-18.php中。此时,在8-15.php中定义的变量、函数都将在8-16.php中生效,凡是在8-15.php中定义的变量、函数都可以在8-16.php中使用。但需要注意的是这些变量和函数作用域是全局的,执行8-18.php,如果一切正常,将看到如图8-17所示的结果。

图8-17 在程序中使用include()语句
从这个执行结果可以看出,在8-16..php中输出的变量$str是在8-15中定义的,它在8-16.php中正常输出。然后8-16.php调用在8-15.php中定义的函数cal_area()计算了圆的面积,并将结果输出到页面。
在PHP程序中,除了使用include()包含指定的文件之外,还可以使用语句require()包含指定的文件到当前文件中。这两种结构用法完全一样,不同之处是它们对错误的处理,include()产生一个警告而require()则会导致一个致命错误。换句话说,如果想在遇到丢失文件时停止处理页面,就要使用require()。而这种情况下使用include(),脚本会继续运行。
和include()、require()对应的还有另外两个用来包含指定文件的语句,它们是include_once()和require_once()。它们和include()、require()语句类似,唯一区别是如果该文件中的代码已经被包含了,不会再次包含。它们的用法和include()语句的用法完全一样,这里不再重复举例。
上一篇:8.3文件和目录的通用操作
下一篇:8.5小结
