PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/cron.php

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