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/application/application.php +810 -0 1.6.2 → 1.8.16 View file →
@@ -1,0 +1,810 @@
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 + * This adapter is required to wrap common wordpress functions
16 + * within the CMSApplication Joomla interface.
17 + * This is helpful to improve the portability between Joomla and Wordpress.
18 + *
19 + * @since 10.0
20 + */
21 +class JApplication
22 +{
23 + /**
24 + * Input handler for REQUEST manipulation.
25 + *
26 + * @var JInput
27 + */
28 + private $input = null;
29 +
30 + /**
31 + * The application client name.
32 + *
33 + * @var string
34 + */
35 + private $name = null;
36 +
37 + /**
38 + * Flag to check if the redirect is going to be made via javascript.
39 + *
40 + * @var boolean
41 + */
42 + private $jsRedirect = false;
43 +
44 + /**
45 + * The HTTP header status code.
46 + *
47 + * @var integer
48 + * @since 10.1.40
49 + */
50 + private $status = null;
51 +
52 + /**
53 + * Class constructor.
54 + *
55 + * @param JInput $input The input handler.
56 + */
57 + public function __construct($input = null)
58 + {
59 + // setup application input
60 + if (is_null($input))
61 + {
62 + $this->input = new JInput;
63 + }
64 + else
65 + {
66 + $this->input = $input;
67 + }
68 +
69 + // get current page
70 + global $pagenow;
71 +
72 + if (!$pagenow)
73 + {
74 + /**
75 + * Current page not yet registered, we are probably under a multi-site,
76 + * because the plugins_loaded hook may run before loading vars.php file.
77 + *
78 + * For this reason, we should auto-fill this global variable in advance
79 + * by ourselves, simply by checking whether the request URL ends with
80 + * admin-ajax.php
81 + *
82 + * @since 10.1.33
83 + */
84 + $self = $this->input->server->getString('PHP_SELF');
85 +
86 + if (preg_match("/\/admin-ajax\.php$/i", $self))
87 + {
88 + // we reached the admin-ajax.php file, flag it
89 + $pagenow = 'admin-ajax.php';
90 + }
91 + }
92 +
93 + /**
94 + * Set application client according to the side we
95 + * are located. In case of AJAX end-point, we should
96 + * fetch the client according to a reserved key
97 + * that should be set in request.
98 + *
99 + * @since 10.1.31
100 + */
101 + if ($pagenow !== 'admin-ajax.php')
102 + {
103 + // rely on the location of the file
104 + $this->name = is_admin() && $pagenow != 'admin-post.php' ? 'administrator' : 'site';
105 + }
106 + else
107 + {
108 + // rely on the AJAX reserved key
109 + $this->name = $this->input->get('vik_ajax_client', 'administrator');
110 + }
111 + }
112 +
113 + /**
114 + * Magic method to access private properties.
115 + *
116 + * @param string $name The property to access.
117 + *
118 + * @return mixed The property.
119 + */
120 + public function __get($name)
121 + {
122 + if ($name == 'input')
123 + {
124 + return $this->input;
125 + }
126 +
127 + return null;
128 + }
129 +
130 + /**
131 + * Returns a property of the object or the default value if the property is not set.
132 + *
133 + * @param string $key The name of the property.
134 + * @param mixed $def The default value (optional) if none is set.
135 + *
136 + * @return mixed The value of the configuration.
137 + */
138 + public function get($key, $def = null)
139 + {
140 + /**
141 + * The configuration is now parsed within a separated object.
142 + *
143 + * @see JConfig
144 + * @since 10.1.4
145 + */
146 + return JFactory::getConfig()->get($key, $def);
147 + }
148 +
149 + /**
150 + * Returns a property of the object or the default value if the property is not set.
151 + *
152 + * @uses get()
153 + */
154 + public function getCfg($key, $def = null)
155 + {
156 + return $this->get($key, $def);
157 + }
158 +
159 + /**
160 + * Modifies a property of the object, creating it if it does not already exist.
161 + *
162 + * @param string $key The name of the property.
163 + * @param mixed $val The value of the property to set (optional).
164 + * @param mixed $network An optional flag to check whether the option
165 + * should be updated for the current blog or for
166 + * a different one (@since 10.1.31).
167 + * - false only the current blog will be updated;
168 + * - true all the network blogs will be updated;
169 + * - int only the specified blog will be updated.
170 + *
171 + * @return mixed Previous value of the property.
172 + *
173 + * @uses get()
174 + */
175 + public function set($key, $val = null, $network = false)
176 + {
177 + $prev = $this->get($key);
178 +
179 + if ($network === false || !is_multisite())
180 + {
181 + // use default function
182 + update_option($key, $val);
183 + }
184 + else
185 + {
186 + if ($network === true)
187 + {
188 + // get all network sites
189 + $sites = array_map(function($site)
190 + {
191 + // take only the blog ID
192 + return $site->blog_id;
193 + }, get_sites());
194 + }
195 + else
196 + {
197 + // create a list with the specified blog ID
198 + $sites = array((int) $network);
199 + }
200 +
201 + // update all existing networks
202 + foreach ($sites as $blog_id)
203 + {
204 + // switch to blog
205 + switch_to_blog($blog_id);
206 +
207 + // update network option
208 + update_option($key, $val);
209 +
210 + // restore previous blog
211 + restore_current_blog();
212 + }
213 + }
214 +
215 + return $prev;
216 + }
217 +
218 + /**
219 + * Is admin interface?
220 + *
221 + * @return boolean True if this application is administrator.
222 + *
223 + * @uses isClient()
224 + */
225 + public function isAdmin()
226 + {
227 + return $this->isClient('administrator');
228 + }
229 +
230 + /**
231 + * Is site interface?
232 + *
233 + * @return boolean True if this application is site.
234 + *
235 + * @uses isClient()
236 + */
237 + public function isSite()
238 + {
239 + return $this->isClient('site');
240 + }
241 +
242 + /**
243 + * Check the client interface by name.
244 + *
245 + * @param string $identifier String identifier for the application interface.
246 + *
247 + * @return boolean True if this application is of the given type client interface.
248 + */
249 + public function isClient($identifier)
250 + {
251 + return $this->name === $identifier;
252 + }
253 +
254 + /**
255 + * Forces the application to run under the specified client.
256 + *
257 + * @param string $identifier String identifier for the application interface.
258 + *
259 + * @return void
260 + *
261 + * @since 10.1.39
262 + */
263 + public function setClient($identifier)
264 + {
265 + $this->name = $identifier;
266 + }
267 +
268 + /**
269 + * Gets a user state.
270 + *
271 + * @param string $key The key of the user state.
272 + * @param mixed $default The default value for the state if not found.
273 + *
274 + * @return mixed The user state.
275 + *
276 + * @since 10.1.15
277 + */
278 + public function getUserState($key, $default = null)
279 + {
280 + $session = JFactory::getSession();
281 +
282 + // extract user state from session
283 + return $session->get($key, $default, 'jsession.userstate');
284 + }
285 +
286 + /**
287 + * Sets the value of a user state variable.
288 + *
289 + * @param string $key The key of the user state.
290 + * @param mixed $value The value of the variable.
291 + *
292 + * @return mixed The previous state, if one existed.
293 + *
294 + * @since 10.1.15
295 + */
296 + public function setUserState($key, $value)
297 + {
298 + // get previous state, if any
299 + $old = $this->getUserState($key);
300 +
301 + $session = JFactory::getSession();
302 +
303 + // update session with specified state
304 + $session->set($key, $value, 'jsession.userstate');
305 +
306 + // return previous state
307 + return $old;
308 + }
309 +
310 + /**
311 + * Gets the value of a user state variable.
312 + *
313 + * @param string $key The key of the user state variable.
314 + * @param string $request The name of the variable passed in a request.
315 + * @param mixed $default The default value for the variable if not found.
316 + * @param string $type Filter for the variable.
317 + *
318 + * @return mixed The request user state.
319 + *
320 + * @uses getUserState()
321 + * @uses setUserState()
322 + */
323 + public function getUserStateFromRequest($key, $request, $default = null, $type = 'none')
324 + {
325 + // try to get value from the request
326 + $val = $this->input->get($request, null, $type);
327 +
328 + if (!is_null($val))
329 + {
330 + // the value exists, register the user state for later use and return it
331 + $this->setUserState($key, $val);
332 +
333 + return $val;
334 + }
335 +
336 + // Otherwise try to access the current user state.
337 + // Returns default value if user state was not previously set.
338 + return $this->getUserState($key, $default);
339 + }
340 +
341 + /**
342 + * Enqueue a system message.
343 + *
344 + * @param string $msg The message to enqueue.
345 + * @param string $type The message type (success, notice, warning or error).
346 + *
347 + * @return void
348 + */
349 + public function enqueueMessage($msg, $type = 'success')
350 + {
351 + $session = JFactory::getSession();
352 +
353 + // use a different namespace for each application client
354 + $namespace = 'jsession.' . $this->name . '.system';
355 +
356 + // create system message object
357 + $obj = new stdClass;
358 + $obj->message = $msg;
359 + $obj->type = $type;
360 +
361 + // get queue from the session (an empty array if not set)
362 + $queue = $session->get('messagesqueue', array(), $namespace);
363 +
364 + // push the object only if it is not already in the queue
365 + if (!in_array($obj, $queue))
366 + {
367 + $queue[] = $obj;
368 + $session->set('messagesqueue', $queue, $namespace);
369 + }
370 + }
371 +
372 + /**
373 + * Returns the queue containing the system messages.
374 + *
375 + * @return array The messages list.
376 + */
377 + public function getMessagesQueue()
378 + {
379 + $session = JFactory::getSession();
380 +
381 + // use a different namespace for each application client
382 + $namespace = 'jsession.' . $this->name . '.system';
383 +
384 + // get queue from the session (an empty array if not set)
385 + $queue = $session->get('messagesqueue', array(), $namespace);
386 +
387 + // flush the system queue to avoid displaying duplicated messages
388 + $session->clear('messagesqueue', $namespace);
389 +
390 + return $queue;
391 + }
392 +
393 + /**
394 + * Returns the application JMenu object.
395 + *
396 + * @param string $name The name of the application/client.
397 + * @param array $options An optional associative array of configuration settings.
398 + *
399 + * @return JMenu|null
400 + *
401 + * @since 10.1.19
402 + */
403 + public function getMenu($name = null, array $options = array())
404 + {
405 + if (!isset($name))
406 + {
407 + $name = $this->name;
408 + }
409 +
410 + // inject this application object into the JMenu tree if one isn't already specified
411 + if (!isset($options['app']))
412 + {
413 + $options['app'] = $this;
414 + }
415 +
416 + try
417 + {
418 + // load JMenu file
419 + JLoader::import('adapter.menu.menu');
420 +
421 + // try to obtain a valid menu instance
422 + $menu = JMenu::getInstance($name, $options);
423 + }
424 + catch (Exception $e)
425 + {
426 + return null;
427 + }
428 +
429 + return $menu;
430 + }
431 +
432 + /**
433 + * Returns the application JPathway object.
434 + *
435 + * @param string $name The name of the application.
436 + * @param array $options An optional associative array of configuration settings.
437 + *
438 + * @return JPathway|null
439 + *
440 + * @since 10.1.19
441 + */
442 + public function getPathway($name = null, $options = array())
443 + {
444 + if (!isset($name))
445 + {
446 + $name = $this->name;
447 + }
448 +
449 + try
450 + {
451 + // load JPathway file
452 + JLoader::import('adapter.pathway.pathway');
453 +
454 + // try to obtain a valid pathway
455 + $pathway = JPathway::getInstance($name, $options);
456 + }
457 + catch (Exception $e)
458 + {
459 + return null;
460 + }
461 +
462 + return $pathway;
463 + }
464 +
465 + /**
466 + * Returns the application JRouter object.
467 + *
468 + * @param string $name The name of the application.
469 + * @param array $options An optional associative array of configuration settings.
470 + *
471 + * @return JRouter A JRouter object.
472 + *
473 + * @throws Exception
474 + *
475 + * @since 10.1.19
476 + */
477 + public function getRouter($name = null, array $options = array())
478 + {
479 + try
480 + {
481 + // load JRouter file
482 + JLoader::import('adapter.router.router');
483 +
484 + // try to obtain a valid router, if any
485 + $router = JRouter::getInstance($name ?: 'site', $options);
486 + }
487 + catch (Exception $e)
488 + {
489 + return null;
490 + }
491 +
492 + return $router;
493 + }
494 +
495 + /**
496 + * Registers a handler to a particular event group.
497 + *
498 + * @param string $event The event name.
499 + * @param callable $handler The handler, a function or an instance of an event object.
500 + *
501 + * @return self This object to support chaining.
502 + *
503 + * @since 10.1.30
504 + */
505 + public function registerEvent($event, $handler)
506 + {
507 + // proxy for JEventDispatcher
508 + return JEventDispatcher::getInstance()->register($event, $handler);
509 + }
510 +
511 + /**
512 + * Calls all handlers associated with an event group.
513 + *
514 + * @param string $event The event name.
515 + * @param array $args An array of arguments (optional).
516 + *
517 + * @return array An array of results from each function call, or null if no dispatcher is defined.
518 + *
519 + * @since 10.1.30
520 + */
521 + public function triggerEvent($event, ?array $args = null)
522 + {
523 + // proxy for JEventDispatcher
524 + return JEventDispatcher::getInstance()->trigger($event, $args);
525 + }
526 +
527 + /**
528 + * Redirect to another URL.
529 + *
530 + * If the headers have not been sent the redirect will be accomplished using a "301 Moved Permanently"
531 + * or "303 See Other" code in the header pointing to the new location. If the headers have already been
532 + * sent this will be accomplished using a JavaScript statement.
533 + *
534 + * @param string $url The URL to redirect to. Can only be http/https URL.
535 + * @param integer $status The HTTP 1.1 status code to be provided. 303 is assumed by default.
536 + *
537 + * @return void
538 + *
539 + * @uses shouldRedirect()
540 + *
541 + * @link https://developer.wordpress.org/reference/functions/wp_redirect/
542 + */
543 + public function redirect($url, $status = 303)
544 + {
545 + if ($this->isAdmin())
546 + {
547 + // if the URL starts with index.php, replace it into admin.php
548 + if (strpos($url, 'index.php?') === 0)
549 + {
550 + $url = str_replace('index.php?', 'admin.php?', $url);
551 + }
552 + // else if the URL starts with ?, prepend admin.php
553 + else if (strpos($url, '?') === 0)
554 + {
555 + $url = 'admin.php' . $url;
556 + }
557 +
558 + // change end-point in case we are doing AJAX
559 + if (wp_doing_ajax())
560 + {
561 + /**
562 + * @note this is not really used for AJAX calls,
563 + * but for redirects between "iframe" pages
564 + * (contents rendered via AJAX in modal boxes).
565 + */
566 + $url = str_replace('admin.php', 'admin-ajax.php', $url);
567 + }
568 + }
569 + else
570 + {
571 + // if the URL is "index.php", we probably need to visit the home page
572 + if ($url == 'index.php')
573 + {
574 + $url = JUri::root();
575 + }
576 +
577 + // we don't need to route URLs that start with "index.php" because
578 + // we are (probably) already under a rewritten page and this means
579 + // that the plugin is going to be processed correctly.
580 + }
581 +
582 + // redirect is allowed only if the headers haven't been sent yet
583 + if (!headers_sent())
584 + {
585 + wp_redirect($url, $status);
586 + exit;
587 + }
588 +
589 + // JS redirect only once
590 + if (!$this->shouldRedirect())
591 + {
592 + // register JS redirect
593 + $this->jsRedirect = true;
594 +
595 + // otherwise redirect using javascript
596 + echo "<script>document.location.href='" . str_replace("'", '&apos;', $url) . "';</script>\n";
597 + }
598 + }
599 +
600 + /**
601 + * Checks if the application is going to do a JS redirect.
602 + * The javascript redirect is applied when the headers have been already sent.
603 + *
604 + * @return boolean True if JS redirect, otherwise false.
605 + */
606 + public function shouldRedirect()
607 + {
608 + return $this->jsRedirect;
609 + }
610 +
611 + /**
612 + * Login authentication function.
613 + *
614 + * @param array $credentials Array('username' => string, 'password' => string)
615 + * @param array $options Array('remember' => boolean)
616 + *
617 + * @return boolean True on success, false if failed.
618 + */
619 + public function login($credentials, $options = array())
620 + {
621 + $login = array();
622 + $login['user_login'] = $credentials['username'];
623 + $login['user_password'] = $credentials['password'];
624 + $login['remember'] = isset($options['remember']) ? $options['remember'] : false;
625 +
626 + $options['redirect'] = isset($options['redirect']) ? $options['redirect'] : '';
627 +
628 + // direct login only if the headers haven't been sent
629 + if (!headers_sent())
630 + {
631 + $res = wp_signon($login);
632 +
633 + return $res instanceof WP_User;
634 + }
635 + // otherwise use <form> workaround to dispatch wp-login.php
636 + else
637 + {
638 + $url = wp_login_url($options['redirect']);
639 + $url .= (strpos($url, '?') !== false ? '&' : '?') . 'action=login';
640 +
641 + ?>
642 +
643 + <form action="<?php echo $url; ?>" method="post" name="loginform" id="loginform">
644 + <input type="hidden" name="log" value="<?php echo $login['user_login']; ?>" />
645 + <input type="hidden" name="pwd" value="<?php echo $login['user_password']; ?>" />
646 + <input type="hidden" name="rememberme" value="<?php echo $login['remember'] ? '1' : ''; ?>" />
647 + </form>
648 +
649 + <script>
650 + document.loginform.submit();
651 + </script>
652 +
653 + <?php
654 + }
655 + }
656 +
657 + /**
658 + * Log the current user out, by destroying the current user session.
659 + * It takes a non-used parameter for compatibility with other CMS.
660 + *
661 + * @param int $uid the id of the current user logged in
662 + *
663 + * @return void
664 + *
665 + * @since 10.1.5
666 + */
667 + public function logout($uid)
668 + {
669 + wp_logout();
670 + }
671 +
672 + /**
673 + * Method to close the application.
674 + *
675 + * @param integer $code The exit code (optional; default is 0).
676 + *
677 + * @return void
678 + *
679 + * @since 10.1.33
680 + */
681 + public function close($code = 0)
682 + {
683 + exit($code);
684 + }
685 +
686 + /**
687 + * Method to set a response header. If the replace flag is set then all headers
688 + * with the given name will be replaced by the new one. The headers are stored
689 + * in an internal array to be sent when the site is dispatched to the browser.
690 + *
691 + * @param string $name The name of the header to set.
692 + * @param string $value The value of the header to set.
693 + * @param boolean $replace True to replace any headers with the same name.
694 + *
695 + * @return self This object to support chaining.
696 + *
697 + * @since 10.1.33
698 + */
699 + public function setHeader($name, $value, $replace = false)
700 + {
701 + /**
702 + * We have to treat the status in a slightly different way because WordPress is unable
703 + * to properly send this header. All the headers registered through the "wp_headers"
704 + * hook are always sent with the "{KEY}: {VALUE}" format, while the status should be
705 + * sent as {PROTOCOL} {CODE} {DESCRIPTION}.
706 + *
707 + * @since 10.1.40
708 + */
709 + if (strtolower($name) === 'status')
710 + {
711 + if (is_null($this->status) || $replace)
712 + {
713 + // update HTTP status
714 + $this->status = (int) $value;
715 + }
716 + }
717 + else
718 + {
719 + // register filter to attach the given header into the WP pool
720 + add_filter('wp_headers', function($headers) use ($name, $value, $replace)
721 + {
722 + if (!isset($headers[$name]) || $replace)
723 + {
724 + // set/replace header with the given value
725 + $headers[$name] = $value;
726 + }
727 +
728 + return $headers;
729 + });
730 + }
731 +
732 + return $this;
733 + }
734 +
735 + /**
736 + * Method to get the array of response headers to be sent when
737 + * the response is dispatched to the client.
738 + *
739 + * @return array
740 + *
741 + * @since 10.1.33
742 + */
743 + public function getHeaders()
744 + {
745 + global $wp;
746 +
747 + $headers = [];
748 +
749 + if (!is_null($this->status))
750 + {
751 + // manually register the status header within the pool
752 + $headers['status'] = $this->status;
753 + }
754 +
755 + /**
756 + * Filters the HTTP headers before they're sent to the browser.
757 + *
758 + * @since 2.8.0
759 + *
760 + * @param string[] $headers Associative array of headers to be sent.
761 + * @param WP $this Current WordPress environment instance.
762 + */
763 + return apply_filters('wp_headers', $headers, $wp);
764 + }
765 +
766 + /**
767 + * Method to clear any set response headers.
768 + *
769 + * @return self This object to support chaining.
770 + *
771 + * @since 10.1.33
772 + */
773 + public function clearHeaders()
774 + {
775 + // remove all the callbacks assigned to this hook
776 + remove_filter('wp_headers');
777 +
778 + // clear the previously registered HTTP status code too
779 + $this->status = null;
780 +
781 + return $this;
782 + }
783 +
784 + /**
785 + * Sends the response headers.
786 + *
787 + * @return self This object to support chaining.
788 + *
789 + * @since 10.1.33
790 + */
791 + public function sendHeaders()
792 + {
793 + global $wp;
794 +
795 + // send headers through WP
796 + $wp->send_headers();
797 +
798 + /**
799 + * In case we have a registered HTTP status code, send this header.
800 + *
801 + * @since 10.1.40
802 + */
803 + if (!is_null($this->status))
804 + {
805 + status_header($this->status);
806 + }
807 +
808 + return $this;
809 + }
810 +}