xref: /dokuwiki/inc/Feed/FeedCreatorOptions.php (revision 0096805f6ef81b9fa159f426c00987ff1cb5a8f9)
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