PHP例解Webzine编辑和发送
时间:2007-02-17 来源:PHP爱好者
作为构建动态网页的一种语言,PHP提供了一种简化的方法来构造复杂而功能强大的 与 Web 相关的程序。Erik用一个原始的、现实世界的网站示例逐步说明了 PHP 的基本原理。本系列文章分为两部分,第 1 部分介绍了 PHP的基本概念,并分析了一个应用程序示例,Webzine。Webzine 包括内容提供者可输入文章文本的一个编辑页,以及用来将该内容展示给全世界的一个前端。
如果您是初次接触PHP,您可能会惊喜地发现在实践中它是多么易于使用。本文旨在使您对 PHP的工作方式留下一个好的印象; 随后您就可以确定它是否适合您。
1.有关PHP的经验
本系列文章分为两部分,第1部分说明这个应用程序是如何工作的(不包含在您的系统上安装PHP)。您将有机会试用主索引页,并窥视一下部分组件在幕后是如何工作的。如果这是您唯一的动力,则请一定要查看下一篇,在那一部分将深入探讨有关主索引页的其他内容。(第 2部分还将用几个程序示例讨论编辑组件。您可以下载源代码并将您自己的想法付诸实施。)
如果您了解 HTML 并熟悉任何一种类似 C 语言的语言(尤其是Perl),则您理解下面的示例应该不成问题。 即使您没有太多使用过类似C的语言,您仍然能够理解这些示例。但您确实需要了解 HTML的基本知识。
这个 PHP 应用程序样例是一个生成阅读器的Webzine,它带有一个简单的发送模块(代码不超过3K)。该模块显示一个主题列表。
在每个主题标题下是一系列按逆时间顺序排列的文章摘要。用户通过单击标题就可以看到整篇文章。还有一个稍复杂一点的编辑模块,它允许任何读者成为作者并提交他/她自己的内容。作者必须选择一个类别,并输入文章的标题、简单的摘要和故事的全文。如果愿意,您可以输入一个图像文件的URL 并单击“预览”按钮来检验是否一切已经就绪。作者的输入要经过验证--甚至要经过安全检查,这种安全检查将把除少数安全的标记以外的所有标记转换为非活动格式,从而防止危险或恶意的HTML 编码被执行。例如,字符串 将变为。这种转换实际上使标记无效。
2.一项专用的 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语句用黑色显示。请注意,专用标记 从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 结构中,则它将是有条件执行的。如果它出现在一个循环结构中(如上所示),则它将重复执行。
3.应用程序概述
Webzine驱动程序,index.php3,有三个主要的组件:主题菜单、故事列表和完整的故事表示。如果读者选定的主题没有任何故事,也会显示一些缺省的文本。编辑页更复杂。它包含一个表单、一个反馈消息和一个确认消息,表单用来接受用户的输入,反馈消息来通知作者需要纠正的问题,确认消息用来向作者显示他们所提交的内容。它还知道如何验证所提交的故事,进行必要的更改以确保内容中不包含任何未经认可的HTML,将故事保存在一个故事文件中,并更新这个故事相应的菜单文件。
该应用程序有三种数据文件:Category.txt包含一个简单的主题列表,故事就是在这里组织的。每个主题与一个主题菜单文件相关联。第一个主题必须是"Main",并与主题菜单文件 Main.txt 相关联。如果第二个主题是 "TheArts",则它与名为 TheArts.txt的主题菜单文件相关联。在菜单文件中,每个故事的信息单独占一行:一个故事编号、一个标题、一个类别、一个简单的摘要,以及一个可选的图像URL。最后,故事文件包含一个故事的实际正文。文件 s1.txt将包含第一个提交的故事,s2.txt包含第二个提交的故事,依此类推。如果您知道一个故事的编号(比如说 26号),则它的文件名很容易确定 (s26.txt)。
4.试用 Webzine!
在您仔细研究这个应用程序之前,请首先试用它。试用 Webzine驱动程序。它的左侧是一个主题列表,右侧是一个故事列表。您可以选择一个主题,或者选择"Main"来查看所有故事。首先出现的是最近的故事列表,第一组故事中如果有图像,同时也会显示这些图像。当您单击一个故事的标题时,就是出现一个包含该故事的完整正文的一个页面。
试用编辑页(您也可以从Webzine 中试用它)。它提供一个表单,允许您提交一个故事。向 Webzine提交内容时,请注重大众的观念和好的品味。如果您录入程序不喜欢的内容,将显示一条错误消息。一旦故事被接受,您就可以返回Webzine 来查看它在读者面前是什么样子。
现在您已经试用了应用程序,请继续阅读后面的部分以了解它的创建过程。
4.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 的边界标记: 使您从 HTML模式进入 PHP 模式,而 ?> 切换回 HTML 模式。您可以来回切换任意次。某些操作在 HTML模式下较容易实现,而另外一些操作在PHP模式下较容易实现。您所做的全部事情就是在程序开头定义两个变量,然后进入HTML 模式。当需要使用某个变量时,就退回 PHP 模式,并发出一条echo语句将该变量的值直接写入网页正文中。
<?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>
类别菜单
Category.txt文件只是主题名的一个列表,每个主题名单独占一行。例如,如果该文件只包含三项:
Main
Politics
Technology
您将获得三个主题菜单文件:Main.txt、Politics.txt和Technology.txt。一旦选定 "Main"主题,驱动程序就会出现,如下所示:
Main
Politics
Technology
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);
?>
接上一篇PHP例解Webzine编辑和发送(一)
清单 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:
<table border=1>
现在,切换到PHP模式:
<?php
for 循环将从0开始,一直到元素的总数减1为止(因为它使用的是 <而不是 <=)。换句话说,如果有3个元素,则将以0/1/2迭代它们:
for ($i=0; $i<$elems; $i++) {
trim 函数将删除前导/尾随空格并返回。这是必不可少的,因为用来读取类别文件内容的 file函数将在每个类别名的最后保留尾随换行字符。所以这将把 "Politicsn"转换为 "Politics"。
$item = trim($cats[$i]);
下面是一个“搜索并替换”操作,用来去掉 $item中的空格,并将结果存放在 $ifile 中。所以主题名 "The Arts" 将变为 "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是 <a
href="index.php?topic=Politics>Politics</a>。如果选定的主题是Politics,则anchor就是 Politics。在任一种情况下,anchor 两侧都有空格。
echo(" <tr><td bgcolor="$color"><center><b>$anchor</b></center></td></tr>n");
下面的echoe语句将指定的字符串插入输出流(即,HTML网页的正文)中。所以可以使用这条语句插入整个表行。在字符串中使用"可以插入一个引号字符。上面计算出的$color和$anchor变量自动代入它们的引用位置:
echo(" <tr><td bgcolor="$color"><center><b>$anchor</b></center></td></tr>n");
for 循环的结束:
}
再次从PHP模式返回HTML模式:
?>
类别菜单的HTML表的结束:
</table>
对程序创建过程的分析到此结束!
故事的表示
一旦选定一个故事,您就需要将这个故事的正文从故事文件打印到当前的网页上。(编辑模块author.php3 以正确的 HTML格式准备这个故事。)这是个简单的过程。在下面的代码段中,假定故事编号存储在变量$story 中。如果 $story 等于33,则这个故事的文件为 s33.txt。
$storyfile = fopen("s$story.txt","r");
fpassthru($storyfile);
在上例中,fopen函数打开一个文件,并返回该文件的一个句柄,然后通过赋值运算符将这个句柄保存在变量$storyfile 中。fpassthru函数将文件的内容复制到当前的输出设备(输出HTML文件),并自动关闭该文件。
内容预告
本文(第 1.2 部分)介绍了 Webzine 这个简单PHP应用程序的第一部分,并详细分析了几小段代码示例。(应用程序的这部分代码大小只有2K,所以没有许多大型的代码示例供我们选择!)这应该使您对PHP的强大功能有了很好的体验,但后面的内容还多着呢。
下一部分的篇幅与前面大致相同。我将说明故事菜单的表示是如何呈现在读者面前的,从而完成对发送模块的讨论。然后我将讨论允许作者提交故事的编辑模块。虽然编辑模块比发送模块大得多,但我们不会如此详细地讨论它:我们只需要说明与发送模块不同的那些有趣概念。
参考资源
PHP.net是 PHP语言的官方主页。在这里您可以免费下载PHP的最新版本,还可以查看PHP开发的发展方向。这里还有一个常见问题解答、一个手册以及许多其他资源。
PHPbuilder.com面向的是开发人员,其中包含大量的文章和代码样例、零活登记以及到PHP资源的链接。
Webmonkey的PHP部分包含有关PHP的大量入门级文章。
作为构建动态网页的一种语言,PHP提供了一种简化的方法来构造复杂而功能强大的与 Web 相关的程序。 Erik用一个原始的、现实世界的网站示例逐步说明了PHP的基本原理。本系列文章的第3、4部分介绍发送模块如何向读者呈现一个故事菜单,并说明编辑模块如何使作者能将故事提交给Webzine。
如果您是初次接触PHP,您可能会惊喜地发现在实践中它是多么易于使用。本文旨在使您对PHP的工作方式留下一个好的印象; 随后您就可以确定它是否适合您。
简介
在本文的第1、2部分,我介绍了Webzine 这个简单PHP应用程序的发送部分。尽管只有大约3K的代码,但它包含了许多功能。您已试用了这个应用程序,并开始研究它的后台工作方式。我说明了应用程序如何向用户显示类别菜单并根据选择显示故事。我还使读者对PHP应用程序的工作方式以及它们从调用页接收参数的方式有了一定的了解。
本文是第3部分,您首先会了解到发送模块是如何将故事菜单呈现给读者的,然后还会快速查看一下使作者能向Webzine 提交故事的编辑模块。
故事菜单
文件中的每个故事在主题菜单文件中都有对应的一行。我已决定将脱字符号("^")用作定界符来分隔文件中的不同项目,但您可以使用任何字符(制表符是一种通用的选择)。下面是基本的布局:
故事编号^标题^图像 URL^摘要
.
举例来说,仅包含三个故事的主题菜单文件 (TradeShow.txt)可能如下所示:
清单1.包含三个故事的主题菜单文件
33^Great New Products This Year^/images/proddemo.jpg^Thursday's product demo ...
12^Opening Event Well Attended^/images/opnfoto.jpg^Ticket sales to the ...
5^Trade Show Opens^/images/tradelogo.gif^The Fourth Annual Trade Show ...
菜单驱动程序接受这些信息并向读者提供一个故事概述。其工作方式如下:
首先,驱动程序将适当的条目编号从主题菜单文件复制到数组$stories 中。对于上面的示例,$stories[0]包含第一行(故事编号为 33),$stories[1] 包含故事编号 12,$stories[2] 包含故事编号5。您还需要统计数组中的元素个数,并将其保存在变量$numstories 中。
下一步,驱动程序将此信息提供给用户,如下所示:
清单 2.驱动程序
for ($i=0; $i<$numstories; $i++) {
$storyinfo = split("^", $stories[$i]);
$storynum = $storyinfo[0]; // 故事编号(例如 33)
$storydesc = $storyinfo[1]; // 故事标题(例如 "Great New Products This Year")。
$storyimg = $storyinfo[2]; // 图像 URL(例如 http://www.ddvip.net/web/php/index2/"/images/proddemo.jpg")。
$dtext = $storyinfo[3]; // 故事摘要(更长的文本说明)。
$url = "<a href="index.php3?topic=$topic&story=$storynum">$storydesc</a><br>";
if ($i<10) {
$url = "<h2>" . $url . "</h2>";
if ($storyimg != "") {
$url = "<p><img align=" . ($i%2==1 ? "right" : "left")
. " src="$storyimg"></p>n"
. $url;
}
$url = "<hr>" . $url;
} else {
$url = "<h3>" . $url . "</h3>";
}
echo("$urln");
echo("<p>$dtext</p>n");
}
split函数将故事信息的内容从一个字符串复制到一个数组中。请注意,脱字符号前面加了一个反斜杠从而成为“转义”字符。该程序将数组节点转换为说明性更强的变量名,从而使代码更易于阅读。然后就会构造URL。if/else 结构对前10个故事的处理与对其他故事的处理不同。前10个故事有一个分隔线,使用H2标记,并包括一张照片(如果有)。剩余的故事使用H3标记,没有分隔线,也没有照片。这个处理突出显示最新的故事,并保留较旧的故事供需要它们的读者访问。请注意,编号为奇数的的图像是右对齐的,而编号为偶数的图像是左对齐的。
作为本例的结束,为上面的 theTradeShow.txt 文件所生成的HTML代码如下所示:
清单 3. 为 theTradeShow.txt 文件所生成的 HTML 代码
<hr><p><img align=left src=http://www.ddvip.net/web/php/index2/"/images/proddemo.jpg"></p>
<h2><a href="index.php3?topic=TradeShow&story=33">Great New Products This Year</a><br></h2>
<p>Thursday's product demo included a couple of exciting new
surprises from competing firms in the industry.</p>
<hr><p><img align=right src=http://www.ddvip.net/web/php/index2/"/images/opnfoto.jpg"></p>
<h2><a href="index.php3?topic=TradeShow&story=12">Opening Event Well Attended</a><br></h2>
<p>Ticket sales to the Trade Show opening event were
up 15% from last year's show.</p>
<hr><p><img align=left src=http://www.ddvip.net/web/php/index2/"/images/tradelogo.gif"></p>
<h2><a href="index.php3?topic=TradeShow&story=5">Trade Show Opens</a><br></h2>
<p>The Fourth Annual Trade Show opened 10/11/2000 to an enthusiastic reception
from attendees.</p>
单击此处查看 index.php3的源代码。在开始下一部分之前您可能希望查看整组源代码。毕竟代码的大小还不到3K!
编辑页 "author.php3"
对编辑页的分析不会像对发送模块的分析那样详细,因为它比较长,而且我们已经讨论了许多基本概念。
为了简要说明一个 PHP 函数的基本结构,让我们看一下编辑模块中的complain函数。这是一个简单的函数,但它是一个很好的入门级材料。
清单 4. 一个 PHP 函数示例
//通知用户输入问题。
function complain($problem) {
global $status;
if ($status != "") $status = $status . "<br>n";
$status = $status . $problem;
}
您可以在代码中的任何地方调用这个函数。例如,complain("The URL is too long."); 接收全局变量 $status并将这个新的错误消息追加到其尾部,如果 $status不为空,则在错误消息前添加一个换行符。
Prepend
prepend函数是编辑模块中最重要的函数之一。它在文件的首行添加一个新条目。下面,我使用它将作者的新提交添加到主题菜单文件的开头。
清单 5. prepend 函数
//在一个现有文件的开头添加一行新内容。
function prepend($file,$string) {
// 有待改进 — 使用数据库提高这个算法的可伸缩性。
// 目前限制为 100 个故事。
if (file_exists($file)) {
$filetext = file($file);
$lines = count($filetext);
} else {
$lines = 0;
}
if ($lines > 100) $lines = 100;
$handle = fopen($file,"w");
fputs ($handle, "$stringn");
for ($i=0; $i<$lines; $i++)
fputs ($handle, $filetext[$i]);
fclose ($handle);
}
如果文件存在,整个正文将存入 $filetext数组中。然后统计出行数。如果文件不存在,则认为它有零行。长度限制为100 行(实际上是 101 行,因为第一行是在开始计数之前添加的)。文件打开,程序首先将当前的字符串写入文件中,然后再将剩余的行(最多100 行)写入文件中。这 100 行以后的任何内容将被丢弃。
这个函数依赖于 PHP
内建的几个重要的文件处理函数。下表说明了每个函数所进行的操作。
函数 说明
file_exists(string) 将字符串作为文件名,如果文件名当前存在,则返回 true。
file(string) 将字符串作为文件名,用一个数组返回文件的正文,每行分别对应一个数组元素。
请注意,行终止字符将位于数组中每行的尾部。
count(array) 返回数组中的元素个数。
fopen(string, mode) 字符串是一个文件名,模式是一个字符串,例如 "w" 表示写入,"r"表示读取。
打开文件,并返回一个句柄。
fputs(handle, string) 将字符串写入指定的输出文件中。必须指定一个文件句柄,
而不能以字符串形式指定文件名。
fclose(handle) 关闭文件,终止输出。
Save
save函数将作者的输入写入一个文件中。因这个函数太长,
在此我不能逐行分析它,但我会强调几个有趣的语句。
$entry = "$storynum^$storytitle^$storyimg^$synopsis";
上面的这个语句将$storynum、$storytitle、$storyimg和 $synopsis 变量连接起来,并用脱字符号作为分隔符。
内嵌的变量替代使它比显式连接更容易且更有趣。
prepend("Main.txt",$entry);
$topicfile = "$subject.txt";
prepend($topicfile,$entry);
$entry变量的值被添加到主故事菜单文件和主题特定的故事菜单文件中。所以,如果变量$subject 等于 "Politics",它就被添加到文件"Politics.txt" 中。
php爱好者站 http://www.phpfans.net 为phper提供一切资讯.