ILIAS  trunk Revision v12.0_alpha-1227-g7ff6d300864
class.ilMimeMail.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
22use ILIAS\Refinery\Factory as Refinery;
23
25{
26 final public const string MAIL_SUBJECT_PREFIX = '[ILIAS]';
27 private const string SKIN_LOGO_PATH = '/public/Customizing/skin/%s/images/logo';
28 private const string SKIN_CSS_PATH = '/public/Customizing/skin/%s/mail.css';
29 private const string MAIL_CSS_PATH = 'assets/css/mail.css';
30 private const string MAIL_LOGO_PATH = '/public/assets/images/logo/HeaderIcon.svg';
31 private const string ROOT_DIR_IDENTIFICATION_FILE = '/ilias_version.php';
32
33 protected static ?ilMailMimeTransport $default_transport = null;
34
38 protected string $subject = '';
39 protected string $body = '';
40 protected string $final_body = '';
41 protected string $final_body_alt = '';
43 protected array $sendto = [];
45 protected array $acc = [];
47 protected array $abcc = [];
49 protected array $images = [];
51 protected array $aattach = [];
53 protected array $actype = [];
55 protected array $adispo = [];
57 protected array $adisplay = [];
58 private readonly Refinery $refinery;
60 private ?Closure $to_html_transformation = null;
61
62 public function __construct()
63 {
64 global $DIC;
65 $this->settings = $DIC->settings();
66
67 if (!(self::getDefaultTransport() instanceof ilMailMimeTransport)) {
68 $factory = $DIC->mail()->mime()->transportFactory();
69 self::setDefaultTransport($factory->getTransport());
70 }
71
72 $this->subject_builder = new ilMailMimeSubjectBuilder($this->settings, self::MAIL_SUBJECT_PREFIX);
73 $this->refinery = $DIC->refinery();
74 }
75
76 public static function setDefaultTransport(?ilMailMimeTransport $transport): void
77 {
78 self::$default_transport = $transport;
79 }
80
81 public static function getDefaultTransport(): ?ilMailMimeTransport
82 {
84 }
85
86 public function Subject(string $subject, bool $add_prefix = false, string $context_prefix = ''): void
87 {
88 $this->subject = $this->subject_builder->subject($subject, $add_prefix, $context_prefix);
89 }
90
91 public function getSubject(): string
92 {
93 return $this->subject;
94 }
95
96 public function From(ilMailMimeSender $sender): void
97 {
98 $this->sender = $sender;
99 }
100
104 public function To($to): void
105 {
106 if (is_array($to)) {
107 $this->sendto = $to;
108 } else {
109 $this->sendto[] = $to;
110 }
111 }
112
116 public function Cc($cc): void
117 {
118 if (is_array($cc)) {
119 $this->acc = $cc;
120 } else {
121 $this->acc[] = $cc;
122 }
123 }
124
128 public function Bcc($bcc): void
129 {
130 if (is_array($bcc)) {
131 $this->abcc = $bcc;
132 } else {
133 $this->abcc[] = $bcc;
134 }
135 }
136
140 public function getTo(): array
141 {
142 return $this->sendto;
143 }
144
148 public function getCc(): array
149 {
150 return $this->acc;
151 }
152
156 public function getBcc(): array
157 {
158 return $this->abcc;
159 }
160
164 public function Body(string $body, ?Closure $to_html_transformation = null): void
165 {
166 $this->body = $body;
167 $this->to_html_transformation = $to_html_transformation;
168 }
169
170 public function getFinalBody(): string
171 {
172 return $this->final_body;
173 }
174
175 public function getFinalBodyalt(): string
176 {
178 }
179
180 public function getFrom(): ilMailMimeSender
181 {
182 return $this->sender;
183 }
184
192 public function Attach(
193 string $filename,
194 string $file_type = '',
195 string $disposition = 'inline',
196 ?string $display_name = null
197 ): void {
198 if ($file_type === '') {
199 $file_type = 'application/octet-stream';
200 }
201
202 $this->aattach[] = $filename;
203 $this->actype[] = $file_type;
204 $this->adispo[] = $disposition;
205 $this->adisplay[] = $display_name;
206 }
207
211 public function getAttachments(): array
212 {
213 $attachments = [];
214
215 $i = 0;
216 foreach ($this->aattach as $attachment) {
217 $name = '';
218 if (isset($this->adisplay[$i]) && is_string($this->adisplay[$i]) && $this->adisplay[$i] !== '') {
219 $name = $this->adisplay[$i];
220 }
221
222 $attachments[] = [
223 'path' => $attachment,
224 'name' => $name
225 ];
226 ++$i;
227 }
228
229 return $attachments;
230 }
231
236 public function getImages(): array
237 {
238 return array_values($this->images);
239 }
240
241 protected function build(): void
242 {
243 global $DIC;
244
245 $this->final_body_alt = '';
246 $this->final_body = '';
247 $this->images = [];
248
249 if ($DIC->settings()->get('mail_send_html', '0')) {
250 $skin = $DIC['ilClientIniFile']->readVariable('layout', 'skin');
251 $style = $DIC['ilClientIniFile']->readVariable('layout', 'style');
252
253 $data_factory = new Factory();
254 $factory = $DIC->ui()->factory();
255 $renderer = $DIC->ui()->renderer();
256
257 $this->prepareHTMLBody();
258
259 $page = $factory->layout()->page()->mail(
260 $this->getStyleSheetPath($skin, $style),
261 "cid:{$this->getLogoCid($skin, $style)}",
263 $factory->legacy()->content($this->body),
264 $data_factory->link(ilUtil::_getHttpPath(), $data_factory->uri(ilUtil::_getHttpPath())),
265 );
266
267 $this->final_body = $renderer->render($page);
268 $this->final_body_alt = $this->removeHtmlTags($this->body);
269 } else {
270 $this->final_body = $this->removeHtmlTags($this->body);
271 }
272 }
273
274 private function removeHtmlTags(string $maybe_html): string
275 {
276 $maybe_html = str_ireplace(['<br />', '<br>', '<br/>'], "\n", $maybe_html);
277
278 return html_entity_decode(strip_tags($maybe_html), ENT_QUOTES);
279 }
280
281 private function getPathToRootDirectory(): string
282 {
283 $current_dir = realpath(__DIR__);
284
285 while ($current_dir !== '.') {
286 if (file_exists($current_dir . self::ROOT_DIR_IDENTIFICATION_FILE)) {
287 break;
288 }
289
290 $current_dir = dirname($current_dir);
291 }
292
293 return $current_dir;
294 }
295
296 private function prepareHTMLBody(): void
297 {
298 if ($this->body === '') {
299 $this->body = ' ';
300 }
301
302 $transformed_body = $this->to_html_transformation ? ($this->to_html_transformation)($this->body) : $this->body;
303
304 $contains_html = $this->containsHtmlBlockElementsOrLineBreaks($transformed_body);
305 if ($contains_html) {
306 $this->final_body_alt = strip_tags(str_ireplace(['<br />', '<br>', '<br/>'], "\n", $this->body));
307 $this->body = $transformed_body;
308 } else {
309 $this->final_body_alt = strip_tags($this->body);
310 $this->body = nl2br($transformed_body);
311 }
312
313 $this->body = $this->refinery->string()->makeClickable()->transform($this->body);
314 }
315
316 private function containsHtmlBlockElementsOrLineBreaks(string $email_body): bool
317 {
318 if (str_contains($email_body, '<') === false || str_contains($email_body, '>') === false) {
319 return false;
320 }
321
322 // Detect common HTML tags produced by Markdown rendering.
323 $pattern = '~</?(p|br|div|ul|ol|li|code|pre|h[1-6])\b~i';
324 if (preg_match($pattern, $email_body) === 1) {
325 return true;
326 }
327
328 return strip_tags($email_body, '<b><u><i><a>') !== $email_body;
329 }
330
331 private function getStyleSheetPath(string $skin, string $style): string
332 {
333 if ($skin !== 'default') {
334 $locations = [
335 $skin,
336 "$skin/$style"
337 ];
338
339 foreach ($locations as $location) {
340 $custom_path = $this->getPathToRootDirectory() . sprintf(self::SKIN_CSS_PATH, $location);
341 if (is_file($custom_path)) {
342 return $custom_path;
343 }
344 }
345 }
346
347 return self::MAIL_CSS_PATH;
348 }
349
350 private function getLogoCid(string $skin, string $style): string
351 {
352 if ($skin !== 'default') {
353 $locations = [
354 $skin,
355 "$skin/$style"
356 ];
357
358 foreach ($locations as $location) {
359 $custom_directory = $this->getPathToRootDirectory() . sprintf(self::SKIN_LOGO_PATH, $location);
360 if (is_dir($custom_directory) && is_readable($custom_directory)) {
361 $this->gatherImagesFromDirectory($custom_directory);
362 }
363 }
364 } else {
365 $path = $this->getPathToRootDirectory() . self::MAIL_LOGO_PATH;
366 if (is_file($path) && is_readable($path)) {
367 return $this->addImage(new SplFileInfo($path), true);
368 }
369 }
370
371 foreach ($this->images as $image) {
372 if ($image['as_logo']) {
373 return $image['cid'];
374 }
375 }
376
377 $logo_cid = count($this->images) > 1 ? current($this->images)['cid'] : null;
378
379 foreach ($this->images as $cid => $image) {
380 $file_name = basename($image['path'], '.' . pathinfo($image['path'], PATHINFO_EXTENSION));
381 if (in_array(strtolower($file_name), ['logo', 'headericon'], true)) {
382 $logo_cid = $cid;
383 break;
384 }
385 }
386
387 if (is_string($logo_cid)) {
388 $this->images[$logo_cid]['as_logo'] = true;
389 return $logo_cid;
390 }
391
392 $path = $this->getPathToRootDirectory() . self::MAIL_LOGO_PATH;
393 if (is_file($path) && is_readable($path)) {
394 return $this->addImage(new SplFileInfo($path), true);
395 }
396
397 return '';
398 }
399
400 protected function gatherImagesFromDirectory(string $directory, bool $clear_previous = false): void
401 {
402 if ($clear_previous) {
403 $this->images = [];
404 }
405
406 foreach (new RegexIterator(
407 new DirectoryIterator($directory),
408 '/\.(jpg|jpeg|gif|svg|png)$/i'
409 ) as $file) {
410 $this->addImage($file);
411 }
412 }
413
414 private function addImage(SplFileInfo $file, bool $as_logo = false): string
415 {
416 $cid = 'img/' . $file->getFilename();
417
418 $this->images[$cid] = [
419 'path' => $file->getPathname(),
420 'cid' => $cid,
421 'name' => $file->getFilename(),
422 'as_logo' => $as_logo
423 ];
424
425 return $cid;
426 }
427
428 public function Send(?ilMailMimeTransport $transport = null): bool
429 {
430 if (!($transport instanceof ilMailMimeTransport)) {
431 $transport = self::getDefaultTransport();
432 }
433
434 $this->build();
435
436 return $transport->send($this);
437 }
438}
$filename
Definition: buildRTE.php:78
$location
Definition: buildRTE.php:22
$renderer
Builds data types.
Definition: Factory.php:36
containsHtmlBlockElementsOrLineBreaks(string $email_body)
Body(string $body, ?Closure $to_html_transformation=null)
Attach(string $filename, string $file_type='', string $disposition='inline', ?string $display_name=null)
getLogoCid(string $skin, string $style)
final const string MAIL_SUBJECT_PREFIX
ilMailMimeSender $sender
removeHtmlTags(string $maybe_html)
const string ROOT_DIR_IDENTIFICATION_FILE
string $final_body_alt
Send(?ilMailMimeTransport $transport=null)
addImage(SplFileInfo $file, bool $as_logo=false)
Closure $to_html_transformation
const string SKIN_CSS_PATH
static ilMailMimeTransport $default_transport
gatherImagesFromDirectory(string $directory, bool $clear_previous=false)
const string SKIN_LOGO_PATH
static getDefaultTransport()
static setDefaultTransport(?ilMailMimeTransport $transport)
getStyleSheetPath(string $skin, string $style)
const string MAIL_LOGO_PATH
Subject(string $subject, bool $add_prefix=false, string $context_prefix='')
ilMailMimeSubjectBuilder $subject_builder
string $final_body
readonly Refinery $refinery
const string MAIL_CSS_PATH
From(ilMailMimeSender $sender)
ilSetting $settings
ILIAS Setting Class.
static _getHttpPath()
$path
Definition: ltiservices.php:30
if(!file_exists('../ilias.ini.php'))
global $DIC
Definition: shib_login.php:26