home *** CD-ROM | disk | FTP | other *** search
/ Cricao de Sites - 650 Layouts Prontos / WebMasters.iso / Servidores / xampp-win32-1.6.7-installer.exe / php / PEAR / Mail / mime.php < prev    next >
Encoding:
PHP Script  |  2008-07-02  |  39.3 KB  |  1,096 lines

  1. <?php
  2. /**
  3.  * The Mail_Mime class is used to create MIME E-mail messages
  4.  *
  5.  * The Mail_Mime class provides an OO interface to create MIME
  6.  * enabled email messages. This way you can create emails that
  7.  * contain plain-text bodies, HTML bodies, attachments, inline
  8.  * images and specific headers.
  9.  *
  10.  * Compatible with PHP versions 4 and 5
  11.  *
  12.  * LICENSE: This LICENSE is in the BSD license style.
  13.  * Copyright (c) 2002-2003, Richard Heyes <richard@phpguru.org>
  14.  * Copyright (c) 2003-2006, PEAR <pear-group@php.net>
  15.  * All rights reserved.
  16.  *
  17.  * Redistribution and use in source and binary forms, with or
  18.  * without modification, are permitted provided that the following
  19.  * conditions are met:
  20.  *
  21.  * - Redistributions of source code must retain the above copyright
  22.  *   notice, this list of conditions and the following disclaimer.
  23.  * - Redistributions in binary form must reproduce the above copyright
  24.  *   notice, this list of conditions and the following disclaimer in the
  25.  *   documentation and/or other materials provided with the distribution.
  26.  * - Neither the name of the authors, nor the names of its contributors 
  27.  *   may be used to endorse or promote products derived from this 
  28.  *   software without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  31.  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  34.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  35.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  36.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  37.  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  38.  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  39.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
  40.  * THE POSSIBILITY OF SUCH DAMAGE.
  41.  *
  42.  * @category  Mail
  43.  * @package   Mail_Mime
  44.  * @author    Richard Heyes  <richard@phpguru.org>
  45.  * @author    Tomas V.V. Cox <cox@idecnet.com>
  46.  * @author    Cipriano Groenendal <cipri@php.net>
  47.  * @author    Sean Coates <sean@php.net>
  48.  * @copyright 2003-2006 PEAR <pear-group@php.net>
  49.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
  50.  * @version   CVS: $Id: mime.php,v 1.81 2007/06/21 19:08:28 cipri Exp $
  51.  * @link      http://pear.php.net/package/Mail_mime
  52.  *
  53.  *            This class is based on HTML Mime Mail class from
  54.  *            Richard Heyes <richard@phpguru.org> which was based also
  55.  *            in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it>
  56.  *            and Sascha Schumann <sascha@schumann.cx>
  57.  */
  58.  
  59.  
  60. /**
  61.  * require PEAR
  62.  *
  63.  * This package depends on PEAR to raise errors.
  64.  */
  65. require_once 'PEAR.php';
  66.  
  67. /**
  68.  * require Mail_mimePart
  69.  *
  70.  * Mail_mimePart contains the code required to
  71.  * create all the different parts a mail can
  72.  * consist of.
  73.  */
  74. require_once 'Mail/mimePart.php';
  75.  
  76.  
  77. /**
  78.  * The Mail_Mime class provides an OO interface to create MIME
  79.  * enabled email messages. This way you can create emails that
  80.  * contain plain-text bodies, HTML bodies, attachments, inline
  81.  * images and specific headers.
  82.  *
  83.  * @category  Mail
  84.  * @package   Mail_Mime
  85.  * @author    Richard Heyes  <richard@phpguru.org>
  86.  * @author    Tomas V.V. Cox <cox@idecnet.com>
  87.  * @author    Cipriano Groenendal <cipri@php.net>
  88.  * @author    Sean Coates <sean@php.net>
  89.  * @copyright 2003-2006 PEAR <pear-group@php.net>
  90.  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
  91.  * @version   Release: @package_version@
  92.  * @link      http://pear.php.net/package/Mail_mime
  93.  */
  94. class Mail_mime
  95. {
  96.     /**
  97.      * Contains the plain text part of the email
  98.      *
  99.      * @var string
  100.      * @access private
  101.      */
  102.     var $_txtbody;
  103.  
  104.     /**
  105.      * Contains the html part of the email
  106.      *
  107.      * @var string
  108.      * @access private
  109.      */
  110.     var $_htmlbody;
  111.  
  112.     /**
  113.      * contains the mime encoded text
  114.      *
  115.      * @var string
  116.      * @access private
  117.      */
  118.     var $_mime;
  119.  
  120.     /**
  121.      * contains the multipart content
  122.      *
  123.      * @var string
  124.      * @access private
  125.      */
  126.     var $_multipart;
  127.  
  128.     /**
  129.      * list of the attached images
  130.      *
  131.      * @var array
  132.      * @access private
  133.      */
  134.     var $_html_images = array();
  135.  
  136.     /**
  137.      * list of the attachements
  138.      *
  139.      * @var array
  140.      * @access private
  141.      */
  142.     var $_parts = array();
  143.  
  144.     /**
  145.      * Build parameters
  146.      *
  147.      * @var array
  148.      * @access private
  149.      */
  150.     var $_build_params = array();
  151.  
  152.     /**
  153.      * Headers for the mail
  154.      *
  155.      * @var array
  156.      * @access private
  157.      */
  158.     var $_headers = array();
  159.  
  160.     /**
  161.      * End Of Line sequence (for serialize)
  162.      *
  163.      * @var string
  164.      * @access private
  165.      */
  166.     var $_eol;
  167.  
  168.  
  169.     /**
  170.      * Constructor function.
  171.      *
  172.      * @param string $crlf what type of linebreak to use.
  173.      *                     Defaults to "\r\n"
  174.      *
  175.      * @return void
  176.      *
  177.      * @access public
  178.      */
  179.     function Mail_mime($crlf = "\r\n")
  180.     {
  181.         $this->_setEOL($crlf);
  182.         $this->_build_params = array(
  183.                                      'head_encoding' => 'quoted-printable',
  184.                                      'text_encoding' => '7bit',
  185.                                      'html_encoding' => 'quoted-printable',
  186.                                      '7bit_wrap'     => 998,
  187.                                      'html_charset'  => 'ISO-8859-1',
  188.                                      'text_charset'  => 'ISO-8859-1',
  189.                                      'head_charset'  => 'ISO-8859-1'
  190.                                     );
  191.     }
  192.  
  193.     /**
  194.      * wakeup function called by unserialize. It re-sets the EOL constant
  195.      *
  196.      * @access private
  197.      * @return void
  198.      */
  199.     function __wakeup()
  200.     {
  201.         $this->_setEOL($this->_eol);
  202.     }
  203.  
  204.  
  205.     /**
  206.      * Accessor function to set the body text. Body text is used if
  207.      * it's not an html mail being sent or else is used to fill the
  208.      * text/plain part that emails clients who don't support
  209.      * html should show.
  210.      *
  211.      * @param string $data   Either a string or
  212.      *                        the file name with the contents
  213.      * @param bool   $isfile If true the first param should be treated
  214.      *                        as a file name, else as a string (default)
  215.      * @param bool   $append If true the text or file is appended to
  216.      *                        the existing body, else the old body is
  217.      *                        overwritten
  218.      *
  219.      * @return mixed   true on success or PEAR_Error object
  220.      * @access public
  221.      */
  222.     function setTXTBody($data, $isfile = false, $append = false)
  223.     {
  224.         if (!$isfile) {
  225.             if (!$append) {
  226.                 $this->_txtbody = $data;
  227.             } else {
  228.                 $this->_txtbody .= $data;
  229.             }
  230.         } else {
  231.             $cont = $this->_file2str($data);
  232.             if (PEAR::isError($cont)) {
  233.                 return $cont;
  234.             }
  235.             if (!$append) {
  236.                 $this->_txtbody = $cont;
  237.             } else {
  238.                 $this->_txtbody .= $cont;
  239.             }
  240.         }
  241.         return true;
  242.     }
  243.  
  244.     /**
  245.      * Adds a html part to the mail.
  246.      *
  247.      * @param string $data   either a string or the file name with the
  248.      *                        contents
  249.      * @param bool   $isfile a flag that determines whether $data is a
  250.      *                        filename, or a string(false, default)
  251.      *
  252.      * @return bool    true on success
  253.      * @access public
  254.      */
  255.     function setHTMLBody($data, $isfile = false)
  256.     {
  257.         if (!$isfile) {
  258.             $this->_htmlbody = $data;
  259.         } else {
  260.             $cont = $this->_file2str($data);
  261.             if (PEAR::isError($cont)) {
  262.                 return $cont;
  263.             }
  264.             $this->_htmlbody = $cont;
  265.         }
  266.  
  267.         return true;
  268.     }
  269.  
  270.     /**
  271.      * Adds an image to the list of embedded images.
  272.      *
  273.      * @param string $file   the image file name OR image data itself
  274.      * @param string $c_type the content type
  275.      * @param string $name   the filename of the image.
  276.      *                        Only used if $file is the image data.
  277.      * @param bool   $isfile whether $file is a filename or not.
  278.      *                        Defaults to true
  279.      *
  280.      * @return bool          true on success
  281.      * @access public
  282.      */
  283.     function addHTMLImage($file, $c_type='application/octet-stream',
  284.                           $name = '', $isfile = true)
  285.     {
  286.         $filedata = ($isfile === true) ? $this->_file2str($file)
  287.                                            : $file;
  288.         if ($isfile === true) {
  289.             $filename = ($name == '' ? $file : $name);
  290.         } else {
  291.             $filename = $name;
  292.         }
  293.         if (PEAR::isError($filedata)) {
  294.             return $filedata;
  295.         }
  296.         $this->_html_images[] = array(
  297.                                       'body'   => $filedata,
  298.                                       'name'   => $filename,
  299.                                       'c_type' => $c_type,
  300.                                       'cid'    => md5(uniqid(time()))
  301.                                      );
  302.         return true;
  303.     }
  304.  
  305.     /**
  306.      * Adds a file to the list of attachments.
  307.      *
  308.      * @param string $file        The file name of the file to attach
  309.      *                             OR the file contents itself
  310.      * @param string $c_type      The content type
  311.      * @param string $name        The filename of the attachment
  312.      *                             Only use if $file is the contents
  313.      * @param bool   $isfile      Whether $file is a filename or not
  314.      *                             Defaults to true
  315.      * @param string $encoding    The type of encoding to use.
  316.      *                             Defaults to base64.
  317.      *                             Possible values: 7bit, 8bit, base64, 
  318.      *                             or quoted-printable.
  319.      * @param string $disposition The content-disposition of this file
  320.      *                             Defaults to attachment.
  321.      *                             Possible values: attachment, inline.
  322.      * @param string $charset     The character set used in the filename
  323.      *                             of this attachment.
  324.      * @param string $language    The language of the attachment
  325.      * @param string $location    The RFC 2557.4 location of the attachment
  326.      *
  327.      * @return mixed true on success or PEAR_Error object
  328.      * @access public
  329.      */
  330.     function addAttachment($file,
  331.                            $c_type      = 'application/octet-stream',
  332.                            $name        = '',
  333.                             $isfile     = true,
  334.                            $encoding    = 'base64',
  335.                            $disposition = 'attachment',
  336.                            $charset     = '',
  337.                             $language   = '',
  338.                            $location    = '')
  339.     {
  340.         $filedata = ($isfile === true) ? $this->_file2str($file)
  341.                                            : $file;
  342.         if ($isfile === true) {
  343.             // Force the name the user supplied, otherwise use $file
  344.             $filename = (strlen($name)) ? $name : $file;
  345.         } else {
  346.             $filename = $name;
  347.         }
  348.         if (!strlen($filename)) {
  349.             $msg = "The supplied filename for the attachment can't be empty";
  350.             $err = PEAR::raiseError($msg);
  351.             return $err;
  352.         }
  353.         $filename = basename($filename);
  354.         if (PEAR::isError($filedata)) {
  355.             return $filedata;
  356.         }
  357.  
  358.         $this->_parts[] = array(
  359.                                 'body'        => $filedata,
  360.                                 'name'        => $filename,
  361.                                 'c_type'      => $c_type,
  362.                                 'encoding'    => $encoding,
  363.                                 'charset'     => $charset,
  364.                                 'language'    => $language,
  365.                                 'location'    => $location,
  366.                                 'disposition' => $disposition
  367.                                );
  368.         return true;
  369.     }
  370.  
  371.     /**
  372.      * Get the contents of the given file name as string
  373.      *
  374.      * @param string $file_name path of file to process
  375.      *
  376.      * @return string  contents of $file_name
  377.      * @access private
  378.      */
  379.     function &_file2str($file_name)
  380.     {
  381.         if (!is_readable($file_name)) {
  382.             $err = PEAR::raiseError('File is not readable ' . $file_name);
  383.             return $err;
  384.         }
  385.         if (!$fd = fopen($file_name, 'rb')) {
  386.             $err = PEAR::raiseError('Could not open ' . $file_name);
  387.             return $err;
  388.         }
  389.         $filesize = filesize($file_name);
  390.         if ($filesize == 0) {
  391.             $cont =  "";
  392.         } else {
  393.             if ($magic_quote_setting = get_magic_quotes_runtime()) {
  394.                 set_magic_quotes_runtime(0);
  395.             }
  396.             $cont = fread($fd, $filesize);
  397.             if ($magic_quote_setting) {
  398.                 set_magic_quotes_runtime($magic_quote_setting);
  399.             }
  400.         }
  401.         fclose($fd);
  402.         return $cont;
  403.     }
  404.  
  405.     /**
  406.      * Adds a text subpart to the mimePart object and
  407.      * returns it during the build process.
  408.      *
  409.      * @param mixed  &$obj The object to add the part to, or
  410.      *                      null if a new object is to be created.
  411.      * @param string $text The text to add.
  412.      *
  413.      * @return object  The text mimePart object
  414.      * @access private
  415.      */
  416.     function &_addTextPart(&$obj, $text)
  417.     {
  418.         $params['content_type'] = 'text/plain';
  419.         $params['encoding']     = $this->_build_params['text_encoding'];
  420.         $params['charset']      = $this->_build_params['text_charset'];
  421.         if (is_object($obj)) {
  422.             $ret = $obj->addSubpart($text, $params);
  423.             return $ret;
  424.         } else {
  425.             $ret = new Mail_mimePart($text, $params);
  426.             return $ret;
  427.         }
  428.     }
  429.  
  430.     /**
  431.      * Adds a html subpart to the mimePart object and
  432.      * returns it during the build process.
  433.      *
  434.      * @param mixed &$obj The object to add the part to, or
  435.      *                     null if a new object is to be created.
  436.      *
  437.      * @return object The html mimePart object
  438.      * @access private
  439.      */
  440.     function &_addHtmlPart(&$obj)
  441.     {
  442.         $params['content_type'] = 'text/html';
  443.         $params['encoding']     = $this->_build_params['html_encoding'];
  444.         $params['charset']      = $this->_build_params['html_charset'];
  445.         if (is_object($obj)) {
  446.             $ret = $obj->addSubpart($this->_htmlbody, $params);
  447.             return $ret;
  448.         } else {
  449.             $ret = new Mail_mimePart($this->_htmlbody, $params);
  450.             return $ret;
  451.         }
  452.     }
  453.  
  454.     /**
  455.      * Creates a new mimePart object, using multipart/mixed as
  456.      * the initial content-type and returns it during the
  457.      * build process.
  458.      *
  459.      * @return object The multipart/mixed mimePart object
  460.      * @access private
  461.      */
  462.     function &_addMixedPart()
  463.     {
  464.         $params                 = array();
  465.         $params['content_type'] = 'multipart/mixed';
  466.         
  467.         //Create empty multipart/mixed Mail_mimePart object to return
  468.         $ret = new Mail_mimePart('', $params);
  469.         return $ret;
  470.     }
  471.  
  472.     /**
  473.      * Adds a multipart/alternative part to a mimePart
  474.      * object (or creates one), and returns it during
  475.      * the build process.
  476.      *
  477.      * @param mixed &$obj The object to add the part to, or
  478.      *                     null if a new object is to be created.
  479.      *
  480.      * @return object  The multipart/mixed mimePart object
  481.      * @access private
  482.      */
  483.     function &_addAlternativePart(&$obj)
  484.     {
  485.         $params['content_type'] = 'multipart/alternative';
  486.         if (is_object($obj)) {
  487.             return $obj->addSubpart('', $params);
  488.         } else {
  489.             $ret = new Mail_mimePart('', $params);
  490.             return $ret;
  491.         }
  492.     }
  493.  
  494.     /**
  495.      * Adds a multipart/related part to a mimePart
  496.      * object (or creates one), and returns it during
  497.      * the build process.
  498.      *
  499.      * @param mixed &$obj The object to add the part to, or
  500.      *                     null if a new object is to be created
  501.      *
  502.      * @return object  The multipart/mixed mimePart object
  503.      * @access private
  504.      */
  505.     function &_addRelatedPart(&$obj)
  506.     {
  507.         $params['content_type'] = 'multipart/related';
  508.         if (is_object($obj)) {
  509.             return $obj->addSubpart('', $params);
  510.         } else {
  511.             $ret = new Mail_mimePart('', $params);
  512.             return $ret;
  513.         }
  514.     }
  515.  
  516.     /**
  517.      * Adds an html image subpart to a mimePart object
  518.      * and returns it during the build process.
  519.      *
  520.      * @param object &$obj  The mimePart to add the image to
  521.      * @param array  $value The image information
  522.      *
  523.      * @return object  The image mimePart object
  524.      * @access private
  525.      */
  526.     function &_addHtmlImagePart(&$obj, $value)
  527.     {
  528.         $params['content_type'] = $value['c_type'];
  529.         $params['encoding']     = 'base64';
  530.         $params['disposition']  = 'inline';
  531.         $params['dfilename']    = $value['name'];
  532.         $params['cid']          = $value['cid'];
  533.         
  534.         $ret = $obj->addSubpart($value['body'], $params);
  535.         return $ret;
  536.     
  537.     }
  538.  
  539.     /**
  540.      * Adds an attachment subpart to a mimePart object
  541.      * and returns it during the build process.
  542.      *
  543.      * @param object &$obj  The mimePart to add the image to
  544.      * @param array  $value The attachment information
  545.      *
  546.      * @return object  The image mimePart object
  547.      * @access private
  548.      */
  549.     function &_addAttachmentPart(&$obj, $value)
  550.     {
  551.         $params['dfilename'] = $value['name'];
  552.         $params['encoding']  = $value['encoding'];
  553.         if ($value['charset']) {
  554.             $params['charset'] = $value['charset'];
  555.         }
  556.         if ($value['language']) {
  557.             $params['language'] = $value['language'];
  558.         }
  559.         if ($value['location']) {
  560.             $params['location'] = $value['location'];
  561.         }
  562.         $params['content_type'] = $value['c_type'];
  563.         $params['disposition']  = isset($value['disposition']) ? 
  564.                                   $value['disposition'] : 'attachment';
  565.         $ret = $obj->addSubpart($value['body'], $params);
  566.         return $ret;
  567.     }
  568.  
  569.     /**
  570.      * Returns the complete e-mail, ready to send using an alternative
  571.      * mail delivery method. Note that only the mailpart that is made
  572.      * with Mail_Mime is created. This means that,
  573.      * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF 
  574.      * using the $xtra_headers parameter!
  575.      * 
  576.      * @param string $separation   The separation etween these two parts.
  577.      * @param array  $build_params The Build parameters passed to the
  578.      *                             &get() function. See &get for more info.
  579.      * @param array  $xtra_headers The extra headers that should be passed
  580.      *                             to the &headers() function.
  581.      *                             See that function for more info.
  582.      * @param bool   $overwrite    Overwrite the existing headers with new.
  583.      *
  584.      * @return string The complete e-mail.
  585.      * @access public
  586.      */
  587.     function getMessage(
  588.                         $separation   = null, 
  589.                         $build_params = null, 
  590.                         $xtra_headers = null, 
  591.                         $overwrite    = false
  592.                        )
  593.     {
  594.         if ($separation === null) {
  595.             $separation = MAIL_MIME_CRLF;
  596.         }
  597.         $body = $this->get($build_params);
  598.         $head = $this->txtHeaders($xtra_headers, $overwrite);
  599.         $mail = $head . $separation . $body;
  600.         return $mail;
  601.     }
  602.  
  603.  
  604.     /**
  605.      * Builds the multipart message from the list ($this->_parts) and
  606.      * returns the mime content.
  607.      *
  608.      * @param array $build_params Build parameters that change the way the email
  609.      *                             is built. Should be associative. Can contain:
  610.      *                head_encoding  -  What encoding to use for the headers. 
  611.      *                                  Options: quoted-printable or base64
  612.      *                                  Default is quoted-printable
  613.      *                text_encoding  -  What encoding to use for plain text
  614.      *                                  Options: 7bit, 8bit,
  615.      *                                  base64, or quoted-printable
  616.      *                                  Default is 7bit
  617.      *                html_encoding  -  What encoding to use for html
  618.      *                                  Options: 7bit, 8bit,
  619.      *                                  base64, or quoted-printable
  620.      *                                  Default is quoted-printable
  621.      *                7bit_wrap      -  Number of characters before text is
  622.      *                                  wrapped in 7bit encoding
  623.      *                                  Default is 998
  624.      *                html_charset   -  The character set to use for html.
  625.      *                                  Default is iso-8859-1
  626.      *                text_charset   -  The character set to use for text.
  627.      *                                  Default is iso-8859-1
  628.      *                head_charset   -  The character set to use for headers.
  629.      *                                  Default is iso-8859-1
  630.      *
  631.      * @return string The mime content
  632.      * @access public
  633.      */
  634.     function &get($build_params = null)
  635.     {
  636.         if (isset($build_params)) {
  637.             while (list($key, $value) = each($build_params)) {
  638.                 $this->_build_params[$key] = $value;
  639.             }
  640.         }
  641.         
  642.         if (isset($this->_headers['From'])){
  643.             $domain = @strstr($this->_headers['From'],'@');
  644.             //Bug #11381: Illegal characters in domain ID
  645.             $domain = str_replace(array("<", ">", "&", "(", ")", " ", "\"", "'"), "", $domain);
  646.             $domain = urlencode($domain);
  647.             foreach($this->_html_images as $i => $img){
  648.                 $this->_html_images[$i]['cid'] = $this->_html_images[$i]['cid'] . $domain;
  649.             }
  650.         }
  651.         
  652.         if (count($this->_html_images) AND isset($this->_htmlbody)) {
  653.             foreach ($this->_html_images as $key => $value) {
  654.                 $regex   = array();
  655.                 $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' .
  656.                             preg_quote($value['name'], '#') . '\3#';
  657.                 $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' .
  658.                             preg_quote($value['name'], '#') . '\1\s*\)#';
  659.  
  660.                 $rep   = array();
  661.                 $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3';
  662.                 $rep[] = 'url(\1cid:' . $value['cid'] . '\2)';
  663.  
  664.                 $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody);
  665.                 $this->_html_images[$key]['name'] = 
  666.                     basename($this->_html_images[$key]['name']);
  667.             }
  668.         }
  669.  
  670.         $null        = null;
  671.         $attachments = count($this->_parts)                 ? true : false;
  672.         $html_images = count($this->_html_images)           ? true : false;
  673.         $html        = strlen($this->_htmlbody)             ? true : false;
  674.         $text        = (!$html AND strlen($this->_txtbody)) ? true : false;
  675.  
  676.         switch (true) {
  677.         case $text AND !$attachments:
  678.             $message =& $this->_addTextPart($null, $this->_txtbody);
  679.             break;
  680.  
  681.         case !$text AND !$html AND $attachments:
  682.             $message =& $this->_addMixedPart();
  683.             for ($i = 0; $i < count($this->_parts); $i++) {
  684.                 $this->_addAttachmentPart($message, $this->_parts[$i]);
  685.             }
  686.             break;
  687.  
  688.         case $text AND $attachments:
  689.             $message =& $this->_addMixedPart();
  690.             $this->_addTextPart($message, $this->_txtbody);
  691.             for ($i = 0; $i < count($this->_parts); $i++) {
  692.                 $this->_addAttachmentPart($message, $this->_parts[$i]);
  693.             }
  694.             break;
  695.  
  696.         case $html AND !$attachments AND !$html_images:
  697.             if (isset($this->_txtbody)) {
  698.                 $message =& $this->_addAlternativePart($null);
  699.                 $this->_addTextPart($message, $this->_txtbody);
  700.                 $this->_addHtmlPart($message);
  701.             } else {
  702.                 $message =& $this->_addHtmlPart($null);
  703.             }
  704.             break;
  705.  
  706.         case $html AND !$attachments AND $html_images:
  707.             $message =& $this->_addRelatedPart($null);
  708.             if (isset($this->_txtbody)) {
  709.                 $alt =& $this->_addAlternativePart($message);
  710.                 $this->_addTextPart($alt, $this->_txtbody);
  711.                 $this->_addHtmlPart($alt);
  712.             } else {
  713.                 $this->_addHtmlPart($message);
  714.             }
  715.             for ($i = 0; $i < count($this->_html_images); $i++) {
  716.                 $this->_addHtmlImagePart($message, $this->_html_images[$i]);
  717.             }
  718.             break;
  719.  
  720.         case $html AND $attachments AND !$html_images:
  721.             $message =& $this->_addMixedPart();
  722.             if (isset($this->_txtbody)) {
  723.                 $alt =& $this->_addAlternativePart($message);
  724.                 $this->_addTextPart($alt, $this->_txtbody);
  725.                 $this->_addHtmlPart($alt);
  726.             } else {
  727.                 $this->_addHtmlPart($message);
  728.             }
  729.             for ($i = 0; $i < count($this->_parts); $i++) {
  730.                 $this->_addAttachmentPart($message, $this->_parts[$i]);
  731.             }
  732.             break;
  733.  
  734.         case $html AND $attachments AND $html_images:
  735.             $message =& $this->_addMixedPart();
  736.             if (isset($this->_txtbody)) {
  737.                 $alt =& $this->_addAlternativePart($message);
  738.                 $this->_addTextPart($alt, $this->_txtbody);
  739.                 $rel =& $this->_addRelatedPart($alt);
  740.             } else {
  741.                 $rel =& $this->_addRelatedPart($message);
  742.             }
  743.             $this->_addHtmlPart($rel);
  744.             for ($i = 0; $i < count($this->_html_images); $i++) {
  745.                 $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
  746.             }
  747.             for ($i = 0; $i < count($this->_parts); $i++) {
  748.                 $this->_addAttachmentPart($message, $this->_parts[$i]);
  749.             }
  750.             break;
  751.  
  752.         }
  753.  
  754.         if (isset($message)) {
  755.             $output = $message->encode();
  756.             
  757.             $this->_headers = array_merge($this->_headers,
  758.                                           $output['headers']);
  759.             $body = $output['body'];
  760.             return $body;
  761.  
  762.         } else {
  763.             $ret = false;
  764.             return $ret;
  765.         }
  766.     }
  767.  
  768.     /**
  769.      * Returns an array with the headers needed to prepend to the email
  770.      * (MIME-Version and Content-Type). Format of argument is:
  771.      * $array['header-name'] = 'header-value';
  772.      *
  773.      * @param array $xtra_headers Assoc array with any extra headers.
  774.      *                             Optional.
  775.      * @param bool  $overwrite    Overwrite already existing headers.
  776.      * 
  777.      * @return array Assoc array with the mime headers
  778.      * @access public
  779.      */
  780.     function &headers($xtra_headers = null, $overwrite = false)
  781.     {
  782.         // Content-Type header should already be present,
  783.         // So just add mime version header
  784.         $headers['MIME-Version'] = '1.0';
  785.         if (isset($xtra_headers)) {
  786.             $headers = array_merge($headers, $xtra_headers);
  787.         }
  788.         if ($overwrite) {
  789.             $this->_headers = array_merge($this->_headers, $headers);
  790.         } else {
  791.             $this->_headers = array_merge($headers, $this->_headers);
  792.         }
  793.  
  794.         $encodedHeaders = $this->_encodeHeaders($this->_headers);
  795.         return $encodedHeaders;
  796.     }
  797.  
  798.     /**
  799.      * Get the text version of the headers
  800.      * (usefull if you want to use the PHP mail() function)
  801.      *
  802.      * @param array $xtra_headers Assoc array with any extra headers.
  803.      *                             Optional.
  804.      * @param bool  $overwrite    Overwrite the existing heaers with new.
  805.      *
  806.      * @return string  Plain text headers
  807.      * @access public
  808.      */
  809.     function txtHeaders($xtra_headers = null, $overwrite = false)
  810.     {
  811.         $headers = $this->headers($xtra_headers, $overwrite);
  812.         
  813.         $ret = '';
  814.         foreach ($headers as $key => $val) {
  815.             $ret .= "$key: $val" . MAIL_MIME_CRLF;
  816.         }
  817.         return $ret;
  818.     }
  819.  
  820.     /**
  821.      * Sets the Subject header
  822.      *
  823.      * @param string $subject String to set the subject to.
  824.      *
  825.      * @return void
  826.      * @access public
  827.      */
  828.     function setSubject($subject)
  829.     {
  830.         $this->_headers['Subject'] = $subject;
  831.     }
  832.  
  833.     /**
  834.      * Set an email to the From (the sender) header
  835.      *
  836.      * @param string $email The email address to use
  837.      *
  838.      * @return void
  839.      * @access public
  840.      */
  841.     function setFrom($email)
  842.     {
  843.         $this->_headers['From'] = $email;
  844.     }
  845.  
  846.     /**
  847.      * Add an email to the Cc (carbon copy) header
  848.      * (multiple calls to this method are allowed)
  849.      *
  850.      * @param string $email The email direction to add
  851.      *
  852.      * @return void
  853.      * @access public
  854.      */
  855.     function addCc($email)
  856.     {
  857.         if (isset($this->_headers['Cc'])) {
  858.             $this->_headers['Cc'] .= ", $email";
  859.         } else {
  860.             $this->_headers['Cc'] = $email;
  861.         }
  862.     }
  863.  
  864.     /**
  865.      * Add an email to the Bcc (blank carbon copy) header
  866.      * (multiple calls to this method are allowed)
  867.      *
  868.      * @param string $email The email direction to add
  869.      *
  870.      * @return void
  871.      * @access public
  872.      */
  873.     function addBcc($email)
  874.     {
  875.         if (isset($this->_headers['Bcc'])) {
  876.             $this->_headers['Bcc'] .= ", $email";
  877.         } else {
  878.             $this->_headers['Bcc'] = $email;
  879.         }
  880.     }
  881.  
  882.     /**
  883.      * Since the PHP send function requires you to specifiy 
  884.      * recipients (To: header) separately from the other
  885.      * headers, the To: header is not properly encoded.
  886.      * To fix this, you can use this public method to 
  887.      * encode your recipients before sending to the send
  888.      * function
  889.      *
  890.      * @param string $recipients A comma-delimited list of recipients
  891.      *
  892.      * @return string Encoded data
  893.      * @access public
  894.      */
  895.     function encodeRecipients($recipients)
  896.     {
  897.         $input = array("To" => $recipients);
  898.         $retval = $this->_encodeHeaders($input);
  899.         return $retval["To"] ;
  900.     }
  901.  
  902.     /**
  903.      * Encodes a header as per RFC2047
  904.      *
  905.      * @param array $input  The header data to encode
  906.      * @param array $params Extra build parameters
  907.      *
  908.      * @return array Encoded data
  909.      * @access private
  910.      */
  911.     function _encodeHeaders($input, $params = array())
  912.     {
  913.         
  914.         $build_params = $this->_build_params;
  915.         while (list($key, $value) = each($params)) {
  916.             $build_params[$key] = $value;
  917.         }
  918.         //$hdr_name: Name of the heaer
  919.         //$hdr_value: Full line of header value.
  920.         //$hdr_value_out: The recombined $hdr_val-atoms, or the encoded string.
  921.                 
  922.         $useIconv = true;        
  923.         if (isset($build_params['ignore-iconv'])) {
  924.             $useIconv = !$build_params['ignore-iconv'];
  925.         }            
  926.         foreach ($input as $hdr_name => $hdr_value) {
  927.             if (preg_match('#([\x80-\xFF]){1}#', $hdr_value)) {
  928.                 if (function_exists('iconv_mime_encode') && $useIconv) {
  929.                     $imePrefs = array();
  930.                     if ($build_params['head_encoding'] == 'base64') {
  931.                         $imePrefs['scheme'] = 'B';
  932.                     } else {
  933.                         $imePrefs['scheme'] = 'Q';
  934.                     }
  935.                     $imePrefs['input-charset']  = $build_params['head_charset'];
  936.                     $imePrefs['output-charset'] = $build_params['head_charset'];
  937.                     $imePrefs['line-length'] = 74;
  938.                     $imePrefs['line-break-chars'] = "\r\n"; //Specified in RFC2047
  939.                     
  940.                     $hdr_value = iconv_mime_encode($hdr_name, $hdr_value, $imePrefs);
  941.                     $hdr_value = preg_replace("#^{$hdr_name}\:\ #", "", $hdr_value);
  942.                 } elseif ($build_params['head_encoding'] == 'base64') {
  943.                     //Base64 encoding has been selected.
  944.                     //Base64 encode the entire string
  945.                     $hdr_value = base64_encode($hdr_value);
  946.                     
  947.                     //Generate the header using the specified params and dynamicly 
  948.                     //determine the maximum length of such strings.
  949.                     //75 is the value specified in the RFC. The first -2 is there so 
  950.                     //the later regexp doesn't break any of the translated chars.
  951.                     //The -2 on the first line-regexp is to compensate for the ": "
  952.                     //between the header-name and the header value
  953.                     $prefix = '=?' . $build_params['head_charset'] . '?B?';
  954.                     $suffix = '?=';
  955.                     $maxLength = 75 - strlen($prefix . $suffix) - 2;
  956.                     $maxLength1stLine = $maxLength - strlen($hdr_name) - 2;
  957.  
  958.                     //We can cut base4 every 4 characters, so the real max
  959.                     //we can get must be rounded down.
  960.                     $maxLength = $maxLength - ($maxLength % 4);
  961.                     $maxLength1stLine = $maxLength1stLine - ($maxLength1stLine % 4);
  962.                     
  963.                     $cutpoint = $maxLength1stLine;
  964.                     $hdr_value_out = $hdr_value;
  965.                     $output = "";
  966.                     while ($hdr_value_out) {
  967.                         //Split translated string at every $maxLength
  968.                         $part = substr($hdr_value_out, 0, $cutpoint);
  969.                         $hdr_value_out = substr($hdr_value_out, $cutpoint);
  970.                         $cutpoint = $maxLength;
  971.                         //RFC 2047 specifies that any split header should 
  972.                         //be seperated by a CRLF SPACE. 
  973.                         if ($output) {
  974.                             $output .=  "\r\n ";
  975.                         }
  976.                         $output .= $prefix . $part . $suffix;
  977.                     }
  978.                     $hdr_value = $output;
  979.                 } else {
  980.                     //quoted-printable encoding has been selected
  981.  
  982.                     //Fix for Bug #10298, Ota Mares <om@viazenetti.de>
  983.                     //Check if there is a double quote at beginning or end of
  984.                     //the string to prevent that an open or closing quote gets 
  985.                     //ignored because it is encapsuled by an encoding pre/suffix.
  986.                     //Remove the double quote and set the specific prefix or 
  987.                     //suffix variable so that we can concat the encoded string and
  988.                     //the double quotes back together to get the intended string.
  989.                     $quotePrefix = $quoteSuffix = '';
  990.                     if ($hdr_value{0} == '"') {
  991.                         $hdr_value = substr($hdr_value, 1);
  992.                         $quotePrefix = '"';
  993.                     }
  994.                     if ($hdr_value{strlen($hdr_value)-1} == '"') {
  995.                         $hdr_value = substr($hdr_value, 0, -1);
  996.                         $quoteSuffix = '"';
  997.                     }
  998.                     
  999.                     //Generate the header using the specified params and dynamicly 
  1000.                     //determine the maximum length of such strings.
  1001.                     //75 is the value specified in the RFC. The -2 is there so 
  1002.                     //the later regexp doesn't break any of the translated chars.
  1003.                     //The -2 on the first line-regexp is to compensate for the ": "
  1004.                     //between the header-name and the header value
  1005.                     $prefix = '=?' . $build_params['head_charset'] . '?Q?';
  1006.                     $suffix = '?=';
  1007.                     $maxLength = 75 - strlen($prefix . $suffix) - 2 - 1;
  1008.                     $maxLength1stLine = $maxLength - strlen($hdr_name) - 2;
  1009.                     $maxLength = $maxLength - 1;
  1010.                     
  1011.                     //Replace all special characters used by the encoder.
  1012.                     $search  = array('=',   '_',   '?',   ' ');
  1013.                     $replace = array('=3D', '=5F', '=3F', '_');
  1014.                     $hdr_value = str_replace($search, $replace, $hdr_value);
  1015.                     
  1016.                     //Replace all extended characters (\x80-xFF) with their
  1017.                     //ASCII values.
  1018.                     $hdr_value = preg_replace('#([\x80-\xFF])#e',
  1019.                         '"=" . strtoupper(dechex(ord("\1")))',
  1020.                         $hdr_value);
  1021.  
  1022.                     //This regexp will break QP-encoded text at every $maxLength
  1023.                     //but will not break any encoded letters.
  1024.                     $reg1st = "|(.{0,$maxLength1stLine}[^\=][^\=])|";
  1025.                     $reg2nd = "|(.{0,$maxLength}[^\=][^\=])|";
  1026.                     //Fix for Bug #10298, Ota Mares <om@viazenetti.de>
  1027.                     //Concat the double quotes and encoded string together
  1028.                     $hdr_value = $quotePrefix . $hdr_value . $quoteSuffix;
  1029.                     
  1030.  
  1031.                     $hdr_value_out = $hdr_value;
  1032.                     $realMax = $maxLength1stLine + strlen($prefix . $suffix);
  1033.                     if (strlen($hdr_value_out) >= $realMax) {
  1034.                         //Begin with the regexp for the first line.
  1035.                         $reg = $reg1st;
  1036.                         $output = "";
  1037.                         while ($hdr_value_out) {
  1038.                             //Split translated string at every $maxLength
  1039.                             //But make sure not to break any translated chars.
  1040.                             $found = preg_match($reg, $hdr_value_out, $matches);
  1041.                             
  1042.                             //After this first line, we need to use a different
  1043.                             //regexp for the first line.
  1044.                             $reg = $reg2nd;
  1045.                             
  1046.                             //Save the found part and encapsulate it in the
  1047.                             //prefix & suffix. Then remove the part from the
  1048.                             //$hdr_value_out variable.
  1049.                             if ($found) {
  1050.                                 $part = $matches[0];
  1051.                                 $len = strlen($matches[0]);
  1052.                                 $hdr_value_out = substr($hdr_value_out, $len);
  1053.                             } else {
  1054.                                 $part = $hdr_value_out;
  1055.                                 $hdr_value_out = "";
  1056.                             }
  1057.                             
  1058.                             //RFC 2047 specifies that any split header should 
  1059.                             //be seperated by a CRLF SPACE
  1060.                             if ($output) {
  1061.                                 $output .=  "\r\n ";
  1062.                             }
  1063.                             $output .= $prefix . $part . $suffix;
  1064.                         }
  1065.                         $hdr_value_out = $output;
  1066.                     } else {
  1067.                         $hdr_value_out = $prefix . $hdr_value_out . $suffix;
  1068.                     }
  1069.                     $hdr_value = $hdr_value_out;
  1070.                 }
  1071.             }
  1072.             $input[$hdr_name] = $hdr_value;
  1073.         }
  1074.         return $input;
  1075.     }
  1076.  
  1077.     /**
  1078.      * Set the object's end-of-line and define the constant if applicable.
  1079.      *
  1080.      * @param string $eol End Of Line sequence
  1081.      *
  1082.      * @return void
  1083.      * @access private
  1084.      */
  1085.     function _setEOL($eol)
  1086.     {
  1087.         $this->_eol = $eol;
  1088.         if (!defined('MAIL_MIME_CRLF')) {
  1089.             define('MAIL_MIME_CRLF', $this->_eol, true);
  1090.         }
  1091.     }
  1092.  
  1093.     
  1094.  
  1095. } // End of class
  1096.