Advertisement
Guest User

Untitled

a guest
Jul 2nd, 2017
503
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 19.42 KB | None | 0 0
  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.  * @global array $conf
  9.  * @global Input $INPUT
  10.  */
  11.  
  12. if(!defined('DOKU_INC')) define('DOKU_INC', dirname(__FILE__).'/');
  13. require_once(DOKU_INC.'inc/init.php');
  14.  
  15. //close session
  16. session_write_close();
  17.  
  18. //feed disabled?
  19. if(!actionOK('rss')) {
  20.     http_status(404);
  21.     echo '<error>RSS feed is disabled.</error>';
  22.     exit;
  23. }
  24.  
  25. // get params
  26. $opt = rss_parseOptions();
  27.  
  28. // the feed is dynamic - we need a cache for each combo
  29. // (but most people just use the default feed so it's still effective)
  30. $key   = join('', array_values($opt)).'$'.$_SERVER['REMOTE_USER'].'$'.$_SERVER['HTTP_HOST'].$_SERVER['SERVER_PORT'];
  31. $cache = new cache($key, '.feed');
  32.  
  33. // prepare cache depends
  34. $depends['files'] = getConfigFiles('main');
  35. $depends['age']   = $conf['rss_update'];
  36. $depends['purge'] = $INPUT->bool('purge');
  37.  
  38. // check cacheage and deliver if nothing has changed since last
  39. // time or the update interval has not passed, also handles conditional requests
  40. header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
  41. header('Pragma: public');
  42. header('Content-Type: application/xml; charset=utf-8');
  43. header('X-Robots-Tag: noindex');
  44. if($cache->useCache($depends)) {
  45.     http_conditionalRequest($cache->_time);
  46.     if($conf['allowdebug']) header("X-CacheUsed: $cache->cache");
  47.     print $cache->retrieveCache();
  48.     exit;
  49. } else {
  50.     http_conditionalRequest(time());
  51. }
  52.  
  53. // create new feed
  54. $rss                 = new DokuWikiFeedCreator();
  55. $rss->title          = $conf['title'].(($opt['namespace']) ? ' '.$opt['namespace'] : '');
  56. $rss->link           = DOKU_URL;
  57. $rss->syndicationURL = DOKU_URL.'feed.php';
  58. $rss->cssStyleSheet  = DOKU_URL.'lib/exe/css.php?s=feed';
  59.  
  60. $image        = new FeedImage();
  61. $image->title = $conf['title'];
  62. $image->url   = tpl_getMediaFile(array(':wiki:favicon.ico', ':favicon.ico', 'images/favicon.ico'), true);
  63. $image->link  = DOKU_URL;
  64. $rss->image   = $image;
  65.  
  66. $data  = null;
  67. $modes = array(
  68.     'list'   => 'rssListNamespace',
  69.     'search' => 'rssSearch',
  70.     'recent' => 'rssRecentChanges'
  71. );
  72. if(isset($modes[$opt['feed_mode']])) {
  73.     $data = $modes[$opt['feed_mode']]($opt);
  74. } else {
  75.     $eventData = array(
  76.         'opt'  => &$opt,
  77.         'data' => &$data,
  78.     );
  79.     $event     = new Doku_Event('FEED_MODE_UNKNOWN', $eventData);
  80.     if($event->advise_before(true)) {
  81.         echo sprintf('<error>Unknown feed mode %s</error>', hsc($opt['feed_mode']));
  82.         exit;
  83.     }
  84.     $event->advise_after();
  85. }
  86.  
  87. rss_buildItems($rss, $data, $opt);
  88. $feed = $rss->createFeed($opt['feed_type'], 'utf-8');
  89.  
  90. // save cachefile
  91. $cache->storeCache($feed);
  92.  
  93. // finally deliver
  94. print $feed;
  95.  
  96. // ---------------------------------------------------------------- //
  97.  
  98. /**
  99.  * Get URL parameters and config options and return an initialized option array
  100.  *
  101.  * @author Andreas Gohr <andi@splitbrain.org>
  102.  */
  103. function rss_parseOptions() {
  104.     global $conf;
  105.     global $INPUT;
  106.  
  107.     $opt = array();
  108.  
  109.     foreach(array(
  110.                 // Basic feed properties
  111.                 // Plugins may probably want to add new values to these
  112.                 // properties for implementing own feeds
  113.  
  114.                 // One of: list, search, recent
  115.                 'feed_mode'    => array('str', 'mode', 'recent'),
  116.                 // One of: diff, page, rev, current
  117.                 'link_to'      => array('str', 'linkto', $conf['rss_linkto']),
  118.                 // One of: abstract, diff, htmldiff, html
  119.                 'item_content' => array('str', 'content', $conf['rss_content']),
  120.  
  121.                 // Special feed properties
  122.                 // These are only used by certain feed_modes
  123.  
  124.                 // String, used for feed title, in list and rc mode
  125.                 'namespace'    => array('str', 'ns', null),
  126.                 // Positive integer, only used in rc mode
  127.                 'items'        => array('int', 'num', $conf['recent']),
  128.                 // Boolean, only used in rc mode
  129.                 'show_minor'   => array('bool', 'minor', false),
  130.                 // String, only used in list mode
  131.                 'sort'         => array('str', 'sort', 'natural'),
  132.                 // String, only used in search mode
  133.                 'search_query' => array('str', 'q', null),
  134.                 // One of: pages, media, both
  135.                 'content_type' => array('str', 'view', $conf['rss_media'])
  136.  
  137.             ) as $name => $val) {
  138.         $opt[$name] = $INPUT->{$val[0]}($val[1], $val[2], true);
  139.     }
  140.  
  141.     $opt['items']      = max(0, (int) $opt['items']);
  142.     $opt['show_minor'] = (bool) $opt['show_minor'];
  143.     $opt['sort'] = valid_input_set('sort', array('default' => 'natural', 'date'), $opt);
  144.  
  145.     $opt['guardmail'] = ($conf['mailguard'] != '' && $conf['mailguard'] != 'none');
  146.  
  147.     $type = $INPUT->valid(
  148.         'type',
  149.         array( 'rss', 'rss2', 'atom', 'atom1', 'rss1'),
  150.         $conf['rss_type']
  151.     );
  152.     switch($type) {
  153.         case 'rss':
  154.             $opt['feed_type'] = 'RSS0.91';
  155.             $opt['mime_type'] = 'text/xml';
  156.             break;
  157.         case 'rss2':
  158.             $opt['feed_type'] = 'RSS2.0';
  159.             $opt['mime_type'] = 'text/xml';
  160.             break;
  161.         case 'atom':
  162.             $opt['feed_type'] = 'ATOM0.3';
  163.             $opt['mime_type'] = 'application/xml';
  164.             break;
  165.         case 'atom1':
  166.             $opt['feed_type'] = 'ATOM1.0';
  167.             $opt['mime_type'] = 'application/atom+xml';
  168.             break;
  169.         default:
  170.             $opt['feed_type'] = 'RSS1.0';
  171.             $opt['mime_type'] = 'application/xml';
  172.     }
  173.  
  174.     $eventData = array(
  175.         'opt' => &$opt,
  176.     );
  177.     trigger_event('FEED_OPTS_POSTPROCESS', $eventData);
  178.     return $opt;
  179. }
  180.  
  181. /**
  182.  * Add recent changed pages to a feed object
  183.  *
  184.  * @author Andreas Gohr <andi@splitbrain.org>
  185.  * @param  FeedCreator $rss the FeedCreator Object
  186.  * @param  array       $data the items to add
  187.  * @param  array       $opt  the feed options
  188.  */
  189. function rss_buildItems(&$rss, &$data, $opt) {
  190.     global $conf;
  191.     global $lang;
  192.     /* @var DokuWiki_Auth_Plugin $auth */
  193.     global $auth;
  194.  
  195.     $eventData = array(
  196.         'rss'  => &$rss,
  197.         'data' => &$data,
  198.         'opt'  => &$opt,
  199.     );
  200.     $event     = new Doku_Event('FEED_DATA_PROCESS', $eventData);
  201.     if($event->advise_before(false)) {
  202.         foreach($data as $ditem) {
  203.             if(!is_array($ditem)) {
  204.                 // not an array? then only a list of IDs was given
  205.                 $ditem = array('id' => $ditem);
  206.             }
  207.  
  208.             $item = new FeedItem();
  209.             $id   = $ditem['id'];
  210.             if(!$ditem['media']) {
  211.                 $meta = p_get_metadata($id);
  212.             } else {
  213.                 $meta = array();
  214.             }
  215.  
  216.             // add date
  217.             if($ditem['date']) {
  218.                 $date = $ditem['date'];
  219.             } elseif ($ditem['media']) {
  220.                 $date = @filemtime(mediaFN($id));
  221.             } elseif (file_exists(wikiFN($id))) {
  222.                 $date = @filemtime(wikiFN($id));
  223.             } elseif($meta['date']['modified']) {
  224.                 $date = $meta['date']['modified'];
  225.             } else {
  226.                 $date = 0;
  227.             }
  228.             if($date) $item->date = date('r', $date);
  229.  
  230.             // add title
  231.             if($conf['useheading'] && $meta['title']) {
  232.                 $item->title = $meta['title'];
  233.             } else {
  234.                 $item->title = $ditem['id'];
  235.             }
  236.             if($conf['rss_show_summary'] && !empty($ditem['sum'])) {
  237.                 $item->title .= ' - '.strip_tags($ditem['sum']);
  238.             }
  239.  
  240.             // add item link
  241.             switch($opt['link_to']) {
  242.                 case 'page':
  243.                     if($ditem['media']) {
  244.                         $item->link = media_managerURL(
  245.                             array(
  246.                                  'image' => $id,
  247.                                  'ns'    => getNS($id),
  248.                                  'rev'   => $date
  249.                             ), '&', true
  250.                         );
  251.                     } else {
  252.                         $item->link = wl($id, 'rev='.$date, true, '&');
  253.                     }
  254.                     break;
  255.                 case 'rev':
  256.                     if($ditem['media']) {
  257.                         $item->link = media_managerURL(
  258.                             array(
  259.                                  'image'       => $id,
  260.                                  'ns'          => getNS($id),
  261.                                  'rev'         => $date,
  262.                                  'tab_details' => 'history'
  263.                             ), '&', true
  264.                         );
  265.                     } else {
  266.                         $item->link = wl($id, 'do=revisions&rev='.$date, true, '&');
  267.                     }
  268.                     break;
  269.                 case 'current':
  270.                     if($ditem['media']) {
  271.                         $item->link = media_managerURL(
  272.                             array(
  273.                                  'image' => $id,
  274.                                  'ns'    => getNS($id)
  275.                             ), '&', true
  276.                         );
  277.                     } else {
  278.                         $item->link = wl($id, '', true, '&');
  279.                     }
  280.                     break;
  281.                 case 'diff':
  282.                 default:
  283.                     if($ditem['media']) {
  284.                         $item->link = media_managerURL(
  285.                             array(
  286.                                  'image'       => $id,
  287.                                  'ns'          => getNS($id),
  288.                                  'rev'         => $date,
  289.                                  'tab_details' => 'history',
  290.                                  'mediado'     => 'diff'
  291.                             ), '&', true
  292.                         );
  293.                     } else {
  294.                         $item->link = wl($id, 'rev='.$date.'&do=diff', true, '&');
  295.                     }
  296.             }
  297.  
  298.             // add item content
  299.             switch($opt['item_content']) {
  300.                 case 'diff':
  301.                 case 'htmldiff':
  302.                     if($ditem['media']) {
  303.                         $medialog = new MediaChangeLog($id);
  304.                         $revs  = $medialog->getRevisions(0, 1);
  305.                         $rev   = $revs[0];
  306.                         $src_r = '';
  307.                         $src_l = '';
  308.  
  309.                         if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)), 300)) {
  310.                             $more  = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
  311.                             $src_r = ml($id, $more, true, '&amp;', true);
  312.                         }
  313.                         if($rev && $size = media_image_preview_size($id, $rev, new JpegMeta(mediaFN($id, $rev)), 300)) {
  314.                             $more  = 'rev='.$rev.'&w='.$size[0].'&h='.$size[1];
  315.                             $src_l = ml($id, $more, true, '&amp;', true);
  316.                         }
  317.                         $content = '';
  318.                         if($src_r) {
  319.                             $content = '<table>';
  320.                             $content .= '<tr><th width="50%">'.$rev.'</th>';
  321.                             $content .= '<th width="50%">'.$lang['current'].'</th></tr>';
  322.                             $content .= '<tr align="center"><td><img src="'.$src_l.'" alt="" /></td><td>';
  323.                             $content .= '<img src="'.$src_r.'" alt="'.$id.'" /></td></tr>';
  324.                             $content .= '</table>';
  325.                         }
  326.  
  327.                     } else {
  328.                         require_once(DOKU_INC.'inc/DifferenceEngine.php');
  329.                         $pagelog = new PageChangeLog($id);
  330.                         $revs = $pagelog->getRevisions(0, 1);
  331.                         $rev  = $revs[0];
  332.  
  333.                         if($rev) {
  334.                             $df = new Diff(explode("\n", rawWiki($id, $rev)),
  335.                                            explode("\n", rawWiki($id, '')));
  336.                         } else {
  337.                             $df = new Diff(array(''),
  338.                                            explode("\n", rawWiki($id, '')));
  339.                         }
  340.  
  341.                         if($opt['item_content'] == 'htmldiff') {
  342.                             // note: no need to escape diff output, TableDiffFormatter provides 'safe' html
  343.                             $tdf     = new TableDiffFormatter();
  344.                             $content = '<table>';
  345.                             $content .= '<tr><th colspan="2" width="50%">'.$rev.'</th>';
  346.                             $content .= '<th colspan="2" width="50%">'.$lang['current'].'</th></tr>';
  347.                             $content .= $tdf->format($df);
  348.                             $content .= '</table>';
  349.                         } else {
  350.                             // note: diff output must be escaped, UnifiedDiffFormatter provides plain text
  351.                             $udf     = new UnifiedDiffFormatter();
  352.                             $content = "<pre>\n".hsc($udf->format($df))."\n</pre>";
  353.                         }
  354.                     }
  355.                     break;
  356.                 case 'html':
  357.                     if($ditem['media']) {
  358.                         if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
  359.                             $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
  360.                             $src     = ml($id, $more, true, '&amp;', true);
  361.                             $content = '<img src="'.$src.'" alt="'.$id.'" />';
  362.                         } else {
  363.                             $content = '';
  364.                         }
  365.                     } else {
  366.                         if (@filemtime(wikiFN($id)) === $date) {
  367.                             $content = p_wiki_xhtml($id, '', false);
  368.                         } else {
  369.                             $content = p_wiki_xhtml($id, $date, false);
  370.                         }
  371.                         // no TOC in feeds
  372.                         $content = preg_replace('/(<!-- TOC START -->).*(<!-- TOC END -->)/s', '', $content);
  373.  
  374.                         // add alignment for images
  375.                         $content = preg_replace('/(<img .*?class="medialeft")/s', '\\1 align="left"', $content);
  376.                         $content = preg_replace('/(<img .*?class="mediaright")/s', '\\1 align="right"', $content);
  377.  
  378.                         // make URLs work when canonical is not set, regexp instead of rerendering!
  379.                         if(!$conf['canonical']) {
  380.                             $base    = preg_quote(DOKU_REL, '/');
  381.                             $content = preg_replace('/(<a href|<img src)="('.$base.')/s', '$1="'.DOKU_URL, $content);
  382.                         }
  383.                     }
  384.  
  385.                     break;
  386.                 case 'abstract':
  387.                 default:
  388.                     if($ditem['media']) {
  389.                         if($size = media_image_preview_size($id, '', new JpegMeta(mediaFN($id)))) {
  390.                             $more    = 'w='.$size[0].'&h='.$size[1].'&t='.@filemtime(mediaFN($id));
  391.                             $src     = ml($id, $more, true, '&amp;', true);
  392.                             $content = '<img src="'.$src.'" alt="'.$id.'" />';
  393.                         } else {
  394.                             $content = '';
  395.                         }
  396.                     } else {
  397.                         $content = $meta['description']['abstract'];
  398.                     }
  399.             }
  400.             $item->description = $content; //FIXME a plugin hook here could be senseful
  401.  
  402.             // add user
  403.             # FIXME should the user be pulled from metadata as well?
  404.            $user         = @$ditem['user']; // the @ spares time repeating lookup
  405.             $item->author = '';
  406.             if($user && $conf['useacl'] && $auth) {
  407.                 $userInfo = $auth->getUserData($user);
  408.                 if($userInfo) {
  409.                     switch($conf['showuseras']) {
  410.                         case 'username':
  411.                         case 'username_link':
  412.                             $item->author = $userInfo['name'];
  413.                             break;
  414.                         default:
  415.                             $item->author = $user;
  416.                             break;
  417.                     }
  418.                 } else {
  419.                     $item->author = $user;
  420.                 }
  421.                 if($userInfo && !$opt['guardmail']) {
  422.                     $item->authorEmail = $userInfo['mail'];
  423.                 } else {
  424.                     //cannot obfuscate because some RSS readers may check validity
  425.                     $item->authorEmail = $user.'@'.$ditem['ip'];
  426.                 }
  427.             } elseif($user) {
  428.                 // this happens when no ACL but some Apache auth is used
  429.                 $item->author      = $user;
  430.                 $item->authorEmail = $user.'@'.$ditem['ip'];
  431.             } else {
  432.                 $item->authorEmail = 'anonymous@'.$ditem['ip'];
  433.             }
  434.  
  435.             // add category
  436.             if(isset($meta['subject'])) {
  437.                 $item->category = $meta['subject'];
  438.             } else {
  439.                 $cat = getNS($id);
  440.                 if($cat) $item->category = $cat;
  441.             }
  442.  
  443.             // finally add the item to the feed object, after handing it to registered plugins
  444.             $evdata = array(
  445.                 'item'  => &$item,
  446.                 'opt'   => &$opt,
  447.                 'ditem' => &$ditem,
  448.                 'rss'   => &$rss
  449.             );
  450.             $evt    = new Doku_Event('FEED_ITEM_ADD', $evdata);
  451.             if($evt->advise_before()) {
  452.                 $rss->addItem($item);
  453.             }
  454.             $evt->advise_after(); // for completeness
  455.         }
  456.     }
  457.     $event->advise_after();
  458. }
  459.  
  460. /**
  461.  * Add recent changed pages to the feed object
  462.  *
  463.  * @author Andreas Gohr <andi@splitbrain.org>
  464.  */
  465. function rssRecentChanges($opt) {
  466.     global $conf;
  467.     $flags = RECENTS_SKIP_DELETED;
  468.     if(!$opt['show_minor']) $flags += RECENTS_SKIP_MINORS;
  469.     if($opt['content_type'] == 'media' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_CHANGES;
  470.     if($opt['content_type'] == 'both' && $conf['mediarevisions']) $flags += RECENTS_MEDIA_PAGES_MIXED;
  471.  
  472.     $recents = getRecents(0, $opt['items'], $opt['namespace'], $flags);
  473.     return $recents;
  474. }
  475.  
  476. /**
  477.  * Add all pages of a namespace to the feed object
  478.  *
  479.  * @author Andreas Gohr <andi@splitbrain.org>
  480.  */
  481. function rssListNamespace($opt) {
  482.     require_once(DOKU_INC.'inc/search.php');
  483.     global $conf;
  484.  
  485.     $ns = ':'.cleanID($opt['namespace']);
  486.     $ns = utf8_encodeFN(str_replace(':', '/', $ns));
  487.  
  488.     $data = array();
  489.     $search_opts = array(
  490.         'depth' => 1,
  491.         'pagesonly' => true,
  492.         'listfiles' => true
  493.     );
  494.     search($data, $conf['datadir'], 'search_universal', $search_opts, $ns, $lvl = 1, $opt['sort']);
  495.  
  496.     return $data;
  497. }
  498.  
  499. /**
  500.  * Add the result of a full text search to the feed object
  501.  *
  502.  * @author Andreas Gohr <andi@splitbrain.org>
  503.  */
  504. function rssSearch($opt) {
  505.     if(!$opt['search_query']) return array();
  506.  
  507.     require_once(DOKU_INC.'inc/fulltext.php');
  508.     $data = ft_pageSearch($opt['search_query'], $poswords);
  509.     $data = array_keys($data);
  510.  
  511.     return $data;
  512. }
  513.  
  514. //Setup VIM: ex: et ts=4 :
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement