/wp-content/plugins/mailpoet/lib/Cron/DaemonHttpRunner.php

https://gitlab.com/remyvianne/krowkaramel · PHP · 162 lines · 122 code · 22 blank · 18 comment · 19 complexity · 57f61cd2555d54d7cfde58a26d8f7c45 MD5 · raw file

  1. <?php
  2. namespace MailPoet\Cron;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\Cron\Triggers\WordPress;
  5. use MailPoet\Settings\SettingsController;
  6. use MailPoet\WP\Functions as WPFunctions;
  7. use Tracy\Debugger;
  8. class DaemonHttpRunner {
  9. public $settingsDaemonData;
  10. public $timer;
  11. public $token;
  12. /** @var Daemon|null */
  13. private $daemon;
  14. /** @var CronHelper */
  15. private $cronHelper;
  16. /** @var SettingsController */
  17. private $settings;
  18. const PING_SUCCESS_RESPONSE = 'pong';
  19. /** @var WordPress */
  20. private $wordpressTrigger;
  21. public function __construct(
  22. Daemon $daemon = null,
  23. CronHelper $cronHelper,
  24. SettingsController $settings,
  25. WordPress $wordpressTrigger
  26. ) {
  27. $this->cronHelper = $cronHelper;
  28. $this->settingsDaemonData = $this->cronHelper->getDaemon();
  29. $this->token = $this->cronHelper->createToken();
  30. $this->timer = microtime(true);
  31. $this->daemon = $daemon;
  32. $this->settings = $settings;
  33. $this->wordpressTrigger = $wordpressTrigger;
  34. }
  35. public function ping() {
  36. // if Tracy enabled & called by 'MailPoet Cron' user agent, disable Tracy Bar
  37. // (happens in CronHelperTest because it's not a real integration test - calls other WP instance)
  38. $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null;
  39. if (class_exists(Debugger::class) && $userAgent === 'MailPoet Cron') {
  40. Debugger::$showBar = false;
  41. }
  42. $this->addCacheHeaders();
  43. $this->terminateRequest(self::PING_SUCCESS_RESPONSE);
  44. }
  45. public function run($requestData) {
  46. ignore_user_abort(true);
  47. if (strpos((string)@ini_get('disable_functions'), 'set_time_limit') === false) {
  48. set_time_limit(0);
  49. }
  50. $this->addCacheHeaders();
  51. if (!$requestData) {
  52. $error = WPFunctions::get()->__('Invalid or missing request data.', 'mailpoet');
  53. } else {
  54. if (!$this->settingsDaemonData) {
  55. $error = WPFunctions::get()->__('Daemon does not exist.', 'mailpoet');
  56. } else {
  57. if (
  58. !isset($requestData['token']) ||
  59. $requestData['token'] !== $this->settingsDaemonData['token']
  60. ) {
  61. $error = 'Invalid or missing token.';
  62. }
  63. }
  64. }
  65. if (!empty($error)) {
  66. return $this->abortWithError($error);
  67. }
  68. if ($this->daemon === null) {
  69. return $this->abortWithError(WPFunctions::get()->__('Daemon does not set correctly.', 'mailpoet'));
  70. }
  71. $this->settingsDaemonData['token'] = $this->token;
  72. $this->daemon->run($this->settingsDaemonData);
  73. // If we're using the WordPress trigger, check the conditions to stop cron if necessary
  74. $enableCronSelfDeactivation = WPFunctions::get()->applyFilters('mailpoet_cron_enable_self_deactivation', false);
  75. if (
  76. $enableCronSelfDeactivation
  77. && $this->isCronTriggerMethodWordPress()
  78. && !$this->checkWPTriggerExecutionRequirements()
  79. ) {
  80. $this->stopCron();
  81. } else {
  82. // if workers took less time to execute than the daemon execution limit,
  83. // pause daemon execution to ensure that daemon runs only once every X seconds
  84. $elapsedTime = microtime(true) - $this->timer;
  85. if ($elapsedTime < $this->cronHelper->getDaemonExecutionLimit()) {
  86. $this->pauseExecution($this->cronHelper->getDaemonExecutionLimit() - $elapsedTime);
  87. }
  88. }
  89. // after each execution, re-read daemon data in case it changed
  90. $settingsDaemonData = $this->cronHelper->getDaemon();
  91. if ($this->shouldTerminateExecution($settingsDaemonData)) {
  92. return $this->terminateRequest();
  93. }
  94. return $this->callSelf();
  95. }
  96. public function pauseExecution($pauseTime) {
  97. return sleep($pauseTime);
  98. }
  99. public function callSelf() {
  100. $this->cronHelper->accessDaemon($this->token);
  101. $this->terminateRequest();
  102. }
  103. public function abortWithError($message) {
  104. WPFunctions::get()->statusHeader(404, $message);
  105. exit;
  106. }
  107. public function terminateRequest($message = false) {
  108. die($message);
  109. }
  110. public function isCronTriggerMethodWordPress() {
  111. return $this->settings->get(CronTrigger::SETTING_NAME . '.method') === CronTrigger::METHOD_WORDPRESS;
  112. }
  113. public function checkWPTriggerExecutionRequirements() {
  114. return $this->wordpressTrigger->checkExecutionRequirements();
  115. }
  116. public function stopCron() {
  117. return $this->wordpressTrigger->stop();
  118. }
  119. /**
  120. * @param array|null $settingsDaemonData
  121. *
  122. * @return bool
  123. */
  124. private function shouldTerminateExecution(array $settingsDaemonData = null) {
  125. return !$settingsDaemonData ||
  126. $settingsDaemonData['token'] !== $this->token ||
  127. (isset($settingsDaemonData['status']) && $settingsDaemonData['status'] !== CronHelper::DAEMON_STATUS_ACTIVE);
  128. }
  129. private function addCacheHeaders() {
  130. if (headers_sent()) {
  131. return;
  132. }
  133. // Common Cache Control header. Should be respected by cache proxies and CDNs.
  134. header('Cache-Control: no-cache');
  135. // Mark as blacklisted for SG Optimizer for sites hosted on SiteGround.
  136. header('X-Cache-Enabled: False');
  137. // Set caching header for LiteSpeed server.
  138. header('X-LiteSpeed-Cache-Control: no-cache');
  139. }
  140. }