/** * Encode a given string to produce an encoded string. * * @param string $string * @param int $firstLineOffset if first line needs to be shorter * @param int $maxLineLength 0 indicates the default length for this encoding * * @return string * * @throws RuntimeException */ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0) { if ($this->charset !== 'utf-8') { throw new RuntimeException(sprintf('Charset "%s" not supported. NativeQpContentEncoder only supports "utf-8"', $this->charset)); } return $this->_standardize(quoted_printable_encode($string)); }
/** * Send an email with the UTF-8 character set * @param string $to * @param string $subject * @param string $body The HTML body part * @param string $text The plaintext body part (optional) * @return bool */ protected function _utf8mail($to, $subject, $body, $text = null) { $f3 = \Base::instance(); // Add basic headers $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'To: ' . $to . "\r\n"; $headers .= 'From: ' . $f3->get("mail.from") . "\r\n"; // Build multipart message if necessary if ($text) { // Generate message breaking hash $hash = md5(date("r")); $headers .= "Content-type: multipart/alternative; boundary=\"{$hash}\"\r\n"; // Normalize line endings $body = str_replace("\r\n", "\n", $body); $body = str_replace("\n", "\r\n", $body); $text = str_replace("\r\n", "\n", $text); $text = str_replace("\n", "\r\n", $text); // Build final message $msg = "--{$hash}\r\n"; $msg .= "Content-type: text/plain; charset=utf-8\r\n"; $msg .= "Content-Transfer-Encoding: quoted-printable\r\n"; $msg .= "\r\n" . quoted_printable_encode($text) . "\r\n"; $msg .= "--{$hash}\r\n"; $msg .= "Content-type: text/html; charset=utf-8\r\n"; $msg .= "Content-Transfer-Encoding: quoted-printable\r\n"; $msg .= "\r\n" . quoted_printable_encode($body) . "\r\n"; $msg .= "--{$hash}\r\n"; $body = $msg; } else { $headers .= "Content-type: text/html; charset=utf-8\r\n"; } return mail($to, $subject, $body, $headers); }
public function sendmail($to, $from, $subject = "", $body = "", $mailtype, $cc = "", $bcc = "", $additional_headers = "") { $mail_from = $this->get_address($this->strip_comment($from)); $body = preg_replace("/(^|(\r\n))(\\.)/", ".", $body); //$body = mb_encode_mimeheader($body, "utf-8", "B"); $body = quoted_printable_encode($body); @($header .= "MIME-Version:1.0\r\n"); if ($mailtype == "HTML") { $header .= "Content-Type:text/html; charset=utf-8\r\n"; //$header .= "Content-Transfer-Encoding: base64\r\n"; $header .= "Content-Transfer-Encoding: quoted-printable\r\n"; } $header .= "To: " . $to . "\r\n"; if ($cc != "") { $header .= "Cc: " . $cc . "\r\n"; } //$header .= "From: $from<".$from.">\r\n"; $header .= "From: {$this->custom_from_name} <" . $this->custom_from_address . ">\r\n"; $header .= "Subject: " . "=?UTF-8?B?" . base64_encode($subject) . "?=" . "\r\n"; $header .= $additional_headers; $header .= "Date: " . date("r") . "\r\n"; $header .= "X-Mailer:By Redhat (PHP/" . phpversion() . ")\r\n"; list($msec, $sec) = explode(" ", microtime()); $header .= "Message-ID: <" . date("YmdHis", $sec) . "." . $msec * 1000000 . "." . $mail_from . ">\r\n"; $TO = explode(",", $this->strip_comment($to)); if ($cc != "") { $TO = array_merge($TO, explode(",", $this->strip_comment($cc))); } if ($bcc != "") { $TO = array_merge($TO, explode(",", $this->strip_comment($bcc))); } $sent = TRUE; $sent_address = array(); foreach ($TO as $rcpt_to) { $rcpt_to = $this->get_address($rcpt_to); $address_hash_sum = sha1($rcpt_to); if (isset($sent_addresses[$address_hash_sum])) { $this->log_write("Warning: Already sent to {$rcpt_to}\n"); continue; } if (!$this->smtp_sockopen($rcpt_to)) { $this->log_write("Error: Cannot send email to " . $rcpt_to . "\n"); $sent = FALSE; continue; } if ($this->smtp_send($this->host_name, $mail_from, $rcpt_to, $header, $body)) { $this->log_write("E-mail has been sent to <" . $rcpt_to . ">\n"); $sent_addresses[$address_hash_sum] = 1; } else { $this->log_write("Error: Cannot send email to <" . $rcpt_to . ">\n"); $sent = TRUE; //忽略离职 } fclose($this->sock); $this->log_write("Disconnected from remote host\n"); } return $sent; }
/** * Test decoding of header values * Uses rcube_mime::decode_mime_string() */ function test_header_decode_qp() { $test = array('quoted-printable (1)' => array('in' => '=?utf-8?Q?Certifica=C3=A7=C3=A3??=', 'out' => 'Certifica=C3=A7=C3=A3?'), 'quoted-printable (2)' => array('in' => '=?utf-8?Q?Certifica=?= =?utf-8?Q?C3=A7=C3=A3?=', 'out' => 'Certifica=C3=A7=C3=A3'), 'quoted-printable (3)' => array('in' => '=?utf-8?Q??= =?utf-8?Q??=', 'out' => ''), 'quoted-printable (4)' => array('in' => '=?utf-8?Q??= a =?utf-8?Q??=', 'out' => ' a '), 'quoted-printable (5)' => array('in' => '=?utf-8?Q?a?= =?utf-8?Q?b?=', 'out' => 'ab'), 'quoted-printable (6)' => array('in' => '=?utf-8?Q? ?= =?utf-8?Q?a?=', 'out' => ' a'), 'quoted-printable (7)' => array('in' => '=?utf-8?Q?___?= =?utf-8?Q?a?=', 'out' => ' a')); foreach ($test as $idx => $item) { $res = rcube_mime::decode_mime_string($item['in'], 'UTF-8'); $res = quoted_printable_encode($res); $this->assertEquals($item['out'], $res, "Header decoding for: " . $idx); } }
/** * @test */ public function it_decodes_a_quoted_printable_string_when_encoding_is_set() { $decoder = new MessageDecoder(); // Let's use all Latin-1 chars. $chars = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ'; $qp = quoted_printable_encode($chars); $decoded = $decoder->decodeBody($qp, ENCQUOTEDPRINTABLE); $this->assertEquals($chars, $decoded); }
function send($mail) { $headers = "MIME-Version: 1.0\r\n"; $headers .= "Content-Type: text/html;charset=utf-8\r\n"; $headers .= "Content-Transfer-Encoding: quoted-printable\r\n"; $headers .= "To: {$address}\r\n"; $headers .= 'From: =?UTF-8?B?' . base64_encode('贴吧签到助手') . "?=\r\n"; $message = quoted_printable_encode($message); return mail($mail->address, '=?UTF-8?B?' . base64_encode($mail->subject) . '?=', $mail->message, $headers); }
function send_email($to, $subject, $message, $from = '') { $headers = array(); $headers[] = 'MIME-Version: 1.0'; $headers[] = 'Content-type: text/html; charset=UTF-8'; $headers[] = 'Content-Transfer-Encoding: quoted-printable'; $headers[] = "From: {$from}"; $email_message = quoted_printable_encode($message); return mail($to, $subject, $email_message, implode("\n", $headers), '-f' . $from); }
/** * @ignore */ public function compileBody() { $tString = ""; if ($this->transferEncoding === 'base64') { $tString .= chunk_split(base64_encode($this->content)); } elseif ($this->transferEncoding === 'quoted-printable') { $tString .= quoted_printable_encode($this->content); } else { $tString .= $this->content; } return $tString; }
/** * Takes a transformed body and turns it into the raw body string needed for the mime encoding. * * @param $transformedBody */ public final function setTransformedBody($transformedBody) { $encoding = isset($this->headers["Content-Transfer-Encoding"]) ? $this->headers["Content-Transfer-Encoding"] : ""; switch ($encoding) { case "quoted-printable": $this->setRawBody(quoted_printable_encode($transformedBody)); break; case "base64": $this->setRawBody(chunk_split(base64_encode($transformedBody), 76)); break; default: $this->setRawBody($transformedBody); } }
private function sendMail($text) { if ($this->config['enable_mailer'] === true) { $sender = $this->config['sender']; $receiver = $this->config['receiver']; $subject = $this->config['subject']; $boundary = $this->mailer->generateBoundary(); $text = quoted_printable_encode($text); $message = "\n--{$boundary}\n"; $message .= "Content-Type: text/plain; charset=UTF-8\n"; $message .= "Content-Transfer-Encoding: quoted-printable\n\n"; $message .= "{$text}\n\n"; $message .= "--{$boundary}--\n"; $this->mailer->send($sender, $receiver, $subject, $message, $boundary); } }
public function sendmail($to, $subject = "", $body = "", $mailtype, $cc = "", $bcc = "", $additional_headers = "") { $mail_from = $this->get_address($this->strip_comment($this->email)); $body = ereg_replace("(^|(\r\n))(\\.)", ".", $body); $header .= "MIME-Version:1.0\r\n"; if ($mailtype == "HTML") { $header .= "Content-Type:text/html;charset=" . $this->charset . "\r\n"; $header .= "Content-Transfer-Encoding: quoted-printable\r\n"; $body = quoted_printable_encode($body); } $header .= "To: " . $to . "\r\n"; if ($cc != "") { $header .= "Cc: " . $cc . "\r\n"; } $header .= "From: " . $this->getCharset($this->name) . " <" . $this->email . ">\r\n"; $header .= "Subject: " . $this->getCharset($subject) . "\r\n"; $header .= $additional_headers; $header .= "Date: " . date("r") . "\r\n"; list($msec, $sec) = explode(" ", microtime()); $header .= "Message-ID: <" . date("YmdHis", $sec) . "." . $msec * 1000000 . "." . $this->email . ">\r\n"; $header .= "Return-Path: <" . $this->email . ">\r\n"; $TO = explode(",", $this->strip_comment($to)); if ($cc != "") { $TO = array_merge($TO, explode(",", $this->strip_comment($cc))); } if ($bcc != "") { $TO = array_merge($TO, explode(",", $this->strip_comment($bcc))); } $sent = TRUE; foreach ($TO as $rcpt_to) { $rcpt_to = $this->get_address($rcpt_to); if (!$this->smtp_sockopen($rcpt_to)) { $this->log_write("Error: Cannot send email to " . $rcpt_to . "\n"); $sent = FALSE; continue; } if ($this->smtp_send($this->relay_host, $mail_from, $rcpt_to, $header, $body)) { $this->log_write("E-mail has been sent to <" . $rcpt_to . ">\n"); } else { $this->log_write("Error: Cannot send email to <" . $rcpt_to . ">\n"); $sent = FALSE; } fclose($this->sock); $this->log_write("Disconnected from remote host\n"); } return $sent; }
function gs_keyval_enc($str) { /* return str_replace(' ', '=20', quoted_printable_encode($str, false)); */ $str = quoted_printable_encode($str, false); # encode trailing spaces: do { $str = preg_replace('/ ( *)$/', '=20$1', $str, -1, $cnt); } while ($cnt > 0); # encode leading spaces: do { $str = preg_replace('/^( *) /', '$1=20', $str, -1, $cnt); } while ($cnt > 0); return $str; }
function email_encode($String = '', $Caracteres = 'ISO-8859-1') { // Quoted-printed (Q) if (function_exists('quoted_printable_encode')) { $String = quoted_printable_encode($String); $RT = '=?' . $Caracteres . '?Q?' . $String . '?='; } else { // IMAP 8bit (Q) if (function_exists('imap_8bit')) { $String = imap_8bit($String); $RT = '=?' . $Caracteres . '?Q?' . $String . '?='; } else { $String = base64_encode($String); $RT = '=?' . $Caracteres . '?B?' . $String . '?='; } } return $RT; }
public static function parse($mimetype, $encoding, $body, $charset = "UTF-8") { $header = new RFC5322Header(); $header->setValue("Content-Type", $mimetype); $header->get("Content-Type")->addExtra("charset", $charset); $header->setValue("Content-Transfer-Encoding", $encoding); switch ($encoding) { case "7bit": case "8bit": case "binary": // Keine weitere Kodierung gewuenscht! break; case "base64": $body = chunk_split(base64_encode($body), 76, "\r\n"); break; case "quoted-printable": $body = quoted_printable_encode($body); break; } return new RFC5322PlainBody($header, $body); }
public function send() { $uid = md5(uniqid(time())); $headers = []; if ($this->from) { $headers[] = 'From: ' . $this->from; } if ($this->replyTo) { $headers[] = 'Reply-To: ' . $this->replyTo; } $headers[] = 'MIME-Version: 1.0'; $headers[] = "Content-Type: multipart/mixed; boundary=\"" . $uid . "\""; $headers[] = "This is a multi-part message in MIME format."; $headers[] = "--{$uid}"; $headers[] = "Content-type: text/html; charset=UTF-8"; $headers[] = "Content-Transfer-Encoding: quoted-printable"; $headers[] = ''; $headers[] = quoted_printable_encode($this->message); $headers[] = ''; foreach ($this->attachments as $file) { $name = basename($file); $headers[] = "--{$uid}"; $headers[] = "Content-type: application/octet-stream; name=\"" . $name . "\""; $headers[] = "Content-Transfer-Encoding: base64"; $headers[] = "Content-Disposition: attachment; filename=\"" . $name . "\""; $headers[] = ''; $headers[] = chunk_split(base64_encode(file_get_contents($file))); $headers[] = ''; } $headers[] = "--{$uid}--"; $success = true; foreach ($this->recipients as $to) { $body = implode("\r\n", $headers); $success = mail($to, $this->subject, '', $body); Event::trigger('core.email.send', $to, $this->from, $this->subject, $body, $success); $success = $success && $success; } return $success; }
/** * Encode plain array to TSV with $encoding. * * @param array $data Array data to encode * @param mixed $encoding Encode type * @access public * @return String Encoded string */ public function encodeTsvrpc(array $data, $encoding = null) { $encoders = array('U' => function ($value) { return urlencode($value); }, 'Q' => function ($value) { return quoted_printable_encode($value); }, 'B' => function ($value) { return base64_encode($value); }); if (isset($encoders[$encoding])) { $encoder = $encoders[$encoding]; } else { // When $encoding is not in $encoders, nothing to do. $encoder = function ($value) { return $value; }; } $res = array(); foreach ($data as $k => $v) { $res[] = $encoder($k) . "\t" . $encoder($v); } return implode("\n", $res); }
public function renderMessage() { $html = $this->renderHtml(); $text = $this->renderText(); $body = ''; if ($text != null && $text != '' && $html != null && $html != '') { $body .= "------mail-boundary----\r\n"; $body .= "Content-Type: text/plain\r\n"; $body .= "Content-Transfer-Encoding: quoted-printable\r\n"; $body .= quoted_printable_encode($text) . "\r\n"; $body .= "------mail-boundary----\r\n"; $body .= "Content-Type: text/html\r\n"; $body .= "Content-Transfer-Encoding: quoted-printable\r\n"; $body .= quoted_printable_encode($html) . "\r\n"; $body .= "------mail-boundary------"; } else { $body .= $html != null ? $html : $text; } if ($body == null || trim($body) == '') { throw new \Exception("No content type templates for mailer view " . $this->view); } return $body; }
/** * Renders an unfolded line * * @return string */ public function toLine() { // Property-name $line = $this->getName(); $value = $this->value; if (false !== strpos($value, "\n")) { $this->params['ENCODING'] = 'QUOTED-PRINTABLE'; $value = quoted_printable_encode($value); $value = strtr($value, array("\r" => "", "\n" => "")); } // Adding params foreach ($this->params as $param => $paramValues) { if (!is_array($paramValues)) { $paramValues = array($paramValues); } foreach ($paramValues as $k => $v) { $paramValues[$k] = $this->escapeParamValue($v); } $line .= ';' . $param . '=' . implode(',', $paramValues); } // Property value $line .= ':' . $value; return $line; }
<?php var_dump(quoted_printable_encode()); var_dump(quoted_printable_encode("")); var_dump(quoted_printable_encode("test")); var_dump(quoted_printable_encode("test", "more")); $a = array("str"); var_dump(quoted_printable_encode($a)); var_dump(quoted_printable_encode(1)); var_dump(quoted_printable_encode(NULL)); var_dump(quoted_printable_encode(false)); echo "Done\n";
/** * Encode a string in quoted-printable format. * According to RFC2045 section 6.7. * @access public * @param string $string The text to encode * @param integer $line_max Number of chars allowed on a line before wrapping * @return string * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment */ public function encodeQP($string, $line_max = 76) { // Use native function if it's available (>= PHP5.3) if (function_exists('quoted_printable_encode')) { return quoted_printable_encode($string); } // Fall back to a pure PHP implementation $string = str_replace(array('%20', '%0D%0A.', '%0D%0A', '%'), array(' ', "\r\n=2E", "\r\n", '='), rawurlencode($string)); return preg_replace('/[^\\r\\n]{' . ($line_max - 3) . '}[^=\\r\\n]{2}/', "\$0=\r\n", $string); }
/** * Encode string to RFC2045 (6.7) quoted-printable format * Uses a PHP5 stream filter to do the encoding about 64x faster than the old version * Also results in same content as you started with after decoding * @see EncodeQPphp() * @access public * @param string $string the text to encode * @param integer $line_max Number of chars allowed on a line before wrapping * @param boolean $space_conv Dummy param for compatibility with existing EncodeQP function * @return string * @author Marcus Bointon */ public function EncodeQP($string, $line_max = 76, $space_conv = false) { if (function_exists('quoted_printable_encode')) { //Use native function if it's available (>= PHP5.3) return quoted_printable_encode($string); } $filters = stream_get_filters(); if (!in_array('convert.*', $filters)) { //Got convert stream filter? return $this->EncodeQPphp($string, $line_max, $space_conv); //Fall back to old implementation } $fp = fopen('php://temp/', 'r+'); $string = preg_replace('/\\r\\n?/', $this->LE, $string); //Normalise line breaks $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE); $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params); fputs($fp, $string); rewind($fp); $out = stream_get_contents($fp); stream_filter_remove($s); $out = preg_replace('/^\\./m', '=2E', $out); //Encode . if it is first char on a line, workaround for bug in Exchange fclose($fp); return $out; }
/** * @unused * * @param string $sEncodeType * @param string $sEncodeCharset * @param string $sValue * * @return string */ public static function EncodeHeaderValue($sEncodeType, $sEncodeCharset, $sValue) { $sValue = \trim($sValue); if (0 < \strlen($sValue) && !\MailSo\Base\Utils::IsAscii($sValue)) { switch (\strtoupper($sEncodeType)) { case 'B': $sValue = '=?' . \strtolower($sEncodeCharset) . '?B?' . \base64_encode($sValue) . '?='; break; case 'Q': $sValue = '=?' . \strtolower($sEncodeCharset) . '?Q?' . \str_replace(array('?', ' ', '_'), array('=3F', '_', '=5F'), \quoted_printable_encode($sValue)) . '?='; break; } } return \trim($sValue); }
/** * Transmit message * @return bool * @param $message string * @param $log bool **/ function send($message, $log = TRUE) { if ($this->scheme == 'ssl' && !extension_loaded('openssl')) { return FALSE; } // Message should not be blank if (!$message) { user_error(self::E_Blank); } $fw = Base::instance(); // Retrieve headers $headers = $this->headers; // Connect to the server $socket =& $this->socket; $socket = @fsockopen($this->host, $this->port); if (!$socket) { return FALSE; } stream_set_blocking($socket, TRUE); // Get server's initial response $this->dialog(NULL, FALSE); // Announce presence $reply = $this->dialog('EHLO ' . $fw->get('HOST'), $log); if (strtolower($this->scheme) == 'tls') { $this->dialog('STARTTLS', $log); stream_socket_enable_crypto($socket, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); $reply = $this->dialog('EHLO ' . $fw->get('HOST'), $log); if (preg_match('/8BITMIME/', $reply)) { $headers['Content-Transfer-Encoding'] = '8bit'; } else { $headers['Content-Transfer-Encoding'] = 'quoted-printable'; $message = quoted_printable_encode($message); } } if ($this->user && $this->pw && preg_match('/AUTH/', $reply)) { // Authenticate $this->dialog('AUTH LOGIN', $log); $this->dialog(base64_encode($this->user), $log); $this->dialog(base64_encode($this->pw), $log); } // Required headers $reqd = array('From', 'To', 'Subject'); foreach ($reqd as $id) { if (empty($headers[$id])) { user_error(sprintf(self::E_Header, $id)); } } $eol = "\r\n"; $str = ''; // Stringify headers foreach ($headers as $key => $val) { if (!in_array($key, $reqd)) { $str .= $key . ': ' . $val . $eol; } } // Start message dialog $this->dialog('MAIL FROM: ' . strstr($headers['From'], '<'), $log); foreach ($fw->split($headers['To'] . (isset($headers['Cc']) ? ';' . $headers['Cc'] : '') . (isset($headers['Bcc']) ? ';' . $headers['Bcc'] : '')) as $dst) { $this->dialog('RCPT TO: ' . strstr($dst, '<'), $log); } $this->dialog('DATA', $log); if ($this->attachments) { // Replace Content-Type $hash = uniqid(NULL, TRUE); $type = $headers['Content-Type']; $headers['Content-Type'] = 'multipart/mixed; ' . 'boundary="' . $hash . '"'; // Send mail headers $out = ''; foreach ($headers as $key => $val) { if ($key != 'Bcc') { $out .= $key . ': ' . $val . $eol; } } $out .= $eol; $out .= 'This is a multi-part message in MIME format' . $eol; $out .= $eol; $out .= '--' . $hash . $eol; $out .= 'Content-Type: ' . $type . $eol; $out .= $eol; $out .= $message . $eol; foreach ($this->attachments as $attachment) { if (is_array($attachment)) { list($alias, $file) = each($attachment); $filename = $alias; $attachment = $file; } else { $filename = basename($attachment); } $out .= '--' . $hash . $eol; $out .= 'Content-Type: application/octet-stream' . $eol; $out .= 'Content-Transfer-Encoding: base64' . $eol; $out .= 'Content-Disposition: attachment; ' . 'filename="' . $filename . '"' . $eol; $out .= $eol; $out .= chunk_split(base64_encode(file_get_contents($attachment))) . $eol; } $out .= $eol; $out .= '--' . $hash . '--' . $eol; $out .= '.'; $this->dialog($out, FALSE); } else { // Send mail headers $out = ''; foreach ($headers as $key => $val) { if ($key != 'Bcc') { $out .= $key . ': ' . $val . $eol; } } $out .= $eol; $out .= $message . $eol; $out .= '.'; // Send message $this->dialog($out); } $this->dialog('QUIT', $log); if ($socket) { fclose($socket); } return TRUE; }
/** * Prep Quoted Printable * * Prepares string for Quoted-Printable Content-Transfer-Encoding * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * * @param string * @return string */ protected function _prep_quoted_printable($str) { // We are intentionally wrapping so mail servers will encode characters // properly and MUAs will behave, so {unwrap} must go! $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); // RFC 2045 specifies CRLF as "\r\n". // However, many developers choose to override that and violate // the RFC rules due to (apparently) a bug in MS Exchange, // which only works with "\n". if ($this->crlf === "\r\n") { if (is_php('5.3')) { return quoted_printable_encode($str); } elseif (function_exists('imap_8bit')) { return imap_8bit($str); } } // Reduce multiple spaces & remove nulls $str = preg_replace(array('| +|', '/\\x00+/'), array(' ', ''), $str); // Standardize newlines if (strpos($str, "\r") !== FALSE) { $str = str_replace(array("\r\n", "\r"), "\n", $str); } $escape = '='; $output = ''; foreach (explode("\n", $str) as $line) { $length = strlen($line); $temp = ''; // Loop through each character in the line to add soft-wrap // characters at the end of a line " =\r\n" and add the newly // processed line(s) to the output (see comment on $crlf class property) for ($i = 0; $i < $length; $i++) { // Grab the next character $char = $line[$i]; $ascii = ord($char); // Convert spaces and tabs but only if it's the end of the line if ($i === $length - 1 && ($ascii === 32 or $ascii === 9)) { $char = $escape . sprintf('%02s', dechex($ascii)); } elseif ($ascii === 61) { $char = $escape . strtoupper(sprintf('%02s', dechex($ascii))); // =3D } // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' if (strlen($temp) + strlen($char) >= 76) { $output .= $temp . $escape . $this->crlf; $temp = ''; } // Add the character to our temporary line $temp .= $char; } // Add our completed line to the output $output .= $temp . $this->crlf; } // get rid of extra CRLF tacked onto the end return substr($output, 0, strlen($this->crlf) * -1); }
/** * Returns encoded message. * @return string */ public function getEncodedMessage() { $output = ''; $boundary = '--------' . Strings::random(); foreach ($this->headers as $name => $value) { $output .= $name . ': ' . $this->getEncodedHeader($name); if ($this->parts && $name === 'Content-Type') { $output .= ';' . self::EOL . "\tboundary=\"{$boundary}\""; } $output .= self::EOL; } $output .= self::EOL; $body = (string) $this->body; if ($body !== '') { switch ($this->getEncoding()) { case self::ENCODING_QUOTED_PRINTABLE: $output .= quoted_printable_encode($body); break; case self::ENCODING_BASE64: $output .= rtrim(chunk_split(base64_encode($body), self::LINE_LENGTH, self::EOL)); break; case self::ENCODING_7BIT: $body = preg_replace('#[\\x80-\\xFF]+#', '', $body); // break intentionally omitted // break intentionally omitted case self::ENCODING_8BIT: $body = str_replace(array("", "\r"), '', $body); $body = str_replace("\n", self::EOL, $body); $output .= $body; break; default: throw new Nette\InvalidStateException('Unknown encoding.'); } } if ($this->parts) { if (substr($output, -strlen(self::EOL)) !== self::EOL) { $output .= self::EOL; } foreach ($this->parts as $part) { $output .= '--' . $boundary . self::EOL . $part->getEncodedMessage() . self::EOL; } $output .= '--' . $boundary . '--'; } return $output; }
/** * Prep Quoted Printable * * Prepares string for Quoted-Printable Content-Transfer-Encoding * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * * @param string * @return string */ protected function _prep_quoted_printable($str) { // ASCII code numbers for "safe" characters that can always be // used literally, without encoding, as described in RFC 2049. // http://www.ietf.org/rfc/rfc2049.txt static $ascii_safe_chars = array(39, 40, 41, 43, 44, 45, 46, 47, 58, 61, 63, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122); // We are intentionally wrapping so mail servers will encode characters // properly and MUAs will behave, so {unwrap} must go! $str = str_replace(array('{unwrap}', '{/unwrap}'), '', $str); // RFC 2045 specifies CRLF as "\r\n". // However, many developers choose to override that and violate // the RFC rules due to (apparently) a bug in MS Exchange, // which only works with "\n". if ($this->crlf === "\r\n") { if (is_php('5.3')) { return quoted_printable_encode($str); } elseif (function_exists('imap_8bit')) { return imap_8bit($str); } } // Reduce multiple spaces & remove nulls $str = preg_replace(array('| +|', '/\\x00+/'), array(' ', ''), $str); // Standardize newlines if (strpos($str, "\r") !== FALSE) { $str = str_replace(array("\r\n", "\r"), "\n", $str); } $escape = '='; $output = ''; foreach (explode("\n", $str) as $line) { $length = strlen($line); $temp = ''; // Loop through each character in the line to add soft-wrap // characters at the end of a line " =\r\n" and add the newly // processed line(s) to the output (see comment on $crlf class property) for ($i = 0; $i < $length; $i++) { // Grab the next character $char = $line[$i]; $ascii = ord($char); // Convert spaces and tabs but only if it's the end of the line if ($ascii === 32 or $ascii === 9) { if ($i === $length - 1) { $char = $escape . sprintf('%02s', dechex($ascii)); } } elseif ($ascii === 61) { $char = $escape . strtoupper(sprintf('%02s', dechex($ascii))); // =3D } elseif (!in_array($ascii, $ascii_safe_chars, TRUE)) { $char = $escape . strtoupper(sprintf('%02s', dechex($ascii))); } // If we're at the character limit, add the line to the output, // reset our temp variable, and keep on chuggin' if (strlen($temp) + strlen($char) >= 76) { $output .= $temp . $escape . $this->crlf; $temp = ''; } // Add the character to our temporary line $temp .= $char; } // Add our completed line to the output $output .= $temp . $this->crlf; } // get rid of extra CRLF tacked onto the end return substr($output, 0, strlen($this->crlf) * -1); }
function qp_encode($text) { if (function_exists('quoted_printable_encode')) { return quoted_printable_encode($text); } elseif (function_exists('imap_8bit')) { return imap_8bit($text); } else { $arrEncodeSupport = mb_list_encodings(); if (array_search('Quoted-Printable', $arrEncodeSupport) != FALSE) { return mb_convert_encoding($text, 'Quoted-Printable', "JIS"); } else { $crlf = "\r\n"; $text = trim($text); $lines = preg_split("/(\r\n|\n|\r)/s", $text); $out = ''; $temp = ''; foreach ($lines as $line) { for ($j = 0; $j < strlen($line); $j++) { $char = substr($line, $j, 1); $ascii = ord($char); if ($ascii < 32 || $ascii == 61 || $ascii > 126) { $char = '=' . strtoupper(dechex($ascii)); } if (strlen($temp) + strlen($char) >= 76) { $out .= $temp . '=' . $crlf; $temp = ''; } $temp .= $char; } } $out .= $temp; return trim($out); } } }
/** * validate and shape an email address. * * @param string email address (in either "name <account@domain>", "account@domain", "name <account@[ip address]>" or "account@[ip address]" format * @param string header type to add address to (To, Cc, Bcc) */ private function address($email, $type = 'To') { //! check if it's a valid email address if (preg_match("/(.*?)?[\\<]?(([^\\<]+)\\@((\\[?)[a-zA-Z0-9\\-\\.\\:\\_]+([a-zA-Z]+|[0-9]{1,3})(\\]?)))[\\>]?\$/", $email, $m)) { //! only localhost allowed not to contain dot if (strpos($m[4], '.') === false && $m[4] != 'localhost') { throw new EmailException(L('invalid email address') . ': ' . $email); } //! remove if it's already exists in headers to avoid duplications foreach (['To', 'Cc', 'Bcc'] as $rcpt) { if (!empty($this->header[$rcpt][$m[2]])) { unset($this->header[$rcpt][$m[2]]); } } //! add to headers $this->header[$type][$m[2]] = '=?utf-8?Q?' . quoted_printable_encode(str_replace("\r", '', str_replace("\n", ' ', str_replace('@', ' AT ', !empty($m[1]) ? trim($m[1]) : $m[3])))) . '?= <' . $m[2] . '>'; return true; } throw new EmailException(L('invalid email address') . ': ' . $email); }
/** * Encodes a string in the given encoding. * * @param string $string string to encode * @param string $encoding the charset * @return string encoded string */ protected static function encode_string($string, $encoding, $newline = null) { $newline or $newline = \Config::get('email.defaults.newline', "\n"); switch ($encoding) { case 'quoted-printable': return quoted_printable_encode($string); case '7bit': case '8bit': return static::prep_newlines(rtrim($string, $newline), $newline); case 'base64': return chunk_split(base64_encode($string), 76, $newline); default: throw new \InvalidEmailStringEncoding($encoding . ' is not a supported encoding method.'); } }
/** * Transmit message * @return bool * @param $message string * @param $log bool * @param $mock bool **/ function send($message, $log = TRUE, $mock = FALSE) { if ($this->scheme == 'ssl' && !extension_loaded('openssl')) { return FALSE; } // Message should not be blank if (!$message) { user_error(self::E_Blank, E_USER_ERROR); } $fw = Base::instance(); // Retrieve headers $headers = $this->headers; // Connect to the server if (!$mock) { $socket =& $this->socket; $socket = @fsockopen($this->host, $this->port, $errno, $errstr); if (!$socket) { $fw->error(500, $errstr); return FALSE; } stream_set_blocking($socket, TRUE); } // Get server's initial response $this->dialog(NULL, TRUE, $mock); // Announce presence $reply = $this->dialog('EHLO ' . $fw->get('HOST'), $log, $mock); if (strtolower($this->scheme) == 'tls') { $this->dialog('STARTTLS', $log, $mock); if (!$mock) { stream_socket_enable_crypto($socket, TRUE, STREAM_CRYPTO_METHOD_TLS_CLIENT); } $reply = $this->dialog('EHLO ' . $fw->get('HOST'), $log, $mock); } if (preg_match('/8BITMIME/', $reply)) { $headers['Content-Transfer-Encoding'] = '8bit'; } else { $headers['Content-Transfer-Encoding'] = 'quoted-printable'; $message = preg_replace('/^\\.(.+)/m', '..$1', quoted_printable_encode($message)); } if ($this->user && $this->pw && preg_match('/AUTH/', $reply)) { // Authenticate $this->dialog('AUTH LOGIN', $log, $mock); $this->dialog(base64_encode($this->user), $log, $mock); $auth_rply = $this->dialog(base64_encode($this->pw), $log, $mock); if (!preg_match('/^235\\s.*/', $auth_rply)) { $this->dialog('QUIT', $log, $mock); if (!$mock && $socket) { fclose($socket); } return FALSE; } } if (empty($headers['Message-ID'])) { $headers['Message-ID'] = '<' . uniqid('', TRUE) . '@' . $this->host . '>'; } if (empty($headers['Date'])) { $headers['Date'] = date('r'); } // Required headers $reqd = ['From', 'To', 'Subject']; foreach ($reqd as $id) { if (empty($headers[$id])) { user_error(sprintf(self::E_Header, $id), E_USER_ERROR); } } $eol = "\r\n"; $str = ''; // Stringify headers foreach ($headers as $key => &$val) { if (!in_array($key, $reqd) && (!$this->attachments || $key != 'Content-Type' && $key != 'Content-Transfer-Encoding')) { $str .= $key . ': ' . $val . $eol; } if (in_array($key, ['From', 'To', 'Cc', 'Bcc'])) { $email = ''; preg_match_all('/(?:".+?" )?(?:<.+?>|[^ ,]+)/', $val, $matches, PREG_SET_ORDER); foreach ($matches as $raw) { $email .= ($email ? ', ' : '') . (preg_match('/<.+?>/', $raw[0]) ? $raw[0] : '<' . $raw[0] . '>'); } $val = $email; } unset($val); } // Start message dialog $this->dialog('MAIL FROM: ' . strstr($headers['From'], '<'), $log, $mock); foreach ($fw->split($headers['To'] . (isset($headers['Cc']) ? ';' . $headers['Cc'] : '') . (isset($headers['Bcc']) ? ';' . $headers['Bcc'] : '')) as $dst) { $this->dialog('RCPT TO: ' . strstr($dst, '<'), $log, $mock); } $this->dialog('DATA', $log, $mock); if ($this->attachments) { // Replace Content-Type $type = $headers['Content-Type']; unset($headers['Content-Type']); $enc = $headers['Content-Transfer-Encoding']; unset($headers['Content-Transfer-Encoding']); $hash = uniqid(NULL, TRUE); // Send mail headers $out = 'Content-Type: multipart/mixed; boundary="' . $hash . '"' . $eol; foreach ($headers as $key => $val) { if ($key != 'Bcc') { $out .= $key . ': ' . $val . $eol; } } $out .= $eol; $out .= 'This is a multi-part message in MIME format' . $eol; $out .= $eol; $out .= '--' . $hash . $eol; $out .= 'Content-Type: ' . $type . $eol; $out .= 'Content-Transfer-Encoding: ' . $enc . $eol; $out .= $str . $eol; $out .= $message . $eol; foreach ($this->attachments as $attachment) { if (is_array($attachment['filename'])) { list($alias, $file) = each($attachment['filename']); } else { $alias = basename($file = $attachment['filename']); } $out .= '--' . $hash . $eol; $out .= 'Content-Type: application/octet-stream' . $eol; $out .= 'Content-Transfer-Encoding: base64' . $eol; if ($attachment['cid']) { $out .= 'Content-ID: ' . $attachment['cid'] . $eol; } $out .= 'Content-Disposition: attachment; ' . 'filename="' . $alias . '"' . $eol; $out .= $eol; $out .= chunk_split(base64_encode(file_get_contents($file))) . $eol; } $out .= $eol; $out .= '--' . $hash . '--' . $eol; $out .= '.'; $this->dialog($out, TRUE, $mock); } else { // Send mail headers $out = ''; foreach ($headers as $key => $val) { if ($key != 'Bcc') { $out .= $key . ': ' . $val . $eol; } } $out .= $eol; $out .= $message . $eol; $out .= '.'; // Send message $this->dialog($out, TRUE, $mock); } $this->dialog('QUIT', $log, $mock); if (!$mock && $socket) { fclose($socket); } return TRUE; }