PluginProbe ʕ •ᴥ•ʔ
GiveWP – Donation Plugin and Fundraising Platform / 2.4.5
GiveWP – Donation Plugin and Fundraising Platform v2.4.5
4.16.3 4.16.2 4.16.1 4.16.0 4.15.5 4.15.4 4.15.3 4.15.2 4.15.1 4.15.0 2.3.0 2.3.1 2.3.2 2.30.0 2.31.0 2.31.1 2.32.0 2.33.0 2.33.1 2.33.2 2.33.3 2.33.4 2.33.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.5.0 2.5.1 2.5.10 2.5.11 2.5.12 2.5.13 2.5.2 2.5.3 2.5.4 2.5.5 2.5.6 2.5.7 2.5.8 2.5.9 2.6.0 2.6.1 2.6.2 2.6.3 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.8.0 2.8.1 2.9.0 2.9.1 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.1.0 3.1.1 3.1.2 3.10.0 3.11.0 3.12.0 3.12.1 3.12.2 3.12.3 3.13.0 3.14.0 3.14.1 3.14.2 3.15.0 3.15.1 3.16.0 3.16.1 3.16.2 3.16.3 3.16.4 3.16.5 3.17.0 3.17.1 3.17.2 3.18.0 3.19.0 3.19.1 3.19.2 3.19.3 3.19.4 3.2.0 3.2.1 3.2.2 3.20.0 3.21.0 3.21.1 3.22.0 3.22.1 3.22.2 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.6.0 3.6.1 3.6.2 3.7.0 3.8.0 3.9.0 4.0.0 4.1.0 4.1.1 4.10.0 4.10.1 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.14.5 4.14.6 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.1 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 trunk 1.9.0 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.2 2.11.3 2.12.0 2.12.1 2.12.2 2.12.3 2.13.0 2.13.1 2.13.2 2.13.3 2.13.4 2.14.0 2.15.0 2.16.0 2.16.1 2.17.0 2.17.1 2.17.3 2.18.0 2.18.1 2.19.1 2.19.2 2.19.3 2.19.4 2.19.5 2.19.6 2.19.7 2.19.8 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.20.0 2.20.1 2.20.2 2.21.0 2.21.1 2.21.2 2.21.3 2.21.4 2.22.0 2.22.1 2.22.2 2.22.3 2.23.0 2.23.1 2.23.2 2.24.0 2.24.1 2.24.2 2.25.0 2.25.1 2.25.2 2.25.3 2.26.0 2.27.0 2.27.1 2.27.2 2.27.3 2.28.0 2.29.0 2.29.1 2.29.2
give / includes / class-give-background-updater.php
give / includes Last commit date
admin 7 years ago api 7 years ago deprecated 7 years ago donors 7 years ago emails 7 years ago forms 7 years ago frontend 7 years ago gateways 7 years ago libraries 7 years ago payments 7 years ago actions.php 7 years ago ajax-functions.php 7 years ago class-give-async-process.php 7 years ago class-give-background-updater.php 7 years ago class-give-cache-setting.php 7 years ago class-give-cache.php 7 years ago class-give-cli-commands.php 7 years ago class-give-comment.php 7 years ago class-give-cron.php 7 years ago class-give-db-comments-meta.php 7 years ago class-give-db-comments.php 7 years ago class-give-db-donor-meta.php 7 years ago class-give-db-donors.php 7 years ago class-give-db-form-meta.php 7 years ago class-give-db-logs-meta.php 7 years ago class-give-db-logs.php 7 years ago class-give-db-meta.php 7 years ago class-give-db-payment-meta.php 7 years ago class-give-db-sequential-ordering.php 7 years ago class-give-db-sessions.php 7 years ago class-give-db.php 7 years ago class-give-donate-form.php 7 years ago class-give-donor-wall-widget.php 7 years ago class-give-donor.php 7 years ago class-give-email-access.php 7 years ago class-give-license-handler.php 7 years ago class-give-logging.php 7 years ago class-give-readme-parser.php 7 years ago class-give-roles.php 7 years ago class-give-scripts.php 7 years ago class-give-session.php 7 years ago class-give-stats.php 7 years ago class-give-template-loader.php 8 years ago class-give-tooltips.php 7 years ago class-give-translation.php 8 years ago class-notices.php 7 years ago country-functions.php 7 years ago currencies-list.php 7 years ago currency-functions.php 7 years ago error-tracking.php 7 years ago filters.php 7 years ago formatting.php 7 years ago install.php 7 years ago login-register.php 7 years ago misc-functions.php 7 years ago plugin-compatibility.php 7 years ago post-types.php 7 years ago price-functions.php 7 years ago process-donation.php 7 years ago setting-functions.php 7 years ago shortcodes.php 7 years ago template-functions.php 7 years ago user-functions.php 7 years ago
class-give-background-updater.php
609 lines
1 <?php
2 /**
3 * Background Updater
4 *
5 * Uses https://github.com/A5hleyRich/wp-background-processing to handle DB
6 * updates in the background.
7 *
8 * @class Give_Background_Updater
9 * @version 2.0.0
10 * @package Give/Classes
11 * @category Class
12 * @author GiveWP
13 */
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Give_Background_Updater Class.
20 */
21 class Give_Background_Updater extends WP_Background_Process {
22
23 /**
24 * @var string
25 */
26 protected $action = 'give_db_updater';
27
28 /**
29 * Dispatch updater.
30 *
31 * Updater will still run via cron job if this fails for any reason.
32 */
33 public function dispatch() {
34 if ( give_test_ajax_works() ) {
35 parent::dispatch();
36 } elseif ( wp_doing_ajax() ) {
37 $this->maybe_handle();
38 }
39 }
40
41
42 /**
43 * Get all batches.
44 *
45 * @since 2.0
46 * @access public
47 * @return stdClass
48 */
49 public function get_all_batch() {
50 return $this->get_batch();
51 }
52
53 /**
54 * Is queue empty
55 *
56 * @since 2.0.3
57 *
58 * @return bool
59 */
60 public function has_queue() {
61 return ( ! $this->is_queue_empty() );
62 }
63
64
65 /**
66 * Lock process
67 *
68 * Lock the process so that multiple instances can't run simultaneously.
69 * Override if applicable, but the duration should be greater than that
70 * defined in the time_exceeded() method.
71 *
72 *
73 * @since 2.0.3
74 */
75 protected function lock_process() {
76 // Check if admin want to pause upgrade.
77 if( get_option('give_pause_upgrade') ) {
78 self::flush_cache();
79
80 delete_option( 'give_paused_batches' );
81
82 Give_Updates::get_instance()->__pause_db_update( true );
83
84 delete_option('give_pause_upgrade');
85
86 /**
87 * Fire action when pause db updates
88 *
89 * @since 2.0.1
90 */
91 do_action( 'give_pause_db_upgrade', Give_Updates::get_instance() );
92
93 wp_die();
94 }
95
96
97 $this->start_time = time(); // Set start time of current process.
98
99 $lock_duration = ( property_exists( $this, 'queue_lock_time' ) ) ? $this->queue_lock_time : 60; // 1 minute
100 $lock_duration = apply_filters( $this->identifier . '_queue_lock_time', $lock_duration );
101
102 set_transient( $this->identifier . '_process_lock', microtime(), $lock_duration );
103 }
104
105 /**
106 * Handle cron healthcheck
107 *
108 * Restart the background process if not already running
109 * and data exists in the queue.
110 */
111 public function handle_cron_healthcheck() {
112 if ( $this->is_process_running() || $this->is_paused_process() ) {
113 // Background process already running.
114 return;
115 }
116
117 if ( $this->is_queue_empty() ) {
118 // No data to process.
119 $this->clear_scheduled_event();
120
121 return;
122 }
123
124 $this->handle();
125 }
126
127 /**
128 * Schedule fallback event.
129 */
130 protected function schedule_event() {
131 if ( ! wp_next_scheduled( $this->cron_hook_identifier ) && ! $this->is_paused_process() ) {
132 wp_schedule_event( time() + 10, $this->cron_interval_identifier, $this->cron_hook_identifier );
133 }
134 }
135
136 /**
137 * Is queue empty
138 *
139 * @since 2.4.5
140 *
141 * @return bool
142 */
143 protected function is_queue_empty() {
144 global $wpdb;
145
146 $table = $wpdb->options;
147 $column = 'option_name';
148
149 $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
150
151 $count = $wpdb->get_var( $wpdb->prepare( "
152 SELECT COUNT(*)
153 FROM {$table}
154 WHERE {$column} LIKE %s
155 ", $key ) );
156
157 return ! ( $count > 0 );
158 }
159
160 /**
161 * Get batch
162 *
163 * @since 2.4.5
164 *
165 * @return stdClass Return the first batch from the queue
166 */
167 protected function get_batch() {
168 global $wpdb;
169
170 $table = $wpdb->options;
171 $column = 'option_name';
172 $key_column = 'option_id';
173 $value_column = 'option_value';
174
175 $key = $wpdb->esc_like( $this->identifier . '_batch_' ) . '%';
176
177 $query = $wpdb->get_row( $wpdb->prepare( "
178 SELECT *
179 FROM {$table}
180 WHERE {$column} LIKE %s
181 ORDER BY {$key_column} ASC
182 LIMIT 1
183 ", $key ) );
184
185 $batch = new stdClass();
186 $batch->key = $query->$column;
187 $batch->data = maybe_unserialize( $query->$value_column );
188
189 return $batch;
190 }
191
192 /**
193 * Save queue
194 *
195 * @since 2.4.5
196 *
197 * @return $this
198 */
199 public function save() {
200 $key = $this->generate_key();
201
202 if ( ! empty( $this->data ) ) {
203 update_option( $key, $this->data );
204 }
205
206 return $this;
207 }
208
209 /**
210 * Update queue
211 *
212 * @since 2.4.5
213 *
214 * @param string $key Key.
215 * @param array $data Data.
216 *
217 * @return $this
218 */
219 public function update( $key, $data ) {
220 if ( ! empty( $data ) ) {
221 update_option( $key, $data );
222 }
223
224 return $this;
225 }
226
227 /**
228 * Delete queue
229 *
230 * @since 2.4.5
231 *
232 * @param string $key Key.
233 *
234 * @return $this
235 */
236 public function delete( $key ) {
237 delete_option( $key );
238
239 return $this;
240 }
241
242 /**
243 * Is process running
244 *
245 * @since 2.4.5
246 *
247 * Check whether the current process is already running
248 * in a background process.
249 */
250 public function is_process_running() {
251 if ( get_transient( $this->identifier . '_process_lock' ) ) {
252 // Process already running.
253 return true;
254 }
255
256 return false;
257 }
258
259 /**
260 * Unlock process
261 *
262 * Unlock the process so that other instances can spawn.
263 *
264 * @since 2.4.5
265 *
266 * @return $this
267 */
268 protected function unlock_process() {
269 delete_transient( $this->identifier . '_process_lock' );
270
271 return $this;
272 }
273
274 /**
275 * Task
276 *
277 * Override this method to perform any actions required on each
278 * queue item. Return the modified item for further processing
279 * in the next pass through. Or, return false to remove the
280 * item from the queue.
281 *
282 * @param array $update Update info
283 *
284 * @return mixed
285 */
286 protected function task( $update ) {
287 // Pause upgrade immediately if admin pausing upgrades.
288 if( $this->is_paused_process() ) {
289 wp_die();
290 }
291
292 if ( empty( $update ) ) {
293 return false;
294 }
295
296 // Delete cache.
297 self::flush_cache();
298
299 /* @var Give_Updates $give_updates */
300 $give_updates = Give_Updates::get_instance();
301 $resume_update = get_option(
302 'give_doing_upgrade',
303
304 // Default update.
305 array(
306 'update_info' => $update,
307 'step' => 1,
308 'update' => 1,
309 'heading' => sprintf( 'Update %s of {update_count}', 1 ),
310 'percentage' => $give_updates->percentage,
311 'total_percentage' => 0,
312 )
313 );
314
315 // Continuously skip update if previous update does not complete yet.
316 if (
317 $resume_update['update_info']['id'] !== $update['id'] &&
318 ! give_has_upgrade_completed( $resume_update['update_info']['id'] )
319 ) {
320 return $update;
321 }
322
323 // Set params.
324 $resume_update['update_info'] = $update;
325 $give_updates->step = absint( $resume_update['step'] );
326 $give_updates->update = absint( $resume_update['update'] );
327 $is_parent_update_completed = $give_updates->is_parent_updates_completed( $update );
328
329
330 // Skip update if dependency update does not complete yet.
331 if ( empty( $is_parent_update_completed ) ) {
332 // @todo: set error when you have only one update with invalid dependency
333 if ( ! is_null( $is_parent_update_completed ) ) {
334 return $update;
335 }
336
337 return false;
338 }
339
340
341 // Pause upgrade immediately if found following:
342 // 1. Running update number greater then total update count
343 // 2. Processing percentage greater then 100%
344 if( (
345 101 < $resume_update['total_percentage'] ) ||
346 ( $give_updates->get_total_db_update_count() < $resume_update['update'] ) ||
347 ! in_array( $resume_update['update_info']['id'], $give_updates->get_update_ids() )
348 ) {
349 if( ! $this->is_paused_process() ){
350 $give_updates->__pause_db_update(true);
351 }
352
353 update_option( 'give_upgrade_error', 1, false );
354
355 $log_data = 'Update Task' . "\n";
356 $log_data .= "Total update count: {$give_updates->get_total_db_update_count()}\n";
357 $log_data .= 'Update IDs: ' . print_r( $give_updates->get_update_ids() , true );
358 $log_data .= 'Update: ' . print_r( $resume_update , true );
359
360 Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
361
362 wp_die();
363 }
364
365 // Disable cache.
366 Give_Cache::disable();
367
368 try{
369 // Run update.
370 if ( is_array( $update['callback'] ) ) {
371 $object = $update['callback'][0];
372 $method_name = $update['callback'][1];
373
374 $object->$method_name();
375
376 } else {
377 $update['callback']();
378 }
379 } catch ( Exception $e ){
380
381 if( ! $this->is_paused_process() ){
382 $give_updates->__pause_db_update(true);
383 }
384
385 $log_data = 'Update Task' . "\n";
386 $log_data .= print_r( $resume_update, true ) . "\n\n";
387 $log_data .= "Error\n {$e->getMessage()}";
388
389 Give()->logs->add( 'Update Error', $log_data, 0, 'update' );
390 update_option( 'give_upgrade_error', 1, false );
391
392 wp_die();
393 }
394
395 // Set update info.
396 $doing_upgrade_args = array(
397 'update_info' => $update,
398 'step' => ++ $give_updates->step,
399 'update' => $give_updates->update,
400 'heading' => sprintf( 'Update %s of %s', $give_updates->update, get_option( 'give_db_update_count' ) ),
401 'percentage' => $give_updates->percentage,
402 'total_percentage' => $give_updates->get_db_update_processing_percentage(),
403 );
404
405 // Cache upgrade.
406 update_option( 'give_doing_upgrade', $doing_upgrade_args, false );
407
408 // Enable cache.
409 Give_Cache::enable();
410
411 // Check if current update completed or not.
412 if ( give_has_upgrade_completed( $update['id'] ) ) {
413 return false;
414 }
415
416 return $update;
417 }
418
419 /**
420 * Complete
421 *
422 * Override if applicable, but ensure that the below actions are
423 * performed, or, call parent::complete().
424 */
425 public function complete() {
426 if ( $this->is_paused_process() ) {
427 return false;
428 }
429
430 parent::complete();
431
432 delete_option( 'give_pause_upgrade' );
433 delete_option( 'give_upgrade_error' );
434 delete_option( 'give_db_update_count' );
435 delete_option( 'give_doing_upgrade' );
436 add_option( 'give_show_db_upgrade_complete_notice', 1, '', false );
437
438 // Flush cache.
439 Give_Cache::flush_cache( true );
440
441 if ( $cache_keys = Give_Cache::get_options_like( '' ) ) {
442 Give_Cache::delete( $cache_keys );
443 }
444 }
445
446 /**
447 * Get memory limit
448 *
449 * @return int
450 */
451 protected function get_memory_limit() {
452 if ( function_exists( 'ini_get' ) ) {
453 $memory_limit = ini_get( 'memory_limit' );
454 } else {
455 // Sensible default.
456 $memory_limit = '128M';
457 }
458
459 if ( ! $memory_limit || '-1' === $memory_limit ) {
460 // Unlimited, set to 32GB.
461 $memory_limit = '32G';
462 }
463
464 return give_let_to_num( $memory_limit );
465 }
466
467 /**
468 * Maybe process queue
469 *
470 * Checks whether data exists within the queue and that
471 * the process is not already running.
472 */
473 public function maybe_handle() {
474 // Don't lock up other requests while processing
475 session_write_close();
476
477 if ( $this->is_process_running() || $this->is_paused_process() ) {
478 // Background process already running.
479 wp_die();
480 }
481
482 if ( $this->is_queue_empty() ) {
483 // No data to process.
484 wp_die();
485 }
486
487 check_ajax_referer( $this->identifier, 'nonce' );
488
489 $this->handle();
490
491 wp_die();
492 }
493
494 /**
495 * Handle
496 *
497 * Pass each queue item to the task handler, while remaining
498 * within server memory and time limit constraints.
499 */
500 protected function handle() {
501 $this->lock_process();
502
503 do {
504 $batch = $this->get_batch();
505
506 foreach ( $batch->data as $key => $value ) {
507 $task = $this->task( $value );
508
509 if ( false !== $task ) {
510 $batch->data[ $key ] = $task;
511 } else {
512 unset( $batch->data[ $key ] );
513 }
514
515 if ( $this->time_exceeded() || $this->memory_exceeded() ) {
516 // Batch limits reached.
517 break;
518 }
519 }
520
521 // Update or delete current batch.
522 if ( ! empty( $batch->data ) ) {
523 $this->update( $batch->key, $batch->data );
524 } else {
525 $this->delete( $batch->key );
526 }
527 } while ( ! $this->time_exceeded() && ! $this->memory_exceeded() && ! $this->is_queue_empty() );
528
529 $this->unlock_process();
530
531 // Start next batch or complete process.
532 if ( ! $this->is_queue_empty() ) {
533
534 // Dispatch only if ajax works.
535 if( give_test_ajax_works() ) {
536 $this->dispatch();
537 }
538 } else {
539 $this->complete();
540 }
541
542 wp_die();
543 }
544
545
546 /**
547 * Check if backgound upgrade paused or not.
548 *
549 * @since 2.0
550 * @access public
551 * @return bool
552 */
553 public function is_paused_process(){
554 // Delete cache.
555 wp_cache_delete( 'give_paused_batches', 'options' );
556
557 $paused_batches = get_option('give_paused_batches');
558
559 return ! empty( $paused_batches );
560 }
561
562
563 /**
564 * Get identifier
565 *
566 * @since 2.0
567 * @access public
568 * @return mixed|string
569 */
570 public function get_identifier() {
571 return $this->identifier;
572 }
573
574 /**
575 * Get cron identifier
576 *
577 * @since 2.0
578 * @access public
579 * @return mixed|string
580 */
581 public function get_cron_identifier() {
582 return $this->cron_hook_identifier;
583 }
584
585
586 /**
587 * Flush background update related cache to prevent task to go to stalled state.
588 *
589 * @since 2.0.3
590 */
591 public static function flush_cache() {
592
593 $options = array(
594 'give_completed_upgrades',
595 'give_doing_upgrade',
596 'give_paused_batches',
597 'give_upgrade_error',
598 'give_db_update_count',
599 'give_pause_upgrade',
600 'give_show_db_upgrade_complete_notice',
601 );
602
603
604 foreach ( $options as $option ) {
605 wp_cache_delete( $option, 'options' );
606 }
607 }
608 }
609