5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
9 if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__
).'/');
10 require_once(DOKU_INC
.'inc/init.php');
11 require_once(DOKU_INC
.'inc/common.php');
12 require_once(DOKU_INC
.'inc/events.php');
13 require_once(DOKU_INC
.'inc/parserutils.php');
14 require_once(DOKU_INC
.'inc/feedcreator.class.php');
15 require_once(DOKU_INC
.'inc/auth.php');
16 require_once(DOKU_INC
.'inc/pageutils.php');
17 require_once(DOKU_INC
.'inc/httputils.php');
20 session_write_close();
23 $opt = rss_parseOptions();
25 // the feed is dynamic - we need a cache for each combo
26 // (but most people just use the default feed so it's still effective)
27 $cache = getCacheName(join('',array_values($opt)).$_SERVER['REMOTE_USER'],'.feed');
28 $key = join('', array_values($opt)) . $_SERVER['REMOTE_USER'];
29 $cache = new cache($key, '.feed');
31 // prepare cache depends
32 $depends['files'] = getConfigFiles('main');
33 $depends['age'] = $conf['rss_update'];
34 $depends['purge'] = ($_REQUEST['purge']) ?
true : false;
36 // check cacheage and deliver if nothing has changed since last
37 // time or the update interval has not passed, also handles conditional requests
38 header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
39 header('Pragma: public');
40 header('Content-Type: application/xml; charset=utf-8');
41 header('X-Robots-Tag: noindex');
42 if($cache->useCache($depends)) {
43 http_conditionalRequest($cache->_time
);
44 if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
45 print $cache->retrieveCache();
48 http_conditionalRequest(time());
52 $rss = new DokuWikiFeedCreator();
53 $rss->title
= $conf['title'].(($opt['namespace']) ?
' '.$opt['namespace'] : '');
54 $rss->link
= DOKU_URL
;
55 $rss->syndicationURL
= DOKU_URL
.'feed.php';
56 $rss->cssStyleSheet
= DOKU_URL
.'lib/exe/css.php?s=feed';
58 $image = new FeedImage();
59 $image->title
= $conf['title'];
60 $image->url
= DOKU_URL
."lib/images/favicon.ico";
61 $image->link
= DOKU_URL
;
65 if($opt['feed_mode'] == 'list'){
66 $data = rssListNamespace($opt);
67 }elseif($opt['feed_mode'] == 'search'){
68 $data = rssSearch($opt);
74 $event = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
75 if ($event->advise_before(true)) {
76 $data = rssRecentChanges($opt);
78 $event->advise_after();
81 rss_buildItems($rss, $data, $opt);
82 $feed = $rss->createFeed($opt['feed_type'],'utf-8');
85 $cache->storeCache($feed);
90 // ---------------------------------------------------------------- //
93 * Get URL parameters and config options and return a initialized option array
95 * @author Andreas Gohr <andi@splitbrain.org>
97 function rss_parseOptions(){
100 $opt['items'] = (int) $_REQUEST['num'];
101 $opt['feed_type'] = $_REQUEST['type'];
102 $opt['feed_mode'] = $_REQUEST['mode'];
103 $opt['show_minor'] = $_REQUEST['minor'];
104 $opt['namespace'] = $_REQUEST['ns'];
105 $opt['link_to'] = $_REQUEST['linkto'];
106 $opt['item_content'] = $_REQUEST['content'];
107 $opt['search_query'] = $_REQUEST['q'];
109 if(!$opt['feed_type']) $opt['feed_type'] = $conf['rss_type'];
110 if(!$opt['item_content']) $opt['item_content'] = $conf['rss_content'];
111 if(!$opt['link_to']) $opt['link_to'] = $conf['rss_linkto'];
112 if(!$opt['items']) $opt['items'] = $conf['recent'];
113 $opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
115 switch ($opt['feed_type']){
117 $opt['feed_type'] = 'RSS0.91';
118 $opt['mime_type'] = 'text/xml';
121 $opt['feed_type'] = 'RSS2.0';
122 $opt['mime_type'] = 'text/xml';
125 $opt['feed_type'] = 'ATOM0.3';
126 $opt['mime_type'] = 'application/xml';
129 $opt['feed_type'] = 'ATOM1.0';
130 $opt['mime_type'] = 'application/atom+xml';
133 $opt['feed_type'] = 'RSS1.0';
134 $opt['mime_type'] = 'application/xml';
140 trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
145 * Add recent changed pages to a feed object
147 * @author Andreas Gohr <andi@splitbrain.org>
148 * @param object $rss - the FeedCreator Object
149 * @param array $data - the items to add
150 * @param array $opt - the feed options
152 function rss_buildItems(&$rss,&$data,$opt){
162 $event = new Doku_Event('FEED_DATA_PROCESS', $eventData);
163 if ($event->advise_before(false)){
164 foreach($data as $ditem){
165 if(!is_array($ditem)){
166 // not an array? then only a list of IDs was given
167 $ditem = array( 'id' => $ditem );
170 $item = new FeedItem();
172 $meta = p_get_metadata($id);
176 $date = $ditem['date'];
177 }elseif($meta['date']['modified']){
178 $date = $meta['date']['modified'];
180 $date = @filemtime
(wikiFN($id));
182 if($date) $item->date
= date('r',$date);
185 if($conf['useheading'] && $meta['title']){
186 $item->title
= $meta['title'];
188 $item->title
= $ditem['id'];
190 if($conf['rss_show_summary'] && !empty($ditem['sum'])){
191 $item->title
.= ' - '.strip_tags($ditem['sum']);
195 switch ($opt['link_to']){
197 $item->link
= wl($id,'rev='.$date,true,'&');
200 $item->link
= wl($id,'do=revisions&rev='.$date,true,'&');
203 $item->link
= wl($id, '', true,'&');
207 $item->link
= wl($id,'rev='.$date.'&do=diff',true,'&');
211 switch ($opt['item_content']){
214 require_once(DOKU_INC
.'inc/DifferenceEngine.php');
215 $revs = getRevisions($id, 0, 1);
219 $df = new Diff(explode("\n",htmlspecialchars(rawWiki($id,$rev))),
220 explode("\n",htmlspecialchars(rawWiki($id,''))));
222 $df = new Diff(array(''),
223 explode("\n",htmlspecialchars(rawWiki($id,''))));
226 if($opt['item_content'] == 'htmldiff'){
227 $tdf = new TableDiffFormatter();
228 $content = '<table>';
229 $content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>';
230 $content .= '<th colspan="2" width="50%">'.$lang['current'].'</th></tr>';
231 $content .= $tdf->format($df);
232 $content .= '</table>';
234 $udf = new UnifiedDiffFormatter();
235 $content = "<pre>\n".$udf->format($df)."\n</pre>";
239 $content = p_wiki_xhtml($id,$date,false);
241 $content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s','',$content);
243 // make URLs work when canonical is not set, regexp instead of rerendering!
244 if(!$conf['canonical']){
245 $base = preg_quote(DOKU_REL
,'/');
246 $content = preg_replace('/(<a href|<img src)="('.$base.')/s','$1="'.DOKU_URL
,$content);
252 $content = $meta['description']['abstract'];
254 $item->description
= $content; //FIXME a plugin hook here could be senseful
257 # FIXME should the user be pulled from metadata as well?
259 $user = @$ditem['user']; // the @ spares time repeating lookup
261 if($user && $conf['useacl'] && $auth){
262 $userInfo = $auth->getUserData($user);
263 $item->author
= $userInfo['name'];
264 if($userInfo && !$opt['guardmail']){
265 $item->authorEmail
= $userInfo['mail'];
267 //cannot obfuscate because some RSS readers may check validity
268 $item->authorEmail
= $user.'@'.$ditem['ip'];
271 // this happens when no ACL but some Apache auth is used
272 $item->author
= $user;
273 $item->authorEmail
= $user.'@'.$ditem['ip'];
275 $item->authorEmail
= 'anonymous@'.$ditem['ip'];
279 if($meta['subject']){
280 $item->category
= $meta['subject'];
283 if($cat) $item->category
= $cat;
286 // finally add the item to the feed object, after handing it to registered plugins
287 $evdata = array('item' => &$item,
291 $evt = new Doku_Event('FEED_ITEM_ADD', $evdata);
292 if ($evt->advise_before()){
293 $rss->addItem($item);
295 $evt->advise_after(); // for completeness
298 $event->advise_after();
303 * Add recent changed pages to the feed object
305 * @author Andreas Gohr <andi@splitbrain.org>
307 function rssRecentChanges($opt){
311 $flags = RECENTS_SKIP_DELETED
;
312 if(!$opt['show_minor']) $flags +
= RECENTS_SKIP_MINORS
;
314 $recents = getRecents(0,$opt['items'],$opt['namespace'],$flags);
319 * Add all pages of a namespace to the feed object
321 * @author Andreas Gohr <andi@splitbrain.org>
323 function rssListNamespace($opt){
324 require_once(DOKU_INC
.'inc/search.php');
327 $ns=':'.cleanID($opt['namespace']);
328 $ns=str_replace(':','/',$ns);
332 search($data,$conf['datadir'],'search_list','',$ns);
338 * Add the result of a full text search to the feed object
340 * @author Andreas Gohr <andi@splitbrain.org>
342 function rssSearch($opt){
343 if(!$opt['search_query']) return;
345 require_once(DOKU_INC
.'inc/fulltext.php');
347 $data = ft_pageSearch($opt['search_query'],$poswords);
348 $data = array_keys($data);
353 //Setup VIM: ex: et ts=4 enc=utf-8 :