PageRenderTime 43ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/wp-includes/cron.php

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