了解了以上所有操作后,我们现在可以来看看如何将一篇新文章加入到论坛中去。用户可以使用两种方法来完成该项操作:第一,通过在索引页面点击/"New Post/"按钮,第二,通过在view_post.php页面点击/"Reply/"按钮。
这些动作都将触发相同的脚本,new_post.php,只是带有不同的参数。图31-8显示通过点击/"Reply/"按钮而得到的new_post.php脚本的输出结果。
图 31-8 在回复文章中,父文章的文本将自动插入和标记首先,让我们查看上图所示的URL:
http://localhost/phpmysql4e/chapter31/new_post.php?parent=5
传递给parent参数值应该是新文章父节点的postid。如果点击了/"New Post/"按钮而不是/"Reply/"按钮,将在URL中得到parent=0的字符串。
其次,可以看到对于一个回复,最初文章的文本被插入进来,而且前面都用“>”字符标记了,这一点与大多数的邮件和新闻阅读程序一样。
第三,可以看到回复消息的默认标题为最初标题加上前缀/"Re:/"。下面,我们来看看产生该输出的代码,如程序清单31-8所示。
程序清单31-8 new_post.php——允许用户对一个已有帖子输入或创建一篇新文章
<?php
include(/'include_fns.php/');
$title=$_POST[/'title/'];
$poster=$_POST[/'poster/'];
$message=$_POST[/'message/'];
if(isset($_GET[/'parent/'])){
$parent=$_GET[/'parent/'];
}else{
$parent=$_POST[/'parent/'];
}
if(!$area){
$area=1;
}
if(!$error){
if(!$parent){
$parent=0;
if(!$title){
$title=/'New Post/';
}
}else{
//get post name
$title=get_post_title($parent);
//append Re:
if(strstr($title,/'Re:/')==false){
$title=/'Re:/'.$title;
}
//make sure title will still fit in db
$title=substr($title,0,20);
//prepend a quoting pattern to the post you are replying to
$message=add_quoting(get_post_message($parent));
}
}
do_html_header($title);
display_new_post_form($parent,$area,$title,$message,$poster);
if($error){
echo/"<p>Your message was not stored.</p>
<p>Make sure you have filled in all fields and
try again.</p>/";
}
do_html_footer;
?>
在完成一些初始化设置之后,该脚本将检查父节点是否为0。如果是0,则表示该文章是一个新主题,而接下来需要完成的操作就相对少些。
如果是一个回复($parent变量是某篇已有文章的postid),以上脚本程序将继续执行并且设置标题和最初消息的文本,如下所示:
//get post name
$title=get_post_title($parent);
//append Re:
if(strstr($title,/'Re:/')==false){
$title=/'Re:/'.$title;
}
//make sure title will still fit in db
$title=substr($title,0,20);
//prepend a quoting pattern to the post you are replying to
$message=add_quoting(get_post_message($parent));
这里用到的函数包括get_post_title、get_post_message和add_quoting。这些函数都来自discussion_fns.php函数库。它们分别如程序清单31-9、程序清单31-10和程序清单31-11所示。
程序清单31-9 discussion_fns.php函数库中的get_post_title函数——从数据库中得到某消息的标题
function get_post_title($postid){
//extract one post/'s name from the database
if(!$postid){
return/'/';
}
$conn=db_connect;
//get all header information from/'header/'
$query=/"select title from header where postid=/'/".$postid./"/'/";
$result=$conn->query($query);
if($result->num_rows!=1){
return/'/';
}
$this_row=$result->fetch_array;
return$this_row[0];
}
程序清单31-10 discussion_fns.php函数库中的get_post_message函数——从数据库中获得某消息的正文
function get_post_message($postid){
//extract one post/'s message from the database
if(!$postid){
return/'/';
}
$conn=db_connect;
$query=/"select message from body where postid=/'/".$postid./"/'/";
$result=$conn->query($query);
if($result->num_rows>0){
$this_row=$result->fetch_array;
return$this_row[0];
}
}
这两个函数分别从数据库中获得特定文章的标题和正文。
程序清单31-11 discussion_fns.php函数库中的add_quoting函数——用“>”符号缩进一则消息的正文
function add_quoting($string,$pattern=/'>/'){
//add a quoting pattern to mark text quoted in your reply
return$pattern.str_replace(/"n/",/"n$pattern/",$string);
}
add_quoting函数将重新格式化字符串,用一个符号开始原始文本的每一行,在默认情况下,该符号为“>”。
用户在回复文章中完成所需输入并且点击/"Post/"按钮后,将进入store_new_post.php脚本程序。图31-9所示的是该脚本的一个示例输出。
图 31-9 新发表的文章在树形结构中显示出来在上图中,新发表的文章在这行下面Re:using gd?-Laura-Julie-09:36 07/20/2008。不仅如此,该页面看起来还像普通的index.php页面。
下面,我们来看看store_new_post.php的代码,如程序清单31-12所示。
程序清单31-12 store_new_post.php——在数据库中存入新的文章
<?php
include(/'include_fns.php/');
if($id=store_new_post($_POST)){
include(/'index.php/');
}else{
$error=true;
include(/'new_post.php/');
}
?>
可以看到,这是一段很短的脚本程序。它的主要任务是调用store_new_post函数。该页面没有它自身的可见内容。如果保存成功,我们会看到索引页面。否则,将回到new_post.php页,这样,用户可以重试。store_new_post函数如程序清单31-13所示。
程序清单31-13 discussion_fns.php函数库中的store_new_post函数——在数据库中保存并检验新发表的文章
function store_new_post($post){
//validate clean and store a new post
$conn=db_connect;
//check no fields are blank
if(!filled_out($post)){
return false;
}
$post=clean_all($post);
//check parent exists
if($post[/'parent/']!=0){
$query=/"select postid from header where
postid=/'/".$post[/'parent/']./"/'/";
$result=$conn->query($query);
if($result->num_rows!=1){
return false;
}
}
//check not a duplicate
$query=/"select header.postid from header,body where
header.postid=body.postid and
header.parent=/".$post[/'parent/']./"and
header.poster=/'/".$post[/'poster/']./"/'and
header.title=/'/".$post[/'title/']./"/'and
header.area=/".$post[/'area/']./"and
body.message=/'/".$post[/'message/']./"/'/";
$result=$conn->query($query);
if(!$result){
return false;
}
if($result->num_rows>0){
$this_row=$result->fetch_array;
return$this_row[0];
}
$query=/"insert into header values
(/'/".$post[/'parent/']./"/',
/'/".$post[/'poster/']./"/',
/'/".$post[/'title/']./"/',
0,
/'/".$post[/'area/']./"/',
now,
NULL
)/";
$result=$conn->query($query);
if(!$result){
return false;
}
//note that our parent now has a child
$query=/"update header set children=1 where postid=/'/".$post[/'parent/']./"/'/";
$result=$conn->query($query);
if(!$result){
return false;
}
//find our post id,note that there could be multiple headers
//that are the same except for id and probably posted time
$query=/"select header.postid from header left join body
on header.postid=body.postid
where parent=/'/".$post[/'parent/']./"/'
and poster=/'/".$post[/'poster/']./"/'
and title=/'/".$post[/'title/']./"/'
and body.postid is NULL/";
$result=$conn->query($query);
if(!$result){
return false;
}
if($result->num_rows>0){
$this_row=$result->fetch_array;
$id=$this_row[0];
}
if($id){
$query=/"insert into body values
($id,/'/".$post[/'message/']./"/')/";
$result=$conn->query($query);
if(!$result){
return false;
}
return$id;
}
}
这是个很长的函数,但它并不太复杂。它之所以长,是因为插入一篇文章就意味着要标题表和正文表进行插入操作,并要在标题表中更新父文章行以表明它现在有子文章了。
以上就是该Web论坛应用程序的所有代码。