31.7 添加新文章

了解了以上所有操作后,我们现在可以来看看如何将一篇新文章加入到论坛中去。用户可以使用两种方法来完成该项操作:第一,通过在索引页面点击"New Post"按钮,第二,通过在view_post.php页面点击"Reply"按钮。

这些动作都将触发相同的脚本,new_post.php,只是带有不同的参数。图31-8显示通过点击"Reply"按钮而得到的new_post.php脚本的输出结果。

31.7 添加新文章 - 图1

图 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.7 添加新文章 - 图2

图 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论坛应用程序的所有代码。