Ticket #34913: 0002-a-Fix-issue-34913.patch
| File 0002-a-Fix-issue-34913.patch, 10.0 KB (added by , 10 years ago) |
|---|
-
src/wp-admin/includes/upgrade.php
From 1c26d9a943f0550b87106def2bd947170227562a Mon Sep 17 00:00:00 2001 From: jrfnl <github_nospam@adviesenzo.nl> Date: Sat, 13 Feb 2016 05:36:43 +0100 Subject: [PATCH] Fix issue #34913 "Unscheduling cron jobs fails when original arguments were not an array." --- src/wp-admin/includes/upgrade.php | 6 ++- src/wp-includes/cron.php | 84 +++++++++++++++++++++++----------- tests/phpunit/tests/cron.php | 96 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 158 insertions(+), 28 deletions(-) diff --git a/src/wp-admin/includes/upgrade.php b/src/wp-admin/includes/upgrade.php index 07de246..55041c3 100644
a b function upgrade_440() { 1672 1672 */ 1673 1673 function upgrade_450() { 1674 1674 global $wp_current_db_version; 1675 if ( $wp_current_db_version < 36180 ) 1675 if ( $wp_current_db_version < 36180 ) { 1676 1676 wp_clear_scheduled_hook( 'wp_maybe_auto_update' ); 1677 } 1678 1679 // Getting the cron array will automatically update it to version 3. 1680 _get_cron_array(); 1677 1681 } 1678 1682 1679 1683 /** -
src/wp-includes/cron.php
diff --git a/src/wp-includes/cron.php b/src/wp-includes/cron.php index 493e0ec..58633e5 100644
a b function wp_schedule_single_event( $timestamp, $hook, $args = array()) { 47 47 if ( ! $event ) 48 48 return false; 49 49 50 $event->args = _cron_cast_to_array_helper( $event->args ); 50 51 $key = md5(serialize($event->args)); 51 52 52 53 $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args ); … … function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) { 94 95 if ( ! $event ) 95 96 return false; 96 97 98 $event->args = _cron_cast_to_array_helper( $event->args ); 97 99 $key = md5(serialize($event->args)); 98 100 99 101 $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() ) 120 122 121 123 $crons = _get_cron_array(); 122 124 $schedules = wp_get_schedules(); 123 $key = md5( serialize( $args ) );124 125 $interval = 0; 125 126 126 127 // First we try to get it from the schedule … … function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array() ) 129 130 } 130 131 // Now we try to get it from the saved interval in case the schedule disappears 131 132 if ( 0 == $interval ) { 133 $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) ); 132 134 $interval = $crons[ $timestamp ][ $hook ][ $key ]['interval']; 133 135 } 134 136 // Now we assume something is wrong and fail to schedule … … function wp_unschedule_event( $timestamp, $hook, $args = array() ) { 170 172 } 171 173 172 174 $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 } 179 183 _set_cron_array( $crons ); 180 184 } 181 185 … … function wp_clear_scheduled_hook( $hook, $args = array() ) { 221 225 */ 222 226 function wp_next_scheduled( $hook, $args = array() ) { 223 227 $crons = _get_cron_array(); 224 $key = md5(serialize($args)); 225 if ( empty($crons) ) 228 if ( empty( $crons ) ) { 226 229 return false; 230 } 231 232 $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) ); 227 233 foreach ( $crons as $timestamp => $cron ) { 228 if ( isset( $cron[ $hook][$key] ) )234 if ( isset( $cron[ $hook ][ $key ] ) ) { 229 235 return $timestamp; 236 } 230 237 } 231 238 return false; 232 239 } … … function wp_get_schedules() { 416 423 */ 417 424 function wp_get_schedule($hook, $args = array()) { 418 425 $crons = _get_cron_array(); 419 $key = md5(serialize($args)); 420 if ( empty($crons) ) 426 if ( empty( $crons ) ) { 421 427 return false; 428 } 429 430 $key = md5( serialize( _cron_cast_to_array_helper( $args ) ) ); 422 431 foreach ( $crons as $timestamp => $cron ) { 423 if ( isset( $cron[$hook][$key] ) ) 424 return $cron[$hook][$key]['schedule']; 432 if ( isset( $cron[ $hook ][ $key ] ) ) { 433 return $cron[ $hook ][ $key ]['schedule']; 434 } 425 435 } 426 436 return false; 427 437 } … … function wp_get_schedule($hook, $args = array()) { 439 449 * @return false|array CRON info array. 440 450 */ 441 451 function _get_cron_array() { 442 $cron = get_option( 'cron');443 if ( ! is_array( $cron) )452 $cron = get_option( 'cron' ); 453 if ( ! is_array( $cron ) ) { 444 454 return false; 455 } 445 456 446 if ( !isset($cron['version']) ) 447 $cron = _upgrade_cron_array($cron); 457 if ( ! isset( $cron['version'] ) || 3 > $cron['version'] ) { 458 $cron = _upgrade_cron_array( $cron ); 459 } 448 460 449 unset( $cron['version']);461 unset( $cron['version'] ); 450 462 451 463 return $cron; 452 464 } … … function _get_cron_array() { 460 472 * @param array $cron Cron info array from {@link _get_cron_array()}. 461 473 */ 462 474 function _set_cron_array($cron) { 463 $cron['version'] = 2;475 $cron['version'] = 3; 464 476 update_option( 'cron', $cron ); 465 477 } 466 478 467 479 /** 468 480 * Upgrade a Cron info array. 469 481 * 470 * This function upgrades the Cron info array to version 2.482 * This function upgrades the Cron info array to version 3. 471 483 * 472 484 * @since 2.1.0 473 485 * @access private … … function _set_cron_array($cron) { 476 488 * @return array An upgraded Cron info array. 477 489 */ 478 490 function _upgrade_cron_array($cron) { 479 if ( isset( $cron['version']) && 2 == $cron['version'])491 if ( isset( $cron['version'] ) && 3 === $cron['version'] ) { 480 492 return $cron; 493 } 481 494 482 495 $new_cron = array(); 483 496 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; 497 foreach ( (array) $cron as $timestamp => $hooks ) { 498 foreach ( (array) $hooks as $hook => $event ) { 499 foreach( (array) $event as $args ) { 500 $key = md5( serialize( _cron_cast_to_array_helper( $args['args'] ) ) ); 501 $new_cron[ $timestamp ][ $hook ][ $key ] = $args; 502 } 488 503 } 489 504 } 490 505 491 $new_cron['version'] = 2;506 $new_cron['version'] = 3; 492 507 update_option( 'cron', $new_cron ); 493 508 return $new_cron; 494 509 } 510 511 /** 512 * Compatibility function for consistent casting to array of cron arguments. 513 * 514 * @since 4.5.0 515 * 516 * @param mixed $args Cron arguments. 517 * @return array 518 */ 519 function _cron_cast_to_array_helper( $args ) { 520 if ( is_object( $args ) ) { 521 return array( $args ); 522 } 523 return (array) $args; 524 } 525 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..bc25eb0 100644
a b class Tests_Cron extends WP_UnitTestCase { 189 189 190 190 } 191 191 192 193 /** 194 * @ticket 34913 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 34913 244 * 245 * {@internal Separate test for resources as this one can easily fail to create 246 * the necessary resource and we don't want to skip the other wp_clear_scheduled_hook() 247 * tests if it does.}} 248 * 249 * @expectedDeprecated wp_clear_scheduled_hook 250 */ 251 function test_clear_schedule_resource_arg() { 252 $hook = rand_str(); 253 $arg = tmpfile(); 254 255 if ( $arg === false ) { 256 $this->markTestSkipped( 'Could not create resource.' ); 257 return; 258 } 259 260 // Schedule event with resource argument. 261 wp_schedule_single_event( strtotime('+1 hour'), $hook, $arg ); 262 263 // Make sure they're returned by wp_next_scheduled(). 264 $this->assertTrue( wp_next_scheduled($hook, $arg) > 0 ); 265 266 // Clear the schedule for the event and make sure it's gone. 267 wp_clear_scheduled_hook($hook, $arg ); 268 $this->assertFalse( wp_next_scheduled($hook, $arg) ); 269 270 fclose( $arg ); 271 272 } 273 274 192 275 /** 193 276 * @ticket 6966 194 277 */ … … class WPTestCronRunning extends _WPEmptyBlog { 327 410 } 328 411 } 329 412 */ 413 414 /** 415 * Test class belonging to the `test_clear_schedule_non_array_arg()` test. 416 */ 417 class cronTestClass { 418 public $property_a = 'something'; 419 public $property_b = 123; 420 private $property_c = false; 421 422 public function some_function() { 423 return true; 424 } 425 }