级别: 初级 Erik Zoltan (erik@zoltan.org), 高级系统工程师, EDS
2000 年 12 月 01 日 作为构建动态网页的一种语言,PHP 提供了一种简化的方法来构造复杂而功能强大的与 Web 相关的程序。Erik 用一个原始的、现实世界的网站示例逐步说明了 PHP 的基本原理。本系列文章分为两部分,第 1 部分介绍了 PHP 的基本概念,并分析了一个应用程序示例,Webzine。Webzine 包括内容提供者可输入文章文本的一个编辑页,以及用来将该内容展示给全世界的一个前端。
如果您是初次接触PHP,您可能会惊喜地发现在实践中它是多么易于使用。本文旨在使您对 PHP的工作方式留下一个好的印象; 随后您就可以确定它是否适合您。
有关 PHP 的经验
本系列文章分为两部分,第 1部分说明这个应用程序是如何工作的(不包含在您的系统上安装PHP)。您将有机会试用主索引页,并窥视一下部分组件在幕后是如何工作的。如果这是您唯一的动力,则请一定要查看
第 2部分,在那一部分将深入探讨有关主索引页的其他内容。(第 2部分还将用几个程序示例讨论编辑组件。您可以下载源代码并将您自己的想法付诸实施。)
如果您了解 HTML 并熟悉任何一种类似 C 语言的语言(尤其是Perl),则您理解下面的示例应该不成问题。 即使您没有太多使用过类似 C的语言,您仍然能够理解这些示例。但您
确实需要了解 HTML的基本知识。
这个 PHP 应用程序样例是一个生成阅读器的Webzine,它带有一个简单的发送模块(代码不超过3K)。该模块显示一个主题列表。在每个主题标题下是一系列按逆时间顺序排列的文章摘要。用户通过单击标题就可以看到整篇文章。还有一个稍复杂一点的编辑模块,它允许任何读者成为作者并提交他/她自己的内容。作者必须选择一个类别,并输入文章的标题、简单的摘要和故事的全文。如果愿意,您可以输入一个图像文件的URL 并单击“预览”按钮来检验是否一切已经就绪。作者的输入要经过验证--甚至要经过安全检查,这种安全检查将把除少数安全的标记以外的所有标记转换为非活动格式,从而防止危险或恶意的HTML 编码被执行。例如,字符串
<applet 将变为
<applet 。这种转换实际上使标记无效。
一项专用的 PHP 技术
在研究 Webzine的实际代码之前,让我们首先考虑一个简单的示例,这个示例很好地说明了PHP 的特征。PHP 的语法允许您任意将 HTML 语句与 PHP语句混合在一起。这意味着 HTML 语句可以出现在循环、if/else语句、函数等上下文中。我在 Webzine程序中利用了这一特性,但下面的代码样例用一种更简单的方法使它变得更简洁。
假定我们有两个数组,
$names 和
$days ,它们包含一年中各个月的信息,于是
$days[0]= 31 和
$names[0] ="January" ,
$days[1] 等于
28 和
$names[1] 等于
"February" ,等等。下面这项技术用来创建包含天数和月名的一个表:
清单 1:创建包含天数和月名的一个表
<table border=2>
<tr><th>Name</th><th>Days</th></tr>
<?php
for($i=0; $i<12; $i++) { // 循环开始。
?>
<tr><td><?php
echo($names[$i]) ?></td>
<td><?php
echo($days[$i]) ?></td></tr>
<?php
} // 循环结束。
?>
</table>
|
为明确起见,上面的 PHP 语句用红色显示;HTML语句用黑色显示。请注意,专用标记
<?php 从 HTML切换到 PHP,而
?> 切换回 HTML。
要注意的一点是:您可以切换到 PHP,开始一个
for 循环(或
if/else ,或
switch ,或其他语句),然后退回到HTML,现在您正在输入的 HTML命令将成为循环结构的一部分,所以它们随循环一起重复。您可以根据需要(例如,如我在上面所做的那样,发出echo 语句以将变量输出到网页中)进入或退出 PHP 模式。然后,当您退回PHP 并输入一个结束花括号时,正如您所料,循环结束。
实际表的外观如下所示:
| Name | Days | | January | 31 | | February | 28 | | March | 31 | | April | 30 | | May | 31 | | June | 30 | | July | 31 | | August | 31 | | September | 30 | | October | 31 | | November | 30 | | December | 31 |
应用程序概述
如果这种行为令人迷惑,则可以这样来考虑它:PHP 解释器将用
echo 语句替换 HTML模式中的每一行,以将该行送入输出流中。如果
echo 语句出现在
if/else 结构中,则它将是有条件执行的。如果它出现在一个循环结构中(如上所示),则它将重复执行。
Webzine驱动程序,index.php3,有三个主要的组件(要查看该驱动程序的
完整清单请参阅此处):主题菜单、故事列表和完整的故事表示。如果读者选定的主题没有任何故事,也会显示一些缺省的文本。编辑页(请查看
清单)更复杂。它包含一个表单、一个反馈消息和一个确认消息,表单用来接受用户的输入,反馈消息来通知作者需要纠正的问题,确认消息用来向作者显示他们所提交的内容。它还知道如何验证所提交的故事,进行必要的更改以确保内容中不包含任何未经认可的HTML,将故事保存在一个故事文件中,并更新这个故事相应的菜单文件。
试用 Webzine!
该应用程序有三种数据文件:
Category.txt包含一个简单的主题列表,故事就是在这里组织的。每个主题与一个主题菜单文件相关联。第一个主题必须是"Main",并与主题菜单文件 Main.txt 相关联。如果第二个主题是 "TheArts",则它与名为 TheArts.txt的主题菜单文件相关联。在
菜单文件中,每个故事的信息单独占一行:一个故事编号、一个标题、一个类别、一个简单的摘要,以及一个可选的图像URL。最后,
故事文件包含一个故事的实际正文。文件 s1.txt将包含第一个提交的故事,s2.txt包含第二个提交的故事,依此类推。如果您知道一个故事的编号(比如说 26号),则它的文件名很容易确定 (s26.txt)。
在您仔细研究这个应用程序之前,请首先试用它。
试用
Webzine驱动程序。它的左侧是一个主题列表,右侧是一个故事列表。您可以选择一个主题,或者选择"Main"来查看所有故事。首先出现的是最近的故事列表,第一组故事中如果有图像,同时也会显示这些图像。当您单击一个故事的标题时,就是出现一个包含该故事的完整正文的一个页面。
试用
编辑页(您也可以从Webzine 中试用它)。它提供一个表单,允许您提交一个故事。向 Webzine提交内容时,请注重大众的观念和好的品味。如果您录入程序不喜欢的内容,将显示一条错误消息。一旦故事被接受,您就可以返回Webzine 来查看它在读者面前是什么样子。
Webzine 驱动程序
现在您已经试用了应用程序,请继续阅读后面的部分以了解它的创建过程。
传递参数
index.php3 页允许传递参数,如下所示:
index.php3?topic=TradeShow&story=33
|
对于上面的调用,下面的变量赋值将在调用 index.php3之前自动进行:
$topic = "TradeShow";
$story = 33;
|
如果您忽略这些参数,则
$topic 和
$story 变量将不存在。您可以显式地对它们进行检测,或在您引用它们时让 PHP返回缺省的空值。
注:如果这个特性在您的系统上不起作用,请查看 php.ini文件,确保 register_globals = On。
网页标题
让我们首先查看许多 PHP应用程序中的一项常用技术;将某些种类的信息存入程序开头的变量赋值语句中。这样易于以后的维护和更新。
清单 2:变量赋值
<?php
$title = "PHP Demo Webzine";
$slogan = "Illustrating the coolness of PHP since September 2000";
?>
<html>
<head>
<title><?php
echo($title) ?></title>
</head>
<body>
<h1><?php
echo($title) ?></h1>
<p><i><?php
echo($slogan) ?></i></p>
|
同样,请注意 PHP 的边界标记:
<?php 使您从 HTML模式进入 PHP 模式,而
?> 切换回 HTML 模式。您可以来回切换任意次。某些操作在 HTML模式下较容易实现,而另外一些操作在 PHP模式下较容易实现。您所做的全部事情就是在程序开头定义两个变量,然后进入HTML 模式。当需要使用某个变量时,就退回 PHP 模式,并发出一条 echo语句将该变量的值直接写入网页正文中。
类别菜单
Category.txt文件只是主题名的一个列表,每个主题名单独占一行。例如,如果该文件只包含三项:
您将获得三个主题菜单文件:Main.txt、Politics.txt 和Technology.txt。一旦选定 "Main"主题,驱动程序就会出现,如下所示:
HTML 源代码如下所示:
<table border=1>
<tr><td bgcolor="pink"><center>
<b> Main </b></center></td></tr>
<tr><td bgcolor="silver"><center>
<b>
<a href="index.php3?topic=Politics">Politics</a> </b></center></td></tr>
<tr><td bgcolor="silver"><center>
<b>
<a href="index.php3?topic=Technology">Technology</a> </b></center></td></tr>
</table>
|
下面是从将 Category.txt 编译为上面所示的 HTML 代码片断的 PHP源代码中摘录出来的相关代码片断。首先,将文件 Category.txt读入一个数组
$cats :
<?php
$cats = file("category.txt");
$elems = count($cats);
?>
|
file 函数只是将文件复制到一个数组中。所以
$cats[0] 等于 "Main",
$cats[1] 等于"Politics" ,
$cats[2] 等于"Technology"。
file 函数使导入一个小 ASCII文本文件变得非常容易,但不要将它用于很大的文件。
count 函数统计数组中的元素个数,所以在本例中
$elems 应该等于3。
下面说明如何利用那个数组创建上面的 HTML 表:
清单 3:创建 HTML 表
<table border=1>
<?php
for ($i=0; $i<$elems; $i++) {
$item = trim($cats[$i]);
$ifile = ereg_replace(" ","",$item);
$color = ($ifile == $topic) ? "pink" : "silver";
$url = "index.php3?topic=$ifile";
$anchor = " " . ($item != $topic ? "<a href=\"$url\">$item</a>" : "$item") . " ";
echo(" <tr><td bgcolor=\"$color\"><center><b>$anchor</b></center></td></tr>\n");
}
?>
</table>
|
这个表以 HTML 模式开始和结束,但其大部分中间过程都处于 PHP模式下。现在我们逐行分析这个示例。 它以 HTML 模式开始(这是 PHP的正常开始模式)。表的边框宽度为 1:
现在,切换到 PHP 模式:
for 循环将从 0 开始,一直到元素的总数减 1为止(因为它使用的是 < 而不是 <=)。换句话说,如果有 3个元素,则将以 0/1/2 迭代它们:
for ($i=0; $i<$elems; $i++) {
|
trim 函数将删除前导/尾随空格并返回。这是必不可少的,因为用来读取类别文件内容的
file 函数将在每个类别名的最后保留尾随换行字符。所以这将把 "Politics\n"转换为 "Politics"。
下面是一个“搜索并替换”操作,用来去掉
$item 中的空格,并将结果存放在
$ifile 中。所以主题名 "TheArts" 将变为 "TheArts"。 在向网页传递参数(index.php3?topic=TheArts) 以及指定主题文件名(如TheArts.txt)时,主题名很有帮助。如果您没有必要关心空格,则会更加简单。
$ifile = ereg_replace(" ","",$item);
|
$color 的赋值使用三元运算符
?: (它有与C 类似的语法
test?truevalue:falsevalue ),以为选定的主题将
$color 变量设置为 pink 或者 silver。
$color = ($ifile == $topic) ? "pink" : "silver";
|
每个菜单项与一个 URL 相关联;所以如果主题为 "Politics",则 URL将为
index.php?topic=Politics 。PHP提供引号内的变量名替换。因此,在这个表达式中,
$ifile 变量的内容只在运行时替换引号中的
$ifile 。许多人发现这比用连接操作符显式地利用引号中的元素和变量名构建字符串更加容易。
$url = "index.php3?topic=$ifile";
|
在 PHP 中,句点操作符表示连接。我仍然使用
?: 运算符在此赋值操作中插入一个条件。如果当前项(比如说,Politics)不是选定的主题,则 anchor 是
<ahref="index.php?topic=Politics>Politics</a> 。如果选定的主题是 Politics,则 anchor 就是
Politics 。在任一种情况下,anchor 两侧都有空格。
$anchor = " " . ($item != $topic ? "<a href=\"$url\">$item</a>" : "$item") . " ";
|
下面的
echo 语句将指定的字符串插入输出流(即,HTML网页的正文)中。所以可以使用这条语句插入整个表行。在字符串中使用
\" 可以插入一个引号字符。上面计算出的
$color 和
$anchor 变量自动代入它们的引用位置:
echo(" <tr><td bgcolor=\"$color\"><center><b>$anchor</b></center></td></tr>\n");
|
for 循环的结束:
再次从 PHP 模式返回 HTML 模式:
类别菜单的 HTML 表的结束:
对程序创建过程的分析到此结束!
故事的表示
一旦选定一个故事,您就需要将这个故事的正文从故事文件打印到当前的网页上。(编辑模块author.php3 以正确的 HTML格式准备这个故事。)这是个简单的过程。在下面的代码段中,假定故事编号存储在变量
$story 中。如果
$story 等于33,则这个故事的文件为 s33.txt。
$storyfile = fopen("s$story.txt","r");
fpassthru($storyfile);
|
内容预告
在上例中,
fopen 函数打开一个文件,并返回该文件的一个句柄,然后通过赋值运算符将这个句柄保存在变量
$storyfile 中。
fpassthru 函数将文件的内容复制到当前的输出设备(输出 HTML文件),并自动关闭该文件。
本文(第 1 部分)介绍了 Webzine 这个简单 PHP应用程序的第一部分,并详细分析了几小段代码示例。(应用程序的这部分代码大小只有2K,所以没有许多
大型的代码示例供我们选择!)这应该使您对 PHP的强大功能有了很好的体验,但后面的内容还多着呢。
第 2 部分的篇幅与第 1部分大致相同。我将说明故事菜单的表示是如何呈现在读者面前的,从而完成对发送模块的讨论。然后我将讨论允许作者提交故事的编辑模块。虽然编辑模块比发送模块大得多,但我们不会如此详细地讨论它:我们只需要说明与发送模块不同的那些有趣概念。
参考资料
关于作者  | 
|  | Erik Zolt 从 1990
年就开始从事专业编程。他住在马萨诸塞州的
Leominster,是一名专职远程工作者。您可以给他发送电子邮件(地址为
erik@zoltan.org)或访问他的主页(网址为
www.zoltan.org)。Erik 开着一辆 1996 年的
Saturn,车身上绘制的是梵高的星夜。
|
对本文的评价
|