This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace XoopsModules\Rssfit; |
||
6 | |||
7 | /* |
||
8 | * You may not change or alter any portion of this comment or credits |
||
9 | * of supporting developers from this source code or any supporting source code |
||
10 | * which is considered copyrighted (c) material of the original comment or credit authors. |
||
11 | * |
||
12 | * This program is distributed in the hope that it will be useful, |
||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
||
15 | */ |
||
16 | |||
17 | /** |
||
18 | * @copyright XOOPS Project (https://xoops.org) |
||
19 | * @license GNU GPL 2 or later (https://www.gnu.org/licenses/gpl-2.0.html) |
||
20 | * @package RSSFit - Extendable XML news feed generator |
||
21 | * @author NS Tai (aka tuff) <http://www.brandycoke.com> |
||
22 | * @author XOOPS Development Team |
||
23 | */ |
||
24 | |||
25 | if (!\defined('RSSFIT_ROOT_PATH')) { |
||
26 | exit(); |
||
27 | } |
||
28 | |||
29 | /** |
||
30 | * Class FeedHandler |
||
31 | * @package XoopsModules\Rssfit |
||
32 | */ |
||
33 | class FeedHandler |
||
34 | { |
||
35 | public $rssmod; |
||
36 | public $pluginHandler; |
||
37 | public $miscHandler; |
||
38 | public $helper; |
||
39 | public $channelreq; |
||
40 | public $subHandler; |
||
41 | public $pluginObject; |
||
42 | public $myts; |
||
43 | public $modConfig; |
||
44 | public $xoopsConfig; |
||
45 | public $cached = ''; |
||
46 | public $charset = _CHARSET; |
||
47 | public $feedkey = 'feed'; |
||
48 | public $pluginFile = '%s.php'; |
||
49 | public $substrRemove = [',', '/', ';', ':', '(', '{', '[', ' ']; |
||
50 | public $substrAdd = ['.', '!', '?', '}', ']', ')', '%']; |
||
51 | public $substrEndwith = '...'; |
||
52 | public $specUrl = 'http://blogs.law.harvard.edu/tech/rss'; |
||
53 | public $specs = [ |
||
54 | 'req' => 'requiredChannelElements', |
||
55 | 'opt' => 'optionalChannelElements', |
||
56 | 'cloud' => 'ltcloudgtSubelementOfLtchannelgt', |
||
57 | 'img' => 'ltimagegtSubelementOfLtchannelgt', |
||
58 | ]; |
||
59 | public $escaped = [ |
||
60 | 128 => '€', |
||
61 | 130 => '‚', |
||
62 | 131 => 'ƒ', |
||
63 | 132 => '„', |
||
64 | 133 => '…', |
||
65 | 134 => '†', |
||
66 | 135 => '‡', |
||
67 | 136 => 'ˆ', |
||
68 | 137 => '‰', |
||
69 | 138 => 'Š', |
||
70 | 139 => '‹', |
||
71 | 140 => 'Œ', |
||
72 | 142 => 'Ž', |
||
73 | 145 => '‘', |
||
74 | 146 => '’', |
||
75 | 147 => '“', |
||
76 | 148 => '”', |
||
77 | 149 => '•', |
||
78 | 150 => '–', |
||
79 | 151 => '—', |
||
80 | 152 => '˜', |
||
81 | 153 => '™', |
||
82 | 154 => 'š', |
||
83 | 155 => '›', |
||
84 | 156 => 'œ', |
||
85 | 158 => 'ž', |
||
86 | 159 => 'Ÿ', |
||
87 | ]; |
||
88 | |||
89 | /** |
||
90 | * FeedHandler constructor. |
||
91 | */ |
||
92 | public function __construct(array $modConfig, array $xoopsConfig, \XoopsModule $xoopsModule) |
||
93 | { |
||
94 | $this->myts = \MyTextSanitizer::getInstance(); |
||
95 | $this->rssmod = $xoopsModule; |
||
96 | $this->helper = Helper::getInstance(); |
||
97 | $this->pluginHandler = Helper::getInstance()->getHandler('Plugin'); |
||
98 | $this->miscHandler = Helper::getInstance()->getHandler('Misc'); |
||
99 | $this->modConfig = $modConfig; |
||
100 | $this->xoopsConfig = $xoopsConfig; |
||
101 | $this->channelreq = [ |
||
102 | 'title' => $this->xoopsConfig['sitename'], |
||
103 | 'link' => XOOPS_URL, |
||
104 | 'description' => $this->xoopsConfig['slogan'], |
||
105 | ]; |
||
106 | } |
||
107 | |||
108 | public function getChannel(array &$feed): void |
||
109 | { |
||
110 | $channel = []; |
||
111 | $elements = $this->miscHandler->getObjects2(new \Criteria('misc_category', 'channel')); |
||
112 | if (\is_array($elements) && !empty($elements)) { |
||
113 | foreach ($elements as $e) { |
||
114 | if ('' !== $e->getVar('misc_content')) { |
||
115 | $channel[$e->getVar('misc_title')] = $e->getVar('misc_content', 'n'); |
||
116 | } |
||
117 | } |
||
118 | $channel['language'] = _LANGCODE; |
||
119 | $channel['lastBuildDate'] = $this->rssTimeStamp(\time()); |
||
120 | if ($this->modConfig['cache']) { |
||
121 | $channel['ttl'] = (string)$this->modConfig['cache']; |
||
122 | } |
||
123 | } |
||
124 | if (!empty($feed['plugin'])) { |
||
125 | if (\is_object($this->pluginObject) && \is_object($this->subHandler)) { |
||
126 | $channel['title'] = $this->pluginObject->getVar('sub_title', 'n'); |
||
127 | $channel['link'] = $this->pluginObject->getVar('sub_link', 'n'); |
||
128 | $channel['description'] = $this->pluginObject->getVar('sub_desc', 'n'); |
||
129 | $image = [ |
||
130 | 'url' => $this->pluginObject->getVar('img_url', 'n'), |
||
131 | 'title' => $this->pluginObject->getVar('img_title', 'n'), |
||
132 | 'link' => $this->pluginObject->getVar('img_link', 'n'), |
||
133 | ]; |
||
134 | } |
||
135 | } else { |
||
136 | $img = $this->miscHandler->getObjects2(new \Criteria('misc_category', 'channelimg'), '*', 'title'); |
||
137 | if ($img) { |
||
138 | $image = [ |
||
139 | 'url' => $img['url']->getVar('misc_content', 'n'), |
||
140 | 'title' => $img['title']->getVar('misc_content', 'n'), |
||
141 | 'link' => $img['link']->getVar('misc_content', 'n'), |
||
142 | ]; |
||
143 | } |
||
144 | } |
||
145 | if (empty($channel['title']) || empty($channel['link']) || empty($channel['description'])) { |
||
146 | $channel = \array_merge($channel, $this->channelreq); |
||
147 | } |
||
148 | foreach ($channel as $k => $v) { |
||
149 | |||
150 | $this->cleanupChars($channel[$k]); |
||
151 | } |
||
152 | if (!empty($image)) { |
||
153 | foreach ($image as $k => $v) { |
||
154 | $this->cleanupChars($image[$k]); |
||
155 | } |
||
156 | $feed['image'] = &$image; |
||
157 | } |
||
158 | $feed['channel'] = &$channel; |
||
159 | } |
||
160 | |||
161 | public function getSticky(array &$feed): bool |
||
162 | { |
||
163 | if (!$intr = $this->miscHandler->getObjects2(new \Criteria('misc_category', 'sticky'))) { |
||
164 | return false; |
||
165 | } |
||
166 | $sticky = &$intr[0]; |
||
167 | unset($intr); |
||
168 | $setting = $sticky->getVar('misc_setting'); |
||
169 | if (\in_array(0, $setting['feeds']) || '' === $sticky->getVar('misc_title') || '' === $sticky->getVar('misc_content')) { |
||
170 | return false; |
||
171 | } |
||
172 | if ((\in_array(-1, $setting['feeds']) && empty($feed['plugin'])) |
||
173 | || (!empty($feed['plugin']) && \in_array($this->pluginObject->getVar('rssf_conf_id'), $setting['feeds']))) { |
||
174 | $feed['sticky']['title'] = $sticky->getVar('misc_title', 'n'); |
||
175 | $feed['sticky']['link'] = $setting['link']; |
||
176 | $sticky->setDoHtml((bool)$setting['dohtml']); |
||
177 | $sticky->setDoBr((bool)$setting['dobr']); |
||
178 | $feed['sticky']['description'] = $sticky->getVar('misc_content'); |
||
179 | $this->cleanupChars($feed['sticky']['title']); |
||
180 | $this->cleanupChars($feed['sticky']['link']); |
||
181 | $this->cleanupChars($feed['sticky']['description'], !$setting['dohtml'], false); |
||
182 | $this->wrapCdata($feed['sticky']['description']); |
||
183 | $feed['sticky']['pubdate'] = $this->rssTimeStamp(\time()); |
||
184 | } |
||
185 | |||
186 | return true; |
||
187 | } |
||
188 | |||
189 | public function getItems(array &$feed): void |
||
190 | { |
||
191 | $entries = []; |
||
192 | $db = \XoopsDatabaseFactory::getDatabaseConnection(); |
||
193 | if (!empty($feed['plugin'])) { |
||
194 | $this->pluginObject->setVar('rssf_grab', $this->pluginObject->getVar('sub_entries')); |
||
195 | $this->subHandler->grab = $this->pluginObject->getVar('sub_entries'); |
||
196 | $grab = $this->subHandler->grabEntries($db); |
||
197 | if (null !== $grab && \count($grab) > 0) { |
||
198 | foreach ($grab as $g) { |
||
199 | $entries[] = $g; |
||
200 | } |
||
201 | } |
||
202 | } elseif ($plugins = $this->pluginHandler->getObjects2(new \Criteria('rssf_activated', '1'))) { |
||
203 | foreach ($plugins as $p) { |
||
204 | $handler = $this->pluginHandler->checkPlugin($p); |
||
205 | if ($handler) { |
||
206 | $handler->grab = $p->getVar('rssf_grab'); |
||
207 | $grab = $handler->grabEntries($db); |
||
208 | if (null !== $grab && \count($grab) > 0) { |
||
209 | foreach ($grab as $g) { |
||
210 | $entries[] = $g; |
||
211 | } |
||
212 | } |
||
213 | } |
||
214 | } |
||
215 | } |
||
216 | if (\count($entries) > 0) { |
||
217 | foreach ($entries as $i => &$iValue) { |
||
218 | $this->cleanupChars($iValue['title']); |
||
219 | $strip = (bool)$this->modConfig['strip_html']; |
||
220 | $this->cleanupChars($iValue['description'], $strip, false, true); |
||
221 | $this->wrapCdata($iValue['description']); |
||
222 | $entries[$i]['category'] = $this->myts->undoHtmlSpecialChars($iValue['category']); |
||
223 | $this->cleanupChars($iValue['category']); |
||
224 | if (!isset($iValue['timestamp'])) { |
||
225 | $entries[$i]['timestamp'] = $this->rssmod->getVar('last_update'); |
||
226 | } |
||
227 | $entries[$i]['pubdate'] = $this->rssTimeStamp((int)$iValue['timestamp']); |
||
228 | } |
||
229 | unset($iValue); |
||
230 | |||
231 | if (empty($feed['plugin']) && 'd' === $this->modConfig['sort']) { |
||
232 | \uasort($entries, [$this, 'sortTimestamp']); |
||
233 | } |
||
234 | if (empty($feed['plugin']) && \count($entries) > $this->modConfig['overall_entries']) { |
||
235 | $entries = \array_slice($entries, 0, $this->modConfig['overall_entries']); |
||
236 | } |
||
237 | } |
||
238 | |||
239 | $feed['items'] = &$entries; |
||
240 | } |
||
241 | |||
242 | public function doSubstr(string $text): string |
||
243 | { |
||
244 | $ret = $text; |
||
245 | $len = \function_exists('mb_strlen') ? mb_strlen($ret, $this->charset) : mb_strlen($ret); |
||
246 | $maxChars = $this->helper->getConfig('max_char'); |
||
247 | if ($len > $maxChars && $maxChars > 0) { |
||
248 | $ret = $this->substrDetect($ret, 0, $maxChars - 1); |
||
249 | if (false === $this->strrposDetect($ret, ' ')) { |
||
250 | if (false !== $this->strrposDetect($text, ' ')) { |
||
251 | $ret = $this->substrDetect($text, 0, (int)mb_strpos($text, ' ')); |
||
252 | } |
||
253 | } |
||
254 | if (\in_array($this->substrDetect($text, $maxChars - 1, 1), $this->substrAdd)) { |
||
255 | $ret .= $this->substrDetect($text, $maxChars - 1, 1); |
||
256 | } else { |
||
257 | if (false !== $this->strrposDetect($ret, ' ')) { |
||
258 | $ret = $this->substrDetect($ret, 0, $this->strrposDetect($ret, ' ')); |
||
259 | } |
||
260 | if (\in_array($this->substrDetect($ret, -1, 1), $this->substrRemove)) { |
||
261 | $ret = $this->substrDetect($ret, 0, -1); |
||
262 | } |
||
263 | } |
||
264 | $ret .= $this->substrEndwith; |
||
265 | } |
||
266 | |||
267 | return $ret; |
||
268 | } |
||
269 | |||
270 | public function substrDetect(string $text, int $start, int $len): string |
||
271 | { |
||
272 | if (\function_exists('mb_strcut')) { |
||
273 | return mb_strcut($text, $start, $len, _CHARSET); |
||
274 | } |
||
275 | |||
276 | return mb_substr($text, $start, $len); |
||
277 | } |
||
278 | |||
279 | /** |
||
280 | * @return false|int |
||
281 | */ |
||
282 | public function strrposDetect(string $text, string $find) |
||
283 | { |
||
284 | if (\function_exists('mb_strrpos')) { |
||
285 | return mb_strrpos($text, $find, 0, _CHARSET); |
||
286 | } |
||
287 | |||
288 | return mb_strrpos($text, $find); |
||
289 | } |
||
290 | |||
291 | public function rssTimeStamp(int $time): ?string |
||
292 | { |
||
293 | return \date('D, j M Y H:i:s O', $time); |
||
294 | } |
||
295 | |||
296 | public function sortTimestamp(array $a, array $b): int |
||
297 | { |
||
298 | if ($a['timestamp'] === $b['timestamp']) { |
||
299 | return 0; |
||
300 | } |
||
301 | |||
302 | return ($a['timestamp'] > $b['timestamp']) ? -1 : 1; |
||
303 | } |
||
304 | |||
305 | public function cleanupChars(string &$text, bool $strip = true, bool $dospec = true, bool $dosub = false): void |
||
306 | { |
||
307 | if ($strip) { |
||
308 | $text = \strip_tags($text); |
||
309 | } |
||
310 | if ($dosub) { |
||
311 | $text = $this->doSubstr($text); |
||
312 | } |
||
313 | if ($dospec) { |
||
314 | $text = \htmlspecialchars($text, \ENT_QUOTES, $this->charset); |
||
315 | $text = \preg_replace('/&(#\d+);/i', '&$1;', $text); |
||
316 | } |
||
317 | if (XOOPS_USE_MULTIBYTES !== 1 || false === stripos($this->charset, "utf-8")) { |
||
318 | $text = \str_replace(\array_map('\chr', \array_keys($this->escaped)), $this->escaped, $text); |
||
319 | } |
||
320 | } |
||
321 | |||
322 | public function wrapCdata(string &$text): void |
||
323 | { |
||
324 | $text = '<![CDATA[' . \str_replace(['<![CDATA[', ']]>'], ['<![CDATA[', ']]>'], $text) . ']]>'; |
||
325 | } |
||
326 | |||
327 | public function &getActivatedSubfeeds(string $fields = '', string $type = ''): ?array |
||
328 | { |
||
329 | $ret = null; |
||
330 | $subs = $this->pluginHandler->getObjects2(new \Criteria('subfeed', '1'), $fields); |
||
331 | if (\is_array($subs) && !empty($subs)) { |
||
332 | $ret = []; |
||
333 | switch ($type) { |
||
334 | default: |
||
335 | $ret = &$subs; |
||
336 | break; |
||
337 | case 'list': |
||
338 | foreach ($subs as $s) { |
||
339 | $ret[$s->getVar('rssf_conf_id')] = $s->getVar('sub_title'); |
||
340 | } |
||
341 | break; |
||
342 | } |
||
343 | } |
||
344 | |||
345 | return $ret; |
||
346 | } |
||
347 | |||
348 | /** |
||
349 | * @param null|string|array $selected |
||
350 | */ |
||
351 | public function feedSelectBox(string $caption = '', $selected = null, int $size = 1, bool $multi = true, bool $none = true, bool $main = true, string $name = 'feeds', string $type = 'id'): \XoopsFormSelect |
||
0 ignored issues
–
show
|
|||
352 | { |
||
353 | $select = new \XoopsFormSelect($caption, $name, $selected, $size, $multi); |
||
354 | if ($none) { |
||
355 | $select->addOption('0', '-------'); |
||
356 | } |
||
357 | if ($main) { |
||
358 | $select->addOption('-1', \_AM_RSSFIT_MAINFEED); |
||
359 | } |
||
360 | $subs = $this->getActivatedSubfeeds('sublist', 'list'); |
||
361 | if ($subs) { |
||
362 | foreach ($subs as $k => $v) { |
||
363 | $select->addOption($k, $v); |
||
364 | } |
||
365 | } |
||
366 | |||
367 | return $select; |
||
368 | } |
||
369 | |||
370 | /** |
||
371 | * @return string |
||
372 | */ |
||
373 | public function specUrl(string $key = '0'): ?string |
||
374 | { |
||
375 | if (isset($this->specs[$key])) { |
||
376 | return $this->specUrl . '#' . $this->specs[$key]; |
||
377 | } |
||
378 | |||
379 | return null; |
||
380 | } |
||
381 | |||
382 | /** |
||
383 | * @return string |
||
384 | */ |
||
385 | public function subFeedUrl(string $filename = ''): ?string |
||
386 | { |
||
387 | if (!empty($filename)) { |
||
388 | $filename = \str_replace(['rssfit.', '.php'], '', $filename); |
||
389 | |||
390 | return \RSSFIT_URL_FEED . '?' . $this->feedkey . '=' . $filename; |
||
391 | } |
||
392 | |||
393 | return null; |
||
394 | } |
||
395 | |||
396 | public function checkSubFeed(array &$feed): void |
||
397 | { |
||
398 | if (!empty($feed['plugin'])) { |
||
399 | $criteria = new \CriteriaCompo(); |
||
400 | $criteria->add(new \Criteria('rssf_filename', \sprintf($this->pluginFile, $feed['plugin']))); |
||
401 | $criteria->add(new \Criteria('subfeed', '1')); |
||
402 | $sub = $this->pluginHandler->getObjects2($criteria); |
||
403 | $handler = null; |
||
404 | if (isset($sub[0])) { |
||
405 | $handler = $this->pluginHandler->checkPlugin($sub[0]); |
||
406 | } |
||
407 | if ($handler) { |
||
408 | $this->pluginObject = $sub[0]; |
||
409 | $this->subHandler = $handler; |
||
410 | $this->cached = 'mod_' . $this->rssmod->getVar('dirname') . '|' . \md5(\str_replace(XOOPS_URL, '', $GLOBALS['xoopsRequestUri'])); |
||
411 | } else { |
||
412 | $feed['plugin'] = ''; |
||
413 | } |
||
414 | } |
||
415 | } |
||
416 | |||
417 | public function buildFeed(array &$feed): void |
||
418 | { |
||
419 | $this->getChannel($feed); |
||
420 | $this->getItems($feed); |
||
421 | $this->getSticky($feed); |
||
422 | } |
||
423 | } |
||
424 |
This check looks for parameters that have been defined for a function or method, but which are not used in the method body.