yllar
2006-12-16 77c28206a14b5bee3f3091f10cffd531bce5649c
commit | author | age
4e17e6 1 <?php
T 2 /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
3 // +-----------------------------------------------------------------------+
4 // | Copyright (c) 2002-2003  Richard Heyes                                |
5 // | Copyright (c) 2003-2005  The PHP Group                                |
15fee7 6 // | All rights reserved.                                                  |
4e17e6 7 // |                                                                       |
T 8 // | Redistribution and use in source and binary forms, with or without    |
9 // | modification, are permitted provided that the following conditions    |
10 // | are met:                                                              |
11 // |                                                                       |
12 // | o Redistributions of source code must retain the above copyright      |
13 // |   notice, this list of conditions and the following disclaimer.       |
14 // | o Redistributions in binary form must reproduce the above copyright   |
15 // |   notice, this list of conditions and the following disclaimer in the |
16 // |   documentation and/or other materials provided with the distribution.|
17 // | o The names of the authors may not be used to endorse or promote      |
18 // |   products derived from this software without specific prior written  |
19 // |   permission.                                                         |
20 // |                                                                       |
21 // | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS   |
22 // | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT     |
23 // | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
24 // | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT  |
25 // | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
26 // | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT      |
27 // | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
28 // | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
29 // | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT   |
30 // | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
31 // | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.  |
32 // |                                                                       |
33 // +-----------------------------------------------------------------------+
34 // | Author: Richard Heyes <richard@phpguru.org>                           |
35 // |         Tomas V.V.Cox <cox@idecnet.com> (port to PEAR)                |
36 // +-----------------------------------------------------------------------+
37 //
38 // $Id$
39
40 require_once('PEAR.php');
41 require_once('Mail/mimePart.php');
42
43 /**
44  * Mime mail composer class. Can handle: text and html bodies, embedded html
45  * images and attachments.
46  * Documentation and examples of this class are avaible here:
47  * http://pear.php.net/manual/
48  *
49  * @notes This class is based on HTML Mime Mail class from
50  *   Richard Heyes <richard@phpguru.org> which was based also
51  *   in the mime_mail.class by Tobias Ratschiller <tobias@dnet.it> and
52  *   Sascha Schumann <sascha@schumann.cx>
53  *
54  * @author   Richard Heyes <richard.heyes@heyes-computing.net>
55  * @author   Tomas V.V.Cox <cox@idecnet.com>
56  * @package  Mail
57  * @access   public
58  */
59 class Mail_mime
60 {
61     /**
62      * Contains the plain text part of the email
63      * @var string
64      */
65     var $_txtbody;
66     /**
67      * Contains the html part of the email
68      * @var string
69      */
70     var $_htmlbody;
71     /**
72      * contains the mime encoded text
73      * @var string
74      */
75     var $_mime;
76     /**
77      * contains the multipart content
78      * @var string
79      */
80     var $_multipart;
81     /**
82      * list of the attached images
83      * @var array
84      */
85     var $_html_images = array();
86     /**
87      * list of the attachements
88      * @var array
89      */
90     var $_parts = array();
91     /**
92      * Build parameters
93      * @var array
94      */
95     var $_build_params = array();
96     /**
97      * Headers for the mail
98      * @var array
99      */
100     var $_headers = array();
101     /**
102      * End Of Line sequence (for serialize)
103      * @var string
104      */
105     var $_eol;
106
107
108     /**
109      * Constructor function
110      *
111      * @access public
112      */
113     function Mail_mime($crlf = "\r\n")
114     {
115         $this->_setEOL($crlf);
116         $this->_build_params = array(
a8435b 117                                      'head_encoding' => 'quoted-printable',
4e17e6 118                                      'text_encoding' => '7bit',
T 119                                      'html_encoding' => 'quoted-printable',
120                                      '7bit_wrap'     => 998,
121                                      'html_charset'  => 'ISO-8859-1',
122                                      'text_charset'  => 'ISO-8859-1',
123                                      'head_charset'  => 'ISO-8859-1'
124                                     );
125     }
126
127     /**
128      * Wakeup (unserialize) - re-sets EOL constant
129      *
130      * @access private
131      */
132     function __wakeup()
133     {
134         $this->_setEOL($this->_eol);
135     }
136
137     /**
138      * Accessor function to set the body text. Body text is used if
139      * it's not an html mail being sent or else is used to fill the
140      * text/plain part that emails clients who don't support
141      * html should show.
142      *
143      * @param  string  $data   Either a string or
144      *                         the file name with the contents
145      * @param  bool    $isfile If true the first param should be treated
146      *                         as a file name, else as a string (default)
147      * @param  bool    $append If true the text or file is appended to
148      *                         the existing body, else the old body is
149      *                         overwritten
150      * @return mixed   true on success or PEAR_Error object
151      * @access public
152      */
153     function setTXTBody($data, $isfile = false, $append = false)
154     {
155         if (!$isfile) {
156             if (!$append) {
157                 $this->_txtbody = $data;
158             } else {
159                 $this->_txtbody .= $data;
160             }
161         } else {
162             $cont = $this->_file2str($data);
163             if (PEAR::isError($cont)) {
164                 return $cont;
165             }
166             if (!$append) {
167                 $this->_txtbody = $cont;
168             } else {
169                 $this->_txtbody .= $cont;
170             }
171         }
172         return true;
173     }
174
175     /**
176      * Adds a html part to the mail
177      *
178      * @param  string  $data   Either a string or the file name with the
179      *                         contents
180      * @param  bool    $isfile If true the first param should be treated
181      *                         as a file name, else as a string (default)
182      * @return mixed   true on success or PEAR_Error object
183      * @access public
184      */
185     function setHTMLBody($data, $isfile = false)
186     {
187         if (!$isfile) {
188             $this->_htmlbody = $data;
189         } else {
190             $cont = $this->_file2str($data);
191             if (PEAR::isError($cont)) {
192                 return $cont;
193             }
194             $this->_htmlbody = $cont;
195         }
196
197         return true;
198     }
199
200     /**
a0109c 201     * returns the HTML body portion of the message
S 202     * @return string HTML body of the message
203     * @access public
204     */
205     function getHTMLBody()
206     {
207        return $this->_htmlbody;
208     }
209     
210     /**
4e17e6 211      * Adds an image to the list of embedded images.
T 212      *
213      * @param  string  $file       The image file name OR image data itself
214      * @param  string  $c_type     The content type
215      * @param  string  $name       The filename of the image.
216      *                             Only use if $file is the image data
217      * @param  bool    $isfilename Whether $file is a filename or not
218      *                             Defaults to true
a0109c 219      * @param  string  $contentid  Desired Content-ID of MIME part
S 220      *                             Defaults to generated unique ID
4e17e6 221      * @return mixed   true on success or PEAR_Error object
T 222      * @access public
223      */
224     function addHTMLImage($file, $c_type='application/octet-stream',
a0109c 225                           $name = '', $isfilename = true, $contentid = '')
4e17e6 226     {
T 227         $filedata = ($isfilename === true) ? $this->_file2str($file)
228                                            : $file;
229         if ($isfilename === true) {
856110 230             $filename = ($name == '' ? $file : $name);
4e17e6 231         } else {
856110 232             $filename = $name;
4e17e6 233         }
T 234         if (PEAR::isError($filedata)) {
235             return $filedata;
236         }
a0109c 237         if ($contentid == '') {
S 238            $contentid = md5(uniqid(time()));
239         }
4e17e6 240         $this->_html_images[] = array(
T 241                                       'body'   => $filedata,
242                                       'name'   => $filename,
243                                       'c_type' => $c_type,
a0109c 244                                       'cid'    => $contentid
4e17e6 245                                      );
T 246         return true;
247     }
248
249     /**
250      * Adds a file to the list of attachments.
251      *
856110 252      * @param  string  $file        The file name of the file to attach
S 253      *                              OR the file contents itself
254      * @param  string  $c_type      The content type
255      * @param  string  $name        The filename of the attachment
256      *                              Only use if $file is the contents
257      * @param  bool    $isFilename  Whether $file is a filename or not
258      *                              Defaults to true
259      * @param  string  $encoding    The type of encoding to use.
260      *                              Defaults to base64.
261      *                              Possible values: 7bit, 8bit, base64, 
262      *                              or quoted-printable.
263      * @param  string  $disposition The content-disposition of this file
264      *                              Defaults to attachment.
265      *                              Possible values: attachment, inline.
a8435b 266      * @param  string  $charset     The character set used in the filename
S 267      *                              of this attachment.
4e17e6 268      * @return mixed true on success or PEAR_Error object
T 269      * @access public
270      */
271     function addAttachment($file, $c_type = 'application/octet-stream',
272                            $name = '', $isfilename = true,
856110 273                            $encoding = 'base64',
a8435b 274                            $disposition = 'attachment', $charset = '')
4e17e6 275     {
T 276         $filedata = ($isfilename === true) ? $this->_file2str($file)
277                                            : $file;
278         if ($isfilename === true) {
279             // Force the name the user supplied, otherwise use $file
280             $filename = (!empty($name)) ? $name : $file;
281         } else {
282             $filename = $name;
283         }
284         if (empty($filename)) {
856110 285             $err = PEAR::raiseError(
S 286               "The supplied filename for the attachment can't be empty"
4e17e6 287             );
856110 288         return $err;
4e17e6 289         }
T 290         $filename = basename($filename);
291         if (PEAR::isError($filedata)) {
292             return $filedata;
293         }
294
295         $this->_parts[] = array(
856110 296                                 'body'        => $filedata,
S 297                                 'name'        => $filename,
298                                 'c_type'      => $c_type,
299                                 'encoding'    => $encoding,
a8435b 300                                 'charset'     => $charset,
856110 301                                 'disposition' => $disposition
4e17e6 302                                );
T 303         return true;
304     }
305
306     /**
307      * Get the contents of the given file name as string
308      *
309      * @param  string  $file_name  path of file to process
310      * @return string  contents of $file_name
311      * @access private
312      */
313     function &_file2str($file_name)
314     {
315         if (!is_readable($file_name)) {
856110 316             $err = PEAR::raiseError('File is not readable ' . $file_name);
S 317             return $err;
4e17e6 318         }
T 319         if (!$fd = fopen($file_name, 'rb')) {
856110 320             $err = PEAR::raiseError('Could not open ' . $file_name);
S 321             return $err;
4e17e6 322         }
15fee7 323         $filesize = filesize($file_name);
T 324         if ($filesize == 0){
325             $cont =  "";
326         }else{
856110 327             if ($magic_quote_setting = get_magic_quotes_runtime()){
S 328                 set_magic_quotes_runtime(0);
329             }
15fee7 330             $cont = fread($fd, $filesize);
856110 331             if ($magic_quote_setting){
S 332                 set_magic_quotes_runtime($magic_quote_setting);
333             }
15fee7 334         }
4e17e6 335         fclose($fd);
T 336         return $cont;
337     }
338
339     /**
340      * Adds a text subpart to the mimePart object and
341      * returns it during the build process.
342      *
343      * @param mixed    The object to add the part to, or
344      *                 null if a new object is to be created.
345      * @param string   The text to add.
346      * @return object  The text mimePart object
347      * @access private
348      */
349     function &_addTextPart(&$obj, $text)
350     {
351         $params['content_type'] = 'text/plain';
352         $params['encoding']     = $this->_build_params['text_encoding'];
353         $params['charset']      = $this->_build_params['text_charset'];
354         if (is_object($obj)) {
856110 355             $ret = $obj->addSubpart($text, $params);
S 356             return $ret;
4e17e6 357         } else {
856110 358             $ret = new Mail_mimePart($text, $params);
S 359             return $ret;
4e17e6 360         }
T 361     }
362
363     /**
364      * Adds a html subpart to the mimePart object and
365      * returns it during the build process.
366      *
367      * @param  mixed   The object to add the part to, or
368      *                 null if a new object is to be created.
369      * @return object  The html mimePart object
370      * @access private
371      */
372     function &_addHtmlPart(&$obj)
373     {
374         $params['content_type'] = 'text/html';
375         $params['encoding']     = $this->_build_params['html_encoding'];
376         $params['charset']      = $this->_build_params['html_charset'];
377         if (is_object($obj)) {
856110 378             $ret = $obj->addSubpart($this->_htmlbody, $params);
S 379             return $ret;
4e17e6 380         } else {
856110 381             $ret = new Mail_mimePart($this->_htmlbody, $params);
S 382             return $ret;
4e17e6 383         }
T 384     }
385
386     /**
387      * Creates a new mimePart object, using multipart/mixed as
388      * the initial content-type and returns it during the
389      * build process.
390      *
391      * @return object  The multipart/mixed mimePart object
392      * @access private
393      */
394     function &_addMixedPart()
395     {
396         $params['content_type'] = 'multipart/mixed';
856110 397         $ret = new Mail_mimePart('', $params);
S 398         return $ret;
4e17e6 399     }
T 400
401     /**
402      * Adds a multipart/alternative part to a mimePart
403      * object (or creates one), and returns it during
404      * the build process.
405      *
406      * @param  mixed   The object to add the part to, or
407      *                 null if a new object is to be created.
408      * @return object  The multipart/mixed mimePart object
409      * @access private
410      */
411     function &_addAlternativePart(&$obj)
412     {
413         $params['content_type'] = 'multipart/alternative';
414         if (is_object($obj)) {
415             return $obj->addSubpart('', $params);
416         } else {
856110 417             $ret = new Mail_mimePart('', $params);
S 418             return $ret;
4e17e6 419         }
T 420     }
421
422     /**
423      * Adds a multipart/related part to a mimePart
424      * object (or creates one), and returns it during
425      * the build process.
426      *
427      * @param mixed    The object to add the part to, or
428      *                 null if a new object is to be created
429      * @return object  The multipart/mixed mimePart object
430      * @access private
431      */
432     function &_addRelatedPart(&$obj)
433     {
434         $params['content_type'] = 'multipart/related';
435         if (is_object($obj)) {
436             return $obj->addSubpart('', $params);
437         } else {
856110 438             $ret = new Mail_mimePart('', $params);
S 439             return $ret;
4e17e6 440         }
T 441     }
442
443     /**
444      * Adds an html image subpart to a mimePart object
445      * and returns it during the build process.
446      *
447      * @param  object  The mimePart to add the image to
448      * @param  array   The image information
449      * @return object  The image mimePart object
450      * @access private
451      */
452     function &_addHtmlImagePart(&$obj, $value)
453     {
856110 454         $params['content_type'] = $value['c_type'] . '; ' .
a8435b 455                                   'name="' . $value['name'] . '"';
4e17e6 456         $params['encoding']     = 'base64';
T 457         $params['disposition']  = 'inline';
458         $params['dfilename']    = $value['name'];
459         $params['cid']          = $value['cid'];
856110 460         $ret = $obj->addSubpart($value['body'], $params);
S 461         return $ret;
462     
4e17e6 463     }
T 464
465     /**
466      * Adds an attachment subpart to a mimePart object
467      * and returns it during the build process.
468      *
469      * @param  object  The mimePart to add the image to
470      * @param  array   The attachment information
471      * @return object  The image mimePart object
472      * @access private
473      */
474     function &_addAttachmentPart(&$obj, $value)
475     {
a8435b 476         $params['dfilename']    = $value['name'];
S 477         $params['encoding']     = $value['encoding'];
478         if ($value['disposition'] != "inline") {
479             $fname = array("fname" => $value['name']);
480             $fname_enc = $this->_encodeHeaders($fname);
481             $params['dfilename'] = $fname_enc['fname'];
482         }
483         if ($value['charset']) {
484             $params['charset'] = $value['charset'];
485         }
856110 486         $params['content_type'] = $value['c_type'] . '; ' .
S 487                                   'name="' . $params['dfilename'] . '"';
488         $params['disposition']  = isset($value['disposition']) ? 
489                                   $value['disposition'] : 'attachment';
490         $ret = $obj->addSubpart($value['body'], $params);
491         return $ret;
4e17e6 492     }
856110 493
S 494     /**
495      * Returns the complete e-mail, ready to send using an alternative
496      * mail delivery method. Note that only the mailpart that is made
497      * with Mail_Mime is created. This means that,
498      * YOU WILL HAVE NO TO: HEADERS UNLESS YOU SET IT YOURSELF 
499      * using the $xtra_headers parameter!
500      * 
501      * @param  string $separation   The separation etween these two parts.
502      * @param  array  $build_params The Build parameters passed to the
503      *                              &get() function. See &get for more info.
504      * @param  array  $xtra_headers The extra headers that should be passed
505      *                              to the &headers() function.
506      *                              See that function for more info.
507      * @param  bool   $overwrite    Overwrite the existing headers with new.
508      * @return string The complete e-mail.
509      * @access public
510      */
511     function getMessage($separation = null, $build_params = null, $xtra_headers = null, $overwrite = false)
512     {
513         if ($separation === null)
514         {
515             $separation = MAIL_MIME_CRLF;
516         }
517         $body = $this->get($build_params);
518         $head = $this->txtHeaders($xtra_headers, $overwrite);
519         $mail = $head . $separation . $body;
520         return $mail;
521     }
522
4e17e6 523
T 524     /**
525      * Builds the multipart message from the list ($this->_parts) and
526      * returns the mime content.
527      *
528      * @param  array  Build parameters that change the way the email
529      *                is built. Should be associative. Can contain:
a8435b 530      *                head_encoding  -  What encoding to use for the headers. 
S 531      *                                  Options: quoted-printable or base64
532      *                                  Default is quoted-printable
4e17e6 533      *                text_encoding  -  What encoding to use for plain text
a8435b 534      *                                  Options: 7bit, 8bit, base64, or quoted-printable
4e17e6 535      *                                  Default is 7bit
T 536      *                html_encoding  -  What encoding to use for html
a8435b 537      *                                  Options: 7bit, 8bit, base64, or quoted-printable
4e17e6 538      *                                  Default is quoted-printable
T 539      *                7bit_wrap      -  Number of characters before text is
540      *                                  wrapped in 7bit encoding
541      *                                  Default is 998
542      *                html_charset   -  The character set to use for html.
543      *                                  Default is iso-8859-1
544      *                text_charset   -  The character set to use for text.
545      *                                  Default is iso-8859-1
546      *                head_charset   -  The character set to use for headers.
547      *                                  Default is iso-8859-1
548      * @return string The mime content
549      * @access public
550      */
551     function &get($build_params = null)
552     {
553         if (isset($build_params)) {
554             while (list($key, $value) = each($build_params)) {
555                 $this->_build_params[$key] = $value;
556             }
557         }
558
559         if (!empty($this->_html_images) AND isset($this->_htmlbody)) {
856110 560             foreach ($this->_html_images as $key => $value) {
S 561                 $regex = array();
562                 $regex[] = '#(\s)((?i)src|background|href(?-i))\s*=\s*(["\']?)' .
563                             preg_quote($value['name'], '#') . '\3#';
564                 $regex[] = '#(?i)url(?-i)\(\s*(["\']?)' .
565                             preg_quote($value['name'], '#') . '\1\s*\)#';
566                 $rep = array();
567                 $rep[] = '\1\2=\3cid:' . $value['cid'] .'\3';
568                 $rep[] = 'url(\1cid:' . $value['cid'] . '\2)';
4e17e6 569                 $this->_htmlbody = preg_replace($regex, $rep,
T 570                                        $this->_htmlbody
571                                    );
856110 572                 $this->_html_images[$key]['name'] = basename($this->_html_images[$key]['name']);
4e17e6 573             }
T 574         }
575
576         $null        = null;
577         $attachments = !empty($this->_parts)                ? true : false;
578         $html_images = !empty($this->_html_images)          ? true : false;
579         $html        = !empty($this->_htmlbody)             ? true : false;
580         $text        = (!$html AND !empty($this->_txtbody)) ? true : false;
581
582         switch (true) {
583         case $text AND !$attachments:
584             $message =& $this->_addTextPart($null, $this->_txtbody);
585             break;
586
587         case !$text AND !$html AND $attachments:
588             $message =& $this->_addMixedPart();
589             for ($i = 0; $i < count($this->_parts); $i++) {
590                 $this->_addAttachmentPart($message, $this->_parts[$i]);
591             }
592             break;
593
594         case $text AND $attachments:
595             $message =& $this->_addMixedPart();
596             $this->_addTextPart($message, $this->_txtbody);
597             for ($i = 0; $i < count($this->_parts); $i++) {
598                 $this->_addAttachmentPart($message, $this->_parts[$i]);
599             }
600             break;
601
602         case $html AND !$attachments AND !$html_images:
603             if (isset($this->_txtbody)) {
604                 $message =& $this->_addAlternativePart($null);
605                 $this->_addTextPart($message, $this->_txtbody);
606                 $this->_addHtmlPart($message);
607             } else {
608                 $message =& $this->_addHtmlPart($null);
609             }
610             break;
611
612         case $html AND !$attachments AND $html_images:
613             if (isset($this->_txtbody)) {
614                 $message =& $this->_addAlternativePart($null);
615                 $this->_addTextPart($message, $this->_txtbody);
616                 $related =& $this->_addRelatedPart($message);
617             } else {
618                 $message =& $this->_addRelatedPart($null);
619                 $related =& $message;
620             }
621             $this->_addHtmlPart($related);
622             for ($i = 0; $i < count($this->_html_images); $i++) {
623                 $this->_addHtmlImagePart($related, $this->_html_images[$i]);
624             }
625             break;
626
627         case $html AND $attachments AND !$html_images:
628             $message =& $this->_addMixedPart();
629             if (isset($this->_txtbody)) {
630                 $alt =& $this->_addAlternativePart($message);
631                 $this->_addTextPart($alt, $this->_txtbody);
632                 $this->_addHtmlPart($alt);
633             } else {
634                 $this->_addHtmlPart($message);
635             }
636             for ($i = 0; $i < count($this->_parts); $i++) {
637                 $this->_addAttachmentPart($message, $this->_parts[$i]);
638             }
639             break;
640
641         case $html AND $attachments AND $html_images:
642             $message =& $this->_addMixedPart();
643             if (isset($this->_txtbody)) {
644                 $alt =& $this->_addAlternativePart($message);
645                 $this->_addTextPart($alt, $this->_txtbody);
646                 $rel =& $this->_addRelatedPart($alt);
647             } else {
648                 $rel =& $this->_addRelatedPart($message);
649             }
650             $this->_addHtmlPart($rel);
651             for ($i = 0; $i < count($this->_html_images); $i++) {
652                 $this->_addHtmlImagePart($rel, $this->_html_images[$i]);
653             }
654             for ($i = 0; $i < count($this->_parts); $i++) {
655                 $this->_addAttachmentPart($message, $this->_parts[$i]);
656             }
657             break;
658
659         }
660
661         if (isset($message)) {
662             $output = $message->encode();
663             $this->_headers = array_merge($this->_headers,
664                                           $output['headers']);
856110 665             $body = $output['body'];
S 666             return $body;
4e17e6 667
T 668         } else {
856110 669             $ret = false;
S 670             return $ret;
4e17e6 671         }
T 672     }
673
674     /**
675      * Returns an array with the headers needed to prepend to the email
676      * (MIME-Version and Content-Type). Format of argument is:
677      * $array['header-name'] = 'header-value';
678      *
679      * @param  array $xtra_headers Assoc array with any extra headers.
680      *                             Optional.
856110 681      * @param  bool  $overwrite    Overwrite already existing headers.
4e17e6 682      * @return array Assoc array with the mime headers
T 683      * @access public
684      */
856110 685     function &headers($xtra_headers = null, $overwrite = false)
4e17e6 686     {
T 687         // Content-Type header should already be present,
688         // So just add mime version header
689         $headers['MIME-Version'] = '1.0';
690         if (isset($xtra_headers)) {
691             $headers = array_merge($headers, $xtra_headers);
692         }
856110 693         if ($overwrite){
S 694             $this->_headers = array_merge($this->_headers, $headers);
695         }else{
696             $this->_headers = array_merge($headers, $this->_headers);
697         }
4e17e6 698
856110 699         $encodedHeaders = $this->_encodeHeaders($this->_headers);
S 700         return $encodedHeaders;
4e17e6 701     }
T 702
703     /**
704      * Get the text version of the headers
705      * (usefull if you want to use the PHP mail() function)
706      *
707      * @param  array   $xtra_headers Assoc array with any extra headers.
708      *                               Optional.
856110 709      * @param  bool    $overwrite    Overwrite the existing heaers with new.
4e17e6 710      * @return string  Plain text headers
T 711      * @access public
712      */
856110 713     function txtHeaders($xtra_headers = null, $overwrite = false)
4e17e6 714     {
856110 715         $headers = $this->headers($xtra_headers, $overwrite);
4e17e6 716         $ret = '';
T 717         foreach ($headers as $key => $val) {
718             $ret .= "$key: $val" . MAIL_MIME_CRLF;
719         }
720         return $ret;
721     }
722
723     /**
724      * Sets the Subject header
725      *
726      * @param  string $subject String to set the subject to
727      * access  public
728      */
729     function setSubject($subject)
730     {
731         $this->_headers['Subject'] = $subject;
732     }
733
734     /**
735      * Set an email to the From (the sender) header
736      *
737      * @param  string $email The email direction to add
738      * @access public
739      */
740     function setFrom($email)
741     {
742         $this->_headers['From'] = $email;
743     }
744
745     /**
746      * Add an email to the Cc (carbon copy) header
747      * (multiple calls to this method are allowed)
748      *
749      * @param  string $email The email direction to add
750      * @access public
751      */
752     function addCc($email)
753     {
754         if (isset($this->_headers['Cc'])) {
755             $this->_headers['Cc'] .= ", $email";
756         } else {
757             $this->_headers['Cc'] = $email;
758         }
759     }
760
761     /**
762      * Add an email to the Bcc (blank carbon copy) header
763      * (multiple calls to this method are allowed)
764      *
765      * @param  string $email The email direction to add
766      * @access public
767      */
768     function addBcc($email)
769     {
770         if (isset($this->_headers['Bcc'])) {
771             $this->_headers['Bcc'] .= ", $email";
772         } else {
773             $this->_headers['Bcc'] = $email;
774         }
775     }
776
777     /**
a8435b 778      * Since the PHP send function requires you to specifiy 
S 779      * recipients (To: header) separately from the other
780      * headers, the To: header is not properly encoded.
781      * To fix this, you can use this public method to 
782      * encode your recipients before sending to the send
783      * function
784      *
785      * @param  string $recipients A comma-delimited list of recipients
786      * @return string Encoded data
787      * @access public
788      */
789     function encodeRecipients($recipients)
790     {
791         $input = array("To" => $recipients);
792         $retval = $this->_encodeHeaders($input);
793         return $retval["To"] ;
794     }
795
796     /**
856110 797      * Encodes a header as per RFC2047
S 798      *
a8435b 799      * @param  array $input The header data to encode
S 800      * @return array Encoded data
856110 801      * @access private
S 802      */
4e17e6 803     function _encodeHeaders($input)
T 804     {
bb5ddf 805         $maxlen = 73;
4e17e6 806         foreach ($input as $hdr_name => $hdr_value) {
bb5ddf 807             // if header contains e-mail addresses
T 808             if (preg_match('/\s<.+@[a-z0-9\-\.]+\.[a-z]+>/U', $hdr_value))
809                 $chunks = $this->_explode_quoted_string(',', $hdr_value);
810             else
811                $chunks = array($hdr_value);
a8435b 812
bb5ddf 813             $hdr_value = '';
T 814             $line_len = 0;
815
816             foreach ($chunks as $i => $value) {
817                 $value = trim($value);
818
819                 //This header contains non ASCII chars and should be encoded.
820                 if (preg_match('#[\x80-\xFF]{1}#', $value)) {
821                     $suffix = '';
822                     // Don't encode e-mail address
b517af 823                     if (preg_match('/(.+)\s(<.+@[a-z0-9\-\.]+>)$/Ui', $value, $matches)) {
bb5ddf 824                         $value = $matches[1];
T 825                         $suffix = ' '.$matches[2];
a8435b 826                     }
bb5ddf 827
T 828                     switch ($this->_build_params['head_encoding']) {
829                     case 'base64':
830                         // Base64 encoding has been selected.
831                         $mode = 'B';
832                         $encoded = base64_encode($value);
833                         break;
834
835                     case 'quoted-printable':
836                     default:
837                         // quoted-printable encoding has been selected
838                         $mode = 'Q';
839                         $encoded = preg_replace('/([\x20-\x25\x2C\x80-\xFF])/e', "'='.sprintf('%02X', ord('\\1'))", $value);
840                         // replace spaces with _
841                         $encoded = str_replace('=20', '_', $encoded);
842                     }
843
844                 $value = '=?' . $this->_build_params['head_charset'] . '?' . $mode . '?' . $encoded . '?=' . $suffix;
845                 }
846
847                 // add chunk to output string by regarding the header maxlen
848                 $len = strlen($value);
849                 if ($line_len + $len < $maxlen) {
850                     $hdr_value .= ($i>0?', ':'') . $value;
851                     $line_len += $len + ($i>0?2:0);
852                 }
853                 else {
854                     $hdr_value .= ($i>0?', ':'') . "\n " . $value;
855                     $line_len = $len;
a8435b 856                 }
4e17e6 857             }
8acab0 858
4e17e6 859             $input[$hdr_name] = $hdr_value;
T 860         }
856110 861
4e17e6 862         return $input;
T 863     }
864
bb5ddf 865
T 866   function _explode_quoted_string($delimiter, $string)
867     {
868     $quotes = explode("\"", $string);
869     foreach ($quotes as $key => $val)
870       if (($key % 2) == 1)
871         $quotes[$key] = str_replace($delimiter, "_!@!_", $quotes[$key]);
872
873     $string = implode("\"", $quotes);
874
875     $result = explode($delimiter, $string);
876     foreach ($result as $key => $val) 
877       $result[$key] = str_replace("_!@!_", $delimiter, $result[$key]);
878
879     return $result;
880     }
881
882
4e17e6 883     /**
T 884      * Set the object's end-of-line and define the constant if applicable
885      *
886      * @param string $eol End Of Line sequence
887      * @access private
888      */
889     function _setEOL($eol)
890     {
891         $this->_eol = $eol;
892         if (!defined('MAIL_MIME_CRLF')) {
893             define('MAIL_MIME_CRLF', $this->_eol, true);
894         }
895     }
896
897     
898
899 } // End of class
900 ?>
a8435b 901