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 */ 8 9 if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__)).'/'); 10 require_once(DOKU_INC.'inc/init.php'); 11 require_once(DOKU_INC.'inc/common.php'); 12 require_once(DOKU_INC.'inc/parserutils.php'); 13 require_once(DOKU_INC.'inc/feedcreator.class.php'); 14 require_once(DOKU_INC.'inc/auth.php'); 15 require_once(DOKU_INC.'inc/pageutils.php'); 16 17 //close session 18 session_write_close(); 19 20 21 $num = $_REQUEST['num']; 22 $type = $_REQUEST['type']; 23 $mode = $_REQUEST['mode']; 24 $minor = $_REQUEST['minor']; 25 $ns = $_REQUEST['ns']; 26 $ltype = $_REQUEST['linkto']; 27 28 if($type == '') 29 $type = $conf['rss_type']; 30 31 switch ($type){ 32 case 'rss': 33 $type = 'RSS0.9'; 34 break; 35 case 'rss2': 36 $type = 'RSS2.0'; 37 break; 38 case 'atom': 39 $type = 'ATOM0.3'; 40 break; 41 default: 42 $type = 'RSS1.0'; 43 } 44 45 // the feed is dynamic - we need a cache for each combo 46 // (but most people just use the default feed so it's still effective) 47 $cache = getCacheName($num.$type.$mode.$ns.$ltype.$_SERVER['REMOTE_USER'],'.feed'); 48 49 // check cacheage and deliver if nothing has changed since last 50 // time or the update interval has not passed, also handles conditional requests 51 header('Cache-Control: must-revalidate, post-check=0, pre-check=0'); 52 header('Pragma: public'); 53 header('Content-Type: application/xml; charset=utf-8'); 54 $cmod = @filemtime($cache); // 0 if not exists 55 if($cmod && (($cmod+$conf['rss_update']>time()) || ($cmod>@filemtime($conf['changelog'])))){ 56 http_conditionalRequest($cmod); 57 print io_readFile($cache); 58 exit; 59 } else { 60 http_conditionalRequest(time()); 61 } 62 63 // create new feed 64 $rss = new DokuWikiFeedCreator(); 65 $rss->title = $conf['title'].(($ns) ? ' '.$ns : ''); 66 $rss->link = DOKU_URL; 67 $rss->syndicationURL = DOKU_URL.'feed.php'; 68 $rss->cssStyleSheet = DOKU_URL.'lib/styles/feed.css'; 69 70 $image = new FeedImage(); 71 $image->title = $conf['title']; 72 $image->url = DOKU_URL."lib/images/favicon.ico"; 73 $image->link = DOKU_URL; 74 $rss->image = $image; 75 76 if($mode == 'list'){ 77 rssListNamespace($rss,$ns); 78 }else{ 79 rssRecentChanges($rss,$num,$ltype,$ns,$minor); 80 } 81 82 $feed = $rss->createFeed($type,'utf-8'); 83 84 // save cachefile 85 io_saveFile($cache,$feed); 86 87 // finally deliver 88 print $feed; 89 90// ---------------------------------------------------------------- // 91 92/** 93 * Add recent changed to a feed object 94 * 95 * @author Andreas Gohr <andi@splitbrain.org> 96 */ 97function rssRecentChanges(&$rss,$num,$ltype,$ns,$minor){ 98 global $conf; 99 global $auth; 100 101 if(!$num) $num = $conf['recent']; 102 $guardmail = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none'); 103 104 105 $flags = RECENTS_SKIP_DELETED; 106 if(!$minor) $flags += RECENTS_SKIP_MINORS; 107 108 $recents = getRecents(0,$num,$ns,$flags); 109 110 //this can take some time if a lot of recaching has to be done 111 @set_time_limit(90); // set max execution time 112 113 foreach($recents as $recent){ 114 115 $item = new FeedItem(); 116 $item->title = $recent['id']; 117 $xhtml = p_wiki_xhtml($recent['id'],'',false); 118 119 if($conf['useheading']) { 120 $matches = array(); 121 if(preg_match('|<h([1-9])>(.*?)</h\1>|', $xhtml, $matches)) 122 $item->title = trim($matches[2]); 123 } 124 if(!empty($recent['sum'])){ 125 $item->title .= ' - '.strip_tags($recent['sum']); 126 } 127 128 $desc = cleanDesc($xhtml); 129 130 if(empty($ltype)) 131 $ltype = $conf['rss_linkto']; 132 133 switch ($ltype){ 134 case 'page': 135 $item->link = wl($recent['id'],'rev='.$recent['date'],true); 136 break; 137 case 'rev': 138 $item->link = wl($recent['id'],'do=revisions&rev='.$recent['date'],true); 139 break; 140 case 'current': 141 $item->link = wl($recent['id'], '', true); 142 break; 143 case 'diff': 144 default: 145 $item->link = wl($recent['id'],'do=diff'.$recent['date'],true); 146 } 147 148 $item->description = $desc; 149 $item->date = date('r',$recent['date']); 150 $cat = getNS($recent['id']); 151 if($cat) $item->category = $cat; 152 153 $user = null; 154 $user = @$recent['user']; // the @ spares time repeating lookup 155 $item->author = ''; 156 157 if($user){ 158 $userInfo = $auth->getUserData($user); 159 $item->author = $userInfo['name']; 160 if($guardmail) { 161 //cannot obfuscate because some RSS readers may check validity 162 $item->authorEmail = $user.'@'.$recent['ip']; 163 }else{ 164 $item->authorEmail = $userInfo['mail']; 165 } 166 }else{ 167 $item->authorEmail = 'anonymous@'.$recent['ip']; 168 } 169 $rss->addItem($item); 170 } 171} 172 173/** 174 * Add all pages of a namespace to a feedobject 175 * 176 * @author Andreas Gohr <andi@splitbrain.org> 177 */ 178function rssListNamespace(&$rss,$ns){ 179 require_once(DOKU_INC.'inc/search.php'); 180 global $conf; 181 182 $ns=':'.cleanID($ns); 183 $ns=str_replace(':','/',$ns); 184 185 $data = array(); 186 sort($data); 187 search($data,$conf['datadir'],'search_list','',$ns); 188 foreach($data as $row){ 189 $item = new FeedItem(); 190 191 $id = $row['id']; 192 $date = filemtime(wikiFN($id)); 193 $xhtml = p_wiki_xhtml($id,'',false); 194 $desc = cleanDesc($xhtml); 195 $item->title = $id; 196 197 if($conf['useheading']) { 198 $matches = array(); 199 if(preg_match('|<h([1-9])>(.*?)</h\1>|', $xhtml, $matches)) 200 $item->title = trim($matches[2]); 201 } 202 203 $item->link = wl($id,'rev='.$date,true); 204 $item->description = $desc; 205 $item->date = date('r',$date); 206 $rss->addItem($item); 207 } 208} 209 210/** 211 * Clean description for feed inclusion 212 * 213 * Removes HTML tags and line breaks and trims the text to 214 * 250 chars 215 * 216 * @author Andreas Gohr <andi@splitbrain.org> 217 */ 218function cleanDesc($desc){ 219 //start description at text of first paragraph 220 $matches = array(); 221 if(preg_match('/<p>|<p\s.*?>/', $desc, $matches, PREG_OFFSET_CAPTURE)) 222 $desc = substr($desc, $matches[0][1]); 223 224 //remove TOC 225 $desc = preg_replace('!<div class="toc">.*?(</div>\n</div>)!s','',$desc); 226 $desc = strip_tags($desc); 227 $desc = preg_replace('/[\n\r\t]/',' ',$desc); 228 $desc = preg_replace('/ /',' ',$desc); 229 $desc = utf8_substr($desc,0,250); 230 $desc = $desc.'...'; 231 return $desc; 232} 233 234?> 235