From 94fb97347f31e4c80ab3e393e9cc68f0aaa89528 Mon Sep 17 00:00:00 2001 From: Tonya Mork Date: Mon, 18 Oct 2021 12:51:00 +0000 Subject: [PATCH] Cron: Fix malformed cron array in `wp_schedule_single_event()` when `_get_cron_array()` returns `false`. In `wp_schedule_single_event()`, the cron info array is retrieved via a call to `_get_cron_array()` and straight away cast to an array. But as the documentation for that function (correctly) states, the return type of that function is `array|false`, where `false` is returned for a site where no cron jobs have been scheduled (yet). In the case that `_get_cron_array()` would return `false`, this would now unintentionally create an array with a single entry with key `0` and as the value `false`. This is a bug. Fixed now by adding validation to the output of `_get_cron_array()` and initializing `$crons` to an empty array if `false` was returned. Tests added first to prove the bug (a) was introduced in #44818 [44917] and (b) is now fixed. Follow-up to [44917]. Props jrf, peterwilsoncc. Fixes #53950. git-svn-id: https://develop.svn.wordpress.org/trunk@51916 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/cron.php | 6 +++++- tests/phpunit/tests/cron.php | 25 ++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php index f4810e55a3..41efeebc44 100644 --- a/src/wp-includes/cron.php +++ b/src/wp-includes/cron.php @@ -118,7 +118,11 @@ function wp_schedule_single_event( $timestamp, $hook, $args = array(), $wp_error * current time) all events scheduled within the next ten minutes * are considered duplicates. */ - $crons = (array) _get_cron_array(); + $crons = _get_cron_array(); + if ( ! is_array( $crons ) ) { + $crons = array(); + } + $key = md5( serialize( $event->args ) ); $duplicate = false; diff --git a/tests/phpunit/tests/cron.php b/tests/phpunit/tests/cron.php index 26453c0111..2940c1708a 100644 --- a/tests/phpunit/tests/cron.php +++ b/tests/phpunit/tests/cron.php @@ -100,7 +100,6 @@ class Tests_Cron extends WP_UnitTestCase { $this->assertSame( $recur, wp_get_schedule( $hook, $args ) ); } - /** * Tests that a call to wp_schedule_event() on a site without any scheduled events * does not result in a PHP deprecation warning on PHP 8.1 or higher. @@ -125,6 +124,30 @@ class Tests_Cron extends WP_UnitTestCase { $this->assertTrue( wp_schedule_event( $timestamp, 'daily', $hook ) ); } + /** + * Tests that a call to wp_schedule_single_event() on a site without any scheduled events + * does not result in the value "false" being added into the cron array. + * + * @ticket 53950 + * + * @covers ::wp_schedule_single_event + */ + function test_wp_schedule_single_event_without_cron_option() { + delete_option( 'cron' ); + + // Verify that the cause of the error is in place. + $this->assertFalse( _get_cron_array(), '_get_cron_array() does not return false' ); + + $hook = __FUNCTION__; + $timestamp = strtotime( '+10 minutes' ); + + // Add an event. + $this->assertTrue( wp_schedule_single_event( $timestamp, $hook ), 'Scheduling single event failed' ); + + // Verify that "false" is not a value in the final cron array. + $this->assertNotContains( false, get_option( 'cron' ), 'Resulting cron array contains the value "false"' ); + } + function test_unschedule_event() { // Schedule an event and make sure it's returned by wp_next_scheduled(). $hook = __FUNCTION__;