comparison vendor/pear/mail_mime/Mail/mime.php @ 0:1e000243b222

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