12.3系统功能实现
12.3 系统功能实现
系统前端页面使用HTML语言构建,页面布局将通过CSS+DIV(层)实现。BLOG实际内容的显示,将由内嵌入HTML中的PHP代码完成。
12.3.1 实现BLOG文章的显示
这一小节将实现从文件中读取日志内容,并将其显示在页面上。
(1)为了能将日志内容显示到页面,建立一个文本文件,在该文件里存储一些日志数据,文件的内容如下。
测试日志标题| 1322862787| 这是一段日志的测试文字,一切无误的话,它应该正确显示。
这段内容中的各项以“|”分割,从左向右依次表示日志的标题、发布该日志的日期时间(以UNIX时间戳表示)、日志的实际内容。目前还没有实现添加日志文章的功能,所以先手工建立一个目录及日志内容文件,以便显示日志内容的程序可以读取该文件。将该文件以名称02-215307.txt并存储到BLOG系统contents目录的201112目录下。测试时,读者可以自行指定目录和文件名。
(2)编写PHP程序读出文件的内容,并向浏览器输出。代码12-1是实现读取文件中日志内容并显示出日志内容的程序,命名为post.php。
代码12-1 读文件并显示日志内容post.php
01 <?php
02 $file_name = "contents/201112/02-215307.txt"; //
存储日志内容的文件
03
04 if(file_exists($file_name)) //
打开文件前判断文件是否存在
05 {
06 $fp = @fopen($file_name, "r"); //
以只读方式打开文件
07 if($fp)
08 {
09 flock($fp, LOCK_SH); //
文件加锁
10 $result = fread($fp, 1024); //
读出文件的内容,并以字符串形式赋给变量$result
11 }
12 flock($fp, LOCK_UN); //
解锁文件
13 fclose($fp);
14 }
15
16 //
将字符串$result
的内容按“|
”分割后存入数组$content_array
17 $content_array = explode("|", $result);
18
19 //
以下代码将日志内容输出至浏览器
20 echo "<h1>
我的BLOG</h1>";
21 echo "<b>
日志标题:</b>".$content_array[0];
22 echo "<br/><b>
发布时间:</b>".date("Y-m-d H:i:s",$content_array[1]);
23 echo "<hr>";
24 echo $content_array[2];
25 ?>
【代码解析】代码第02行首先打开指定目录下的文本文件contents/201112/02-215307.txt,该文件保存了某天某时刻的日志内容。读出文件内容后,将其赋给变量$result,此时变量$result的值为“测试日志标题|1322862787|这是一段日志的测试文字,一切无误的话,它应该正确显示。”。接着程序第17行使用函数explode()将该字符串按竖线“|”做分割,分割后的3个部分分别是日志的标题、发布日志的时间和日志的实际内容,然后程序将这3项内容存入数组$content_array,作为其单元的值。最后使用echo语句将数组的内容输出,即将日志内容输出至页面。代码12-1的执行结果如图12-3所示。

图12-3 显示日志内容的简易界面
注意 文件中存储的时间是一个UNIX时间戳1322862787,程序中使用函数date()将这个时间戳格式化普通时间格式后输出。如果读者已经对时间戳没有印象,可参考第7.2节。
(3)代码12-1中只能读取2011年12月2日某时刻的日志文件,这肯定是不能满足实际需要的。显示BLOG内容的程序应该能够访问每一天的日志文件,这可以通过URL向程序传入参数实现,不同的参数值代表不同的日期时间,程序根据这个参数值的不同,完成访问不同目录下的日志文件,并获取该文件中的数据。比如,传入参数entry=201112-02-215307,表示访问目录201112下的02-215307.txt文件。从这个参数可以看出,它的值实际反映出了日志路径。代码12-2是使用了URL传入参数的post.php。
代码12-2 处理由URL传入的字符串参数post.php
01 <?php
02 if(!isset($_GET["entry"]))
03 {
04 echo "
请求参数错误";
05 exit;
06 }
07
08 $path = substr($_GET["entry"],0,6); //
日志存储目录
09 $entry = substr($_GET["entry"],7,9); //
日志文件名称
10
11 $file_name = "contents/".$path."/".$entry.".txt"; //
拼接出完整的日志路径
12
13 if(file_exists($file_name)) //
打开文件前需要判断文件是否存在
14 {
15 $fp = @fopen($file_name, "r"); //
以只读方式打开文件
16 if($fp)
17 {
18 flock($fp, LOCK_SH); //
文件加锁
19 $result = fread($fp, 1024); //
读出文件中的内容
20 }
21 flock($fp, LOCK_UN); //
解锁文件
22 fclose($fp);
23 }
24
25 //
将字符串$result
的内容按“|
”分割后存入数组$content_array
26 $content_array = explode("|", $result);
27
28 //
以下代码将日志内容输出
29 echo "<h1>
我的BLOG</h1>";
30 echo "<b>
日志标题:</b>".$content_array[0];
31 echo "<br/><b>
发布时间:</b>".date("Y-m-d H:i:s",$content_array[1]);
32 echo "<hr>";
33 echo $content_array[2];
34 ?>
【代码解析】URL中entry参数的值存放在PHP的预定义变量$_GET中。代码第02~06行首先判断是否传入了参数entry,如果通过GET方法没有得到URL参数entry,程序会输出一个提示信息,告知用户请求参数错误。如果得到了参数entry,程序会通过函数substr()将该参数的值分割,分别分割成日志的存储目录和日志文件名。字符串201112-02-215307的前6位代表的是日志的存储目录,因此通过代码第08行的“substr($_GET["entry"],0,6)”可以得到日志的存储目录。同理,代码第09行中的“substr($_GET["entry"],7,9)”获取的是日志文件名。通过浏览器,访问修改后的post.php,将看到和图12-3完全一样的结果。

