See Release Notes
Long Term Support Release
<?php /** * Copyright 1997-2017 Horde LLC (http://www.horde.org/) * Copyright (c) 2002-2007, Richard Heyes * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * o Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * o Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * o The names of the authors may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @category Horde * @copyright 1997-2017 Horde LLC (http://www.horde.org/) * @copyright 2002-2007 Richard Heyes * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail */ /** * Mail transport base class. * * @author Chuck Hagenbuch <chuck@horde.org> * @author Richard Heyes <richard@phpguru.org> * @author Michael Slusarz <slusarz@horde.org> * @category Horde * @copyright 1997-2017 Horde LLC (http://www.horde.org/) * @copyright 2002-2007 Richard Heyes * @license http://www.horde.org/licenses/bsd New BSD License * @package Mail * * @property-read boolean $eai Does the transport driver support EAI (RFC * 6532) headers? (@since 2.5.0) */ abstract class Horde_Mail_Transport { /** * Line terminator used for separating header lines. * * @var string */ public $sep = PHP_EOL; /** * Configuration parameters. * * @var array */ protected $_params = array(); /** */ public function __get($name) { switch ($name) { case 'eai': return false; } } /** * Send a message. * * @param mixed $recipients Either a comma-seperated list of recipients * (RFC822 compliant), or an array of * recipients, each RFC822 valid. This may * contain recipients not specified in the * headers, for Bcc:, resending messages, etc. * @param array $headers The headers to send with the mail, in an * associative array, where the array key is the * header name (ie, 'Subject'), and the array * value is the header value (ie, 'test'). The * header produced from those values would be * 'Subject: test'. * If the '_raw' key exists, the value of this * key will be used as the exact text for * sending the message. * @param mixed $body The full text of the message body, including * any Mime parts, etc. Either a string or a * stream resource. * * @throws Horde_Mail_Exception */ abstract public function send($recipients, array $headers, $body); /** * Take an array of mail headers and return a string containing text * usable in sending a message. * * @param array $headers The array of headers to prepare, in an * associative array, where the array key is the * header name (ie, 'Subject'), and the array value * is the header value (ie, 'test'). The header * produced from those values would be 'Subject: * test'. * If the '_raw' key exists, the value of this key * will be used as the exact text for sending the * message. * * @return mixed Returns false if it encounters a bad address; otherwise * returns an array containing two elements: Any From: * address found in the headers, and the plain text version * of the headers. * @throws Horde_Mail_Exception */ public function prepareHeaders(array $headers) { $from = null; $lines = array(); $raw = isset($headers['_raw']) ? $headers['_raw'] : null; foreach ($headers as $key => $value) { if (strcasecmp($key, 'From') === 0) { $parser = new Horde_Mail_Rfc822(); $addresses = $parser->parseAddressList($value, array( 'validate' => $this->eai ? 'eai' : true )); $from = $addresses[0]->bare_address; // Reject envelope From: addresses with spaces. if (strstr($from, ' ')) { return false; } $lines[] = $key . ': ' . $this->_normalizeEOL($value); } elseif (!$raw && (strcasecmp($key, 'Received') === 0)) { $received = array(); if (!is_array($value)) { $value = array($value); } foreach ($value as $line) { $received[] = $key . ': ' . $this->_normalizeEOL($line); } // Put Received: headers at the top. Spam detectors often // flag messages with Received: headers after the Subject: // as spam. $lines = array_merge($received, $lines); } elseif (!$raw) { // If $value is an array (i.e., a list of addresses), convert // it to a comma-delimited string of its elements (addresses). if (is_array($value)) { $value = implode(', ', $value); } $lines[] = $key . ': ' . $this->_normalizeEOL($value); } } return array($from, $raw ? $raw : implode($this->sep, $lines)); } /** * Take a set of recipients and parse them, returning an array of bare * addresses (forward paths) that can be passed to sendmail or an SMTP * server with the 'RCPT TO:' command. * * @param mixed $recipients Either a comma-separated list of recipients * (RFC822 compliant), or an array of * recipients, each RFC822 valid. * * @return array Forward paths (bare addresses, IDN encoded). * @throws Horde_Mail_Exception */ public function parseRecipients($recipients) { // Parse recipients, leaving out all personal info. This is // for smtp recipients, etc. All relevant personal information // should already be in the headers. $rfc822 = new Horde_Mail_Rfc822(); return $rfc822->parseAddressList($recipients, array( 'validate' => $this->eai ? 'eai' : true ))->bare_addresses_idn; } /** * Sanitize an array of mail headers by removing any additional header * strings present in a legitimate header's value. The goal of this * filter is to prevent mail injection attacks. * * Raw headers are sent as-is. * * @param array $headers The associative array of headers to sanitize. * * @return array The sanitized headers. */ protected function _sanitizeHeaders($headers) { foreach (array_diff(array_keys($headers), array('_raw')) as $key) {< $headers[$key] = preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', null, $headers[$key]);> $headers[$key] = preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i', '', $headers[$key]);} return $headers; } /** * Normalizes EOLs in string data. * * @param string $data Data. * * @return string Normalized data. */ protected function _normalizeEOL($data) { return strtr($data, array( "\r\n" => $this->sep, "\r" => $this->sep, "\n" => $this->sep )); } /** * Get the from address. * * @param string $from From address. * @param array $headers Headers array. * * @return string Address object. * @throws Horde_Mail_Exception */ protected function _getFrom($from, $headers) { /* Since few MTAs are going to allow this header to be forged unless * it's in the MAIL FROM: exchange, we'll use Return-Path instead of * From: if it's set. */ foreach (array_keys($headers) as $hdr) { if (strcasecmp($hdr, 'Return-Path') === 0) { $from = $headers[$hdr]; break; } }< if (!strlen($from)) {> if (empty($from)) {throw new Horde_Mail_Exception('No from address provided.'); } $from = new Horde_Mail_Rfc822_Address($from); return $from->bare_address_idn; } }