| @@ -613,8 +613,11 @@ | ||
| 613 | 613 | |
| 614 | 614 | |
| 615 | 615 | $this->mailId = $mailId; |
| 616 | 616 | $this->id = $this->mailId; |
| 617 | + if (empty($this->defaultMail[$mailId]->language)) { | |
| 618 | + $this->defaultMail[$mailId]->language = acym_getDefaultNewsletterLanguage(); | |
| 619 | + } | |
| 617 | 620 | $this->mail = clone $this->defaultMail[$mailId]; |
| 618 | 621 | acym_trigger('replaceContent', [&$this->defaultMail[$mailId], true]); |
| 619 | 622 | |
| 620 | 623 | $this->prepareEmailContent($mailId); |
| @@ -1003,22 +1006,24 @@ | ||
| 1003 | 1006 | // We convert the url into local directory |
| 1004 | 1007 | $path = acym_internalUrlToPath($url); |
| 1005 | 1008 | $path = $this->removeAdditionalParams($path); |
| 1006 | 1009 | |
| 1010 | + // The file has to be an image located in the website's folder | |
| 1011 | + $path = $this->getEmbeddableImagePath($path); | |
| 1012 | + if (empty($path)) { | |
| 1013 | + continue; | |
| 1014 | + } | |
| 1015 | + | |
| 1016 | + $ext = strtolower(pathinfo($path, PATHINFO_EXTENSION)); | |
| 1017 | + if (!isset($mimetypes[$ext])) { | |
| 1018 | + continue; | |
| 1019 | + } | |
| 1020 | + | |
| 1007 | 1021 | $filename = str_replace(['%', ' '], '_', basename($url)); |
| 1008 | 1022 | $filename = $this->removeAdditionalParams($filename); |
| 1009 | 1023 | |
| 1010 | 1024 | $md5 = md5($filename); |
| 1011 | 1025 | $cid = 'cid:'.$md5; |
| 1012 | - $fileParts = explode(".", $filename); | |
| 1013 | - if (empty($fileParts[1])) { | |
| 1014 | - continue; | |
| 1015 | - } | |
| 1016 | - $ext = strtolower($fileParts[1]); | |
| 1017 | - // We only embed image files | |
| 1018 | - if (!isset($mimetypes[$ext])) { | |
| 1019 | - continue; | |
| 1020 | - } | |
| 1021 | 1026 | |
| 1022 | 1027 | // We only change the url if we were able to embed the image. |
| 1023 | 1028 | if ($this->addEmbeddedImage($path, $md5, $filename, 'base64', $mimetypes[$ext])) { |
| 1024 | 1029 | $this->Body = preg_replace('/'.preg_quote($images[0][$i], '/').'/Ui', $images[1][$i].'="'.$cid.'"', $this->Body); |
| @@ -1029,8 +1034,34 @@ | ||
| 1029 | 1034 | |
| 1030 | 1035 | return $embedSuccess; |
| 1031 | 1036 | } |
| 1032 | 1037 | |
| 1038 | + private function getEmbeddableImagePath(string $path): string | |
| 1039 | + { | |
| 1040 | + // No url and no stream wrapper, we only read local files | |
| 1041 | + if (empty($path) || preg_match('#^[a-z][a-z\d+.-]*://#i', $path) === 1) { | |
| 1042 | + return ''; | |
| 1043 | + } | |
| 1044 | + | |
| 1045 | + // The file must be inside the website's folder | |
| 1046 | + $root = rtrim(ACYM_ROOT, DS).DS; | |
| 1047 | + if (strpos($path, $root) !== 0 || preg_match('#(^|[/\\\\])\.\.([/\\\\]|$)#', substr($path, strlen($root))) === 1) { | |
| 1048 | + return ''; | |
| 1049 | + } | |
| 1050 | + | |
| 1051 | + if (!is_file($path) || !is_readable($path)) { | |
| 1052 | + return ''; | |
| 1053 | + } | |
| 1054 | + | |
| 1055 | + // An image extension doesn't tell what the file actually contains, so we check the content itself | |
| 1056 | + $imageInfo = @getimagesize($path); | |
| 1057 | + if (empty($imageInfo['mime']) || strpos($imageInfo['mime'], 'image/') !== 0) { | |
| 1058 | + return ''; | |
| 1059 | + } | |
| 1060 | + | |
| 1061 | + return $path; | |
| 1062 | + } | |
| 1063 | + | |
| 1033 | 1064 | public function cleanText(?string $text): string |
| 1034 | 1065 | { |
| 1035 | 1066 | return trim(preg_replace('/(%0A|%0D|\n+|\r+)/i', '', (string)$text)); |
| 1036 | 1067 | } |
| @@ -1211,9 +1242,9 @@ | ||
| 1211 | 1242 | if (empty($receiver)) { |
| 1212 | 1243 | throw new Exception(esc_attr(acym_translation('ACYM_USER_NOT_FOUND'))); |
| 1213 | 1244 | } |
| 1214 | 1245 | |
| 1215 | - $this->userLanguage = empty($receiver->language) ? acym_getLanguageTag() : $receiver->language; | |
| 1246 | + $this->userLanguage = empty($receiver->language) ? acym_getDefaultNewsletterLanguage() : $receiver->language; | |
| 1216 | 1247 | $this->receiverEmail = (string)($receiver->email ?? ''); |
| 1217 | 1248 | |
| 1218 | 1249 | return $receiver; |
| 1219 | 1250 | } |
| @@ -1238,9 +1269,9 @@ | ||
| 1238 | 1269 | $this->Body = $this->introtext.$this->Body; |
| 1239 | 1270 | } |
| 1240 | 1271 | |
| 1241 | 1272 | if (!empty($this->defaultMail[$mailId]->preheader)) { |
| 1242 | - $preHeader = '<!--[if !mso 9]><!--><div style="visibility:hidden;mso-hide:all;font-size:0;color:transparent;height:0;line-height:0;max-height:0;max-width:0;opacity:0;overflow:hidden;">'; | |
| 1273 | + $preHeader = '<!--[if !mso 9]><!--><div style="visibility:hidden;mso-hide:all;font-size:0;height:0;line-height:0;max-height:0;max-width:0;opacity:0;overflow:hidden;">'; | |
| 1243 | 1274 | $preHeader .= $this->defaultMail[$mailId]->preheader; |
| 1244 | 1275 | $preHeader .= '</div><!--<![endif]-->'; |
| 1245 | 1276 | |
| 1246 | 1277 | //We want to insert the preview at the start of the body so we match the start of the mail |
| @@ -1614,9 +1645,9 @@ | ||
| 1614 | 1645 | if (!empty($mailId) && !empty($this->defaultMail[$mailId]->$mailType)) { |
| 1615 | 1646 | return $this->defaultMail[$mailId]->$mailType; |
| 1616 | 1647 | } |
| 1617 | 1648 | |
| 1618 | - $lang = empty($this->userLanguage) ? acym_getLanguageTag() : $this->userLanguage; | |
| 1649 | + $lang = empty($this->userLanguage) ? acym_getDefaultNewsletterLanguage() : $this->userLanguage; | |
| 1619 | 1650 | $setting = $this->config->get($type); |
| 1620 | 1651 | $translation = $this->config->get('sender_info_translation'); |
| 1621 | 1652 | |
| 1622 | 1653 | if (!empty($translation)) { |