图12-4 页面整体布局
至此,从文件中获取BLOG内容的基本功能已完全实现。
12.3.2 完善用户界面
12.2.1小节虽然实现了BLOG内容的显示,但页面本身还是相当简陋的。本小节将实现使用HTML构建基本页面,通过CSS+DIV技术实现对页面布局的控制和显示效果,进而完善上小节的BLOG内容显示界面。
完整的页面应该分成几大块,每块负责显示不同的内容。在这个BLOG系统中,页面的整体布局如图12-4所示。
下面就按图12-4完成页面的构建。
(1)使用HTML完成页面的创建,然后通过CSS控制页面布局和显示效果。代码12-3是用来显示日志文章内容的完整HTML文档,将其按文件名page.html保存。
代码12-3 用来显示日志文章的HTML文档page.html
01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03 <html>
04 <head>
05 <title>BLOG</title>
06
07 </head>
08 <body>
09
10 <div id="containor">
11 <div id="header">
12 BLOG
名称
13 </div>
14 <div id="title">
15 ----I have a dream....
16 </div>
17 <div id="left">
18 <div id="blog_entry">
19 <div id="blog_title">
日志文章标题</div>
20 <div id="blog_body">
21 <div id="blog_date">2012-12-01</div>
22
日志文章内容
23 </div>
24 </div>
25 </div>
26
27 <div id="right">
28 <div id="sidebar">
29 <div id="menu_title">
关于我</div>
30 <div id="menu_body">
我是个PHP
爱好者</div>
31 </div>
32 </div>
33
34 <div id="footer">
35 CopyRight 2011
36 </div>
37 </div>
38
39 <body>
40 </html>
【代码解析】代码是一些简单的HTML标签,重点是一些div的布局,这里笔者不再详细介绍每个标签的意义,读者可参考前文的介绍。通过浏览器访问page.html,可以看到如图12-5所示的效果。
(2)可以肯定,这个页面仍然是不能满足需求的。下面通过CSS来控制页面的显示效果。创建一个名为style.css,在该CSS文件输入如下CSS代码并保存。
01 body{
02 font-size:13px;
03 background-color:#C6C68C;
04 padding:0px;
05 } <!
—定义 body
样式 -->
06 #header{
07 margin-left:auto;
08 margin-right:auto;
09 padding:8px;
10 height:80px;
11 background-color:#E8F3FD;
12 border-bottom:1px solid #000;
13 } <!
—定义 header
样式 -->
14 #title{
15 margin-left:auto;
16 margin-right:auto;
17 padding:8px;
18 height:10px;
19 background-color:#E8F3FD;
20 border-bottom:1px solid #000;
21 } <!
—定义 title
样式 -->
22 #container
23 {margin-left:auto;
24 margin-right:auto;margin-top:2px;
25 margin-bottom:0px;
26 padding:0;
27 width:760px;
28 height:400px;
29 background-color:#EDEDED;
30 border:1px solid #000;
31 }
<!
—定义 container
样式 -->
【代码解析】从代码可以看出,style.css中设定了body元素的背景色、header、title和container层的背景色、margin、padding的属性。
(3)在代码12-3所示的HTML文档中引入style.css,即在page.html的<head>与</head>标签之间加入如下代码。
<link rel="stylesheet" type="text/css" href="style.css" />
再通过浏览器查看page.html,会看到如图12-6所示的效果。

图12-5 显示文章内容的HTML页面

图12-6 在页面中加入CSS
(4)这个CSS文件已经使原始的HTML文件显示出一定的效果,但上述CSS代码仅是对页面头部的显示效果加以控制,还需要使用CSS控制整个页面的显示效果。现在继续完善这个CSS,代码12-4是完整的CSS代码。这个CSS文件会随BLOG系统功能的改变而有所改动或增加。
代码12-4 控制页面显示效果的CSS代码style.css
01 body{
02 font-size:12px;
03 background-color:#C6C68C;
04 padding:0px;
05 font-family:Helvetica,sans-serif;
06 } <!
—定义 body
样式 -->
07
08 #container{
09 margin-left:auto;
10 margin-right:auto;
11 margin-top:2px;
12 margin-bottom:0px;
13 padding:0;
14 width:760px;
15 border:1px solid #000;
16 background-color:#F6F6F6;
17 } <!
—定义 container
样式 -->
18
19 #header{
20 margin-left:auto;
21 margin-right:auto;
22 padding:8px;
23 height:80px;
24 background-color:#E8F3FD;
25 border-bottom:1px solid #000;
26 font-size:16px;
27 font-weight:bold;
28 } <!
—定义 header -->
29
30 #title{
31 margin-left:auto;
32 margin-right:auto;
33 padding:8px;
34 height:10px;
35 background-color:#E8F3FD;
36 border-bottom:1px solid #000;
37 font-style:italic;
38 } <!
—定义 title
样式 -->
39
40 #left{
41 float:left;
42 margin-left:auto;
43 margin-right:auto;
44 margin:6px 0 4px 2px;
45 padding:5px;
46 width:530px;
47 } <!
—定义 left
样式 -->
48
49 #right{
50 float:right;
51 margin-left:auto;
52 margin-right:auto;
53 margin:6px 0 4px 2px;
54 padding:5px;
55 width:200px;
56 } <!
—定义 right
样式 -->
57
58 #blog_entry{
59 margin-left:auto;
60 margin-right:auto;
61 margin-top:4px;
62 margin-bottom:10px;
63 border:1px solid #000;
64 background-color:#FFF;
65 } <!
—定义 blog_entry
样式 -->
66
67 #blog_title{
68 border-bottom:1px solid #000;
69 background-color:#E8ECDB;magin:0px;
70 padding:4px;
71 font-weight:bold;
72 font-size:13px;
73 } <!
—定义 blog_title
样式 -->
74
75 #blog_body{
76 margin-left:auto;
77 margin-right:auto;
78 margin-top:4px;
79 padding:6px;
80 } <!
—定义 blog_body
样式 -->
81
82 #blog_date{
83 margin-left:auto;
84 margin-right:auto;
85 padding:0 0 8px 0;
86 font-size:10px;
87 } <!
—定义 blog_date
样式 -->
88
89 #sidebar{
90 margin-left:auto;
91 margin-right:auto;
92 border:1px solid #000;
93 width:180px;
94 background-color:#FFF;
95 } <!
—定义 sidebar
样式 -->
96
97 #menu_title{
98 border-bottom:1px solid #000;
99 background-color:#E8ECDB;
100 magin:0px;padding:4px;
101 height:10px;
102 font-weight:bold;
103 } <!
—定义 menu_title
样式 -->
104
105 #menu_body{
106 margin-left:auto;
107 margin-right:auto;
108 margin-top:4px;
109 padding:6px;
110 } <!
—定义 menu_body
样式 -->
111
112 #footer{
113 clear:both;
114 text-align:center;
115 margin-left:auto;
116 margin-right:auto;
117 padding:8px;
118 height:10px;
119 background-color:#E8F3FD;
120 border-top:1px solid #000;
121 } <!
—定义 footer _title
样式 -->
【代码解析】关于CSS的代码,这里不做详细介绍,读者可参考注释。在后续的开发中,将看到由此CSS文件控制的各个界面效果。
12.3.3 实现BLOG文章的添加功能
为12.2.2小节显示日志文章的页面增加一个含有文本框和“提交”按钮的HTML表单,实现添加日志文章的界面,如图12-7所示。

