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

/wp-includes/cron.php

https://gitlab.com/Blueprint-Marketing/WordPress-1
PHP | 464 lines | 191 code | 54 blank | 219 comment | 48 complexity | cb9d5e722ee53d7bd4baac56b33298c1 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. /**
  29. * Filter a single event before it is scheduled.
  30. *
  31. * @since 3.1.0
  32. *
  33. * @param object $event An object containing an event's data.
  34. */
  35. $event = apply_filters( 'schedule_event', $event );
  36. // A plugin disallowed this event
  37. if ( ! $event )
  38. return false;
  39. $key = md5(serialize($event->args));
  40. $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args );
  41. uksort( $crons, "strnatcasecmp" );
  42. _set_cron_array( $crons );
  43. }
  44. /**
  45. * Schedule a periodic event.
  46. *
  47. * Schedules a hook which will be executed by the WordPress actions core on a
  48. * specific interval, specified by you. The action will trigger when someone
  49. * visits your WordPress site, if the scheduled time has passed.
  50. *
  51. * Valid values for the recurrence are hourly, daily and twicedaily. These can
  52. * be extended using the cron_schedules filter in wp_get_schedules().
  53. *
  54. * Use wp_next_scheduled() to prevent duplicates
  55. *
  56. * @since 2.1.0
  57. *
  58. * @param int $timestamp Timestamp for when to run the event.
  59. * @param string $recurrence How often the event should recur.
  60. * @param string $hook Action hook to execute when cron is run.
  61. * @param array $args Optional. Arguments to pass to the hook's callback function.
  62. * @return bool|null False on failure, null when complete with scheduling event.
  63. */
  64. function wp_schedule_event( $timestamp, $recurrence, $hook, $args = array()) {
  65. $crons = _get_cron_array();
  66. $schedules = wp_get_schedules();
  67. if ( !isset( $schedules[$recurrence] ) )
  68. return false;
  69. $event = (object) array( 'hook' => $hook, 'timestamp' => $timestamp, 'schedule' => $recurrence, 'args' => $args, 'interval' => $schedules[$recurrence]['interval'] );
  70. /** This filter is documented in wp-includes/cron.php */
  71. $event = apply_filters( 'schedule_event', $event );
  72. // A plugin disallowed this event
  73. if ( ! $event )
  74. return false;
  75. $key = md5(serialize($event->args));
  76. $crons[$event->timestamp][$event->hook][$key] = array( 'schedule' => $event->schedule, 'args' => $event->args, 'interval' => $event->interval );
  77. uksort( $crons, "strnatcasecmp" );
  78. _set_cron_array( $crons );
  79. }
  80. /**
  81. * Reschedule a recurring event.
  82. *
  83. * @since 2.1.0
  84. *
  85. * @param int $timestamp Timestamp for when to run the event.
  86. * @param string $recurrence How often the event should recur.
  87. * @param string $hook Action hook to execute when cron is run.
  88. * @param array $args Optional. Arguments to pass to the hook's callback function.
  89. * @return bool|null False on failure. Null when event is rescheduled.
  90. */
  91. function wp_reschedule_event( $timestamp, $recurrence, $hook, $args = array()) {
  92. $crons = _get_cron_array();
  93. $schedules = wp_get_schedules();
  94. $key = md5(serialize($args));
  95. $interval = 0;
  96. // First we try to get it from the schedule
  97. if ( 0 == $interval )
  98. $interval = $schedules[$recurrence]['interval'];
  99. // Now we try to get it from the saved interval in case the schedule disappears
  100. if ( 0 == $interval )
  101. $interval = $crons[$timestamp][$hook][$key]['interval'];
  102. // Now we assume something is wrong and fail to schedule
  103. if ( 0 == $interval )
  104. return false;
  105. $now = time();
  106. if ( $timestamp >= $now )
  107. $timestamp = $now + $interval;
  108. else
  109. $timestamp = $now + ($interval - (($now - $timestamp) % $interval));
  110. wp_schedule_event( $timestamp, $recurrence, $hook, $args );
  111. }
  112. /**
  113. * Unschedule a previously scheduled cron job.
  114. *
  115. * The $timestamp and $hook parameters are required, so that the event can be
  116. * identified.
  117. *
  118. * @since 2.1.0
  119. *
  120. * @param int $timestamp Timestamp for when to run the event.
  121. * @param string $hook Action hook, the execution of which will be unscheduled.
  122. * @param array $args Arguments to pass to the hook's callback function.
  123. * Although not passed to a callback function, these arguments are used
  124. * to uniquely identify the scheduled event, so they should be the same
  125. * as those used when originally scheduling the event.
  126. */
  127. function wp_unschedule_event( $timestamp, $hook, $args = array() ) {
  128. $crons = _get_cron_array();
  129. $key = md5(serialize($args));
  130. unset( $crons[$timestamp][$hook][$key] );
  131. if ( empty($crons[$timestamp][$hook]) )
  132. unset( $crons[$timestamp][$hook] );
  133. if ( empty($crons[$timestamp]) )
  134. unset( $crons[$timestamp] );
  135. _set_cron_array( $crons );
  136. }
  137. /**
  138. * Unschedule all cron jobs attached to a specific hook.
  139. *
  140. * @since 2.1.0
  141. *
  142. * @param string $hook Action hook, the execution of which will be unscheduled.
  143. * @param array $args Optional. Arguments that were to be pass to the hook's callback function.
  144. */
  145. function wp_clear_scheduled_hook( $hook, $args = array() ) {
  146. // Backward compatibility
  147. // Previously this function took the arguments as discrete vars rather than an array like the rest of the API
  148. if ( !is_array($args) ) {
  149. _deprecated_argument( __FUNCTION__, '3.0', __('This argument has changed to an array to match the behavior of the other cron functions.') );
  150. $args = array_slice( func_get_args(), 1 );
  151. }
  152. // This logic duplicates wp_next_scheduled()
  153. // It's required due to a scenario where wp_unschedule_event() fails due to update_option() failing,
  154. // and, wp_next_scheduled() returns the same schedule in an infinite loop.
  155. $crons = _get_cron_array();
  156. if ( empty( $crons ) )
  157. return;
  158. $key = md5( serialize( $args ) );
  159. foreach ( $crons as $timestamp => $cron ) {
  160. if ( isset( $cron[ $hook ][ $key ] ) ) {
  161. wp_unschedule_event( $timestamp, $hook, $args );
  162. }
  163. }
  164. }
  165. /**
  166. * Retrieve the next timestamp for a cron event.
  167. *
  168. * @since 2.1.0
  169. *
  170. * @param string $hook Action hook to execute when cron is run.
  171. * @param array $args Optional. Arguments to pass to the hook's callback function.
  172. * @return bool|int The UNIX timestamp of the next time the scheduled event will occur.
  173. */
  174. function wp_next_scheduled( $hook, $args = array() ) {
  175. $crons = _get_cron_array();
  176. $key = md5(serialize($args));
  177. if ( empty($crons) )
  178. return false;
  179. foreach ( $crons as $timestamp => $cron ) {
  180. if ( isset( $cron[$hook][$key] ) )
  181. return $timestamp;
  182. }
  183. return false;
  184. }
  185. /**
  186. * Send request to run cron through HTTP request that doesn't halt page loading.
  187. *
  188. * @since 2.1.0
  189. *
  190. * @return null Cron could not be spawned, because it is not needed to run.
  191. */
  192. function spawn_cron( $gmt_time = 0 ) {
  193. if ( ! $gmt_time )
  194. $gmt_time = microtime( true );
  195. if ( defined('DOING_CRON') || isset($_GET['doing_wp_cron']) )
  196. return;
  197. /*
  198. * multiple processes on multiple web servers can run this code concurrently
  199. * try to make this as atomic as possible by setting doing_cron switch
  200. */
  201. $lock = get_transient('doing_cron');
  202. if ( $lock > $gmt_time + 10 * MINUTE_IN_SECONDS )
  203. $lock = 0;
  204. // don't run if another process is currently running it or more than once every 60 sec.
  205. if ( $lock + WP_CRON_LOCK_TIMEOUT > $gmt_time )
  206. return;
  207. //sanity check
  208. $crons = _get_cron_array();
  209. if ( !is_array($crons) )
  210. return;
  211. $keys = array_keys( $crons );
  212. if ( isset($keys[0]) && $keys[0] > $gmt_time )
  213. return;
  214. if ( defined('ALTERNATE_WP_CRON') && ALTERNATE_WP_CRON ) {
  215. if ( !empty($_POST) || defined('DOING_AJAX') )
  216. return;
  217. $doing_wp_cron = sprintf( '%.22F', $gmt_time );
  218. set_transient( 'doing_cron', $doing_wp_cron );
  219. ob_start();
  220. wp_redirect( add_query_arg( 'doing_wp_cron', $doing_wp_cron, wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
  221. echo ' ';
  222. // flush any buffers and send the headers
  223. while ( @ob_end_flush() );
  224. flush();
  225. WP_DEBUG ? include_once( ABSPATH . 'wp-cron.php' ) : @include_once( ABSPATH . 'wp-cron.php' );
  226. return;
  227. }
  228. $doing_wp_cron = sprintf( '%.22F', $gmt_time );
  229. set_transient( 'doing_cron', $doing_wp_cron );
  230. /**
  231. * Filter the cron request arguments.
  232. *
  233. * @since 3.5.0
  234. *
  235. * @param array $cron_request_array {
  236. * An array of cron request URL arguments.
  237. *
  238. * @type string $url The cron request URL.
  239. * @type int $key The 22 digit GMT microtime.
  240. * @type array $args {
  241. * An array of cron request arguments.
  242. *
  243. * @type int $timeout The request timeout in seconds. Default .01 seconds.
  244. * @type bool $blocking Whether to set blocking for the request. Default false.
  245. * @type bool $sslverify Whether to sslverify. Default true.
  246. * }
  247. * }
  248. */
  249. $cron_request = apply_filters( 'cron_request', array(
  250. 'url' => add_query_arg( 'doing_wp_cron', $doing_wp_cron, site_url( 'wp-cron.php' ) ),
  251. 'key' => $doing_wp_cron,
  252. 'args' => array(
  253. 'timeout' => 0.01,
  254. 'blocking' => false,
  255. /** This filter is documented in wp-includes/class-http.php */
  256. 'sslverify' => apply_filters( 'https_local_ssl_verify', true )
  257. )
  258. ) );
  259. wp_remote_post( $cron_request['url'], $cron_request['args'] );
  260. }
  261. /**
  262. * Run scheduled callbacks or spawn cron for all scheduled events.
  263. *
  264. * @since 2.1.0
  265. *
  266. * @return null When doesn't need to run Cron.
  267. */
  268. function wp_cron() {
  269. // Prevent infinite loops caused by lack of wp-cron.php
  270. if ( strpos($_SERVER['REQUEST_URI'], '/wp-cron.php') !== false || ( defined('DISABLE_WP_CRON') && DISABLE_WP_CRON ) )
  271. return;
  272. if ( false === $crons = _get_cron_array() )
  273. return;
  274. $gmt_time = microtime( true );
  275. $keys = array_keys( $crons );
  276. if ( isset($keys[0]) && $keys[0] > $gmt_time )
  277. return;
  278. $schedules = wp_get_schedules();
  279. foreach ( $crons as $timestamp => $cronhooks ) {
  280. if ( $timestamp > $gmt_time ) break;
  281. foreach ( (array) $cronhooks as $hook => $args ) {
  282. if ( isset($schedules[$hook]['callback']) && !call_user_func( $schedules[$hook]['callback'] ) )
  283. continue;
  284. spawn_cron( $gmt_time );
  285. break 2;
  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. /**
  326. * Filter the non-default cron schedules.
  327. *
  328. * @since 2.1.0
  329. *
  330. * @param array $new_schedules An array of non-default cron schedules. Default empty.
  331. */
  332. return array_merge( apply_filters( 'cron_schedules', array() ), $schedules );
  333. }
  334. /**
  335. * Retrieve Cron schedule for hook with arguments.
  336. *
  337. * @since 2.1.0
  338. *
  339. * @param string $hook Action hook to execute when cron is run.
  340. * @param array $args Optional. Arguments to pass to the hook's callback function.
  341. * @return string|bool False, if no schedule. Schedule on success.
  342. */
  343. function wp_get_schedule($hook, $args = array()) {
  344. $crons = _get_cron_array();
  345. $key = md5(serialize($args));
  346. if ( empty($crons) )
  347. return false;
  348. foreach ( $crons as $timestamp => $cron ) {
  349. if ( isset( $cron[$hook][$key] ) )
  350. return $cron[$hook][$key]['schedule'];
  351. }
  352. return false;
  353. }
  354. //
  355. // Private functions
  356. //
  357. /**
  358. * Retrieve cron info array option.
  359. *
  360. * @since 2.1.0
  361. * @access private
  362. *
  363. * @return array CRON info array.
  364. */
  365. function _get_cron_array() {
  366. $cron = get_option('cron');
  367. if ( ! is_array($cron) )
  368. return false;
  369. if ( !isset($cron['version']) )
  370. $cron = _upgrade_cron_array($cron);
  371. unset($cron['version']);
  372. return $cron;
  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. * Upgrade a Cron info array.
  388. *
  389. * This function upgrades the Cron info array to version 2.
  390. *
  391. * @since 2.1.0
  392. * @access private
  393. *
  394. * @param array $cron Cron info array from {@link _get_cron_array()}.
  395. * @return array An upgraded Cron info array.
  396. */
  397. function _upgrade_cron_array($cron) {
  398. if ( isset($cron['version']) && 2 == $cron['version'])
  399. return $cron;
  400. $new_cron = array();
  401. foreach ( (array) $cron as $timestamp => $hooks) {
  402. foreach ( (array) $hooks as $hook => $args ) {
  403. $key = md5(serialize($args['args']));
  404. $new_cron[$timestamp][$hook][$key] = $args;
  405. }
  406. }
  407. $new_cron['version'] = 2;
  408. update_option( 'cron', $new_cron );
  409. return $new_cron;
  410. }