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