PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 10.2.2
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v10.2.2
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
acymailing / back / Classes / MailClass.php

MailClass.php in AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress 10.2.2, at back/Classes/MailClass.php

1,521 lines 55.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace AcyMailing\Classes;
4
5 use AcyMailing\Helpers\MailerHelper;
6 use AcyMailing\Helpers\PaginationHelper;
7 use AcyMailing\Helpers\PluginHelper;
8 use AcyMailing\Core\AcymClass;
9
10 class MailClass extends AcymClass
11 {
12 var $templateNames = [];
13
14 public $exceptKeysDecode = [];
15 public $autosave;
16 public $access;
17 public $templateId;
18
19 const FIELDS_ENCODING = ['name', 'subject', 'body', 'autosave', 'preheader'];
20
21 const TYPE_STANDARD = 'standard';
22 const TYPE_NOTIFICATION = 'notification';
23 const TYPE_OVERRIDE = 'override';
24 const TYPE_WELCOME = 'welcome';
25 const TYPE_UNSUBSCRIBE = 'unsubscribe';
26 const TYPE_AUTOMATION = 'automation';
27 const TYPE_FOLLOWUP = 'followup';
28 const TYPE_MAILBOX_ACTION = 'mailbox_action';
29 const TYPE_TEMPLATE = 'template';
30 const TYPE_SCENARIO = 'scenario';
31
32 const ALL_TYPES = [
33 self::TYPE_STANDARD,
34 self::TYPE_NOTIFICATION,
35 self::TYPE_OVERRIDE,
36 self::TYPE_WELCOME,
37 self::TYPE_UNSUBSCRIBE,
38 self::TYPE_AUTOMATION,
39 self::TYPE_FOLLOWUP,
40 self::TYPE_MAILBOX_ACTION,
41 self::TYPE_TEMPLATE,
42 self::TYPE_SCENARIO,
43 ];
44
45 const TYPES_TRANSACTIONAL = [
46 self::TYPE_NOTIFICATION,
47 self::TYPE_OVERRIDE,
48 self::TYPE_WELCOME,
49 self::TYPE_UNSUBSCRIBE,
50 self::TYPE_TEMPLATE,
51 self::TYPE_SCENARIO,
52 ];
53
54 const TYPES_WITH_STATS = [
55 self::TYPE_STANDARD,
56 self::TYPE_AUTOMATION,
57 self::TYPE_WELCOME,
58 self::TYPE_UNSUBSCRIBE,
59 self::TYPE_FOLLOWUP,
60 self::TYPE_MAILBOX_ACTION,
61 self::TYPE_SCENARIO,
62 ];
63
64 const TYPES_NO_NAME = [
65 self::TYPE_NOTIFICATION,
66 self::TYPE_OVERRIDE,
67 ];
68
69 const MAX_ALLOWED_TEMPLATE_FILES = 100;
70 const MAX_ALLOWED_TEMPLATE_SIZE = 20971520;
71 const ALLOWED_TEMPLATE_FILE_TYPES = [
72 'image/jpeg',
73 'image/png',
74 'image/gif',
75 'text/html',
76 'image/x-ms-bmp',
77 'image/bmp',
78 'text/plain',
79 'image/vnd.microsoft.icon',
80 ];
81
82 public function __construct()
83 {
84 parent::__construct();
85
86 $this->table = 'mail';
87 $this->pkey = 'id';
88 }
89
90 public function getMatchingElements(array $settings = []): array
91 {
92 $query = 'SELECT mail.* FROM #__acym_mail AS mail';
93 $queryCount = 'SELECT COUNT(mail.id) AS total FROM #__acym_mail AS mail';
94
95 $filters = [];
96 $tagJoin = '';
97
98 if (!empty($settings['tag'])) {
99 $tagJoin = ' JOIN #__acym_tag AS tag ON mail.id = tag.id_element ';
100 $filters[] = 'tag.name = '.acym_escapeDB($settings['tag']);
101 $filters[] = 'tag.type = "mail"';
102 }
103 $query .= $tagJoin;
104 $queryCount .= $tagJoin;
105
106 if (!empty($settings['search'])) {
107 $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.acym_utf8Encode($settings['search']).'%');
108 }
109
110 if (!empty($settings['gettingTemplates'])) {
111 $filters[] = 'mail.type = '.acym_escapeDB(self::TYPE_TEMPLATE);
112 if (!acym_isAdmin()) {
113 $currentUserId = acym_currentUserId();
114 $condition = 'mail.creator_id = '.intval($currentUserId);
115
116 $userGroups = acym_getGroupsByUser($currentUserId);
117 if (!empty($userGroups)) {
118 $condition .= ' OR access LIKE "%,'.implode(',%" OR access LIKE "%,', $userGroups).',%"';
119 }
120
121 $filters[] = $condition;
122 }
123 } else {
124 if (!empty($settings['automation']) || empty($settings['onlyStandard'])) {
125 $filters[] = 'mail.type != '.acym_escapeDB(self::TYPE_NOTIFICATION);
126 $filters[] = 'mail.type != '.acym_escapeDB(self::TYPE_OVERRIDE);
127 } else {
128 $filters[] = 'mail.type IN ('.acym_escapeDB(self::TYPE_STANDARD).', '.acym_escapeDB(self::TYPE_TEMPLATE).')';
129 }
130
131 if (empty($settings['automation'])) {
132 $filters[] = 'mail.type IN ('.acym_escapeDB(self::TYPE_TEMPLATE).', '.acym_escapeDB(self::TYPE_WELCOME).', '.acym_escapeDB(self::TYPE_UNSUBSCRIBE).')';
133 }
134
135 if (!empty($settings['creator_id'])) {
136 $mailTypeCondition = 'mail.type IN ('.acym_escapeDB(self::TYPE_TEMPLATE).', '.acym_escapeDB(self::TYPE_WELCOME).', '.acym_escapeDB(self::TYPE_UNSUBSCRIBE).')';
137 $userGroups = acym_getGroupsByUser($settings['creator_id']);
138 $groupCondition = '(mail.access LIKE "%,'.implode(',%" OR mail.access LIKE "%,', $userGroups).',%")';
139 $filter = 'mail.creator_id = '.intval($settings['creator_id']).' OR ('.$mailTypeCondition.' AND '.$groupCondition.')';
140
141 if (!acym_isAdmin() && !empty($settings['element_tab'])) {
142 $filter = '('.$filter.')
143 OR list.cms_user_id = '.intval($settings['creator_id']).'
144 OR (list.access LIKE "%,'.implode(',%" OR list.access LIKE "%,', $userGroups).',%")';
145 }
146
147 $filters['list'] = '('.$filter.')';
148 }
149 }
150
151 $filters[] = 'mail.parent_id IS NULL';
152
153 if (!empty($settings['drag_editor'])) {
154 $filters[] = 'mail.drag_editor = 1';
155 }
156
157 if (!empty($settings['element_tab'])) {
158 $statJoin = ' LEFT JOIN #__acym_mail_stat AS mail_stat ON mail.id = mail_stat.mail_id ';
159 $listJoin = acym_isAdmin() ? '' : ' LEFT JOIN #__acym_list AS list ON list.'.acym_escape($settings['element_tab']).'_id = mail.id';
160 $query = 'SELECT DISTINCT mail.*, mail_stat.sent as subscribers, mail_stat.open_unique FROM #__acym_mail AS mail'.$statJoin.$tagJoin.$listJoin;
161 $filters[] = 'mail.type = '.acym_escapeDB($settings['element_tab']);
162 }
163
164 if (!empty($filters)) {
165 $query .= ' WHERE ('.implode(') AND (', $filters).')';
166 if (!acym_isAdmin()) {
167 unset($filters['list']);
168 }
169 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
170 }
171
172 if (!empty($settings['ordering']) && !empty($settings['ordering_sort_order'])) {
173 $query .= ' ORDER BY mail.'.acym_secureDBColumn($settings['ordering']).' '.acym_secureDBColumn(strtoupper($settings['ordering_sort_order']));
174 }
175
176 if (empty($settings['offset']) || $settings['offset'] < 0) {
177 $settings['offset'] = 0;
178 }
179
180 if (empty($settings['elementsPerPage']) || $settings['elementsPerPage'] < 1) {
181 $pagination = new PaginationHelper();
182 $settings['elementsPerPage'] = $pagination->getListLimit();
183 }
184
185 $results['elements'] = $this->decode(acym_loadObjectList($query, '', $settings['offset'], $settings['elementsPerPage']));
186 $results['total'] = acym_loadObject($queryCount);
187
188 if (!empty($settings['element_tab'])) {
189 $this->getAllListIdsForWelcomeUnsub($results['elements'], $settings['element_tab']);
190 }
191
192 $results['status'] = [];
193
194 if (!empty($settings['element_tab'])) {
195 $urlClickClass = new UrlClickClass();
196 for ($i = 0 ; $i < count($results['elements']) ; $i++) {
197 $results['elements'][$i]->open = 0;
198 if (!empty($results['elements'][$i]->subscribers)) {
199 $results['elements'][$i]->open = number_format($results['elements'][$i]->open_unique / $results['elements'][$i]->subscribers * 100, 2);
200
201 $clicksNb = $urlClickClass->getNumberUsersClicked($results['elements'][$i]->id);
202 $results['elements'][$i]->click = number_format($clicksNb / $results['elements'][$i]->subscribers * 100, 2);
203 }
204 }
205 }
206
207 return $results;
208 }
209
210 private function getAllListIdsForWelcomeUnsub(&$elements, $type)
211 {
212 if (empty($elements)) return true;
213 $column = $type == self::TYPE_WELCOME ? 'welcome_id' : 'unsubscribe_id';
214
215 foreach ($elements as $key => $element) {
216 $elements[$key]->lists = acym_loadObjectList('SELECT color, name FROM #__acym_list WHERE '.$column.' = '.intval($element->id));
217 }
218
219 return true;
220 }
221
222 public function getAll(?string $key = null): array
223 {
224 $allMails = parent::getAll($key);
225
226 return $this->decode($allMails);
227 }
228
229 public function getOneById($id, $needTranslatedSettings = false)
230 {
231 $mail = $this->decode(acym_loadObject('SELECT * FROM #__acym_mail WHERE id = '.intval($id)));
232
233 if (!empty($mail)) {
234 $tagsClass = new TagClass();
235 $mail->tags = $tagsClass->getAllTagsByElementId(TagClass::TYPE_MAIL, intval($id));
236 }
237
238 if (isset($mail->access) && !is_array($mail->access)) $mail->access = explode(',', $mail->access);
239
240 if (!empty($mail->parent_id) && $needTranslatedSettings) {
241 $this->getTranslatedSettingsMail($mail);
242 }
243
244 return $mail;
245 }
246
247 private function getTranslatedSettingsMail(&$mail)
248 {
249 $parentMailTranslation = acym_loadResult('SELECT translation FROM #__acym_mail WHERE id = '.intval($mail->parent_id));
250 $parentMailTranslation = empty($parentMailTranslation) ? [] : json_decode($parentMailTranslation, true);
251
252 $translationConfig = $this->config->get('sender_info_translation', '');
253 $translationConfig = empty($translationConfig) ? [] : json_decode($translationConfig, true);
254
255 if (!empty($parentMailTranslation[$mail->language])) {
256 $senderTranslation = $parentMailTranslation[$mail->language];
257 } elseif (!empty($translationConfig[$mail->language])) {
258 $senderTranslation = $translationConfig[$mail->language];
259 $senderTranslation['reply_to_email'] = $senderTranslation['replyto_email'];
260 $senderTranslation['reply_to_name'] = $senderTranslation['replyto_name'];
261 } else {
262 return $mail;
263 }
264
265 $mail->from_name = $senderTranslation['from_name'];
266 $mail->from_email = $senderTranslation['from_email'];
267 $mail->reply_to_name = $senderTranslation['reply_to_name'];
268 $mail->reply_to_email = $senderTranslation['reply_to_email'];
269
270 return $mail;
271 }
272
273 public function getOneByName(string $name, bool $needTranslatedSettings = false, string $type = '')
274 {
275 $query = 'SELECT * FROM #__acym_mail WHERE `parent_id` IS NULL AND `name` = '.acym_escapeDB(acym_utf8Encode($name));
276 if (!empty($type)) {
277 $query .= ' AND `type` = '.acym_escapeDB($type);
278 }
279
280 $mail = $this->decode(acym_loadObject($query));
281
282 if (!empty($mail)) {
283 $tagsClass = new TagClass();
284 $mail->tags = $tagsClass->getAllTagsByElementId(TagClass::TYPE_MAIL, intval($mail->id));
285 }
286
287 if (!empty($mail->parent_id) && $needTranslatedSettings) {
288 $this->getTranslatedSettingsMail($mail);
289 }
290
291 return $mail;
292 }
293
294 public function getMailsByType(?string $typeMail, array $settings)
295 {
296 if (empty($settings['key'])) {
297 $settings['key'] = '';
298 }
299 if (empty($settings['offset'])) {
300 $settings['offset'] = 0;
301 }
302 if (empty($settings['mailsPerPage'])) {
303 $settings['mailsPerPage'] = 12;
304 }
305 $search = $settings['filters']['search'] ?? '';
306
307 $query = 'SELECT * FROM #__acym_mail AS mail';
308 $queryCount = 'SELECT count(*) FROM #__acym_mail AS mail';
309
310 $filters = [];
311 if (!empty($typeMail)) {
312 $filters[] = 'mail.type = '.acym_escapeDB($typeMail);
313 }
314
315 if (!empty($search)) {
316 $filters[] = 'mail.name LIKE '.acym_escapeDB('%'.$search.'%');
317 }
318
319 if (!empty($filters)) {
320 $query .= ' WHERE ('.implode(') AND (', $filters).')';
321 $queryCount .= ' WHERE ('.implode(') AND (', $filters).')';
322 }
323
324 $query .= ' ORDER BY id DESC';
325
326 $results['mails'] = $this->decode(acym_loadObjectList($query, $settings['key'], $settings['offset'], $settings['mailsPerPage']));
327 $results['total'] = acym_loadResult($queryCount);
328
329 return $results;
330 }
331
332 public function getAllListsWithCountSubscribersByMailIds($ids)
333 {
334 acym_arrayToInteger($ids);
335 if (empty($ids)) {
336 return [];
337 }
338
339 $query = 'SELECT mailLists.list_id, mailLists.mail_id, list.*, COUNT(userLists.user_id) AS subscribers
340 FROM #__acym_mail_has_list AS mailLists
341 JOIN #__acym_list AS list ON mailLists.list_id = list.id
342 LEFT JOIN #__acym_user_has_list AS userLists
343 JOIN #__acym_user AS acyuser ON userLists.user_id = acyuser.id
344 AND userLists.status = 1
345 AND acyuser.active = 1 ';
346
347 if ($this->config->get('require_confirmation', 1) == 1) {
348 $query .= ' AND acyuser.confirmed = 1 ';
349 }
350
351 $query .= 'ON list.id = userLists.list_id
352 WHERE mailLists.mail_id IN ('.implode(',', $ids).')
353 GROUP BY mailLists.list_id, mailLists.mail_id';
354
355 acym_query('SET SQL_BIG_SELECTS=1');
356
357 return acym_loadObjectList($query);
358 }
359
360 public function getAllListsByMailIds($ids)
361 {
362 acym_arrayToInteger($ids);
363 if (empty($ids)) {
364 return [];
365 }
366
367 $query = 'SELECT mailLists.mail_id, list.name, list.color
368 FROM #__acym_mail_has_list AS mailLists
369 JOIN #__acym_list AS list ON mailLists.list_id = list.id
370 WHERE mailLists.mail_id IN ('.implode(',', $ids).')';
371
372 return acym_loadObjectList($query);
373 }
374
375 public function getAllListsByMailId($id)
376 {
377 if (is_array($id)) $id = $id[0];
378
379 $mail = $this->getOneById($id);
380 if (empty($mail)) return [];
381
382 if (self::TYPE_WELCOME === $mail->type) {
383 $query = 'SELECT * FROM #__acym_list WHERE welcome_id = '.intval($id);
384 } elseif (self::TYPE_FOLLOWUP === $mail->type) {
385 $query = 'SELECT list.* FROM #__acym_followup_has_mail AS followup_mail
386 JOIN #__acym_followup AS followup ON followup.id = followup_mail.followup_id AND followup_mail.mail_id = '.intval($id).'
387 JOIN #__acym_list AS list ON list.id = followup.list_id';
388 } else {
389 $query = 'SELECT list.*
390 FROM #__acym_mail_has_list AS mailLists
391 JOIN #__acym_mail AS mail ON (mailLists.mail_id = mail.id OR mailLists.mail_id = mail.parent_id) AND mail.id = '.intval($id).'
392 JOIN #__acym_list AS list ON mailLists.list_id = list.id';
393 }
394
395 return acym_loadObjectList($query, 'id');
396 }
397
398 public function getAllListsByMailIdAndUserId($mailId, $userId)
399 {
400 if (empty($mailId) || empty($userId)) return [];
401
402 $query = 'SELECT list.* FROM #__acym_list AS list';
403 $query .= ' JOIN #__acym_user_has_list AS userlist ON list.id = userlist.list_id AND userlist.user_id = '.intval($userId);
404 $query .= ' JOIN #__acym_mail_has_list AS maillist ON maillist.list_id = list.id AND maillist.mail_id = '.intval($mailId);
405
406 return acym_loadObjectList($query);
407 }
408
409 public function save($mailToSave)
410 {
411 $mail = clone $mailToSave;
412
413 if (isset($mail->tags)) {
414 $tags = $mail->tags;
415 unset($mail->tags);
416 }
417
418 if (empty($mail->id)) {
419 $mail->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
420 if (empty($mail->creator_id)) $mail->creator_id = acym_currentUserId();
421 }
422
423 $mail = $this->encode($mail);
424
425 $mail->autosave = null;
426
427
428 if (isset($mail->thumbnail) && ((empty($mail->thumbnail) && !is_null($mail->thumbnail)) || strpos($mail->thumbnail, 'data:image/png;base64') !== false)) {
429 unset($mail->thumbnail);
430 }
431
432 if (!isset($mail->access)) {
433 $mail->access = '';
434 }
435
436 foreach ($mail as $oneAttribute => $value) {
437 if (empty($value) || in_array($oneAttribute, ['thumbnail', 'settings'])) {
438 continue;
439 }
440
441 if ($oneAttribute === 'access' && is_array($mail->$oneAttribute)) {
442 $value = ','.trim(implode(',', $mail->$oneAttribute), ',').',';
443 $mail->$oneAttribute = $value;
444 }
445
446 if (is_array($value)) {
447 $mail->$oneAttribute = json_encode($value);
448 }
449
450 if (in_array($oneAttribute, ['body', 'headers'])) {
451 $mail->$oneAttribute = preg_replace('#<input[^>]*value="[^"]*"[^>]*>#Uis', '', $mail->$oneAttribute);
452 $mail->$oneAttribute = preg_replace('#<script.*</script>#Uis', '', $mail->$oneAttribute);
453
454 $mail->$oneAttribute = str_replace(' contenteditable="true"', '', $mail->$oneAttribute);
455 } else {
456 $mail->$oneAttribute = strip_tags($mail->$oneAttribute);
457 }
458 }
459
460 $mailID = parent::save($mail);
461
462 if (!empty($mailID) && isset($tags)) {
463 $tagClass = new TagClass();
464 $tagClass->setTags(TagClass::TYPE_MAIL, intval($mailID), $tags);
465 }
466
467 return $mailID;
468 }
469
470 public function autoSave($mail, $language = 'main')
471 {
472 if (empty($mail->id)) return false;
473 $mail->autosave = str_replace(' contenteditable="true"', '', $mail->autosave);
474
475 if (acym_isMultilingual() && $language !== 'main') {
476 $translationId = $this->getTranslationId($mail->id, $language);
477 if (empty($translationId)) {
478 $parentCopy = $this->getOneById($mail->id);
479 if (empty($parentCopy)) return false;
480
481 unset($parentCopy->id);
482 $parentCopy->parent_id = $mail->id;
483 $parentCopy->language = $language;
484 $translationId = $this->save($parentCopy);
485 }
486 $mail->id = $translationId;
487 }
488
489 $mail = $this->encode($mail);
490
491 return parent::save($mail);
492 }
493
494 public function delete($elements)
495 {
496 if (empty($elements)) return 0;
497 if (!is_array($elements)) $elements = [$elements];
498
499 $this->deleteMediaFolder($elements);
500 acym_arrayToInteger($elements);
501
502 $favoriteTemplate = (int)$this->config->get('favorite_template', 0);
503 if (in_array($favoriteTemplate, $elements)) {
504 $this->config->save(['favorite_template' => 0]);
505 }
506
507 $allThumbnailToDelete = acym_loadResultArray('SELECT DISTINCT thumbnail FROM #__acym_mail WHERE id IN ('.implode(',', $elements).')');
508
509 $translations = acym_loadResultArray('SELECT id FROM #__acym_mail WHERE parent_id IN ('.implode(',', $elements).')');
510 $elements = array_merge($elements, $translations);
511 if (!empty($translations)) {
512 acym_query('UPDATE #__acym_mail SET `parent_id` = null WHERE `id` IN ('.implode(',', $translations).')');
513 }
514
515 acym_query('UPDATE #__acym_list SET welcome_id = null WHERE welcome_id IN ('.implode(',', $elements).')');
516 acym_query('UPDATE #__acym_list SET unsubscribe_id = null WHERE unsubscribe_id IN ('.implode(',', $elements).')');
517 acym_query('DELETE FROM #__acym_queue WHERE mail_id IN ('.implode(',', $elements).')');
518 acym_query('DELETE FROM #__acym_mail_has_list WHERE mail_id IN ('.implode(',', $elements).')');
519 acym_query('DELETE FROM #__acym_tag WHERE `type` = "mail" AND `id_element` IN ('.implode(',', $elements).')');
520 acym_query('DELETE FROM #__acym_user_stat WHERE mail_id IN ('.implode(',', $elements).')');
521 acym_query('DELETE FROM #__acym_url_click WHERE mail_id IN ('.implode(',', $elements).')');
522 acym_query('DELETE FROM #__acym_mail_stat WHERE mail_id IN ('.implode(',', $elements).')');
523 acym_query('DELETE FROM #__acym_followup_has_mail WHERE mail_id IN ('.implode(',', $elements).')');
524 acym_query('DELETE FROM #__acym_mail_archive WHERE mail_id IN ('.implode(',', $elements).')');
525
526 $return = parent::delete($elements);
527
528 $this->deleteUnusedThumbnails($allThumbnailToDelete);
529
530 return $return;
531 }
532
533 public function deleteMediaFolder($elements)
534 {
535 if (empty($elements)) return;
536
537 acym_arrayToInteger($elements);
538 $results = acym_loadResultArray('SELECT mail_settings FROM #__acym_mail WHERE mail_settings IS NOT NULL AND id IN ('.implode(',', $elements).')');
539
540 foreach ($results as $template) {
541 $settings = json_decode($template, true);
542
543 if (empty($settings['media_folder']) || !file_exists(ACYM_TEMPLATE.$settings['media_folder'])) continue;
544 acym_deleteFolder(ACYM_TEMPLATE.$settings['media_folder']);
545 }
546 }
547
548 public function deleteUnusedThumbnails($thumbnails)
549 {
550 if (empty($thumbnails)) return;
551
552 if (!is_array($thumbnails)) $thumbnails = [$thumbnails];
553 foreach ($thumbnails as $key => $oneThumb) {
554 $thumbnails[$key] = acym_escapeDB($oneThumb);
555 }
556
557 $stillUsedThumbnails = acym_loadResultArray('SELECT thumbnail FROM #__acym_mail WHERE thumbnail IN ('.implode(',', $thumbnails).')');
558 $thumbnailToDelete = array_diff($thumbnails, $stillUsedThumbnails);
559 foreach ($thumbnailToDelete as $one) {
560 if (!empty($one) && file_exists(ACYM_UPLOAD_FOLDER_THUMBNAIL.$one)) {
561 unlink(ACYM_UPLOAD_FOLDER_THUMBNAIL.$one);
562 }
563 }
564 }
565
566 public function deleteOneAttachment($mailId, $idAttachment)
567 {
568 $mailId = intval($mailId);
569 if (empty($mailId)) {
570 return false;
571 }
572 $mail = $this->getOneById($mailId);
573
574 $attachments = $mail->attachments;
575 if (empty($attachments)) {
576 return false;
577 }
578 $decodedAttach = json_decode($attachments, true);
579 unset($decodedAttach[$idAttachment]);
580 $newAttachments = [];
581 if (!empty($decodedAttach)) {
582 foreach ($decodedAttach as $oneAttach) {
583 $newAttachments[] = $oneAttach;
584 }
585 }
586 $attachDb = json_encode($newAttachments);
587
588 return acym_query('UPDATE #__acym_mail SET attachments = '.acym_escapeDB($attachDb).' WHERE id = '.intval($mailId).' OR parent_id = '.intval($mailId));
589 }
590
591 public function createTemplateFile($id)
592 {
593 if (empty($id)) {
594 return '';
595 }
596 $cssfile = ACYM_TEMPLATE.'css'.DS.'template_'.$id.'.css';
597
598 $template = $this->getOneById($id);
599 if (empty($template->id)) {
600 return '';
601 }
602 $css = $this->buildCSS($template->stylesheet);
603
604 if (empty($css)) {
605 return '';
606 }
607
608 acym_createDir(ACYM_TEMPLATE.'css');
609
610 if (acym_writeFile($cssfile, $css)) {
611 return $cssfile;
612 } else {
613 acym_enqueueMessage('Could not create the file '.$cssfile, 'error');
614
615 return '';
616 }
617 }
618
619 public function buildCSS($stylesheet): string
620 {
621 if (empty($stylesheet)) {
622 return '';
623 }
624
625 $inline = '';
626
627 if (preg_match_all('#@import[^;]*;#is', $stylesheet, $results)) {
628 foreach ($results[0] as $oneResult) {
629 $inline .= trim($oneResult)."\n";
630 $stylesheet = str_replace($oneResult, '', $stylesheet);
631 }
632 }
633
634 $inline .= $stylesheet;
635
636 return $inline;
637 }
638
639 public function doupload(): bool
640 {
641 $zipFilePath = $this->uploadTemplate();
642 if (empty($zipFilePath)) {
643 return false;
644 }
645
646 $templateFolder = $this->extractTemplate($zipFilePath);
647 if (empty($templateFolder)) {
648 return false;
649 }
650
651 if (!$this->installExtractedTemplate($templateFolder)) {
652 return false;
653 }
654
655 return true;
656 }
657
658 private function uploadTemplate()
659 {
660 $importFile = acym_getVar('file', 'uploadedfile', '', 'files');
661
662 $fileError = $importFile['error'];
663 if ($fileError > 0) {
664 switch ($fileError) {
665 case 1:
666 acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_1'), 'error');
667
668 return false;
669 case 2:
670 acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_2'), 'error');
671
672 return false;
673 case 3:
674 acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_3'), 'error');
675
676 return false;
677 case 4:
678 acym_enqueueMessage(acym_translation('ACYM_FILE_UPLOAD_ERROR_4'), 'error');
679
680 return false;
681 default:
682 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_5', $fileError), 'error');
683
684 return false;
685 }
686 }
687 if (empty($importFile['name'])) {
688 acym_enqueueMessage(acym_translation('ACYM_BROWSE_FILE'), 'error');
689
690 return false;
691 }
692
693 $uploadPath = acym_cleanPath(ACYM_ROOT.ACYM_MEDIA_FOLDER.'templates');
694
695 if (!is_writable($uploadPath)) {
696 @chmod($uploadPath, '0755');
697 if (!is_writable($uploadPath)) {
698 acym_enqueueMessage(acym_translationSprintf('ACYM_WRITABLE_FOLDER', $uploadPath), 'warning');
699 }
700 }
701
702 if (!(bool)ini_get('file_uploads')) {
703 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_6'), 'error');
704
705 return false;
706 }
707
708 if (!extension_loaded('zlib')) {
709 acym_raiseError(500, acym_translation('ACYM_MISSING_ZLIB'));
710
711 return false;
712 }
713
714 $filename = strtolower(acym_makeSafeFile($importFile['name']));
715 $extension = strtolower(substr($filename, strrpos($filename, '.') + 1));
716
717 $allowedFileType = true;
718 if ($extension !== 'zip') {
719 $allowedFileType = false;
720 } elseif (!in_array($importFile['type'], ['application/zip', 'application/x-zip-compressed'])) {
721 $allowedFileType = false;
722 } elseif (function_exists('mime_content_type') && !in_array(mime_content_type($importFile['tmp_name']), ['application/zip', 'application/x-zip-compressed'])) {
723 $allowedFileType = false;
724 }
725
726 if (!$allowedFileType) {
727 acym_enqueueMessage(acym_translationSprintf('ACYM_ACCEPTED_TYPE', $extension, 'zip'), 'error');
728
729 return false;
730 }
731
732 if (class_exists('ZipArchive')) {
733 $zip = new \ZipArchive();
734 if (filesize($importFile['tmp_name']) > self::MAX_ALLOWED_TEMPLATE_SIZE || !$zip->open($importFile['tmp_name']) || $zip->count() > self::MAX_ALLOWED_TEMPLATE_FILES) {
735 acym_enqueueMessage(acym_translation('ACYM_UPLOADED_ARCHIVE_NOT_ALLOWED'), 'error');
736
737 return false;
738 }
739
740 $zip->close();
741 }
742
743 $tmpPath = acym_getCMSConfig('tmp_path', ACYM_MEDIA.'tmp'.DS);
744 $zipFilePath = acym_cleanPath($tmpPath.DS.$filename);
745
746 $uploaded = acym_uploadFile($importFile['tmp_name'], $zipFilePath);
747 if (!$uploaded) {
748 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_7', $importFile['tmp_name'], $zipFilePath), 'error');
749
750 return false;
751 }
752
753 return $zipFilePath;
754 }
755
756 public function extractTemplate($zipFilePath, $deleteZip = true)
757 {
758 $extractdir = acym_cleanPath(dirname($zipFilePath).DS.uniqid().uniqid().uniqid().'_template');
759
760 $result = acym_extractArchive($zipFilePath, $extractdir);
761
762 if (!$result) {
763 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_9', $zipFilePath, $extractdir), 'error');
764
765 return false;
766 }
767
768 if ($deleteZip) {
769 acym_deleteFile($zipFilePath);
770 }
771
772 $allFiles = acym_getFiles($extractdir, '.', true, true, [], []);
773 foreach ($allFiles as $oneFile) {
774 if (function_exists('mime_content_type')) {
775 $fileType = mime_content_type($oneFile);
776 if (in_array($fileType, self::ALLOWED_TEMPLATE_FILE_TYPES) && preg_match('#\.(jpg|gif|png|jpeg|ico|bmp|html|htm|css|webp)$#i', $oneFile)) {
777 continue;
778 }
779 } elseif (preg_match('#\.(jpg|gif|png|jpeg|ico|bmp|html|htm|css|webp)$#i', $oneFile)) {
780 continue;
781 }
782
783 if (acym_deleteFile($oneFile)) {
784 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_8', $oneFile), 'warning');
785 }
786 }
787
788 return $extractdir;
789 }
790
791 public function installExtractedTemplate($templateFolder)
792 {
793 if ($this->detecttemplates($templateFolder)) {
794 $messages = $this->templateNames;
795 array_unshift($messages, acym_translationSprintf('ACYM_TEMPLATES_INSTALL', count($this->templateNames)));
796 acym_enqueueMessage($messages);
797 if (is_dir($templateFolder)) acym_deleteFolder($templateFolder);
798
799 return true;
800 }
801
802 acym_enqueueMessage(acym_translationSprintf('ACYM_FILE_UPLOAD_ERROR_10'), 'error');
803 if (is_dir($templateFolder)) acym_deleteFolder($templateFolder);
804
805 return false;
806 }
807
808 public function detecttemplates($folder)
809 {
810 $allFiles = acym_getFiles($folder);
811 if (!empty($allFiles)) {
812 foreach ($allFiles as $oneFile) {
813 if (preg_match('#^.*(html|htm)$#i', $oneFile)) {
814 if ($this->_installtemplate($folder.DS.$oneFile)) return true;
815 }
816 }
817 }
818
819 $status = false;
820 $allFolders = acym_getFolders($folder);
821 if (!empty($allFolders)) {
822 foreach ($allFolders as $oneFolder) {
823 $status = $this->detecttemplates($folder.DS.$oneFolder) || $status;
824 }
825 }
826
827 return $status;
828 }
829
830 private function _installtemplate($filepath)
831 {
832 $fileContent = acym_fileGetContent($filepath);
833
834 $newTemplate = new \stdClass();
835 $newTemplate->name = trim(preg_replace('#[^a-z0-9]#i', ' ', substr(dirname($filepath), strpos($filepath, '_template'))));
836 if (preg_match('#< *title[^>]*>(.*)< */ *title *>#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->name = $results[1];
837
838 if (preg_match('#< *meta *name="fromname" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->fromname = $results[1];
839 if (preg_match('#< *meta *name="fromemail" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->fromemail = $results[1];
840 if (preg_match('#< *meta *name="replyname" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->replyname = $results[1];
841 if (preg_match('#< *meta *name="replyemail" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->replyemail = $results[1];
842 if (preg_match('#< *meta *name="subject" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) $newTemplate->subject = $results[1];
843 if (preg_match('#< *meta *name="settings" *content="([^"]*)"#Uis', $fileContent, $results) && !empty($results[1])) {
844 $newTemplate->settings = htmlspecialchars_decode($results[1]);
845 }
846
847 $newFolder = preg_replace('#[^a-z0-9]#i', '_', strtolower($newTemplate->name));
848 $newTemplateFolder = $newFolder;
849 $i = 1;
850 while (is_dir(ACYM_TEMPLATE.$newTemplateFolder)) {
851 $newTemplateFolder = $newFolder.'_'.$i;
852 $i++;
853 }
854 $newTemplate->mail_settings = ['media_folder' => $newTemplateFolder];
855
856 $moveResult = acym_copyFolder(dirname($filepath), ACYM_TEMPLATE.$newTemplateFolder);
857 if ($moveResult !== true) {
858 acym_display([acym_translationSprintf('ACYM_ERROR_COPYING_FOLDER_TO', dirname($filepath), ACYM_TEMPLATE.$newTemplateFolder), $moveResult], 'error');
859
860 return false;
861 }
862
863 if (!file_exists(ACYM_TEMPLATE.$newTemplateFolder.DS.'index.html')) {
864 $indexFile = '<html><body bgcolor="#FFFFFF"></body></html>';
865 acym_writeFile(ACYM_TEMPLATE.$newTemplateFolder.DS.'index.html', $indexFile);
866 }
867
868 $fileContent = str_replace(
869 [
870 'src="./',
871 'src="../',
872 'src="images/',
873 'url("images/',
874 'url(&quot;images/',
875 ],
876 [
877 'src="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/',
878 'src="'.ACYM_TEMPLATE_URL,
879 'src="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
880 'url("'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
881 'url(&quot;'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/images/',
882 ],
883 $fileContent
884 );
885
886 $fileContent = preg_replace('#(src|background)[ ]*=[ ]*\"(?!(https?://|/))(?:\.\./|\./)?#', '$1="'.ACYM_TEMPLATE_URL.$newTemplateFolder.'/', $fileContent);
887
888 if (preg_match('#< *body[^>]*>(.*)< */ *body *>#Uis', $fileContent, $results)) {
889 $newTemplate->body = $results[1];
890 } else {
891 $newTemplate->body = $fileContent;
892 }
893
894 $newTemplate->stylesheet = '';
895 if (preg_match_all('#< *style[^>]*>(.*)< */ *style *>#Uis', $fileContent, $results)) {
896 $newTemplate->stylesheet .= preg_replace('#(<!--|-->)#s', '', implode("\n", $results[1]));
897 }
898 $cssFiles = [];
899 $cssFiles[ACYM_TEMPLATE.$newTemplateFolder] = acym_getFiles(ACYM_TEMPLATE.$newTemplateFolder, '\.css$');
900 $subFolders = acym_getFolders(ACYM_TEMPLATE.$newTemplateFolder);
901 foreach ($subFolders as $oneFolder) {
902 $cssFiles[ACYM_TEMPLATE.$newTemplateFolder.DS.$oneFolder] = acym_getFiles(ACYM_TEMPLATE.$newTemplateFolder.DS.$oneFolder, '\.css$');
903 }
904
905 foreach ($cssFiles as $cssFolder => $cssFile) {
906 if (empty($cssFile)) continue;
907 $newTemplate->stylesheet .= "\n".acym_fileGetContent($cssFolder.DS.reset($cssFile));
908 }
909
910 if (!empty($newTemplate->stylesheet)) {
911 if (preg_match('#body *\{[^\}]*background-color:([^;\}]*)[;\}]#Uis', $newTemplate->stylesheet, $backgroundresults)) {
912 $newTemplate->stylesheet = preg_replace('#(body *\{[^\}]*)background-color:[^;\}]*[;\}]#Uis', '$1', $newTemplate->stylesheet);
913 }
914
915 $quickstyle = [
916 'tag_h1' => 'h1',
917 'tag_h2' => 'h2',
918 'tag_h3' => 'h3',
919 'tag_h4' => 'h4',
920 'tag_h5' => 'h5',
921 'tag_h6' => 'h6',
922 'tag_a' => 'a',
923 'tag_ul' => 'ul',
924 'tag_li' => 'li',
925 'acym_unsub' => '\.acym_unsub',
926 'acym_online' => '\.acym_online',
927 'acym_title' => '\.acym_title',
928 'acym_content' => '\.acym_content',
929 'acym_readmore' => '\.acym_readmore',
930 ];
931 foreach ($quickstyle as $styledb => $oneStyle) {
932 if (preg_match('#[^a-z\. ,] *'.$oneStyle.' *{([^}]*)}#Uis', $newTemplate->stylesheet, $quickstyleresults)) {
933 $newTemplate->stylesheet = str_replace($quickstyleresults[0], '', $newTemplate->stylesheet);
934 }
935 }
936 }
937
938 $foldersForPicts = [$newTemplateFolder];
939 $otherFolders = acym_getFolders(ACYM_TEMPLATE.$newTemplateFolder);
940 foreach ($otherFolders as $oneFold) {
941 $foldersForPicts[] = $newTemplateFolder.DS.$oneFold;
942 }
943 $allPictures = [];
944 foreach ($foldersForPicts as $oneFolder) {
945 $allPictures[$oneFolder] = acym_getFiles(ACYM_TEMPLATE.$oneFolder);
946 }
947
948 $uploadsFolder = ACYM_UPLOAD_FOLDER_THUMBNAIL;
949
950 $newConfig = new \stdClass();
951 $thumbNb = intval($this->config->get('numberThumbnail', 2));
952
953 foreach ($allPictures as $folder => $pictfolders) {
954 foreach ($pictfolders as $onePict) {
955 if (!preg_match('#\.(jpg|gif|png|jpeg|ico|bmp)$#i', $onePict)) continue;
956 if (preg_match('#(thumbnail|screenshot|muestra)#i', $onePict)) {
957 $thumbNb++;
958 $newNamePict = 'thumbnail_'.$thumbNb.'.png';
959 copy(ACYM_TEMPLATE.str_replace(DS, '/', $folder).'/'.$onePict, $uploadsFolder.$newNamePict);
960 $newTemplate->thumbnail = $newNamePict;
961 }
962 }
963 }
964
965 $newConfig->numberThumbnail = $thumbNb;
966 $this->config->save($newConfig);
967
968 $newTemplate->drag_editor = strpos($newTemplate->body, 'acym__wysid__template__content') !== false ? 1 : 0;
969 $newTemplate->type = self::TYPE_TEMPLATE;
970 $newTemplate->creation_date = acym_date('now', 'Y-m-d H:i:s', false);
971
972 $tempid = $this->save($newTemplate);
973
974 $this->templateId = $tempid;
975 $this->templateNames[] = $newTemplate->name;
976
977 return true;
978 }
979
980 public function sendAutomation($mailId, $userIds, $sendingDate, $automationAdmin = [])
981 {
982 if (empty($mailId)) return acym_translationSprintf('ACYM_EMAILS_ADDED_QUEUE', 0);
983 if (empty($sendingDate)) return acym_translation('ACYM_WRONG_DATE');
984 if (empty($userIds)) return acym_translation('ACYM_USER_NOT_FOUND');
985 acym_arrayToInteger($userIds);
986
987 if (isset($automationAdmin['automationAdmin']) && $automationAdmin['automationAdmin']) {
988 $userClass = new UserClass();
989 $mail = $this->getOneById($mailId);
990 $user = $userClass->getOneById($automationAdmin['user_id']);
991
992 if (empty($mail) || empty($user)) return false;
993
994 $mailerHelper = new MailerHelper();
995 $pluginHelper = new PluginHelper();
996 $extractedTags = $pluginHelper->extractTags($mail, 'subscriber');
997 if (!empty($extractedTags)) {
998 foreach ($extractedTags as $dtext => $oneTag) {
999 if (empty($oneTag->info) || $oneTag->info != 'current' || empty($user->{$oneTag->id})) continue;
1000
1001 $mailerHelper->addParam(str_replace(['{', '}'], '', $dtext), $user->{$oneTag->id});
1002 }
1003 }
1004
1005 if (!empty($automationAdmin['user_id'])) {
1006 $userClass = new UserClass();
1007 $user = $userClass->getOneById($automationAdmin['user_id']);
1008 if (!empty($user)) {
1009 $userField = $userClass->getAllUserFields($user);
1010 foreach ($userField as $map => $value) {
1011 $mailerHelper->addParam('user:'.$map, $value);
1012 }
1013 }
1014 }
1015
1016 $emailsSent = 0;
1017 foreach ($userIds as $userId) {
1018 if ($mailerHelper->sendOne($mail->id, $userId)) {
1019 $emailsSent++;
1020 }
1021 }
1022
1023 return $emailsSent;
1024 }
1025
1026 $result = acym_query(
1027 'INSERT IGNORE INTO #__acym_queue (`mail_id`, `user_id`, `sending_date`)
1028 SELECT '.intval($mailId).', user.id, '.acym_escapeDB($sendingDate).'
1029 FROM #__acym_user AS user
1030 WHERE user.active = 1 AND user.id IN ('.implode(',', $userIds).')'
1031 );
1032
1033
1034 $mailStatClass = new MailStatClass();
1035 $mailStat = $mailStatClass->getOneRowByMailId($mailId);
1036
1037 $newMailStat = [
1038 'mail_id' => intval($mailId),
1039 'total_subscribers' => intval($result),
1040 ];
1041 if (empty($mailStat)) {
1042 $newMailStat['send_date'] = $sendingDate;
1043 }
1044
1045 $mailStatClass->save($newMailStat);
1046
1047 if ($result === 0) {
1048 return acym_translation('ACYM_CAMPAIGN_ALREADY_QUEUED');
1049 }
1050
1051 return $result;
1052 }
1053
1054 public function encode($mails = [])
1055 {
1056 $isArray = true;
1057 if (!is_array($mails)) {
1058 $mails = [$mails];
1059
1060 $isArray = false;
1061 }
1062
1063 $encodedMails = array_map([$this, 'removePoweredByAcyMailing'], $mails);
1064
1065 $encodedMails = array_map([$this, 'utf8Encode'], $encodedMails);
1066
1067 return $isArray ? $encodedMails : $encodedMails[0];
1068 }
1069
1070 public function decode($mails = [])
1071 {
1072 $isArray = true;
1073 if (!is_array($mails)) {
1074 $mails = [$mails];
1075
1076 $isArray = false;
1077 }
1078
1079 $decodedMails = array_map([$this, 'utf8Decode'], $mails);
1080
1081 $decodedMails = array_map([$this, 'addPoweredByAcyMailing'], $decodedMails);
1082
1083 foreach ($decodedMails as $i => $oneMail) {
1084 if (!isset($oneMail->access) || is_array($oneMail->access)) continue;
1085 $decodedMails[$i]->access = empty($oneMail->access) ? '' : explode(',', $oneMail->access);
1086 }
1087
1088 return $isArray ? $decodedMails : $decodedMails[0];
1089 }
1090
1091 protected function utf8Decode($mail)
1092 {
1093 if (!empty($mail)) {
1094 foreach (self::FIELDS_ENCODING as $oneField) {
1095 if (in_array($oneField, $this->exceptKeysDecode)) {
1096 continue;
1097 }
1098
1099 if (is_array($mail)) {
1100 if (empty($mail[$oneField])) continue;
1101 $value = &$mail[$oneField];
1102 } else {
1103 if (empty($mail->$oneField)) continue;
1104 $value = &$mail->$oneField;
1105 }
1106
1107 $value = acym_utf8Decode($value);
1108 }
1109 }
1110
1111 return $mail;
1112 }
1113
1114 protected function addPoweredByAcyMailing($mail)
1115 {
1116 if (empty($mail->body)) {
1117 return $mail;
1118 }
1119
1120 if ($this->config->get('display_built_by', 0) != 1) {
1121 if (strpos($mail->body, 'acym__powered_by_acymailing') !== false) {
1122 $mailBodyDom = new \DOMDocument();
1123 @$mailBodyDom->loadHTML('<?xml encoding="utf-8" ?>'.$mail->body);
1124 $tables = $mailBodyDom->getElementsByTagName('table');
1125 foreach ($tables as $table) {
1126 if ($table->getAttribute('id') != 'acym__powered_by_acymailing') continue;
1127 $table->parentNode->removeChild($table);
1128 break;
1129 }
1130 $mail->body = $mailBodyDom->saveHTML();
1131 }
1132
1133 return $mail;
1134 }
1135
1136 if (strpos($mail->body, 'acym__powered_by_acymailing') !== false) {
1137 return $mail;
1138 }
1139
1140 $isWysidEditor = strpos($mail->body, 'acym__wysid__template') !== false;
1141 $urlPoweredByImage = ACYM_IMAGES.'editor/poweredby_black.png';
1142
1143 if (!$isWysidEditor) {
1144 $poweredByHTML = '<p id="acym__powered_by_acymailing">';
1145 $poweredByHTML .= '<a href="'.ACYM_ACYMAILING_WEBSITE.'?utm_campaign=powered_by_v7&utm_source=acymailing_plugin&utm_medium=built_with_footer" target="blank">';
1146 $poweredByHTML .= '<img alt="Email built with AcyMailing" height="40" width="199" style="height: 40px; width:199px; max-width: 100%; height: auto; box-sizing: border-box; padding: 0 5px; display: block; margin-left: auto; margin-right: auto;" src="'.$urlPoweredByImage.'"/>';
1147 $poweredByHTML .= '</a></p>';
1148
1149 $mail->body = $mail->body.$poweredByHTML;
1150 } else {
1151 $poweredByWYSID = '<table id="acym__powered_by_acymailing" class="row" bgcolor="#ffffff" style="background-color: transparent" cellpadding="0" cellspacing="0" border="0">
1152 <tbody bgcolor style="background-color: inherit;">
1153 <tr>
1154 <th class="small-12 medium-12 large-12 columns" valign="top" style="height: auto;">
1155 <table border="0" cellpadding="0" cellspacing="0"
1156 style="min-height: 0px; display: table; height: auto;">
1157 <tbody style="min-height: 0px; display: table-row-group;">
1158 <tr
1159 style="position: relative; top: inherit; left: inherit; right: inherit; bottom: inherit; height: auto;">
1160 <td class="large-12">
1161 <div style="position: relative;">
1162 <p style="word-break: break-word; text-align: center;">
1163 <a href="'.ACYM_ACYMAILING_WEBSITE.'?utm_campaign=powered_by_v7&utm_source=acymailing_plugin&utm_medium=built_with_footer" target="_blank">
1164 <img src="'.$urlPoweredByImage.'"
1165 title="poweredby" alt="Email built with AcyMailing"
1166 style="height: 40px; width:199px; max-width: 100%; height: auto; box-sizing: border-box; padding: 0px 5px; display: inline-block; margin-left: auto; margin-right: auto;"
1167 height="40" width="199">
1168 </a>
1169 </p>
1170 </div>
1171 </td>
1172 </tr>
1173 </tbody>
1174 </table>
1175 </th>
1176 </tr>
1177 </tbody>
1178 </table>';
1179
1180 $mailBodyDom = new \DOMDocument();
1181 @$mailBodyDom->loadHTML('<?xml encoding="utf-8" ?>'.$mail->body);
1182
1183 $htmlToAddDom = new \DOMDocument();
1184 @$htmlToAddDom->loadHTML('<?xml encoding="utf-8" ?>'.$poweredByWYSID);
1185 $tableToAdd = $htmlToAddDom->getElementById('acym__powered_by_acymailing');
1186
1187 $tds = $mailBodyDom->getElementsByTagName('td');
1188 foreach ($tds as $td) {
1189 $classes = explode(' ', $td->getAttribute('class'));
1190 if (!in_array('acym__wysid__row', $classes)) continue;
1191 if (!empty($tableToAdd)) $td->appendChild($mailBodyDom->importNode($tableToAdd, true));
1192 break;
1193 }
1194 $mail->body = $mailBodyDom->saveHTML();
1195 }
1196
1197 return $mail;
1198 }
1199
1200 protected function removePoweredByAcyMailing($mail)
1201 {
1202 if (empty($mail->body)) return $mail;
1203
1204 if (strpos($mail->body, 'acym__wysid__template') !== false) return $mail;
1205
1206 $regexPoweredByAcyMailing = '#<p id="acym__powered_by_acymailing.*<\/p>#U';
1207
1208 $mail->body = preg_replace($regexPoweredByAcyMailing, '', $mail->body);
1209
1210 return $mail;
1211 }
1212
1213 protected function utf8Encode($mail)
1214 {
1215 if (!empty($mail)) {
1216 foreach (self::FIELDS_ENCODING as $oneField) {
1217 if (is_array($mail)) {
1218 if (empty($mail[$oneField])) continue;
1219 $value = &$mail[$oneField];
1220 } else {
1221 if (empty($mail->$oneField)) continue;
1222 $value = &$mail->$oneField;
1223 }
1224
1225 $value = acym_utf8Encode($value);
1226 }
1227 }
1228
1229 return $mail;
1230 }
1231
1232 public function getTranslationId($parentId, $langCode)
1233 {
1234 return acym_loadResult(
1235 'SELECT `id`
1236 FROM #__acym_mail
1237 WHERE `parent_id` = '.intval($parentId).'
1238 AND `language` = '.acym_escapeDB($langCode)
1239 );
1240 }
1241
1242 public function getTranslationsById($mailId, $full = false, $includeParent = false)
1243 {
1244 $data = $full ? '*' : '`language`, `subject`, `preheader`, `body`, `autosave`';
1245 $where = $includeParent ? ' OR `id` = '.intval($mailId) : '';
1246
1247 return $this->decode(
1248 acym_loadObjectList(
1249 'SELECT '.$data.'
1250 FROM #__acym_mail
1251 WHERE `parent_id` = '.intval($mailId).$where,
1252 'language'
1253 )
1254 );
1255 }
1256
1257 public function deleteByTranslationLang($languageCodes)
1258 {
1259 if (!is_array($languageCodes)) $languageCodes = [$languageCodes];
1260 if (empty($languageCodes)) return;
1261
1262 foreach ($languageCodes as $key => $oneLangCode) {
1263 $languageCodes[$key] = acym_escapeDB($oneLangCode);
1264 }
1265
1266 $this->delete(
1267 acym_loadResultArray(
1268 'SELECT `id`
1269 FROM #__acym_mail
1270 WHERE `parent_id` IS NOT NULL
1271 AND `language` IN ('.implode(', ', $languageCodes).')'
1272 )
1273 );
1274 }
1275
1276 public function getMultilingualMails(int $parentId)
1277 {
1278 $mails = $this->decode(
1279 acym_loadObjectList(
1280 'SELECT * FROM #__acym_mail WHERE parent_id = '.intval($parentId).' OR id = '.intval($parentId),
1281 'language'
1282 )
1283 );
1284
1285 return $this->translateMailSettings($mails);
1286 }
1287
1288 private function translateMailSettings($mails)
1289 {
1290 if (empty($mails)) return $mails;
1291
1292 $defaultLanguage = $this->config->get('multilingual_default');
1293
1294 if (empty($mails[$defaultLanguage])) {
1295 $firstMail = reset($mails);
1296 if (empty($firstMail) || empty($firstMail->parent_id)) return $mails;
1297 $mainMail = $this->getOneById($firstMail->parent_id);
1298 } else {
1299 $mainMail = $mails[$defaultLanguage];
1300 }
1301
1302 if (!empty($mainMail->translation)) {
1303 $translation = json_decode($mainMail->translation, true);
1304
1305 foreach ($mails as $lang => $mail) {
1306 if (empty($mail->parent_id) || empty($translation[$lang])) continue;
1307
1308 if (!empty($translation[$lang]['from_name'])) $mails[$lang]->from_name = $translation[$lang]['from_name'];
1309 if (!empty($translation[$lang]['from_email'])) $mails[$lang]->from_email = $translation[$lang]['from_email'];
1310 if (!empty($translation[$lang]['reply_to_name'])) $mails[$lang]->reply_to_name = $translation[$lang]['reply_to_name'];
1311 if (!empty($translation[$lang]['reply_to_email'])) $mails[$lang]->reply_to_email = $translation[$lang]['reply_to_email'];
1312 }
1313 }
1314
1315 return $mails;
1316 }
1317
1318 public function getMailAttachments($mailId)
1319 {
1320 return acym_loadResult('SELECT attachments FROM #__acym_mail WHERE id = '.intval($mailId));
1321 }
1322
1323 public function isTransactionalMail($mail): bool
1324 {
1325 return $mail->type !== self::TYPE_STANDARD;
1326 }
1327
1328 public function isOneTimeMail($mail): bool
1329 {
1330 return in_array(
1331 $mail->type,
1332 [
1333 self::TYPE_NOTIFICATION,
1334 self::TYPE_OVERRIDE,
1335 self::TYPE_WELCOME,
1336 self::TYPE_UNSUBSCRIBE,
1337 self::TYPE_TEMPLATE,
1338 ]
1339 );
1340 }
1341
1342 public function getAutomaticMailIds($mailIds)
1343 {
1344 acym_arrayToInteger($mailIds);
1345
1346 $query = 'SELECT DISTINCT campaign2.mail_id
1347 FROM #__acym_campaign AS campaign1
1348 JOIN #__acym_campaign AS campaign2 ON campaign1.id = campaign2.parent_id
1349 WHERE campaign1.mail_id IN ('.implode(',', $mailIds).')';
1350 $generatedMailIds = acym_loadResultArray($query);
1351
1352 if (empty($generatedMailIds)) return [];
1353
1354 acym_arrayToInteger($generatedMailIds);
1355
1356 return $generatedMailIds;
1357 }
1358
1359 public function getMultilingualMailIds($mailIds)
1360 {
1361 acym_arrayToInteger($mailIds);
1362
1363 $query = 'SELECT DISTINCT mail2.id
1364 FROM #__acym_mail AS mail1
1365 JOIN #__acym_mail AS mail2 ON mail1.id = mail2.parent_id
1366 WHERE mail1.id IN ('.implode(',', $mailIds).')';
1367
1368 $multipleMailIds = acym_loadResultArray($query);
1369
1370 if (empty($multipleMailIds)) return [];
1371
1372 acym_arrayToInteger($multipleMailIds);
1373
1374 return $multipleMailIds;
1375 }
1376
1377 public function duplicateMail($mailId, $type = null)
1378 {
1379 $mail = $this->getOneById($mailId);
1380
1381 if (empty($mail)) {
1382 return false;
1383 }
1384
1385 $newMail = new \stdClass();
1386 $newMail->name = $mail->name.'_copy';
1387 $newMail->thumbnail = '';
1388 $newMail->type = empty($type) ? $mail->type : $type;
1389 $newMail->drag_editor = $mail->drag_editor;
1390 $newMail->body = $mail->body;
1391 $newMail->subject = $mail->subject;
1392 $newMail->from_name = $mail->from_name;
1393 $newMail->from_email = $mail->from_email;
1394 $newMail->reply_to_name = $mail->reply_to_name;
1395 $newMail->reply_to_email = $mail->reply_to_email;
1396 $newMail->bcc = $mail->bcc;
1397 $newMail->settings = $mail->settings;
1398 $newMail->stylesheet = $mail->stylesheet;
1399 $newMail->attachments = $mail->attachments;
1400 $newMail->headers = $mail->headers;
1401 $newMail->preheader = $mail->preheader;
1402
1403 $newMail->id = $this->save($newMail);
1404
1405 return $newMail;
1406 }
1407
1408 public function getTemplatesForMailboxAction()
1409 {
1410 return $this->decode(
1411 acym_loadObjectList(
1412 'SELECT `id`, `name`
1413 FROM #__acym_mail
1414 WHERE `type` = '.acym_escapeDB(self::TYPE_TEMPLATE).'
1415 AND `body` LIKE '.acym_escapeDB('%'.acym_utf8Encode('{emailcontent}').'%')
1416 )
1417 );
1418 }
1419
1420 public function hasUserAccess(int $mailId): bool
1421 {
1422 $userId = acym_currentUserId();
1423 if (empty($userId)) {
1424 return false;
1425 }
1426
1427 if (acym_isAdmin()) {
1428 return true;
1429 }
1430
1431 return acym_loadResult(
1432 'SELECT COUNT(*)
1433 FROM #__acym_mail
1434 WHERE id = '.intval($mailId).'
1435 AND (creator_id = '.intval($userId).'
1436 OR type = '.acym_escapeDB(self::TYPE_TEMPLATE).')'
1437 ) > 0;
1438 }
1439
1440
1441 public function getVersionsById($mailId, $includeParent = false)
1442 {
1443 $where = $includeParent ? ' OR `id` = '.intval($mailId) : '';
1444
1445 return $this->decode(
1446 acym_loadObjectList(
1447 'SELECT *
1448 FROM #__acym_mail
1449 WHERE `parent_id` = '.intval($mailId).$where.' ORDER BY id ASC',
1450 'id'
1451 )
1452 );
1453 }
1454
1455 public function getParentAndChildMails($parentId)
1456 {
1457 $mails = $this->decode(
1458 acym_loadObjectList(
1459 'SELECT * FROM #__acym_mail WHERE parent_id = '.intval($parentId).' OR id = '.intval($parentId),
1460 'id'
1461 )
1462 );
1463
1464 return $mails;
1465 }
1466
1467 public function getAllTemplatesByType($options)
1468 {
1469 $limit = $options['limit'] ?? 10;
1470 $offset = $options['offset'] ?? 0;
1471 $filters = $options['filters'] ?? [];
1472 $search = $filters['search'] ?? '';
1473 $templateType = $filters['templateType'] ?? '';
1474
1475 $query = 'SELECT * FROM #__acym_mail';
1476 $conditions = ['`type` = '.acym_escapeDB(self::TYPE_TEMPLATE)];
1477
1478 if (!empty($search)) {
1479 $conditions[] = '(name LIKE '.acym_escapeDB('%'.$search.'%').' OR subject LIKE '.acym_escapeDB('%'.$search.'%').')';
1480 }
1481
1482 if (!empty($templateType)) {
1483 if ($templateType === 'drag') {
1484 $conditions[] = 'drag_editor = 1';
1485 } else {
1486 $conditions[] = 'drag_editor = 0';
1487 }
1488 }
1489
1490 $query .= ' WHERE '.implode(' AND ', $conditions);
1491
1492 return $this->decode(acym_loadObjectList($query, '', $offset, $limit));
1493 }
1494
1495 public function updateFollowupPriority($oldPriority, $newPriority)
1496 {
1497 if ($oldPriority == 0 && $newPriority == 1) {
1498 $updatePriorityQuery = 'UPDATE `#__acym_queue` AS `queue`
1499 INNER JOIN `#__acym_mail` AS `mail` ON `queue`.`mail_id` = `mail`.`id`
1500 SET `queue`.`priority` = 1
1501 WHERE `mail`.`type` = "'.self::TYPE_FOLLOWUP.'"';
1502
1503 return acym_query($updatePriorityQuery);
1504 }
1505 }
1506
1507 public function getCampaignIdByMailId(int $mailId): int
1508 {
1509 $mainMailId = $this->getMainMailId($mailId);
1510
1511 return intval(acym_loadResult('SELECT id FROM #__acym_campaign WHERE mail_id = '.intval($mainMailId)));
1512 }
1513
1514 public function getMainMailId(int $mailId): int
1515 {
1516 $parentId = acym_loadResult('SELECT parent_id FROM #__acym_mail WHERE id = '.intval($mailId));
1517
1518 return empty($parentId) ? $mailId : intval($parentId);
1519 }
1520 }
1521