图12-7 添加BLOG文章的界面
代码12-5实现了该页面,将代码12-5按文件名add.php进行保存。
代码12-5 添加BLOG文章的界面add.php
01 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
02 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
03 <html>
04 <head>
05 <title>
基于文本的简易BLOG</title>
06 <link rel="stylesheet" type="text/css" href="style.css" />
07 </head>
08 <body>
09
10 <div id="container">
11 <div id="header">
12 <h1>
我的BLOG</h1>
13 </div>
14 <div id="title">
15 ----i have dream....
16 </div>
17
18 <div id="left">
19 <div id="blog_entry">
20 <div id="blog_title">
添加一篇新日志</div>
21 <div id="blog_body">
22 <div id="blog_date"></div>
23 <table border="0">
24 <form method="POST" action="add.php">
25 <tr><td>
日志标题:</td></tr>
26 <tr><td><input type="text" name="title" size="50"></td></tr>
27 <tr><td>
日志内容:</td></tr>
28 <tr><td><textarea name="content" cols="49" rows="10">< /textarea></td></tr>
29 <tr><td><input type="submit" value="
提交"></td></tr>
30 </form>
31 </table>
32 </div>
33 </div>
34 </div>
35
36 <div id="right">
37 <div id="sidebar">
38 <div id="menu_title">
关于我</div>
39 <div id="menu_body">
我是个PHP
爱好者</div>
40 </div>
41 </div>
42
43 <div id="footer">
44 CopyRight 2011
45 </div>
46 </div>
47
48 <body>
49 </html>
【代码解析】这里读者要注意的也是一些div+css的布局,读者要注意,每个div的id与前面定义的CSS代码相对应。
还需要在add.php里实现对用户提交数据的处理。该处理的主要工作是,把用户提交的数据存储到文本文件中。在完成数据存储之后,程序还应该向用户反馈一个信息,提示用户数据已经成功保存,或者提示由于某些原因,数据存储失败。代码12-6是增加了数据处理功能的add.php的完整代码。
代码12-6 添加日志文章的完整程序add.php
01 <?php
02 $ok = true;
03 if(isset($_POST["title"]) && isset($_POST["content"])) //
判断变量$_POST["content"]
和$_POST["title"]
04 {
05 $ok = true;
06
07 $title = trim($_POST["title"]); //
获取日志标题
08 $content = trim($_POST["content"]); //
获取日志内容
09 $date = time(); //
获取日志时间
10 $blog_str = $title."|".$date."|".$content; //
将上述内容合并成字符串
11
12 $ym = date("Ym",time()); //
获取日期中的年和月
13 $d = date("d",time()); //
获取日期中的日
14 $time = date("His",time()); //
获取日期中的时间,His
可参考表7-1
15
16 $folder = "contents/".$ym; //
根据年和月设置目录名
17 $file = $d."-".$time.".txt"; //
获取时间和日来设置文件名
18 $filename = $folder."/".$file;
19 $entry = $ym."-".$d."-".$time;
20
21 if(file_exists($folder) == false)
22 {
23 if(!mkdir($folder))
24 {
25 //$ok = false;
26 //$msg = "<font color=red>
创建目录异常,添加日志失败</font>";
27 }
28 }
29
30 $fp = @fopen($filename, "w"); //
打开文件
31 if($fp)
32 {
33 flock($fp, LOCK_EX);
34 $result = fwrite($fp, $blog_str); //
写入文件
35 $lock = flock($fp, LOCK_UN);
36 fclose($fp); //
关闭文件
37 }
38 if(strlen($result)>0)
//
判断写入是否成功
39 {
40 //$ok = false;
41 $msg = "
日志添加成功,<a href="post.php?entry=".$entry."">
查看该日志文章</a>";
42 echo $msg;
43 }
44 }
45 ?>
46
47 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
48 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
49 <html>
50 <head>
51 <title>
基于文本的简易BLOG</title>
52 <link rel="stylesheet" type="text/css" href="style.css" />
53 </head>
54 <body>
55
56 <div id="container">
57 <div id="header">
58 <h1>
我的BLOG</h1>
59 </div>
60 <div id="title">
61 ----I have dream....
62 </div>
63
64 <div id="left">
65 <div id="blog_entry">
66 <div id="blog_title">
添加一篇新日志</div>
67
68 <div id="blog_body">
69 <div id="blog_date"></div>
70 <table border="0">
71 <form method="POST" action="add.php">
72 <tr><td>
日志标题:</td></tr>
73 <tr><td><input type="text" name="title" size="50"></td></tr>
74 <tr><td>
日志内容:</td></tr>
75 <tr><td><textarea name="content" cols="49" rows="10"></textarea> </td></tr>
76 <tr><td><input type="submit" value="
提交"></td></tr>
77 </form>
78 </table>
79 </div><!-- blog_body-->
80 </div><!-- blog_entry-->
81 </div>
82
83 <div id="right">
84 <div id="sidebar">
85 <div id="menu_title">
关于我</div>
86 <div id="menu_body">
我是个PHP
爱好者</div>
87 </div>
88 </div>
89
90 <div id="footer">
91 CopyRight 2011
92 </div>
93 </div>
94
95 <body>
96 </html>
【代码解析】代码第03行的isset()函数判断变量是否已经被赋值,如果是则返回真。第03行只有两个变量$_POST["content"]和$_POST["title"]都被赋值才会返回真。
下面就来添加一篇日志文章,看看add.php的实际执行效果。打开浏览器,访问add.php,输入一段文章内容,如图12-8所示。单击“提交”按钮后,如果一切正常,将会在该页的最上方看到日志文章添加成功的信息,如图12-9所示。
这个提示信息不仅告知用户日志文章添加成功,而且给出了刚刚所添加文章的链接,这是一个链接到post.php的,单击该链接,可以看到刚刚添加的日志文章,如图12-10所示。

