1fe9d054bSAndreas Gohr<?php 2fe9d054bSAndreas Gohr 3fe9d054bSAndreas Gohrnamespace dokuwiki\Feed; 4fe9d054bSAndreas Gohr 5fe9d054bSAndreas Gohruse dokuwiki\Extension\Event; 6fe9d054bSAndreas Gohr 7fe9d054bSAndreas Gohr/** 8fe9d054bSAndreas Gohr * Hold the options for feed generation 9fe9d054bSAndreas Gohr */ 10fe9d054bSAndreas Gohrclass FeedCreatorOptions 11fe9d054bSAndreas Gohr{ 12fe9d054bSAndreas Gohr /** @var array[] supported feed types */ 13fe9d054bSAndreas Gohr protected $types = [ 14fe9d054bSAndreas Gohr 'rss' => [ 15fe9d054bSAndreas Gohr 'name' => 'RSS0.91', 16fe9d054bSAndreas Gohr 'mime' => 'text/xml; charset=utf-8', 17fe9d054bSAndreas Gohr ], 187e23bd08SAndreas Gohr 'rss1' => [ 197e23bd08SAndreas Gohr 'name' => 'RSS1.0', 207e23bd08SAndreas Gohr 'mime' => 'text/xml; charset=utf-8', 217e23bd08SAndreas Gohr ], 22fe9d054bSAndreas Gohr 'rss2' => [ 23fe9d054bSAndreas Gohr 'name' => 'RSS2.0', 24fe9d054bSAndreas Gohr 'mime' => 'text/xml; charset=utf-8', 25fe9d054bSAndreas Gohr ], 26fe9d054bSAndreas Gohr 'atom' => [ 27fe9d054bSAndreas Gohr 'name' => 'ATOM0.3', 28fe9d054bSAndreas Gohr 'mime' => 'application/xml; charset=utf-8', 29fe9d054bSAndreas Gohr ], 30fe9d054bSAndreas Gohr 'atom1' => [ 31fe9d054bSAndreas Gohr 'name' => 'ATOM1.0', 32fe9d054bSAndreas Gohr 'mime' => 'application/atom+xml; charset=utf-8', 33fe9d054bSAndreas Gohr ], 34fe9d054bSAndreas Gohr ]; 35fe9d054bSAndreas Gohr 36fe9d054bSAndreas Gohr /** @var array[] the set options */ 37fe9d054bSAndreas Gohr public $options = [ 38fe9d054bSAndreas Gohr 'type' => 'rss', 39fe9d054bSAndreas Gohr 'feed_mode' => 'recent', 40fe9d054bSAndreas Gohr 'link_to' => 'page', 41fe9d054bSAndreas Gohr 'item_content' => 'diff', 42fe9d054bSAndreas Gohr 'namespace' => '', 43fe9d054bSAndreas Gohr 'items' => 15, 44fe9d054bSAndreas Gohr 'show_minor' => false, 45fe9d054bSAndreas Gohr 'show_deleted' => false, 46fe9d054bSAndreas Gohr 'show_summary' => false, 47fe9d054bSAndreas Gohr 'only_new' => false, 48fe9d054bSAndreas Gohr 'sort' => 'natural', 49fe9d054bSAndreas Gohr 'search_query' => '', 50fe9d054bSAndreas Gohr 'content_type' => 'pages', 51fe9d054bSAndreas Gohr 'guardmail' => 'none', 52fe9d054bSAndreas Gohr 'title' => '', 53*867da04dSAndreas Gohr 'cache_allow' => false, 54*867da04dSAndreas Gohr 'cache_key' => '', 55fe9d054bSAndreas Gohr ]; 56fe9d054bSAndreas Gohr 57fe9d054bSAndreas Gohr /** 58fe9d054bSAndreas Gohr * Initialize the options from the request, falling back to config defaults 59fe9d054bSAndreas Gohr * 60fe9d054bSAndreas Gohr * @triggers FEED_OPTS_POSTPROCESS 61fe9d054bSAndreas Gohr * @param array $options additional options to set (for testing) 62fe9d054bSAndreas Gohr */ 63fe9d054bSAndreas Gohr public function __construct($options = []) 64fe9d054bSAndreas Gohr { 65fe9d054bSAndreas Gohr global $conf; 66fe9d054bSAndreas Gohr global $INPUT; 67fe9d054bSAndreas Gohr 68fe9d054bSAndreas Gohr $this->options['type'] = $INPUT->valid( 69fe9d054bSAndreas Gohr 'type', 70fe9d054bSAndreas Gohr array_keys($this->types), 71fe9d054bSAndreas Gohr $conf['rss_type'] 72fe9d054bSAndreas Gohr ); 73fe9d054bSAndreas Gohr // we only support 'list', 'search', 'recent' but accept anything so plugins can take over 74fe9d054bSAndreas Gohr $this->options['feed_mode'] = $INPUT->str('mode', 'recent'); 75fe9d054bSAndreas Gohr $this->options['link_to'] = $INPUT->valid( 76fe9d054bSAndreas Gohr 'linkto', 77fe9d054bSAndreas Gohr ['diff', 'page', 'rev', 'current'], 78fe9d054bSAndreas Gohr $conf['rss_linkto'] 79fe9d054bSAndreas Gohr ); 80fe9d054bSAndreas Gohr $this->options['item_content'] = $INPUT->valid( 81fe9d054bSAndreas Gohr 'content', 82fe9d054bSAndreas Gohr ['abstract', 'diff', 'htmldiff', 'html'], 83fe9d054bSAndreas Gohr $conf['rss_content'] 84fe9d054bSAndreas Gohr ); 85fe9d054bSAndreas Gohr $this->options['namespace'] = $INPUT->filter('cleanID')->str('ns'); 86*867da04dSAndreas Gohr $this->options['items'] = $INPUT->int('num', $conf['recent']); 87fe9d054bSAndreas Gohr $this->options['show_minor'] = $INPUT->bool('minor'); 88fe9d054bSAndreas Gohr $this->options['show_deleted'] = $conf['rss_show_deleted']; 89fe9d054bSAndreas Gohr $this->options['show_summary'] = $conf['rss_show_summary']; 90fe9d054bSAndreas Gohr $this->options['only_new'] = $INPUT->bool('onlynewpages'); 91fe9d054bSAndreas Gohr $this->options['sort'] = $INPUT->valid( 92fe9d054bSAndreas Gohr 'sort', 93fe9d054bSAndreas Gohr ['natural', 'date'], 94fe9d054bSAndreas Gohr 'natural' 95fe9d054bSAndreas Gohr ); 96fe9d054bSAndreas Gohr $this->options['search_query'] = $INPUT->str('q'); 97fe9d054bSAndreas Gohr $this->options['content_type'] = $INPUT->valid( 98fe9d054bSAndreas Gohr 'view', 99fe9d054bSAndreas Gohr ['pages', 'media', 'both'], 100fe9d054bSAndreas Gohr $conf['rss_media'] 101fe9d054bSAndreas Gohr ); 102fe9d054bSAndreas Gohr $this->options['guardmail'] = $conf['mailguard']; 103fe9d054bSAndreas Gohr $this->options['title'] = $conf['title']; 104fe9d054bSAndreas Gohr if ($this->options['namespace']) { 105fe9d054bSAndreas Gohr $this->options['title'] .= ' - ' . $this->options['namespace']; 106fe9d054bSAndreas Gohr } 1071136941dSAndreas Gohr $this->options['subtitle'] = $conf['tagline']; 108fe9d054bSAndreas Gohr 109fe9d054bSAndreas Gohr $this->options = array_merge($this->options, $options); 110*867da04dSAndreas Gohr // clamp items to a reasonable range to prevent cache DoS via arbitrary num values 111*867da04dSAndreas Gohr $this->options['items'] = min(max(1, (int)$this->options['items']), $conf['recent'] * 5); 112*867da04dSAndreas Gohr // only the recent mode is cached by default to prevent cache DoS; 113*867da04dSAndreas Gohr // plugins can enable caching for their modes via FEED_OPTS_POSTPROCESS 114*867da04dSAndreas Gohr $this->options['cache_allow'] = ($this->options['feed_mode'] === 'recent'); 115fe9d054bSAndreas Gohr 116fe9d054bSAndreas Gohr // initialization finished, let plugins know 117fe9d054bSAndreas Gohr $eventData = [ 118fe9d054bSAndreas Gohr 'opt' => &$this->options, 119fe9d054bSAndreas Gohr ]; 120fe9d054bSAndreas Gohr Event::createAndTrigger('FEED_OPTS_POSTPROCESS', $eventData); 121fe9d054bSAndreas Gohr } 122fe9d054bSAndreas Gohr 123fe9d054bSAndreas Gohr /** 124fe9d054bSAndreas Gohr * The cache key to use for a feed with these options 125fe9d054bSAndreas Gohr * 126*867da04dSAndreas Gohr * Only includes options that affect the current mode's output. 127fe9d054bSAndreas Gohr * 128*867da04dSAndreas Gohr * @param string[] $additional additional key parts (e.g. user, host, port) 129*867da04dSAndreas Gohr * @return string|null null if the feed should not be cached 130fe9d054bSAndreas Gohr */ 131*867da04dSAndreas Gohr public function getCacheKey(array $additional = []): ?string 132fe9d054bSAndreas Gohr { 133*867da04dSAndreas Gohr if (!$this->options['cache_allow']) { 134*867da04dSAndreas Gohr return null; 135*867da04dSAndreas Gohr } 136*867da04dSAndreas Gohr 137*867da04dSAndreas Gohr return implode('$', array_merge([ 138*867da04dSAndreas Gohr $this->options['feed_mode'], 139*867da04dSAndreas Gohr $this->options['type'], 140*867da04dSAndreas Gohr $this->options['link_to'], 141*867da04dSAndreas Gohr $this->options['item_content'], 142*867da04dSAndreas Gohr $this->options['show_summary'], 143*867da04dSAndreas Gohr $this->options['guardmail'], 144*867da04dSAndreas Gohr $this->options['namespace'], 145*867da04dSAndreas Gohr $this->options['items'], 146*867da04dSAndreas Gohr $this->options['show_minor'], 147*867da04dSAndreas Gohr $this->options['show_deleted'], 148*867da04dSAndreas Gohr $this->options['only_new'], 149*867da04dSAndreas Gohr $this->options['content_type'], 150*867da04dSAndreas Gohr $this->options['cache_key'], 151*867da04dSAndreas Gohr ], $additional)); 152fe9d054bSAndreas Gohr } 153fe9d054bSAndreas Gohr 154fe9d054bSAndreas Gohr /** 155fe9d054bSAndreas Gohr * Return a feed option by name 156fe9d054bSAndreas Gohr * 157fe9d054bSAndreas Gohr * @param string $option The name of the option 158fe9d054bSAndreas Gohr * @param mixed $default default value if option is not set (should usually not happen) 159fe9d054bSAndreas Gohr * @return mixed 160fe9d054bSAndreas Gohr */ 161fe9d054bSAndreas Gohr public function get($option, $default = null) 162fe9d054bSAndreas Gohr { 16372c714a3Ssplitbrain return $this->options[$option] ?? $default; 164fe9d054bSAndreas Gohr } 165fe9d054bSAndreas Gohr 166fe9d054bSAndreas Gohr /** 167fe9d054bSAndreas Gohr * Return the feed type for UniversalFeedCreator 168fe9d054bSAndreas Gohr * 169fe9d054bSAndreas Gohr * This returns the apropriate type for UniversalFeedCreator 170fe9d054bSAndreas Gohr * 171fe9d054bSAndreas Gohr * @return string 172fe9d054bSAndreas Gohr */ 173fe9d054bSAndreas Gohr public function getType() 174fe9d054bSAndreas Gohr { 175fe9d054bSAndreas Gohr return $this->types[$this->options['type']]['name']; 176fe9d054bSAndreas Gohr } 177fe9d054bSAndreas Gohr 178fe9d054bSAndreas Gohr /** 179fe9d054bSAndreas Gohr * Return the feed mime type 180fe9d054bSAndreas Gohr * 181fe9d054bSAndreas Gohr * @return string 182fe9d054bSAndreas Gohr */ 183fe9d054bSAndreas Gohr public function getMimeType() 184fe9d054bSAndreas Gohr { 185fe9d054bSAndreas Gohr return $this->types[$this->options['type']]['mime']; 186fe9d054bSAndreas Gohr } 187fe9d054bSAndreas Gohr} 188