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/system/cron.php +542 -0 1.6.2 → 1.8.16 View file →
@@ -1,0 +1,542 @@
1 +<?php
2 +/**
3 + * @package VikBooking - Libraries
4 + * @subpackage system
5 + * @author E4J s.r.l.
6 + * @copyright Copyright (C) 2018 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 + * Class used to handle the cron jobs execution.
16 + *
17 + * @since 1.5.10
18 + */
19 +class VikBookingCron
20 +{
21 + /**
22 + * Schedules the published cron jobs to be executed according
23 + * to the selected recurrence.
24 + *
25 + * @return void
26 + */
27 + public static function setup()
28 + {
29 + static $setup = false;
30 +
31 + if ($setup)
32 + {
33 + // setup is allowed only once
34 + return;
35 + }
36 +
37 + // prevent double setup
38 + $setup = true;
39 +
40 + /**
41 + * Filters the non-default cron schedules.
42 + * Adds support to repeat the cron jobs every 5 minutes, every half hour,
43 + * every 2 hours, and every month.
44 + *
45 + * @param array $schedules An array of non-default cron schedules.
46 + */
47 + add_filter('cron_schedules', function($schedules)
48 + {
49 + // add support for "every 5 minutes" recurrence
50 + $schedules['every_5_minutes'] = array(
51 + 'interval' => MINUTE_IN_SECONDS * 5,
52 + 'display' => __('Every 5 Minutes', 'vikbooking'),
53 + );
54 +
55 + // add support for "every 15 minutes" recurrence
56 + $schedules['every_15_minutes'] = array(
57 + 'interval' => MINUTE_IN_SECONDS * 15,
58 + 'display' => __('Every 15 Minutes', 'vikbooking'),
59 + );
60 +
61 + // add support for "every 30 minutes" recurrence
62 + $schedules['half_hour'] = array(
63 + 'interval' => HOUR_IN_SECONDS / 2,
64 + 'display' => __('Every Half Hour', 'vikbooking'),
65 + );
66 +
67 + // add support for "every 2 hours" recurrence
68 + $schedules['every_2_hours'] = array(
69 + 'interval' => HOUR_IN_SECONDS * 2,
70 + 'display' => __('Every 2 Hours', 'vikbooking'),
71 + );
72 +
73 + // add support for "every month" recurrence
74 + $schedules['monthly'] = array(
75 + 'interval' => MONTH_IN_SECONDS,
76 + 'display' => __('Monthly', 'vikbooking'),
77 + );
78 +
79 + return $schedules;
80 + });
81 +
82 + /**
83 + * Trigger event to allow the plugins to include custom HTML within the view.
84 + * It is possible to return an associative array to group the HTML strings
85 + * under different fieldsets. Plain/html string will be always pushed within
86 + * the "custom" fieldset instead.
87 + *
88 + * Displays the field to select the cron job recurrence.
89 + *
90 + * @param mixed $forms The HTML to display.
91 + * @param mixed $view The current view instance.
92 + *
93 + * @since 1.5.10
94 + */
95 + add_filter('vikbooking_display_view_cron', array('VikBookingCron', 'addScheduleControlForm'), 10, 2);
96 +
97 + /**
98 + * Trigger event to allow the plugins to make something before saving
99 + * a record in the database. Used to extend the cron jobs management
100 + * in order to support the selection of the recurrence.
101 + *
102 + * @param bool $save False to abort the saving process.
103 + * @param array $args The saved record.
104 + *
105 + * @since 1.5.10
106 + */
107 + add_filter('vikbooking_before_save_cronjob', array('VikBookingCron', 'saveScheduleControl'), 10, 2);
108 +
109 + /**
110 + * Trigger event to allow the plugins to make something after saving
111 + * a record in the database. Used to schedule the cron job execution.
112 + *
113 + * @param mixed $status The saving status.
114 + * @param array $args The saved record.
115 + * @param bool $is_new True in case of insert.
116 + *
117 + * @since 1.5.10
118 + */
119 + add_filter('vikbooking_after_save_cronjob', array('VikBookingCron', 'checkSchedulingAfterSave'), 10, 3);
120 +
121 + /**
122 + * Trigger event to allow the plugins to make something after publishing or
123 + * unpublishing one or more records. Used to unschedule the unpublished cron jobs.
124 + *
125 + * @param bool $delete False to abort the deleting process.
126 + * @param array $ids An array of IDs to delete.
127 + *
128 + * @since 1.5.10
129 + */
130 + add_filter('vikbooking_before_delete_cronjob', array('VikBookingCron', 'checkSchedulingBeforeDelete'), 10, 2);
131 +
132 + // fetch list of cron jobs
133 + $crons = static::getJobs();
134 +
135 + if (!$crons)
136 + {
137 + // nothing to execute
138 + return;
139 + }
140 +
141 + $model = VBOMvcModel::getInstance('cronjob');
142 +
143 + // iterate cron jobs list
144 + foreach ($crons as $id_cron)
145 + {
146 + // get cron job details
147 + $cron = $model->getItem($id_cron);
148 +
149 + if (!$cron)
150 + {
151 + // cron not found, go ahead
152 + continue;
153 + }
154 +
155 + // fetch recurrence interval
156 + $interval = !empty($cron->schedule_key) ? $cron->schedule_key : 'daily';
157 +
158 + // build cron listener hook
159 + $hook = static::getScheduleHook($cron);
160 +
161 + /**
162 + * Action used to execute all the cron jobs that have been created
163 + * through the VikBooking panel. Only published cron jobs can
164 + * be executed.
165 + *
166 + * The scheduling of this hook must be registered through
167 + * WordPress in order to be executed.
168 + */
169 + add_action($hook, function() use ($id_cron)
170 + {
171 + VikBookingCron::runJob($id_cron);
172 + });
173 +
174 + // Make sure the cron event hasn't been yet scheduled.
175 + // After its execution, wp_next_scheduled will return false and
176 + // we will be able to register it again.
177 + if (!wp_next_scheduled($hook))
178 + {
179 + // schedule event starting from the current time for every minute, by
180 + // launching the cron listener hook (3rd argument)
181 + wp_schedule_event(time(), $interval, $hook);
182 + }
183 + }
184 + }
185 +
186 + /**
187 + * Executes the specified cron job.
188 + *
189 + * @param integer $id_cron The cron job ID.
190 + *
191 + * @return boolean True on success, false otherwise.
192 + */
193 + public static function runJob($id_cron)
194 + {
195 + // require the main library in case WPCron runs the job
196 + require_once VBO_SITE_PATH . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'lib.vikbooking.php';
197 +
198 + $app = JFactory::getApplication();
199 +
200 + /**
201 + * Initialize timezone handler when WP-Cron executes the job to make sure we
202 + * set the proper timezone. This is just for the scheduled cron job execution.
203 + *
204 + * @since 1.6.3
205 + */
206 + JDate::getDefaultTimezone();
207 + date_default_timezone_set($app->get('offset', 'UTC'));
208 +
209 + $error = null;
210 + $status = false;
211 +
212 + // force the option in request to prevent weird behaviors
213 + $app->input->set('option', 'com_vikbooking');
214 +
215 + // get CRON JOB model
216 + $model = VBOMvcModel::getInstance('cronjob');
217 +
218 + try
219 + {
220 + // dispatch cron job
221 + $status = $model->dispatch($id_cron);
222 +
223 + if (!$status)
224 + {
225 + // get any registered error
226 + $error = $model->getError($last = null, $string = true);
227 + }
228 + }
229 + catch (Exception $e)
230 + {
231 + // catch any exception and go ahead
232 + $error = $e->getMessage();
233 + }
234 + catch (Throwable $e)
235 + {
236 + // catch any failure and go ahead
237 + $error = sprintf('%s in %s on line %d', $e->getMessage(), $e->getFile(), $e->getLine());
238 + }
239 +
240 + if (!$status && $error)
241 + {
242 + $item = $model->getItem($id_cron);
243 +
244 + if ($item)
245 + {
246 + // register error message within the logs of the cron job
247 + $item->logs = "<div style=\"color:var(--vbo-red-color);\">$error</div>\n<hr />\n" . $item->logs;
248 +
249 + $model->save($item);
250 + }
251 + }
252 +
253 + /**
254 + * Restore standard timezone when WP-Cron executes the job to make sure we
255 + * set the proper timezone. This is just for the scheduled cron job execution.
256 + *
257 + * @since 1.6.3
258 + */
259 + date_default_timezone_set(JDate::getDefaultTimezone());
260 +
261 + return $status;
262 + }
263 +
264 + /**
265 + * Returns a list of published cron jobs.
266 + *
267 + * @param boolean True to return all the cron job columns.
268 + *
269 + * @return array An array of cron jobs.
270 + */
271 + public static function getJobs($all = false)
272 + {
273 + $dbo = JFactory::getDbo();
274 +
275 + // retrieve all the published cron jobs
276 + $q = $dbo->getQuery(true)
277 + ->from($dbo->qn('#__vikbooking_cronjobs'))
278 + ->where($dbo->qn('published') . ' = 1');
279 +
280 + if ($all)
281 + {
282 + $q->select('*');
283 + }
284 + else
285 + {
286 + $q->select($dbo->qn('id'));
287 + }
288 +
289 + $dbo->setQuery($q);
290 +
291 + if ($all)
292 + {
293 + return $dbo->loadObjectList();
294 + }
295 +
296 + return $dbo->loadColumn();
297 + }
298 +
299 + /**
300 + * Creates the HTML to support a field for the selection of the
301 + * recurrence while creating/editing a cron job.
302 + *
303 + * @param array $forms An associative array containing the HTML.
304 + * @param object $view The view instance.
305 + *
306 + * @return array $forms The resulting HTML array.
307 + */
308 + public static function addScheduleControlForm($forms, $view)
309 + {
310 + if (!is_array($forms))
311 + {
312 + $forms = [];
313 + }
314 +
315 + if (!isset($forms['cronjob']))
316 + {
317 + // init details section
318 + $forms['cronjob'] = '';
319 + }
320 +
321 + $schedule_key = null;
322 +
323 + // check whether the schedule key property exists
324 + if (!$view->row || !array_key_exists('schedule_key', $view->row))
325 + {
326 + static::installScheduleControl();
327 + }
328 + else
329 + {
330 + $schedule_key = $view->row['schedule_key'];
331 + }
332 +
333 + // fetch list of supported schedule intervals
334 + $schedules = wp_get_schedules();
335 +
336 + // sort the options in ascending order
337 + uasort($schedules, function($a, $b)
338 + {
339 + return $a['interval'] - $b['interval'];
340 + });
341 +
342 + $options = [];
343 +
344 + foreach ($schedules as $k => $schedule)
345 + {
346 + $options[] = JHtml::fetch('select.option', $k, $schedule['display']);
347 + }
348 +
349 + $options = JHtml::fetch('select.options', $options, 'value', 'text', $schedule_key ?: 'daily');
350 +
351 + $label = __('Recurrence', 'vikbooking');
352 +
353 + // build HTML control
354 + $forms['cronjob'] .=
355 +<<<HTML
356 +<div class="vbo-param-container">
357 + <div class="vbo-param-label">$label</div>
358 + <div class="vbo-param-setting"><select name="schedule_key">$options</select></div>
359 +</div>
360 +HTML
361 + ;
362 +
363 + return $forms;
364 + }
365 +
366 + /**
367 + * Executes while saving a cron job, so that it is possible to
368 + * inject within the array to save the selected recurrence.
369 + *
370 + * @param boolean $save The saving flag.
371 + * @param array &$src The array holding the data to save.
372 + *
373 + * @return boolean False to abort the saving process.
374 + *
375 + */
376 + public static function saveScheduleControl($save, &$src)
377 + {
378 + if (is_null($save))
379 + {
380 + $save = true;
381 + }
382 +
383 + $src = (array) $src;
384 +
385 + $input = JFactory::getApplication()->input;
386 +
387 + // fetch schedule key from request
388 + $schedule_key = $input->get('schedule_key', null, 'string');
389 +
390 + // make sure the schedule key has been specified
391 + if (!is_null($schedule_key))
392 + {
393 + // inject schedule key into the array to save
394 + $src['schedule_key'] = $schedule_key;
395 + }
396 +
397 + return $save;
398 + }
399 +
400 + /**
401 + * Checks the cron job scheduling after updating a record.
402 + *
403 + * @param boolean $status Dummy argument for WordPress bc.
404 + * @param array $cron The cron jobs details.
405 + * @param boolean $is_new True in case of insert.
406 + *
407 + * @return void
408 + */
409 + public static function checkSchedulingAfterSave($status, $cron, $is_new)
410 + {
411 + if (!$is_new)
412 + {
413 + // check only in case of update
414 + static::checkJobScheduling($cron);
415 + }
416 + }
417 +
418 + /**
419 + * Unschedules the cron jobs that are going to be deleted.
420 + *
421 + * @param boolean $delete The deleting flag.
422 + * @param object $item The item to delete.
423 + *
424 + * @return boolean False to abort the deleting process.
425 + */
426 + public static function checkSchedulingBeforeDelete($delete, $item)
427 + {
428 + if (is_null($delete))
429 + {
430 + $delete = true;
431 + }
432 +
433 + if ($delete)
434 + {
435 + // turn off publishing to detach the scheduling
436 + $item->published = 0;
437 +
438 + // trigger changes
439 + static::checkJobScheduling($item);
440 + }
441 +
442 + return $delete;
443 + }
444 +
445 + /**
446 + * Checks whether an existing schedule should be recreated as a result
447 + * of any significant changes.
448 + *
449 + * @param array $cron The cron record.
450 + *
451 + * @return void
452 + */
453 + protected static function checkJobScheduling($cron)
454 + {
455 + $cron = (array) $cron;
456 +
457 + if (!array_key_exists('published', $cron) || !array_key_exists('schedule_key', $cron))
458 + {
459 + // reload all the details of the updated cron job
460 + $cron = VBOMvcModel::getInstance('cronjob')->getItem(@$cron['id']);
461 + }
462 + else
463 + {
464 + // cast to object
465 + $cron = (object) $cron;
466 + }
467 +
468 + if (!$cron)
469 + {
470 + // ops...
471 + return;
472 + }
473 +
474 + if (!isset($cron->schedule_key))
475 + {
476 + // property not yet installed, use the default one to properly
477 + // unschedule the registered event
478 + $cron->schedule_key = 'daily';
479 + }
480 +
481 + // build cron listener hook
482 + $hook = static::getScheduleHook($cron);
483 +
484 + // fetch the next scheduled event
485 + $event = wp_get_scheduled_event($hook);
486 +
487 + if (!$event)
488 + {
489 + // no scheduled event, do nothing...
490 + return;
491 + }
492 +
493 + if (!$cron->published || $cron->schedule_key !== $event->schedule)
494 + {
495 + // unschedule the event
496 + wp_unschedule_event($event->timestamp, $hook);
497 + }
498 + }
499 +
500 + /**
501 + * Returns the hook to be used while scheduling the execution
502 + * of a cron job.
503 + *
504 + * @param object $cron The cron object.
505 + *
506 + * @return string The resulting hook.
507 + */
508 + protected static function getScheduleHook($cron)
509 + {
510 + $cron = (object) $cron;
511 +
512 + // build cron listener hook
513 + return implode('_', [
514 + 'vikbooking',
515 + 'cron',
516 + preg_replace("/\.php$/", '', $cron->class_file),
517 + $cron->id,
518 + ]);
519 + }
520 +
521 + /**
522 + * Install the resources needed to support a custom recurrence for
523 + * the created cron jobs.
524 + *
525 + * @return void
526 + */
527 + protected static function installScheduleControl()
528 + {
529 + $fields = VBOMvcModel::getInstance('cronjob')->getTableColumns();
530 +
531 + if (!isset($fields['schedule_key']))
532 + {
533 + $db = JFactory::getDbo();
534 +
535 + // alter the table to allow the storage of the selected recurrence
536 + $query = "ALTER TABLE `#__vikbooking_cronjobs` ADD COLUMN `schedule_key` varchar(64) DEFAULT NULL AFTER `published`";
537 +
538 + $db->setQuery($query);
539 + $db->execute();
540 + }
541 + }
542 +}