WordPress.org

Make WordPress Core

Ticket #34913: 0001-Fix-issue-34913.patch

File 0001-Fix-issue-34913.patch, 9.2 KB (added by jrf, 4 years ago)
  • src/wp-includes/cron.php

    From 21cc58d06684e74713ae095b3dbafa361f014a2c Mon Sep 17 00:00:00 2001
    From: jrfnl <github_nospam@adviesenzo.nl>
    Date: Tue, 8 Dec 2015 14:30:12 +0100
    Subject: [PATCH] Fix issue #34913 "Unscheduling cron jobs fails when original
     arguments were not an array."
    
    ---
     src/wp-includes/cron.php     | 76 ++++++++++++++++++++++-------------
     tests/phpunit/tests/cron.php | 95 ++++++++++++++++++++++++++++++++++++++++++++
     2 files changed, 144 insertions(+), 27 deletions(-)
    
    diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php
    index 60492c5..8dbc2b1 100644
    a b function wp_schedule_single_event( $timestamp, $hook, $args = array()) { 
    4747        if ( ! $event )
    4848                return false;
    4949
     50        $event->args = _cron_cast_to_array_helper( $event->args );
    5051        $key = md5(serialize($event->args));
    5152
    5253        $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { 
    9495        if ( ! $event )
    9596                return false;
    9697
     98        $event->args = _cron_cast_to_array_helper( $event->args );
    9799        $key = md5(serialize($event->args));
    98100
    99101        $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    120122
    121123        $crons = _get_cron_array();
    122124        $schedules = wp_get_schedules();
    123         $key = md5( serialize( $args ) );
    124125        $interval = 0;
    125126
    126127        // First we try to get it from the schedule
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    129130        }
    130131        // Now we try to get it from the saved interval in case the schedule disappears
    131132        if ( 0 == $interval ) {
     133                $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    132134                $interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
    133135        }
    134136        // Now we assume something is wrong and fail to schedule
    function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 
    170172        }
    171173
    172174        $crons = _get_cron_array();
    173         $key = md5(serialize($args));
    174         unset( $crons[$timestamp][$hook][$key] );
    175         if ( empty($crons[$timestamp][$hook]) )
    176                 unset( $crons[$timestamp][$hook] );
    177         if ( empty($crons[$timestamp]) )
    178                 unset( $crons[$timestamp] );
     175        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
     176        unset( $crons[ $timestamp ][ $hook ][ $key ] );
     177        if ( empty( $crons[ $timestamp ][ $hook ] ) ) {
     178                unset( $crons[ $timestamp ][ $hook ] );
     179        }
     180        if ( empty( $crons[ $timestamp ] ) ) {
     181                unset( $crons[ $timestamp ] );
     182        }
    179183        _set_cron_array( $crons );
    180184}
    181185
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    221225 */
    222226function wp_next_scheduled( $hook, $args = array() ) {
    223227        $crons = _get_cron_array();
    224         $key = md5(serialize($args));
    225         if ( empty($crons) )
     228        if ( empty( $crons ) ) {
    226229                return false;
     230        }
     231
     232        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    227233        foreach ( $crons as $timestamp => $cron ) {
    228                 if ( isset( $cron[$hook][$key] ) )
     234                if ( isset( $cron[ $hook ][ $key ] ) ) {
    229235                        return $timestamp;
     236                }
    230237        }
    231238        return false;
    232239}
    function wp_get_schedules() { 
    412419 */
    413420function wp_get_schedule($hook, $args = array()) {
    414421        $crons = _get_cron_array();
    415         $key = md5(serialize($args));
    416         if ( empty($crons) )
     422        if ( empty( $crons ) ) {
    417423                return false;
     424        }
     425
     426        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    418427        foreach ( $crons as $timestamp => $cron ) {
    419                 if ( isset( $cron[$hook][$key] ) )
    420                         return $cron[$hook][$key]['schedule'];
     428                if ( isset( $cron[ $hook ][ $key ] ) ) {
     429                        return $cron[ $hook ][ $key ]['schedule'];
     430                }
    421431        }
    422432        return false;
    423433}
    function wp_get_schedule($hook, $args = array()) { 
    435445 * @return false|array CRON info array.
    436446 */
    437447function _get_cron_array()  {
    438         $cron = get_option('cron');
    439         if ( ! is_array($cron) )
     448        $cron = get_option( 'cron' );
     449        if ( ! is_array( $cron ) ) {
    440450                return false;
     451        }
    441452
    442         if ( !isset($cron['version']) )
    443                 $cron = _upgrade_cron_array($cron);
     453        if ( ! isset( $cron['version'] ) || 3 > $cron['version'] ) {
     454                $cron = _upgrade_cron_array( $cron );
     455        }
    444456
    445         unset($cron['version']);
     457        unset( $cron['version'] );
    446458
    447459        return $cron;
    448460}
    function _get_cron_array() { 
    456468 * @param array $cron Cron info array from {@link _get_cron_array()}.
    457469 */
    458470function _set_cron_array($cron) {
    459         $cron['version'] = 2;
     471        $cron['version'] = 3;
    460472        update_option( 'cron', $cron );
    461473}
    462474
    463475/**
    464476 * Upgrade a Cron info array.
    465477 *
    466  * This function upgrades the Cron info array to version 2.
     478 * This function upgrades the Cron info array to version 3.
    467479 *
    468480 * @since 2.1.0
    469481 * @access private
    function _set_cron_array($cron) { 
    472484 * @return array An upgraded Cron info array.
    473485 */
    474486function _upgrade_cron_array($cron) {
    475         if ( isset($cron['version']) && 2 == $cron['version'])
     487        if ( isset( $cron['version'] ) && 3 === $cron['version'] ) {
    476488                return $cron;
     489        }
    477490
    478491        $new_cron = array();
    479492
    480         foreach ( (array) $cron as $timestamp => $hooks) {
    481                 foreach ( (array) $hooks as $hook => $args ) {
    482                         $key = md5(serialize($args['args']));
    483                         $new_cron[$timestamp][$hook][$key] = $args;
     493        foreach ( (array) $cron as $timestamp => $hooks ) {
     494                foreach ( (array) $hooks as $hook => $event ) {
     495                        foreach( (array) $event as $args ) {
     496                                $key = md5( serialize( _cron_cast_to_array_helper( $args['args'] ) ) );
     497                                $new_cron[ $timestamp ][ $hook ][ $key ] = $args;
     498                        }
    484499                }
    485500        }
    486501
    487         $new_cron['version'] = 2;
     502        $new_cron['version'] = 3;
    488503        update_option( 'cron', $new_cron );
    489504        return $new_cron;
    490505}
     506
     507function _cron_cast_to_array_helper( $args ) {
     508        if ( is_object( $args ) ) {
     509                return array( $args );
     510        }
     511        return (array) $args;
     512}
     513 No newline at end of file
  • tests/phpunit/tests/cron.php

    diff --git a/tests/phpunit/tests/cron.php b/tests/phpunit/tests/cron.php
    index b411a5b..967ddb5 100644
    a b class Tests_Cron extends WP_UnitTestCase { 
    189189
    190190        }
    191191
     192
     193        /**
     194         * @ticket ....
     195         *
     196         * @expectedDeprecated wp_clear_scheduled_hook
     197         */
     198        function test_clear_schedule_non_array_args() {
     199                $hook = rand_str();
     200                $bool_arg = true;
     201                $int_arg = mt_rand();
     202                $float_arg = mt_rand() / mt_getrandmax();
     203                $string_arg = rand_str();
     204                $obj_arg = new cronTestClass();
     205
     206                // Schedule several events with non-array arguments.
     207                wp_schedule_single_event( strtotime('+1 hour'), $hook, $bool_arg );
     208                wp_schedule_single_event( strtotime('+2 hour'), $hook, $int_arg );
     209                wp_schedule_single_event( strtotime('+3 hour'), $hook, $float_arg );
     210                wp_schedule_single_event( strtotime('+4 hour'), $hook, $string_arg );
     211                wp_schedule_single_event( strtotime('+5 hour'), $hook, $obj_arg );
     212
     213                // Make sure they're returned by wp_next_scheduled().
     214                $this->assertTrue( wp_next_scheduled($hook, $bool_arg) > 0 );
     215                $this->assertTrue( wp_next_scheduled($hook, $int_arg) > 0 );
     216                $this->assertTrue( wp_next_scheduled($hook, $float_arg) > 0 );
     217                $this->assertTrue( wp_next_scheduled($hook, $string_arg) > 0 );
     218                $this->assertTrue( wp_next_scheduled($hook, $obj_arg) > 0 );
     219
     220                // Clear the schedule for the bool_arg event and make sure it's gone.
     221                wp_clear_scheduled_hook($hook, $bool_arg );
     222                $this->assertFalse( wp_next_scheduled($hook, $bool_arg) );
     223
     224                // Clear the schedule for the int_arg event and make sure it's gone.
     225                wp_clear_scheduled_hook($hook, $int_arg );
     226                $this->assertFalse( wp_next_scheduled($hook, $int_arg) );
     227
     228                // Clear the schedule for the float_arg event and make sure it's gone.
     229                wp_clear_scheduled_hook($hook, $float_arg );
     230                $this->assertFalse( wp_next_scheduled($hook, $float_arg) );
     231
     232                // Clear the schedule for the string_arg event and make sure it's gone.
     233                wp_clear_scheduled_hook($hook, $string_arg );
     234                $this->assertFalse( wp_next_scheduled($hook, $string_arg) );
     235
     236                // Clear the schedule for the object_arg event and make sure it's gone.
     237                wp_clear_scheduled_hook($hook, $obj_arg );
     238                $this->assertFalse( wp_next_scheduled($hook, $obj_arg) );
     239
     240        }
     241
     242        /**
     243         * @ticket ....
     244         *
     245         * @internal Separate test for resources as this one can easily fail and we don't want to skip the
     246         * complete group of tests if it does.
     247         *
     248         * @expectedDeprecated wp_clear_scheduled_hook
     249         */
     250        function test_clear_schedule_resource_arg() {
     251                $hook = rand_str();
     252                $arg = tmpfile();
     253
     254                if ( $arg === false ) {
     255                        $this->markTestSkipped( 'Could not create resource.' );
     256                        return;
     257                }
     258
     259                // Schedule event with resource argument.
     260                wp_schedule_single_event( strtotime('+1 hour'), $hook, $arg );
     261
     262                // Make sure they're returned by wp_next_scheduled().
     263                $this->assertTrue( wp_next_scheduled($hook, $arg) > 0 );
     264
     265                // Clear the schedule for the event and make sure it's gone.
     266                wp_clear_scheduled_hook($hook, $arg );
     267                $this->assertFalse( wp_next_scheduled($hook, $arg) );
     268               
     269                fclose( $arg );
     270
     271        }
     272
     273
    192274        /**
    193275         * @ticket 6966
    194276         */
    class WPTestCronRunning extends _WPEmptyBlog { 
    327409        }
    328410}
    329411*/
     412
     413/**
     414 * Test class belonging to the `test_clear_schedule_non_array_arg()` test.
     415 */
     416class cronTestClass {
     417        public $property_a = 'something';
     418        public $property_b = 123;
     419        private $property_c = false;
     420
     421        public function some_function() {
     422                return true;
     423        }
     424}