Não pode escolher mais do que 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 

508 linhas
16 KiB

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