1<?php 2/** 3 * XML feed export 4 * 5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 6 * @author Andreas Gohr <andi@splitbrain.org> 7 * @author Esther Brunner <wikidesign@gmail.com> 8 */ 9 10if (!defined('DOKU_INC')) define('DOKU_INC', __DIR__ . '/../../../'); 11require_once(DOKU_INC . 'inc/init.php'); 12session_write_close(); 13 14$plugin = $INPUT->str('plugin'); 15$fn = $INPUT->str('fn'); 16$ns = cleanID($INPUT->str('ns')); 17$num = $INPUT->int('num'); 18$other = $INPUT->str('tag') . $INPUT->str('user'); 19$title = $INPUT->str('title'); 20$type = $INPUT->str('type', $conf['rss_type']); 21 22switch ($type) { 23 case 'rss': 24 $type = 'RSS0.91'; 25 $mime = 'text/xml'; 26 break; 27 case 'rss2': 28 $type = 'RSS2.0'; 29 $mime = 'text/xml'; 30 break; 31 case 'atom': 32 $type = 'ATOM0.3'; 33 $mime = 'application/xml'; 34 break; 35 case 'atom1': 36 $type = 'ATOM1.0'; 37 $mime = 'application/atom+xml'; 38 break; 39 default: 40 $type = 'RSS1.0'; 41 $mime = 'application/xml'; 42} 43 44// the feed is dynamic - we need a cache for each combo 45// (but most people just use the default feed so it's still effective) 46$cache = getCacheName($plugin . $fn . $ns . $num . $other . $type . $INPUT->server->str('REMOTE_USER'), '.feed'); 47$cmod = @filemtime($cache); // 0 if not exists 48if ($cmod && (@filemtime(DOKU_CONF . 'local.php') > $cmod 49 || @filemtime(DOKU_CONF . 'dokuwiki.php') > $cmod) 50) { 51 // ignore cache if feed prefs may have changed 52 $cmod = 0; 53} 54 55// check cacheage and deliver if nothing has changed since last 56// time or the update interval has not passed, also handles conditional requests 57header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 58header('Pragma: public'); 59header('Content-Type: application/xml; charset=utf-8'); 60 61if ($cmod && ( 62 ($cmod + $conf['rss_update'] > time()) 63 || ( 64 ($cmod > @filemtime($conf['changelog'])) 65 && 66 //discussion has its own changelog 67 ($plugin !== 'discussion' || $cmod > @filemtime($conf['metadir'] . '/_comments.changes')) 68 ) 69 )) { 70 http_conditionalRequest($cmod); 71 if ($conf['allowdebug']) header("X-CacheUsed: $cache"); 72 print io_readFile($cache); 73 exit; 74} else { 75 http_conditionalRequest(time()); 76} 77 78// create new feed 79$rss = new UniversalFeedCreator(); 80$rss->title = $title; 81if ($ns) { 82 $rss->title .= ' ' . ucwords(str_replace(array('_', ':'), array(' ', ': '), $ns)); 83} elseif ($other) { 84 $rss->title .= ' ' . ucwords(str_replace('_', ' ', $other)); 85} 86$rss->title .= ' · ' . $conf['title']; 87$rss->link = DOKU_URL; 88$rss->syndicationURL = DOKU_PLUGIN . 'feed/feed.php'; 89$rss->cssStyleSheet = DOKU_URL . 'lib/exe/css.php?s=feed'; 90 91$image = new FeedImage(); 92$image->title = $conf['title']; 93$image->url = DOKU_URL . "lib/images/favicon.ico"; 94$image->link = DOKU_URL; 95$rss->image = $image; 96 97if ($po = plugin_load('helper', $plugin)) { 98 feed_getPages($rss, $po, $ns, $num, $fn); 99} 100$feed = $rss->createFeed($type); 101 102// save cachefile 103io_saveFile($cache, $feed); 104 105// finally deliver 106print $feed; 107 108/* ---------- */ 109 110/** 111 * Add pages given by plugin to feed object 112 * 113 * @param UniversalFeedCreator $rss 114 * @param \dokuwiki\Extension\PluginInterface $po 115 * @param string $ns 116 * @param int $num 117 * @param string $fn 118 * @return bool 119 * @author Andreas Gohr <andi@splitbrain.org> 120 * @author Esther Brunner <wikidesign@gmail.com> 121 * 122 */ 123function feed_getPages($rss, $po, $ns, $num, $fn) 124{ 125 global $conf; 126 127 if ((!$num) || (!is_numeric($num))) $num = $conf['recent']; 128 129 // get the pages for our namespace 130 $pages = $po->$fn($ns, $num); 131 if (!$pages) return false; 132 133 foreach ($pages as $page) { 134 $item = new FeedItem(); 135 136 list($id, /* $hash */) = explode('#', $page['id'], 2); 137 $meta = p_get_metadata($id); 138 139 // title 140 if ($page['title']) { 141 $item->title = $page['title']; 142 } elseif ($meta['title']) { 143 $item->title = $meta['title']; 144 } else { 145 $item->title = ucwords($id); 146 } 147 148 // link 149 $item->link = wl($page['id'], '', true, '&') . '#' . $page['anchor']; 150 151 // description 152 if ($page['desc']) { 153 $description = $page['desc']; 154 } else { 155 $description = $meta['description']['abstract']; 156 } 157 if (get_class($po) == 'helper_plugin_discussion') { 158 //discussion plugins returns striped parsed text, inclusive encoded chars. Don't double encode. 159 $description = htmlspecialchars($description, ENT_COMPAT, 'UTF-8', $double_encode = false); 160 } else { 161 $description = htmlspecialchars($description); 162 } 163 $item->description = $description; 164 165 // date 166 $item->date = date('r', $page['date']); 167 168 // category 169 if ($page['cat']) { 170 $item->category = $page['cat']; 171 } elseif ($meta['subject']) { 172 if (is_array($meta['subject'])) { 173 $item->category = $meta['subject'][0]; 174 } else { 175 $item->category = $meta['subject']; 176 } 177 } 178 179 // creator 180 if ($page['user']) { 181 $item->author = $page['user']; 182 } else { 183 $item->author = $meta['creator']; 184 } 185 186 $rss->addItem($item); 187 } 188 return true; 189} 190