图12-8 添加一篇新日志文章

图12-9 日志文章添加成功

图12-10 新添加的日志文章
12.3.4 实现登录功能
至此,已经完成了该BLOG系统日志文章浏览与添加的功能。通常,一个系统只有允许用户登录后,才能完成该系统相应的管理操作,本章要实现的BLOG系统也不例外。本小节将向读者介绍该BLOG系统用户登录与退出的实现。
用户登录需要用户名和密码,这里将用户名和密码配置到.php文件中,登录程序将用户输入的用户名和密码与该php文件中设置的用户名和密码进行比较,如果完全匹配,则登录成功,否则提示用户名或密码错误。建立一个名为auth.php的文件,存放在BLOG系统的config目录下,用来设置用户名和密码,程序内容如代码12-7所示。
代码12-7 用户名和密码配置文件auth.php
01 <?php
02 $AUTH = array();
03 $AUTH["user"] = "admin";
04 $AUTH["passwd"] = "21232f297a57a5a743894a0e4a801fc3";
05 ?>
【代码解析】代码第02行定义了数组$AUTH,然后第03~04行分别为数组中的用户名和用户密码赋值。
注意 auth.php定义了一个数组来存放用户名和密码,其中,密码是将某字符串经过函数md5()加密的,读者在测试时可通过使用函数md5()加密某字符串后自行设定。
然后实现用户登录程序。该程序由处理用户登录的PHP代码和显示登录界面的HTML组成,其完整代码如代码12-8所示。
代码12-8 用户登录程序login.php
01 <?php
02 include "config/auth.php"; //
包含配置文件
03 session_start();
04
05 if(isset($_POST["user"]) && isset($_POST["passwd"])) //
判断用户的输入
06 {
07 $user = $_POST["user"];
08 $passwd = $_POST["passwd"];
09
10 $passwd = md5($passwd); //
对密码使用md5
加密
11
12 if($user != $AUTH["user"] || $passwd != $AUTH["passwd"]) //
验证失败
13 {
14 echo "<strong><font color="red">
用户名或密码错误!</font></strong>";
15 }
16 else
17 {
18 $_SESSION["user"] = $user; //
验证成功,设置session
19 header("location: index.php");
20 }
21 }
22 ?>
23
24 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
25 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
26 <html>
27 <head>
28 <title>
基于文本的简易BLOG</title>
29 <link rel="stylesheet" type="text/css" href="style.css" />
30 </head>
31 <body>
32
33 <div id="container">
34 <div id="header">
35 <h1>
我的BLOG</h1>
36 </div>
37 <div id="title">
38 ----I have dream....
39 </div>
40
41 <div id="left">
42 <div id="blog_entry">
43 <div id="blog_title">
用户登录</div>
44
45 <div id="blog_body">
46 <div id="blog_date"></div>
47 <table border="0">
48 <form method="POST" action="login.php">
49 <tr><td>
用户名称:</td><td><input type="text" name="user" size="15"> </td></tr>
50 <tr><td>
用户密码:</td><td><input type="password" name="passwd"
51 size="15"></td></tr>
52 <tr><td><input type="submit" value="
登录"></td></tr>
53 </form>
54 </table>
55 </div><!-- blog_body-->
56 </div><!-- blog_entry-->
57 </div>
58
59 <div id="right">
60 <div id="sidebar">
61 <div id="menu_title">
关于我</div>
62 <div id="menu_body">
我是个PHP
爱好者</div>
63 </div>
64 </div>
65
66 <div id="footer">
67 CopyRight 2011
68 </div>
69 </div>
70
71 <body>
72 </html>
【代码解析】首先将用户名和密码设置文件config/auth.php包含到程序当中,如代码第02行所示。接着判断用户是否输入了正确的用户名和密码,如果输入有误,将提示错误信息,如代码第14行所示;如果输入正确,将用户名存入session,然后跳转到BLOG首页,如代码第18~19行所示。通过浏览器访问login.php,可以看到如图12-11所示的登录界面。

