* Replaced the RDF support (rdf.php) with a newer version (backend.php).

The new version is a generic framework that has everything ready to add
  support RSS and XML backends in a 100% transparant way.  It's a flexible
  framework. Other changes include: better coding, improved robustness and
  readability.
* RSS and XML support will be integrated in near future.
* Cache-invalidation is set to 30 minutes.
3-00
Dries Buytaert 2000-05-25 20:35:18 +00:00
parent 6590fec2e0
commit 70d7a06c70
5 changed files with 404 additions and 257 deletions

View File

@ -7,7 +7,6 @@ function navigation() {
}
function validateAccount($uname, $email) {
### Verify username and e-mail address:
if ((!$email) || ($email=="") || (strrpos($uname,' ') > 0) || (!eregi("^[_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,3}$", $email))) $rval = "the specified e-mail address is not valid.<BR>";
if ((!$uname) || ($uname=="") || (ereg("[^a-zA-Z0-9_-]",$uname))) $rval = "the specified username '$uname' is not valid.<BR>";
@ -319,7 +318,7 @@ function user_edit_home() {
<P>
<B>Theme:</B><BR>
<SELECT NAME="theme">
<SELECT NAME="thm">
<?php
include "themes/list.php";
$themelist = explode(" ", $themelist);
@ -351,7 +350,7 @@ function user_edit_home() {
$theme->footer();
}
function user_save_home($uid, $uname, $storynum, $theme, $ublockon, $ublock) {
function user_save_home($uid, $uname, $storynum, $thm, $ublockon, $ublock) {
global $user, $userinfo;
include "functions.inc";
dbconnect();
@ -362,7 +361,7 @@ function user_save_home($uid, $uname, $storynum, $theme, $ublockon, $ublock) {
getusrinfo($user);
mysql_query("UNLOCK TABLES");
docookie($userinfo[uid],$userinfo[uname],$userinfo[pass],$userinfo[storynum],$userinfo[umode],$userinfo[uorder],$userinfo[thold],$userinfo[noscore],$userinfo[ublockon],$userinfo[theme]);
Header("Location: account.php?theme=$theme");
Header("Location: account.php?theme=$thm");
}
function user_edit_comm() {
@ -472,7 +471,7 @@ switch($op) {
user_edit_home();
break;
case "Save homepage settings":
user_save_home($uid, $uname, $storynum, $theme, $ublockon, $ublock);
user_save_home($uid, $uname, $storynum, $thm, $ublockon, $ublock);
userinfo($uname);
break;
case "editcomm":

256
backend.class.php Normal file
View File

@ -0,0 +1,256 @@
<?
include "functions.inc";
class backend {
// Channel properties:
var $id;
var $url;
var $site;
var $file;
var $contact;
var $timestamp;
// Contains the raw rdf/rss/xml file:
var $data;
// Contains the parsed rdf/rss/xml file:
var $headlines = array(); // latest headlines
#####
# Syntax.......: backend(...);
# Description..: Constructor - initializes the internal variables.
#
function backend($id, $site, $url, $file, $contact, $timout = 1800) {
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel WHERE id = '$id' OR site = '$site'");
if ($channel = mysql_fetch_object($result)) {
### Initialize internal variables:
$this->id = $channel->id;
$this->site = $channel->site;
$this->file = $channel->file;
$this->url = $channel->url;
$this->contact = $channel->contact;
$this->timestamp = $channel->timestamp;
### Check to see whether we have to update our headlines first:
if (time() - $this->timestamp > $timout) $this->url2sql();
### Read headlines:
$result = mysql_query("SELECT * FROM headlines WHERE id = $this->id ORDER BY number");
while ($headline = mysql_fetch_object($result)) {
array_push($this->headlines, "<A HREF=\"$headline->link\">$headline->title</A>");
}
}
else {
$this->site = $site;
$this->url = $url;
$this->file = $file;
$this->contact = $contact;
}
}
#####
# Syntax.......: rdf2sql(optional timout value in seconds);
# Description..: Reads a RDF file from a server, parses it and inserts
# the fresh data in a MySQL table.
#
function rdf2sql($timout = 10) {
if ($this->file) {
### Decode URL:
$url = parse_url($this->file);
$host = $url[host];
$port = $url[port] ? $url[port] : 80;
$path = $url[path];
// print "<PRE>$url - $host - $port - $path</PRE>";
### Retrieve data from website:
$fp = fsockopen($host, $port, &$errno, &$errstr, $timout);
if ($fp) {
### Get data from URL:
fputs($fp, "GET $path HTTP/1.0\n");
fputs($fp, "User-Agent: headline grabber\n");
fputs($fp, "Host: ". $host ."\n");
fputs($fp, "Accept: */*\n\n");
while(!feof($fp)) $data .= fgets($fp, 128);
// print "<PRE>$data</PRE><HR>";
if (strstr($data, "200 OK")) {
### Remove existing entries:
$result = mysql_query("DELETE FROM headlines WHERE id = $this->id");
### Strip all 'junk':
$data = ereg_replace("<?xml.*/image>", "", $data);
$data = ereg_replace("</rdf.*", "", $data);
$data = chop($data);
### Iterating through our data processing each entry/item:
$items = explode("</item>", $data);
$number = 0;
for (reset($items); $item = current($items); next($items)) {
### Extract data:
$link = ereg_replace(".*<link>", "", $item);
$link = ereg_replace("</link>.*", "", $link);
$title = ereg_replace(".*<title>", "", $item);
$title = ereg_replace("</title>.*", "", $title);
### Clean headlines:
$title = stripslashes(fixquotes($title));
### Count the number of stories:
$number += 1;
### Insert item in database:
$result = mysql_query("INSERT INTO headlines (id, title, link, number) VALUES('$this->id', '$title', '$link', '$number')");
}
### Mark channels as being updated:
$result = mysql_query("UPDATE channel SET timestamp = '". time() ."' WHERE id = $this->id");
$this->timestamp = time();
}
else print "<HR>RDF parser: 404 error?<BR><BR><PRE>$data</PRE><HR>";
}
}
}
#####
# Syntax.......: rss2sql(optional timout value in seconds);
# Description..: Reads a RSS file from a server, parses it and inserts
# the fresh data in a MySQL table.
#
function rss2sql($timout = 10) {
print "backend->rss2sql : TODO<BR>";
}
#####
# Syntax.......: xml2sql(optional timout value in seconds);
# Description..: Reads a XML file from a server, parses it and inserts
# the fresh data in a MySQL table.
#
function xml2sql($timout = 10) {
print "backend->xml2sql : TODO<BR>";
}
#####
# Syntax.......: url2sql(optional timout value in seconds);
# Description..: Generic function to fetch fresh headlines. It checks whether
# we are dealing with a remote RDF, RSS or XML file and calls
# the appropriate function to fetch the headline. The function
# is an abstraction towards the programmer as he doesn't need
# to know with what file extension we are dealing.
#
function url2sql($timout = 10) {
if (strstr($this->file, ".rdf")) $this->rdf2sql($timout);
if (strstr($this->file, ".rss")) $this->rss2sql($timout);
if (strstr($this->file, ".xml")) $this->xml2sql($timout);
}
#####
# Syntax.......:
# Description..:
#
function displayHeadlines($timout = 1800) {
global $theme;
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel WHERE site = '$this->site'");
if ($this->id) {
### Check to see whether we have to update our headlines first:
if (time() - $this->timestamp > $timout) $this->url2sql();
### Grab headlines from database:
$result = mysql_query("SELECT * FROM headlines WHERE id = $this->id ORDER BY number");
while ($headline = mysql_fetch_object($result)) {
$content .= "<LI><A HREF=\"$headline->link\">$headline->title</A></LI>";
}
### Add timestamp:
$update = round((time() - $this->timestamp) / 60);
$content .= "<P ALIGN=\"right\">[ <A HREF=\"backend.php?op=reset&site=$this->site\"><FONT COLOR=\"$theme->hlcolor2\">reset</FONT></A> | updated $update min. ago ]</P>";
### Display box:
$theme->box("$this->site", $content);
}
else print "<P>Warning: something whiched happened: specified channel could not be found in database.</P>";
}
#####
# Syntax.......: add()
# Description..: Adds this backend to the database.
#
function add() {
### Connect to database:
dbconnect();
### Add channel:
$result = mysql_query("INSERT INTO channel (site, file, url, contact, timestamp) VALUES ('$this->site', '$this->file', '$this->url', '$this->contact', 42)");
}
#####
# Syntax.......: delete()
# Description..: Deletes this backend
#
function delete() {
### Connect to database:
dbconnect();
### Delete channel:
$result = mysql_query("DELETE FROM channel WHERE id = $this->id");
### Delete headlines:
$result = mysql_query("DELETE FROM headlines WHERE id = $this->id");
}
#####
# Syntax.......: refresh()
# Description..: Deletes all headlines associated with this backend.
#
function refresh() {
### Connect to database:
dbconnect();
### Delete headlines:
$result = mysql_query("DELETE FROM headlines WHERE id = $this->id");
### Mark channel as invalid to enforce an update:
$result = mysql_query("UPDATE channel SET timestamp = 42 WHERE id = $this->id");
}
#####
# Syntax.......: dump()
# Description..: Dumps the content of this class to screen.
#
function dump() {
print "<B>Dump backend:</B><BR>";
print "Id: $this->id<BR>";
print "Site: $this->site<BR>";
print "URL: $this->url<BR>";
print "File: $this->file<BR>";
print "Contact: $this->contact<BR>";
}
}
?>

130
backend.php Normal file
View File

@ -0,0 +1,130 @@
<?
include "theme.inc";
include "backend.class.php";
function adminAddChannel() {
?>
<HR>
<FORM ACTION="backend.php" METHOD="post">
<P>
<B>Site name:</B><BR>
<INPUT TYPE="text" NAME="site" SIZE="50">
</P>
<P>
<B>URL:</B><BR>
<INPUT TYPE="text" NAME="url" SIZE="50">
</P>
<P>
<B>Backend file:</B><BR>
<INPUT TYPE="text" NAME="file" SIZE="50">
</P>
<P>
<B>Contact information:</B><BR>
<INPUT TYPE="text" NAME="contact" SIZE="50">
</P>
<INPUT TYPE="submit" NAME="op" VALUE="Add backend">
</FORM>
<?
}
function displayAll() {
global $theme;
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel ORDER BY id");
print "<HR>";
print "<TABLE BORDER=\"0\">";
while ($channel = mysql_fetch_object($result)) {
if ($state % 3 == 0) print " <TR>";
print " <TD ALIGN=\"center\" VALIGN=\"top\" WIDTH=\"33%\">";
### Load backend from database:
$backend = new backend($channel->id);
### Read headlines from backend class:
$content = "";
for (reset($backend->headlines); $headline = current($backend->headlines); next($backend->headlines)) {
$content .= "<LI>$headline</LI>";
}
### Print backend box to screen:
$theme->box($backend->site, "$content<P ALIGN=\"right\">[ <A HREF=\"$backend->url\">more</A> ]");
print " </TD>";
if ($state % 3 == 2) print " </TR>";
$state += 1;
}
print "</TABLE>";
}
function adminMain() {
global $theme, $PHP_SELF;
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel ORDER BY id");
print "<TABLE BORDER=\"0\" WIDTH=\"100%\" CELLSPACING=\"2\" CELLPADDING=\"4\">";
print "
<TR BGCOLOR=\"$theme->bgcolor1\"><TD ALIGN=\"center\"><B><FONT COLOR=\"$theme->fgcolor1\">Site</FONT></B></TD><TD ALIGN=\"center\"><B><FONT COLOR=\"$theme->fgcolor1\">Contact</FONT></B></TD><TD ALIGN=\"center\"><B><FONT COLOR=\"$theme->fgcolor1\">Last updated</FONT></B></TD><TD ALIGN=\"center\" COLSPAN=\"2\"><B><FONT COLOR=\"$theme->fgcolor1\">Operations</FONT></B></TD></TR>";
while ($channel = mysql_fetch_object($result)) {
### Load backend from database:
$backend = new backend($channel->id);
print "<TR BGCOLOR=\"$theme->bgcolor2\">";
print " <TD><A HREF=\"$backend->url\">$backend->site</A></TD>";
print " <TD><A HREF=\"mailto:$backend->contact\">$backend->contact</A></TD>";
print " <TD ALIGN=\"center\">". round((time() - $backend->timestamp) / 60) ." min. ago</TD>";
print " <TD ALIGN=\"center\"><A HREF=\"$PHP_SELF?op=refresh&id=$backend->id\">refresh</A></TD>";
print " <TD ALIGN=\"center\"><A HREF=\"$PHP_SELF?op=delete&id=$backend->id\">delete</A></TD>";
print "</TR>";
}
print "</TABLE>";
print "<BR><BR>";
}
$theme->header();
switch($op) {
case "refresh":
$backend = new backend($id);
$backend->refresh();
adminMain();
displayAll();
adminAddChannel();
break;
case "delete":
print "ID = $id<BR>";
$backend = new backend($id);
$backend->dump();
$backend->delete();
adminMain();
displayAll();
adminAddChannel();
break;
case "Add backend":
$backend = new backend($id, $site, $url, $file, $contact);
$backend->add();
// fall through:
default:
adminMain();
displayAll();
adminAddChannel();
}
$theme->footer();
?>

View File

@ -1,3 +1,14 @@
DROP TABLE authors;
DROP TABLE stories;
DROP TABLE blocks;
DROP TABLE channel;
DROP TABLE comments;
DROP TABLE headlines;
DROP TABLE poll;
DROP TABLE queue;
DROP TABLE users;
DROP TABLE webboard;
# MySQL dump 7.1
#
# Host: zind.net Database: dries
@ -48,12 +59,13 @@ INSERT INTO blocks VALUES (1,'','Development','<P>These links point to pages or
CREATE TABLE channel (
id int(11) DEFAULT '0' NOT NULL auto_increment,
site varchar(255) DEFAULT '' NOT NULL,
file varchar(255) DEFAULT '' NOT NULL,
url varchar(255) DEFAULT '' NOT NULL,
rdf varchar(255) DEFAULT '' NOT NULL,
contact varchar(255) DEFAULT '',
timestamp int(11),
UNIQUE site (site),
UNIQUE file (file),
UNIQUE url (url),
UNIQUE rdf (rdf),
PRIMARY KEY (id)
);

250
rdf.php
View File

@ -1,250 +0,0 @@
<?
include "functions.inc";
include "theme.inc";
class rdf {
// Contains the raw rdf file:
var $data;
// Contains the parsed rdf file:
var $title; // website name
var $items; // latest headlines
function url2sql($site, $timout = 10) {
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel WHERE site = '$site'");
if ($channel = mysql_fetch_object($result)) {
### Decode URL:
$url = parse_url($channel->rdf);
$host = $url[host];
$port = $url[port] ? $url[port] : 80;
$path = $url[path];
// print "<PRE>$url - $host - $port - $path</PRE>";
### Retrieve data from website:
$fp = fsockopen($host, $port, &$errno, &$errstr, $timout);
if ($fp) {
### Get data from URL:
fputs($fp, "GET $path HTTP/1.0\n");
fputs($fp, "User-Agent: headline grabber\n");
fputs($fp, "Host: ". $host ."\n");
fputs($fp, "Accept: */*\n\n");
while(!feof($fp)) $data .= fgets($fp, 128);
// print "<PRE>$data</PRE><HR>";
if (strstr($data, "200 OK")) {
### Remove existing entries:
$result = mysql_query("DELETE FROM headlines WHERE id = $channel->id");
### Strip all 'junk':
$data = ereg_replace("<?xml.*/image>", "", $data);
$data = ereg_replace("</rdf.*", "", $data);
$data = chop($data);
### Iterating through our data processing each entry/item:
$items = explode("</item>", $data);
$number = 0;
for (reset($items); $item = current($items); next($items)) {
### Extract data:
$link = ereg_replace(".*<link>", "", $item);
$link = ereg_replace("</link>.*", "", $link);
$title = ereg_replace(".*<title>", "", $item);
$title = ereg_replace("</title>.*", "", $title);
### Clean headlines:
$title = stripslashes(fixquotes($title));
### Count the number of stories:
$number += 1;
### Insert item in database:
$result = mysql_query("INSERT INTO headlines (id, title, link, number) VALUES('$channel->id', '$title', '$link', '$number')");
}
### Mark channels as being updated:
$result = mysql_query("UPDATE channel SET timestamp = '". time() ."' WHERE id = $channel->id");
}
else print "<HR>RDF parser: 404 error?<BR><BR><PRE>$data</PRE><HR>";
}
}
}
function displayHeadlines($site, $timout = 1800) {
global $theme;
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel WHERE site = '$site'");
if ($channel = mysql_fetch_object($result)) {
### Check to see whether we have to update our headlines first:
if (time() - $channel->timestamp > $timout) $this->url2sql($site);
### Grab headlines from database:
$result = mysql_query("SELECT * FROM headlines WHERE id = $channel->id ORDER BY number");
while ($headline = mysql_fetch_object($result)) {
$content .= "<LI><A HREF=\"$headline->link\">$headline->title</A></LI>";
}
### Add timestamp:
$update = round((time() - $channel->timestamp) / 60);
$content .= "<P ALIGN=\"right\">[ <A HREF=\"rdf.php?op=reset&id=$channel->id\"><FONT COLOR=\"$theme->hlcolor2\">reset</FONT></A> | updated $update min. ago ]</P>";
### Display box:
$theme->box("$channel->site", $content);
}
else print "<P>Warning: something whiched happened: specified channel could not be found in database.</P>";
}
function addChannel($site, $url, $rdf) {
### Connect to database:
dbconnect();
### Add channel:
$query = mysql_query("INSERT INTO channel (site, url, rdf, timestamp) VALUES ('$site', '$url', '$rdf', now())");
}
function resetChannel($id) {
### Connect to database:
dbconnect();
### Delete headlines:
$result = mysql_query("DELETE FROM headlines WHERE id = $id");
### Mark channel as invalid to enforce an update:
$result = mysql_query("UPDATE channel SET timestamp = 42 WHERE id = $id");
}
}
function adminAddChannel() {
?>
<HR>
<FORM ACTION="rdf.php" METHOD="post">
<P>
<B>Site name:</B><BR>
<INPUT TYPE="text" NAME="site" SIZE="50">
</P>
<P>
<B>URL:</B><BR>
<INPUT TYPE="text" NAME="url" SIZE="50">
</P>
<P>
<B>RDF file:</B><BR>
<INPUT TYPE="text" NAME="rdf" SIZE="50">
</P>
<INPUT TYPE="submit" NAME="op" VALUE="Add RDF channel">
</FORM>
<?
}
function adminDisplayAll() {
### Connect to database:
dbconnect();
### Get channel info:
$result = mysql_query("SELECT * FROM channel ORDER BY id");
print "<TABLE BORDER=\"0\">";
while ($channel = mysql_fetch_object($result)) {
if ($state % 3 == 0) print " <TR>";
print " <TD ALIGN=\"center\" VALIGN=\"top\" WIDTH=\"33%\">";
$rdf = new rdf();
$rdf->displayHeadlines($channel->site);
print " </TD>";
if ($state % 3 == 2) print " </TR>";
$state += 1;
}
print "</TABLE>";
}
function adminDisplayInfo() {
?>
<H1>Headlines</H1>
Dries was here.
<H3>Concept</H3>
<P>
RDF support can change a portal in a significant way: third party websites
can become <I>channels</I> in our portal without having to make 'real' deals
and with a minimum of extra work. All they need to do is to publish an RDF,
so we can include their latest updates in our portal. Yet another easy way
to add content.
</P>
<P>
That in and of itself is interesting, but it's not half so interesting as
the fact that other sites can include our headlines as well. Anyone can
grab our RDF, anyone can parse it, and anyone can put a list of our
headlines. Yet another way to generate more traffic.
</P>
<H3>Features</H3>
<P>
One of the most important features (if not the most important) is
chaching support. To avoid bogging down other portals with a continous
stream of headline grabbing, all headlines are cached and refreshed once
in a while. The 'while' can be costumized but is set to 30 minutes by
default.
</P>
<P>
You can reset a channel, that is force to update a channels headlines
and you can add new channels. If you don't know what channel to add,
check <A HREF="http://www.xmltree.com/">http://www.xmltree.com/</A>.
Make sure you don't add anything except valid RDF files!
</P>
<H3>Status</H3>
<P>
The RDF parser is still in beta and needs proper integration in the engine.
Until then this test page generates nothing more then an overview off all
subscribed channels along with their headlines: handy for news squatting. ;)
</P>
<P>
RDF files are non-proprietary and publically available. Unfortunatly,
RDF is not the only standard: another commonly used format is RSS which
would be nice to support as well.
</P>
<HR>
<?
}
$theme->header();
switch($op) {
case "reset":
$channel = new rdf();
$channel->resetChannel($id);
print "<H2>channel has been reset</H2>";
print "<A HREF=\"rdf.php\">back</A>";
break;
case "Add RDF channel":
$channel = new rdf();
$channel->addChannel($site, $url, $rdf);
// fall through:
default:
adminDisplayInfo();
adminDisplayAll();
adminAddChannel();
}
$theme->footer();
?>