thomascube
2010-12-17 db1a87cd6c506f2afbd1a37c64cb56ae11120b49
commit | author | age
4e17e6 1 <?php
ab6f80 2 /**
T 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  *
ee289d 42  * @category  Mail
A 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>
091735 48  * @author    Aleksander Machniak <alec@php.net>
ee289d 49  * @copyright 2003-2006 PEAR <pear-group@php.net>
A 50  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
51  * @version   CVS: $Id$
52  * @link      http://pear.php.net/package/Mail_mime
53  *
54  *            This class is based on HTML Mime Mail class from
55  *            Richard Heyes <richard@phpguru.org> which was based also
56  *            in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it>
57  *            and Sascha Schumann <sascha@schumann.cx>
ab6f80 58  */
4e17e6 59
T 60
61 /**
ab6f80 62  * require PEAR
4e17e6 63  *
ab6f80 64  * This package depends on PEAR to raise errors.
T 65  */
ee289d 66 require_once 'PEAR.php';
ab6f80 67
T 68 /**
69  * require Mail_mimePart
4e17e6 70  *
ab6f80 71  * Mail_mimePart contains the code required to
T 72  * create all the different parts a mail can
73  * consist of.
74  */
ee289d 75 require_once 'Mail/mimePart.php';
ab6f80 76
T 77
78 /**
79  * The Mail_Mime class provides an OO interface to create MIME
80  * enabled email messages. This way you can create emails that
81  * contain plain-text bodies, HTML bodies, attachments, inline
82  * images and specific headers.
83  *
ee289d 84  * @category  Mail
A 85  * @package   Mail_Mime
86  * @author    Richard Heyes  <richard@phpguru.org>
87  * @author    Tomas V.V. Cox <cox@idecnet.com>
88  * @author    Cipriano Groenendal <cipri@php.net>
89  * @author    Sean Coates <sean@php.net>
90  * @copyright 2003-2006 PEAR <pear-group@php.net>
91  * @license   http://www.opensource.org/licenses/bsd-license.php BSD License
92  * @version   Release: @package_version@
93  * @link      http://pear.php.net/package/Mail_mime
4e17e6 94  */
T 95 class Mail_mime
96 {
97     /**
98      * Contains the plain text part of the email
ab6f80 99      *
4e17e6 100      * @var string
ab6f80 101      * @access private
4e17e6 102      */
T 103     var $_txtbody;
ab6f80 104
4e17e6 105     /**
T 106      * Contains the html part of the email
ab6f80 107      *
4e17e6 108      * @var string
ab6f80 109      * @access private
4e17e6 110      */
T 111     var $_htmlbody;
ab6f80 112
4e17e6 113     /**
T 114      * list of the attached images
ab6f80 115      *
4e17e6 116      * @var array
ab6f80 117      * @access private
4e17e6 118      */
T 119     var $_html_images = array();
ab6f80 120
4e17e6 121     /**
T 122      * list of the attachements
ab6f80 123      *
4e17e6 124      * @var array
ab6f80 125      * @access private
4e17e6 126      */
T 127     var $_parts = array();
ab6f80 128
4e17e6 129     /**
T 130      * Headers for the mail
ab6f80 131      *
4e17e6 132      * @var array
ab6f80 133      * @access private
4e17e6 134      */
T 135     var $_headers = array();
ab6f80 136
4e17e6 137     /**
091735 138      * Build parameters
ab6f80 139      *
091735 140      * @var array
ab6f80 141      * @access private
4e17e6 142      */
091735 143     var $_build_params = array(
A 144         // What encoding to use for the headers
145         // Options: quoted-printable or base64
146         'head_encoding' => 'quoted-printable',
147         // What encoding to use for plain text
148         // Options: 7bit, 8bit, base64, or quoted-printable
149         'text_encoding' => 'quoted-printable',
150         // What encoding to use for html
151         // Options: 7bit, 8bit, base64, or quoted-printable
152         'html_encoding' => 'quoted-printable',
153         // The character set to use for html
154         'html_charset'  => 'ISO-8859-1',
155         // The character set to use for text
156         'text_charset'  => 'ISO-8859-1',
157         // The character set to use for headers
158         'head_charset'  => 'ISO-8859-1',
159         // End-of-line sequence
160         'eol'           => "\r\n",
161         // Delay attachment files IO until building the message
162         'delay_file_io' => false
163     );
4e17e6 164
T 165     /**
091735 166      * Constructor function
ab6f80 167      *
091735 168      * @param mixed $params Build parameters that change the way the email
A 169      *                      is built. Should be an associative array.
170      *                      See $_build_params.
ee289d 171      *
ab6f80 172      * @return void
4e17e6 173      * @access public
T 174      */
091735 175     function Mail_mime($params = array())
4e17e6 176     {
091735 177         // Backward-compatible EOL setting
A 178         if (is_string($params)) {
179             $this->_build_params['eol'] = $params;
180         } else if (defined('MAIL_MIME_CRLF') && !isset($params['eol'])) {
181             $this->_build_params['eol'] = MAIL_MIME_CRLF;
182         }
183
184         // Update build parameters
185         if (!empty($params) && is_array($params)) {
186             while (list($key, $value) = each($params)) {
187                 $this->_build_params[$key] = $value;
188             }
189         }
4e17e6 190     }
T 191
192     /**
091735 193      * Set build parameter value
4e17e6 194      *
091735 195      * @param string $name  Parameter name
A 196      * @param string $value Parameter value
197      *
ee289d 198      * @return void
091735 199      * @access public
A 200      * @since 1.6.0
4e17e6 201      */
091735 202     function setParam($name, $value)
4e17e6 203     {
091735 204         $this->_build_params[$name] = $value;
4e17e6 205     }
T 206
091735 207     /**
A 208      * Get build parameter value
209      *
210      * @param string $name Parameter name
211      *
212      * @return mixed Parameter value
213      * @access public
214      * @since 1.6.0
215      */
216     function getParam($name)
217     {
218         return isset($this->_build_params[$name]) ? $this->_build_params[$name] : null;
219     }
ab6f80 220
4e17e6 221     /**
T 222      * Accessor function to set the body text. Body text is used if
223      * it's not an html mail being sent or else is used to fill the
224      * text/plain part that emails clients who don't support
225      * html should show.
226      *
ee289d 227      * @param string $data   Either a string or
091735 228      *                       the file name with the contents
ee289d 229      * @param bool   $isfile If true the first param should be treated
091735 230      *                       as a file name, else as a string (default)
ee289d 231      * @param bool   $append If true the text or file is appended to
091735 232      *                       the existing body, else the old body is
A 233      *                       overwritten
ee289d 234      *
091735 235      * @return mixed         True on success or PEAR_Error object
4e17e6 236      * @access public
T 237      */
238     function setTXTBody($data, $isfile = false, $append = false)
239     {
240         if (!$isfile) {
241             if (!$append) {
242                 $this->_txtbody = $data;
243             } else {
244                 $this->_txtbody .= $data;
245             }
246         } else {
247             $cont = $this->_file2str($data);
248             if (PEAR::isError($cont)) {
249                 return $cont;
250             }
251             if (!$append) {
252                 $this->_txtbody = $cont;
253             } else {
254                 $this->_txtbody .= $cont;
255             }
256         }
257         return true;
258     }
259
260     /**
091735 261      * Get message text body
A 262      *
263      * @return string Text body
264      * @access public
265      * @since 1.6.0
266      */
267     function getTXTBody()
268     {
269         return $this->_txtbody;
270     }
271
272     /**
ab6f80 273      * Adds a html part to the mail.
4e17e6 274      *
091735 275      * @param string $data   Either a string or the file name with the
A 276      *                       contents
277      * @param bool   $isfile A flag that determines whether $data is a
278      *                       filename, or a string(false, default)
ee289d 279      *
091735 280      * @return bool          True on success
4e17e6 281      * @access public
T 282      */
283     function setHTMLBody($data, $isfile = false)
284     {
285         if (!$isfile) {
286             $this->_htmlbody = $data;
287         } else {
288             $cont = $this->_file2str($data);
289             if (PEAR::isError($cont)) {
290                 return $cont;
291             }
292             $this->_htmlbody = $cont;
293         }
294
295         return true;
296     }
297
298     /**
091735 299      * Get message HTML body
A 300      *
301      * @return string HTML body
302      * @access public
303      * @since 1.6.0
304      */
305     function getHTMLBody()
306     {
307         return $this->_htmlbody;
308     }
309
310     /**
4e17e6 311      * Adds an image to the list of embedded images.
T 312      *
091735 313      * @param string $file       The image file name OR image data itself
A 314      * @param string $c_type     The content type
315      * @param string $name       The filename of the image.
316      *                           Only used if $file is the image data.
317      * @param bool   $isfile     Whether $file is a filename or not.
318      *                           Defaults to true
319      * @param string $content_id Desired Content-ID of MIME part
320      *                           Defaults to generated unique ID
ee289d 321      *
091735 322      * @return bool          True on success
4e17e6 323      * @access public
T 324      */
091735 325     function addHTMLImage($file,
A 326         $c_type='application/octet-stream',
327         $name = '',
328         $isfile = true,
329         $content_id = null
330     ) {
331         $bodyfile = null;
332
333         if ($isfile) {
334             // Don't load file into memory
335             if ($this->_build_params['delay_file_io']) {
336                 $filedata = null;
337                 $bodyfile = $file;
338             } else {
339                 if (PEAR::isError($filedata = $this->_file2str($file))) {
340                     return $filedata;
341                 }
342             }
343             $filename = ($name ? $name : $file);
4e17e6 344         } else {
091735 345             $filedata = $file;
856110 346             $filename = $name;
4e17e6 347         }
091735 348
A 349         if (!$content_id) {
350             $content_id = md5(uniqid(time()));
4e17e6 351         }
091735 352
4e17e6 353         $this->_html_images[] = array(
091735 354             'body'      => $filedata,
A 355             'body_file' => $bodyfile,
356             'name'      => $filename,
357             'c_type'    => $c_type,
358             'cid'       => $content_id
359         );
360
4e17e6 361         return true;
T 362     }
363
364     /**
365      * Adds a file to the list of attachments.
366      *
ee289d 367      * @param string $file        The file name of the file to attach
db1a87 368      *                            or the file contents itself
ee289d 369      * @param string $c_type      The content type
A 370      * @param string $name        The filename of the attachment
091735 371      *                            Only use if $file is the contents
db1a87 372      * @param bool   $isfile      Whether $file is a filename or not. Defaults to true
T 373      * @param string $encoding    The type of encoding to use. Defaults to base64.
374      *                            Possible values: 7bit, 8bit, base64 or quoted-printable.
ee289d 375      * @param string $disposition The content-disposition of this file
091735 376      *                            Defaults to attachment.
A 377      *                            Possible values: attachment, inline.
db1a87 378      * @param string $charset     The character set of attachment's content.
ee289d 379      * @param string $language    The language of the attachment
A 380      * @param string $location    The RFC 2557.4 location of the attachment
db1a87 381      * @param string $n_encoding  Encoding of the attachment's name in Content-Type
091735 382      *                            By default filenames are encoded using RFC2231 method
A 383      *                            Here you can set RFC2047 encoding (quoted-printable
384      *                            or base64) instead
db1a87 385      * @param string $f_encoding  Encoding of the attachment's filename
T 386      *                            in Content-Disposition header.
be5133 387      * @param string $description Content-Description header
db1a87 388      * @param string $h_charset   The character set of the headers e.g. filename
T 389      *                            If not specified, $charset will be used
ee289d 390      *
091735 391      * @return mixed              True on success or PEAR_Error object
4e17e6 392      * @access public
T 393      */
ee289d 394     function addAttachment($file,
091735 395         $c_type      = 'application/octet-stream',
A 396         $name        = '',
397         $isfile      = true,
398         $encoding    = 'base64',
399         $disposition = 'attachment',
400         $charset     = '',
401         $language    = '',
402         $location    = '',
403         $n_encoding  = null,
be5133 404         $f_encoding  = null,
db1a87 405         $description = '',
T 406         $h_charset   = null
091735 407     ) {
A 408         $bodyfile = null;
f7f934 409
091735 410         if ($isfile) {
A 411             // Don't load file into memory
412             if ($this->_build_params['delay_file_io']) {
413                 $filedata = null;
414                 $bodyfile = $file;
415             } else {
416                 if (PEAR::isError($filedata = $this->_file2str($file))) {
417                     return $filedata;
418                 }
419             }
4e17e6 420             // Force the name the user supplied, otherwise use $file
091735 421             $filename = ($name ? $name : $file);
4e17e6 422         } else {
091735 423             $filedata = $file;
4e17e6 424             $filename = $name;
T 425         }
091735 426
ee289d 427         if (!strlen($filename)) {
A 428             $msg = "The supplied filename for the attachment can't be empty";
429             $err = PEAR::raiseError($msg);
430             return $err;
4e17e6 431         }
09f19e 432         $filename = $this->_basename($filename);
4e17e6 433
T 434         $this->_parts[] = array(
091735 435             'body'        => $filedata,
A 436             'body_file'   => $bodyfile,
437             'name'        => $filename,
438             'c_type'      => $c_type,
439             'charset'     => $charset,
db1a87 440             'encoding'    => $encoding,
091735 441             'language'    => $language,
A 442             'location'    => $location,
443             'disposition' => $disposition,
be5133 444             'description' => $description,
091735 445             'name_encoding'     => $n_encoding,
db1a87 446             'filename_encoding' => $f_encoding,
T 447             'headers_charset'   => $h_charset,
091735 448         );
A 449
4e17e6 450         return true;
T 451     }
452
453     /**
454      * Get the contents of the given file name as string
455      *
091735 456      * @param string $file_name Path of file to process
ee289d 457      *
091735 458      * @return string           Contents of $file_name
4e17e6 459      * @access private
T 460      */
461     function &_file2str($file_name)
462     {
091735 463         // Check state of file and raise an error properly
ee289d 464         if (!file_exists($file_name)) {
A 465             $err = PEAR::raiseError('File not found: ' . $file_name);
466             return $err;
467         }
468         if (!is_file($file_name)) {
469             $err = PEAR::raiseError('Not a regular file: ' . $file_name);
470             return $err;
471         }
4e17e6 472         if (!is_readable($file_name)) {
ee289d 473             $err = PEAR::raiseError('File is not readable: ' . $file_name);
856110 474             return $err;
4e17e6 475         }
f7f934 476
091735 477         // Temporarily reset magic_quotes_runtime and read file contents
ee289d 478         if ($magic_quote_setting = get_magic_quotes_runtime()) {
091735 479             @ini_set('magic_quotes_runtime', 0);
4e17e6 480         }
f7f934 481         $cont = file_get_contents($file_name);
ee289d 482         if ($magic_quote_setting) {
091735 483             @ini_set('magic_quotes_runtime', $magic_quote_setting);
15fee7 484         }
f7f934 485
4e17e6 486         return $cont;
T 487     }
488
489     /**
490      * Adds a text subpart to the mimePart object and
491      * returns it during the build process.
492      *
ee289d 493      * @param mixed  &$obj The object to add the part to, or
091735 494      *                     null if a new object is to be created.
ee289d 495      * @param string $text The text to add.
A 496      *
091735 497      * @return object      The text mimePart object
4e17e6 498      * @access private
T 499      */
500     function &_addTextPart(&$obj, $text)
501     {
502         $params['content_type'] = 'text/plain';
503         $params['encoding']     = $this->_build_params['text_encoding'];
504         $params['charset']      = $this->_build_params['text_charset'];
091735 505         $params['eol']          = $this->_build_params['eol'];
A 506
4e17e6 507         if (is_object($obj)) {
856110 508             $ret = $obj->addSubpart($text, $params);
S 509             return $ret;
4e17e6 510         } else {
856110 511             $ret = new Mail_mimePart($text, $params);
S 512             return $ret;
4e17e6 513         }
T 514     }
515
516     /**
517      * Adds a html subpart to the mimePart object and
518      * returns it during the build process.
519      *
ee289d 520      * @param mixed &$obj The object to add the part to, or
091735 521      *                    null if a new object is to be created.
ee289d 522      *
091735 523      * @return object     The html mimePart object
4e17e6 524      * @access private
T 525      */
526     function &_addHtmlPart(&$obj)
527     {
528         $params['content_type'] = 'text/html';
529         $params['encoding']     = $this->_build_params['html_encoding'];
530         $params['charset']      = $this->_build_params['html_charset'];
091735 531         $params['eol']          = $this->_build_params['eol'];
A 532
4e17e6 533         if (is_object($obj)) {
856110 534             $ret = $obj->addSubpart($this->_htmlbody, $params);
S 535             return $ret;
4e17e6 536         } else {
856110 537             $ret = new Mail_mimePart($this->_htmlbody, $params);
S 538             return $ret;
4e17e6 539         }
T 540     }
541
542     /**
543      * Creates a new mimePart object, using multipart/mixed as
544      * the initial content-type and returns it during the
545      * build process.
546      *
ee289d 547      * @return object The multipart/mixed mimePart object
4e17e6 548      * @access private
T 549      */
550     function &_addMixedPart()
551     {
ee289d 552         $params                 = array();
4e17e6 553         $params['content_type'] = 'multipart/mixed';
091735 554         $params['eol']          = $this->_build_params['eol'];
f7f934 555
091735 556         // Create empty multipart/mixed Mail_mimePart object to return
856110 557         $ret = new Mail_mimePart('', $params);
S 558         return $ret;
4e17e6 559     }
T 560
561     /**
562      * Adds a multipart/alternative part to a mimePart
563      * object (or creates one), and returns it during
564      * the build process.
565      *
ee289d 566      * @param mixed &$obj The object to add the part to, or
091735 567      *                    null if a new object is to be created.
ee289d 568      *
091735 569      * @return object     The multipart/mixed mimePart object
4e17e6 570      * @access private
T 571      */
572     function &_addAlternativePart(&$obj)
573     {
574         $params['content_type'] = 'multipart/alternative';
091735 575         $params['eol']          = $this->_build_params['eol'];
A 576
4e17e6 577         if (is_object($obj)) {
T 578             return $obj->addSubpart('', $params);
579         } else {
856110 580             $ret = new Mail_mimePart('', $params);
S 581             return $ret;
4e17e6 582         }
T 583     }
584
585     /**
586      * Adds a multipart/related part to a mimePart
587      * object (or creates one), and returns it during
588      * the build process.
589      *
ee289d 590      * @param mixed &$obj The object to add the part to, or
091735 591      *                    null if a new object is to be created
ee289d 592      *
091735 593      * @return object     The multipart/mixed mimePart object
4e17e6 594      * @access private
T 595      */
596     function &_addRelatedPart(&$obj)
597     {
598         $params['content_type'] = 'multipart/related';
091735 599         $params['eol']          = $this->_build_params['eol'];
A 600
4e17e6 601         if (is_object($obj)) {
T 602             return $obj->addSubpart('', $params);
603         } else {
856110 604             $ret = new Mail_mimePart('', $params);
S 605             return $ret;
4e17e6 606         }
T 607     }
608
609     /**
610      * Adds an html image subpart to a mimePart object
611      * and returns it during the build process.
612      *
ee289d 613      * @param object &$obj  The mimePart to add the image to
A 614      * @param array  $value The image information
615      *
091735 616      * @return object       The image mimePart object
4e17e6 617      * @access private
T 618      */
619     function &_addHtmlImagePart(&$obj, $value)
620     {
ee289d 621         $params['content_type'] = $value['c_type'];
4e17e6 622         $params['encoding']     = 'base64';
T 623         $params['disposition']  = 'inline';
db1a87 624         $params['filename']     = $value['name'];
4e17e6 625         $params['cid']          = $value['cid'];
091735 626         $params['body_file']    = $value['body_file'];
A 627         $params['eol']          = $this->_build_params['eol'];
f7f934 628
091735 629         if (!empty($value['name_encoding'])) {
A 630             $params['name_encoding'] = $value['name_encoding'];
f7f934 631         }
091735 632         if (!empty($value['filename_encoding'])) {
A 633             $params['filename_encoding'] = $value['filename_encoding'];
f7f934 634         }
A 635
856110 636         $ret = $obj->addSubpart($value['body'], $params);
S 637         return $ret;
4e17e6 638     }
T 639
640     /**
641      * Adds an attachment subpart to a mimePart object
642      * and returns it during the build process.
643      *
ee289d 644      * @param object &$obj  The mimePart to add the image to
A 645      * @param array  $value The attachment information
646      *
091735 647      * @return object       The image mimePart object
4e17e6 648      * @access private
T 649      */
650     function &_addAttachmentPart(&$obj, $value)
651     {
091735 652         $params['eol']          = $this->_build_params['eol'];
db1a87 653         $params['filename']     = $value['name'];
091735 654         $params['encoding']     = $value['encoding'];
A 655         $params['content_type'] = $value['c_type'];
656         $params['body_file']    = $value['body_file'];
657         $params['disposition']  = isset($value['disposition']) ? 
658                                   $value['disposition'] : 'attachment';
db1a87 659
T 660         // content charset
661         if (!empty($value['charset'])) {
a8435b 662             $params['charset'] = $value['charset'];
S 663         }
db1a87 664         // headers charset (filename, description)
T 665         if (!empty($value['headers_charset'])) {
666             $params['headers_charset'] = $value['headers_charset'];
667         }
668         if (!empty($value['language'])) {
ee289d 669             $params['language'] = $value['language'];
A 670         }
db1a87 671         if (!empty($value['location'])) {
ee289d 672             $params['location'] = $value['location'];
A 673         }
091735 674         if (!empty($value['name_encoding'])) {
A 675             $params['name_encoding'] = $value['name_encoding'];
f7f934 676         }
091735 677         if (!empty($value['filename_encoding'])) {
A 678             $params['filename_encoding'] = $value['filename_encoding'];
f7f934 679         }
be5133 680         if (!empty($value['description'])) {
A 681             $params['description'] = $value['description'];
682         }
091735 683
856110 684         $ret = $obj->addSubpart($value['body'], $params);
S 685         return $ret;
4e17e6 686     }
856110 687
S 688     /**
689      * Returns the complete e-mail, ready to send using an alternative
690      * mail delivery method. Note that only the mailpart that is made
691      * with Mail_Mime is created. This means that,
692      * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF 
091735 693      * using the $headers parameter!
856110 694      * 
091735 695      * @param string $separation The separation between these two parts.
A 696      * @param array  $params     The Build parameters passed to the
697      *                           &get() function. See &get for more info.
698      * @param array  $headers    The extra headers that should be passed
699      *                           to the &headers() function.
700      *                           See that function for more info.
701      * @param bool   $overwrite  Overwrite the existing headers with new.
ee289d 702      *
091735 703      * @return mixed The complete e-mail or PEAR error object
856110 704      * @access public
S 705      */
091735 706     function getMessage($separation = null, $params = null, $headers = null,
A 707         $overwrite = false
708     ) {
ee289d 709         if ($separation === null) {
091735 710             $separation = $this->_build_params['eol'];
856110 711         }
091735 712
A 713         $body = $this->get($params);
714
715         if (PEAR::isError($body)) {
716             return $body;
717         }
718
719         $head = $this->txtHeaders($headers, $overwrite);
856110 720         $mail = $head . $separation . $body;
S 721         return $mail;
722     }
723
091735 724     /**
90fe6c 725      * Returns the complete e-mail body, ready to send using an alternative
A 726      * mail delivery method.
727      * 
728      * @param array $params The Build parameters passed to the
729      *                      &get() function. See &get for more info.
730      *
731      * @return mixed The e-mail body or PEAR error object
732      * @access public
733      * @since 1.6.0
734      */
735     function getMessageBody($params = null)
736     {
737         return $this->get($params, null, true);
738     }
739
740     /**
091735 741      * Writes (appends) the complete e-mail into file.
A 742      * 
743      * @param string $filename  Output file location
744      * @param array  $params    The Build parameters passed to the
745      *                          &get() function. See &get for more info.
746      * @param array  $headers   The extra headers that should be passed
747      *                          to the &headers() function.
748      *                          See that function for more info.
749      * @param bool   $overwrite Overwrite the existing headers with new.
750      *
751      * @return mixed True or PEAR error object
752      * @access public
90fe6c 753      * @since 1.6.0
091735 754      */
A 755     function saveMessage($filename, $params = null, $headers = null, $overwrite = false)
756     {
757         // Check state of file and raise an error properly
758         if (file_exists($filename) && !is_writable($filename)) {
759             $err = PEAR::raiseError('File is not writable: ' . $filename);
760             return $err;
761         }
762
763         // Temporarily reset magic_quotes_runtime and read file contents
764         if ($magic_quote_setting = get_magic_quotes_runtime()) {
765             @ini_set('magic_quotes_runtime', 0);
766         }
767
768         if (!($fh = fopen($filename, 'ab'))) {
769             $err = PEAR::raiseError('Unable to open file: ' . $filename);
770             return $err;
771         }
772
773         // Write message headers into file (skipping Content-* headers)
774         $head = $this->txtHeaders($headers, $overwrite, true);
775         if (fwrite($fh, $head) === false) {
776             $err = PEAR::raiseError('Error writing to file: ' . $filename);
777             return $err;
778         }
779
780         fclose($fh);
781
782         if ($magic_quote_setting) {
783             @ini_set('magic_quotes_runtime', $magic_quote_setting);
784         }
785
786         // Write the rest of the message into file
787         $res = $this->get($params, $filename);
788
789         return $res ? $res : true;
790     }
4e17e6 791
T 792     /**
90fe6c 793      * Writes (appends) the complete e-mail body into file.
A 794      * 
795      * @param string $filename Output file location
796      * @param array  $params   The Build parameters passed to the
797      *                         &get() function. See &get for more info.
798      *
799      * @return mixed True or PEAR error object
800      * @access public
801      * @since 1.6.0
802      */
803     function saveMessageBody($filename, $params = null)
804     {
805         // Check state of file and raise an error properly
806         if (file_exists($filename) && !is_writable($filename)) {
807             $err = PEAR::raiseError('File is not writable: ' . $filename);
808             return $err;
809         }
810
811         // Temporarily reset magic_quotes_runtime and read file contents
812         if ($magic_quote_setting = get_magic_quotes_runtime()) {
813             @ini_set('magic_quotes_runtime', 0);
814         }
815
816         if (!($fh = fopen($filename, 'ab'))) {
817             $err = PEAR::raiseError('Unable to open file: ' . $filename);
818             return $err;
819         }
820
821         // Write the rest of the message into file
822         $res = $this->get($params, $filename, true);
823
824         return $res ? $res : true;
825     }
826
827     /**
4e17e6 828      * Builds the multipart message from the list ($this->_parts) and
T 829      * returns the mime content.
830      *
90fe6c 831      * @param array    $params    Build parameters that change the way the email
A 832      *                            is built. Should be associative. See $_build_params.
833      * @param resource $filename  Output file where to save the message instead of
834      *                            returning it
835      * @param boolean  $skip_head True if you want to return/save only the message
836      *                            without headers
ee289d 837      *
091735 838      * @return mixed The MIME message content string, null or PEAR error object
4e17e6 839      * @access public
T 840      */
90fe6c 841     function &get($params = null, $filename = null, $skip_head = false)
4e17e6 842     {
091735 843         if (isset($params)) {
A 844             while (list($key, $value) = each($params)) {
4e17e6 845                 $this->_build_params[$key] = $value;
T 846             }
847         }
f7f934 848
091735 849         if (isset($this->_headers['From'])) {
A 850             // Bug #11381: Illegal characters in domain ID
8fc810 851             if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->_headers['From'], $matches)) {
ee289d 852                 $domainID = $matches[1];
091735 853             } else {
8fc810 854                 $domainID = '@localhost';
ee289d 855             }
091735 856             foreach ($this->_html_images as $i => $img) {
8fc810 857                 $cid = $this->_html_images[$i]['cid']; 
141eb8 858                 if (!preg_match('#'.preg_quote($domainID).'$#', $cid)) {
S 859                     $this->_html_images[$i]['cid'] = $cid . $domainID;
860                 }
ee289d 861             }
A 862         }
f7f934 863
091735 864         if (count($this->_html_images) && isset($this->_htmlbody)) {
856110 865             foreach ($this->_html_images as $key => $value) {
ee289d 866                 $regex   = array();
856110 867                 $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' .
S 868                             preg_quote($value['name'], '#') . '\3#';
869                 $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' .
870                             preg_quote($value['name'], '#') . '\1\s*\)#';
ee289d 871
A 872                 $rep   = array();
856110 873                 $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3';
ee289d 874                 $rep[] = 'url(\1cid:' . $value['cid'] . '\1)';
A 875
876                 $this->_htmlbody = preg_replace($regex, $rep, $this->_htmlbody);
091735 877                 $this->_html_images[$key]['name']
A 878                     = $this->_basename($this->_html_images[$key]['name']);
4e17e6 879             }
T 880         }
881
be5133 882         $this->_checkParams();
A 883
4e17e6 884         $null        = null;
ee289d 885         $attachments = count($this->_parts)                 ? true : false;
A 886         $html_images = count($this->_html_images)           ? true : false;
887         $html        = strlen($this->_htmlbody)             ? true : false;
be5133 888         $text        = (!$html && strlen($this->_txtbody))  ? true : false;
4e17e6 889
T 890         switch (true) {
091735 891         case $text && !$attachments:
4e17e6 892             $message =& $this->_addTextPart($null, $this->_txtbody);
T 893             break;
894
091735 895         case !$text && !$html && $attachments:
4e17e6 896             $message =& $this->_addMixedPart();
T 897             for ($i = 0; $i < count($this->_parts); $i++) {
898                 $this->_addAttachmentPart($message, $this->_parts[$i]);
899             }
900             break;
901
091735 902         case $text && $attachments:
4e17e6 903             $message =& $this->_addMixedPart();
T 904             $this->_addTextPart($message, $this->_txtbody);
905             for ($i = 0; $i < count($this->_parts); $i++) {
906                 $this->_addAttachmentPart($message, $this->_parts[$i]);
907             }
908             break;
909
091735 910         case $html && !$attachments && !$html_images:
4e17e6 911             if (isset($this->_txtbody)) {
T 912                 $message =& $this->_addAlternativePart($null);
913                 $this->_addTextPart($message, $this->_txtbody);
914                 $this->_addHtmlPart($message);
915             } else {
916                 $message =& $this->_addHtmlPart($null);
917             }
918             break;
919
091735 920         case $html && !$attachments && $html_images:
A 921             // * Content-Type: multipart/alternative;
922             //    * text
923             //    * Content-Type: multipart/related;
924             //       * html
925             //       * image...
926             if (isset($this->_txtbody)) {
927                 $message =& $this->_addAlternativePart($null);
928                 $this->_addTextPart($message, $this->_txtbody);
929
930                 $ht =& $this->_addRelatedPart($message);
931                 $this->_addHtmlPart($ht);
932                 for ($i = 0; $i < count($this->_html_images); $i++) {
933                     $this->_addHtmlImagePart($ht, $this->_html_images[$i]);
934                 }
935             } else {
936                 // * Content-Type: multipart/related;
937                 //    * html
938                 //    * image...
939                 $message =& $this->_addRelatedPart($null);
940                 $this->_addHtmlPart($message);
941                 for ($i = 0; $i < count($this->_html_images); $i++) {
942                     $this->_addHtmlImagePart($message, $this->_html_images[$i]);
943                 }
944             }
945             /*
946             // #13444, #9725: the code below was a non-RFC compliant hack
947             // * Content-Type: multipart/related;
948             //    * Content-Type: multipart/alternative;
949             //        * text
950             //        * html
951             //    * image...
ee289d 952             $message =& $this->_addRelatedPart($null);
4e17e6 953             if (isset($this->_txtbody)) {
ee289d 954                 $alt =& $this->_addAlternativePart($message);
A 955                 $this->_addTextPart($alt, $this->_txtbody);
956                 $this->_addHtmlPart($alt);
4e17e6 957             } else {
ee289d 958                 $this->_addHtmlPart($message);
4e17e6 959             }
T 960             for ($i = 0; $i < count($this->_html_images); $i++) {
ee289d 961                 $this->_addHtmlImagePart($message, $this->_html_images[$i]);
4e17e6 962             }
091735 963             */
4e17e6 964             break;
T 965
091735 966         case $html && $attachments && !$html_images:
4e17e6 967             $message =& $this->_addMixedPart();
T 968             if (isset($this->_txtbody)) {
969                 $alt =& $this->_addAlternativePart($message);
970                 $this->_addTextPart($alt, $this->_txtbody);
971                 $this->_addHtmlPart($alt);
972             } else {
973                 $this->_addHtmlPart($message);
974             }
975             for ($i = 0; $i < count($this->_parts); $i++) {
976                 $this->_addAttachmentPart($message, $this->_parts[$i]);
977             }
978             break;
979
091735 980         case $html && $attachments && $html_images:
4e17e6 981             $message =& $this->_addMixedPart();
T 982             if (isset($this->_txtbody)) {
983                 $alt =& $this->_addAlternativePart($message);
984                 $this->_addTextPart($alt, $this->_txtbody);
985                 $rel =& $this->_addRelatedPart($alt);
986             } else {
987                 $rel =& $this->_addRelatedPart($message);
988             }
989             $this->_addHtmlPart($rel);
990             for ($i = 0; $i < count($this->_html_images); $i++) {
991                 $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
992             }
993             for ($i = 0; $i < count($this->_parts); $i++) {
994                 $this->_addAttachmentPart($message, $this->_parts[$i]);
995             }
996             break;
997
998         }
999
091735 1000         if (!isset($message)) {
A 1001             $ret = null;
1002             return $ret;
1003         }
8fc810 1004
091735 1005         // Use saved boundary
A 1006         if (!empty($this->_build_params['boundary'])) {
1007             $boundary = $this->_build_params['boundary'];
1008         } else {
1009             $boundary = null;
1010         }
f7f934 1011
091735 1012         // Write output to file
A 1013         if ($filename) {
1014             // Append mimePart message headers and body into file
90fe6c 1015             $headers = $message->encodeToFile($filename, $boundary, $skip_head);
A 1016             if (PEAR::isError($headers)) {
091735 1017                 return $headers;
A 1018             }
1019             $this->_headers = array_merge($this->_headers, $headers);
1020             $ret = null;
1021             return $ret;
1022         } else {
90fe6c 1023             $output = $message->encode($boundary, $skip_head);
A 1024             if (PEAR::isError($output)) {
091735 1025                 return $output;
A 1026             }
1027             $this->_headers = array_merge($this->_headers, $output['headers']);
856110 1028             $body = $output['body'];
S 1029             return $body;
4e17e6 1030         }
T 1031     }
1032
1033     /**
1034      * Returns an array with the headers needed to prepend to the email
1035      * (MIME-Version and Content-Type). Format of argument is:
1036      * $array['header-name'] = 'header-value';
1037      *
091735 1038      * @param array $xtra_headers Assoc array with any extra headers (optional)
6b0113 1039      *                            (Don't set Content-Type for multipart messages here!)
ee289d 1040      * @param bool  $overwrite    Overwrite already existing headers.
e62346 1041      * @param bool  $skip_content Don't return content headers: Content-Type,
091735 1042      *                            Content-Disposition and Content-Transfer-Encoding
ee289d 1043      * 
091735 1044      * @return array              Assoc array with the mime headers
4e17e6 1045      * @access public
T 1046      */
091735 1047     function &headers($xtra_headers = null, $overwrite = false, $skip_content = false)
4e17e6 1048     {
091735 1049         // Add mime version header
4e17e6 1050         $headers['MIME-Version'] = '1.0';
091735 1051
A 1052         // Content-Type and Content-Transfer-Encoding headers should already
1053         // be present if get() was called, but we'll re-set them to make sure
1054         // we got them when called before get() or something in the message
1055         // has been changed after get() [#14780]
1056         if (!$skip_content) {
1057             $headers += $this->_contentHeaders();
1058         }
1059
1060         if (!empty($xtra_headers)) {
4e17e6 1061             $headers = array_merge($headers, $xtra_headers);
T 1062         }
091735 1063
ee289d 1064         if ($overwrite) {
856110 1065             $this->_headers = array_merge($this->_headers, $headers);
ee289d 1066         } else {
856110 1067             $this->_headers = array_merge($headers, $this->_headers);
S 1068         }
4e17e6 1069
091735 1070         $headers = $this->_headers;
A 1071
1072         if ($skip_content) {
1073             unset($headers['Content-Type']);
1074             unset($headers['Content-Transfer-Encoding']);
1075             unset($headers['Content-Disposition']);
6b0113 1076         } else if (!empty($this->_build_params['ctype'])) {
A 1077             $headers['Content-Type'] = $this->_build_params['ctype'];
091735 1078         }
A 1079
1080         $encodedHeaders = $this->_encodeHeaders($headers);
856110 1081         return $encodedHeaders;
4e17e6 1082     }
T 1083
1084     /**
1085      * Get the text version of the headers
1086      * (usefull if you want to use the PHP mail() function)
1087      *
091735 1088      * @param array $xtra_headers Assoc array with any extra headers (optional)
6b0113 1089      *                            (Don't set Content-Type for multipart messages here!)
e62346 1090      * @param bool  $overwrite    Overwrite the existing headers with new.
A 1091      * @param bool  $skip_content Don't return content headers: Content-Type,
1092      *                            Content-Disposition and Content-Transfer-Encoding
ee289d 1093      *
091735 1094      * @return string             Plain text headers
4e17e6 1095      * @access public
T 1096      */
091735 1097     function txtHeaders($xtra_headers = null, $overwrite = false, $skip_content = false)
4e17e6 1098     {
091735 1099         $headers = $this->headers($xtra_headers, $overwrite, $skip_content);
A 1100
1101         // Place Received: headers at the beginning of the message
1102         // Spam detectors often flag messages with it after the Subject: as spam
1103         if (isset($headers['Received'])) {
1104             $received = $headers['Received'];
1105             unset($headers['Received']);
1106             $headers = array('Received' => $received) + $headers;
1107         }
f7f934 1108
4e17e6 1109         $ret = '';
091735 1110         $eol = $this->_build_params['eol'];
A 1111
4e17e6 1112         foreach ($headers as $key => $val) {
091735 1113             if (is_array($val)) {
A 1114                 foreach ($val as $value) {
1115                     $ret .= "$key: $value" . $eol;
1116                 }
1117             } else {
1118                 $ret .= "$key: $val" . $eol;
1119             }
4e17e6 1120         }
091735 1121
4e17e6 1122         return $ret;
T 1123     }
1124
1125     /**
6b0113 1126      * Sets message Content-Type header.
A 1127      * Use it to build messages with various content-types e.g. miltipart/raport
1128      * not supported by _contentHeaders() function.
1129      *
1130      * @param string $type   Type name
1131      * @param array  $params Hash array of header parameters
1132      *
1133      * @return void
1134      * @access public
1135      * @since 1.7.0
1136      */
1137     function setContentType($type, $params = array())
1138     {
1139         $header = $type;
1140
1141         $eol = !empty($this->_build_params['eol'])
1142             ? $this->_build_params['eol'] : "\r\n";
1143
1144         // add parameters
1145         $token_regexp = '#([^\x21,\x23-\x27,\x2A,\x2B,\x2D'
1146             . ',\x2E,\x30-\x39,\x41-\x5A,\x5E-\x7E])#';
1147         if (is_array($params)) {
1148             foreach ($params as $name => $value) {
1149                 if ($name == 'boundary') {
1150                     $this->_build_params['boundary'] = $value;
1151                 }
1152                 if (!preg_match($token_regexp, $value)) {
1153                     $header .= ";$eol $name=$value";
1154                 } else {
1155                     $value = addcslashes($value, '\\"');
1156                     $header .= ";$eol $name=\"$value\"";
1157                 }
1158             }
1159         }
1160
1161         // add required boundary parameter if not defined
1162         if (preg_match('/^multipart\//i', $type)) {
1163             if (empty($this->_build_params['boundary'])) {
8fc810 1164                 $this->_build_params['boundary'] = '=_' . md5(rand() . microtime());
6b0113 1165             }
A 1166
1167             $header .= ";$eol boundary=\"".$this->_build_params['boundary']."\"";
1168         }
1169
1170         $this->_build_params['ctype'] = $header;
1171     }
1172
1173     /**
4e17e6 1174      * Sets the Subject header
T 1175      *
ee289d 1176      * @param string $subject String to set the subject to.
A 1177      *
1178      * @return void
1179      * @access public
4e17e6 1180      */
T 1181     function setSubject($subject)
1182     {
1183         $this->_headers['Subject'] = $subject;
1184     }
1185
1186     /**
1187      * Set an email to the From (the sender) header
1188      *
ee289d 1189      * @param string $email The email address to use
A 1190      *
1191      * @return void
4e17e6 1192      * @access public
T 1193      */
1194     function setFrom($email)
1195     {
1196         $this->_headers['From'] = $email;
1197     }
1198
1199     /**
8fc810 1200      * Add an email to the To header
A 1201      * (multiple calls to this method are allowed)
1202      *
1203      * @param string $email The email direction to add
1204      *
1205      * @return void
1206      * @access public
1207      */
1208     function addTo($email)
1209     {
1210         if (isset($this->_headers['To'])) {
1211             $this->_headers['To'] .= ", $email";
1212         } else {
1213             $this->_headers['To'] = $email;
1214         }
1215     }
1216
1217     /**
4e17e6 1218      * Add an email to the Cc (carbon copy) header
T 1219      * (multiple calls to this method are allowed)
1220      *
ee289d 1221      * @param string $email The email direction to add
A 1222      *
1223      * @return void
4e17e6 1224      * @access public
T 1225      */
1226     function addCc($email)
1227     {
1228         if (isset($this->_headers['Cc'])) {
1229             $this->_headers['Cc'] .= ", $email";
1230         } else {
1231             $this->_headers['Cc'] = $email;
1232         }
1233     }
1234
1235     /**
1236      * Add an email to the Bcc (blank carbon copy) header
1237      * (multiple calls to this method are allowed)
1238      *
ee289d 1239      * @param string $email The email direction to add
A 1240      *
1241      * @return void
4e17e6 1242      * @access public
T 1243      */
1244     function addBcc($email)
1245     {
1246         if (isset($this->_headers['Bcc'])) {
1247             $this->_headers['Bcc'] .= ", $email";
1248         } else {
1249             $this->_headers['Bcc'] = $email;
1250         }
1251     }
1252
1253     /**
091735 1254      * Since the PHP send function requires you to specify
a8435b 1255      * recipients (To: header) separately from the other
S 1256      * headers, the To: header is not properly encoded.
1257      * To fix this, you can use this public method to 
1258      * encode your recipients before sending to the send
1259      * function
1260      *
ee289d 1261      * @param string $recipients A comma-delimited list of recipients
A 1262      *
091735 1263      * @return string            Encoded data
a8435b 1264      * @access public
S 1265      */
1266     function encodeRecipients($recipients)
1267     {
1268         $input = array("To" => $recipients);
1269         $retval = $this->_encodeHeaders($input);
1270         return $retval["To"] ;
1271     }
1272
1273     /**
091735 1274      * Encodes headers as per RFC2047
856110 1275      *
ee289d 1276      * @param array $input  The header data to encode
A 1277      * @param array $params Extra build parameters
1278      *
091735 1279      * @return array        Encoded data
856110 1280      * @access private
S 1281      */
ab6f80 1282     function _encodeHeaders($input, $params = array())
4e17e6 1283     {
ab6f80 1284         $build_params = $this->_build_params;
T 1285         while (list($key, $value) = each($params)) {
1286             $build_params[$key] = $value;
1287         }
f7f934 1288
4e17e6 1289         foreach ($input as $hdr_name => $hdr_value) {
091735 1290             if (is_array($hdr_value)) {
A 1291                 foreach ($hdr_value as $idx => $value) {
1292                     $input[$hdr_name][$idx] = $this->encodeHeader(
1293                         $hdr_name, $value,
1294                         $build_params['head_charset'], $build_params['head_encoding']
1295                     );
ab6f80 1296                 }
091735 1297             } else {
A 1298                 $input[$hdr_name] = $this->encodeHeader(
1299                     $hdr_name, $hdr_value,
1300                     $build_params['head_charset'], $build_params['head_encoding']
1301                 );
ee289d 1302             }
A 1303         }
091735 1304
4e17e6 1305         return $input;
T 1306     }
bb5ddf 1307
4e17e6 1308     /**
091735 1309      * Encodes a header as per RFC2047
4e17e6 1310      *
091735 1311      * @param string $name     The header name
A 1312      * @param string $value    The header data to encode
1313      * @param string $charset  Character set name
1314      * @param string $encoding Encoding name (base64 or quoted-printable)
ee289d 1315      *
091735 1316      * @return string          Encoded header data (without a name)
A 1317      * @access public
1318      * @since 1.5.3
1319      */
1320     function encodeHeader($name, $value, $charset, $encoding)
1321     {
be5133 1322         return Mail_mimePart::encodeHeader(
A 1323             $name, $value, $charset, $encoding, $this->_build_params['eol']
091735 1324         );
4e17e6 1325     }
T 1326
09f19e 1327     /**
A 1328      * Get file's basename (locale independent) 
1329      *
091735 1330      * @param string $filename Filename
09f19e 1331      *
091735 1332      * @return string          Basename
09f19e 1333      * @access private
A 1334      */
1335     function _basename($filename)
1336     {
f7f934 1337         // basename() is not unicode safe and locale dependent
091735 1338         if (stristr(PHP_OS, 'win') || stristr(PHP_OS, 'netware')) {
f7f934 1339             return preg_replace('/^.*[\\\\\\/]/', '', $filename);
091735 1340         } else {
f7f934 1341             return preg_replace('/^.*[\/]/', '', $filename);
091735 1342         }
A 1343     }
1344
1345     /**
1346      * Get Content-Type and Content-Transfer-Encoding headers of the message
1347      *
1348      * @return array Headers array
1349      * @access private
1350      */
1351     function _contentHeaders()
1352     {
1353         $attachments = count($this->_parts)                 ? true : false;
1354         $html_images = count($this->_html_images)           ? true : false;
1355         $html        = strlen($this->_htmlbody)             ? true : false;
1356         $text        = (!$html && strlen($this->_txtbody))  ? true : false;
1357         $headers     = array();
1358
1359         // See get()
1360         switch (true) {
1361         case $text && !$attachments:
1362             $headers['Content-Type'] = 'text/plain';
1363             break;
1364
1365         case !$text && !$html && $attachments:
1366         case $text && $attachments:
1367         case $html && $attachments && !$html_images:
1368         case $html && $attachments && $html_images:
1369             $headers['Content-Type'] = 'multipart/mixed';
1370             break;
1371
1372         case $html && !$attachments && !$html_images && isset($this->_txtbody):
1373         case $html && !$attachments && $html_images && isset($this->_txtbody):
1374             $headers['Content-Type'] = 'multipart/alternative';
1375             break;
1376
1377         case $html && !$attachments && !$html_images && !isset($this->_txtbody):
1378             $headers['Content-Type'] = 'text/html';
1379             break;
1380
1381         case $html && !$attachments && $html_images && !isset($this->_txtbody):
1382             $headers['Content-Type'] = 'multipart/related';
1383             break;
1384
1385         default:
1386             return $headers;
1387         }
1388
be5133 1389         $this->_checkParams();
A 1390
091735 1391         $eol = !empty($this->_build_params['eol'])
A 1392             ? $this->_build_params['eol'] : "\r\n";
1393
1394         if ($headers['Content-Type'] == 'text/plain') {
1395             // single-part message: add charset and encoding
db1a87 1396             $charset = 'charset=' . $this->_build_params['text_charset'];
T 1397             // place charset parameter in the same line, if possible
1398             // 26 = strlen("Content-Type: text/plain; ")
091735 1399             $headers['Content-Type']
db1a87 1400                 .= (strlen($charset) + 26 <= 76) ? "; $charset" : ";$eol $charset";
091735 1401             $headers['Content-Transfer-Encoding']
A 1402                 = $this->_build_params['text_encoding'];
1403         } else if ($headers['Content-Type'] == 'text/html') {
1404             // single-part message: add charset and encoding
db1a87 1405             $charset = 'charset=' . $this->_build_params['html_charset'];
T 1406             // place charset parameter in the same line, if possible
091735 1407             $headers['Content-Type']
db1a87 1408                 .= (strlen($charset) + 25 <= 76) ? "; $charset" : ";$eol $charset";
091735 1409             $headers['Content-Transfer-Encoding']
A 1410                 = $this->_build_params['html_encoding'];
1411         } else {
db1a87 1412             // multipart message: and boundary
091735 1413             if (!empty($this->_build_params['boundary'])) {
A 1414                 $boundary = $this->_build_params['boundary'];
1415             } else if (!empty($this->_headers['Content-Type'])
1416                 && preg_match('/boundary="([^"]+)"/', $this->_headers['Content-Type'], $m)
1417             ) {
1418                 $boundary = $m[1];
1419             } else {
1420                 $boundary = '=_' . md5(rand() . microtime());
1421             }
1422
1423             $this->_build_params['boundary'] = $boundary;
1424             $headers['Content-Type'] .= ";$eol boundary=\"$boundary\"";
1425         }
1426
1427         return $headers;
09f19e 1428     }
4e17e6 1429
be5133 1430     /**
A 1431      * Validate and set build parameters
1432      *
1433      * @return void
1434      * @access private
1435      */
1436     function _checkParams()
1437     {
1438         $encodings = array('7bit', '8bit', 'base64', 'quoted-printable');
1439
1440         $this->_build_params['text_encoding']
1441             = strtolower($this->_build_params['text_encoding']);
1442         $this->_build_params['html_encoding']
1443             = strtolower($this->_build_params['html_encoding']);
1444
1445         if (!in_array($this->_build_params['text_encoding'], $encodings)) {
1446             $this->_build_params['text_encoding'] = '7bit';
1447         }
1448         if (!in_array($this->_build_params['html_encoding'], $encodings)) {
1449             $this->_build_params['html_encoding'] = '7bit';
1450         }
1451
1452         // text body
1453         if ($this->_build_params['text_encoding'] == '7bit'
1454             && !preg_match('/ascii/i', $this->_build_params['text_charset'])
1455             && preg_match('/[^\x00-\x7F]/', $this->_txtbody)
1456         ) {
1457             $this->_build_params['text_encoding'] = 'quoted-printable';
1458         }
1459         // html body
1460         if ($this->_build_params['html_encoding'] == '7bit'
1461             && !preg_match('/ascii/i', $this->_build_params['html_charset'])
1462             && preg_match('/[^\x00-\x7F]/', $this->_htmlbody)
1463         ) {
1464             $this->_build_params['html_encoding'] = 'quoted-printable';
1465         }
1466     }
1467
4e17e6 1468 } // End of class