WordPress.org

Make WordPress Core

Ticket #34913: 0002-b-Fix-issue-34913-with-doing-it-wrong-refreshed.patch

File 0002-b-Fix-issue-34913-with-doing-it-wrong-refreshed.patch, 12.3 KB (added by jrf, 4 years ago)

Refreshed against current master

  • src/wp-admin/includes/upgrade.php

    ---
     src/wp-admin/includes/upgrade.php |   3 ++
     src/wp-includes/cron.php          | 108 ++++++++++++++++++++++++++++----------
     tests/phpunit/tests/cron.php      | 100 +++++++++++++++++++++++++++++++++++
     3 files changed, 184 insertions(+), 27 deletions(-)
    
    diff --git a/src/wp-admin/includes/upgrade.php b/src/wp-admin/includes/upgrade.php
    index e09d42a..649847c 100644
    a b function upgrade_450() { 
    16821682        if ( $wp_current_db_version < 36679 && is_multisite() ) {
    16831683                $wpdb->query( "DELETE FROM $wpdb->options WHERE option_name REGEXP '^[0-9]+_new_email$'" );
    16841684        }
     1685       
     1686        // Getting the cron array will automatically update it to version 3.
     1687        _get_cron_array();
    16851688}
    16861689
    16871690/**
  • src/wp-includes/cron.php

    diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php
    index 493e0ec..e823026 100644
    a b  
    2121 * @return false|void False when an event is not scheduled.
    2222 */
    2323function wp_schedule_single_event( $timestamp, $hook, $args = array()) {
     24        if ( ! is_array( $args ) ) {
     25                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     26        }
     27
    2428        // Make sure timestamp is a positive integer
    2529        if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    2630                return false;
    function wp_schedule_single_event( $timestamp, $hook, $args = array()) { 
    4751        if ( ! $event )
    4852                return false;
    4953
     54        $event->args = _cron_cast_to_array_helper( $event->args );
    5055        $key = md5(serialize($event->args));
    5156
    5257        $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
    function wp_schedule_single_event( $timestamp, $hook, $args = array()) { 
    7580 * @return false|void False when an event is not scheduled.
    7681 */
    7782function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
     83        if ( ! is_array( $args ) ) {
     84                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     85        }
     86
    7887        // Make sure timestamp is a positive integer
    7988        if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    8089                return false;
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { 
    94103        if ( ! $event )
    95104                return false;
    96105
     106        $event->args = _cron_cast_to_array_helper( $event->args );
    97107        $key = md5(serialize($event->args));
    98108
    99109        $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
    function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { 
    113123 * @return false|void False when an event is not scheduled.
    114124 */
    115125function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) {
     126        if ( ! is_array( $args ) ) {
     127                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     128        }
     129
    116130        // Make sure timestamp is a positive integer
    117131        if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    118132                return false;
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    120134
    121135        $crons = _get_cron_array();
    122136        $schedules = wp_get_schedules();
    123         $key = md5( serialize( $args ) );
    124137        $interval = 0;
    125138
    126139        // First we try to get it from the schedule
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    129142        }
    130143        // Now we try to get it from the saved interval in case the schedule disappears
    131144        if ( 0 == $interval ) {
     145                $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    132146                $interval = $crons[ $timestamp ][ $hook ][ $key ]['interval'];
    133147        }
    134148        // Now we assume something is wrong and fail to schedule
    function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 
    164178 * @return false|void False when an event is not unscheduled.
    165179 */
    166180function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
     181        if ( ! is_array( $args ) ) {
     182                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     183        }
     184
    167185        // Make sure timestamp is a positive integer
    168186        if ( ! is_numeric( $timestamp ) || $timestamp <= 0 ) {
    169187                return false;
    170188        }
    171189
    172190        $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] );
     191        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
     192        unset( $crons[ $timestamp ][ $hook ][ $key ] );
     193        if ( empty( $crons[ $timestamp ][ $hook ] ) ) {
     194                unset( $crons[ $timestamp ][ $hook ] );
     195        }
     196        if ( empty( $crons[ $timestamp ] ) ) {
     197                unset( $crons[ $timestamp ] );
     198        }
    179199        _set_cron_array( $crons );
    180200}
    181201
    function wp_clear_scheduled_hook( $hook, $args = array() ) { 
    220240 * @return false|int The UNIX timestamp of the next time the scheduled event will occur.
    221241 */
    222242function wp_next_scheduled( $hook, $args = array() ) {
     243        if ( ! is_array( $args ) ) {
     244                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     245        }
     246
    223247        $crons = _get_cron_array();
    224         $key = md5(serialize($args));
    225         if ( empty($crons) )
     248        if ( empty( $crons ) ) {
    226249                return false;
     250        }
     251
     252        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    227253        foreach ( $crons as $timestamp => $cron ) {
    228                 if ( isset( $cron[$hook][$key] ) )
     254                if ( isset( $cron[ $hook ][ $key ] ) ) {
    229255                        return $timestamp;
     256                }
    230257        }
    231258        return false;
    232259}
    function wp_get_schedules() { 
    415442 * @return string|false False, if no schedule. Schedule on success.
    416443 */
    417444function wp_get_schedule($hook, $args = array()) {
     445        if ( ! is_array( $args ) ) {
     446                _doing_it_wrong( __FUNCTION__, __( 'Cron arguments are expected to be an array. Please update your function call.' ), '2.1.0' );
     447        }
     448
    418449        $crons = _get_cron_array();
    419         $key = md5(serialize($args));
    420         if ( empty($crons) )
     450        if ( empty( $crons ) ) {
    421451                return false;
     452        }
     453
     454        $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) );
    422455        foreach ( $crons as $timestamp => $cron ) {
    423                 if ( isset( $cron[$hook][$key] ) )
    424                         return $cron[$hook][$key]['schedule'];
     456                if ( isset( $cron[ $hook ][ $key ] ) ) {
     457                        return $cron[ $hook ][ $key ]['schedule'];
     458                }
    425459        }
    426460        return false;
    427461}
    function wp_get_schedule($hook, $args = array()) { 
    439473 * @return false|array CRON info array.
    440474 */
    441475function _get_cron_array()  {
    442         $cron = get_option('cron');
    443         if ( ! is_array($cron) )
     476        $cron = get_option( 'cron' );
     477        if ( ! is_array( $cron ) ) {
    444478                return false;
     479        }
    445480
    446         if ( !isset($cron['version']) )
    447                 $cron = _upgrade_cron_array($cron);
     481        if ( ! isset( $cron['version'] ) || 3 > $cron['version'] ) {
     482                $cron = _upgrade_cron_array( $cron );
     483        }
    448484
    449         unset($cron['version']);
     485        unset( $cron['version'] );
    450486
    451487        return $cron;
    452488}
    function _get_cron_array() { 
    460496 * @param array $cron Cron info array from {@link _get_cron_array()}.
    461497 */
    462498function _set_cron_array($cron) {
    463         $cron['version'] = 2;
     499        $cron['version'] = 3;
    464500        update_option( 'cron', $cron );
    465501}
    466502
    467503/**
    468504 * Upgrade a Cron info array.
    469505 *
    470  * This function upgrades the Cron info array to version 2.
     506 * This function upgrades the Cron info array to version 3.
    471507 *
    472508 * @since 2.1.0
    473509 * @access private
    function _set_cron_array($cron) { 
    476512 * @return array An upgraded Cron info array.
    477513 */
    478514function _upgrade_cron_array($cron) {
    479         if ( isset($cron['version']) && 2 == $cron['version'])
     515        if ( isset( $cron['version'] ) && 3 === $cron['version'] ) {
    480516                return $cron;
     517        }
    481518
    482519        $new_cron = array();
    483520
    484         foreach ( (array) $cron as $timestamp => $hooks) {
    485                 foreach ( (array) $hooks as $hook => $args ) {
    486                         $key = md5(serialize($args['args']));
    487                         $new_cron[$timestamp][$hook][$key] = $args;
     521        foreach ( (array) $cron as $timestamp => $hooks ) {
     522                foreach ( (array) $hooks as $hook => $event ) {
     523                        foreach( (array) $event as $args ) {
     524                                $key = md5( serialize( _cron_cast_to_array_helper( $args['args'] ) ) );
     525                                $new_cron[ $timestamp ][ $hook ][ $key ] = $args;
     526                        }
    488527                }
    489528        }
    490529
    491         $new_cron['version'] = 2;
     530        $new_cron['version'] = 3;
    492531        update_option( 'cron', $new_cron );
    493532        return $new_cron;
    494533}
     534
     535/**
     536 * Compatibility function for consistent casting to array of cron arguments.
     537 *
     538 * @since 4.5.0
     539 *
     540 * @param mixed $args Cron arguments.
     541 * @return array
     542 */
     543function _cron_cast_to_array_helper( $args ) {
     544        if ( is_object( $args ) ) {
     545                return array( $args );
     546        }
     547        return (array) $args;
     548}
     549 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..390f00c 100644
    a b class Tests_Cron extends WP_UnitTestCase { 
    189189
    190190        }
    191191
     192
     193        /**
     194         * @ticket 34913
     195         *
     196         * @expectedDeprecated wp_clear_scheduled_hook
     197         * @expectedIncorrectUsage wp_schedule_single_event
     198         * @expectedIncorrectUsage wp_next_scheduled
     199         */
     200        function test_clear_schedule_non_array_args() {
     201                $hook = rand_str();
     202                $bool_arg = true;
     203                $int_arg = mt_rand();
     204                $float_arg = mt_rand() / mt_getrandmax();
     205                $string_arg = rand_str();
     206                $obj_arg = new cronTestClass();
     207
     208                // Schedule several events with non-array arguments.
     209                wp_schedule_single_event( strtotime('+1 hour'), $hook, $bool_arg );
     210                wp_schedule_single_event( strtotime('+2 hour'), $hook, $int_arg );
     211                wp_schedule_single_event( strtotime('+3 hour'), $hook, $float_arg );
     212                wp_schedule_single_event( strtotime('+4 hour'), $hook, $string_arg );
     213                wp_schedule_single_event( strtotime('+5 hour'), $hook, $obj_arg );
     214
     215                // Make sure they're returned by wp_next_scheduled().
     216                $this->assertTrue( wp_next_scheduled($hook, $bool_arg) > 0 );
     217                $this->assertTrue( wp_next_scheduled($hook, $int_arg) > 0 );
     218                $this->assertTrue( wp_next_scheduled($hook, $float_arg) > 0 );
     219                $this->assertTrue( wp_next_scheduled($hook, $string_arg) > 0 );
     220                $this->assertTrue( wp_next_scheduled($hook, $obj_arg) > 0 );
     221
     222                // Clear the schedule for the bool_arg event and make sure it's gone.
     223                wp_clear_scheduled_hook($hook, $bool_arg );
     224                $this->assertFalse( wp_next_scheduled($hook, $bool_arg) );
     225
     226                // Clear the schedule for the int_arg event and make sure it's gone.
     227                wp_clear_scheduled_hook($hook, $int_arg );
     228                $this->assertFalse( wp_next_scheduled($hook, $int_arg) );
     229
     230                // Clear the schedule for the float_arg event and make sure it's gone.
     231                wp_clear_scheduled_hook($hook, $float_arg );
     232                $this->assertFalse( wp_next_scheduled($hook, $float_arg) );
     233
     234                // Clear the schedule for the string_arg event and make sure it's gone.
     235                wp_clear_scheduled_hook($hook, $string_arg );
     236                $this->assertFalse( wp_next_scheduled($hook, $string_arg) );
     237
     238                // Clear the schedule for the object_arg event and make sure it's gone.
     239                wp_clear_scheduled_hook($hook, $obj_arg );
     240                $this->assertFalse( wp_next_scheduled($hook, $obj_arg) );
     241
     242        }
     243
     244        /**
     245         * @ticket 34913
     246         *
     247         * {@internal Separate test for resources as this one can easily fail to create
     248         * the necessary resource and we don't want to skip the other wp_clear_scheduled_hook()
     249         * tests if it does.}}
     250         *
     251         * @expectedDeprecated wp_clear_scheduled_hook
     252         * @expectedIncorrectUsage wp_schedule_single_event
     253         * @expectedIncorrectUsage wp_next_scheduled
     254         */
     255        function test_clear_schedule_resource_arg() {
     256                $hook = rand_str();
     257                $arg = tmpfile();
     258
     259                if ( $arg === false ) {
     260                        $this->markTestSkipped( 'Could not create resource.' );
     261                        return;
     262                }
     263
     264                // Schedule event with resource argument.
     265                wp_schedule_single_event( strtotime('+1 hour'), $hook, $arg );
     266
     267                // Make sure they're returned by wp_next_scheduled().
     268                $this->assertTrue( wp_next_scheduled($hook, $arg) > 0 );
     269
     270                // Clear the schedule for the event and make sure it's gone.
     271                wp_clear_scheduled_hook($hook, $arg );
     272                $this->assertFalse( wp_next_scheduled($hook, $arg) );
     273               
     274                fclose( $arg );
     275
     276        }
     277
     278
    192279        /**
    193280         * @ticket 6966
    194281         */
    class WPTestCronRunning extends _WPEmptyBlog { 
    327414        }
    328415}
    329416*/
     417
     418/**
     419 * Test class belonging to the `test_clear_schedule_non_array_arg()` test.
     420 */
     421class cronTestClass {
     422        public $property_a = 'something';
     423        public $property_b = 123;
     424        private $property_c = false;
     425
     426        public function some_function() {
     427                return true;
     428        }
     429}