3 Outputs RSS/Atom feeds, multiple versions supported (RSS 0.91, 1.0, 2.0,
4 3.0 and Atom 0.3); what clients get depends on what they asked for:
5 - Accept: text/x-rss; revision=2.0
6 - Accept: application/atom+xml
9 //define("EWIKI_DESC", "ThisWiki - site slogan..."); # site description
10 //define("EWIKI_COPY", "PrimarilyPublicDomain"); # site copyright
11 //define("EWIKI_CATEGORY", "Technique"); # site subject
12 //define("EWIKI_LOGO_URL", "http://.../logo.png");
15 #---------------------------------------------------------------------------
16 # outputs a feed from the given array of page $data hashes
18 function ewiki_feed($pages, $type="AUTO")
23 #-- general feed infos
25 "title" => EWIKI_NAME,
26 "lang" => EWIKI_DEFAULT_LANG,
27 "desc" => defined("EWIKI_DESC")?EWIKI_DESC : EWIKI_NAME . " - an open hypertext site",
28 "copyright" => defined("EWIKI_COPY")?EWIKI_COPY : "copyrighted",
29 "category" => defined("EWIKI_CATEGORY")?EWIKI_CATEGORY : "None",
30 // "logo" => defined("EWIKI_LOGO_URL")?EWIKI_LOGO_URL : "http://erfurtwiki.sf.net/squirrel.jpeg",
31 "url" => ewiki_script_url(),
32 "rc_url" => ewiki_script_url("", "UpdatedPages"),
33 "ewiki" => "ewiki/".EWIKI_VERSION,
34 "charset" => EWIKI_CHARSET,
37 #-- fix/prepare feed entries
38 $lm = UNIX_MILLENNIUM;
39 foreach ($pages as $i=>$data) {
40 if (!is_array($data)) {
41 $data = ewiki_db::GET($data);
46 if (empty($data["title"])) { $pages[$i]["title"] = ewiki_split_title($data["id"], -1, 0); }
47 if (empty($data["url"])) { $pages[$i]["url"] = ewiki_script_url("", $data["id"]); }
48 if (empty($data["uri"])) { $pages[$i]["uri"] = "x-wiki:".EWIKI_NAME.":".ewiki_xmlentities(urlencode($data["id"])); }
49 if (empty($data["guid"])) { $pages[$i]["guid"] = ewiki_script_url("", $data["id"], "version=$data[version]"); }
51 $pages[$i]["content"] = strtr(ewiki_xmlentities(substr($data["content"], 0, 300)), "\r\n\t\f", " ");
52 $pages[$i]["pdate"] = gmstrftime("%a, %d %b %G %T %Z", $data["lastmodified"]);
53 $pages[$i]["idate"] = gmstrftime("%G%m%dT%TZ", $data["lastmodified"]);
54 $pages[$i]["icdate"] = gmstrftime("%G%m%dT%TZ", $data["created"]);
55 if ($lm < $data["lastmodified"]) {
56 $lm = $data["lastmodified"];
58 $data["content"] = "";
60 $info["modified"] = $lm;
62 #-- respect some common parameters
63 if (($limit = $_REQUEST["limit"])
64 or ($limit = $_REQUEST["items"])
65 or ($limit = $ewiki_config["list_limit_rss"])
66 or ($limit = $ewiki_config["list_limit"])) {
67 $pages = array_slice($pages, 0, $limit);
70 #-- encode everything into UTF-8?
73 #-- engage compression
74 if ($_SERVER["HTTP_ACCEPT_ENCODING"]) {
75 ob_start("ob_gzhandler");
80 if (!is_string($type) || (strtoupper($type)=="AUTO") || ($type=="*")) {
81 $type = ewiki_feed_type();
83 header("Vary: accept,negotiate");
84 header("TCN: choice");
87 ewiki_feed_rss0($feed_info, $pages);
89 ewiki_feed_rss2($feed_info, $pages);
91 ewiki_feed_rss3($feed_info, $pages);
93 ewiki_feed_rss1($feed_info, $pages);
95 ewiki_feed_atom($feed_info, $pages);
98 header("Status: 406 Not Acceptable");
99 header("Content-Type: text/plain");
100 die("You are using a pretty dumb feed reader, it didn't\n".
101 "send any appropriate Accept: header. Go away.");
108 #---------------------------------------------------------------------------
109 # returns Netscape RSS 0.91 (other versions are neglectable)
111 function ewiki_feed_rss0($info, $pages)
113 # header('Content-Type: text/x-rss');
114 header('Content-Type: application/rss+xml; revision="0.91"');
116 $pages = array_slice($pages, 0, 15);
117 $name = $info["title"];
120 <?xml version="1.0" encoding="$info[charset]"?>
121 <!DOCTYPE rss PUBLIC "-//Netscape Communications//DTD RSS 0.91//EN" "http://my.netscape.com/publish/formats/rss-0.91.dtd">
124 <title>$info[title]</title>
125 <language>$info[lang]</language>
126 <description>$info[desc]</description>
127 <link>$info[url]</link> \n
131 foreach ($pages as $data) {
134 <title>$data[title]</title>
135 <link>$data[url]</link>
136 <description>$data[content]</description>
137 <pubDate>$data[pdate]</pubDate>
142 echo " </channel>\n</rss>\n";
148 #---------------------------------------------------------------------------
151 function ewiki_feed_rss2($info, $pages)
153 header('Content-Type: application/rss+xml; revision="2.0"');
155 $name = $info["title"];
158 <?xml version="1.0" encoding="$info[charset]"?>
161 <title>$info[title]</title>
162 <link>$info[url]</link>
163 <language>$info[lang]</language>
164 <description>$info[desc]</description>
165 <generator>$info[ewiki]</generator>
166 <webMaster>$_SERVER[SERVER_ADMIN]</webMaster>\n
170 foreach ($pages as $data) {
173 <title>$data[title]</title>
174 <link>$data[url]</link>
175 <description>$data[content]</description>
176 <pubDate>$data[pdate]</pubDate>
177 <guid>$data[guid]</guid>
182 echo " </channel>\n</rss>\n";
188 #---------------------------------------------------------------------------
189 # outputs RSS 3.0 (text/plain, much like 822)
191 function ewiki_feed_rss3($info, $pages)
193 header('Content-Type: text/plain; charset="'.$info["charset"].'"');
195 $name = $info["title"];
200 language: $info[lang]
201 description: $info[desc]
202 generator: $info[ewiki]
203 webMaster: $_SERVER[SERVER_ADMIN]
204 rights: $info[copyright]
209 foreach ($pages as $data) {
215 description: $data[content]
216 created: $data[icdate]
217 last-modified: $data[idate]
228 #---------------------------------------------------------------------------
229 # returns RDF/RSS1.0 (no real RSS, obsoleted by Atom)
231 function ewiki_feed_rss1($info, $pages)
233 header('Content-Type: application/rss+xml; revision="1.0"');
235 $name = $info["title"];
236 $urnpfix = "x-wiki"; // uniform resource name prefix ("urn:x-wiki" was ok)
239 $_logo = $info["logo"] ? "<image rdf:resource=\"$urnpfix:$name:logo#1\" />\n" : "";
242 <?xml version="1.0" encoding="$info[charset]"?>
244 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
245 xmlns:dc="http://purl.org/dc/elements/1.1/"
246 xmlns:RSS="http://purl.org/rss/1.0/"
247 xmlns:wiki="http://purl.org/rss/1.0/modules/wiki/">
248 <RSS:channel rdf:about="$info[url]">
249 <RSS:title>$name</RSS:title>
250 <dc:title>$name</dc:title>
251 <RSS:link>$info[rc_url]</RSS:link>
252 <RSS:description>UpdatedPages on $name</RSS:description>
253 <wiki:interwiki>$name</wiki:interwiki>
259 foreach ($pages as $i=>$data) {
260 $pages[$i]["rdf_id"] = "$urnpfix:$name:".ewiki_xmlentities(urlencode($data["id"]))."#$data[version]_$data[lastmodified]";
261 echo ' <rdf:li rdf:resource="'.$pages[$i]["rdf_id"].'"/>' . "\n";
267 <!-- RDF associated data for references from above -->\n
272 <RSS:image rdf:about="$urnpfix:$name:logo#1">
273 <RSS:title>$name</RSS:title>
274 <RSS:link>$url</RSS:link>
275 <RSS:url>$info[logo]</RSS:url>
281 foreach ($pages as $i=>$data) {
282 preg_match('/^([^\s]+).+\(.*([\d.]+)\)/', $data["author"], $uu);
283 $author_host = $uu[2];
284 $author_name = $uu[1];
285 $url_diff = ewiki_script_url("diff", $data["id"]);
286 $url_info = ewiki_script_url("info", $data["id"]);
287 $stat = ($data["version"]==1) ? "created" : "updated";
289 <RSS:item rdf:about="$data[rdf_id]">
290 <RSS:title>$data[title]</RSS:title>
291 <dc:title>$data[title]</dc:title>
292 <RSS:description>$data[content]</RSS:description>
293 <RSS:link>$data[url]</RSS:link>
294 <wiki:diff>$url_diff</wiki:diff>
295 <wiki:history>$url_info</wiki:history>
296 <wiki:version>$data[version]</wiki:version>
297 <wiki:status>$stat</wiki:status>
298 <dc:date>$data[idate]</dc:date>
300 <rdf:Description wiki:host="$author_host">
301 <rdf:value>$author_name</rdf:value>
314 #---------------------------------------------------------------------------
315 # returns ATOM 0.3 feed
317 function ewiki_feed_atom($info, $pages)
319 header('Content-Type: application/atom+xml');
320 $name = $info["title"];
321 $ilm = gmstrftime("%G%m%dT%TZ", $info["modified"]);
324 <?xml version="1.0" encoding="$info[charset]"?>
325 <feed version="0.3" xmlns="http://purl.org/atom/ns#">
327 <link rel="alternate" type="text/html" href="$info[url]"/>
328 <modified>$ilm</modified>
330 <generator>$info[ewiki]</generator>\n
334 foreach ($pages as $i=>$data) {
335 $etag = ewiki_etag($data);
338 <title>$data[title]</title>
339 <link rel="alternate" type="text/html" href="$data[url]"/>
341 <issued>$data[icdate]</issued>
342 <created>$data[icdate]</created>
343 <modified>$data[idate]</modified>
344 <content>$data[content]</content>
355 #---------------------------------------------------------------------------
356 # checks HTTP Accept: header for guessing what's desired
357 # (btw, we just ignore dumb and HTTP incompliant clients)
359 function ewiki_feed_type()
361 $regex_RSS = '#^(text|application)/(x[-.])*rss(\+xml)?$|^\*/\*$#';
362 $regex_RDF = '#^(text|application)/(x[-.])*(rss[-.+])?rdf([-.]rss)?(\+xml)?$#';
363 $regex_ATOM= '#^(text|application)/(x[-.])*atom(\+xml)*$#';
365 $types = ewiki_sort_accept($_SERVER["HTTP_ACCEPT"]);
366 foreach ($types as $type=>$attr) {
368 if (preg_match($regex_RSS, $type) || ($type == "text/xml")) {
369 $ver = isset($attr["version"]) ? (int) $attr["version"] : (int) $attr["revision"];
371 $WHAT = "RSS$ver"; // one of "RSS0", "RSS1", "RSS2", "RSS3"
378 elseif (preg_match($regex_ATOM, $type)) {
383 elseif (preg_match($regex_RDF, $type))
384 { $WHAT = "RSS1"; break; }
385 elseif ($type == "text/plain")
386 { $WHAT = "RSS3"; break; }
387 elseif ($type == "*/*")
395 #---------------------------------------------------------------------------
396 # evaluates and sorts Accept: header (and alikes)
398 function ewiki_sort_accept($str) {
402 foreach (explode(",", $str) as $type) {
403 $type = strtok(trim($type), ";");
405 if ($params = trim(strtok("\000"))) {
406 foreach (explode(";", $params) as $p) {
407 $pname = trim(strtok($p, "="));
408 $val = trim(strtok("\000"));
410 ($q = $val * 1.0) or ($q = $def);
412 $attr[$type][$pname] = $val;
418 foreach ($r as $t=>$uu) {
425 #-- PHP backwards compatibility
426 if (!function_exists("xmlentities")) {
427 function xmlentities($str) {
428 return strtr($str, array("&"=>"&", "<"=>"<",
429 ">"=>">", "\""=>""", "'"=>"'"));
433 #-- does not reescape numeric XML entities
434 function ewiki_xmlentities($str) {
435 $xe = array("&"=>"&", "<"=>"<", ">"=>">", "\""=>""", "'"=>"'");
436 return preg_replace("/(&(?>!#x|#\d)|[<>\"'])/e", '$xe["$1"]', $str);