PageRenderTime 58ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/cron.php

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