From fff2440ba5b05e3846a76ea5dc3a1dc552670f9b Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Sat, 16 Mar 2019 06:42:50 +0000 Subject: [PATCH] Cron: Ensure identical single events aren't scheduled less than 10min apart. Improves the logic in `wp_schedule_single_event()` to ensure an identical event is not scheduled within ten minutes. This moves the logic for checking for identical events to be self contained rather than relying on `wp_next_scheduled()` as this fails to account for events with a past timestamp when wp-cron fails to trigger or for multiple identical events being scheduled already. Props bodohugobarwich. Fixes #44818. Built from https://develop.svn.wordpress.org/trunk@44917 git-svn-id: http://core.svn.wordpress.org/trunk@44748 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-includes/cron.php | 49 ++++++++++++++++++++++++++++++++++++----- wp-includes/version.php | 2 +- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/wp-includes/cron.php b/wp-includes/cron.php index dd348784b9..bd6138256c 100644 --- a/wp-includes/cron.php +++ b/wp-includes/cron.php @@ -79,9 +79,49 @@ function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { return $pre; } - // Don't schedule a duplicate if there's already an identical event due within 10 minutes of it - $next = wp_next_scheduled( $hook, $args ); - if ( $next && abs( $next - $timestamp ) <= 10 * MINUTE_IN_SECONDS ) { + /* + * Check for a duplicated event. + * + * Don't schedule an event if there's already an identical event + * within 10 minutes. + * + * When scheduling events within ten minutes of the current time, + * all past identical events are considered duplicates. + * + * When scheduling an event with a past timestamp (ie, before the + * current time) all events scheduled within the next ten minutes + * are considered duplicates. + */ + $crons = (array) _get_cron_array(); + $key = md5( serialize( $event->args ) ); + $duplicate = false; + + if ( $event->timestamp < time() + 10 * MINUTE_IN_SECONDS ) { + $min_timestamp = 0; + } else { + $min_timestamp = $event->timestamp - 10 * MINUTE_IN_SECONDS; + } + + if ( $event->timestamp < time() ) { + $max_timestamp = time() + 10 * MINUTE_IN_SECONDS; + } else { + $max_timestamp = $event->timestamp + 10 * MINUTE_IN_SECONDS; + } + + foreach ( $crons as $event_timestamp => $cron ) { + if ( $event_timestamp < $min_timestamp ) { + continue; + } + if ( $event_timestamp > $max_timestamp ) { + break; + } + if ( isset( $cron[ $event->hook ][ $key ] ) ) { + $duplicate = true; + break; + } + } + + if ( $duplicate ) { return false; } @@ -107,9 +147,6 @@ function wp_schedule_single_event( $timestamp, $hook, $args = array() ) { return false; } - $key = md5( serialize( $event->args ) ); - - $crons = _get_cron_array(); $crons[ $event->timestamp ][ $event->hook ][ $key ] = array( 'schedule' => $event->schedule, 'args' => $event->args, diff --git a/wp-includes/version.php b/wp-includes/version.php index f9811736a7..f8bc63a916 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -13,7 +13,7 @@ * * @global string $wp_version */ -$wp_version = '5.2-alpha-44916'; +$wp_version = '5.2-alpha-44917'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.