图12-11 用户登录界面
12.3.5 实现BLOG首页
用户成功登录后,会转向BLOG的首页,本小节向读者介绍BLOG首页的实现。因为用户登录后,可以完成对BLOG的各项管理操作,所以如果用户已经登录,就在首页的日志文章后添加“编辑”和“删除”链接,以便用户完成对日志文章的编辑和删除。因为登录程序设置了session,所以可以在首页中使用session对用户是否已经登录进行判断。
登录前和登录后的首页显示会稍有不同。比如,登录后应该显示“编辑”、“删除”和“退出”链接,而没有登录的情况下,用户只能看到“登录”链接。另外,BLOG首页除了显示日志文章外,还将显示日志文章按年月归档的导航列表,所以首页还应该实现日志文章的归档处理。代码12-9是实现BLOG首页的完整程序。
代码12-9 首页程序index.php
01 <?php
02 $login = false;
03 session_start();
04
05 if(!empty($_SESSION["user"]) && $_SESSION["user"]=="admin") //
判断用户是否登录
06 $login = true;
07
08 $file_array = array();
09 $folder_array = array();
10
11 $dir = "contents";
12 $dh = opendir($dir); //
打开保存日志的目录
13
14 if($dh)
15 {
16 $filename = readdir($dh); //
读取目录下的文件
17
18 while($filename) //
循环处理按年月归档的日志文章
19 {
20 if($filename != "." && $filename != "..")
21 {
22 $folder_name = $filename;
23 array_push($folder_array,$folder_name);
24 }
25 $filename = readdir($dh);
26 }
27 }
28 rsort($folder_array); //
对目录排序
29
30 $post_data = array();
31 foreach($folder_array as $folder)
32 {
33 $dh = opendir($dir."/".$folder); //
处理每个目录下的日志文件
34 while(($filename = readdir($dh)) !== FALSE)
35 {
36 if(is_file($dir."/".$folder."/".$filename))
37 {
38 $file = $filename;
39 $file_name = $dir."/".$folder."/".$file;
40
41 if(file_exists($file_name)) //
判断文件是否存在
42 {
43 $fp = @fopen($file_name, "r");
44 if($fp)
45 {
46 flock($fp, LOCK_SH);
47 $result = fread($fp, filesize($file_name)); //
读取文件内容
48 }
49 flock($fp, LOCK_UN);
50 fclose($fp);
51 }
52 $temp_data = array();
53 $content_array = explode("|", $result);
54
55 $temp_data["SUBJECT"] = $content_array[0]; //
文章标题
56 $temp_data["DATE"] = date("Y-m-d H:i:s",$content_array[1]); //
发表时间
57 $temp_data["CONTENT"] = $content_array[2]; //
文章内容
58 $file = substr($file,0,9); //
日志文章所在文件夹名
59 $temp_data["FILENAME"] = $folder."-".$file;
60 array_push($post_data,$temp_data);
61 }
62 }
63 }
64 ?>
65
66 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
67 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
68 <html>
69 <head>
70 <title>
基于文本的简易BLOG</title>
71 <link rel="stylesheet" type="text/css" href="style.css" />
72 </head>
73 <body>
74
75 <div id="container">
76 <div id="header">
77 <h1>
我的BLOG</h1>
78 </div>
79 <div id="title">
80 ----I have dream....
81 </div>
82 <div id="left">
83 <?php foreach($post_data as $post)
//
显示所有日志文章
84 {
85 ?>
86 <div id="blog_entry">
87 <div id="blog_title"><?php echo $post["SUBJECT"]; ?></div>
88 <div id="blog_body">
89 <div id="blog_date"><?php echo $post["DATE"]; ?></div>
90 <?php echo $post["CONTENT"];?>
91 <div>
92 <?php
93 if($login)
94 {
95 echo "<a href="edit.php?entry=".$post["FILENAME"]."">
编辑 </a> <a
96 href="delete.php?entry=".$post["FILENAME"]."">
删除</a>";
//
输出日志文章的“编辑”和“删除”链接
97 }
98 ?>
99
100 </div>
101 </div><!--blog_body-->
102 </div><!--blog_entry-->
103 <?php } ?>
104 </div>
105
106 <div id="right">
107 <div id="sidebar">
108 <div id="menu_title">
关于我</div>
109 <div id="menu_body">
110
我是个PHP
爱好者
111 <br/><br/>
112 <?php if($login) {echo "<a href="logout.php">
退出</a>";} else{ echo "<a href="login.php">
登录
113 </a>";} ?>
114 </div>
115 </div>
116 <br/>
117 <div id="sidebar">
118 <div id="menu_title">
日志归档</div>
119 <?php foreach($folder_array as $ym) //
输出日志按年月的归档
120 {
121 $entry = $ym;
122 $ym = substr($ym,0,4)."-".substr($ym,4,2);
123 echo "<div id="menu_body"><a href="archives.php?ym=".$entry.""> ".$ym."</a></div>";
124 }
125 ?>
126 </div>
127 </div>
128
129 <div id="footer">
130 copyright 2011
131 </div>
132 </div>
133
134 <body>
135 </html>
136 <?php close($dh);?>
【代码解析】index.php主要实现了3大功能,一是列出所有日志文章;二是实现了日志文章按年月归档的显示;三是根据用户登录与否显示不同的链接。
如果用户已经登录,将会看到如图12-12所示的首页界面。这时,用户可以通过首页的“编辑”或“删除”链接对日志文章进行相关管理操作。因为post.php会显示某篇具体的日志文章,所以,应该在post.php中也提供“编辑”和“删除”链接,当然,这些链接只有在用户登录后才能显示出来。

图12-12 登录后的首页
说明 post.php中实现了提供“编辑”和“删除”链接的方法,与在index.php中的实现方法几乎一样,这里不再赘述,读者可以自行完成。
12.3.6 实现BLOG文章的编辑功能
用户单击“编辑”链接后,进入日志文章的编辑界面。该编辑界面可以让用户修改日志文章的标题、文章内容,修改后提交,即可完成对日志文章的编辑。BLOG的编辑界面如图12-13所示。

图12-13 日志文章的编辑界面
编辑日志文章的程序,首先应该判断用户是否登录,也就是说只有登录用户才能执行日志文章的修改操作,这可以通过使用session来完成。还需要将要编辑的日志内容显示出来,以供用户修改。编辑日志文章功能的完整程序如代码12-10所示。
代码12-10 编辑日志文章的程序edit.php
01 <?php
02 session_start();
03 $ok = false;
04
05 if(!isset($_GET["entry"])) //
判断是否设置了$_GET["entry"]
的值
06 {
07 echo "
请求参数错误!";
08 exit;
09 }
10
11 if(empty($_SESSION["user"]) || $_SESSION["user"]!="admin")
//
判断是否设置了这俩变量的值
12 {
13 echo "
请<a href="login.php">
登录</a>
后执行该操作。";
14 exit;
15 }
16
17 $path = substr($_GET["entry"],0,6); //
日志存储目录
18 $entry = substr($_GET["entry"],7,9); //
日志文件名称
19 $file_name = "contents/".$path."/".$entry.".txt";
20
21 if(file_exists($file_name)) //
取出原文件内容
22 {
23 $fp = @fopen($file_name, "r");
24 if($fp)
25 {
26 flock($fp, LOCK_SH);
27 $result = fread($fp, filesize($file_name));
28 }
29 flock($fp, LOCK_UN);
30 fclose($fp);
31
32 $content_array = explode("|", $result);
//
将文件内容存放在数组中
33 }
34
35 if(isset($_POST["title"]) && isset($_POST["content"]))
36 {
37 $title = trim($_POST["title"]); //
获取日志主题
38 $content = trim($_POST["content"]); //
获取日志内容
39
40 if(file_exists($file_name)) //
判断文件是否存在
41 {
42 //
根据用户修改时提交的内容,替换现有文件的内容,注意替换的对应关系,即标题、内容各自对应
43
做替换
44 $blog_temp = str_replace($content_array[0],$title,$result);
45 $blog_str = str_replace($content_array[2],$content,$blog_temp);
46
47 $fp = @fopen($file_name, "w");
48 if($fp)
49 {
50 flock($fp, LOCK_EX);
51 $result = fwrite($fp, $blog_str); //
写入文件
52 $lock = flock($fp, LOCK_UN);
53 fclose($fp);
54 }
55 }
56
57 if(strlen($result)>0) //
判断修订是否成功
58 {
59 $ok = true;
60 $msg = "
日志修改成功,<a href="post.php?entry=".$_GET["entry"]."">
查看该日志文
章</a>";
61 }
62 }
63 ?>
64
65 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
66 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
67 <html>
68 <head>
69 <title>
基于文本的简易BLOG</title>
70 <link rel="stylesheet" type="text/css" href="style.css" />
71 </head>
72 <body>
73
74 <div id="container">
75 <div id="header">
76 <h1>
我的BLOG</h1>
77 </div>
78 <div id="title">
79 ----I have dream....
80 </div>
81
82 <div id="left">
83 <div id="blog_entry">
84 <div id="blog_title">
编辑日志</div>
85
86 <div id="blog_body">
87 <?php if($ok == false)
88 {
89 ?>
90 <div id="blog_date"></div>
91 <table border="0">
92 <form method="POST" action="edit.php?entry=<?php echo $_GET["entry"];?>">
93 <tr><td>
日志标题:</td></tr>
94 <tr><td><input type="text" name="title" size="50" value="<?php echo
95 $content_array[0]; ?>"></td></tr>
96 <tr><td>
日志内容:</td></tr>
97 <tr><td><textarea name="content" cols="49" rows="10"><?php echo
98 $content_array[2];?></textarea></td></tr>
99 <tr><td>
创建于:<?php echo date("Y-m-d H:i:s",$content_array[1]); ?> </td></tr>
100 <tr><td><input type="submit" value="
提交"></td></tr>
101 </form>
102 </table>
103 <?php } ?>
104 <?php if ($ok == true){ echo $msg; }?>
105 </div><!-- blog_body-->
106 </div><!-- blog_entry-->
107 </div>
108
109 <div id="right">
110 <div id="sidebar">
111 <div id="menu_title">
关于我</div>
112 <div id="menu_body">
我是个PHP
爱好者</div>
113 </div>
114 </div>
115
116 <div id="footer">
117 CopyRight 2011
118 </div>
119 </div>
120
121 <body>
122 </html>
【代码解析】编辑操作的实质是更改文件的内容。为此,首先要从所要编辑的日志文章的文件中将文件内容全部取出,并存入数组中,如代码第21~33行所示。这个数组将在显示日志文章原有内容时使用,如代码91~102行所示。然后,程序根据用户传入的内容使用字符串替换函数str_replace()将原有内容替换为新的内容,从而完成对日志文章的修改,如代码第44、45行所示。最后,还需要将最新的内容写回到文件中,如代码第47~54行所示。如果这一切都正常完成,程序会向用户发出日志修改成功的信息,如图12-14所示。

图12-14 日志修改成功后的提示信息
12.3.7 实现BLOG文章的删除功能
删除日志文章也是BLOG系统的基本功能之一,本小节将向读者介绍删除日志文章功能的实现。删除一篇日志文章的基本操作是,找到日志文章所在路径和文件,然后执行删除操作。对于不存在的日志执行删除操作,应该给出“所要删除文章不存在”的提示信息。
当用户单击“删除”链接后,应该给用户一个提示界面,确认是否用户真的想删除该日志文章,以免用户误操作。另外,和编辑日志文章一样,只能在用户登录之后才能执行删除操作。
因为删除确认界面和执行删除操作的功能由同一个程序实现,所以这里通过向程序传入两个不同的URL参数,以便程序可以判断是显示删除确认界面还是执行删除操作,这两个参数是entry和id,其中id将作为表单隐藏域数据传给删除程序。如果程序获得id参数,则表示要执行删除操作。参数id的值和参数entry的值完全一样,它们只是用来区分不同的操作。删除日志文章的程序如代码12-11所示。
代码12-11 删除日志文章的程序delete.php
01 <?php
02 session_start();
03 $ok = false;
04
05 if(empty($_SESSION["user"]) || $_SESSION["user"]!="admin") //
判断用户是否登录
06 {
07 echo "
请<a href="login.php">
登录</a>
后执行该操作。";
08 exit;
09 }
10
11 if(!isset($_GET["entry"])) //
判断$_GET["entry"]
变量是否已经设置了
12 {
13 if(!isset($_POST["id"])) //
判断是否有id
参数
14 {
15 $ok = true;
16 $msg = "
请求参数错误!<a href="index.php">
返回首页</a>";
17 }
18 else
19 {
20 //
做删除操作
21 $path = substr($_POST["id"],0,6); //
日志存储目录
22 $entry = substr($_POST["id"],7,9); //
日志文件名称
23 $file_name = "contents/".$path."/".$entry.".txt";
24 if(unlink($file_name))
25 {
26 $ok = true;
27 $msg = "
该日志成功删除!<a href="index.php">
返回首页</a>";
28 }
29 else
30 {
31 $ok = true;
32 $msg = "
该日志删除失败!<a href="index.php">
返回首页</a>";
33 }
34 }
35 }
36 else
37 {
38 $form_data = "";
39 $path = substr($_GET["entry"],0,6); //
日志存储目录
40 $entry = substr($_GET["entry"],7,9); //
日志文件名称
41 $file_name = "contents/".$path."/".$entry.".txt";
42 if(file_exists($file_name)) //
判断是否已经存在该文件
43 {
44 $form_data = "<input type="hidden" name="id" value="".$_GET["entry"]."">";
45 }
46 else
47 {
48 $ok = true;
49 $msg = "
所要删除的日志不存在!<a href="index.php">
返回首页</a>";
50 }
51 }
52 ?>
53
54 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
55 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
56 <html>
57 <head>
58 <title>
基于文本的简易BLOG</title>
59 <link rel="stylesheet" type="text/css" href="style.css" />
60 </head>
61 <body>
62
63 <div id="container">
64 <div id="header">
65 <h1>
我的BLOG</h1>
66 </div>
67 <div id="title">
68 ----i have dream....
69 </div>
70 <div id="left">
71 <div id="blog_entry">
72 <div id="blog_title">
删除日志</div>
73 <div id="blog_body">
74 <?php if($ok == false)
75 {
76 ?>
77 <form method="POST" action="delete.php">
78 <font color="red">
删除的日志将无法恢复,确定要删除吗?</font><br/>
79 <input type=submit value="
确定">
80 <?php echo $form_data; ?>
81 </form>
82 <?php } ?>
83 <?php if($ok == true) { echo $msg; } ?>
84 </div><!--blog_body-->
85 </div><!--blog_entry-->
86 </div>
87
88 <div id="right">
89 <div id="sidebar">
90 <div id="menu_title">
关于我</div>
91 <div id="menu_body">
我是个PHP
爱好者</div>
92 </div>
93 </div>
94
95 <div id="footer">
96 copyright 2011
97 </div>
98 </div>
99
100 <body>
101 </html>
【代码解析】该程序首先根据session判断用户是否登录,没有登录则提示用户登录后再执行删除操作,如代码第05~09行所示。如果已经登录,则根据是否传入URL参数entry来判断是显示删除确认界面还是执行删除操作。如果没有传入entry参数,则判断是否传入日志文章id,程序将根据此id删除日志文章。如果传入id,则执行删除操作。当用户登录后,单击“删除”链接,将会看到如图12-15所示的确认界面。

图12-15 删除日志文章确认界面
在此确认界面中单击“确定”按钮,将会删除该日志文章。如果删除成功,将会看到如图12-16所示的“该日志成功删除!”提示信息。

图12-16 成功删除日志文章后的提示界面
12.3.8 实现BLOG归档显示的功能
BLOG系统通常会提供按年月归档显示日志的功能,本BLOG系统也将实现这一功能。该功能会将某年某月下的所有日志文章列出,方便用户按时间查看每天的日志文章。
浏览归档显示的日志文章,不需要用户登录。向浏览归档日志文章程序传入的参数是一个年月值字符串,程序根据该值找到日志所在目录,从而获取日志文章的文件内容,然后将文件内容显示到Web界面上。代码12-12是该程序的实现,程序命名为archives.php,如下所示。
代码12-12 归档显示日志文章的程序archives.php
01 <?php
02 $ok = false;
03
04 if(!isset($_GET["ym"]) || empty($_GET["ym"])) //
请求参数中的目录信息
05 {
06 $ok = true;
07 $msg = "
请求参数错误!<a href="index.php">
返回首页</a>";
08 }
09
10 $folder_array = array(); //
归档目录后的所有目录存在此数组中
11 $dir = "contents";
12 $folder = $_GET["ym"];
13 if(!is_dir($dir."/".$folder)) //
找到contents
目录下的所有归档目录
14 {
15 $ok = true;
16 $msg = "
请求参数错误!<a href="index.php">
返回首页</a>";
17 }
18
19 $dh = opendir($dir); //
打开目录
20 if($dh)
21 {
22 $filename = readdir($dh); //
读取指定目录下的所有目录
23 while($filename)
24 {
25 if($filename != "." && $filename != "..")
26 {
27 $folder_name = $filename;
28 array_push($folder_array,$folder_name);
29 }
30 $filename = readdir($dh);
31 }
32 }
33 rsort($folder_array); //
对目录进行排序
34
35 $post_data = array();
36 $dh = opendir($dir."/".$folder);
37
38 while(($filename = readdir($dh)) !== FALSE)
39 {
40 if(is_file($dir."/".$folder."/".$filename))
41 {
42 $file = $filename;
43 $file_name = $dir."/".$folder."/".$file;
44
45 if(file_exists($file_name)) //
判断文件是否存在
46 {
47 $fp = @fopen($file_name, "r");
48 if($fp)
49 {
50 flock($fp, LOCK_SH);
51 $result = fread($fp, filesize($file_name)); //
读取文件
52 }
53 flock($fp, LOCK_UN);
54 fclose($fp);
55 }
56 $temp_data = array();
57 $content_array = explode("|", $result);
58 //
以下是文件中的3
个日志信息
59 $temp_data["SUBJECT"] = $content_array[0]; //
读取标题
60 $temp_data["DATE"] = date("Y-m-d H:i:s",$content_array[1]); //
读取日期
61 $temp_data["CONTENT"] = $content_array[2]; //
读取内容
62 array_push($post_data,$temp_data);
63 }
64 }
65 ?>
66
67 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
68 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
69 <html>
70 <head>
71 <title>
基于文本的简易BLOG</title>
72 <link rel="stylesheet" type="text/css" href="style.css" />
73 </head>
74 <body>
75
76 <div id="container">
77 <div id="header">
78 <h1>
我的BLOG</h1>
79 </div>
80 <div id="title">
81 ----I have dream....
82 </div>
83 <div id="left">
84 <?php
85 if($ok == false)
86 {
87 foreach($post_data as $post)
88 {
89 ?>
90 <div id="blog_entry">
91 <div id="blog_title"><? echo $post["SUBJECT"]; ?></div>
92 <div id="blog_body">
93 <div id="blog_date"><? echo $post["DATE"]; ?></div>
94 <?php echo $post["CONTENT"]; ?>
95 </div><!--blog_body-->
96 </div><!--blog_entry-->
97 <?php }
98 }
99 else{
100 echo $msg;
101 }
102 ?>
103 </div>
104
105 <div id="right">
106 <div id="sidebar">
107 <div id="menu_title">
关于我</div>
108 <div id="menu_body">
109
我是个PHP
爱好者
110 <br/><br/>
111 <a href="login.php">
登录</a>
112 </div>
113 </div>
114 <br/>
115 <div id="sidebar">
116 <div id="menu_title">
日志归档</div>
117 <?php foreach($folder_array as $ym)
118 {
119 $entry = $ym;
120 $ym = substr($ym,0,4)."-".substr($ym,4,2);
121 echo "<div id="menu_body"><a href="archives.php?ym= ".$entry."">".$ym."</a></div>";
122 }
123 ?>
124 </div>
125 </div>
126
127 <div id="footer">
128 CopyRight 2011
129 </div>
130
</div>
131
132
<body>
133
</html>
134
<?php close($dh);?>
【代码解析】程序首先判断是否传入参数ym,该参数的值类似于201112,表示日志的归档年月。如果没有传入该参数,程序将提示错误信息,如代码第04~08行所示;如果传入的参数值没有其对应的目录,也会提示错误信息,如代码第10~17行所示。
接着,程序会在对应年月的目录下找出日志文章所在文件,这是一个循环查找的过程,如代码第38~64行所示。然后判断当前文件是目录还是普通文件,如代码第40行所示,如果是普通文件,程序将打开该文件并读取文件内容,存入数组当中;如果不是普通文件,则继续循环查找当前目录下的文件,直到找出所有普通文件(及日志文章所在文件)为止。从BLOG首页可以访问archives.php的结果如图12-17所示。

图12-17 按年月归档显示日志内容
12.3.9 实现BLOG的退出功能
这个BLOG系统的退出功能很简单,只需在程序中将用户登录时注册的session清空删除即可。代码12-13是退出程序的完整代码。
代码12-13 退出登录的程序logout.php
01 <?php
02 session_start();
03 $info = "";
04
05 if(isset($_SESSION["user"])) //
判断用户是否登录
06 {
07 $_SESSION["user"] = "";
08 $msg = "
您已经成功退出,<a href="index.php">
返回首页</a>";
09 }
10 else
11 {
12 $msg = "
您未曾登录或已经超时退出,<a href="index.php">
返回首页</a>";
13 }
14 ?>
15 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
16 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
17 <html>
18 <head>
19 <title>
基于文本的简易BLOG</title>
20 <link rel="stylesheet" type="text/css" href="style.css" />
21 </head>
22 <body>
23
24 <div id="container">
25 <div id="header">
26 <h1>
我的BLOG</h1>
27 </div>
28 <div id="title">
29 ----i have dream....
30 </div>
31 <div id="left">
32 <div id="blog_entry">
33 <div id="blog_title">
退出登录</div>
34 <div id="blog_body">
35 <?php echo $msg; ?>
36 </div><!--blog_body-->
37 </div><!--blog_entry-->
38 </div>
39
40 <div id="right">
41 <div id="sidebar">
42 <div id="menu_title">
关于我</div>
43 <div id="menu_body">
我是个PHP
爱好者</div>
44 </div>
45 </div>
46
47 <div id="footer">
48 copyright 2011
49 </div>
50 </div>
51
52 <body>
53 </html>
【代码解析】必须有第05行的判断,因为只有用户在登录状态下才能退出。当用户在登录状态下单击首页的“退出”链接时,如果一切正常,将会看到如图12-18所示的成功退出提示界面。

图12-18 成功退出BLOG系统的提示界面
上一篇:12.2数据的存储及系统架构
下一篇:12.4小结
