PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.16
VikBooking Hotel Booking Engine & PMS v1.8.16
1.8.16 1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 All 37 releases
← All changes | libraries/adapter/rss/reader.php +303 -0 1.6.1 → 1.8.16 View file →
@@ -1,0 +1,303 @@
1 +<?php
2 +/**
3 + * @package VikWP - Libraries
4 + * @subpackage adapter.rss
5 + * @author E4J s.r.l.
6 + * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
7 + * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 + * @link https://vikwp.com
9 + */
10 +
11 +// No direct access
12 +defined('ABSPATH') or die('No script kiddies please!');
13 +
14 +JLoader::import('adapter.rss.feed');
15 +JLoader::import('adapter.rss.optinexception');
16 +
17 +/**
18 + * Helper class used to read the RSS feed provided by VikWP.
19 + *
20 + * @since 10.1.31
21 + */
22 +class JRssReader
23 +{
24 + /**
25 + * A list of instances.
26 + *
27 + * @var array
28 + */
29 + protected static $instances = array();
30 +
31 + /**
32 + * A list of feed channels (URL).
33 + *
34 + * @var array
35 + */
36 + protected $channels;
37 +
38 + /**
39 + * The name of the callee;
40 + *
41 + * @var string
42 + */
43 + protected $plugin;
44 +
45 + /**
46 + * Returns the singleton of this class.
47 + *
48 + * @param mixed $url Either the feed URL or an array.
49 + * @param string $plugin The plugin that called this class. If not
50 + * specified, it will be taken from the request.
51 + *
52 + * @return self The instance of this object.
53 + */
54 + public static function getInstance($url, $plugin = null)
55 + {
56 + if (!$plugin)
57 + {
58 + // try to recover plugin name from request if not specified
59 + $plugin = JFactory::getApplication()->input->get('option', 'vikplugin');
60 + }
61 +
62 + // serialize arguments
63 + $sign = serialize(func_get_args());
64 +
65 + // check whether the instance already exists
66 + if (!isset(static::$instances[$sign]))
67 + {
68 + // instantiate only once
69 + static::$instances[$sign] = new static($url, $plugin);
70 + }
71 +
72 + return static::$instances[$sign];
73 + }
74 +
75 + /**
76 + * Class constructor.
77 + *
78 + * @param mixed $url Either the feed URL or an array.
79 + * @param string $plugin The plugin that called this class.
80 + */
81 + protected function __construct($url, $plugin)
82 + {
83 + $this->channels = (array) $url;
84 + $this->plugin = (string) $plugin;
85 + }
86 +
87 + /**
88 + * Choose whether to opt in to the RSS feed services.
89 + *
90 + * @param boolean $status True to opt in, false to the decline.
91 + *
92 + * @return self This object to support chaining.
93 + */
94 + public function optIn($status = true)
95 + {
96 + $user = JFactory::getUser();
97 +
98 + if ($user->guest)
99 + {
100 + // throw exception in case of guest user
101 + throw new Exception('Guest users cannot opt-in to the RSS service', 403);
102 + }
103 +
104 + if ($status)
105 + {
106 + // register opt-in date
107 + $status = JDate::getInstance()->toSql();
108 + }
109 + else
110 + {
111 + // service declined
112 + $status = 0;
113 + }
114 +
115 + // register user choice
116 + update_user_meta($user->id, $this->plugin . '_rss_optin', $status);
117 +
118 + return $this;
119 + }
120 +
121 + /**
122 + * Checks whether the user opted in the RSS feed services.
123 + *
124 + * @param string $date True to return the opt-in date.
125 + *
126 + * @return mixed $status True if opted in, false if declined.
127 + * A JDate instance in case $date is true.
128 + *
129 + * @throws Exception In case the user didn't decide yet.
130 + */
131 + public function optedIn($date = false)
132 + {
133 + $user = JFactory::getUser();
134 +
135 + if ($user->guest)
136 + {
137 + // ignore choice of guest users
138 + return false;
139 + }
140 +
141 + // retrieve user choice
142 + $choice = get_user_meta($user->id, $this->plugin . '_rss_optin', true);
143 +
144 + // make sure a choice was made
145 + if ($choice === false || $choice === '')
146 + {
147 + // missing choice, throw exception
148 + throw new JRssOptInException();
149 + }
150 +
151 + if ($date && $choice)
152 + {
153 + // return opt-in date
154 + return new JDate($choice);
155 + }
156 +
157 + return (bool) $choice;
158 + }
159 +
160 + /**
161 + * Returns a list of RSS permalinks.
162 + *
163 + * @return array
164 + */
165 + public function getChannels()
166 + {
167 + return $this->channels;
168 + }
169 +
170 + /**
171 + * Download a list of feeds from the registered channels.
172 + *
173 + * @param array $options A configuration array.
174 + * - start the starting index to take feeds;
175 + * - limit the number of feeds to take;
176 + * - new true to retrieve only feeds never seen;
177 + * - order the sorting mode (asc or desc).
178 + *
179 + * @return JRssFeed[] An array of feeds.
180 + */
181 + public function download(array $options = array())
182 + {
183 + // get opt-in date
184 + $optinDate = $this->optedIn(true);
185 +
186 + // make sure the user opted in the RSS service
187 + if (!$optinDate)
188 + {
189 + // authorization denied, do not go ahead
190 + throw new Exception('Missing RSS authorization', 403);
191 + }
192 +
193 + $feeds = [];
194 +
195 + /**
196 + * Since WP 6.9 and SimplePie 1.9, multiple channels are no longer accepted.
197 + * We should rather instantiate a single object per feed and then merge them
198 + * together through SimplePie::merge_items().
199 + *
200 + * @since 10.1.67
201 + */
202 + foreach ($this->channels as $channel)
203 + {
204 + // read feed channels
205 + $feed = fetch_feed($channel);
206 +
207 + if ($feed instanceof WP_Error)
208 + {
209 + // get SimplePie error
210 + $error = $feed->get_error_message();
211 +
212 + // extract first element as long as error is an array
213 + while (is_array($error))
214 + {
215 + $error = array_shift($error);
216 + }
217 +
218 + // something went wrong, propagate error
219 + throw new Exception($error, (int) $feed->get_error_code());
220 + }
221 +
222 + $feeds[] = $feed;
223 + }
224 +
225 + $list = array();
226 +
227 + $start = isset($options['start']) ? abs($options['start']) : 0;
228 + $limit = isset($options['limit']) ? abs($options['limit']) : 0;
229 +
230 + // check if we should retrive only the visible feeds
231 + $strict = isset($options['new']) ? (bool) $options['new'] : false;
232 +
233 + // check if we should retrieve the feeds in ascending order
234 + $ordering = isset($options['order']) ? strtolower($options['order']) : 'desc';
235 +
236 + if ($strict || $ordering == 'asc')
237 + {
238 + // take all the items without limits because
239 + // we need to check whether the feeds are visible
240 + // $items = $feed->get_items();
241 + $items = \SimplePie\SimplePie::merge_items($feeds);
242 +
243 + if ($ordering == 'asc')
244 + {
245 + // load items in reverse order from oldest to newest
246 + $items = array_reverse($items);
247 + }
248 + }
249 + else
250 + {
251 + // take the feeds according to the specified limits
252 + // $items = $feed->get_items($start, $limit);
253 + $items = \SimplePie\SimplePie::merge_items($feeds, $start, $limit);
254 + }
255 +
256 + // iterate multi-feed property to scan all the supported feeds
257 + foreach ($items as $data)
258 + {
259 + try
260 + {
261 + // encapsulate feed data
262 + $feed = new JRssFeed($data, $this->plugin);
263 +
264 + // check if we should take only visible feeds
265 + if (!$strict || ($feed->isVisible() && $optinDate < $feed->date))
266 + {
267 + // take feed
268 + $list[] = $feed;
269 + }
270 + }
271 + catch (Throwable $error)
272 + {
273 + // an error has occurred while trying to initialize the feed
274 + continue;
275 + }
276 + }
277 +
278 + if ($strict)
279 + {
280 + // prepare base arguments for array_splice
281 + $args = array(&$list, $start);
282 +
283 + if ($limit)
284 + {
285 + // consider limit only if specified, because
286 + // array_splice take care of the number of
287 + // arguments instead of on their values
288 + $args[] = $limit;
289 + }
290 +
291 + // take only the feeds inside the specified range
292 + $list = call_user_func_array('array_splice', $args);
293 + }
294 +
295 + if ($limit == 1)
296 + {
297 + // take directly the first element
298 + return array_shift($list);
299 + }
300 +
301 + return $list;
302 + }
303 +}