Skip to content
Snippets Groups Projects
Mail.php 9.68 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?php
    /**
     *  PEAR's Mail:: interface.
     *
     * PHP versions 4 and 5
     *
     * LICENSE:
     *
     * 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    Mail
     * @package     Mail
     * @author      Chuck Hagenbuch <chuck@horde.org>
     * @copyright   1997-2010 Chuck Hagenbuch
     * @license     http://opensource.org/licenses/bsd-license.php New BSD License
     * @version     CVS: $Id: Mail.php 294747 2010-02-08 08:18:33Z clockwerx $
     * @link        http://pear.php.net/package/Mail/
     */
    
    require_once 'PEAR.php';
    
    /**
     * PEAR's Mail:: interface. Defines the interface for implementing
     * mailers under the PEAR hierarchy, and provides supporting functions
     * useful in multiple mailer backends.
     *
     * @access public
     * @version $Revision: 294747 $
     * @package Mail
     */
    class Mail
    {
        /**
         * Line terminator used for separating header lines.
         * @var string
         */
        var $sep = "\r\n";
    
        /**
         * Provides an interface for generating Mail:: objects of various
         * types
         *
         * @param string $driver The kind of Mail:: object to instantiate.
         * @param array  $params The parameters to pass to the Mail:: object.
         * @return object Mail a instance of the driver class or if fails a PEAR Error
         * @access public
         */
        function &factory($driver, $params = array())
        {
            $driver = strtolower($driver);
            $class = 'Mail_' . $driver;
    
            if (!class_exists($class))
    
                include_once 'Mail/' . $driver . '.php';
    
            if (!class_exists($class))
                return PEAR::raiseError('Unable to find class for driver ' .  $driver);
    
            $mailer = new $class($params);
            return $mailer;
    
        }
    
        /**
         * Implements Mail::send() function using php's built-in mail()
         * command.
         *
         * @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 array of 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'.
         *
         * @param string $body The full text of the message body, including any
         *               Mime parts, etc.
         *
         * @return mixed Returns true on success, or a PEAR_Error
         *               containing a descriptive error message on
         *               failure.
         *
         * @access public
         * @deprecated use Mail_mail::send instead
         */
        function send($recipients, $headers, $body)
        {
            if (!is_array($headers)) {
                return PEAR::raiseError('$headers must be an array');
            }
    
            $result = $this->_sanitizeHeaders($headers);
            if (is_a($result, 'PEAR_Error')) {
                return $result;
            }
    
            // if we're passed an array of recipients, implode it.
            if (is_array($recipients)) {
                $recipients = implode(', ', $recipients);
            }
    
            // get the Subject out of the headers array so that we can
            // pass it as a seperate argument to mail().
            $subject = '';
            if (isset($headers['Subject'])) {
                $subject = $headers['Subject'];
                unset($headers['Subject']);
            }
    
            // flatten the headers out.
            list(, $text_headers) = Mail::prepareHeaders($headers);
    
            return mail($recipients, $subject, $body, $text_headers);
        }
    
        /**
         * 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.
         *
         * @param array $headers The associative array of headers to sanitize.
         *
         * @access private
         */
        function _sanitizeHeaders(&$headers)
        {
            foreach ($headers as $key => $value) {
                $headers[$key] =
                    preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i',
                                 null, $value);
            }
        }
    
        /**
         * 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'.
         *
         * @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.
         * @access private
         */
        function prepareHeaders($headers)
        {
            $lines = array();
            $from = null;
    
            foreach ($headers as $key => $value) {
                if (strcasecmp($key, 'From') === 0) {
                    include_once 'Mail/RFC822.php';
                    $parser = new Mail_RFC822();
                    $addresses = $parser->parseAddressList($value, 'localhost', false);
                    if (is_a($addresses, 'PEAR_Error')) {
                        return $addresses;
                    }
    
                    $from = $addresses[0]->mailbox . '@' . $addresses[0]->host;
    
                    // Reject envelope From: addresses with spaces.
                    if (strstr($from, ' ')) {
                        return false;
                    }
    
                    $lines[] = $key . ': ' . $value;
                } elseif (strcasecmp($key, 'Received') === 0) {
                    $received = array();
                    if (is_array($value)) {
                        foreach ($value as $line) {
                            $received[] = $key . ': ' . $line;
                        }
                    }
                    else {
                        $received[] = $key . ': ' . $value;
                    }
                    // Put Received: headers at the top.  Spam detectors often
                    // flag messages with Received: headers after the Subject:
                    // as spam.
                    $lines = array_merge($received, $lines);
                } else {
                    // 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 . ': ' . $value;
                }
            }
    
            return array($from, join($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 Either a comma-seperated list of recipients
         *              (RFC822 compliant), or an array of recipients,
         *              each RFC822 valid.
         *
         * @return mixed An array of forward paths (bare addresses) or a PEAR_Error
         *               object if the address list could not be parsed.
         * @access private
         */
        function parseRecipients($recipients)
        {
            include_once 'Mail/RFC822.php';
    
            // if we're passed an array, assume addresses are valid and
            // implode them before parsing.
            if (is_array($recipients)) {
                $recipients = implode(', ', $recipients);
            }
    
            // Parse recipients, leaving out all personal info. This is
            // for smtp recipients, etc. All relevant personal information
            // should already be in the headers.
            $addresses = Mail_RFC822::parseAddressList($recipients, 'localhost', false);
    
            // If parseAddressList() returned a PEAR_Error object, just return it.
            if (is_a($addresses, 'PEAR_Error')) {
                return $addresses;
            }
    
            $recipients = array();
            if (is_array($addresses)) {
                foreach ($addresses as $ob) {
                    $recipients[] = $ob->mailbox . '@' . $ob->host;
                }
            }
    
            return $recipients;
        }
    
    }