/var/www/vhosts/ihelp.ro/_OLD/vendor/cakephp/cakephp/src/Mailer
NameSizeModeActions
Exception/-0755rm
Transport/-0755rm
AbstractTransport.php20550644editdlrm
Email.php170510644editdlrm
Mailer.php187220644editdlrm
MailerAwareTrait.php15330644editdlrm
Message.php518440644editdlrm
Renderer.php32930644editdlrm
TransportFactory.php35000644editdlrm
TransportRegistry.php32060644editdlrm
Edit: /var/www/vhosts/ihelp.ro/_OLD/vendor/cakephp/cakephp/src/Mailer/Message.php (51844B)
'ISO-2022-JP', ]; /** * Regex for email validation * * If null, filter_var() will be used. Use the emailPattern() method * to set a custom pattern.' * * @var string|null */ protected $emailPattern = self::EMAIL_PATTERN; /** * Constructor * * @param array|null $config Array of configs, or string to load configs from app.php */ public function __construct(?array $config = null) { $this->appCharset = Configure::read('App.encoding'); if ($this->appCharset !== null) { $this->charset = $this->appCharset; } $this->domain = preg_replace('/\:\d+$/', '', (string)env('HTTP_HOST')); if (empty($this->domain)) { $this->domain = php_uname('n'); } if ($config) { $this->setConfig($config); } } /** * Sets "from" address. * * @param string|array $email Null to get, String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ public function setFrom($email, ?string $name = null) { return $this->setEmailSingle('from', $email, $name, 'From requires only 1 email address.'); } /** * Gets "from" address. * * @return array */ public function getFrom(): array { return $this->from; } /** * Sets "sender" address. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ public function setSender($email, ?string $name = null) { return $this->setEmailSingle('sender', $email, $name, 'Sender requires only 1 email address.'); } /** * Gets "sender" address. * * @return array */ public function getSender(): array { return $this->sender; } /** * Sets "Reply-To" address. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ public function setReplyTo($email, ?string $name = null) { return $this->setEmailSingle('replyTo', $email, $name, 'Reply-To requires only 1 email address.'); } /** * Gets "Reply-To" address. * * @return array */ public function getReplyTo(): array { return $this->replyTo; } /** * Sets Read Receipt (Disposition-Notification-To header). * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ public function setReadReceipt($email, ?string $name = null) { return $this->setEmailSingle( 'readReceipt', $email, $name, 'Disposition-Notification-To requires only 1 email address.' ); } /** * Gets Read Receipt (Disposition-Notification-To header). * * @return array */ public function getReadReceipt(): array { return $this->readReceipt; } /** * Sets return path. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ public function setReturnPath($email, ?string $name = null) { return $this->setEmailSingle('returnPath', $email, $name, 'Return-Path requires only 1 email address.'); } /** * Gets return path. * * @return array */ public function getReturnPath(): array { return $this->returnPath; } /** * Sets "to" address. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function setTo($email, ?string $name = null) { return $this->setEmail('to', $email, $name); } /** * Gets "to" address * * @return array */ public function getTo(): array { return $this->to; } /** * Add "To" address. * * @param string|array $email Null to get, String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function addTo($email, ?string $name = null) { return $this->addEmail('to', $email, $name); } /** * Sets "cc" address. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function setCc($email, ?string $name = null) { return $this->setEmail('cc', $email, $name); } /** * Gets "cc" address. * * @return array */ public function getCc(): array { return $this->cc; } /** * Add "cc" address. * * @param string|array $email Null to get, String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function addCc($email, ?string $name = null) { return $this->addEmail('cc', $email, $name); } /** * Sets "bcc" address. * * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function setBcc($email, ?string $name = null) { return $this->setEmail('bcc', $email, $name); } /** * Gets "bcc" address. * * @return array */ public function getBcc(): array { return $this->bcc; } /** * Add "bcc" address. * * @param string|array $email Null to get, String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this */ public function addBcc($email, ?string $name = null) { return $this->addEmail('bcc', $email, $name); } /** * Charset setter. * * @param string $charset Character set. * @return $this */ public function setCharset(string $charset) { $this->charset = $charset; return $this; } /** * Charset getter. * * @return string Charset */ public function getCharset(): string { return $this->charset; } /** * HeaderCharset setter. * * @param string|null $charset Character set. * @return $this */ public function setHeaderCharset(?string $charset) { $this->headerCharset = $charset; return $this; } /** * HeaderCharset getter. * * @return string Charset */ public function getHeaderCharset(): string { return $this->headerCharset ?: $this->charset; } /** * TransferEncoding setter. * * @param string|null $encoding Encoding set. * @return $this * @throws \InvalidArgumentException */ public function setTransferEncoding(?string $encoding) { if ($encoding !== null) { $encoding = strtolower($encoding); if (!in_array($encoding, $this->transferEncodingAvailable, true)) { throw new InvalidArgumentException( sprintf( 'Transfer encoding not available. Can be : %s.', implode(', ', $this->transferEncodingAvailable) ) ); } } $this->transferEncoding = $encoding; return $this; } /** * TransferEncoding getter. * * @return string|null Encoding */ public function getTransferEncoding(): ?string { return $this->transferEncoding; } /** * EmailPattern setter/getter * * @param string|null $regex The pattern to use for email address validation, * null to unset the pattern and make use of filter_var() instead. * @return $this */ public function setEmailPattern(?string $regex) { $this->emailPattern = $regex; return $this; } /** * EmailPattern setter/getter * * @return string|null */ public function getEmailPattern(): ?string { return $this->emailPattern; } /** * Set email * * @param string $varName Property name * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ protected function setEmail(string $varName, $email, ?string $name) { if (!is_array($email)) { $this->validateEmail($email, $varName); $this->{$varName} = [$email => $name ?? $email]; return $this; } $list = []; foreach ($email as $key => $value) { if (is_int($key)) { $key = $value; } $this->validateEmail($key, $varName); $list[$key] = $value ?? $key; } $this->{$varName} = $list; return $this; } /** * Validate email address * * @param string $email Email address to validate * @param string $context Which property was set * @return void * @throws \InvalidArgumentException If email address does not validate */ protected function validateEmail(string $email, string $context): void { if ($this->emailPattern === null) { if (filter_var($email, FILTER_VALIDATE_EMAIL)) { return; } } elseif (preg_match($this->emailPattern, (string)$email)) { return; } $context = ltrim($context, '_'); if ($email === '') { throw new InvalidArgumentException(sprintf('The email set for "%s" is empty.', $context)); } throw new InvalidArgumentException(sprintf('Invalid email set for "%s". You passed "%s".', $context, $email)); } /** * Set only 1 email * * @param string $varName Property name * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @param string $throwMessage Exception message * @return $this * @throws \InvalidArgumentException */ protected function setEmailSingle(string $varName, $email, ?string $name, string $throwMessage) { if ($email === []) { $this->{$varName} = $email; return $this; } $current = $this->{$varName}; $this->setEmail($varName, $email, $name); if (count($this->{$varName}) !== 1) { $this->{$varName} = $current; throw new InvalidArgumentException($throwMessage); } return $this; } /** * Add email * * @param string $varName Property name * @param string|array $email String with email, * Array with email as key, name as value or email as value (without name) * @param string|null $name Name * @return $this * @throws \InvalidArgumentException */ protected function addEmail(string $varName, $email, ?string $name) { if (!is_array($email)) { $this->validateEmail($email, $varName); if ($name === null) { $name = $email; } $this->{$varName}[$email] = $name; return $this; } $list = []; foreach ($email as $key => $value) { if (is_int($key)) { $key = $value; } $this->validateEmail($key, $varName); $list[$key] = $value; } $this->{$varName} = array_merge($this->{$varName}, $list); return $this; } /** * Sets subject. * * @param string $subject Subject string. * @return $this */ public function setSubject(string $subject) { $this->subject = $this->encodeForHeader($subject); return $this; } /** * Gets subject. * * @return string */ public function getSubject(): string { return $this->subject; } /** * Get original subject without encoding * * @return string Original subject */ public function getOriginalSubject(): string { return $this->decodeForHeader($this->subject); } /** * Sets headers for the message * * @param array $headers Associative array containing headers to be set. * @return $this */ public function setHeaders(array $headers) { $this->headers = $headers; return $this; } /** * Add header for the message * * @param array $headers Headers to set. * @return $this */ public function addHeaders(array $headers) { $this->headers = Hash::merge($this->headers, $headers); return $this; } /** * Get list of headers * * ### Includes: * * - `from` * - `replyTo` * - `readReceipt` * - `returnPath` * - `to` * - `cc` * - `bcc` * - `subject` * * @param string[] $include List of headers. * @return string[] */ public function getHeaders(array $include = []): array { $this->createBoundary(); if ($include === array_values($include)) { $include = array_fill_keys($include, true); } $defaults = array_fill_keys( [ 'from', 'sender', 'replyTo', 'readReceipt', 'returnPath', 'to', 'cc', 'bcc', 'subject', ], false ); $include += $defaults; $headers = []; $relation = [ 'from' => 'From', 'replyTo' => 'Reply-To', 'readReceipt' => 'Disposition-Notification-To', 'returnPath' => 'Return-Path', ]; foreach ($relation as $var => $header) { if ($include[$var]) { $headers[$header] = (string)current($this->formatAddress($this->{$var})); } } if ($include['sender']) { if (key($this->sender) === key($this->from)) { $headers['Sender'] = ''; } else { $headers['Sender'] = (string)current($this->formatAddress($this->sender)); } } foreach (['to', 'cc', 'bcc'] as $var) { if ($include[$var]) { $headers[ucfirst($var)] = implode(', ', $this->formatAddress($this->{$var})); } } $headers += $this->headers; if (!isset($headers['Date'])) { $headers['Date'] = date(DATE_RFC2822); } if ($this->messageId !== false) { if ($this->messageId === true) { $this->messageId = '<' . str_replace('-', '', Text::uuid()) . '@' . $this->domain . '>'; } $headers['Message-ID'] = $this->messageId; } if ($this->priority) { $headers['X-Priority'] = (string)$this->priority; } if ($include['subject']) { $headers['Subject'] = $this->subject; } $headers['MIME-Version'] = '1.0'; if ($this->attachments) { $headers['Content-Type'] = 'multipart/mixed; boundary="' . (string)$this->boundary . '"'; } elseif ($this->emailFormat === static::MESSAGE_BOTH) { $headers['Content-Type'] = 'multipart/alternative; boundary="' . (string)$this->boundary . '"'; } elseif ($this->emailFormat === static::MESSAGE_TEXT) { $headers['Content-Type'] = 'text/plain; charset=' . $this->getContentTypeCharset(); } elseif ($this->emailFormat === static::MESSAGE_HTML) { $headers['Content-Type'] = 'text/html; charset=' . $this->getContentTypeCharset(); } $headers['Content-Transfer-Encoding'] = $this->getContentTransferEncoding(); return $headers; } /** * Get headers as string. * * @param string[] $include List of headers. * @param string $eol End of line string for concatenating headers. * @param \Closure $callback Callback to run each header value through before stringifying. * @return string * @see Message::getHeaders() */ public function getHeadersString(array $include = [], string $eol = "\r\n", ?Closure $callback = null): string { $lines = $this->getHeaders($include); if ($callback) { $lines = array_map($callback, $lines); } $headers = []; foreach ($lines as $key => $value) { if (empty($value) && $value !== '0') { continue; } foreach ((array)$value as $val) { $headers[] = $key . ': ' . $val; } } return implode($eol, $headers); } /** * Format addresses * * If the address contains non alphanumeric/whitespace characters, it will * be quoted as characters like `:` and `,` are known to cause issues * in address header fields. * * @param array $address Addresses to format. * @return array */ protected function formatAddress(array $address): array { $return = []; foreach ($address as $email => $alias) { if ($email === $alias) { $return[] = $email; } else { $encoded = $this->encodeForHeader($alias); if ($encoded === $alias && preg_match('/[^a-z0-9 ]/i', $encoded)) { $encoded = '"' . str_replace('"', '\"', $encoded) . '"'; } $return[] = sprintf('%s <%s>', $encoded, $email); } } return $return; } /** * Sets email format. * * @param string $format Formatting string. * @return $this * @throws \InvalidArgumentException */ public function setEmailFormat(string $format) { if (!in_array($format, $this->emailFormatAvailable, true)) { throw new InvalidArgumentException('Format not available.'); } $this->emailFormat = $format; return $this; } /** * Gets email format. * * @return string */ public function getEmailFormat(): string { return $this->emailFormat; } /** * Gets the body types that are in this email message * * @return array Array of types. Valid types are Email::MESSAGE_TEXT and Email::MESSAGE_HTML */ public function getBodyTypes(): array { $format = $this->emailFormat; if ($format === static::MESSAGE_BOTH) { return [static::MESSAGE_HTML, static::MESSAGE_TEXT]; } return [$format]; } /** * Sets message ID. * * @param bool|string $message True to generate a new Message-ID, False to ignore (not send in email), * String to set as Message-ID. * @return $this * @throws \InvalidArgumentException */ public function setMessageId($message) { if (is_bool($message)) { $this->messageId = $message; } else { if (!preg_match('/^\<.+@.+\>$/', $message)) { throw new InvalidArgumentException( 'Invalid format to Message-ID. The text should be something like ""' ); } $this->messageId = $message; } return $this; } /** * Gets message ID. * * @return bool|string */ public function getMessageId() { return $this->messageId; } /** * Sets domain. * * Domain as top level (the part after @). * * @param string $domain Manually set the domain for CLI mailing. * @return $this */ public function setDomain(string $domain) { $this->domain = $domain; return $this; } /** * Gets domain. * * @return string */ public function getDomain(): string { return $this->domain; } /** * Add attachments to the email message * * Attachments can be defined in a few forms depending on how much control you need: * * Attach a single file: * * ``` * $this->setAttachments('path/to/file'); * ``` * * Attach a file with a different filename: * * ``` * $this->setAttachments(['custom_name.txt' => 'path/to/file.txt']); * ``` * * Attach a file and specify additional properties: * * ``` * $this->setAttachments(['custom_name.png' => [ * 'file' => 'path/to/file', * 'mimetype' => 'image/png', * 'contentId' => 'abc123', * 'contentDisposition' => false * ] * ]); * ``` * * Attach a file from string and specify additional properties: * * ``` * $this->setAttachments(['custom_name.png' => [ * 'data' => file_get_contents('path/to/file'), * 'mimetype' => 'image/png' * ] * ]); * ``` * * The `contentId` key allows you to specify an inline attachment. In your email text, you * can use `` to display the image inline. * * The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve * attachment compatibility with outlook email clients. * * @param array $attachments Array of filenames. * @return $this * @throws \InvalidArgumentException */ public function setAttachments(array $attachments) { $attach = []; foreach ($attachments as $name => $fileInfo) { if (!is_array($fileInfo)) { $fileInfo = ['file' => $fileInfo]; } if (!isset($fileInfo['file'])) { if (!isset($fileInfo['data'])) { throw new InvalidArgumentException('No file or data specified.'); } if (is_int($name)) { throw new InvalidArgumentException('No filename specified.'); } $fileInfo['data'] = chunk_split(base64_encode($fileInfo['data']), 76, "\r\n"); } elseif ($fileInfo['file'] instanceof UploadedFileInterface) { $fileInfo['mimetype'] = $fileInfo['file']->getClientMediaType(); if (is_int($name)) { /** @var string $name */ $name = $fileInfo['file']->getClientFilename(); } } elseif (is_string($fileInfo['file'])) { $fileName = $fileInfo['file']; $fileInfo['file'] = realpath($fileInfo['file']); if ($fileInfo['file'] === false || !file_exists($fileInfo['file'])) { throw new InvalidArgumentException(sprintf('File not found: "%s"', $fileName)); } if (is_int($name)) { $name = basename($fileInfo['file']); } } else { throw new InvalidArgumentException(sprintf( 'File must be a filepath or UploadedFileInterface instance. Found `%s` instead.', gettype($fileInfo['file']) )); } if ( !isset($fileInfo['mimetype']) && isset($fileInfo['file']) && is_string($fileInfo['file']) && function_exists('mime_content_type') ) { $fileInfo['mimetype'] = mime_content_type($fileInfo['file']); } if (!isset($fileInfo['mimetype'])) { $fileInfo['mimetype'] = 'application/octet-stream'; } $attach[$name] = $fileInfo; } $this->attachments = $attach; return $this; } /** * Gets attachments to the email message. * * @return array Array of attachments. */ public function getAttachments(): array { return $this->attachments; } /** * Add attachments * * @param array $attachments Array of filenames. * @return $this * @throws \InvalidArgumentException * @see \Cake\Mailer\Email::setAttachments() */ public function addAttachments(array $attachments) { $current = $this->attachments; $this->setAttachments($attachments); $this->attachments = array_merge($current, $this->attachments); return $this; } /** * Get generated message body as array. * * @return array */ public function getBody() { if (empty($this->message)) { $this->message = $this->generateMessage(); } return $this->message; } /** * Get generated body as string. * * @param string $eol End of line string for imploding. * @return string * @see Message::getBody() */ public function getBodyString(string $eol = "\r\n"): string { $lines = $this->getBody(); return implode($eol, $lines); } /** * Create unique boundary identifier * * @return void */ protected function createBoundary(): void { if ( $this->boundary === null && ( $this->attachments || $this->emailFormat === static::MESSAGE_BOTH ) ) { $this->boundary = md5(Security::randomBytes(16)); } } /** * Generate full message. * * @return string[] */ protected function generateMessage(): array { $this->createBoundary(); $msg = []; $contentIds = array_filter((array)Hash::extract($this->attachments, '{s}.contentId')); $hasInlineAttachments = count($contentIds) > 0; $hasAttachments = !empty($this->attachments); $hasMultipleTypes = $this->emailFormat === static::MESSAGE_BOTH; $multiPart = ($hasAttachments || $hasMultipleTypes); /** @var string $boundary */ $boundary = $this->boundary; $relBoundary = $textBoundary = $boundary; if ($hasInlineAttachments) { $msg[] = '--' . $boundary; $msg[] = 'Content-Type: multipart/related; boundary="rel-' . $boundary . '"'; $msg[] = ''; $relBoundary = $textBoundary = 'rel-' . $boundary; } if ($hasMultipleTypes && $hasAttachments) { $msg[] = '--' . $relBoundary; $msg[] = 'Content-Type: multipart/alternative; boundary="alt-' . $boundary . '"'; $msg[] = ''; $textBoundary = 'alt-' . $boundary; } if ( $this->emailFormat === static::MESSAGE_TEXT || $this->emailFormat === static::MESSAGE_BOTH ) { if ($multiPart) { $msg[] = '--' . $textBoundary; $msg[] = 'Content-Type: text/plain; charset=' . $this->getContentTypeCharset(); $msg[] = 'Content-Transfer-Encoding: ' . $this->getContentTransferEncoding(); $msg[] = ''; } $content = explode("\n", $this->textMessage); $msg = array_merge($msg, $content); $msg[] = ''; $msg[] = ''; } if ( $this->emailFormat === static::MESSAGE_HTML || $this->emailFormat === static::MESSAGE_BOTH ) { if ($multiPart) { $msg[] = '--' . $textBoundary; $msg[] = 'Content-Type: text/html; charset=' . $this->getContentTypeCharset(); $msg[] = 'Content-Transfer-Encoding: ' . $this->getContentTransferEncoding(); $msg[] = ''; } $content = explode("\n", $this->htmlMessage); $msg = array_merge($msg, $content); $msg[] = ''; $msg[] = ''; } if ($textBoundary !== $relBoundary) { $msg[] = '--' . $textBoundary . '--'; $msg[] = ''; } if ($hasInlineAttachments) { $attachments = $this->attachInlineFiles($relBoundary); $msg = array_merge($msg, $attachments); $msg[] = ''; $msg[] = '--' . $relBoundary . '--'; $msg[] = ''; } if ($hasAttachments) { $attachments = $this->attachFiles($boundary); $msg = array_merge($msg, $attachments); } if ($hasAttachments || $hasMultipleTypes) { $msg[] = ''; $msg[] = '--' . $boundary . '--'; $msg[] = ''; } return $msg; } /** * Attach non-embedded files by adding file contents inside boundaries. * * @param string|null $boundary Boundary to use. If null, will default to $this->boundary * @return string[] An array of lines to add to the message */ protected function attachFiles(?string $boundary = null): array { if ($boundary === null) { /** @var string $boundary */ $boundary = $this->boundary; } $msg = []; foreach ($this->attachments as $filename => $fileInfo) { if (!empty($fileInfo['contentId'])) { continue; } $data = $fileInfo['data'] ?? $this->readFile($fileInfo['file']); $hasDisposition = ( !isset($fileInfo['contentDisposition']) || $fileInfo['contentDisposition'] ); $part = new FormDataPart('', $data, '', $this->getHeaderCharset()); if ($hasDisposition) { $part->disposition('attachment'); $part->filename($filename); } $part->transferEncoding('base64'); $part->type($fileInfo['mimetype']); $msg[] = '--' . $boundary; $msg[] = (string)$part; $msg[] = ''; } return $msg; } /** * Attach inline/embedded files to the message. * * @param string|null $boundary Boundary to use. If null, will default to $this->boundary * @return string[] An array of lines to add to the message */ protected function attachInlineFiles(?string $boundary = null): array { if ($boundary === null) { /** @var string $boundary */ $boundary = $this->boundary; } $msg = []; foreach ($this->getAttachments() as $filename => $fileInfo) { if (empty($fileInfo['contentId'])) { continue; } $data = $fileInfo['data'] ?? $this->readFile($fileInfo['file']); $msg[] = '--' . $boundary; $part = new FormDataPart('', $data, 'inline', $this->getHeaderCharset()); $part->type($fileInfo['mimetype']); $part->transferEncoding('base64'); $part->contentId($fileInfo['contentId']); $part->filename($filename); $msg[] = (string)$part; $msg[] = ''; } return $msg; } /** * Sets priority. * * @param int|null $priority 1 (highest) to 5 (lowest) * @return $this */ public function setPriority(?int $priority) { $this->priority = $priority; return $this; } /** * Gets priority. * * @return int|null */ public function getPriority(): ?int { return $this->priority; } /** * Sets the configuration for this instance. * * @param array $config Config array. * @return $this */ public function setConfig(array $config) { $simpleMethods = [ 'from', 'sender', 'to', 'replyTo', 'readReceipt', 'returnPath', 'cc', 'bcc', 'messageId', 'domain', 'subject', 'attachments', 'emailFormat', 'emailPattern', 'charset', 'headerCharset', ]; foreach ($simpleMethods as $method) { if (isset($config[$method])) { $this->{'set' . ucfirst($method)}($config[$method]); } } if (isset($config['headers'])) { $this->setHeaders($config['headers']); } return $this; } /** * Set message body. * * @param array $content Content array with keys "text" and/or "html" with * content string of respective type. * @return $this */ public function setBody(array $content) { foreach ($content as $type => $text) { if (!in_array($type, $this->emailFormatAvailable, true)) { throw new InvalidArgumentException(sprintf( 'Invalid message type: "%s". Valid types are: "text", "html".', $type )); } $text = str_replace(["\r\n", "\r"], "\n", $text); $text = $this->encodeString($text, $this->getCharset()); $text = $this->wrap($text); $text = implode("\n", $text); $text = rtrim($text, "\n"); $property = "{$type}Message"; $this->$property = $text; } $this->boundary = null; $this->message = []; return $this; } /** * Set text body for message. * * @param string $content Content string * @return $this */ public function setBodyText(string $content) { $this->setBody([static::MESSAGE_TEXT => $content]); return $this; } /** * Set HTML body for message. * * @param string $content Content string * @return $this */ public function setBodyHtml(string $content) { $this->setBody([static::MESSAGE_HTML => $content]); return $this; } /** * Get text body of message. * * @return string */ public function getBodyText() { return $this->textMessage; } /** * Get HTML body of message. * * @return string */ public function getBodyHtml() { return $this->htmlMessage; } /** * Translates a string for one charset to another if the App.encoding value * differs and the mb_convert_encoding function exists * * @param string $text The text to be converted * @param string $charset the target encoding * @return string */ protected function encodeString(string $text, string $charset): string { if ($this->appCharset === $charset) { return $text; } if ($this->appCharset === null) { return mb_convert_encoding($text, $charset); } return mb_convert_encoding($text, $charset, $this->appCharset); } /** * Wrap the message to follow the RFC 2822 - 2.1.1 * * @param string|null $message Message to wrap * @param int $wrapLength The line length * @return array Wrapped message */ protected function wrap(?string $message = null, int $wrapLength = self::LINE_LENGTH_MUST): array { if ($message === null || strlen($message) === 0) { return ['']; } $message = str_replace(["\r\n", "\r"], "\n", $message); $lines = explode("\n", $message); $formatted = []; $cut = ($wrapLength === static::LINE_LENGTH_MUST); foreach ($lines as $line) { if (empty($line) && $line !== '0') { $formatted[] = ''; continue; } if (strlen($line) < $wrapLength) { $formatted[] = $line; continue; } if (!preg_match('/<[a-z]+.*>/i', $line)) { $formatted = array_merge( $formatted, explode("\n", Text::wordWrap($line, $wrapLength, "\n", $cut)) ); continue; } $tagOpen = false; $tmpLine = $tag = ''; $tmpLineLength = 0; for ($i = 0, $count = strlen($line); $i < $count; $i++) { $char = $line[$i]; if ($tagOpen) { $tag .= $char; if ($char === '>') { $tagLength = strlen($tag); if ($tagLength + $tmpLineLength < $wrapLength) { $tmpLine .= $tag; $tmpLineLength += $tagLength; } else { if ($tmpLineLength > 0) { $formatted = array_merge( $formatted, explode("\n", Text::wordWrap(trim($tmpLine), $wrapLength, "\n", $cut)) ); $tmpLine = ''; $tmpLineLength = 0; } if ($tagLength > $wrapLength) { $formatted[] = $tag; } else { $tmpLine = $tag; $tmpLineLength = $tagLength; } } $tag = ''; $tagOpen = false; } continue; } if ($char === '<') { $tagOpen = true; $tag = '<'; continue; } if ($char === ' ' && $tmpLineLength >= $wrapLength) { $formatted[] = $tmpLine; $tmpLineLength = 0; continue; } $tmpLine .= $char; $tmpLineLength++; if ($tmpLineLength === $wrapLength) { $nextChar = $line[$i + 1] ?? ''; if ($nextChar === ' ' || $nextChar === '<') { $formatted[] = trim($tmpLine); $tmpLine = ''; $tmpLineLength = 0; if ($nextChar === ' ') { $i++; } } else { $lastSpace = strrpos($tmpLine, ' '); if ($lastSpace === false) { continue; } $formatted[] = trim(substr($tmpLine, 0, $lastSpace)); $tmpLine = substr($tmpLine, $lastSpace + 1); $tmpLineLength = strlen($tmpLine); } } } if (!empty($tmpLine)) { $formatted[] = $tmpLine; } } $formatted[] = ''; return $formatted; } /** * Reset all the internal variables to be able to send out a new email. * * @return $this */ public function reset() { $this->to = []; $this->from = []; $this->sender = []; $this->replyTo = []; $this->readReceipt = []; $this->returnPath = []; $this->cc = []; $this->bcc = []; $this->messageId = true; $this->subject = ''; $this->headers = []; $this->textMessage = ''; $this->htmlMessage = ''; $this->message = []; $this->emailFormat = static::MESSAGE_TEXT; $this->priority = null; $this->charset = 'utf-8'; $this->headerCharset = null; $this->transferEncoding = null; $this->attachments = []; $this->emailPattern = static::EMAIL_PATTERN; return $this; } /** * Encode the specified string using the current charset * * @param string $text String to encode * @return string Encoded string */ protected function encodeForHeader(string $text): string { if ($this->appCharset === null) { return $text; } /** @var string $restore */ $restore = mb_internal_encoding(); mb_internal_encoding($this->appCharset); $return = mb_encode_mimeheader($text, $this->getHeaderCharset(), 'B'); mb_internal_encoding($restore); return $return; } /** * Decode the specified string * * @param string $text String to decode * @return string Decoded string */ protected function decodeForHeader(string $text): string { if ($this->appCharset === null) { return $text; } /** @var string $restore */ $restore = mb_internal_encoding(); mb_internal_encoding($this->appCharset); $return = mb_decode_mimeheader($text); mb_internal_encoding($restore); return $return; } /** * Read the file contents and return a base64 version of the file contents. * * @param string|\Psr\Http\Message\UploadedFileInterface $file The absolute path to the file to read * or UploadedFileInterface instance. * @return string File contents in base64 encoding */ protected function readFile($file): string { if (is_string($file)) { $content = (string)file_get_contents($file); } else { $content = (string)$file->getStream(); } return chunk_split(base64_encode($content)); } /** * Return the Content-Transfer Encoding value based * on the set transferEncoding or set charset. * * @return string */ public function getContentTransferEncoding(): string { if ($this->transferEncoding) { return $this->transferEncoding; } $charset = strtoupper($this->charset); if (in_array($charset, $this->charset8bit, true)) { return '8bit'; } return '7bit'; } /** * Return charset value for Content-Type. * * Checks fallback/compatibility types which include workarounds * for legacy japanese character sets. * * @return string */ public function getContentTypeCharset(): string { $charset = strtoupper($this->charset); if (array_key_exists($charset, $this->contentTypeCharset)) { return strtoupper($this->contentTypeCharset[$charset]); } return strtoupper($this->charset); } /** * Serializes the email object to a value that can be natively serialized and re-used * to clone this email instance. * * @return array Serializable array of configuration properties. * @throws \Exception When a view var object can not be properly serialized. */ public function jsonSerialize(): array { $properties = [ 'to', 'from', 'sender', 'replyTo', 'cc', 'bcc', 'subject', 'returnPath', 'readReceipt', 'emailFormat', 'emailPattern', 'domain', 'attachments', 'messageId', 'headers', 'appCharset', 'charset', 'headerCharset', ]; $array = []; foreach ($properties as $property) { $array[$property] = $this->{$property}; } array_walk($array['attachments'], function (&$item, $key): void { if (!empty($item['file'])) { $item['data'] = $this->readFile($item['file']); unset($item['file']); } }); return array_filter($array, function ($i) { return $i !== null && !is_array($i) && !is_bool($i) && strlen($i) || !empty($i); }); } /** * Configures an email instance object from serialized config. * * @param array $config Email configuration array. * @return $this Configured email instance. */ public function createFromArray(array $config) { foreach ($config as $property => $value) { $this->{$property} = $value; } return $this; } /** * Serializes the Email object. * * @return string */ public function serialize(): string { $array = $this->jsonSerialize(); array_walk_recursive($array, function (&$item, $key): void { if ($item instanceof SimpleXMLElement) { $item = json_decode(json_encode((array)$item), true); } }); return serialize($array); } /** * Unserializes the Email object. * * @param string $data Serialized string. * @return void */ public function unserialize($data) { $array = unserialize($data); if (!is_array($array)) { throw new Exception('Unable to unserialize message.'); } $this->createFromArray($array); } }