PHP应用实例: PHP编写RSS系统

2010-08-28 10:52:36来源:西部e网作者:

  经过上次我给你的训练之后,你可能或者对建立另外一个PHP应用摩拳擦掌或者你已经决定放弃PHP编程而以尝试种植黄瓜来代替。如果是后者,那么你应该立即停止阅读,因为我可以向你保证PHP 101的结束部分绝对与教授你关于蔬菜耕作方面的内容没有一点关系。

  然而,如果是前者,那么你将会享受接下来的内容。通过接下来的几页,我将会使用PHP、SQLite和SimpleXML来开发一个简单的RSS新闻聚合器。使用这种新闻聚合器,你可以从所有的Web页面中插入RSS新闻信源,从而为你的Web站点创建一个反映你的需求和兴趣的新闻广播。其中最好的部分是:每次你浏览它的时候,其采用最新的消息自动更新。

  请跟着来,让我们开始吧!

  字母汤

  我将会从基础开始。RSS到底是什么呢?

  RSS(该缩写词代表RDF站点摘要--RDF Site Summary)是一个最初由Netscape设计的格式,它用来分发关于Netscape的My.Netscape.Com门户上的内容的信息。该格式自其在1997年初期出现以来已经经过了许多反复(请访问http://backend.userland.com/stories/rss091以获取关于RSS的长期和复杂的历史方面的信息),但是大部分信源使用RSS 1.0或者RSS 0.91,这两个版本均是轻量级但具有全部特征。

  RSS使得Web站点管理员在特定站点特定时间公布和分发新的和有趣的信息变得可能。该信息范围从新闻文章列表到股票市场数据或者天气预报,该信息以格式化良好的XML文档发布,而且因此它可以被任意XML解析器(包括为PHP 5的一部分的SimpleXML)解析、处理和呈现。

  相当多的流行Web站点使得RSS或者RDF新闻信源普遍对公众可用。Freshmeat和Slashdot两个均有一个,而且许多其他站点也是这样包括PEAR、PECL和Zend站点。一个对于公众RSS信源的快捷的Google搜索将使你得到数不清的链接。

  一个RSS文档通常情况下包含采用描述性元数据标注的资源列表(URLs)。请看下面的例子:

<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/">
<channel rdf:about="http://www.melonfire.com/">
<title>Trog</title>
<description>Well-written technical articles and tutorials on web technologies</description>
<link>http://www.melonfire.com/community/columns/trog/</link>
  <items>
<rdf:Seq>
<li rdf:resource="http://www.melonfire.com/community/columns/trog/article.php?id=100" />
<li rdf:resource="http://www.melonfire.com/community/columns/trog/article.php?id=71" />
<li rdf:resource="http://www.melonfire.com/community/columns/trog/article.php?id=62" />
</rdf:Seq>
</items>
</channel>
<item rdf:about="http://www.melonfire.com/community/columns/trog/article.php?id=100">
<title>Building A PHP-Based Mail Client (part 1)</title>
<link>http://www.melonfire.com/community/columns/trog/article.php?id=100</link>
  <description>Ever wondered how web-based mail clients work? Find out here.</description>
</item>
<item rdf:about="http://www.melonfire.com/community/columns/trog/article.php?id=71">
<title>Using PHP With XML (part 1)</title>
<link>http://www.melonfire.com/community/columns/trog/article.php?id=71</link>
  <description>Use PHP's SAX parser to parse XML data and generate HTML pages.</description>
</item>
<item rdf:about="http://www.melonfire.com/community/columns/trog/article.php?id=62">
<title>Access Granted</title>
<link>http://www.melonfire.com/community/columns/trog/article.php?id=62</link>
  <description>Precisely control access to information with the SQLite grant tables.</description>
</item>
</rdf:RDF>

  正如你所见,一个RDF文件被划分为明显地以分割线划分的段落。第一部分以文档序言、命名空间声明以及根元素开始。第一部分后面紧跟着一个<channel>块,它包含了关于该RDF文件所描述的频道方面的概要信息。在上述例子中,这个频道是Melonfire's Trog专栏,它每周以新的技术文章和教程而更新。

  <channel>块包含一个<items>块,该块包含了RDF文档内所描述的所有资源的顺序列表。该块内的每个资源对应于其后续的<item>块内详细描述的资源。每一个<item>块更加详细地描述了一单一资源,提供了该资源的题目、一个URL地址和描述。我们的应用程序将会用来产生个性化新闻信源的就是该信息。

  奠定基础

  既然你已经知道了RSS和RDF是关于什么的,那么是开始工作的时候了。我将会以坐在窗户附近的桌子上然后在一页纸上漫无目的地乱画开始,直到我逐渐地准确勾画出我的应用程序应该做什么事情为止(实际上,在这个实例中,需求实际上是非常基本的):
  1.应用程序必须支持一或多个RSS兼容的新闻信源。在启动阶段,应用程序应该获取这些新闻信源的最新版本,解析它们然后以一种易于阅读的方式显示它们的内容。SQLite数据库是存储这些信源列表的较好的选择。

  2.用户应当能够控制她/他从每个信源挑选的消息的数量。举例而言,一个用户可能想显示比商业新闻更多的科学和健康新闻。

  3 .应用程序应该为用户提供一个基于Web的界面以增加和删除新闻信源。该界面将使用PHP的SQLite API来在SQLite数据库文件上运行适当的SQL查询和修改存储于数据库中的信息。

  请记住这些需求,设计一个简单的数据库表格以保存(用户可定制的)RSS新闻信源列表是可能的。下面是它可能看上去的样子: CREATE TABLE rss (
id INTEGER NOT NULL PRIMARY KEY,
title varchar(255) NOT NULL,
url varchar(255) NOT NULL,
count INTEGER NOT NULL
);

  从上面的表格可以看出,很明显每个新闻信源将会有三个属性:描述性题目、信源自身的URL以及指示你愿意在你自己定制的新闻页面上显示多少条信源的信息的值。让我们增加一些数据来开始做些事情。

INSERT INTO rss VALUES(1, 'Slashdot', 'http://slashdot.org/slashdot.rdf', 5);
INSERT INTO rss VALUES(2, 'Wired News', 'http://www.wired.com/news_drop/netcenter/netcenter.rdf', 5);
INSERT INTO rss VALUES(3, 'Business News', 'http://www.npr.org/rss/rss.php?topicId=6', 3);
INSERT INTO rss VALUES(4, 'Health News',
'http://news.bbc.co.uk/rss/newsonline_world_edition/health/rss091.xml', 3);
INSERT INTO rss VALUES(5, 'Freshmeat', 'http://www.freshmeat.net/backend/fm-releases.rdf', 5);

  你可以使用SQLite命令直接从schema文件rss.sql中来创建所有这些。如果你仍然在使用来自第九章的命令行客户端,那么请从中读取。实际上,现在是你下载用于该应用程序的所有源代码的好时机,这样可以使得你在完成该教程的过程中容易地检查和参考。请注意,你将需要一个支持PHP 5的Web服务器来运行该代码。

  重要的消息

  将数据库安全的放置在其Web不可访问的目录内,下一步就是编写使用该数据库内数据连接至每个新闻信源,将其解析用于新闻数据然后展现一个定制的新闻页面的代码。

下面就是该代码usrer.php:

<?php
// PHP 5
// include configuration file
include('config.php');
// open database file
$handle = sqlite_open($db) or die('ERROR: Unable to open database!');
// generate and execute query
$query = "SELECT id, title, url, count FROM rss";
$result = sqlite_query($handle, $query) or die("ERROR: $query. ".sqlite_error_string(sqlite_last_error($handle)));
// if records present
if (sqlite_num_rows($result) > 0) {
// iterate through resultset
// fetch and parse feed
   while($row = sqlite_fetch_object($result)) {
$xml = simplexml_load_file($row->url);
echo "<h4>$row->title</h4>";
// print descriptions
      for ($x = 0; $x < $row->count; $x++) {
// for RSS 0.91
        if (isset($xml->channel->item)) {
$item = $xml->channel->item[$x];
}
// for RSS 1.0
        elseif (isset($xml->item)) {
$item = $xml->item[$x];
}
echo "<a href=\"$item->link\">$item->title</a><br />$item->description<p />";
}
echo "<hr />";
// reset variables
      unset($xml);
unset($item);
}
}
// if no records present
// display message
else {
?>
<font size = '-1'>No feeds currently configured</font>
<?php
}
// close connection
sqlite_close($handle);
?>

  下面是一种可能的输出(请注意,在产生页面的时候会有一个时间延迟,因为PHP将会悄悄地打开到每个URL的HTTP链接以检索相应的RSS信源):
 
  完成这项工作的代码可能看上去比较简单,但实际上,在系统后台,还有很多操作正在发生。第一步就是从SQLite数据库中获取用户配置的RSS信源列表。为了达到这个目的,初始化一个SQLite数据库句柄,然后执行一个SQL SELECT查询。While()循环用于遍历该查询结果的记录集。

  对于每个因此得到的URL,使用simplexml_load_file()函数以检索和读取RSS信源。取决于所显示的信息数目,执行一个for()循环,然后解析信源中<item>元素的适当数目。请注意,访问一个<item>元素的路径根据信源是RSS 0.91还是RSS1.0而不同。
请注意,如果数据库为空,那么会出现一条错误消息。在这个例子中,既然我已经插入了一系列的记录到数据库中,所以你根本不会看到错误消息;然而,保证所有的可能发生的事情甚至细微的事情都得到解决是良好的编程习惯。

  正如之前一样,文件config.php被包含在每个脚本的顶部。该文件包含数据库访问参数,如下所示:

<?php
// database details
// always use a directory that cannot be accessed from the web
$path = $_SERVER['DOCUMENT_ROOT'].'/../';
$db = $path.'rss.db';
?>

  点和点击

  随着新闻显示已不再是问题,所剩下的就是增加一个简单的管理工具来管理SQLite数据库的内容。这里的代码和你在PHP 101第14章所看到的将会十分相似:一个提供了当前数据库的快照以及增加新条目的表单的被称为admin.php的起始页面。此处为其全文:

<html>
<head><basefont face = 'Arial'></head>
<body>
<h2>Feed Manager</h2>
<h4>Current Feeds:</h4>
<table border = '0' cellspacing = '10'>
<?php
// PHP 5
// include configuration file
include('config.php');
// open database file
$handle = sqlite_open($db) or die('ERROR: Unable to open database!');
// generate and execute query
$query = "SELECT id, title, url, count FROM rss";
$result = sqlite_query($handle, $query) or die("ERROR: $query. ".sqlite_error_string(sqlite_last_error($handle)));
// if records present
if (sqlite_num_rows($result) > 0) {
// iterate through result set
// print article titles
   while ($row = sqlite_fetch_object($result)) {
?>
<tr>
<td><?php echo $row->title; ?> (<?php echo $row->count; ?>)</td>
<td><font size = '-2'><a href="delete.php?id=<?php echo $row->id; ?>">delete</a></font></td>
</tr>
<?php
}
}
// if there are no records present, display message
else {
?>
<font size = '-1'>No feeds currently configured</font>
<?php
}
// close connection
sqlite_close($handle);
?>
</table>
<h4>Add New Feed:</h4>
<form action = 'add.php' method = 'post'>
<table border = '0' cellspacing = '5'>
<tr>
<td>Title</td>
<td><input type = 'text' name = 'title'></td>
</tr>
<tr>
<td>Feed URL</td>
<td><input type = 'text' name = 'url'></td>
</tr>
<tr>
<td>Stories to display</td>
<td><input type = 'text' name = 'count' size = '2'></td>
</tr>
<tr>
<td colspan = '2' align = 'right'><input type = 'submit' name = 'submit' value = 'Add RSS Feed'></td>
</tr>
</table>
</form>
</body>
</html>

  下面是结果显示的样子:
 
  正如你所看到的那样,该脚本中有两个部分。前半部分连接至数据库然后打印所有当前配置的新闻信源的列表,每个新闻信源后面紧跟着“删除”连接。后半部分包含了一个用于管理员增加一个新的信源及其属性的表单。
一旦表单被递交,数据就被递交给脚本add.php,该脚本验证数据然后将其保存到数据库中,下面是add.php脚本中的代码:

<html>
<head><basefont face = 'Arial'></head>
<body>
<h2>Feed Manager</h2>
<?php
// PHP 5

if (isset($_POST['submit'])) {
// check form input for errors
// check title
   if (trim($_POST['title']) == '') {
die('ERROR: Please enter a title');
}
// check URL
   if ((trim($_POST['url']) == '') || !ereg("^http\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\._\?\,\'/\\\+&%\$#\=~\-])*$", $_POST['url'])) {
die('ERROR: Please enter a valid URL');
}
// check story number
   if (!is_numeric($_POST['count'])) {
die('ERROR: Please enter a valid story count');
}
// include configuration file
   include('config.php');
// open database file
   $handle = sqlite_open($db) or die('ERROR: Unable to open database!');
// generate and execute query
   $query = "INSERT INTO rss (title, url, count) VALUES ('".$_POST['title']."', '".$_POST['url']."', '".$_POST['count']."')";
$result = sqlite_query($handle, $query) or die("ERROR: $query. ".sqlite_error_string(sqlite_last_error($handle)));
// close connection
   sqlite_close($handle);
// print success message
   echo "Item successfully added to the database! Click <a href = 'admin.php'>here</a> to return to the main page";
}
else {
die('ERROR: Data not correctly submitted');
}
?>
</body>
</html>

  脚本的下半部分对你来说应该是熟悉的:它包含了常用的函数调用来打开SQLite数据库然后执行一条插入查询语句来保存用户数据到数据库中。然而有趣的是脚本的上半部分,它包含了一些输入测试以确保正在被保存的数据不包含无用数据。

  这里有三个测试。一个检查描述性题目是否存在,另外一个使用is_numeric()函数来验证用于信息数目的输入值是有效的数字,而第三个使用ereg()函数来检查URL的格式。如果你阅读了第十三章,那么你将会完全了解验证用户输入的重要性;在这里,该理论在起作用。

  上面的代码负责增加新的RSS信源。现在,怎样去除它们呢?

  回忆一下在admin.php文件中列表中显示的每个信源如何拥有一个“删除”链接,该链接指向了脚本delete.php。假定给出一个信源ID号(通过链接传递),该delete.php脚本负责从表格中删除一个新闻信源。请看代码然后事情会变得更加清楚:

<html>
<head><basefont face = 'Arial'></head>
<body>
<h2>Feed Manager</h2>
<?php
// PHP 5

if (isset($_GET['id']) && is_numeric($_GET['id'])) {
// include configuration file
   include('config.php');
// open database file
   $handle = sqlite_open($db) or die('ERROR: Unable to open database!');
// generate and execute query
   $query = "DELETE FROM rss WHERE id = '".$_GET['id']."'";
$result = sqlite_query($handle, $query) or die("ERROR: $query. ".sqlite_error_string(sqlite_last_error($handle)));
// close connection
   sqlite_close($handle);
// print success message
   echo "Item successfully removed from the database! Click <a href = 'admin.php'>here</a> to return to the main page";
}
else {
die('ERROR: Data not correctly submitted');
}
?>
</body>
</html>

  通过URL GET方法传递的记录ID号由delete.php脚本获得,然后使用DELETE SQL查询来删除对应的记录。请亲自试验然后查看结果。

  那就是我为你准备的一切。我希望你喜爱这总共15章的PHP 101旅程,而且希望你觉得它既有教育意义也有趣(我知道,我是这么觉得的,而且有你在前行中伴随是一种乐趣)。如果你期望阅读更多的关于PHP的特定方面内容,请访问www.melonfire.com然后浏览部分更多我的教程和文章。到那时… 编码快乐!

关键词:PHP