backup de julho
[h2N7SspZmY.git] / feed.php
blobe7ea5808c2e7bc51d2cc36d9de745bfa836b6c79
1 <?php
2 /**
3 * XML feed export
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author Andreas Gohr <andi@splitbrain.org>
7 */
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');
19 //close session
20 session_write_close();
22 // get params
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();
46 exit;
47 } else {
48 http_conditionalRequest(time());
51 // create new feed
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;
62 $rss->image = $image;
64 $data = null;
65 if($opt['feed_mode'] == 'list'){
66 $data = rssListNamespace($opt);
67 }elseif($opt['feed_mode'] == 'search'){
68 $data = rssSearch($opt);
69 }else{
70 $eventData = array(
71 'opt' => &$opt,
72 'data' => &$data,
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');
84 // save cachefile
85 $cache->storeCache($feed);
87 // finally deliver
88 print $feed;
90 // ---------------------------------------------------------------- //
92 /**
93 * Get URL parameters and config options and return a initialized option array
95 * @author Andreas Gohr <andi@splitbrain.org>
97 function rss_parseOptions(){
98 global $conf;
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']){
116 case 'rss':
117 $opt['feed_type'] = 'RSS0.91';
118 $opt['mime_type'] = 'text/xml';
119 break;
120 case 'rss2':
121 $opt['feed_type'] = 'RSS2.0';
122 $opt['mime_type'] = 'text/xml';
123 break;
124 case 'atom':
125 $opt['feed_type'] = 'ATOM0.3';
126 $opt['mime_type'] = 'application/xml';
127 break;
128 case 'atom1':
129 $opt['feed_type'] = 'ATOM1.0';
130 $opt['mime_type'] = 'application/atom+xml';
131 break;
132 default:
133 $opt['feed_type'] = 'RSS1.0';
134 $opt['mime_type'] = 'application/xml';
137 $eventData = array(
138 'opt' => &$opt,
140 trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
141 return $opt;
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){
153 global $conf;
154 global $lang;
155 global $auth;
157 $eventData = array(
158 'rss' => &$rss,
159 'data' => &$data,
160 'opt' => &$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();
171 $id = $ditem['id'];
172 $meta = p_get_metadata($id);
174 // add date
175 if($ditem['date']){
176 $date = $ditem['date'];
177 }elseif($meta['date']['modified']){
178 $date = $meta['date']['modified'];
179 }else{
180 $date = @filemtime(wikiFN($id));
182 if($date) $item->date = date('r',$date);
184 // add title
185 if($conf['useheading'] && $meta['title']){
186 $item->title = $meta['title'];
187 }else{
188 $item->title = $ditem['id'];
190 if($conf['rss_show_summary'] && !empty($ditem['sum'])){
191 $item->title .= ' - '.strip_tags($ditem['sum']);
194 // add item link
195 switch ($opt['link_to']){
196 case 'page':
197 $item->link = wl($id,'rev='.$date,true,'&');
198 break;
199 case 'rev':
200 $item->link = wl($id,'do=revisions&rev='.$date,true,'&');
201 break;
202 case 'current':
203 $item->link = wl($id, '', true,'&');
204 break;
205 case 'diff':
206 default:
207 $item->link = wl($id,'rev='.$date.'&do=diff',true,'&');
210 // add item content
211 switch ($opt['item_content']){
212 case 'diff':
213 case 'htmldiff':
214 require_once(DOKU_INC.'inc/DifferenceEngine.php');
215 $revs = getRevisions($id, 0, 1);
216 $rev = $revs[0];
218 if($rev){
219 $df = new Diff(explode("\n",htmlspecialchars(rawWiki($id,$rev))),
220 explode("\n",htmlspecialchars(rawWiki($id,''))));
221 }else{
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>';
233 }else{
234 $udf = new UnifiedDiffFormatter();
235 $content = "<pre>\n".$udf->format($df)."\n</pre>";
237 break;
238 case 'html':
239 $content = p_wiki_xhtml($id,$date,false);
240 // no TOC in feeds
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);
249 break;
250 case 'abstract':
251 default:
252 $content = $meta['description']['abstract'];
254 $item->description = $content; //FIXME a plugin hook here could be senseful
256 // add user
257 # FIXME should the user be pulled from metadata as well?
258 $user = null;
259 $user = @$ditem['user']; // the @ spares time repeating lookup
260 $item->author = '';
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'];
266 }else{
267 //cannot obfuscate because some RSS readers may check validity
268 $item->authorEmail = $user.'@'.$ditem['ip'];
270 }elseif($user){
271 // this happens when no ACL but some Apache auth is used
272 $item->author = $user;
273 $item->authorEmail = $user.'@'.$ditem['ip'];
274 }else{
275 $item->authorEmail = 'anonymous@'.$ditem['ip'];
278 // add category
279 if($meta['subject']){
280 $item->category = $meta['subject'];
281 }else{
282 $cat = getNS($id);
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,
288 'opt' => &$opt,
289 'ditem' => &$ditem,
290 'rss' => &$rss);
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){
308 global $conf;
309 global $auth;
311 $flags = RECENTS_SKIP_DELETED;
312 if(!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
314 $recents = getRecents(0,$opt['items'],$opt['namespace'],$flags);
315 return $recents;
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');
325 global $conf;
327 $ns=':'.cleanID($opt['namespace']);
328 $ns=str_replace(':','/',$ns);
330 $data = array();
331 sort($data);
332 search($data,$conf['datadir'],'search_list','',$ns);
334 return $data;
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');
346 $data = array();
347 $data = ft_pageSearch($opt['search_query'],$poswords);
348 $data = array_keys($data);
350 return $data;
353 //Setup VIM: ex: et ts=4 enc=utf-8 :