[pmwiki-users] Read RSS feeds
Patrick R. Michaud
pmichaud at pobox.com
Thu Jan 26 12:14:40 CST 2006
On Thu, Jan 26, 2006 at 07:01:41PM +0100, Jean DEMARTINI wrote:
> I have (by patching the feeds.php file):
> - changed <dc:date> by <pubDate>,
> - used the RFC822 date format,
>
> and then items updating date is taken in account.
There's no need to eliminate <dc:date> -- I'm pretty sure
it's okay for a feed to have both a <dc:date> and a <pubDate>.
This would hit a wider variety of readers.
I've gone ahead and updated feeds.php to include <pubDate> in
rss feeds. The new version is attached, and will be in the
beta21 release.
Pm
-------------- next part --------------
<?php if (!defined('PmWiki')) exit();
/* Copyright 2005 Patrick R. Michaud (pmichaud at pobox.com)
This file is part of PmWiki; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; either version 2 of the License, or
(at your option) any later version. See pmwiki.php for full details.
This script provides a number of syndication feed and xml-based
metadata options to PmWiki, including Atom, RSS 2.0, RSS 1.0 (RDF),
and the Dublin Core Metadata extensions. This module is typically
activated from a local configuration file via a line such as
if ($action == 'atom') include_once("$FarmD/scripts/feeds.php");
if ($action == 'dc') include_once("$FarmD/scripts/feeds.php");
When enabled, ?action=atom, ?action=rss, and ?action=rdf produce
syndication feeds based on any wikitrail contained in the page,
or, for Category pages, on the pages in the category. The feeds
are generated using pagelist, thus one can include parameters such
as count=, list=, order=, etc. in the url to adjust the feed output.
?action=dc will normally generate Dublin Core Metadata for the
current page only, but placing a group=, trail=, or link= argument
in the url causes it to generate metadata for all pages in the
associated group, trail, or backlink.
There are a large number of customizations available, most of which
are controlled by the $FeedFmt array. Elements $FeedFmt look like
$FeedFmt['atom']['feed']['rights'] = 'All Rights Reserved';
where the first index corresponds to the action (?action=atom),
the second index indicates a per-feed or per-item element, and
the third index is the name of the element being generated.
The above setting would therefore generate a
"<rights>All Rights Reserved</rights>" in the feed for
?action=atom. If the value of an entry begins with a '<',
then feeds.php doesn't automatically add the tag around it.
Elements can also be callable functions which are called to
generate the appropriate output.
Feeds.php can also be combined with attachments to support
podcasting via ?action=rss. Any page such as "PageName"
that has an mp3 attachment with the same name as the page
("PageName.mp3") will have an appropriate <enclosure> element
in the feed output. The set of allowed attachments can be
extended using the $RSSEnclosureFmt array:
$RSSEnclosureFmt = array('{$Name}.mp3', '{$Name}.mp4');
References:
http://www.atomenabled.org/developers/syndication/
http://dublincore.org/documents/dcmes-xml/
http://en.wikipedia.org/wiki/Podcasting
*/
## Settings for ?action=atom
SDVA($FeedFmt['atom']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<feed xmlns="http://www.w3.org/2005/Atom">'."\n",
'_end' => "</feed>\n",
'title' => '$WikiTitle',
'link' => '<link rel="self" href="{$PageUrl}?action=atom" />',
'id' => '{$PageUrl}?action=atom',
'updated' => '$FeedISOTime',
'author' => "<author><name>$WikiTitle</name></author>\n",
'generator' => '$Version',
'logo' => '$PageLogoUrl'));
SDVA($FeedFmt['atom']['item'], array(
'_start' => "<entry>\n",
'id' => '{$PageUrl}',
'title' => '{$Title}',
'updated' => '$ItemISOTime',
'link' => "<link rel=\"alternate\" href=\"{\$PageUrl}\" />\n",
'author' => "<author><name>{\$LastModifiedBy}</name></author>\n",
'summary' => '$ItemDesc',
'category' => "<category term=\"\$Category\" />\n",
'_end' => "</entry>\n"));
## Settings for ?action=dc
SDVA($FeedFmt['dc']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<!DOCTYPE rdf:RDF PUBLIC "-//DUBLIN CORE//DCMES DTD 2002/07/31//EN"
"http://dublincore.org/documents/2002/07/31/dcmes-xml/dcmes-xml-dtd.dtd">
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">'."\n",
'_end' => "</rdf:RDF>\n"));
SDVA($FeedFmt['dc']['item'], array(
'_start' => "<rdf:Description rdf:about=\"{\$PageUrl}\">\n",
'dc:title' => '{$Title}',
'dc:identifier' => '{$PageUrl}',
'dc:date' => '$ItemISOTime',
'dc:type' => 'Text',
'dc:format' => 'text/html',
'dc:description' => '$ItemDesc',
'dc:subject' => "<dc:subject>\$Category</dc:subject>\n",
'dc:publisher' => '$WikiTitle',
'dc:author' => '{$LastModifiedBy}',
'_end' => "</rdf:Description>\n"));
## RSS 2.0 settings for ?action=rss
SDVA($FeedFmt['rss']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>'."\n",
'_end' => "</channel>\n</rss>\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}?action=rss',
'description' => '{$Group}.{$Title}',
'lastBuildDate' => '$FeedRSSTime'));
SDVA($FeedFmt['rss']['item'], array(
'_start' => "<item>\n",
'_end' => "</item>\n",
'title' => '{$Group} / {$Title}',
'link' => '{$PageUrl}',
'description' => '$ItemDesc',
'dc:contributor' => '{$LastModifiedBy}',
'dc:date' => '$ItemISOTime',
'pubDate' => '$ItemRSSTime',
'enclosure' => 'RSSEnclosure'));
## RDF 1.0, for ?action=rdf
SDVA($FeedFmt['rdf']['feed'], array(
'_header' => 'Content-type: text/xml; charset="$Charset"',
'_start' => '<?xml version="1.0" encoding="$Charset"?'.'>
<rdf:RDF xmlns="http://purl.org/rss/1.0/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel rdf:about="{$PageUrl}?action=rdf">'."\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}?action=rdf',
'description' => '{$Group}.{$Title}',
'dc:date' => '$FeedISOTime',
'items' => "<items>\n<rdf:Seq>\n\$FeedRDFSeq</rdf:Seq>\n</items>\n",
'_items' => "</channel>\n",
'_end' => "</rdf:RDF>\n"));
SDVA($FeedFmt['rdf']['item'], array(
'_start' => "<item rdf:about=\"{\$PageUrl}\">\n",
'_end' => "</item>\n",
'title' => '$WikiTitle | {$Group} / {$Title}',
'link' => '{$PageUrl}',
'description' => '$ItemDesc',
'dc:date' => '$ItemISOTime'));
foreach(array_keys($FeedFmt) as $k) {
SDV($HandleActions[$k], 'HandleFeed');
SDV($HandleAuth[$k], 'read');
}
function HandleFeed($pagename, $auth = 'read') {
global $FeedFmt, $action, $PCache, $FmtV, $ISOTimeFmt, $RSSTimeFmt,
$FeedOpt, $FeedDescPatterns, $CategoryGroup, $EntitiesTable;
SDV($ISOTimeFmt, '%Y-%m-%dT%H:%M:%SZ');
SDV($RSSTimeFmt, 'D, d M Y H:i:s \G\M\T');
SDV($FeedDescPatterns,
array('/<[^>]*$/' => ' ', '/\\w+$/' => '', '/<[^>]+>/' => ''));
SDVA($FeedCategoryOpt, array('link' => $pagename, 'readf' => 1));
SDVA($FeedTrailOpt, array('trail' => $pagename, 'count' => 10, 'readf' => 1));
$f = $FeedFmt[$action];
$page = RetrieveAuthPage($pagename, $auth, true, READPAGE_CURRENT);
if (!$page) Abort("?cannot generate feed");
$feedtime = $page['time'];
# determine list of pages to display
if (@($_REQUEST['trail'] || $_REQUEST['group'] || $_REQUEST['link']))
$opt['readf'] = 1;
else if ($action == 'dc') $opt = array();
else if (preg_match("/^$CategoryGroup\\./", $pagename))
$opt = $FeedCategoryOpt;
else $opt = $FeedTrailOpt;
if (!$opt)
{ PCache($pagename, $page); $pagelist = array(&$PCache[$pagename]); }
else {
$opt = array_merge($opt, @$_REQUEST);
$pagelist = MakePageList($pagename, $opt, 0);
}
# process list of pages in feed
$rdfseq = '';
$pl = array();
foreach($pagelist as $pn) {
if (!PageExists($pn)) continue;
$page = & $PCache[$pn];
$pl[] = $pn;
if (@$opt['count'] && count($pl) >= $opt['count']) break;
$rdfseq .= FmtPageName("<rdf:li resource=\"{\$PageUrl}\" />\n", $pn);
if ($page['time'] > $feedtime) $feedtime = $page['time'];
}
$pagelist = $pl;
$FmtV['$FeedRDFSeq'] = $rdfseq;
$FmtV['$FeedISOTime'] = gmstrftime($ISOTimeFmt, $feedtime);
$FmtV['$FeedRSSTime'] = gmdate($RSSTimeFmt, $feedtime);
# format start of feed
$out = FmtPageName($f['feed']['_start'], $pagename);
# format feed elements
foreach($f['feed'] as $k => $v) {
if ($k{0} == '_' || !$v) continue;
$x = FmtPageName($v, $pagename);
if (!$x) continue;
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
}
# format items in feed
if (@$f['feed']['_items'])
$out .= FmtPageName($f['feed']['_items'], $pagename);
foreach($pagelist as $pn) {
$page = &$PCache[$pn];
$FmtV['$ItemDesc'] = (@$page['description'])
? $page['description']
: trim(preg_replace(array_keys($FeedDescPatterns),
array_values($FeedDescPatterns), @$page['excerpt']));
$FmtV['$ItemISOTime'] = gmstrftime($ISOTimeFmt, $page['time']);
$FmtV['$ItemRSSTime'] = gmdate($RSSTimeFmt, $page['time']);
$out .= FmtPageName($f['item']['_start'], $pn);
foreach((array)@$f['item'] as $k => $v) {
if ($k{0} == '_' || !$v) continue;
if (is_callable($v)) { $out .= $v($pn, $page, $k); continue; }
if (strpos($v, '$LastModifiedBy') !== false && !@$page['author'])
continue;
if (strpos($v, '$Category') !== false) {
if (preg_match_all("/(?<=^|,)$CategoryGroup\\.([^,]+)/",
@$page['targets'], $match)) {
foreach($match[1] as $c) {
$FmtV['$Category'] = $c;
$out .= FmtPageName($v, $pn);
}
}
continue;
}
$x = FmtPageName($v, $pn);
if (!$x) continue;
$out .= ($v{0} == '<') ? $x : "<$k>$x</$k>\n";
}
$out .= FmtPageName($f['item']['_end'], $pn);
}
$out .= FmtPageName($f['feed']['_end'], $pagename);
foreach((array)@$f['feed']['_header'] as $fmt)
header(FmtPageName($fmt, $pagename));
print str_replace(array_keys($EntitiesTable),
array_values($EntitiesTable), $out);
}
## RSSEnclosure is called in ?action=rss to generate <enclosure>
## tags for any pages that have an attached "PageName.mp3" file.
## The set of attachments to enclose is given by $RSSEnclosureFmt.
function RSSEnclosure($pagename, &$page, $k) {
global $RSSEnclosureFmt, $UploadFileFmt, $UploadExts;
if (!function_exists('MakeUploadName')) return '';
SDV($RSSEnclosureFmt, array('{$Name}.mp3'));
$encl = '';
foreach((array)$RSSEnclosureFmt as $fmt) {
$path = FmtPageName($fmt, $pagename);
$upname = MakeUploadName($pagename, $path);
$filepath = FmtPageName("$UploadFileFmt/$upname", $pagename);
if (file_exists($filepath)) {
$length = filesize($filepath);
$type = @$UploadExts[preg_replace('/.*\\./', '', $filepath)];
$url = LinkUpload($pagename, 'Attach:', $path, '', '', '$LinkUrl');
$encl .= "<$k url='$url' length='$length' type='$type' />";
}
}
return $encl;
}
## Since most feeds don't understand html character entities, we
## convert the common ones to their numeric form here.
SDVA($EntitiesTable, array(
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent"
' ' => ' ',
'¡' => '¡',
'¢' => '¢',
'£' => '£',
'¤' => '¤',
'¥' => '¥',
'¦' => '¦',
'§' => '§',
'¨' => '¨',
'©' => '©',
'ª' => 'ª',
'«' => '«',
'¬' => '¬',
'­' => '­',
'®' => '®',
'¯' => '¯',
'°' => '°',
'±' => '±',
'²' => '²',
'³' => '³',
'´' => '´',
'µ' => 'µ',
'¶' => '¶',
'·' => '·',
'¸' => '¸',
'¹' => '¹',
'º' => 'º',
'»' => '»',
'¼' => '¼',
'½' => '½',
'¾' => '¾',
'¿' => '¿',
'À' => 'À',
'Á' => 'Á',
'Â' => 'Â',
'Ã' => 'Ã',
'Ä' => 'Ä',
'Å' => 'Å',
'Æ' => 'Æ',
'Ç' => 'Ç',
'È' => 'È',
'É' => 'É',
'Ê' => 'Ê',
'Ë' => 'Ë',
'Ì' => 'Ì',
'Í' => 'Í',
'Î' => 'Î',
'Ï' => 'Ï',
'Ð' => 'Ð',
'Ñ' => 'Ñ',
'Ò' => 'Ò',
'Ó' => 'Ó',
'Ô' => 'Ô',
'Õ' => 'Õ',
'Ö' => 'Ö',
'×' => '×',
'Ø' => 'Ø',
'Ù' => 'Ù',
'Ú' => 'Ú',
'Û' => 'Û',
'Ü' => 'Ü',
'Ý' => 'Ý',
'Þ' => 'Þ',
'ß' => 'ß',
'à' => 'à',
'á' => 'á',
'â' => 'â',
'ã' => 'ã',
'ä' => 'ä',
'å' => 'å',
'æ' => 'æ',
'ç' => 'ç',
'è' => 'è',
'é' => 'é',
'ê' => 'ê',
'ë' => 'ë',
'ì' => 'ì',
'í' => 'í',
'î' => 'î',
'ï' => 'ï',
'ð' => 'ð',
'ñ' => 'ñ',
'ò' => 'ò',
'ó' => 'ó',
'ô' => 'ô',
'õ' => 'õ',
'ö' => 'ö',
'÷' => '÷',
'ø' => 'ø',
'ù' => 'ù',
'ú' => 'ú',
'û' => 'û',
'ü' => 'ü',
'ý' => 'ý',
'þ' => 'þ',
'ÿ' => 'ÿ',
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent"
'"' => '"',
#'&' => '&#38;',
#'<' => '&#60;',
#'>' => '>',
''' => ''',
'Œ' => 'Œ',
'œ' => 'œ',
'Š' => 'Š',
'š' => 'š',
'Ÿ' => 'Ÿ',
'ˆ' => 'ˆ',
'˜' => '˜',
' ' => ' ',
' ' => ' ',
' ' => ' ',
'‌' => '‌',
'‍' => '‍',
'‎' => '‎',
'‏' => '‏',
'–' => '–',
'—' => '—',
'‘' => '‘',
'’' => '’',
'‚' => '‚',
'“' => '“',
'”' => '”',
'„' => '„',
'†' => '†',
'‡' => '‡',
'‰' => '‰',
'‹' => '‹',
'›' => '›',
'€' => '€',
# entities defined in "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent"
'ƒ' => 'ƒ',
'Α' => 'Α',
'Β' => 'Β',
'Γ' => 'Γ',
'Δ' => 'Δ',
'Ε' => 'Ε',
'Ζ' => 'Ζ',
'Η' => 'Η',
'Θ' => 'Θ',
'Ι' => 'Ι',
'Κ' => 'Κ',
'Λ' => 'Λ',
'Μ' => 'Μ',
'Ν' => 'Ν',
'Ξ' => 'Ξ',
'Ο' => 'Ο',
'Π' => 'Π',
'Ρ' => 'Ρ',
'Σ' => 'Σ',
'Τ' => 'Τ',
'Υ' => 'Υ',
'Φ' => 'Φ',
'Χ' => 'Χ',
'Ψ' => 'Ψ',
'Ω' => 'Ω',
'α' => 'α',
'β' => 'β',
'γ' => 'γ',
'δ' => 'δ',
'ε' => 'ε',
'ζ' => 'ζ',
'η' => 'η',
'θ' => 'θ',
'ι' => 'ι',
'κ' => 'κ',
'λ' => 'λ',
'μ' => 'μ',
'ν' => 'ν',
'ξ' => 'ξ',
'ο' => 'ο',
'π' => 'π',
'ρ' => 'ρ',
'ς' => 'ς',
'σ' => 'σ',
'τ' => 'τ',
'υ' => 'υ',
'φ' => 'φ',
'χ' => 'χ',
'ψ' => 'ψ',
'ω' => 'ω',
'ϑ' => 'ϑ',
'ϒ' => 'ϒ',
'ϖ' => 'ϖ',
'•' => '•',
'…' => '…',
'′' => '′',
'″' => '″',
'‾' => '‾',
'⁄' => '⁄',
'℘' => '℘',
'ℑ' => 'ℑ',
'ℜ' => 'ℜ',
'™' => '™',
'ℵ' => 'ℵ',
'←' => '←',
'↑' => '↑',
'→' => '→',
'↓' => '↓',
'↔' => '↔',
'↵' => '↵',
'⇐' => '⇐',
'⇑' => '⇑',
'⇒' => '⇒',
'⇓' => '⇓',
'⇔' => '⇔',
'∀' => '∀',
'∂' => '∂',
'∃' => '∃',
'∅' => '∅',
'∇' => '∇',
'∈' => '∈',
'∉' => '∉',
'∋' => '∋',
'∏' => '∏',
'∑' => '∑',
'−' => '−',
'∗' => '∗',
'√' => '√',
'∝' => '∝',
'∞' => '∞',
'∠' => '∠',
'∧' => '∧',
'∨' => '∨',
'∩' => '∩',
'∪' => '∪',
'∫' => '∫',
'∴' => '∴',
'∼' => '∼',
'≅' => '≅',
'≈' => '≈',
'≠' => '≠',
'≡' => '≡',
'≤' => '≤',
'≥' => '≥',
'⊂' => '⊂',
'⊃' => '⊃',
'⊄' => '⊄',
'⊆' => '⊆',
'⊇' => '⊇',
'⊕' => '⊕',
'⊗' => '⊗',
'⊥' => '⊥',
'⋅' => '⋅',
'⌈' => '⌈',
'⌉' => '⌉',
'⌊' => '⌊',
'⌋' => '⌋',
'⟨' => '〈',
'⟩' => '〉',
'◊' => '◊',
'♠' => '♠',
'♣' => '♣',
'♥' => '♥',
'♦' => '♦'));
More information about the pmwiki-users
mailing list