PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.6.7
VikBooking Hotel Booking Engine & PMS v1.6.7
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
vikbooking / libraries / adapter / application / route.php

route.php in VikBooking Hotel Booking Engine & PMS 1.6.7, at libraries/adapter/application/route.php

455 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.application
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 /**
15 * Route adapter class.
16 *
17 * @since 10.0
18 */
19 class JRoute
20 {
21 /**
22 * A list of component shortcodes.
23 *
24 * @var array
25 */
26 protected static $shortcodes = array();
27
28 /**
29 * Translates an internal URL to a human-readable URL.
30 *
31 * @param string $url Absolute or Relative URI.
32 * @param boolean $xhtml Replace & by &amp; for XML compliance.
33 * @param integer $ssl Secure state for the resolved URI.
34 * 0: (default) No change, use the protocol currently used in the request.
35 * 1: Make URI secure using global secure site URI.
36 * 2: Make URI unsecure using the global unsecure site URI.
37 *
38 * @return string The translated humanly readable URL.
39 *
40 * @uses getPermalink()
41 * @uses replace()
42 */
43 public static function _($url, $xhtml = true, $ssl = null)
44 {
45 // parse URL to obtain query args (true: as array)
46 $args = JUri::getInstance($url)->getQuery(true);
47
48 // prepend current URI if starts with 'index.php'
49 if (strpos($url, 'index.php') === 0)
50 {
51 $url = static::getPermalink();
52 $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($args);
53 }
54
55 // if 'option' and 'view' arguments are not empty, try to route URLs
56 if (!empty($args['option']) && (!empty($args['view']) || !empty($args['Itemid'])))
57 {
58 $url = static::replace($args, $url);
59 }
60
61 /**
62 * Prepend base URL in case the system
63 * was not able to find a permalink.
64 *
65 * @since 10.1.29
66 */
67 if (preg_match("/^\?/", $url))
68 {
69 $url = JUri::root() . $url;
70 }
71
72 // replace & with &amp; for XML compliance
73 if ($xhtml)
74 {
75 $url = str_replace('&', '&amp;', $url);
76 }
77
78 if ($ssl == 1)
79 {
80 // force HTTPS
81 $url = str_replace('http://', 'https://', $url);
82 }
83 else if ($ssl == 2)
84 {
85 // force HTTP
86 $url = str_replace('https://', 'http://', $url);
87 }
88
89 return $url;
90 }
91
92 /**
93 * Proxy for underscore method.
94 * Needed to bypass the issue reported here:
95 * @link https://meta.trac.wordpress.org/ticket/3601
96 *
97 * @since 10.1.32 Renamed from `u`.
98 */
99 public static function rewrite($url, $xhtml = true, $ssl = null)
100 {
101 return static::_($url, $xhtml, $ssl);
102 }
103
104 /**
105 * Replaces the plain URL with the rewritten one.
106 *
107 * @param array $args The URL parts.
108 * @param string $url The URL to rewrite.
109 *
110 * @return string The rewritten URL, if possible.
111 *
112 * @uses getPermalink()
113 * @uses matchShortcode()
114 * @uses withQueryString()
115 */
116 protected static function replace(array $args, $url)
117 {
118 // make safe by replacing initial 'com_' (if any)
119 $option = preg_replace("/^com_/", "", $args['option']);
120 unset($args['option']);
121
122 // check if the shortcodes have been already cached
123 if (!isset(static::$shortcodes[$option]))
124 {
125 // get model to access shortcodes
126 $model = JModel::getInstance($option, 'shortcodes', 'admin');
127
128 /**
129 * Make sure the model exists for the requested option.
130 *
131 * @since 10.1.19
132 */
133 if ($model)
134 {
135 // cache the component shortcodes
136 static::$shortcodes[$option] = $model->all();
137 }
138 else
139 {
140 // create an empty list
141 static::$shortcodes[$option] = array();
142 }
143 }
144
145 $post_id = false;
146
147 if (!empty($args['view']))
148 {
149 // try to rewrite the URL with a matching shortcode
150 $post_id = static::matchShortcode(static::$shortcodes[$option], $args);
151 }
152
153 if (!$post_id && !empty($args['Itemid']))
154 {
155 // if the Itemid is set, get the POST permalink directly
156 $post_id = (int) $args['Itemid'];
157 }
158
159 if ($post_id)
160 {
161 $url = static::getPermalink($post_id);
162 $url = static::withQueryString($url, $post_id, static::$shortcodes[$option], $args);
163 }
164
165 /**
166 * Try to instantiate an external router.
167 *
168 * @since 10.1.19
169 */
170 $router = JFactory::getApplication()->getRouter($option);
171
172 if ($router)
173 {
174 // route URL using the specified arguments
175 $url = $router->build($url);
176 }
177
178 return $url;
179 }
180
181 /**
182 * Wrapper method to extend the function used to obtain
183 * the current permalink or the post link.
184 *
185 * @param mixed $post_id The post ID. Null to obtain the current link.
186 *
187 * @return string The permalink.
188 */
189 protected static function getPermalink($post_id = null)
190 {
191 // if the post ID is set, get the permalink directly
192 if ($post_id)
193 {
194 return get_permalink($post_id);
195 }
196
197 // otherwise get the current permalink
198 $link = get_permalink();
199
200 // return the permalink only if it is not empty
201 if ($link)
202 {
203 return $link;
204 }
205
206 // obtain the post ID from the current URL
207 $post_id = url_to_postid(JUri::current());
208
209 // if the current URL doesn't match any post, return an empty string
210 if (!$post_id)
211 {
212 return '';
213 }
214
215 // recursive call to obtain the permalink of the post found
216 return static::getPermalink($post_id);
217 }
218
219 /**
220 * Returns a URL containing the specified query string.
221 *
222 * @param string $url The URL to which append the query string.
223 * @param integer $post_id The post ID.
224 * @param array $shortcodes The shortcodes list.
225 * @param array $args The args to build the query string.
226 *
227 * @return string The URL with the query string.
228 */
229 protected static function withQueryString($url, $post_id, array $shortcodes, array $args = array())
230 {
231 // unset always the Item ID
232 unset($args['Itemid']);
233
234 // iterate the shortcodes
235 foreach ($shortcodes as $shortcode)
236 {
237 // process only if the given post ID matches the one assigned to the shortcode
238 if ($post_id == $shortcode->post_id)
239 {
240 // get shortcodes parameters, view and language
241 $json = (array) json_decode($shortcode->json, true);
242 $json['view'] = $shortcode->type;
243 $json['lang'] = $shortcode->lang;
244
245 // get the keys that the shortcode doesn't contain
246 $diff = self::diff($args, $json);
247
248 // if there are differences between the args, append them to the URL
249 if (count($diff))
250 {
251 $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($diff);
252 }
253
254 // return the URL with the query string (do not proceed)
255 return $url;
256 }
257 }
258
259 if (count($args))
260 {
261 /**
262 * if no shortcodes found, attach the whole query string
263 *
264 * @since 10.1.8
265 */
266 $url .= (strpos($url, '?') !== false ? '&' : '?') . http_build_query($args);
267 }
268
269 // nothing found, return plain URL
270 return $url;
271 }
272
273 /**
274 * Checks if there is a shortcode object that matches the given URL parts.
275 * In addition, the shortcode MUST own an existing post ID.
276 *
277 * @param array $shortcodes The shortcode objects list.
278 * @param array $args The URL query parts.
279 *
280 * @return mixed The post ID found, false on failure.
281 */
282 protected static function matchShortcode($shortcodes, array $args)
283 {
284 $post_id = false;
285 $last_count = 0;
286
287 if (empty($args['lang']))
288 {
289 // inject current langtag within URL arguments, only if not specified
290 // by query string
291 $args['lang'] = JFactory::getLanguage()->getTag();
292 }
293
294 foreach ($shortcodes as $shortcode)
295 {
296 $count = 0;
297
298 // decode JSON data
299 $json = json_decode($shortcode->json, true);
300 // inject VIEW name
301 $json['view'] = $shortcode->type;
302 // inject shortcode LANGTAG
303 $json['lang'] = $shortcode->lang;
304
305 // proceed only if the view is the same
306 if ($json['view'] == $args['view'])
307 {
308 // iterate the URL arguments
309 foreach ($args as $k => $v)
310 {
311 // the property should be matched only if the shortcode
312 // owns a parameter with the same name (defined in xml view)
313 // and value.
314 if (isset($json[$k]))
315 {
316 /**
317 * Improved the comparison of the language tag, which might be
318 * handled in different ways from different sections of WP.
319 *
320 * @since 10.1.38
321 */
322 if ($k === 'lang')
323 {
324 // check whether at least a language code doesn't mention the country code
325 if (!preg_match("/[_\-]/", $json[$k]) || !preg_match("/[_\-]/", $v))
326 {
327 // remove country code from locale assigned to the shortcode
328 $json[$k] = preg_split("/[_\-]/", $json[$k]);
329 $json[$k] = array_shift($json[$k]);
330
331 // remove country code from URL locale
332 $v = preg_split("/[_\-]/", $v);
333 $v = array_shift($v);
334 }
335
336 // normalize locale separators
337 $json[$k] = str_replace('-', '_', $json[$k]);
338 $v = str_replace('-', '_', $v);
339 }
340
341 // make sure both the values are scalar
342 if (is_scalar($json[$k]) && is_scalar($v))
343 {
344 if (!strcmp($json[$k], $v))
345 {
346 // if the shortcode owns the parameter and it is equals
347 // to the one specified in the URL, increase the counter
348 $count++;
349 }
350 }
351 /**
352 * Added support for arrays in query string, such as cid[].
353 *
354 * @since 10.1.27
355 */
356 else
357 {
358 // treat both the arguments as arrays
359 $json[$k] = (array) $json[$k];
360 $v = (array) $v;
361
362 // sort them to maximize the possibility of having matching URLs
363 sort($json[$k]);
364 sort($v);
365
366 if ($json[$k] == $v)
367 {
368 // increase the counter as we have a matching parameter
369 $count++;
370 }
371 }
372 }
373 }
374
375 // if the count of matches is higher than the last one,
376 // update the flags with the shortcode post ID and the current count
377 if ($count > $last_count)
378 {
379 $post_id = $shortcode->post_id;
380 $last_count = $count;
381 }
382 }
383 }
384
385 return $post_id;
386 }
387
388 /**
389 * Implementation of array_diff_assoc with recursion.
390 *
391 * @param array array1 The array to compare from.
392 * @param array array2 An array to compare against.
393 *
394 * @return array Returns an array containing all the values from array1
395 * that are not present in the second array.
396 *
397 * @since 10.1.27
398 */
399 private static function diff($array1, $array2)
400 {
401 $difference = array();
402
403 foreach ($array1 as $key => $value)
404 {
405 /**
406 * Improved the comparison of the language tag, which might be
407 * handled in different ways from different sections of WP.
408 *
409 * @since 10.1.49
410 */
411 if ($key === 'lang')
412 {
413 // check whether at least a language code doesn't mention the country code
414 if (!preg_match("/[_\-]/", $value) || !preg_match("/[_\-]/", $array2[$key]))
415 {
416 // remove country code from locale assigned to the shortcode
417 $array2[$key] = preg_split("/[_\-]/", $array2[$key]);
418 $array2[$key] = array_shift($array2[$key]);
419
420 // remove country code from URL locale
421 $value = preg_split("/[_\-]/", $value);
422 $value = array_shift($value);
423 }
424
425 // normalize locale separators
426 $array2[$key] = str_replace('-', '_', $array2[$key]);
427 $value = str_replace('-', '_', $value);
428 }
429
430 if (is_array($value))
431 {
432 if (!isset($array2[$key]) || !is_array($array2[$key]))
433 {
434 $difference[$key] = $value;
435 }
436 else
437 {
438 $new_diff = self::diff($value, $array2[$key]);
439
440 if (!empty($new_diff))
441 {
442 $difference[$key] = $new_diff;
443 }
444 }
445 }
446 else if (!array_key_exists($key, $array2) || $array2[$key] !== $value)
447 {
448 $difference[$key] = $value;
449 }
450 }
451
452 return $difference;
453 }
454 }
455