PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 3.2.3
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v3.2.3
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / vendor / team-updraft / common-libs / src / updraft-tasks / class-updraft-task.php

class-updraft-task.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 3.2.3, at vendor/team-updraft/common-libs/src/updraft-tasks/class-updraft-task.php

694 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The base class which must be extended to use the tasks library
4 */
5
6 if (!defined('ABSPATH')) die('Access denied.');
7
8 if (!class_exists('Updraft_Task_1_2')) :
9
10 if (!class_exists('Updraft_Task_Options')) require_once('class-updraft-task-options.php');
11 if (!class_exists('Updraft_Task_Meta')) require_once('class-updraft-task-meta.php');
12
13 abstract class Updraft_Task_1_2 {
14
15 /**
16 * A unique ID for the specific task
17 *
18 * @var int
19 */
20 private $id;
21
22 /**
23 * The user id of the creator of this task
24 *
25 * @var string
26 */
27 private $user_id;
28
29 /**
30 * A text description for the task
31 *
32 * @var string
33 */
34 private $description;
35
36 /**
37 * A type for the task
38 *
39 * @var string
40 */
41 private $type;
42
43 /**
44 * A timestamp indicating the time the task was created
45 *
46 * @var string
47 */
48 private $time_created;
49
50 /**
51 * The number of times this task was attempted
52 *
53 * @var int
54 */
55 private $attempts;
56
57 /**
58 * A text description describing the status of the task
59 *
60 * @var string
61 */
62 private $status;
63
64 /**
65 * An identifier indicating which child class created this instance
66 *
67 * @var string
68 */
69 private $class_identifier;
70
71 /**
72 * A logger object that can be used to capture interesting events / messages
73 *
74 * @var Object
75 */
76 protected $_loggers;
77
78 /**
79 * The Task constructor
80 *
81 * @param UpdraftPlus_Task|object $task UpdraftPlus_Task object.
82 */
83 public function __construct($task) {
84 foreach (get_object_vars($task) as $key => $value)
85 $this->$key = $value;
86 }
87
88 /**
89 * Sets the instance ID.
90 *
91 * @param String $instance_id - the instance ID
92 */
93 public function set_id($instance_id) {
94 $this->id = $instance_id;
95 }
96
97 /**
98 * Gets the instance ID.
99 *
100 * @return String the instance ID
101 */
102 public function get_id() {
103 return $this->id;
104 }
105
106 /**
107 * Sets the description.
108 *
109 * @param String $description - the description of the task
110 */
111 public function set_description($description) {
112 $this->description = $description;
113 }
114
115 /**
116 * Gets the task description
117 *
118 * @return String $description - the description of the task
119 */
120 public function get_description() {
121 return $this->description;
122 }
123
124 /**
125 * Sets the type.
126 *
127 * @param String $type - the type of the task
128 */
129 public function set_type($type) {
130 $this->type = $type;
131 }
132
133 /**
134 * Gets the number of times this task was attempted
135 *
136 * @return int $attempts - the count
137 */
138 public function get_attempts() {
139 return $this->attempts;
140 }
141
142 /**
143 * Sets the number of times this task was attempted
144 *
145 * @param String $attempts - the count
146 */
147 public function set_attempts($attempts) {
148 if (is_numeric($attempts))
149 $this->attempts = $attempts;
150 else return false;
151
152 return $this->update_attempts($this->id, $this->attempts);
153 }
154
155 /**
156 * Gets the task type
157 *
158 * @return String $type - the type of the task
159 */
160 public function get_type() {
161 return $this->type;
162 }
163
164 /**
165 * Sets the task status.
166 *
167 * @param String $status - the status of the task
168 *
169 * @return Boolean - the result of the status update
170 */
171 public function set_status($status) {
172
173 if (array_key_exists($status, self::get_allowed_statuses()))
174 $this->status = $status;
175 else return false;
176
177 return $this->update_status($this->id, $this->status);
178 }
179
180 /**
181 * Gets the task status
182 *
183 * @return String $status - the status of the task
184 */
185 public function get_status() {
186 return $this->status;
187 }
188
189 /**
190 * Sets the logger for this task.
191 *
192 * @param array $loggers - the loggers for this task
193 */
194 public function set_loggers($loggers) {
195 if (is_array($loggers)) {
196 foreach ($loggers as $logger) {
197 $this->add_logger($logger);
198 }
199 }
200 }
201
202 /**
203 * Add a logger to loggers list
204 *
205 * @param Object $logger - a logger for the task
206 */
207 public function add_logger($logger) {
208 $this->_loggers[] = $logger;
209 }
210
211 /**
212 * Return list of loggers
213 *
214 * @return array
215 */
216 public function get_loggers() {
217 return $this->_loggers;
218 }
219
220 /**
221 * The initialisation function that accepts and processes any parameters needed before the task starts
222 *
223 * @param Array $options - array of options
224 *
225 * @uses update_option
226 */
227 public function initialise($options = array()) {
228
229 do_action('ud_task_before_initialise', $this, $options);
230
231 /**
232 * Parse incoming $options into an array and merge it with defaults
233 */
234 $defaults = $this->get_default_options();
235 $options = wp_parse_args($options, $defaults);
236
237 foreach ($options as $option => $value) {
238 $this->update_option($option, $value);
239 }
240
241 do_action('ud_task_initialise_complete', $this, $options);
242
243 }
244
245 /**
246 * Attempts to perform the task
247 *
248 * @param integer $lock_for - if greater than zero, then lock the task, and don't break until this number of seconds has passed
249 *
250 * @return boolean Status of the attempt
251 */
252 public function attempt($lock_for = 0) {
253
254 $_task = $this->get_task_from_db($this->get_id());
255
256 if (!$_task) {
257 $this->log("The task with id : {$this->get_id()}, and type '{$this->get_type()}' seems to have been deleted from the database.");
258 return false;
259 }
260
261 if ('complete' == $this->get_status()) {
262 $this->log("Attempting already complete task with ID : {$this->get_id()}, and type '{$this->get_type()}'. Aborting !");
263 return true;
264 }
265
266 if ($lock_for) {
267 $try = 1;
268 $locked = false;
269 while ($try < 4) {
270 if ($locked = $this->lock($this->get_id(), true, $lock_for)) break;
271 $try ++;
272 sleep(1);
273 }
274 if (!$locked) {
275 $this->fail('could_not_lock', 'The task could not be locked');
276 return false;
277 }
278 }
279
280 $attempts = $this->get_attempts();
281
282 if ($attempts >= $this->get_max_attempts()) {
283 $this->fail("max_attempts_exceeded", "Maximum attempts ($attempts) exceeded for task");
284 return false;
285 }
286
287 $this->log("Processing task with ID : {$this->get_id()}, and type '{$this->get_type()}'");
288 $this->set_attempts(++$attempts);
289 $status = $this->run();
290
291 if ($status) {
292 $this->complete();
293 $this->log("Completed processing task with ID : {$this->get_id()}, and type '{$this->get_type()}'");
294 }
295
296 if ($lock_for) $this->lock($this->get_id(), false);
297
298 return $status;
299 }
300
301 /**
302 * Lock or unlock a task
303 *
304 * @param Integer - $task_id - task identifier
305 * @param Boolean - $lock - whether to lock or unlock
306 * @param Integer - $lock_for - if already locked, how long after which to break the lock
307 *
308 * @return Boolean - whether the operation was successful
309 */
310 public function lock($task_id, $lock = true, $lock_for = 60) {
311
312 global $wpdb;
313
314 if (!$lock) {
315 return $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => 0), array('id' => $task_id)) ? true : false;
316 }
317
318 // Mode: lock. Attempt to set the lock
319 $affected = $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => time()), array('id' => $task_id, 'last_locked_at' => 0));
320
321 // Success.
322 if (1 == $affected) return true;
323
324 // Failed - something else already had it locked. Grab the lock if it had expired.
325 $affected = $wpdb->update($wpdb->base_prefix.'tm_tasks', array('last_locked_at' => time()), array('id' => $task_id, 'last_locked_at' => 0));
326
327 $expires_at = time() - $lock_for;
328
329 $affected = $wpdb->query($wpdb->prepare("
330 UPDATE {$wpdb->base_prefix}tm_tasks
331 SET last_locked_at = %d
332 WHERE id = %d
333 AND last_locked_at <= %s
334 ", time(), $task_id, $expires_at));
335
336 return $affected ? true : false;
337 }
338
339 /**
340 * This function is called to allow for the task to perform a small chunk of work.
341 * It should be written in a way that anticipates it being killed off at any time.
342 */
343 abstract public function run();
344
345 /**
346 * Any clean up code goes here.
347 */
348 public function complete() {
349
350 do_action('ud_task_before_complete', $this);
351
352 $this->set_status('complete');
353
354 do_action('ud_task_completed', $this);
355
356 return true;
357 }
358
359 /**
360 * Fires if the task fails, any clean up code and logging should go here
361 *
362 * @param String $error_code - A code for the failure
363 * @param String $error_message - A description for the failure
364 */
365 public function fail($error_code = "Unknown", $error_message = "Unknown") {
366
367 do_action('ud_task_before_failed', $this);
368
369 $this->set_status('failed');
370 $this->log(sprintf("Task with ID %d and type (%s) failed with error code %s - %s", $this->id, $this->type, $error_code, $error_message));
371
372 $this->update_option("error_code", $error_code);
373 $this->update_option("error_message", $error_message);
374
375 do_action('ud_task_failed', $this);
376
377 return true;
378 }
379
380 /**
381 * Prints any information about the task that the UI can use on the front end for debugging
382 * @param String $title the header to use in the report
383 *
384 * @return String The task report HTML
385 */
386 public function print_task_report_widget($title = 'Task Summary') {
387
388 $ret = "";
389
390 $status = $this->get_status();
391 $stage = $this->get_option('stage') ? $this->get_option('stage') : 'Unknown';
392 $description = $this->get_status_description($status);
393
394
395 $ret .= "<div class='task task-report task-{$this->type}' id='task-id-{$this->id}'>";
396 $ret .= "<h4>Task Summary</h4>";
397 $ret .= "<ul class='properties-list task-{$this->type}'>";
398
399 foreach ($this as $key => $value) {
400 $ret .= sprintf("<li> %s : %s </li>", $key, $value);
401 }
402 $ret .='</ul>';
403
404 $ret .= "<h4> $title </h4>";
405 $ret .= "<ul class='data-list task-{$this->type}'>";
406
407 foreach ($this->get_all_options() as $key => $value) {
408 if (is_array(maybe_unserialize($value))) {
409 $ret .= sprintf("<li> %s</li>", $key);
410 $ret .= "<ul class='sub-list'>";
411 foreach (maybe_unserialize($value) as $k => $v) {
412 $ret .= sprintf("<li> %s => %s </li>", $k, $v);
413 }
414 $ret .= "</ul>";
415 } else {
416 $ret .= sprintf("<li> %s : %s </li>", $key, $value);
417 }
418 }
419 $ret .='</ul>';
420 $ret .='</div>';
421
422 return apply_filters('ud_print_task_report_widget', $ret, $this);
423
424 }
425
426 /**
427 * This method gets an option from the task options in the WordPress database if available,
428 * otherwise returns the default for this task type
429 *
430 * @param String $option the name of the option to get
431 * @param Mixed $default a value to return if the option is not currently set
432 *
433 * @return Mixed The option from the database
434 */
435 public function get_option($option = null, $default = null) {
436 return Updraft_Task_Options::get_task_option($this->id, $option, $default);
437 }
438
439 /**
440 * This method is used to add a task option stored in the WordPress database
441 *
442 * @param String $option the name of the option to update
443 * @param Mixed $value the value to save to the option
444 *
445 * @return Mixed the status of the add operation
446 */
447 public function add_option($option, $value) {
448 return Updraft_Task_Options::update_task_option($this->id, $option, $value);
449 }
450
451 /**
452 * This method is used to update a task option stored in the WordPress database
453 *
454 * @param String $option the name of the option to update
455 * @param Mixed $value the value to save to the option
456 *
457 * @return Mixed the status of the update operation
458 */
459 public function update_option($option, $value) {
460 return Updraft_Task_Options::update_task_option($this->id, $option, $value);
461 }
462
463 /**
464 * This method is used to delete a task option stored in the WordPress database
465 *
466 * @param String $option the option to delete
467 *
468 * @return Boolean the result of the delete operation
469 */
470 public function delete_option($option) {
471 return Updraft_Task_Options::delete_task_option($this->id, $option);
472 }
473
474 /**
475 * This method gets all options assoicated with a task
476 */
477 public function get_all_options() {
478 return Updraft_Task_Options::get_all_task_options($this->id);
479 }
480
481 /**
482 * Retrieve default options for this task.
483 * This method should normally be over-ridden by the child.
484 *
485 * @return Array - an array of options
486 */
487 public function get_default_options() {
488
489 $this->log(sprintf('The get_default_options() method was not over-ridden for the class : %s', $this->get_description()));
490
491 return array();
492 }
493
494 /**
495 * Returns a unique label for this instance that can be used as an identifier
496 *
497 * @return String - a unique label for this instance
498 */
499 protected function get_unique_label() {
500 return apply_filters('ud_task_unique_label', $this->id."-".$this->type, $this);
501 }
502
503 /**
504 * Updates the status of the given task in the DB
505 *
506 * @param String $id - the id of the task
507 * @param String $status - the status of the task
508 *
509 * @return Boolean - the stauts of the update operation
510 */
511 public function update_status($id, $status) {
512
513 if (!array_key_exists($status, self::get_allowed_statuses()))
514 return false;
515
516 global $wpdb;
517 $sql = $wpdb->prepare("UPDATE {$wpdb->base_prefix}tm_tasks SET status = %s WHERE id = %d", $status, $id);
518
519 return $wpdb->query($sql);
520 }
521
522 /**
523 * Updates the number of attempts made for the given task in the DB
524 *
525 * @param String $id - the id of the task
526 * @param int $attempts - the status of the task
527 *
528 * @return Boolean - the stauts of the update operation
529 */
530 public function update_attempts($id, $attempts) {
531
532 if (!is_numeric($attempts))
533 return false;
534
535 global $wpdb;
536 $sql = $wpdb->prepare("UPDATE {$wpdb->base_prefix}tm_tasks SET attempts = %s WHERE id = %d", $attempts, $id);
537
538 return $wpdb->query($sql);
539 }
540
541 /**
542 * Cleans out the given task from the DB
543 *
544 * @return Boolean - the status of the delete operation
545 */
546 public function delete() {
547 global $wpdb;
548
549 $sql = $wpdb->prepare("DELETE FROM {$wpdb->base_prefix}tm_tasks WHERE id = %d", $this->id);
550 return $wpdb->query($sql);
551 }
552
553 /**
554 * Cleans out the given task meta from the DB
555 *
556 * @return Boolean - the status of the delete operation
557 */
558 public function delete_meta() {
559 return Updraft_Task_Meta::bulk_delete_task_meta($this->id);
560 }
561
562 /**
563 * Helper function to convert object to array.
564 *
565 * @return array Object as array.
566 */
567 public function to_array() {
568 $task = get_object_vars($this);
569
570 foreach (array( 'task_options', 'task_data', 'task_logs', 'task_extras' ) as $key) {
571 if ($this->__isset($key))
572 $task[$key] = $this->__get($key);
573 }
574
575 return $task;
576 }
577
578 /**
579 * Captures and logs any interesting messages
580 *
581 * @param String $message - the error message
582 * @param String $error_type - the error type
583 */
584 public function log($message, $error_type = 'info') {
585
586 if (isset($this->_loggers)) {
587 foreach ($this->_loggers as $logger) {
588 $logger->log($message, $error_type);
589 }
590 }
591 }
592
593 /**
594 * Retrieve all the supported task statuses.
595 *
596 * Tasks should have a limited set of valid status values, this method provides a
597 * list of values and descriptions.
598 *
599 * @return array List of task statuses.
600 */
601 public static function get_allowed_statuses() {
602 $status = array(
603 'initialised' => __('Initialised'),
604 'active' => __('Active'),
605 'paused' => __('Paused'),
606 'complete' => __('Completed'),
607 'failed' => __('Failed')
608 );
609
610 return apply_filters('ud_allowed_task_statuses', $status);
611 }
612
613
614 /**
615 * Retrieve the max attempts permitted for task type
616 *
617 * @return int Max attempts permitted for task type
618 */
619 private function get_max_attempts() {
620 return apply_filters('ud_max_attempts', 5, $this);
621 }
622
623 /**
624 * Retrieve the text description of the task status.
625 *
626 * @param String $status - The task status
627 *
628 * @return String Description of the task status.
629 */
630 public static function get_status_description($status) {
631 $list = self::get_allowed_statuses();
632
633 if (!array_key_exists($status, self::get_allowed_statuses()))
634 return __('Unknown');
635
636 return apply_filters("ud_task_status_description_{$status}", $list[$status], $status, $list);
637 }
638
639
640 /**
641 * Creates a new task instance and returns it
642 *
643 * @access public
644 *
645 * @global wpdb $wpdb WordPress database abstraction object.
646 *
647 * @param String $type A identifier for the task
648 * @param String $description A description of the task
649 * @param Mixed $options A list of options to initialise the task
650 * @param String $task_class Class name of task; only needed/used on PHP 5.2 (due to lack of late static binding)
651 *
652 * @return Updraft_Task|false Task object, false otherwise.
653 */
654 public static function create_task($type, $description, $options = array(), $task_class = '') {
655 global $wpdb;
656
657 $user_id = get_current_user_id();
658 $class_identifier = function_exists('get_called_class') ? get_called_class() : $task_class;// phpcs:ignore PHPCompatibility.FunctionUse.NewFunctions.get_called_classFound
659
660 $is_anonymous_user_allowed = isset($options['anonymous_user_allowed']) && $options['anonymous_user_allowed'];
661 if (!$user_id && !$is_anonymous_user_allowed) return false;
662
663 $sql = $wpdb->prepare("INSERT INTO {$wpdb->base_prefix}tm_tasks (type, user_id, description, class_identifier, status) VALUES (%s, %d, %s, %s, %s)", $type, $user_id, $description, $class_identifier, 'active');
664
665 $wpdb->query($sql);
666
667 $task_id = $wpdb->insert_id;
668
669 if (!$task_id) return false;
670
671 $_task = $wpdb->get_row("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE id = {$task_id} LIMIT 1");
672
673 $task = new $class_identifier($_task);
674
675 if (!$task) return false;
676
677 $task->initialise($options);
678
679 return $task;
680 }
681
682 /**
683 * Select the current task from the database
684 *
685 * @param int $task_id - The task ID
686 * @return object|false
687 */
688 private function get_task_from_db($task_id) {
689 global $wpdb;
690 return $wpdb->get_row("SELECT * FROM {$wpdb->base_prefix}tm_tasks WHERE id = {$task_id} LIMIT 1");
691 }
692 }
693 endif;
694