wp/wp-includes/cron.php
changeset 0 d970ebf37754
child 5 5e2f62d02dcd
equal deleted inserted replaced
-1:000000000000 0:d970ebf37754
       
     1 <?php
       
     2 /**
       
     3  * WordPress CRON API
       
     4  *
       
     5  * @package WordPress
       
     6  */
       
     7 
       
     8 /**
       
     9  * Schedules a hook to run only once.
       
    10  *
       
    11  * Schedules a hook which will be executed once by the WordPress actions core at
       
    12  * a time which you specify. The action will fire off when someone visits your
       
    13  * WordPress site, if the schedule time has passed.
       
    14  *
       
    15  * @since 2.1.0
       
    16  * @link http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
       
    17  *
       
    18  * @param int $timestamp Timestamp for when to run the event.
       
    19  * @param string $hook Action hook to execute when cron is run.
       
    20  * @param array $args Optional. Arguments to pass to the hook's callback function.
       
    21  */
       
    22 function wp_schedule_single_event( $timestamp, $hook, $args = array()) {
       
    23 	// don't schedule a duplicate if there's already an identical event due in the next 10 minutes
       
    24 	$next = wp_next_scheduled($hook, $args);
       
    25 	if ( $next && $next <= $timestamp + 10 * MINUTE_IN_SECONDS )
       
    26 		return;
       
    27 
       
    28 	$crons = _get_cron_array();
       
    29 	$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => false, 'args' => $args );
       
    30 	$event = apply_filters('schedule_event', $event);
       
    31 
       
    32 	// A plugin disallowed this event
       
    33 	if ( ! $event )
       
    34 		return false;
       
    35 
       
    36 	$key = md5(serialize($event->args));
       
    37 
       
    38 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
       
    39 	uksort( $crons, "strnatcasecmp" );
       
    40 	_set_cron_array( $crons );
       
    41 }
       
    42 
       
    43 /**
       
    44  * Schedule a periodic event.
       
    45  *
       
    46  * Schedules a hook which will be executed by the WordPress actions core on a
       
    47  * specific interval, specified by you. The action will trigger when someone
       
    48  * visits your WordPress site, if the scheduled time has passed.
       
    49  *
       
    50  * Valid values for the recurrence are hourly, daily and twicedaily. These can
       
    51  * be extended using the cron_schedules filter in wp_get_schedules().
       
    52  *
       
    53  * Use wp_next_scheduled() to prevent duplicates
       
    54  *
       
    55  * @since 2.1.0
       
    56  *
       
    57  * @param int $timestamp Timestamp for when to run the event.
       
    58  * @param string $recurrence How often the event should recur.
       
    59  * @param string $hook Action hook to execute when cron is run.
       
    60  * @param array $args Optional. Arguments to pass to the hook's callback function.
       
    61  * @return bool|null False on failure, null when complete with scheduling event.
       
    62  */
       
    63 function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
       
    64 	$crons = _get_cron_array();
       
    65 	$schedules = wp_get_schedules();
       
    66 
       
    67 	if ( !isset( $schedules[$recurrence] ) )
       
    68 		return false;
       
    69 
       
    70 	$event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
       
    71 	$event = apply_filters('schedule_event', $event);
       
    72 
       
    73 	// A plugin disallowed this event
       
    74 	if ( ! $event )
       
    75 		return false;
       
    76 
       
    77 	$key = md5(serialize($event->args));
       
    78 
       
    79 	$crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
       
    80 	uksort( $crons, "strnatcasecmp" );
       
    81 	_set_cron_array( $crons );
       
    82 }
       
    83 
       
    84 /**
       
    85  * Reschedule a recurring event.
       
    86  *
       
    87  * @since 2.1.0
       
    88  *
       
    89  * @param int $timestamp Timestamp for when to run the event.
       
    90  * @param string $recurrence How often the event should recur.
       
    91  * @param string $hook Action hook to execute when cron is run.
       
    92  * @param array $args Optional. Arguments to pass to the hook's callback function.
       
    93  * @return bool|null False on failure. Null when event is rescheduled.
       
    94  */
       
    95 function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) {
       
    96 	$crons = _get_cron_array();
       
    97 	$schedules = wp_get_schedules();
       
    98 	$key = md5(serialize($args));
       
    99 	$interval = 0;
       
   100 
       
   101 	// First we try to get it from the schedule
       
   102 	if ( 0 == $interval )
       
   103 		$interval = $schedules[$recurrence]['interval'];
       
   104 	// Now we try to get it from the saved interval in case the schedule disappears
       
   105 	if ( 0 == $interval )
       
   106 		$interval = $crons[$timestamp][$hook][$key]['interval'];
       
   107 	// Now we assume something is wrong and fail to schedule
       
   108 	if ( 0 == $interval )
       
   109 		return false;
       
   110 
       
   111 	$now = time();
       
   112 
       
   113 	if ( $timestamp >= $now )
       
   114 		$timestamp = $now + $interval;
       
   115 	else
       
   116 		$timestamp = $now + ($interval - (($now - $timestamp) % $interval));
       
   117 
       
   118 	wp_schedule_event( $timestamp, $recurrence, $hook, $args );
       
   119 }
       
   120 
       
   121 /**
       
   122  * Unschedule a previously scheduled cron job.
       
   123  *
       
   124  * The $timestamp and $hook parameters are required, so that the event can be
       
   125  * identified.
       
   126  *
       
   127  * @since 2.1.0
       
   128  *
       
   129  * @param int $timestamp Timestamp for when to run the event.
       
   130  * @param string $hook Action hook, the execution of which will be unscheduled.
       
   131  * @param array $args Arguments to pass to the hook's callback function.
       
   132  * Although not passed to a callback function, these arguments are used
       
   133  * to uniquely identify the scheduled event, so they should be the same
       
   134  * as those used when originally scheduling the event.
       
   135  */
       
   136 function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
       
   137 	$crons = _get_cron_array();
       
   138 	$key = md5(serialize($args));
       
   139 	unset( $crons[$timestamp][$hook][$key] );
       
   140 	if ( empty($crons[$timestamp][$hook]) )
       
   141 		unset( $crons[$timestamp][$hook] );
       
   142 	if ( empty($crons[$timestamp]) )
       
   143 		unset( $crons[$timestamp] );
       
   144 	_set_cron_array( $crons );
       
   145 }
       
   146 
       
   147 /**
       
   148  * Unschedule all cron jobs attached to a specific hook.
       
   149  *
       
   150  * @since 2.1.0
       
   151  *
       
   152  * @param string $hook Action hook, the execution of which will be unscheduled.
       
   153  * @param array $args Optional. Arguments that were to be pass to the hook's callback function.
       
   154  */
       
   155 function wp_clear_scheduled_hook( $hook, $args = array() ) {
       
   156 	// Backward compatibility
       
   157 	// Previously this function took the arguments as discrete vars rather than an array like the rest of the API
       
   158 	if ( !is_array($args) ) {
       
   159 		_deprecated_argument( __FUNCTION__, '3.0', __('This argument has changed to an array to match the behavior of the other cron functions.') );
       
   160 		$args = array_slice( func_get_args(), 1 );
       
   161 	}
       
   162 
       
   163 	while ( $timestamp = wp_next_scheduled( $hook, $args ) )
       
   164 		wp_unschedule_event( $timestamp, $hook, $args );
       
   165 }
       
   166 
       
   167 /**
       
   168  * Retrieve the next timestamp for a cron event.
       
   169  *
       
   170  * @since 2.1.0
       
   171  *
       
   172  * @param string $hook Action hook to execute when cron is run.
       
   173  * @param array $args Optional. Arguments to pass to the hook's callback function.
       
   174  * @return bool|int The UNIX timestamp of the next time the scheduled event will occur.
       
   175  */
       
   176 function wp_next_scheduled( $hook, $args = array() ) {
       
   177 	$crons = _get_cron_array();
       
   178 	$key = md5(serialize($args));
       
   179 	if ( empty($crons) )
       
   180 		return false;
       
   181 	foreach ( $crons as $timestamp => $cron ) {
       
   182 		if ( isset( $cron[$hook][$key] ) )
       
   183 			return $timestamp;
       
   184 	}
       
   185 	return false;
       
   186 }
       
   187 
       
   188 /**
       
   189  * Send request to run cron through HTTP request that doesn't halt page loading.
       
   190  *
       
   191  * @since 2.1.0
       
   192  *
       
   193  * @return null Cron could not be spawned, because it is not needed to run.
       
   194  */
       
   195 function spawn_cron( $gmt_time = 0 ) {
       
   196 
       
   197 	if ( ! $gmt_time )
       
   198 		$gmt_time = microtime( true );
       
   199 
       
   200 	if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) )
       
   201 		return;
       
   202 
       
   203 	/*
       
   204 	* multiple processes on multiple web servers can run this code concurrently
       
   205 	* try to make this as atomic as possible by setting doing_cron switch
       
   206 	*/
       
   207 	$lock = get_transient('doing_cron');
       
   208 
       
   209 	if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS )
       
   210 		$lock = 0;
       
   211 
       
   212 	// don't run if another process is currently running it or more than once every 60 sec.
       
   213 	if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
       
   214 		return;
       
   215 
       
   216 	//sanity check
       
   217 	$crons = _get_cron_array();
       
   218 	if ( !is_array($crons) )
       
   219 		return;
       
   220 
       
   221 	$keys = array_keys( $crons );
       
   222 	if ( isset($keys[0]) && $keys[0] > $gmt_time )
       
   223 		return;
       
   224 
       
   225 	if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ) {
       
   226 		if ( !empty($_POST) || defined('DOING_AJAX') )
       
   227 			return;
       
   228 
       
   229 		$doing_wp_cron = sprintf( '%.22F', $gmt_time );
       
   230 		set_transient( 'doing_cron', $doing_wp_cron );
       
   231 
       
   232 		ob_start();
       
   233 		wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
       
   234 		echo ' ';
       
   235 
       
   236 		// flush any buffers and send the headers
       
   237 		while ( @ob_end_flush() );
       
   238 		flush();
       
   239 
       
   240 		WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
       
   241 		return;
       
   242 	}
       
   243 
       
   244 	$doing_wp_cron = sprintf( '%.22F', $gmt_time );
       
   245 	set_transient( 'doing_cron', $doing_wp_cron );
       
   246 
       
   247 	$cron_request = apply_filters( 'cron_request', array(
       
   248 		'url' => site_url( 'wp-cron.php?doing_wp_cron=' . $doing_wp_cron ),
       
   249 		'key' => $doing_wp_cron,
       
   250 		'args' => array( 'timeout' => 0.01, 'blocking' => false, 'sslverify' => apply_filters( 'https_local_ssl_verify', true ) )
       
   251 	) );
       
   252 
       
   253 	wp_remote_post( $cron_request['url'], $cron_request['args'] );
       
   254 }
       
   255 
       
   256 /**
       
   257  * Run scheduled callbacks or spawn cron for all scheduled events.
       
   258  *
       
   259  * @since 2.1.0
       
   260  *
       
   261  * @return null When doesn't need to run Cron.
       
   262  */
       
   263 function wp_cron() {
       
   264 
       
   265 	// Prevent infinite loops caused by lack of wp-cron.php
       
   266 	if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
       
   267 		return;
       
   268 
       
   269 	if ( false === $crons = _get_cron_array() )
       
   270 		return;
       
   271 
       
   272 	$gmt_time = microtime( true );
       
   273 	$keys = array_keys( $crons );
       
   274 	if ( isset($keys[0]) && $keys[0] > $gmt_time )
       
   275 		return;
       
   276 
       
   277 	$schedules = wp_get_schedules();
       
   278 	foreach ( $crons as $timestamp => $cronhooks ) {
       
   279 		if ( $timestamp > $gmt_time ) break;
       
   280 		foreach ( (array) $cronhooks as $hook => $args ) {
       
   281 			if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
       
   282 				continue;
       
   283 			spawn_cron( $gmt_time );
       
   284 			break 2;
       
   285 		}
       
   286 	}
       
   287 }
       
   288 
       
   289 /**
       
   290  * Retrieve supported and filtered Cron recurrences.
       
   291  *
       
   292  * The supported recurrences are 'hourly' and 'daily'. A plugin may add more by
       
   293  * hooking into the 'cron_schedules' filter. The filter accepts an array of
       
   294  * arrays. The outer array has a key that is the name of the schedule or for
       
   295  * example 'weekly'. The value is an array with two keys, one is 'interval' and
       
   296  * the other is 'display'.
       
   297  *
       
   298  * The 'interval' is a number in seconds of when the cron job should run. So for
       
   299  * 'hourly', the time is 3600 or 60*60. For weekly, the value would be
       
   300  * 60*60*24*7 or 604800. The value of 'interval' would then be 604800.
       
   301  *
       
   302  * The 'display' is the description. For the 'weekly' key, the 'display' would
       
   303  * be <code>__('Once Weekly')</code>.
       
   304  *
       
   305  * For your plugin, you will be passed an array. you can easily add your
       
   306  * schedule by doing the following.
       
   307  * <code>
       
   308  * // filter parameter variable name is 'array'
       
   309  *	$array['weekly'] = array(
       
   310  *		'interval' => 604800,
       
   311  *		'display' => __('Once Weekly')
       
   312  *	);
       
   313  * </code>
       
   314  *
       
   315  * @since 2.1.0
       
   316  *
       
   317  * @return array
       
   318  */
       
   319 function wp_get_schedules() {
       
   320 	$schedules = array(
       
   321 		'hourly'     => array( 'interval' => HOUR_IN_SECONDS,      'display' => __( 'Once Hourly' ) ),
       
   322 		'twicedaily' => array( 'interval' => 12 * HOUR_IN_SECONDS, 'display' => __( 'Twice Daily' ) ),
       
   323 		'daily'      => array( 'interval' => DAY_IN_SECONDS,       'display' => __( 'Once Daily' ) ),
       
   324 	);
       
   325 	return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
       
   326 }
       
   327 
       
   328 /**
       
   329  * Retrieve Cron schedule for hook with arguments.
       
   330  *
       
   331  * @since 2.1.0
       
   332  *
       
   333  * @param string $hook Action hook to execute when cron is run.
       
   334  * @param array $args Optional. Arguments to pass to the hook's callback function.
       
   335  * @return string|bool False, if no schedule. Schedule on success.
       
   336  */
       
   337 function wp_get_schedule($hook, $args = array()) {
       
   338 	$crons = _get_cron_array();
       
   339 	$key = md5(serialize($args));
       
   340 	if ( empty($crons) )
       
   341 		return false;
       
   342 	foreach ( $crons as $timestamp => $cron ) {
       
   343 		if ( isset( $cron[$hook][$key] ) )
       
   344 			return $cron[$hook][$key]['schedule'];
       
   345 	}
       
   346 	return false;
       
   347 }
       
   348 
       
   349 //
       
   350 // Private functions
       
   351 //
       
   352 
       
   353 /**
       
   354  * Retrieve cron info array option.
       
   355  *
       
   356  * @since 2.1.0
       
   357  * @access private
       
   358  *
       
   359  * @return array CRON info array.
       
   360  */
       
   361 function _get_cron_array()  {
       
   362 	$cron = get_option('cron');
       
   363 	if ( ! is_array($cron) )
       
   364 		return false;
       
   365 
       
   366 	if ( !isset($cron['version']) )
       
   367 		$cron = _upgrade_cron_array($cron);
       
   368 
       
   369 	unset($cron['version']);
       
   370 
       
   371 	return $cron;
       
   372 }
       
   373 
       
   374 /**
       
   375  * Updates the CRON option with the new CRON array.
       
   376  *
       
   377  * @since 2.1.0
       
   378  * @access private
       
   379  *
       
   380  * @param array $cron Cron info array from {@link _get_cron_array()}.
       
   381  */
       
   382 function _set_cron_array($cron) {
       
   383 	$cron['version'] = 2;
       
   384 	update_option( 'cron', $cron );
       
   385 }
       
   386 
       
   387 /**
       
   388  * Upgrade a Cron info array.
       
   389  *
       
   390  * This function upgrades the Cron info array to version 2.
       
   391  *
       
   392  * @since 2.1.0
       
   393  * @access private
       
   394  *
       
   395  * @param array $cron Cron info array from {@link _get_cron_array()}.
       
   396  * @return array An upgraded Cron info array.
       
   397  */
       
   398 function _upgrade_cron_array($cron) {
       
   399 	if ( isset($cron['version']) && 2 == $cron['version'])
       
   400 		return $cron;
       
   401 
       
   402 	$new_cron = array();
       
   403 
       
   404 	foreach ( (array) $cron as $timestamp => $hooks) {
       
   405 		foreach ( (array) $hooks as $hook => $args ) {
       
   406 			$key = md5(serialize($args['args']));
       
   407 			$new_cron[$timestamp][$hook][$key] = $args;
       
   408 		}
       
   409 	}
       
   410 
       
   411 	$new_cron['version'] = 2;
       
   412 	update_option( 'cron', $new_cron );
       
   413 	return $new_cron;
       
   414 }