【IT168 PHP开发】如果你来这里是想学习基本的PHP4或者PHP5知识,那这就是为你准备的,开始享受吧!
回到课堂
当你第一次开始阅读此系列教程时,我保证你能得到很多很多的乐趣。若你比较挑剔,那你可能感到我并没有信守诺言。毕竟,到目前为止,你真正得到了多少乐趣呢?所有你所做的就是学习一系列的理论规则,互相加及减数字,学习简单的决策制定且周而复始地在循环的圆形乐趣房里。如果这个不是PHP教程,那么它就是启蒙阶段的教育。
在我们正在进行的传奇故事的该章节中,我将教你如何做一些绝对不适合小孩子的事情。这些事情包含静下心来处理磁盘上的文件:见到文件、读取它们的内容且将数据写入文件中。所有这些令人兴奋的活动将发生在PHP非常酷的文件处理API的维护下,该API允许你察看及修改文件属性、读取及列出目录内容、改变文件权限、检索具有多种原始数据结构的文件内容且基于指定的模式来搜寻文件。
让我们开始吧!
小心处理
我将从一些简单的事情开始:打开一文件然后读取其内容。让我们假定在你的磁盘某处(比如隐藏在/usr/local/stuff/that/should/be/elsewhere/recipes/目录下),你有一文本文件,该文件包含完美的西班牙煎蛋的菜谱。你现在希望将该文件的内容读入PHP脚本中。
为了做这样一件事,需要三个清楚地步骤:
•打开文件且为其分配一文件句柄。
•通过其句柄与文件相互作用,且取出PHP变量中的其内容。
•关闭文件。
此处为展示该三个步骤的PHP脚本:
<?php // set file to read $file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt'
or
die('Could not open file!'); // open file $fh = fopen($file, 'r') or die('Could not open file!'); // read file contents $data = fread($fh, filesize($file)) or die('Could not read file!'); // close file fclose($fh); // print file contents echo $data; ?>
通过你的Web浏览器运行该脚本,且PHP应返回该文件的内容。
现在让我详细地解释上述三个步骤的每一个。
打开文件且为其分配一文件句柄
PHP需要一文件句柄以从一文件来读取数据。该文件句柄可用fopen()函数来建立,该fopen()函数接收两个参数:文件的名称及路径,以及一指示“模式”的字符串,在该“模式”中,文件被打开(‘r’用于读取)。
三个不同的模式可与fopen()函数一起使用,请参看以下列表:
•‘r’---以读取模式打开一文件。
•‘w’---以写入模式打开一文件,破坏现有的文件内容。
•‘a’---以附加模式打开一文件,保存现有的文件内容。
通过其句柄与文件相互作用且取出其内容放入PHP变量中
如果fopen()函数执行成功,那么它返回一个文件句柄$fh,该文件句柄$fh可用于进一步与文件交互作用。这个文件句柄被fread()函数使用,该fread()函数从文件读取数据然后将数据放到变量中。
fread()函数的第二个参数是要读取的字节数。你通常可以通过函数filesize()(它以字节返回文件的大小)来取得该信息。
关闭文件
最后一步并不是严格要求必须的,因为一旦PHP到达脚本的末端,其会自动关闭该文件,但它还是要养成好的习惯。用函数fclose()明确地关闭文件有两个优点:它在你的脚本中拴牢松散末尾,且它为你在PHP社区赢得很多好人缘。
你可能之前没有看到过die()函数。该函数大部分用做一个简单的错误处理机制。如果发生一个致命的错误(诸如,文件路径无效或者文件许可如此以至于PHP无法对其进行读取),die()函数终止脚本的进一步的处理然后随意的显示一条用户指定的错误信息,该错误信息指出为什么脚本终止执行。
不同的函数
一种从文件读取数据的替代方法就是非常酷的file()函数,该函数用一行代码将整个文件的数据读入到一个数组中(你还记得它们吗?)。然后数组的每个元素包含了文件中的一行数据。为了显示文件的内容,简单的使用foreach()循环对数组反复然后打印每一个数组元素。
下列例子给出了具体的示范:
<?php // set file to read $file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt'
or
die('Could not read file!'); // read file into array $data = file($file) or die('Could not read file!'); // loop through array and print each line foreach ($data as $line) { echo $line; } ?>
在这个例子中,file()命令打开该文件,将其数据以单一、优雅的运动方式读入到数组中,然后关闭文件。数组中的每一个元素现在都对应文件中的一行。现在可以很容易的打印文件的内容了,只需要使用数组处理的主要方法---foreach()循环即可。
不想将数据放入到数组中的吗?试试file_get_contents()函数,它是PHP 4.3.0和PHP 5.0中的新的功能,它将整个文件的内容读入到一个字符串中:
<?php // set file to read $file = '/usr/local/stuff/that/should/be/elsewhere/recipes/omelette.txt' ; // read file into string $data = file_get_contents($file) or die('Could not read file!'); // print contents echo $data; ?>
我在骗谁呢?我一直使用上述注解的一行函数而不是由fopen()、fread()和fclose()函数的三行序列。懒惰征服一切。
include()和requier()函数
PHP也提供了两种非常有用的函数以将文件引入到PHP脚本中:include()和requier()函数。这些函数可用于吸取外部文件锁,并将之存储及装入PHP脚本中,如果(例如)你有一模块化应用程序,该模块化应用程序将其代码分解到不同位置的不同文件中,该方法可非常容易地做到这一点。
理解include()和require()函数最好的方法就是使用例子。假定在你的Web站点上,你在每一个页面顶部都有一个标准的菜单条,在底部具有一个标准的版权声明。PHP权威仅仅为标题和页脚创建单独的文件,然后将它们引入到每个脚本的顶部和底部而不是在每个单独的页面中复制和粘贴标题和页脚的代码。这也使得对站点设计的改变更加容易实现:你不需要手工编辑大量的文件,你只要简单编辑两个文件即可,然后这些变化就立即反映到整个站点上。
让我们看一个起作用的真实鲜活的例子。在一个文件中创建标题,将其命名为:header.php:
<html> <head> <title><?php echo $page['title'];?></title> </head> <body> <!-- top menu bar --> <table width="90%" border="0" cellspacing="5" cellpadding="5"> <tr> <td><a href="#">Home</a></td> <td><a href="#">Site Map</a></td> <td><a href="#">Search</a></td> <td><a href="#">Help</a></td> </tr> </table> <!-- header ends -->
其次,在第二个文件中创建具有版权声明的页脚,footer.php:
<!-- footer begins --> <br /> <center>Your usage of this site is subject to its published
<a href="tac.html">terms and conditions</a>. Data is copyright Big Company Inc,
1995-<?php echo date("Y", mktime()); ?></center> </body> </html>
最后,创建一个显示站点主要内容的脚本,然后在适当的位置包含标题和页脚文件:
<?php // create an array to set page-level variables $page = array(); $page['title'] = 'Product Catalog'; /* once the file is imported, the variables set above will become available to it */ // include the page header include('header.php'); ?> <!-- HTML content here --> <?php // include the page footer include('footer.php'); ?>
现在,当你运行上述脚本时,PHP将会自动读取标题和页脚文件,将其和HTML内容合并在一起,然后将完整的页面显示给你。很简单,不是吗?
请注意,你甚至可以在被引入的文件中编写PHP代码。当文件第一次被读入时,解析器会寻找<?php...?>标签,然后自动执行其内部的代码。(如果你对JavaScript脚本语言熟悉的话,那么你可以使用该特征来重复类似于JavaScript中的onLoad()页面事件处理器功能的这种功能)。
PHP也提供了require_once()和include_once()函数,该等函数保证了已经被读入的文件不会再被读取。如果你面临你打算排除对由于性能原因或者为避免变量空间冲突的同样包含的文件的多次读取的情形,那么这两个函数可以派的上用场。
对include()和require()函数之间的差异的快捷解释:如果指定的文件没有找到,require()函数会返回一个致命错误并停止脚本的处理,而include()函数返回一个警告但允许脚本处理继续进行。
写文件
在你读完这些之后,你可能意识到读文件并不完全是脑力劳动。因此让我们开始一些稍微困难的事情:写文件。
将数据写入到文件的步骤和读取文件所需的步骤几乎是一致的:打开文件并得到文件句柄,然后使用文件句柄将数据写入文件,最后关闭文件。这里有两个差异:首先,你必须以写入的模式打开文件(‘w’代表写);其次,使用fwrite()函数写入文件句柄,而不是用fread()函数从文件句柄读取。请看下面的代码:
<?php // set file to write $file = '/tmp/dump.txt'; // open file $fh = fopen($file, 'w') or die('Could not open file!'); // write to file fwrite($fh, "Look, Ma, I wrote a file! ") or die('Could not write to file'); // close file fclose($fh); ?>
当你运行该脚本时,该脚本应该在目录/tmp下创建一个名字为dump.txt的文件,然后在其中写入一行文本,在其末尾加上回车。请注意,双引号需要被转换为回车。
fopen()、fwrite()和fread()函数是二进制安全的,也就是说你可以在二进制文件上使用这些函数而不用担心对文件内容的损害。
阅读更多关于不同平台下的二进制安全的文件操作方面的问题,请访问下列网址:http://www.php.net/manual/en/function.fopen.php
如果因为向你展示用于文件读取的一行快捷函数而宠坏了你的话,那么让我通过向你介绍file_put_contents()函数而进一步宠坏你吧,该函数是PHP5.0中的新特征,它接受一个字符串然后用一行代码将其写入到文件中。
<?php // set file to write $filename = '/tmp/dump.txt'; // write to file file_put_contents($filename, "Look, Ma, I wrote a file! ") or die('Could not write to file'); ?>
请记住,你试图创建文件的所在的目录必须在你对其写入文件之前存在。忘记这个重要的步骤是脚本错误常见的原因。
信息就是力量
PHP也提供了一系列允许你测试文件状态的函数,例如,发现文件是否存在、是否为空、是否可读或可写以及是二进制还是文本文件。在这些函数汇总中,最常用的操作符就是file_exists()函数,该函数它用于测试一特定文件是否存在。
下面是一个例子,它要求用户在Web表单中输入文件的路径,然后返回一条关于文件是否存在的消息:
<html> <head> </head> <body> <?php // if form has not yet been submitted // display input box if (!isset($_POST['file'])) { ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> Enter file path <input type="text" name="file"> </form> <?php } // else process form input else { // check if file exists // display appropriate message if (file_exists($_POST['file'])) { echo 'File exists!'; } else { echo 'File does not exist!'; } } ?> </body> </html>
这里有很多这样的函数。下面是一个简短的列表,后面跟着一个例子,该例子在上一个例子的基础上为用户指定的文件提供更多的信息。
•is_dir()- 返回一个指示指定路径是否是目录的Boolean值。
•is_file- 返回一个指示指定文件是否是合格的文件的Boolean值。
•is_link()-返回一个指示指定文件是否是符号链接的Boolean值。
•is_executable()-返回一个指示指定文件是否可执行的Boolean值。
•is_readable()-返回一个指示指定文件是否可读的Boolean值
•is_writable()-返回一个指示指定文件是否可写的Boolean值
•filesize()-得到文件的大小
•filemtime()-得到文件的最后修改时间
•filamtime()-得到文件的最后访问时间
•fileowner()-得到文件的所有者
•filegroup()-得到文件所属的组
•fileperms()-得到文件的许可
•filetype()-得到文件的类型
下面的脚本要求以文件名字作为输入然后使用上述函数返回该文件的信息
<html> <head> </head> <body> <?php /* if form has not yet been submitted, display input box */ if (!isset($_POST['file'])) { ?> <form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post"> Enter file path <input type="text" name="file"> </form> <?php } // else process form input else { echo 'File name: <b>'.$_POST['file'] .'</b><br />'; /* check if file exists and display appropriate message */ if (file_exists($_POST['file'])) { // print file size echo 'File size: '.filesize($_POST['file']).' bytes<br />'; // print file owner echo 'File owner: '.fileowner($_POST['file']).'<br />'; // print file group echo 'File group: '.filegroup($_POST['file']).'<br />'; // print file permissions echo 'File permissions: '.fileperms($_POST['file']).'<br />'; // print file type echo 'File type: '.filetype($_POST['file']).'<br />'; // print file last access time echo 'File last accessed on: '.date('Y-m-d', fileatime($_POST['file'])).'<br />'; // print file last modification time echo 'File last modified on: '.date('Y-m-d', filemtime($_POST['file'])).'<br />'; // is it a directory? if (is_dir($_POST['file'])) { echo 'File is a directory <br />'; } // is it a file? if (is_file($_POST['file'])) { echo 'File is a regular file <br />'; } // is it a link? if (is_link($_POST['file'])) { echo 'File is a symbolic link <br />'; } // is it executable? if (is_executable($_POST['file'])) { echo 'File is executable <br />'; } // is it readable? if (is_readable($_POST['file'])) { echo 'File is readable <br />'; } // is it writable? if (is_writable($_POST['file'])) { echo 'File is writable <br />'; } } else { echo 'File does not exist! <br />'; } } ?> </body> </html>
下面是程序的输出可能看上去的样子:
File name: /usr/local/apache/logs/error_log File size: 53898 bytes File owner: 0 File group: 0 File permissions: 33188 File type: file File last accessed on: 2004-05-26 File last modified on: 2004-06-20 File is a regular file File is readable
实例
现在你知道了如何读取文件,写文件以及测试其状态。让我们看看一些使用这些新发现的能力你所能做的例子。
让我们返回到我的西班牙煎蛋菜谱。让我们假定我非常慷慨,且我决定我想听听人们对我的烹调技巧的真实想法。因为我有一批烹饪菜谱想和大家分享,它们看起来就像下面所示的一样:
SPANISH OMELETTE INGREDIENTS: - 1 chopped onion - 1 chopped tomato - 1/2 chopped green pepper - 4 beaten eggs - Salt and pepper to taste METHOD: 1. Fry onions in a pan 2. Pour beaten eggs over onions and fry gently 3. Add tomatoes, green pepper, salt and pepper to taste 4. Serve with toast or bread
我需要一快速的方法以将菜谱转换为HTML以使得它们在我的Web站点上看起来像个样子。已经确定我是懒散的,因此用HTML重新创建菜谱会使我烦闷。相反,我将用PHP为我做这些繁重的体力活:
<html> <head></head> <body> <?php // read recipe file into array $data = file('/usr/local/stuff/that/should/be/elsewhere/omelette.txt')
or
die('Could not read file!'); /* first line contains title: read it into variable */ $title = $data[0]; // remove first line from array array_shift($data); ?> <h2><?php echo $title; ?></h2> <?php /* iterate over content and print it */ foreach ($data as $line) { echo nl2br($line); } ?> </body> </html>
我已使用file()函数来将菜谱读入到一个数组中,然后将菜谱的第一行(标题)赋值给一个变量。那个标题然后被打印在页面的顶部。因为剩余的数据十分像样,所以我可以将这些行一个接一个地简单打印到屏幕上。换行符通过使用非常酷的函数nl2br()可以被自动处理,该函数将一般的文本换行符转换为HTML中等价的<br/>标签。最终的结果就是:世界为之惊奇的我的菜单的HTML化版本。请看:
<html> <head></head><body> <h2>SPANISH OMELETTE </h2> INGREDIENTS:<br /> - 1 chopped onion<br /> - 1 chopped tomato<br /> - 1/2 chopped green pepper<br /> - 4 beaten eggs<br /> - Salt and pepper to taste<br /> METHOD:<br /> 1. Fry onions in a pan<br /> 2. Pour beaten eggs over onions and fry gently<br /> 3. Add tomatoes, green pepper, salt and pepper to taste<br /> 4. Serve with toast or bread<br /> </body> </html>
如果我的西班牙煎蛋菜谱的雅致和具有创造性的简单性让你无话可说,我一点儿也不惊奇,因为很多人都这么认为的。直到你听到你声音的回音:再见…而且确定你返回以完成PHP 101的第六章,该章讨论了如何创建你自己的可重用的函数。