PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
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/QueueHelper.php +170 -85 10.2.2 → 11.1.0 View file →
@@ -19,8 +19,9 @@
19 19 public bool $fromManual = false;
20 20 public int $id = 0;
21 21 public int $send_limit = 0;
22 22 public int $nbprocess = 0;
23 + public int $startSendingFrom = 0;
23 24 public int $start = 0;
24 25 public int $stoptime = 0;
25 26 public int $successSend = 0;
26 27 public int $errorSend = 0;
@@ -29,9 +30,11 @@
29 30 public array $messages = [];
30 31 public array $emailTypes = [];
31 32
32 33 private int $consecutiveError = 0;
34 + // Check apache module "mod_security" to avoid flush issue
33 35 private bool $mod_security2 = false;
36 + // Number of ob_end_flush used in the process
34 37 private int $obend = 0;
35 38
36 39 private UserClass $userClass;
37 40 private QueueClass $queueClass;
@@ -44,26 +47,27 @@
44 47 $this->userClass = new UserClass();
45 48
46 49 $this->send_limit = (int)$this->config->get('queue_nbmail', 40);
47 50
48 - acym_increasePerf();
49 -
51 + // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- The default is 60s, which is far too much for email sending.
50 52 @ini_set('default_socket_timeout', 10);
51 53
54 + // We call cron URLs but don't wait for the result, we still want the script to execute
52 55 @ignore_user_abort(true);
53 56
54 - $timelimit = intval(ini_get('max_execution_time'));
55 - if (empty($timelimit)) {
56 - $timelimit = 600;
57 + // Increase the limit to have enough time to send, and prevent infinite process
58 + $timeLimit = acym_increasePerf();
59 + if (empty($timeLimit)) {
60 + $timeLimit = 600;
57 61 }
58 62
59 - if (!empty($timelimit)) {
60 - $this->stoptime = time() + $timelimit - 4;
61 - }
63 + // We keep 4 seconds to finish the process properly
64 + $this->stoptime = time() + $timeLimit - 4;
62 65 }
63 66
64 67 public function process(): bool
65 68 {
69 + // Check if the current sending method has credits left and load the correct number of emails to send for this batch
66 70 $creditsLeft = 10000;
67 71 acym_trigger('onAcymCreditsLeft', [&$creditsLeft]);
68 72
69 73 if (empty($creditsLeft)) {
@@ -73,8 +77,9 @@
73 77 }
74 78
75 79 return false;
76 80 }
81 +
77 82 if ($this->send_limit > $creditsLeft) {
78 83 $this->send_limit = $creditsLeft;
79 84 }
80 85
@@ -79,9 +84,9 @@
79 84 }
80 85
81 86 $queueClass = new QueueClass();
82 87 $queueClass->emailtypes = $this->emailTypes;
83 - $queueElements = $queueClass->getReady($this->send_limit, $this->id);
88 + $queueElements = $queueClass->getReady($this->startSendingFrom, $this->send_limit, $this->id);
84 89
85 90 if (empty($queueElements)) {
86 91 $this->finish = true;
87 92 if ($this->report) {
@@ -90,8 +95,9 @@
90 95
91 96 return true;
92 97 }
93 98
99 + //We stop the flush
94 100 if ($this->report) {
95 101 if (function_exists('apache_get_modules')) {
96 102 $modules = apache_get_modules();
97 103 $this->mod_security2 = in_array('mod_security2', $modules);
@@ -96,9 +102,12 @@
96 102 $modules = apache_get_modules();
97 103 $this->mod_security2 = in_array('mod_security2', $modules);
98 104 }
99 105
106 + /*This is to avoid the blank page... and it apparently works! ;) */
107 + // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Disabled to prevent blank output pages.
100 108 @ini_set('output_buffering', 'off');
109 + // phpcs:ignore Squiz.PHP.DiscouragedFunctions.Discouraged -- Disabled to prevent blank output pages.
101 110 @ini_set('zlib.output_compression', 0);
102 111
103 112 if (!headers_sent()) {
104 113 while (ob_get_level() > 0 && $this->obend++ < 3) {
@@ -105,40 +114,61 @@
105 114 @ob_end_flush();
106 115 }
107 116 }
108 117
109 - $disp = '<html><head><meta http-equiv="Content-Type" content="text/html;charset=utf-8" />';
110 - $disp .= '<title>'.acym_translation('ACYM_SEND_PROCESS').'</title>';
111 - $disp .= '<style>body{font-size:12px;font-family: Arial,Helvetica,sans-serif;}</style></head><body>';
112 - $disp .= '<div style="margin-bottom: 18px;padding: 8px !important; background-color: #fcf8e3; border: 1px solid #fbeed5; border-radius: 4px;"><p style="margin:0;">'.acym_translation(
113 - 'ACYM_DONT_CLOSE'
114 - ).'</p></div>';
115 - $disp .= "<div style='display: inline;background-color : white;border : 1px solid grey; padding : 3px;font-size:14px'>";
116 - $disp .= "<span id='divpauseinfo' style='padding:10px;margin:5px;font-size:16px;font-weight:bold;display:none;background-color:black;color:white;'> </span>";
117 - $disp .= acym_translation('ACYM_SEND_PROCESS').': <span id="counter" >'.$this->start.'</span> / '.$this->total;
118 - $disp .= '</div>';
119 - $disp .= "<div id='divinfo' style='display:none; position:fixed; bottom:3px;left:3px;background-color : white; border : 1px solid grey; padding : 3px;'> </div>";
120 - $disp .= '<br /><br />';
121 - $url = acym_completeLink('queue&task=continuesend&id='.$this->id.'&totalsend='.$this->total, true, true).'&alreadysent=';
122 - $disp .= '<script type="text/javascript" language="javascript">';
123 - $disp .= 'var mycounter = document.getElementById("counter");';
124 - $disp .= 'var divinfo = document.getElementById("divinfo");
125 - var divpauseinfo = document.getElementById("divpauseinfo");
126 - function setInfo(message){ divinfo.style.display = \'block\';divinfo.innerHTML=message; }
127 - function setPauseInfo(nbpause){ divpauseinfo.style.display = \'\';divpauseinfo.innerHTML=nbpause;}
128 - function setCounter(val){ mycounter.innerHTML=val;}
129 - var scriptpause = '.$this->pause.';
130 - function handlePause(){
131 - setPauseInfo(scriptpause);
132 - if(scriptpause > 0){
133 - scriptpause = scriptpause - 1;
134 - setTimeout(\'handlePause()\',1000);
135 - }else{
136 - document.location.href=\''.$url.'\'+mycounter.innerHTML;
137 - }
138 - }
139 - </script>';
140 - echo $disp;
118 + ?>
119 + <html>
120 + <head>
121 + <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
122 + <title><?php echo esc_html(acym_translation('ACYM_SEND_PROCESS')); ?></title>
123 + <style>body{
124 + font-size: 12px;
125 + font-family: Arial, Helvetica, sans-serif;
126 + }</style>
127 + </head>
128 + <body>
129 + <div style="margin-bottom: 18px;padding: 8px !important; background-color: #fcf8e3; border: 1px solid #fbeed5; border-radius: 4px;">
130 + <p style="margin:0;"><?php echo esc_html(acym_translation('ACYM_DONT_CLOSE')); ?></p>
131 + </div>
132 + <div style="display: inline;background-color : white;border : 1px solid grey; padding : 3px;font-size:14px">
133 + <span id="divpauseinfo" style="padding:10px;margin:5px;font-size:16px;font-weight:bold;display:none;background-color:black;color:white;"> </span>
134 + <?php echo esc_html(acym_translation('ACYM_SEND_PROCESS')); ?>:
135 + <span id="counter"><?php echo intval($this->start); ?></span> / <?php echo intval($this->total); ?>
136 + </div>
137 + <div id="divinfo" style="display:none; position:fixed; bottom:3px;left:3px;background-color : white; border : 1px solid grey; padding : 3px;"></div>
138 + <br /><br />
139 + <script type="text/javascript" language="javascript">
140 + function setInfo(message) {
141 + const divinfo = document.getElementById('divinfo');
142 + divinfo.style.display = 'block';
143 + divinfo.innerHTML = message;
144 + }
145 +
146 + function setPauseInfo(nbpause) {
147 + const divpauseinfo = document.getElementById('divpauseinfo');
148 + divpauseinfo.style.display = '';
149 + divpauseinfo.innerHTML = nbpause;
150 + }
151 +
152 + function setCounter(val) {
153 + document.getElementById('counter').innerHTML = val;
154 + }
155 +
156 + let acymailingScriptPause = <?php echo intval($this->pause); ?>;
157 +
158 + function handlePause() {
159 + setPauseInfo(acymailingScriptPause);
160 + if (acymailingScriptPause > 0) {
161 + acymailingScriptPause = acymailingScriptPause - 1;
162 + setTimeout(handlePause, 1000);
163 + } else {
164 + document.location.href = <?php echo json_encode(
165 + acym_completeLink('queue&task=continuesend&id='.$this->id.'&totalsend='.$this->total, true, true).'&'.acym_getFormToken().'&alreadysent='
166 + ); ?> +document.getElementById('counter').innerHTML;
167 + }
168 + }
169 + </script>
170 + <?php
141 171 if (function_exists('ob_flush')) {
142 172 @ob_flush();
143 173 }
144 174 if (!$this->mod_security2) {
@@ -147,16 +177,23 @@
147 177 }
148 178
149 179 $mailerHelper = new MailerHelper();
150 180 $mailerHelper->report = false;
151 - if ($this->config->get('smtp_keepalive', 1) || in_array($this->config->get('mailer_method'), ['elasticemail'])) {
181 + if ($this->config->get('smtp_keepalive', 1) || $this->config->get('mailer_method') === 'elasticemail') {
152 182 $mailerHelper->SMTPKeepAlive = true;
153 183 }
154 184
185 + //To delete some entries from the queue
186 + //$queueDelete[mailing][] = subid;
155 187 $queueDelete = [];
188 + //Update some entries with a new try and a new delay
189 + //$queueUpdate[mailing][] = subid;
156 190 $queueUpdate = [];
191 + //Add some stats because we deleted the Newsletter
192 + //$statsAdd[mailing][status (1 for success/0 for fail)][] = subid;
157 193 $statsAdd = [];
158 194
195 + //Maximum number of try...
159 196 $maxTry = (int)$this->config->get('queue_try', 0);
160 197
161 198 $currentMail = $this->start;
162 199 $this->nbprocess = 0;
@@ -194,8 +231,10 @@
194 231 $isSendingMethodByListActive = false;
195 232 acym_trigger('sendingMethodByListActive', [&$isSendingMethodByListActive]);
196 233 $mailerHelper->isSendingMethodByListActive = $isSendingMethodByListActive;
197 234
235 + $statisticsByBatch = $this->config->get('queue_statistics_by_batch', 1) == 1;
236 +
198 237 foreach ($queueElements as $oneQueue) {
199 238 if ($isSendingMethodByListActive && empty($userLists[$oneQueue->user_id])) {
200 239 $userSubscriptions = $userClass->getUserStandardListIdById($oneQueue->user_id);
201 240 $userLists[$oneQueue->user_id] = empty($userSubscriptions) ? [] : $userSubscriptions;
@@ -206,9 +245,9 @@
206 245
207 246 $currentMail++;
208 247 $this->nbprocess++;
209 248 if ($this->report) {
210 - echo '<script type="text/javascript">setCounter('.$currentMail.')</script>';
249 + echo '<script type="text/javascript">setCounter('.esc_html($currentMail).')</script>';
211 250 if (function_exists('ob_flush')) {
212 251 @ob_flush();
213 252 }
214 253 if (!$this->mod_security2) {
@@ -223,9 +262,9 @@
223 262
224 263 $isAbTesting = isset($sendingParams['abtest']);
225 264 }
226 265
227 - $this->triggerSentHook((int)$oneQueue->mail_id);
266 + $this->triggerSendHook((int)$oneQueue->mail_id);
228 267 try {
229 268 $mailerHelper->isAbTest = $isAbTesting;
230 269 $mailerHelper->listsIds = empty($userLists[$oneQueue->user_id]) ? [] : $userLists[$oneQueue->user_id];
231 270 $mailerHelper->setSendingMethodSetting();
@@ -247,13 +286,15 @@
247 286 $this->consecutiveError = 0;
248 287 $queueDelete[$oneQueue->mail_id][] = $oneQueue->user_id;
249 288 $statsAdd[$oneQueue->mail_id][1][] = $oneQueue->user_id;
250 289
290 + //In case of the e-mail has been sent now, we immediately process the update/delete and stats
251 291 $queueDeleteOk = $this->deleteQueue($queueDelete);
252 292 $mailerHelper->triggerFollowUpAgain($oneQueue->mail_id, $oneQueue->user_id);
253 293 $queueDelete = [];
254 294
255 - if ($this->nbprocess % 10 == 0) {
295 + //We only update the queue and add the stats every 10 emails so that we can group things and avoid queries
296 + if (!$statisticsByBatch || $this->nbprocess % 10 == 0) {
256 297 $this->statsAdd($statsAdd);
257 298 $this->queueUpdate($queueUpdate);
258 299 $statsAdd = [];
259 300 $queueUpdate = [];
@@ -260,8 +301,9 @@
260 301 }
261 302 } elseif ($mailerHelper->dtextsFailed) {
262 303 $this->consecutiveError = 0;
263 304 $queueDelete[$oneQueue->mail_id][] = $oneQueue->user_id;
305 + //In case of the e-mail has been sent now, we immediately process the update/delete and stats
264 306 $queueDeleteOk = $this->deleteQueue($queueDelete);
265 307 $queueDelete = [];
266 308 } else {
267 309 acym_trigger('onAcymFailedSendingEmail', [$oneQueue->mail_id, $oneQueue->user_id, $mailerHelper->errorNumber]);
@@ -279,19 +321,23 @@
279 321 if ($mailerHelper->errorNumber === 1) {
280 322 $this->consecutiveError++;
281 323 }
282 324
325 + //If we have 2 consecutive errors, we pause the process a little bit to avoid possible other issues.
283 326 if ($this->consecutiveError === 2) {
284 327 sleep(1);
285 328 }
286 329 }
287 330
331 + //We delete the queue entry if it's more than number of try allowed
288 332 if (!$shouldTrySendingLater) {
289 333 $queueDelete[$oneQueue->mail_id][] = $oneQueue->user_id;
290 334 $statsAdd[$oneQueue->mail_id][0][] = $oneQueue->user_id;
291 335 if ($mailerHelper->errorNumber === 1 && $this->config->get('bounce_action_maxtry')) {
336 + //We have to delete the queue now otherwise we may have problems!
292 337 $queueDeleteOk = $this->deleteQueue($queueDelete);
293 338 $queueDelete = [];
339 + //Let's execute an action on this subscriber if we have something to do...
294 340 $otherMessage .= $this->failedActions((int)$oneQueue->user_id);
295 341 }
296 342 } elseif ($mailerHelper->failedCounting) {
297 343 $queueUpdate[$oneQueue->mail_id][] = $oneQueue->user_id;
@@ -305,8 +351,9 @@
305 351 $messageOnScreen .= ' => '.$otherMessage;
306 352 }
307 353 $this->displayMessage([$messageOnScreen], $result ? self::MESSAGE_TYPE_SUCCESS : self::MESSAGE_TYPE_ERROR, $currentMail);
308 354
355 + //We didn't delete the right number of elements so to avoid a double send process, we stop immediately
309 356 if (!$queueDeleteOk) {
310 357 $this->finish = true;
311 358 break;
312 359 }
@@ -319,12 +366,15 @@
319 366 break;
320 367 }
321 368
322 369 if ($this->consecutiveError > 3 && $this->successSend > 3) {
370 + //We refresh the page in case of we used to send e-mails but now we can not, that may be due to a mysql close connection
323 371 $this->displayMessage([acym_translation('ACYM_SEND_REFRESH_CONNECTION')], self::MESSAGE_TYPE_WARNING);
324 372 break;
325 373 }
326 374
375 + //After 5 consecutive send error, we stop the process and display a message
376 + //We stop the send process if the user closed the windows so that he can stop the send process at any time he wants
327 377 if ($this->consecutiveError > 5 || ($this->report && connection_aborted())) {
328 378 $this->finish = true;
329 379 break;
330 380 }
@@ -337,8 +387,9 @@
337 387 acym_trigger('onAcymSendCampaignOnExternalSendingMethod', [$mailId, $content]);
338 388 }
339 389 }
340 390
391 + //Update all values if it's not already done (we don't do it for each error so that's why we still have some
341 392 $this->deleteQueue($queueDelete);
342 393 $this->statsAdd($statsAdd);
343 394 $this->queueUpdate($queueUpdate);
344 395
@@ -345,8 +396,9 @@
345 396 if ($mailerHelper->SMTPKeepAlive) {
346 397 $mailerHelper->smtpClose();
347 398 }
348 399
400 + //We finished the send process
349 401 if (!empty($this->total) && $currentMail >= $this->total) {
350 402 $this->finish = true;
351 403 }
352 404
@@ -356,13 +408,15 @@
356 408 return false;
357 409 }
358 410
359 411 if ($this->report && !$this->finish) {
412 + //We handle the pause in JS.
360 413 echo '<script type="text/javascript" language="javascript">handlePause();</script>';
361 414 }
362 415
363 416 if ($this->report) {
364 - echo "</body></html>";
417 + //We need to finish the current page properly
418 + echo '</body></html>';
365 419 while ($this->obend-- > 0) {
366 420 ob_start();
367 421 }
368 422 exit;
@@ -370,8 +424,13 @@
370 424
371 425 return true;
372 426 }
373 427
428 + /**
429 + * Function to add/update elements in the stats
430 + * $statsAdd[mailing][1 for success or 0 for fail][] = subscriber id;
431 + * $statsAdd[mailing][1][] = 123;
432 + */
374 433 public function statsAdd(array $statsAdd): void
375 434 {
376 435 if (empty($statsAdd)) {
377 436 return;
@@ -379,9 +438,9 @@
379 438
380 439 $userStatClass = new UserStatClass();
381 440 $mailStatClass = new MailStatClass();
382 441
383 - $currentDate = acym_date('now', 'Y-m-d H:i:s');
442 + $currentDate = acym_date('now', 'Y-m-d H:i:s', false);
384 443 $subscriberIds = [];
385 444
386 445 foreach ($statsAdd as $mailId => $infos) {
387 446 $mailId = intval($mailId);
@@ -387,18 +446,17 @@
387 446 $mailId = intval($mailId);
388 447
389 448 foreach ($infos as $status => $subscribers) {
390 449 foreach ($subscribers as $oneSubscriber) {
391 -
392 450 $oneSubscriber = intval($oneSubscriber);
393 451
394 - $userStat = [];
395 - $userStat['user_id'] = $oneSubscriber;
396 - $userStat['mail_id'] = $mailId;
397 - $userStat['send_date'] = $currentDate;
398 - $userStat['fail'] = $status ? 0 : 1;
399 - $userStat['sent'] = $status ? 1 : 0;
400 - $userStat['statusSending'] = $status;
452 + $userStat = new \stdClass();
453 + $userStat->user_id = $oneSubscriber;
454 + $userStat->mail_id = $mailId;
455 + $userStat->send_date = $currentDate;
456 + $userStat->fail = $status ? 0 : 1;
457 + $userStat->sent = $status ? 1 : 0;
458 + $userStat->statusSending = $status;
401 459
402 460 $userStatClass->save($userStat, true);
403 461
404 462 if ($status) {
@@ -409,13 +467,12 @@
409 467
410 468 $nbSent = empty($infos[1]) ? 0 : count($infos[1]);
411 469 $nbFail = empty($infos[0]) ? 0 : count($infos[0]);
412 470
413 - $mailStat = [
414 - 'mail_id' => $mailId,
415 - 'sent' => $nbSent,
416 - 'fail' => $nbFail,
417 - ];
471 + $mailStat = new \stdClass();
472 + $mailStat->mail_id = $mailId;
473 + $mailStat->sent = $nbSent;
474 + $mailStat->fail = $nbFail;
418 475
419 476 $mailStatClass->save($mailStat);
420 477 }
421 478
@@ -423,9 +480,9 @@
423 480 acym_query('UPDATE `#__acym_user` SET `last_sent_date` = '.acym_escapeDB($currentDate).' WHERE `id` IN ('.implode(',', $subscriberIds).')');
424 481 }
425 482 }
426 483
427 - private function triggerSentHook(int $mailId): void
484 + private function triggerSendHook(int $mailId): void
428 485 {
429 486 static $triggered = [];
430 487 if (!empty($triggered[$mailId])) {
431 488 return;
@@ -434,8 +491,12 @@
434 491 $triggered[$mailId] = true;
435 492 acym_triggerCmsHook('onAcymSendMail', [$mailId]);
436 493 }
437 494
495 + /**
496 + * Function to delete elements from the queue
497 + * $queueDelete[mailId][] = subscriberId;
498 + */
438 499 private function deleteQueue(array $queueDelete): bool
439 500 {
440 501 if (empty($queueDelete)) {
441 502 return true;
@@ -442,20 +503,21 @@
442 503 }
443 504
444 505 $status = true;
445 506
446 - foreach ($queueDelete as $mailid => $subscribers) {
447 - $nbsub = count($subscribers);
448 - $res = $this->queueClass->deleteOne($subscribers, $mailid);
449 - if ($res === false || !empty($this->queueClass->errors)) {
507 + foreach ($queueDelete as $mailId => $userIds) {
508 + $nbUsers = count($userIds);
509 + $nbDeleted = $this->queueClass->deleteQueuedByUserIds($userIds, $mailId);
510 +
511 + if (!empty($this->queueClass->errors)) {
450 512 $status = false;
451 513 $this->displayMessage($this->queueClass->errors, self::MESSAGE_TYPE_ERROR);
452 514 } else {
453 - $nbdeleted = $res;
454 - if ($nbdeleted != $nbsub) {
515 + // If we didn't delete the entry, it may have been done by another send process so we stop it immediately to avoid double send
516 + if ($nbDeleted !== $nbUsers) {
455 517 $status = false;
456 518 $this->displayMessage(
457 - [$nbdeleted < $nbsub ? acym_translation('ACYM_QUEUE_DOUBLE') : $nbdeleted.' emails deleted from the queue whereas we only have '.$nbsub.' subscribers'],
519 + [$nbDeleted < $nbUsers ? acym_translation('ACYM_QUEUE_DOUBLE') : $nbDeleted.' emails deleted from the queue whereas we only have '.$nbUsers.' subscribers'],
458 520 self::MESSAGE_TYPE_ERROR
459 521 );
460 522 }
461 523 }
@@ -463,8 +525,12 @@
463 525
464 526 return $status;
465 527 }
466 528
529 + /**
530 + * Function to update elements in the queue
531 + * $queueUpdate[mailing][] = subid;
532 + */
467 533 private function queueUpdate(array $queueUpdate): void
468 534 {
469 535 if (empty($queueUpdate)) {
470 536 return;
@@ -469,8 +535,9 @@
469 535 if (empty($queueUpdate)) {
470 536 return;
471 537 }
472 538
539 + //Delay to requeue the e-mail in seconds
473 540 foreach ($queueUpdate as $mailid => $subscribers) {
474 541 $this->queueClass->delayFailed($mailid, $subscribers);
475 542 }
476 543 }
@@ -481,8 +548,9 @@
481 548 $message = acym_translation('ACYM_SEND_STOPED');
482 549 $message .= '<br />';
483 550 $message .= acym_translation('ACYM_SEND_KEPT_ALL');
484 551 $message .= '<br />';
552 + //ERROR 1 : no e-mail sent at all...
485 553 if ($this->report) {
486 554 if (empty($this->successSend) && empty($this->start)) {
487 555 $message .= acym_translation('ACYM_SEND_CHECKONE');
488 556 $message .= '<br />';
@@ -487,8 +555,9 @@
487 555 $message .= acym_translation('ACYM_SEND_CHECKONE');
488 556 $message .= '<br />';
489 557 $message .= acym_translation('ACYM_SEND_ADVISE_LIMITATION');
490 558 } else {
559 + //We used to send e-mails but now we can not any more... sounds like a server limitation!
491 560 $message .= acym_translation('ACYM_SEND_REFUSE');
492 561 $message .= '<br />';
493 562 if (!acym_level(ACYM_ESSENTIAL)) {
494 563 $message .= acym_translation('ACYM_SEND_CONTINUE_COMMERCIAL');
@@ -500,12 +569,15 @@
500 569
501 570 $this->displayMessage([$message], self::MESSAGE_TYPE_WARNING);
502 571 }
503 572
573 + /**
574 + * If num is empty then it's a message otherwise it's a send status
575 + */
504 576 private function displayMessage(array $messages, int $status, int $num = 0): void
505 577 {
506 578 foreach ($messages as $message) {
507 - $this->messages[] = strip_tags($message);
579 + $this->messages[] = acym_stripTags($message);
508 580 }
509 581
510 582 if (!$this->report) {
511 583 return;
@@ -513,11 +585,21 @@
513 585
514 586 $color = $status === self::MESSAGE_TYPE_SUCCESS ? 'green' : ($status === self::MESSAGE_TYPE_WARNING ? 'orange' : 'red');
515 587 foreach ($messages as $message) {
516 588 if (!empty($num)) {
517 - echo '<br />'.$num.' : <span style="color:'.$color.';">'.$message.'</span>';
589 + echo '<br />'.esc_html($num).' : <span style="color:'.esc_attr($color).';">'.wp_kses(
590 + $message,
591 + [
592 + 'b' => [],
593 + 'i' => [],
594 + 'a' => [
595 + 'href' => true,
596 + 'target' => true,
597 + ],
598 + ]
599 + ).'</span>';
518 600 } else {
519 - echo '<script type="text/javascript" language="javascript">setInfo(\''.addslashes($message).'\')</script>';
601 + echo '<script type="text/javascript" language="javascript">setInfo('.json_encode($message).')</script>';
520 602 }
521 603 }
522 604
523 605 if (function_exists('ob_flush')) {
@@ -529,47 +611,50 @@
529 611 }
530 612
531 613 private function failedActions(int $userId): string
532 614 {
533 - $listId = 0;
534 - if (in_array($this->config->get('bounce_action_maxtry'), ['sub', 'remove', 'unsub'])) {
615 + $actionMaxTries = $this->config->get('bounce_action_maxtry');
616 + if (in_array($actionMaxTries, ['sub', 'remove', 'unsub'])) {
535 617 $subscriptions = $this->userClass->getUserSubscriptionById($userId);
536 618 }
537 619
620 + $listId = 0;
538 621 $message = '';
539 - switch ($this->config->get('bounce_action_maxtry')) {
540 - case 'sub' :
622 + switch ($actionMaxTries) {
623 + case 'sub':
541 624 $listId = $this->config->get('bounce_action_lists_maxtry');
542 625 if (!empty($listId)) {
543 626 $message .= ' user '.$userId.' subscribed to list n°'.$listId;
544 - $this->userClass->subscribe($userId, [$listId]);
627 + $this->userClass->subscribe([$userId], [$listId]);
545 628 }
546 - case 'remove' :
629 + // There is no break here as we will remove the user from the other lists
630 + case 'remove':
547 631 $unsubLists = array_diff(array_keys($subscriptions), [$listId]);
548 632 if (!empty($unsubLists)) {
549 633 $message .= ' user '.$userId.' removed from lists '.implode(',', $unsubLists);
550 - $this->userClass->removeSubscription($userId, $unsubLists);
634 + $this->userClass->removeSubscription([$userId], $unsubLists);
551 635 } else {
552 636 $message .= ' user '.$userId.' not subscribed';
553 637 }
554 638 break;
555 - case 'unsub' :
639 + case 'unsub':
556 640 $unsubLists = array_diff(array_keys($subscriptions), [$listId]);
557 641 if (!empty($unsubLists)) {
558 642 $message .= ' user '.$userId.' unsubscribed from lists '.implode(',', $unsubLists);
559 - $this->userClass->unsubscribe($userId, $unsubLists);
643 + $this->userClass->unsubscribe([$userId], $unsubLists);
560 644 } else {
561 645 $message .= ' user '.$userId.' not unsubscribed';
562 646 }
563 647 break;
564 - case 'delete' :
648 + case 'delete':
565 649 $message .= ' user '.$userId.' deleted';
566 - $this->userClass->delete($userId);
650 + $this->userClass->delete([$userId]);
567 651 break;
568 - case 'block' :
652 + case 'block':
569 653 $message .= ' user '.$userId.' blocked';
570 - $this->userClass->deactivate($userId);
571 - $this->queueClass->deleteOne($userId);
654 + $this->userClass->deactivate([$userId]);
655 + // We delete any other e-mail from the queue as well
656 + $this->queueClass->deleteQueuedByUserIds([$userId]);
572 657 break;
573 658 }
574 659
575 660 return $message;