123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544 |
- <?php if (!defined('PmWiki')) exit();
- /* Copyright 2005-2006 Patrick R. Michaud (pmichaud@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.
- For example, to set the RSS 2.0 <author> element to the
- value of the last author to modify a page, one can set
- (in local/config.php):
- $FeedFmt['rss']['item']['author'] = '$LastModifiedBy';
- To use the RSS 2.0 <description> element to contain the
- change summary of the most recent edit, set
- $FeedFmt['rss']['item']['description'] = '$LastModifiedSummary';
- 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' => '{$Description}',
- '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' => '{$Description}',
- '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' => '{$Description}',
- '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' => '{$Description}',
- '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($FeedPageListOpt, array());
- SDVA($FeedCategoryOpt, array('link' => $pagename));
- SDVA($FeedTrailOpt, array('trail' => $pagename, 'count' => 10));
- $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']
- || $_REQUEST['name']))
- $opt = $FeedPageListOpt;
- else if (preg_match("/^$CategoryGroup\\./", $pagename))
- $opt = $FeedCategoryOpt;
- else if ($action != 'dc') $opt = $FeedTrailOpt;
- else {
- PCache($pagename, $page);
- $pagelist = array($pagename);
- }
- if (!$pagelist) {
- $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;
- if (!isset($PCache[$pn]['time']))
- { $page = ReadPage($pn, READPAGE_CURRENT); PCache($pn, $page); }
- $pc = & $PCache[$pn];
- $pl[] = $pn;
- if (@$opt['count'] && count($pl) >= $opt['count']) break;
- $rdfseq .= FmtPageName("<rdf:li resource=\"{\$PageUrl}\" />\n", $pn);
- if ($pc['time'] > $feedtime) $feedtime = $pc['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'];
- $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"
- 'ƒ' => 'ƒ',
- 'Α' => 'Α',
- 'Β' => 'Β',
- 'Γ' => 'Γ',
- 'Δ' => 'Δ',
- 'Ε' => 'Ε',
- 'Ζ' => 'Ζ',
- 'Η' => 'Η',
- 'Θ' => 'Θ',
- 'Ι' => 'Ι',
- 'Κ' => 'Κ',
- 'Λ' => 'Λ',
- 'Μ' => 'Μ',
- 'Ν' => 'Ν',
- 'Ξ' => 'Ξ',
- 'Ο' => 'Ο',
- 'Π' => 'Π',
- 'Ρ' => 'Ρ',
- 'Σ' => 'Σ',
- 'Τ' => 'Τ',
- 'Υ' => 'Υ',
- 'Φ' => 'Φ',
- 'Χ' => 'Χ',
- 'Ψ' => 'Ψ',
- 'Ω' => 'Ω',
- 'α' => 'α',
- 'β' => 'β',
- 'γ' => 'γ',
- 'δ' => 'δ',
- 'ε' => 'ε',
- 'ζ' => 'ζ',
- 'η' => 'η',
- 'θ' => 'θ',
- 'ι' => 'ι',
- 'κ' => 'κ',
- 'λ' => 'λ',
- 'μ' => 'μ',
- 'ν' => 'ν',
- 'ξ' => 'ξ',
- 'ο' => 'ο',
- 'π' => 'π',
- 'ρ' => 'ρ',
- 'ς' => 'ς',
- 'σ' => 'σ',
- 'τ' => 'τ',
- 'υ' => 'υ',
- 'φ' => 'φ',
- 'χ' => 'χ',
- 'ψ' => 'ψ',
- 'ω' => 'ω',
- 'ϑ' => 'ϑ',
- 'ϒ' => 'ϒ',
- 'ϖ' => 'ϖ',
- '•' => '•',
- '…' => '…',
- '′' => '′',
- '″' => '″',
- '‾' => '‾',
- '⁄' => '⁄',
- '℘' => '℘',
- 'ℑ' => 'ℑ',
- 'ℜ' => 'ℜ',
- '™' => '™',
- 'ℵ' => 'ℵ',
- '←' => '←',
- '↑' => '↑',
- '→' => '→',
- '↓' => '↓',
- '↔' => '↔',
- '↵' => '↵',
- '⇐' => '⇐',
- '⇑' => '⇑',
- '⇒' => '⇒',
- '⇓' => '⇓',
- '⇔' => '⇔',
- '∀' => '∀',
- '∂' => '∂',
- '∃' => '∃',
- '∅' => '∅',
- '∇' => '∇',
- '∈' => '∈',
- '∉' => '∉',
- '∋' => '∋',
- '∏' => '∏',
- '∑' => '∑',
- '−' => '−',
- '∗' => '∗',
- '√' => '√',
- '∝' => '∝',
- '∞' => '∞',
- '∠' => '∠',
- '∧' => '∧',
- '∨' => '∨',
- '∩' => '∩',
- '∪' => '∪',
- '∫' => '∫',
- '∴' => '∴',
- '∼' => '∼',
- '≅' => '≅',
- '≈' => '≈',
- '≠' => '≠',
- '≡' => '≡',
- '≤' => '≤',
- '≥' => '≥',
- '⊂' => '⊂',
- '⊃' => '⊃',
- '⊄' => '⊄',
- '⊆' => '⊆',
- '⊇' => '⊇',
- '⊕' => '⊕',
- '⊗' => '⊗',
- '⊥' => '⊥',
- '⋅' => '⋅',
- '⌈' => '⌈',
- '⌉' => '⌉',
- '⌊' => '⌊',
- '⌋' => '⌋',
- '⟨' => '〈',
- '⟩' => '〉',
- '◊' => '◊',
- '♠' => '♠',
- '♣' => '♣',
- '♥' => '♥',
- '♦' => '♦'));
|