From d2da3adcf75f9f2f76c549a3370a921ea731a82d Mon Sep 17 00:00:00 2001 From: Ryan Cramer Date: Thu, 31 May 2018 13:17:22 -0400 Subject: [PATCH] Add new $mail->mail() method, which is the same as the existing $mail->send() method except that its arguments duplicate those of PHP mail(), making it possible to use as a drop-in replacement for PHP mail(). --- wire/core/Sanitizer.php | 6 +++ wire/core/WireMailTools.php | 86 ++++++++++++++++++++++++++++++++++++- wire/core/WireTextTools.php | 2 +- 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/wire/core/Sanitizer.php b/wire/core/Sanitizer.php index 427491f0..9155ea86 100644 --- a/wire/core/Sanitizer.php +++ b/wire/core/Sanitizer.php @@ -988,6 +988,7 @@ class Sanitizer extends Wire { * - `maxBytes` (int): maximum bytes allowed (default=0, which implies maxLength*4). * - `stripTags` (bool): strip markup tags? (default=true). * - `stripMB4` (bool): strip emoji and other 4-byte UTF-8? (default=false). + * - `stripQuotes` (bool): strip out any "quote" or 'quote' characters? Specify true, or character to replace with. (default=false) * - `stripSpace` (bool|string): strip whitespace? Specify true or character to replace whitespace with (default=false). * - `reduceSpace` (bool|string): reduce consecutive whitespace to single? Specify true or character to reduce to (default=false). * Note that the reduceSpace option is an alternative to the stripSpace option, they should not be used together. @@ -1009,6 +1010,7 @@ class Sanitizer extends Wire { 'maxBytes' => 0, // maximum bytes allowed (0 = default, which is maxLength*4) 'stripTags' => true, // strip markup tags 'stripMB4' => false, // strip Emoji and 4-byte characters? + 'stripQuotes' => false, // strip quote characters? Specify true, or character to replace them with 'stripSpace' => false, // remove/replace whitespace? If yes, specify character to replace with, or true for blank 'reduceSpace' => false, // reduce whitespace to single? If yes, specify character to replace with or true for ' '. 'allowableTags' => '', // tags that are allowed, if stripTags is true (use same format as for PHP's strip_tags function) @@ -1073,6 +1075,10 @@ class Sanitizer extends Wire { $value = $this->removeMB4($value); } + if($options['stripQuotes']) { + $value = str_replace(array('"', "'"), (is_string($options['stripQuotes']) ? $options['strip_quotes'] : ''), $value); + } + if($options['trim']) { $value = is_string($options['trim']) ? trim($value, $options['trim']) : trim($value); } diff --git a/wire/core/WireMailTools.php b/wire/core/WireMailTools.php index 5111417d..fffc6c33 100644 --- a/wire/core/WireMailTools.php +++ b/wire/core/WireMailTools.php @@ -120,6 +120,7 @@ class WireMailTools extends Wire { * @param array|string $options Array of options OR the $bodyHTML string. Array $options are: * - `body` (string): Email body (text) * - `bodyHTML` (string): Email body (HTML) + * - `replyTo` (string): Reply-to email address * - `headers` (array): Associative array of header name => header value * - Any additional options will be sent along to the WireMail module or class, in tact. * @return int|WireMail Returns number of messages sent or WireMail object if no arguments specified. @@ -133,7 +134,7 @@ class WireMailTools extends Wire { if(empty($to)) return $mail; $defaults = array( - 'body' => $body, + 'body' => is_string($body) ? $body : '', 'bodyHTML' => '', 'replyTo' => '', // email address 'headers' => array(), @@ -159,8 +160,10 @@ class WireMailTools extends Wire { try { // configure the mail - $mail->to($to)->from($from)->subject($subject)->body($options['body']); + $mail->to($to)->subject($subject); + if(strlen($from)) $mail->from($from); if(strlen($options['bodyHTML'])) $mail->bodyHTML($options['bodyHTML']); + if(strlen($options['body'])) $mail->body($options['body']); if(count($options['headers'])) foreach($options['headers'] as $k => $v) $mail->header($k, $v); // send along any options we don't recognize foreach($options as $key => $value) { @@ -177,6 +180,85 @@ class WireMailTools extends Wire { return $numSent; } + /** + * Send an email, drop-in replacement for PHP mail() that uses the same arguments + * + * This is an alternative to using the `$mail->send()` method, and may be simpler for those converting + * existing PHP `mail()` calls to WireMail calls. + * + * This function duplicates the same arguments as PHP’s mail function, enabling you to replace an existing + * PHP `mail(…)` call with `$mail->mail(…)`. + * + * But unlike PHP’s mail function, this one can also send HTML (or multipart) emails if you provide + * an `$options` array for the `$message` argument (rather than a string). See the options array for + * the `$mail->send()` method for details. + * ~~~~~ + * // 1. Basic PHP mail() style usage + * $mail->mail('ryan@processwire.com', 'Subject', 'Message body'); + * + * // 2. PHP mail() style usage with with $headers argument + * $mail->mail('ryan@processwire.com', 'Subject', 'Message body', 'From: hello@world.com'); + * + * // 3. Alternate usage with html and text body + * $mail->mail('ryan@processwire.com', 'Subject', [ + * 'bodyHTML' => '

Message HTML body

', + * 'body' => 'Message text body', + * 'from' => 'hello@world.com', + * ]); + * ~~~~~ + * + * @param string|array $to Email address TO. For multiple, specify CSV string or array. + * @param string $subject Email subject + * @param string|array $message Email body (PHP mail style), OR specify $options array with any of the following: + * - `bodyHTML` (string): Email body (HTML) + * - `body` (string): Email body (text). If not specified, and bodyHTML is, then text body will be auto-generated. + * - `from` (string): From email address + * - `replyTo` (string): Reply-to email address + * - `headers` (array): Associative array of header name => header value + * @param array $headers Optional additional headers as [name=value] array or "Name: Value" newline-separated string. + * Use this argument to duplicate PHP mail() style arguments. No need to use if you used $options array for the $message argument. + * @return bool True on success, false on fail. + * + */ + public function mail($to, $subject, $message, $headers = array()) { + $from = ''; + + if(is_string($headers)) { + $_headers = explode("\n", $headers); + $headers = array(); + foreach($_headers as $header) { + if(!strpos($header, ':')) continue; + list($key, $val) = explode(':', $header, 2); + $headers[trim($key)] = trim($val); + } + } + + foreach($headers as $key => $val) { + if(strtolower($key) !== 'from') continue; + $from = $val; + unset($headers[$key]); + break; + } + + if(is_array($message)) { + // message is $options array + $options = $message; + if(!empty($options['headers'])) $headers = array_merge($headers, $options['headers']); + $options['headers'] = $headers; + if(isset($options['from'])) { + if(empty($from)) $from = $options['from']; + unset($options['from']); + } + $qty = $this->send($to, $from, $subject, $options); + + } else { + // regular PHP style mail() call converted to $mail->send() call + $qty = $this->send($to, $from, $subject, $message, $headers); + } + + return $qty > 0; + } + public function __get($key) { if($key === 'new') return $this->new(); return parent::__get($key); diff --git a/wire/core/WireTextTools.php b/wire/core/WireTextTools.php index e818f7d2..e4b87d2c 100644 --- a/wire/core/WireTextTools.php +++ b/wire/core/WireTextTools.php @@ -107,7 +107,7 @@ class WireTextTools extends Wire { // convert entities to plain text equivalents if($options['convertEntities'] && strpos($str, '&') !== false) { - $str = $this->unentities($str); + $str = $this->wire('sanitizer')->unentities($str); } return trim($str);