PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.1
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Helpers/CronHelper.php +0 -807 11.0.2 → 11.1.1 View file →
@@ -1,807 +1,0 @@
1 -<?php
2 -
3 -namespace AcyMailing\Helpers;
4 -
5 -use AcyMailing\Classes\AutomationClass;
6 -use AcyMailing\Classes\CampaignClass;
7 -use AcyMailing\Classes\FollowupClass;
8 -use AcyMailing\Classes\MailArchiveClass;
9 -use AcyMailing\Classes\MailboxClass;
10 -use AcyMailing\Classes\MailClass;
11 -use AcyMailing\Classes\QueueClass;
12 -use AcyMailing\Classes\UserClass;
13 -use AcyMailing\Classes\UserStatClass;
14 -use AcyMailing\Core\AcymObject;
15 -
16 -class CronHelper extends AcymObject
17 -{
18 - const STEP_SCHEDULE = 'schedule';
19 - const STEP_CLEAN_QUEUE = 'cleanqueue';
20 - const STEP_SEND = 'send';
21 - const STEP_BOUNCE = 'bounce';
22 - const STEP_AUTOMATION = 'automation';
23 - const STEP_CAMPAIGN = 'campaign';
24 - const STEP_SPECIFIC = 'specific';
25 - const STEP_FOLLOWUP = 'followup';
26 - const STEP_DELETE_HISTORY = 'delete_history';
27 - const STEP_CLEAN_DATA_EXTERNAL_SENDING_METHOD = 'clean_data_external_sending_method';
28 - const STEP_CLEAN_EXPORT_CHANGES = 'clean_export_changes';
29 - const STEP_MAILBOX_ACTION = 'mailbox_action';
30 - const STEP_ABTEST = 'abtest';
31 - const STEP_SCENARIO = 'scenario';
32 -
33 - const ALL_STEPS = [
34 - self::STEP_SCHEDULE,
35 - self::STEP_CLEAN_QUEUE,
36 - self::STEP_SEND,
37 - self::STEP_BOUNCE,
38 - self::STEP_AUTOMATION,
39 - self::STEP_CAMPAIGN,
40 - self::STEP_SPECIFIC,
41 - self::STEP_FOLLOWUP,
42 - self::STEP_DELETE_HISTORY,
43 - self::STEP_CLEAN_DATA_EXTERNAL_SENDING_METHOD,
44 - self::STEP_CLEAN_EXPORT_CHANGES,
45 - self::STEP_MAILBOX_ACTION,
46 - self::STEP_ABTEST,
47 - self::STEP_SCENARIO,
48 - ];
49 -
50 - const SEND_REPORT_NO = 0;
51 - const SEND_REPORT_EACH_TIME = 1;
52 - const SEND_REPORT_ONLY_ON_ACTION = 2;
53 - const SEND_REPORT_ONLY_ON_ERROR = 3;
54 -
55 - private array $messages = [];
56 - private array $detailMessages = [];
57 - private array $emailTypes = [];
58 - private array $skip = [];
59 -
60 - private int $cronTimeLimit = 0;
61 - private bool $cronTimeLimitReached = false;
62 - private int $startQueue;
63 -
64 - // Save the main message
65 - private string $mainMessage = '';
66 -
67 - // Did the cron process anything?
68 - private bool $processed = false;
69 -
70 - // Is there any error in the process
71 - private bool $errorDetected = false;
72 -
73 - // If we call the cron just to send a batch of emails
74 - private bool $externalSendingActivated = false;
75 - private bool $externalSendingRepeat;
76 - private bool $externalSendingNotFinished = false;
77 - private bool $isSendingCall = false;
78 -
79 - public function __construct()
80 - {
81 - parent::__construct();
82 -
83 - acym_trigger('onAcymProcessQueueExternalSendingCampaign', [&$this->externalSendingActivated]);
84 -
85 - $callType = acym_getVar('string', 'type', '');
86 - $this->startQueue = acym_getVar('int', 'startqueue', 0);
87 - $this->externalSendingRepeat = !empty(acym_getVar('int', 'external_sending_repeat', 0));
88 -
89 - if ($callType === 'sending' || !empty($this->startQueue) || !empty($this->externalSendingRepeat)) {
90 - $this->skip = array_diff(self::ALL_STEPS, [self::STEP_SEND]);
91 - $this->isSendingCall = true;
92 - }
93 - }
94 -
95 - public function addSkipFromString(string $skipVar): void
96 - {
97 - if (empty($skipVar)) {
98 - return;
99 - }
100 -
101 - $skipVar = explode(',', $skipVar);
102 -
103 - if (empty($skipVar)) {
104 - return;
105 - }
106 -
107 - $this->skip = array_unique(array_merge($this->skip, $skipVar));
108 - }
109 -
110 - public function cron(): void
111 - {
112 -
113 - $this->handleUnlinkLicenseCalls();
114 - $this->triggeredMessage();
115 - if (!$this->checkCronFrequency()) {
116 - return;
117 - }
118 -
119 - $this->queueScheduledCampaigns();
120 - $this->cleanQueue();
121 - $this->handleQueue();
122 - $this->handleBounceMessages();
123 - $this->handleAutomations();
124 - $this->handleAutomaticCampaigns();
125 - $this->handleSpecificEmails();
126 - $this->handleFollowups();
127 - $this->handleMailboxActions();
128 - $this->cleanData();
129 - $this->handleABTestCampaigns();
130 - $this->handleScenario();
131 - $this->continueCronCall();
132 - $this->handleCronReport();
133 - }
134 -
135 - public function saveReport(array $messages = [], array $detailMessages = []): void
136 - {
137 - $saveReport = $this->config->get('cron_savereport');
138 - $reportPath = $this->config->get('cron_savepath');
139 -
140 - if (empty($saveReport) || empty($reportPath)) {
141 - return;
142 - }
143 -
144 - if (!(($saveReport == 2 && $this->processed) || $saveReport == 1 || ($saveReport == 3 && $this->errorDetected))) {
145 - return;
146 - }
147 -
148 - if (!empty($messages)) {
149 - $this->messages = $messages;
150 - }
151 -
152 - if (!empty($detailMessages)) {
153 - $this->detailMessages = $detailMessages;
154 - }
155 -
156 - // Prepare the cron file path
157 - $reportPath = str_replace(['{year}', '{month}'], [gmdate('Y'), gmdate('m')], $reportPath);
158 - $reportPath = acym_cleanPath(ACYM_ROOT.trim(html_entity_decode($reportPath)));
159 - acym_createDir(dirname($reportPath), true, true);
160 -
161 - $lr = "\r\n";
162 - // Catch warnings
163 - ob_start();
164 - file_put_contents(
165 - $reportPath,
166 - $lr.$lr.'******************** '.acym_getDate(time()).' UTC ********************'.$lr.implode($lr, $this->messages),
167 - FILE_APPEND
168 - );
169 -
170 - if ($saveReport == 2 && !empty($this->detailMessages)) {
171 - file_put_contents(
172 - $reportPath,
173 - $lr.'---- Details ----'.$lr.implode($lr, $this->detailMessages),
174 - FILE_APPEND
175 - );
176 - }
177 - $potentialWarnings = ob_get_clean();
178 -
179 - if (!empty($potentialWarnings)) {
180 - $this->messages[] = $potentialWarnings;
181 - }
182 - }
183 -
184 - /**
185 - * Sets the types of emails that will be sent by the cron
186 - */
187 - public function setEmailTypes(array $emailTypes): void
188 - {
189 - $this->emailTypes = $emailTypes;
190 - }
191 -
192 - public function addMessage(string $message): void
193 - {
194 - $this->messages[] = $message;
195 - }
196 -
197 - public function handleCronReport(): void
198 - {
199 - $sendReport = (int)$this->config->get('cron_sendreport');
200 -
201 - if (
202 - ($sendReport === self::SEND_REPORT_ONLY_ON_ACTION && $this->processed)
203 - || $sendReport === self::SEND_REPORT_EACH_TIME
204 - || ($sendReport === self::SEND_REPORT_ONLY_ON_ERROR && $this->errorDetected)
205 - ) {
206 - $mailerHelper = new MailerHelper();
207 - $mailerHelper->report = false;
208 - $mailerHelper->autoAddUser = true;
209 - $mailerHelper->addParam('report', implode('<br />', $this->messages));
210 - $mailerHelper->addParam('mainreport', $this->mainMessage);
211 - $mailerHelper->addParam('detailreport', implode('<br />', $this->detailMessages));
212 -
213 - $receiverString = $this->config->get('cron_sendto');
214 - $receivers = [];
215 - if (substr_count($receiverString, '@') > 1) {
216 - $receivers = explode(' ', trim(preg_replace('# +#', ' ', str_replace([';', ','], ' ', $receiverString))));
217 - } else {
218 - $receivers[] = trim($receiverString);
219 - }
220 -
221 - if (!empty($receivers)) {
222 - $mailClass = new MailClass();
223 - foreach ($receivers as $oneReceiver) {
224 - if (empty($oneReceiver)) {
225 - continue;
226 - }
227 -
228 - try {
229 - $reportEmail = $mailClass->getOneByName('acy_report');
230 - if (!empty($reportEmail)) {
231 - $mailerHelper->sendOne($reportEmail->id, $oneReceiver);
232 - }
233 - } catch (\Exception $e) {
234 - acym_logError('Error while sending the cron report to '.$oneReceiver.' : '.$e->getMessage());
235 - }
236 - }
237 - }
238 - }
239 -
240 - $this->saveReport();
241 -
242 - $newConfig = [
243 - 'cron_report' => implode("\n", $this->messages),
244 - ];
245 -
246 - if (strlen($newConfig['cron_report']) > 800) {
247 - $newConfig['cron_report'] = substr($newConfig['cron_report'], 0, 795).'...';
248 - }
249 -
250 - $this->config->saveConfig($newConfig);
251 - }
252 -
253 - /**
254 - * Call made by the API to remove the API key when the user unlinks the website from their account page on our website
255 - */
256 - private function handleUnlinkLicenseCalls(): void
257 - {
258 - if (acym_getVar('int', 'unlink', 0) !== 1) {
259 - return;
260 - }
261 -
262 - $callLicenseKey = acym_getVar('string', 'licenseKey');
263 - $configLicenseKey = $this->config->get('license_key');
264 -
265 - if (!empty($configLicenseKey) && $configLicenseKey === $callLicenseKey) {
266 - $this->config->saveConfig(['license_key' => '', 'active_cron' => 0]);
267 - }
268 -
269 - exit;
270 - }
271 -
272 - /**
273 - * Displays the message shown on the cron URL page
274 - */
275 - private function triggeredMessage(): void
276 - {
277 - $firstMessage = acym_translationSprintf('ACYM_CRON_TRIGGERED', acym_date('now', 'd F Y H:i'));
278 - $this->messages[] = $firstMessage;
279 - acym_display($firstMessage, 'info');
280 - }
281 -
282 - /**
283 - * Checks the cron frequency in the configuration to make sure the call is wanted
284 - */
285 - private function checkCronFrequency(): bool
286 - {
287 - if ($this->isSendingCall) {
288 - return true;
289 - }
290 -
291 - $time = time();
292 - $nextCronTime = $this->config->get('cron_next', 0);
293 - $cronFrequency = $this->config->get('cron_frequency', 900);
294 -
295 - if ($nextCronTime > $time) {
296 - if ($nextCronTime > ($time + $cronFrequency)) {
297 - // The next cron time is too far in the future, should not happen but we'll handle the case, so we reset the next cron time
298 - $this->config->saveConfig(['cron_next' => $time + $cronFrequency]);
299 - }
300 -
301 - $notTimeMessage = acym_translationSprintf('ACYM_CRON_NEXT', acym_date($this->config->get('cron_next'), 'd F Y H:i'));
302 - $this->messages[] = $notTimeMessage;
303 - // We don't need to trigger anything, it's not time yet
304 - acym_display($notTimeMessage, 'info');
305 -
306 - return false;
307 - }
308 -
309 - // We update the next cron and the last cron dates
310 - $newConfig = [
311 - 'cron_last' => $time,
312 - 'cron_fromip' => acym_getIP(true),
313 - 'cron_next' => $nextCronTime + $cronFrequency,
314 - ];
315 -
316 - if ($newConfig['cron_next'] <= $time || $newConfig['cron_next'] > $time + $cronFrequency) {
317 - $newConfig['cron_next'] = $time + $cronFrequency;
318 - }
319 -
320 - $this->config->saveConfig($newConfig);
321 -
322 - return true;
323 - }
324 -
325 - /**
326 - * Adds the scheduled emails to the queue when the date is reached
327 - */
328 - private function queueScheduledCampaigns(): void
329 - {
330 - if (in_array(self::STEP_SCHEDULE, $this->skip)) {
331 - return;
332 - }
333 -
334 - $queueClass = new QueueClass();
335 - $nbScheduled = $queueClass->scheduleReady();
336 - if (!empty($nbScheduled)) {
337 - $this->messages[] = acym_translationSprintf('ACYM_NB_SCHEDULED', $nbScheduled);
338 - $this->detailMessages = array_merge($this->detailMessages, $queueClass->messages);
339 - $this->processed = true;
340 - }
341 - }
342 -
343 - /**
344 - * Cleans the emails that are stuck in the queue for too long (disabled/unconfirmed recipients)
345 - */
346 - private function cleanQueue(): void
347 - {
348 - if (in_array(self::STEP_CLEAN_QUEUE, $this->skip)) {
349 - return;
350 - }
351 -
352 - $queueClass = new QueueClass();
353 - $deletedNb = $queueClass->cleanQueue();
354 -
355 - if (!empty($deletedNb)) {
356 - $this->messages[] = acym_translationSprintf('ACYM_EMAILS_REMOVED_QUEUE_CLEAN', $deletedNb);
357 - $this->processed = true;
358 - }
359 - }
360 -
361 - private function handleQueue(): void
362 - {
363 - if (in_array(self::STEP_SEND, $this->skip) || !$this->canSendQueuedEmails()) {
364 - return;
365 - }
366 -
367 - if (!$this->isSendingCall && acym_level(ACYM_ENTERPRISE) && function_exists('curl_multi_exec')) {
368 - $this->handleMultiCron();
369 - }
370 -
371 - if ($this->isSendingCall || $this->config->get('dedicated_send_process', 0) != 1) {
372 - $this->sendQueuedEmails();
373 - }
374 - }
375 -
376 - /**
377 - * Makes sure the current process doesn't reach the server time limit
378 - */
379 - private function checkTimeRemaining(): void
380 - {
381 - $time = time();
382 - if (empty($this->cronTimeLimit) || $time < $this->cronTimeLimit) {
383 - return;
384 - }
385 -
386 - $this->messages[] = acym_translation('ACYM_CRON_TIME_LIMIT_REACHED');
387 -
388 - $this->cronTimeLimitReached = true;
389 - }
390 -
391 - /**
392 - * If the configuration is set to send multiple batches of emails at the same time
393 - */
394 - private function handleMultiCron(): void
395 - {
396 - $emailsPerBatches = $this->config->get('queue_nbmail_auto', 70);
397 - if (empty($emailsPerBatches)) {
398 - return;
399 - }
400 -
401 - $nbBatches = $this->config->get('queue_batch_auto', 1);
402 - $nbBatches = intval($nbBatches);
403 -
404 - if ($this->config->get('dedicated_send_process', 0) == 1) {
405 - $startCron = 0;
406 - } else {
407 - if ($nbBatches < 2) {
408 - return;
409 - }
410 -
411 - $startCron = 1;
412 - }
413 -
414 - $cronParams = '&t='.time();
415 - if (!empty($this->config->get('cron_security', 0)) && !empty($this->config->get('cron_key'))) {
416 - $cronParams .= '&cronKey='.$this->config->get('cron_key');
417 - }
418 -
419 - $urls = [];
420 - for ($i = $startCron; $i < $nbBatches; $i++) {
421 - $urls[] = acym_frontendLink('cron&task=cron&type=sending&startqueue='.($emailsPerBatches * $i).$cronParams);
422 - }
423 -
424 - acym_asyncUrlCalls($urls);
425 - }
426 -
427 - private function handleBounceMessages(): void
428 - {
429 - $this->checkTimeRemaining();
430 - $time = time();
431 - $autoBounceHandlingActive = (int)$this->config->get('auto_bounce', 0) === 1;
432 - $autoBounceHandlingNextTime = (int)$this->config->get('auto_bounce_next', 0);
433 - $autoBounceHandlingFrequency = (int)$this->config->get('auto_bounce_frequency', 0);
434 - $isEnterprise = acym_level(ACYM_ENTERPRISE);
435 -
436 - if (in_array(self::STEP_BOUNCE, $this->skip) || $this->cronTimeLimitReached || !$isEnterprise || !$autoBounceHandlingActive || $time < $autoBounceHandlingNextTime) {
437 - return;
438 - }
439 -
440 - $this->config->saveConfig(
441 - [
442 - 'auto_bounce_last' => $time,
443 - 'auto_bounce_next' => $time + $autoBounceHandlingFrequency,
444 - ]
445 - );
446 -
447 - $bounceHelper = new BounceHelper();
448 - $bounceHelper->report = false;
449 - $bounceHelper->stoptime = $this->cronTimeLimit;
450 -
451 - $newConfig = [];
452 - if ($bounceHelper->init() && $bounceHelper->connect()) {
453 - $nbMessages = $bounceHelper->getNBMessages();
454 - $nbMessagesReport = acym_translationSprintf('ACYM_NB_MAIL_MAILBOX', $nbMessages);
455 - $this->messages[] = $nbMessagesReport;
456 - $newConfig['auto_bounce_report'] = $nbMessagesReport;
457 - $this->detailMessages[] = $nbMessagesReport;
458 - if (!empty($nbMessages)) {
459 - $bounceHelper->handleMessages();
460 - $this->processed = true;
461 - }
462 - $this->detailMessages = array_merge($this->detailMessages, $bounceHelper->messages);
463 - } else {
464 - $bounceErrors = $bounceHelper->getErrors();
465 - $newConfig['auto_bounce_report'] = implode('<br />', $bounceErrors);
466 - //We add "bounce handling" just before the error so the user knows where it comes from...
467 - if (!empty($bounceErrors[0])) {
468 - $bounceErrors[0] = acym_translation('ACYM_BOUNCE_HANDLING').' : '.$bounceErrors[0];
469 - }
470 - $this->messages = array_merge($this->messages, $bounceErrors);
471 - $this->processed = true;
472 - $this->errorDetected = true;
473 - }
474 -
475 - $this->config->saveConfig($newConfig);
476 - }
477 -
478 - /**
479 - * Triggers the automations based on time frequency
480 - */
481 - private function handleAutomations(): void
482 - {
483 - $this->checkTimeRemaining();
484 - if (in_array(self::STEP_AUTOMATION, $this->skip) || $this->cronTimeLimitReached || !acym_level(ACYM_ENTERPRISE)) {
485 - return;
486 - }
487 -
488 - $automationClass = new AutomationClass();
489 - $automationClass->trigger('classic');
490 -
491 - $userStatusCheckTriggers = [];
492 - acym_trigger('onAcymDefineUserStatusCheckTriggers', [&$userStatusCheckTriggers]);
493 - $automationClass->trigger($userStatusCheckTriggers);
494 -
495 - if (!empty($automationClass->report)) {
496 - if ($automationClass->didAnAction) {
497 - $this->processed = true;
498 - }
499 - $this->messages = array_merge($this->messages, $automationClass->report);
500 - }
501 - }
502 -
503 - private function handleAutomaticCampaigns(): void
504 - {
505 - $this->checkTimeRemaining();
506 - if (in_array(self::STEP_CAMPAIGN, $this->skip) || $this->cronTimeLimitReached || !acym_level(ACYM_ENTERPRISE)) {
507 - return;
508 - }
509 -
510 - $campaignClass = new CampaignClass();
511 - $campaignClass->triggerAutoCampaign();
512 -
513 - if (!empty($campaignClass->messages)) {
514 - $this->messages = array_merge($this->messages, $campaignClass->messages);
515 - $this->processed = true;
516 - }
517 - }
518 -
519 - /**
520 - * Sends special emails such as birthday or WooCommerce reminders
521 - */
522 - private function handleSpecificEmails(): void
523 - {
524 - $this->checkTimeRemaining();
525 - if (in_array(self::STEP_SPECIFIC, $this->skip) || $this->cronTimeLimitReached) {
526 - return;
527 - }
528 -
529 - $campaignClass = new CampaignClass();
530 - $specialTypes = [];
531 -
532 - acym_trigger('getCampaignTypes', [&$specialTypes]);
533 -
534 - $specialMail = $campaignClass->getCampaignsByTypes($specialTypes, true);
535 - $time = time();
536 -
537 - acym_trigger('filterSpecificMailsToSend', [&$specialMail, $time]);
538 -
539 - foreach ($specialMail as $onespecialMail) {
540 - $campaignClass->send($onespecialMail->id);
541 - }
542 - }
543 -
544 - /**
545 - * Sends follow-ups based on time frequency like birthdays
546 - */
547 - private function handleFollowups(): void
548 - {
549 - $this->checkTimeRemaining();
550 - if (in_array(self::STEP_FOLLOWUP, $this->skip) || $this->cronTimeLimitReached) {
551 - return;
552 - }
553 -
554 - $followupClass = new FollowupClass();
555 - $followups = $followupClass->getFollowupDailyBases();
556 -
557 - // Only once a day
558 - $dailyHour = $this->config->get('daily_hour', '12');
559 - $dailyMinute = $this->config->get('daily_minute', '00');
560 - // The day it is currently based on the timezone specified in the CMS configuration
561 - $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
562 - // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
563 - $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$dailyHour.':'.$dailyMinute);
564 - $time = time();
565 -
566 - foreach ($followups as $followup) {
567 - $lastTrigger = empty($followup->last_trigger) ? '' : acym_date($followup->last_trigger, 'Y-m-d');
568 - if ($time >= $dayBasedOnCMSTimezoneAtSpecifiedHour && $lastTrigger != $dayBasedOnCMSTimezone) {
569 - if (!empty($followup->condition)) {
570 - $followup->condition = json_decode($followup->condition, true);
571 - }
572 -
573 - acym_trigger('onAcymFollowupDailyBasesNeedToBeTriggered', [$followup]);
574 - }
575 - }
576 - }
577 -
578 - /**
579 - * Checks messages received on mailboxes and triggers actions accordingly
580 - */
581 - private function handleMailboxActions(): void
582 - {
583 - $this->checkTimeRemaining();
584 - if (in_array(self::STEP_MAILBOX_ACTION, $this->skip) || $this->cronTimeLimitReached || !acym_level(ACYM_ENTERPRISE)) {
585 - return;
586 - }
587 -
588 - $mailboxActionClass = new MailboxClass();
589 - $mailboxes = $mailboxActionClass->getAllActiveReadyWithActions();
590 -
591 - if (empty($mailboxes)) {
592 - return;
593 - }
594 -
595 - $mailboxHelper = new MailboxHelper();
596 - $mailboxHelper->report = false;
597 - foreach ($mailboxes as $oneMailboxAction) {
598 - $this->processed = true;
599 -
600 - if (!$mailboxHelper->isConnectionValid($oneMailboxAction, false)) {
601 - $this->messages[] = acym_translationSprintf('ACYM_CONNECTION_FAILED_MAILBOX_X', $oneMailboxAction->id.'-'.$oneMailboxAction->name);
602 - $this->errorDetected = true;
603 - continue;
604 - }
605 -
606 - $nbMessages = $mailboxHelper->getNBMessages();
607 - if (!$nbMessages) {
608 - $this->messages[] = acym_translationSprintf('ACYM_NO_MESSAGE_IN_MAILBOX_X', $oneMailboxAction->id.'-'.$oneMailboxAction->name);
609 - $mailboxHelper->close();
610 - continue;
611 - }
612 -
613 - $mailboxHelper->handleAction();
614 - $mailboxHelper->close();
615 -
616 -
617 - // Update next trigger
618 - $oneMailboxAction->nextdate = time() + $oneMailboxAction->frequency;
619 - unset($oneMailboxAction->conditions);
620 - unset($oneMailboxAction->actions);
621 - $mailboxActionClass->save($oneMailboxAction);
622 - }
623 - }
624 -
625 - private function cleanData(): void
626 - {
627 - // Clean the history and detailed stats based on the configuration
628 - if (!in_array(self::STEP_DELETE_HISTORY, $this->skip) && $this->isDailyCron()) {
629 - $userStatClass = new UserStatClass();
630 - $userDetailedStatsDeleted = $userStatClass->deleteDetailedStatsPeriod();
631 - if (!empty($userDetailedStatsDeleted['message'])) {
632 - $this->messages[] = $userDetailedStatsDeleted['message'];
633 - $this->processed = true;
634 - }
635 -
636 - $userClass = new UserClass();
637 - $userHistoryDeleted = $userClass->deleteHistoryPeriod();
638 - if (!empty($userHistoryDeleted['message'])) {
639 - $this->messages[] = $userHistoryDeleted['message'];
640 - $this->processed = true;
641 - }
642 -
643 - $mailArchiveClass = new MailArchiveClass();
644 - $archiveDeleted = $mailArchiveClass->deleteArchivePeriod();
645 - if (!empty($archiveDeleted['message'])) {
646 - $this->messages[] = $archiveDeleted['message'];
647 - $this->processed = true;
648 - }
649 - }
650 -
651 - // Clean data on external sending method
652 - if (!in_array(self::STEP_CLEAN_DATA_EXTERNAL_SENDING_METHOD, $this->skip) && $this->isDailyCron()) {
653 - acym_trigger('onAcymCleanDataExternalSendingMethod');
654 - }
655 -
656 - // Clean export changes
657 - if (!in_array(self::STEP_CLEAN_EXPORT_CHANGES, $this->skip) && $this->isDailyCron()) {
658 - $exportHelper = new ExportHelper();
659 - $exportHelper->cleanExportChangesFile();
660 - }
661 -
662 - if ($this->isDailyCron()) {
663 - $time = time();
664 - $this->config->saveConfig(['cron_last_daily' => $time]);
665 - }
666 - }
667 -
668 - private function isDailyCron(): bool
669 - {
670 - // Only once a day
671 - $dailyHour = $this->config->get('daily_hour', '12');
672 - $dailyMinute = $this->config->get('daily_minute', '00');
673 - // The day it is currently based on the timezone specified in the CMS configuration
674 - $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
675 - // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
676 - $dayBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$dailyHour.':'.$dailyMinute);
677 -
678 - $time = time();
679 -
680 - //If we do not have run the cron we set it to yesterday so it will be trigger
681 - $lastCronDayBasedOnCMSTimezone = acym_date($this->config->get('cron_last_daily', $time - 86400), 'Y-m-d');
682 -
683 - return $time >= $dayBasedOnCMSTimezoneAtSpecifiedHour && $lastCronDayBasedOnCMSTimezone != $dayBasedOnCMSTimezone;
684 - }
685 -
686 - private function handleABTestCampaigns(): void
687 - {
688 - $this->checkTimeRemaining();
689 - if (in_array(self::STEP_ABTEST, $this->skip) || $this->cronTimeLimitReached) {
690 - return;
691 - }
692 -
693 - $campaignClass = new CampaignClass();
694 - $abTestCampaigns = $campaignClass->getAllAbTestCampaignsToFinishSending();
695 - foreach ($abTestCampaigns as $campaign) {
696 - if ($campaignClass->finishAbTestCampaign($campaign)) {
697 - $this->messages[] = acym_translationSprintf('ACYM_ABTEST_CAMPAIGN_X_FINAL_VERSION_SENT', $campaign->id);
698 - $this->processed = true;
699 - }
700 - }
701 - }
702 -
703 - private function handleScenario(): void
704 - {
705 - $this->checkTimeRemaining();
706 - if (in_array(self::STEP_SCENARIO, $this->skip) || $this->cronTimeLimitReached) {
707 - return;
708 - }
709 -
710 - $scenarioHelper = new ScenarioHelper();
711 - $scenarioHelper->executeAvailableSteps();
712 - $scenarioHelper->triggerTimeScenarios();
713 - }
714 -
715 - /**
716 - * We reached the maximum time allowed so the tasks are not finished, we begin a new process to finish it up
717 - */
718 - private function continueCronCall(): void
719 - {
720 - if ($this->externalSendingNotFinished) {
721 - $cronKey = '';
722 - if (!empty($this->config->get('cron_security', 0)) && !empty($this->config->get('cron_key'))) {
723 - $cronKey = '&cronKey='.$this->config->get('cron_key');
724 - }
725 - acym_makeCurlCall(acym_frontendLink('cron&task=cron&external_sending_repeat=1&t='.time().$cronKey), ['verifySsl' => false]);
726 - }
727 - }
728 -
729 - private function canSendQueuedEmails(): bool
730 - {
731 - if ($this->config->get('queue_type') === 'manual') {
732 - return false;
733 - }
734 -
735 - $dayOfWeek = acym_date('now', 'N');
736 - if ($this->config->get('queue_stop_weekend', 0) && $dayOfWeek >= 6) {
737 - return false;
738 - }
739 -
740 - // Make sure we are within the sending hours defined in the configuration
741 - $fromHour = $this->config->get('queue_send_from_hour', '00');
742 - $fromMinute = $this->config->get('queue_send_from_minute', '00');
743 - $toHour = $this->config->get('queue_send_to_hour', '23');
744 - $toMinute = $this->config->get('queue_send_to_minute', '59');
745 - $time = time();
746 -
747 - if ($fromHour != '00' || $fromMinute != '00' || $toHour != '23' || $toMinute != '59') {
748 - // The day it is currently based on the timezone specified in the CMS configuration
749 - $dayBasedOnCMSTimezone = acym_date('now', 'Y-m-d');
750 - // The UTC timestamp of the current day based on the CMS timezone, at the specified hour
751 - $fromBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$fromHour.':'.$fromMinute);
752 - $toBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate($dayBasedOnCMSTimezone.' '.$toHour.':'.$toMinute);
753 - // In case we want to send during the night and the FROM is superior to the TO (from 8pm to 4am), we should change the day of ones of the limits
754 - if ($fromBasedOnCMSTimezoneAtSpecifiedHour > $toBasedOnCMSTimezoneAtSpecifiedHour) {
755 - // TO becomes tomorrow as we are not passed midnight
756 - if ($time > $fromBasedOnCMSTimezoneAtSpecifiedHour) {
757 - $toBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate(acym_date('tomorrow', 'Y-m-d').' '.$toHour.':'.$toMinute);
758 - } elseif ($time < $toBasedOnCMSTimezoneAtSpecifiedHour) {
759 - // FROM becomes yesterday as we are passed midnight
760 - $fromBasedOnCMSTimezoneAtSpecifiedHour = acym_getTimeFromCMSDate(acym_date('yesterday', 'Y-m-d').' '.$fromHour.':'.$fromMinute);
761 - }
762 - }
763 -
764 - if ($time < $fromBasedOnCMSTimezoneAtSpecifiedHour || $time > $toBasedOnCMSTimezoneAtSpecifiedHour) {
765 - return false;
766 - }
767 - }
768 -
769 - return true;
770 - }
771 -
772 - private function sendQueuedEmails(): void
773 - {
774 - $queueHelper = new QueueHelper();
775 - $queueHelper->send_limit = (int)$this->config->get('queue_nbmail_auto');
776 - $queueHelper->report = false;
777 - $queueHelper->emailTypes = $this->emailTypes;
778 - $queueHelper->startSendingFrom = $this->startQueue;
779 - $queueHelper->process();
780 -
781 - if (!empty($queueHelper->messages)) {
782 - $this->detailMessages = array_merge($this->detailMessages, $queueHelper->messages);
783 - }
784 -
785 - if (!empty($queueHelper->nbprocess)) {
786 - $this->processed = true;
787 -
788 - if (!$queueHelper->finish && $this->externalSendingActivated) {
789 - $this->externalSendingNotFinished = true;
790 - }
791 - }
792 -
793 - $this->mainMessage = acym_translationSprintf(
794 - 'ACYM_CRON_PROCESS',
795 - $queueHelper->nbprocess,
796 - $queueHelper->successSend,
797 - $queueHelper->errorSend
798 - );
799 - $this->messages[] = $this->mainMessage;
800 -
801 - if (!empty($queueHelper->errorSend)) {
802 - $this->errorDetected = true;
803 - }
804 -
805 - $this->cronTimeLimit = $queueHelper->stoptime;
806 - }
807 -}