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 | front/FrontControllers/FrontusersController.php +192 -34 10.9.1 → 11.1.0 View file →
@@ -6,8 +6,9 @@
6 6 use AcyMailing\Classes\ListClass;
7 7 use AcyMailing\Classes\MailClass;
8 8 use AcyMailing\Classes\ScenarioClass;
9 9 use AcyMailing\Classes\UserClass;
10 +use AcyMailing\Classes\UserStatClass;
10 11 use AcyMailing\Controllers\UsersController;
11 12 use AcyMailing\Helpers\CaptchaHelper;
12 13 use AcyMailing\Helpers\EntitySelectHelper;
13 14 use AcyMailing\Helpers\ExportHelper;
@@ -33,8 +34,9 @@
33 34 $this->publicFrontTasks = [
34 35 'subscribe',
35 36 'unsubscribe',
36 37 'unsubscribeAll',
38 + 'disableTracking',
37 39 'saveSubscriptions',
38 40 'unsubscribePage',
39 41 'confirm',
40 42 'profile',
@@ -58,9 +60,9 @@
58 60 ]
59 61 );
60 62 } else {
61 63 acym_header('Content-type:text/html; charset=utf-8');
62 - echo '<script>alert("'.acym_translation($message, true).'"); window.history.go(-1);</script>';
64 + echo '<script>alert("'.esc_html(acym_translation($message)).'"); window.history.go(-1);</script>';
63 65 }
64 66 exit;
65 67 }
66 68
@@ -67,22 +69,33 @@
67 69 public function subscribe(): void
68 70 {
69 71 acym_checkRobots();
70 72
71 - if (!acym_getVar('string', 'acy_source') && !empty($_GET['user'])) {
73 + $formData = acym_getVar('array', 'user', []);
74 + if (!acym_getVar('string', 'acy_source') && !empty($formData)) {
75 + // Coming from a subscription via url...
72 76 acym_setVar('acy_source', 'url');
73 77 }
74 78
79 + // Do we have to return an ajax response or a web page ?
75 80 $ajax = acym_getVar('int', 'ajax', 0);
76 81 if ($ajax) {
82 + //in case of the page displays some warnings or whatever
77 83 @ob_end_clean();
78 84 acym_header('Content-type:application/json; charset=utf-8');
79 85 }
80 86
87 + //We only allow logged in users and this user is not logged it...
81 88 $currentUserid = acym_currentUserId();
82 89 if ((int)$this->config->get('allow_visitor', 1) != 1 && empty($currentUserid)) {
83 90 if ($ajax) {
84 - echo '{"message":"'.acym_translation('ACYM_ONLY_LOGGED', true).'","type":"error","code":"0"}';
91 + echo json_encode(
92 + [
93 + 'message' => acym_translation('ACYM_ONLY_LOGGED'),
94 + 'type' => 'error',
95 + 'code' => '0',
96 + ]
97 + );
85 98 exit;
86 99 } else {
87 100 acym_askLog(false, 'ACYM_ONLY_LOGGED');
88 101
@@ -96,9 +109,8 @@
96 109 $this->displayMessage('ACYM_WRONG_CAPTCHA', $ajax);
97 110 }
98 111 }
99 112
100 - $formData = acym_getVar('array', 'user', [], '');
101 113 $user = new \stdClass();
102 114 if (!empty($formData['email'])) {
103 115 $user->email = $formData['email'];
104 116 }
@@ -111,12 +123,15 @@
111 123 }
112 124 }
113 125 $user->email = trim($user->email);
114 126
127 + // Check email validity
115 128 if (empty($user->email) || !acym_isValidEmail($user->email, true)) {
116 129 $this->displayMessage('ACYM_VALID_EMAIL', $ajax);
117 130 }
118 131
132 + // E-mail is valid now...
133 + // Check if this user already exists or not...
119 134 $alreadyExists = $userClass->getOneByEmail($user->email);
120 135 if (!empty($alreadyExists->id)) {
121 136 $user->id = $alreadyExists->id;
122 137 }
@@ -131,8 +146,9 @@
131 146 if (!$successfullySaved || empty($user->id)) {
132 147 $this->displayMessage('ACYM_ERROR_SAVE_USER', $ajax);
133 148 }
134 149
150 + //We will now load back the user from the one we saved so that we will have all its infos
135 151 $myuser = $userClass->getOneById($user->id);
136 152 if (empty($myuser->id)) {
137 153 $this->displayMessage('ACYM_ERROR_SAVE_USER', $ajax);
138 154 }
@@ -139,9 +155,9 @@
139 155
140 156 $msgtype = 'success';
141 157 if (empty($myuser->confirmed) && $this->config->get('require_confirmation', 1) == 1) {
142 158 if ($userClass->confirmationSentSuccess || empty($userClass->confirmationSentError)) {
143 - $msg = strip_tags(acym_getVar('string', 'confirmation_message', ''));
159 + $msg = acym_stripTags(acym_getVar('string', 'confirmation_message', ''));
144 160 if (empty($msg)) {
145 161 $msg = 'ACYM_CONFIRMATION_SENT';
146 162 }
147 163 $code = 2;
@@ -151,9 +167,9 @@
151 167 $msgtype = 'error';
152 168 }
153 169 } else {
154 170 if ($userClass->subscribed) {
155 - $msg = strip_tags(acym_getVar('string', 'confirmation_message', ''));
171 + $msg = acym_stripTags(acym_getVar('string', 'confirmation_message', ''));
156 172 if (empty($msg)) {
157 173 $msg = 'ACYM_SUBSCRIPTION_OK';
158 174 }
159 175 $code = 3;
@@ -163,8 +179,9 @@
163 179 $enqueueMsgType = 'info';
164 180 }
165 181 }
166 182
183 + // Replace tags inside the $msg and redirect link
167 184 $replace = [];
168 185 foreach ($myuser as $oneProp => $oneVal) {
169 186 $replace['{user:'.$oneProp.'}'] = $oneVal;
170 187 }
@@ -171,10 +188,17 @@
171 188
172 189 $msg = str_replace(array_keys($replace), $replace, acym_translation($msg));
173 190
174 191 if ($ajax) {
192 + //Make sure the message has a valid format for Ajax... so the user can customize it the way he wants without breaking anything
175 193 $msg = str_replace(["\n", "\r", '"', '\\'], [' ', ' ', "'", '\\\\'], $msg);
176 - echo '{"message":"'.$msg.'","type":"'.$msgtype.'","code":"'.$code.'"}';
194 + echo json_encode(
195 + [
196 + 'message' => $msg,
197 + 'type' => $msgtype,
198 + 'code' => $code,
199 + ]
200 + );
177 201 exit;
178 202 } else {
179 203 acym_enqueueMessage($msg, !empty($enqueueMsgType) ? $enqueueMsgType : $msgtype);
180 204 }
@@ -207,10 +231,22 @@
207 231 $visibleSubscription = acym_getVar('array', 'subscription', []);
208 232 $hiddenLists = trim(acym_getVar('string', 'hiddenlists', ''));
209 233 $hiddenSubscription = empty($hiddenLists) ? [] : explode(',', $hiddenLists);
210 234 $unsubscribeLists = array_merge($visibleSubscription, $hiddenSubscription);
235 + acym_arrayToInteger($unsubscribeLists);
211 236
212 237 $mailId = acym_getVar('int', 'mail_id', 0);
238 +
239 + // Protect against bots
240 + if (!empty($mailId) && !empty($currentUser->id)) {
241 + $userStatClass = new UserStatClass();
242 + $userStat = $userStatClass->getOneByMailAndUserId($mailId, $currentUser->id);
243 + $delay = $this->config->get('tracking_delay', 0);
244 + if (acym_isRobot() || (!empty($userStat) && !empty($delay) && acym_getTimeFromUTCDate($userStat->send_date) > time() - $delay)) {
245 + return;
246 + }
247 + }
248 +
213 249 if (empty($unsubscribeLists)) {
214 250 $mailClass = new MailClass();
215 251 $mailType = $mailClass->getMailType($mailId);
216 252 if (empty($currentUser) || empty($currentUser->id)) {
@@ -224,8 +260,9 @@
224 260 $scenarioClass->markUserUnsubscribeFromScenario($currentUser->id, $scenarioId);
225 261 }
226 262 }
227 263 }
264 +
228 265 if (!empty($mailId)) {
229 266 $mailClass = new MailClass();
230 267 $unsubscribeLists = array_keys($mailClass->getAllListsByMailId($mailId));
231 268 }
@@ -266,11 +303,29 @@
266 303 if (empty($redirectUrl)) {
267 304 $redirectUrl = acym_rootURI();
268 305 }
269 306
270 - acym_redirect($redirectUrl);
307 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
271 308 }
272 309
310 + private function normalizeRedirectUrl(string $url): string
311 + {
312 + if ($url === '') {
313 + return '';
314 + }
315 + if (preg_match('~^[a-z][a-z0-9+.\-]*://~i', $url)) {
316 + return $url;
317 + }
318 + if (strpos($url, '/') === 0 || strpos($url, 'index.php') === 0) {
319 + return $url;
320 + }
321 + if (preg_match('~^[^/?#]+\.[a-z]{2,}(?:[/?#]|$)~i', $url)) {
322 + return 'https://'.$url;
323 + }
324 +
325 + return $url;
326 + }
327 +
273 328 public function unsubscribe(): void
274 329 {
275 330 acym_checkRobots();
276 331 $userClass = new UserClass();
@@ -277,8 +332,9 @@
277 332
278 333 $redirectToUnsubPage = $this->config->get('unsubscribe_page', 1);
279 334 $direct = acym_getVar('int', 'direct', 0);
280 335
336 + // Do we have to return an ajax response or a web page ?
281 337 $ajax = acym_getVar('int', 'ajax', 0);
282 338 if ($ajax) {
283 339 @ob_end_clean();
284 340 acym_header('Content-type:application/json; charset=utf-8');
@@ -300,9 +356,9 @@
300 356 $formData = acym_getVar('array', 'user', []);
301 357 $email = '';
302 358
303 359 if (!empty($formData['email'])) {
304 - $email = trim(strip_tags($formData['email']));
360 + $email = trim(acym_stripTags($formData['email']));
305 361 } elseif (empty($user)) {
306 362 return;
307 363 } elseif (!empty($user->email)) {
308 364 $email = $user->email;
@@ -314,8 +370,9 @@
314 370 if (empty($email) && !empty($currentEmail)) {
315 371 $email = $currentEmail;
316 372 }
317 373
374 + // Check email validity
318 375 if (empty($email) || !acym_isValidEmail($email)) {
319 376 $this->displayMessage('ACYM_VALID_EMAIL', $ajax);
320 377 }
321 378
@@ -320,8 +377,9 @@
320 377 }
321 378
322 379 $alreadyExists = $userClass->getOneByEmail($email);
323 380
381 + // User not found
324 382 if (empty($alreadyExists->id)) {
325 383 $this->displayMessage(acym_translationSprintf('ACYM_SUB_NOT_IN_LIST', $email), $ajax);
326 384 }
327 385
@@ -328,12 +386,76 @@
328 386 $fromModuleOrWidget = acym_getVar('string', 'acysubmode', '');
329 387 if ((!empty($fromModuleOrWidget) && in_array($fromModuleOrWidget, ['form_acym', 'mod_acym', 'widget_acym'])) || $ajax || !$redirectToUnsubPage || !empty($direct)) {
330 388 $this->unsubscribeDirectly($alreadyExists, $ajax);
331 389 } elseif ($redirectToUnsubPage && !$ajax && !$direct) {
390 + $identifiedEmail = !empty($user->email) ? $user->email : $currentEmail;
391 + if (empty($identifiedEmail) || strtolower($alreadyExists->email) !== strtolower($identifiedEmail)) {
392 + $this->displayMessage('ACYM_NOT_ALLOWED_MODIFY_USER', $ajax);
393 + }
332 394 $this->unsubscribePage($alreadyExists);
333 395 }
334 396 }
335 397
398 + public function disableTracking(): void
399 + {
400 + acym_checkRobots();
401 +
402 + // Do we have to return an ajax response or a web page ?
403 + $ajax = acym_getVar('int', 'ajax', 0);
404 + if ($ajax) {
405 + @ob_end_clean();
406 + acym_header('Content-type:application/json; charset=utf-8');
407 + }
408 +
409 + $userClass = new UserClass();
410 + $user = $userClass->identify(true, 'userId', 'userKey');
411 +
412 + if (empty($user->id)) {
413 + $this->displayMessage('ACYM_USER_NOT_FOUND', $ajax);
414 + }
415 +
416 + // Protect against bots opening the link right after the email was sent
417 + $mailId = acym_getVar('int', 'mail_id', 0);
418 + if (!empty($mailId)) {
419 + $userStatClass = new UserStatClass();
420 + $userStat = $userStatClass->getOneByMailAndUserId($mailId, $user->id);
421 + $delay = $this->config->get('tracking_delay', 0);
422 + if (acym_isRobot() || (!empty($userStat) && !empty($delay) && acym_getTimeFromUTCDate($userStat->send_date) > time() - $delay)) {
423 + return;
424 + }
425 + }
426 +
427 + if ((int)$user->tracking !== 0) {
428 + $userClass->disableTracking($user, $mailId);
429 + }
430 +
431 + $this->endDisableTracking('ACYM_TRACKING_DISABLED_OK', $ajax);
432 + }
433 +
434 + private function endDisableTracking(string $msg, bool $ajax, string $type = 'success'): void
435 + {
436 + $msg = acym_translation($msg);
437 +
438 + if ($ajax) {
439 + echo json_encode(
440 + [
441 + 'message' => $msg,
442 + 'type' => $type,
443 + 'code' => '10',
444 + ]
445 + );
446 + exit;
447 + }
448 + acym_enqueueMessage($msg, $type);
449 +
450 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
451 + if (empty($redirectUrl)) {
452 + $redirectUrl = acym_rootURI();
453 + }
454 +
455 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
456 + }
457 +
336 458 private function getUserFromUnsubPage(): object
337 459 {
338 460 $userID = acym_getVar('int', 'user_id');
339 461 $userClass = new UserClass();
@@ -352,14 +474,17 @@
352 474 private function unsubscribeAllInner(bool $update = false): void
353 475 {
354 476 $userClass = new UserClass();
355 477 $user = $this->getUserFromUnsubPage();
356 - $redirectUrl = $this->config->get('unsub_redirect_url', acym_rootURI());
478 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
479 + if (empty($redirectUrl)) {
480 + $redirectUrl = $this->config->get('unsub_redirect_url', '');
481 + }
357 482
358 483 $allLists = $userClass->getUserSubscriptionById($user->id);
359 484 if (empty($allLists)) {
360 485 acym_enqueueMessage(acym_translation('ACYM_NOT_SUBSCRIBED_ANY_LIST'), 'info');
361 - acym_redirect(!empty($redirectUrl) ? $redirectUrl : acym_rootURI());
486 + acym_redirect($this->normalizeRedirectUrl(!empty($redirectUrl) ? $redirectUrl : acym_rootURI()), '', 'message', true);
362 487 }
363 488
364 489 $lists = [];
365 490 foreach ($allLists as $list) {
@@ -368,8 +493,9 @@
368 493 }
369 494 }
370 495
371 496 $userClass->sendNotification($user->id, 'acy_notification_unsuball');
497 + // A notification is sent when a user unsubscribes from a list, be we already sent a notification for this
372 498 $userClass->blockNotifications = true;
373 499 $userClass->unsubscribe([$user->id], $lists);
374 500 }
375 501
@@ -375,11 +501,14 @@
375 501
376 502 private function redirectUnsubWorked(): void
377 503 {
378 504 acym_enqueueMessage(acym_translation('ACYM_SUBSCRIPTION_UPDATED_OK'));
379 - $redirectUrl = $this->config->get('unsub_redirect_url');
505 + $redirectUrl = urldecode(acym_getVar('string', 'redirectunsub', ''));
506 + if (empty($redirectUrl)) {
507 + $redirectUrl = $this->config->get('unsub_redirect_url', '');
508 + }
380 509 if (!empty($redirectUrl)) {
381 - acym_redirect($redirectUrl);
510 + acym_redirect($this->normalizeRedirectUrl($redirectUrl), '', 'message', true);
382 511 } else {
383 512 acym_redirect(acym_rootURI());
384 513 }
385 514 }
@@ -413,21 +542,28 @@
413 542 if (empty($userClass->identify(true, 'user_id', 'user_key'))) {
414 543 $this->displayMessage('ACYM_USER_NOT_FOUND', false);
415 544 }
416 545
546 + // Get the user
417 547 $user = $this->getUserFromUnsubPage();
548 + // Get the list the user want to sub
418 549 $listsChecked = acym_getVar('array', 'lists', []);
419 550 $listsChecked = array_filter($listsChecked, function ($status) {
420 551 return intval($status) === 1;
421 552 });
422 553 $listsChecked = array_keys($listsChecked);
554 + // Get the displayed lists
423 555 $displayedCheckedLists = explode(',', acym_getVar('string', 'displayed_checked_lists', ''));
556 + // We get the user subscriptions
424 557 $userSubscriptions = $userClass->getUserSubscriptionById($user->id);
425 558
559 + // We subscribe the user to the checked lists
426 560 $userClass->subscribe([$user->id], $listsChecked);
427 561
562 + // We unsub to the unchecked lists
428 563 $listsToUnsub = [];
429 564 foreach ($userSubscriptions as $subscription) {
565 + // The list wasn't checked && the list is displayed && the user is subscribed to it
430 566 if (
431 567 !in_array($subscription->id, $listsChecked)
432 568 && in_array($subscription->id, $displayedCheckedLists)
433 569 && intval($subscription->status) === 1
@@ -447,14 +583,20 @@
447 583 $mailId = acym_getVar('int', 'mail_id', 0);
448 584 $campaignListOnly = $this->config->get('unsubscribe_campaign_list_only', '0') === '1';
449 585 $displaySurvey = $this->config->get('unsubpage_survey', '0') === '1';
450 586 $surveyAnswers = $this->config->get('unsub_survey', '[]');
451 - $unsubscribeColor = $this->config->get('unsubscribe_color', '#00a4ff');
587 + $unsubscribeColor = $this->config->get('unsubscribe_color');
588 + if (empty($unsubscribeColor)) {
589 + $unsubscribeColor = '#0079d3';
590 + }
452 591 $hoverColor = $this->darkenRGBColor($unsubscribeColor, 20);
453 592
454 593 $surveyAnswers = json_decode($surveyAnswers, true);
455 594
456 - if (ACYM_CMS === 'joomla' && !empty($_GET['language'])) $lang = $_GET['language'];
595 + $languageCode = acym_getVar('string', 'language');
596 + if (ACYM_CMS === 'joomla' && !empty($languageCode)) {
597 + $lang = $languageCode;
598 + }
457 599 acym_setLanguage($lang);
458 600 acym_loadLanguage($lang);
459 601
460 602 $userSubscriptions = $userClass->getUserSubscriptionById($alreadyExists->id, 'id', false, false, true, false, $mailId, $campaignListOnly);
@@ -493,14 +635,10 @@
493 635 $data['surveyAnswers'][] = acym_translation('ACYM_OTHER');
494 636 $data['surveyAnswers'] = array_combine($data['surveyAnswers'], $data['surveyAnswers']);
495 637 }
496 638
497 - if (!empty($this->config->get('unsubscribe_color'))) {
498 - $unsubscribeColor = $this->config->get('unsubscribe_color');
499 - $hoverColor = $this->darkenRGBColor($unsubscribeColor, 20);
500 - $data['unsubscribeColor'] = $unsubscribeColor;
501 - $data['hoverColor'] = $hoverColor;
502 - }
639 + $data['unsubscribeColor'] = $unsubscribeColor;
640 + $data['hoverColor'] = $hoverColor;
503 641 $data['svgImage'] = $this->getSVGImage($unsubscribeColor, $hoverColor);
504 642
505 643 acym_setVar('layout', 'unsubscribepage');
506 644 acym_header('Content-Type: text/html; charset=utf-8');
@@ -556,8 +694,9 @@
556 694 if (acym_isRobot()) {
557 695 return;
558 696 }
559 697
698 + // We identify the user
560 699 $userClass = new UserClass();
561 700 $user = $userClass->identify(true, 'userId', 'userKey');
562 701 if (empty($user)) {
563 702 acym_enqueueMessage(acym_translation('ACYM_USER_NOT_FOUND'), 'error');
@@ -573,20 +712,23 @@
573 712 acym_enqueueMessage(acym_translation('ACYM_SUBSCRIPTION_CONFIRMED'), 'success');
574 713 }
575 714 }
576 715
716 + // Now we can really confirm the user
577 717 if (!$user->confirmed) {
578 718 $userClass->confirm($user->id);
579 719 }
580 720
721 + // Get the redirect url from the configuration page if specified
581 722 $redirectUrl = $this->config->get('confirm_redirect');
582 723 if (!empty($redirectUrl)) {
583 724 $replace = [];
725 + // We replace tags in case of the user added some dynamic information to its url.
584 726 foreach ($user as $key => $val) {
585 727 $replace['{user:'.$key.'}'] = $val;
586 728 }
587 729 $redirectUrl = str_replace(array_keys($replace), $replace, $redirectUrl);
588 - acym_redirect($redirectUrl);
730 + acym_redirect($redirectUrl, '', 'message', false);
589 731
590 732 return;
591 733 }
592 734
@@ -598,8 +740,9 @@
598 740 $userClass = new UserClass();
599 741 $user = $userClass->identify(true);
600 742
601 743 if (empty($user)) {
744 + // Check if the subscription is allowed for non registered users
602 745 $allowvisitor = $this->config->get('allow_visitor', 1);
603 746 if (empty($allowvisitor)) {
604 747 acym_askLog(true, 'ACYM_ONLY_LOGGED', 'message');
605 748
@@ -616,8 +759,9 @@
616 759 acym_addScript(false, ACYM_JS.'libraries/email-misspelled.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'libraries'.DS.'email-misspelled.min.js'));
617 760 }
618 761 acym_addScript(false, ACYM_JS.'module.min.js?v='.filemtime(ACYM_MEDIA.'js'.DS.'module.min.js'));
619 762
763 + // Get the page parameters
620 764 $params = new \stdClass();
621 765 $menu = acym_getMenu();
622 766 if (is_object($menu)) {
623 767 $params->source = 'Menu n°'.$menu->id;
@@ -624,8 +768,9 @@
624 768 $menuParameters = method_exists($menu, 'getParams') ? $menu->getParams() : $menu->params;
625 769 $menuparams = new AcymParameter($menuParameters);
626 770
627 771 if (!empty($menuparams)) {
772 + // Joomla specific params
628 773 $params->suffix = $menuparams->get('pageclass_sfx', '');
629 774 $params->page_heading = $menuparams->get('page_heading');
630 775 $params->show_page_heading = $menuparams->get('show_page_heading', 0);
631 776
@@ -638,8 +783,9 @@
638 783 if ($menuparams->get('robots')) {
639 784 acym_addMetadata('robots', $menuparams->get('robots'));
640 785 }
641 786
787 + // Our params
642 788 $params->lists = $menuparams->get('lists', 'none');
643 789 $params->listschecked = $menuparams->get('listschecked', 'none');
644 790 $params->dropdown = $menuparams->get('dropdown');
645 791 $params->hiddenlists = $menuparams->get('hiddenlists', 'None');
@@ -663,8 +809,9 @@
663 809 }
664 810
665 811 public function prepareParams(object $values): array
666 812 {
813 + //TODO problem with the types throughout the entire method
667 814 if (!isset($values->lists)) {
668 815 $values->lists = 'none';
669 816 }
670 817 if (!isset($values->listschecked)) {
@@ -676,13 +823,18 @@
676 823 if (!isset($values->hiddenlists)) {
677 824 $values->hiddenlists = 'None';
678 825 }
679 826 if (empty($values->fields)) {
680 - $values->fields = ['1', '2'];
827 + $values->fields = [2];
828 + } elseif (is_string($values->fields)) {
829 + $values->fields = explode(',', $values->fields);
681 830 }
682 831 if (!in_array('2', $values->fields) && !in_array(2, $values->fields)) {
683 832 $values->fields[] = '2';
684 833 }
834 + if (!isset($values->page_heading)) {
835 + $values->page_heading = '';
836 + }
685 837 if (!isset($values->introtext)) {
686 838 $values->introtext = '';
687 839 }
688 840 if (!isset($values->posttext)) {
@@ -698,8 +850,9 @@
698 850 if ((empty($values->lists) || in_array('None', $values->lists)) && (empty($values->hiddenlists) || strtolower(implode('', $values->hiddenlists)) == 'none')) {
699 851 $values->lists[] = 'All';
700 852 }
701 853
854 + // Get the current user and his subscription
702 855 $userClass = new UserClass();
703 856 $user = $userClass->identify(true);
704 857 if (empty($user)) {
705 858 $listClass = new ListClass();
@@ -780,8 +933,9 @@
780 933 }
781 934 $values->hiddenlists = $hiddenListsArray;
782 935 }
783 936
937 + // Overriding the list with the URL parameters: &listid= for displayed list, &hiddenlist= for hidden lists
784 938 $defaultSubscription = $subscription;
785 939 $forceLists = acym_getVar('string', 'listid', '');
786 940 if (!empty($forceLists)) {
787 941 $subscription = [];
@@ -837,9 +991,9 @@
837 991 }
838 992
839 993 public function savechanges(): void
840 994 {
841 - acym_checkToken();
995 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
842 996 acym_checkRobots();
843 997
844 998 $userClass = new UserClass();
845 999
@@ -865,9 +1019,9 @@
865 1019 }
866 1020
867 1021 public function exportdata(): void
868 1022 {
869 - acym_checkToken();
1023 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
870 1024
871 1025 $userClass = new UserClass();
872 1026 $user = $userClass->identify(true, 'userId', 'userKey');
873 1027
@@ -897,18 +1051,20 @@
897 1051 acym_createArchive($tempFolder.'export_data_user_'.$user->id, $exportFiles);
898 1052
899 1053 $exportHelper = new ExportHelper();
900 1054 $exportHelper->setDownloadHeaders('export_data_user_'.$user->id, 'zip');
1055 + // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_readfile -- Downloading a file, better than WP functions for memory handling.
901 1056 readfile($tempFolder.'export_data_user_'.$user->id.'.zip');
902 1057
1058 + // Avoid issue when user cancels the download
903 1059 ignore_user_abort(true);
904 - unlink($tempFolder.'export_data_user_'.$user->id.'.zip');
1060 + acym_deleteFile($tempFolder.'export_data_user_'.$user->id.'.zip');
905 1061 exit;
906 1062 }
907 1063
908 1064 public function gdprDelete(): void
909 1065 {
910 - acym_checkToken();
1066 + wp_verify_nonce(acym_getVar('cmd', '_wpnonce'), 'acymnonce') || die('Invalid Token');
911 1067
912 1068 $userClass = new UserClass();
913 1069 $user = $userClass->identify(true, 'userId', 'userKey');
914 1070 if (empty($user->id)) {
@@ -915,29 +1071,31 @@
915 1071 acym_redirect(acym_rootURI());
916 1072 }
917 1073
918 1074 $userClass->delete([$user->id], true);
1075 +
1076 + acym_redirect(acym_rootURI(), 'ACYM_GDPR_DATA_DELETED');
919 1077 }
920 1078
921 1079 public function ajaxGetEnqueuedMessages(): void
922 1080 {
923 - acym_session();
924 -
925 1081 $output = '';
926 1082 $types = ['success', 'info', 'warning', 'error'];
927 1083 foreach ($types as $type) {
928 - if (empty($_SESSION['acymessage'.$type])) continue;
1084 + $messages = acym_getVar('array', 'acymessage'.$type, [], 'SESSION', ACYM_ALLOWHTML);
1085 + if (empty($messages)) {
1086 + continue;
1087 + }
929 1088
930 - $messages = $_SESSION['acymessage'.$type];
931 1089 if (!is_array($messages)) {
932 1090 $messages = [$messages];
933 1091 }
934 1092
935 - $output .= '<div class="acym_callout acym__callout__front__'.$type.'" role="alert">';
1093 + $output .= '<div class="acym_callout acym__callout__front__'.esc_attr($type).'" role="alert">';
936 1094 $output .= '<div>'.implode(' ', $messages).'</div>';
937 - $output .= '<button class="acym_callout_close" aria-label="'.acym_escape(acym_translation('ACYM_CLOSE_NOTIFICATION')).'">x</button></div>';
1095 + $output .= '<button class="acym_callout_close" aria-label="'.esc_attr(acym_translation('ACYM_CLOSE_NOTIFICATION')).'">x</button></div>';
938 1096
939 - unset($_SESSION['acymessage'.$type]);
1097 + acym_setSession('acymessage'.$type, null, true);
940 1098 }
941 1099
942 1100 if (!empty($output)) {
943 1101 $output = '<div id="acym__callout__container">'.$output.'</div>';