source: github/program/lib/Mail/mime.php @ ab6f807

HEADcourier-fixdev-browser-capabilitiespdorelease-0.6release-0.7release-0.8
Last change on this file since ab6f807 was ab6f807, checked in by thomascube <thomas@…>, 6 years ago

Updated PEAR::Mail_mime package

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