Fixing a small css issue in the user class.
[elgg.git] / lib / phpmailer / class.phpmailer.php
blob759b5e6951c03b54f5916eb0c46991466bd1cde5
1 <?php
2 ////////////////////////////////////////////////////
3 // PHPMailer - PHP email class
4 //
5 // Class for sending email using either
6 // sendmail, PHP mail(), or SMTP. Methods are
7 // based upon the standard AspEmail(tm) classes.
8 //
9 // Copyright (C) 2001 - 2003 Brent R. Matzelle
11 // License: LGPL, see LICENSE
12 ////////////////////////////////////////////////////
14 /**
15 * PHPMailer - PHP email transport class
16 * @package PHPMailer
17 * @author Brent R. Matzelle
18 * @copyright 2001 - 2003 Brent R. Matzelle
20 class PHPMailer
22 /////////////////////////////////////////////////
23 // PUBLIC VARIABLES
24 /////////////////////////////////////////////////
26 /**
27 * Email priority (1 = High, 3 = Normal, 5 = low).
28 * @var int
30 var $Priority = 3;
32 /**
33 * Sets the CharSet of the message.
34 * @var string
36 var $CharSet = "iso-8859-1";
38 /**
39 * Sets the Content-type of the message.
40 * @var string
42 var $ContentType = "text/plain";
44 /**
45 * Sets the Encoding of the message. Options for this are "8bit",
46 * "7bit", "binary", "base64", and "quoted-printable".
47 * @var string
49 var $Encoding = "8bit";
51 /**
52 * Holds the most recent mailer error message.
53 * @var string
55 var $ErrorInfo = "";
57 /**
58 * Sets the From email address for the message.
59 * @var string
61 var $From = "root@localhost";
63 /**
64 * Sets the From name of the message.
65 * @var string
67 var $FromName = "Root User";
69 /**
70 * Sets the Sender email (Return-Path) of the message. If not empty,
71 * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
72 * @var string
74 var $Sender = "";
76 /**
77 * Sets the Subject of the message.
78 * @var string
80 var $Subject = "";
82 /**
83 * Sets the Body of the message. This can be either an HTML or text body.
84 * If HTML then run IsHTML(true).
85 * @var string
87 var $Body = "";
89 /**
90 * Sets the text-only body of the message. This automatically sets the
91 * email to multipart/alternative. This body can be read by mail
92 * clients that do not have HTML email capability such as mutt. Clients
93 * that can read HTML will view the normal Body.
94 * @var string
96 var $AltBody = "";
98 /**
99 * Sets word wrapping on the body of the message to a given number of
100 * characters.
101 * @var int
103 var $WordWrap = 0;
106 * Method to send mail: ("mail", "sendmail", or "smtp").
107 * @var string
109 var $Mailer = "mail";
112 * Sets the path of the sendmail program.
113 * @var string
115 var $Sendmail = "/usr/sbin/sendmail";
118 * Path to PHPMailer plugins. This is now only useful if the SMTP class
119 * is in a different directory than the PHP include path.
120 * @var string
122 var $PluginDir = "";
125 * Holds PHPMailer version.
126 * @var string
128 var $Version = "1.73";
131 * Sets the email address that a reading confirmation will be sent.
132 * @var string
134 var $ConfirmReadingTo = "";
137 * Sets the hostname to use in Message-Id and Received headers
138 * and as default HELO string. If empty, the value returned
139 * by SERVER_NAME is used or 'localhost.localdomain'.
140 * @var string
142 var $Hostname = "";
144 /////////////////////////////////////////////////
145 // SMTP VARIABLES
146 /////////////////////////////////////////////////
149 * Sets the SMTP hosts. All hosts must be separated by a
150 * semicolon. You can also specify a different port
151 * for each host by using this format: [hostname:port]
152 * (e.g. "smtp1.example.com:25;smtp2.example.com").
153 * Hosts will be tried in order.
154 * @var string
156 var $Host = "localhost";
159 * Sets the default SMTP server port.
160 * @var int
162 var $Port = 25;
165 * Sets the SMTP HELO of the message (Default is $Hostname).
166 * @var string
168 var $Helo = "";
171 * Sets SMTP authentication. Utilizes the Username and Password variables.
172 * @var bool
174 var $SMTPAuth = false;
177 * Sets SMTP username.
178 * @var string
180 var $Username = "";
183 * Sets SMTP password.
184 * @var string
186 var $Password = "";
189 * Sets the SMTP server timeout in seconds. This function will not
190 * work with the win32 version.
191 * @var int
193 var $Timeout = 10;
196 * Sets SMTP class debugging on or off.
197 * @var bool
199 var $SMTPDebug = false;
202 * Prevents the SMTP connection from being closed after each mail
203 * sending. If this is set to true then to close the connection
204 * requires an explicit call to SmtpClose().
205 * @var bool
207 var $SMTPKeepAlive = false;
209 /**#@+
210 * @access private
212 var $smtp = NULL;
213 var $to = array();
214 var $cc = array();
215 var $bcc = array();
216 var $ReplyTo = array();
217 var $attachment = array();
218 var $CustomHeader = array();
219 var $message_type = "";
220 var $boundary = array();
221 var $language = array();
222 var $error_count = 0;
223 var $LE = "\n";
224 /**#@-*/
226 /////////////////////////////////////////////////
227 // VARIABLE METHODS
228 /////////////////////////////////////////////////
231 * Constructor
232 * Hack for Moodle as class may be included from various locations
233 * SE 20041001
234 * @param void
235 * @return void
237 function PHPMailer () {
238 global $CFG;
239 $this->PluginDir = $CFG->libdir.'/phpmailer/';
245 * Sets message type to HTML.
246 * @param bool $bool
247 * @return void
249 function IsHTML($bool) {
250 if($bool == true)
251 $this->ContentType = "text/html";
252 else
253 $this->ContentType = "text/plain";
257 * Sets Mailer to send message using SMTP.
258 * @return void
260 function IsSMTP() {
261 $this->Mailer = "smtp";
265 * Sets Mailer to send message using PHP mail() function.
266 * @return void
268 function IsMail() {
269 $this->Mailer = "mail";
273 * Sets Mailer to send message using the $Sendmail program.
274 * @return void
276 function IsSendmail() {
277 $this->Mailer = "sendmail";
281 * Sets Mailer to send message using the qmail MTA.
282 * @return void
284 function IsQmail() {
285 $this->Sendmail = "/var/qmail/bin/sendmail";
286 $this->Mailer = "sendmail";
290 /////////////////////////////////////////////////
291 // RECIPIENT METHODS
292 /////////////////////////////////////////////////
295 * Adds a "To" address.
296 * @param string $address
297 * @param string $name
298 * @return void
300 function AddAddress($address, $name = "") {
301 $cur = count($this->to);
302 $this->to[$cur][0] = trim($address);
303 $this->to[$cur][1] = $name;
307 * Adds a "Cc" address. Note: this function works
308 * with the SMTP mailer on win32, not with the "mail"
309 * mailer.
310 * @param string $address
311 * @param string $name
312 * @return void
314 function AddCC($address, $name = "") {
315 $cur = count($this->cc);
316 $this->cc[$cur][0] = trim($address);
317 $this->cc[$cur][1] = $name;
321 * Adds a "Bcc" address. Note: this function works
322 * with the SMTP mailer on win32, not with the "mail"
323 * mailer.
324 * @param string $address
325 * @param string $name
326 * @return void
328 function AddBCC($address, $name = "") {
329 $cur = count($this->bcc);
330 $this->bcc[$cur][0] = trim($address);
331 $this->bcc[$cur][1] = $name;
335 * Adds a "Reply-to" address.
336 * @param string $address
337 * @param string $name
338 * @return void
340 function AddReplyTo($address, $name = "") {
341 $cur = count($this->ReplyTo);
342 $this->ReplyTo[$cur][0] = trim($address);
343 $this->ReplyTo[$cur][1] = $name;
347 /////////////////////////////////////////////////
348 // MAIL SENDING METHODS
349 /////////////////////////////////////////////////
352 * Creates message and assigns Mailer. If the message is
353 * not sent successfully then it returns false. Use the ErrorInfo
354 * variable to view description of the error.
355 * @return bool
357 function Send() {
358 $header = "";
359 $body = "";
360 $result = true;
362 if((count($this->to) + count($this->cc) + count($this->bcc)) < 1)
364 $this->SetError($this->Lang("provide_address"));
365 return false;
368 // Set whether the message is multipart/alternative
369 if(!empty($this->AltBody))
370 $this->ContentType = "multipart/alternative";
372 $this->error_count = 0; // reset errors
373 $this->SetMessageType();
374 $header .= $this->CreateHeader();
375 $body = $this->CreateBody();
377 if($body == "") { return false; }
379 // Choose the mailer
380 switch($this->Mailer)
382 case "sendmail":
383 $result = $this->SendmailSend($header, $body);
384 break;
385 case "mail":
386 $result = $this->MailSend($header, $body);
387 break;
388 case "smtp":
389 $result = $this->SmtpSend($header, $body);
390 break;
391 default:
392 $this->SetError($this->Mailer . $this->Lang("mailer_not_supported"));
393 $result = false;
394 break;
397 return $result;
401 * Sends mail using the $Sendmail program.
402 * @access private
403 * @return bool
405 function SendmailSend($header, $body) {
406 if ($this->Sender != "")
407 $sendmail = sprintf("%s -oi -f %s -t", $this->Sendmail, $this->Sender);
408 else
409 $sendmail = sprintf("%s -oi -t", $this->Sendmail);
411 if(!@$mail = popen($sendmail, "w"))
413 $this->SetError($this->Lang("execute") . $this->Sendmail);
414 return false;
417 fputs($mail, $header);
418 fputs($mail, $body);
420 $result = pclose($mail) >> 8 & 0xFF;
421 if($result != 0)
423 $this->SetError($this->Lang("execute") . $this->Sendmail);
424 return false;
427 return true;
431 * Sends mail using the PHP mail() function.
432 * @access private
433 * @return bool
435 function MailSend($header, $body) {
436 $to = "";
437 for($i = 0; $i < count($this->to); $i++)
439 if($i != 0) { $to .= ", "; }
440 $to .= $this->to[$i][0];
443 $safe = ini_get("safe_mode");
444 if ($this->Sender != "" && ($safe == "" || $safe == "0"))
446 $old_from = ini_get("sendmail_from");
447 ini_set("sendmail_from", $this->Sender);
448 $params = sprintf("-oi -f %s", $this->Sender);
449 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body,
450 $header, $params);
452 else
453 $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header);
455 if (isset($old_from))
456 ini_set("sendmail_from", $old_from);
458 if(!$rt)
460 $this->SetError($this->Lang("instantiate"));
461 return false;
464 return true;
468 * Sends mail via SMTP using PhpSMTP (Author:
469 * Chris Ryan). Returns bool. Returns false if there is a
470 * bad MAIL FROM, RCPT, or DATA input.
471 * @access private
472 * @return bool
474 function SmtpSend($header, $body) {
475 include_once($this->PluginDir . "class.smtp.php");
476 $error = "";
477 $bad_rcpt = array();
479 if(!$this->SmtpConnect())
480 return false;
482 $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender;
483 if(!$this->smtp->Mail($smtp_from))
485 $error = $this->Lang("from_failed") . $smtp_from;
486 $this->SetError($error);
487 $this->smtp->Reset();
488 return false;
491 // Attempt to send attach all recipients
492 for($i = 0; $i < count($this->to); $i++)
494 if(!$this->smtp->Recipient($this->to[$i][0]))
495 $bad_rcpt[] = $this->to[$i][0];
497 for($i = 0; $i < count($this->cc); $i++)
499 if(!$this->smtp->Recipient($this->cc[$i][0]))
500 $bad_rcpt[] = $this->cc[$i][0];
502 for($i = 0; $i < count($this->bcc); $i++)
504 if(!$this->smtp->Recipient($this->bcc[$i][0]))
505 $bad_rcpt[] = $this->bcc[$i][0];
508 if(count($bad_rcpt) > 0) // Create error message
510 for($i = 0; $i < count($bad_rcpt); $i++)
512 if($i != 0) { $error .= ", "; }
513 $error .= $bad_rcpt[$i];
515 $error = $this->Lang("recipients_failed") . $error;
516 $this->SetError($error);
517 $this->smtp->Reset();
518 return false;
521 if(!$this->smtp->Data($header . $body))
523 $this->SetError($this->Lang("data_not_accepted"));
524 $this->smtp->Reset();
525 return false;
527 if($this->SMTPKeepAlive == true)
528 $this->smtp->Reset();
529 else
530 $this->SmtpClose();
532 return true;
536 * Initiates a connection to an SMTP server. Returns false if the
537 * operation failed.
538 * @access private
539 * @return bool
541 function SmtpConnect() {
542 if($this->smtp == NULL) { $this->smtp = new SMTP(); }
544 $this->smtp->do_debug = $this->SMTPDebug;
545 $hosts = explode(";", $this->Host);
546 $index = 0;
547 $connection = ($this->smtp->Connected());
549 // Retry while there is no connection
550 while($index < count($hosts) && $connection == false)
552 if(strstr($hosts[$index], ":"))
553 list($host, $port) = explode(":", $hosts[$index]);
554 else
556 $host = $hosts[$index];
557 $port = $this->Port;
560 if($this->smtp->Connect($host, $port, $this->Timeout))
562 if ($this->Helo != '')
563 $this->smtp->Hello($this->Helo);
564 else
565 $this->smtp->Hello($this->ServerHostname());
567 if($this->SMTPAuth)
569 if(!$this->smtp->Authenticate($this->Username,
570 $this->Password))
572 $this->SetError($this->Lang("authenticate"));
573 $this->smtp->Reset();
574 $connection = false;
577 $connection = true;
579 $index++;
581 if(!$connection)
582 $this->SetError($this->Lang("connect_host"));
584 return $connection;
588 * Closes the active SMTP session if one exists.
589 * @return void
591 function SmtpClose() {
592 if($this->smtp != NULL)
594 if($this->smtp->Connected())
596 $this->smtp->Quit();
597 $this->smtp->Close();
603 * Sets the language for all class error messages. Returns false
604 * if it cannot load the language file. The default language type
605 * is English.
606 * SE 20041001: Added '$this->PluginDir' for Moodle compatibility
608 * @param string $lang_type Type of language (e.g. Portuguese: "br")
609 * @param string $lang_path Path to the language file directory
610 * @access public
611 * @return bool
613 function SetLanguage($lang_type, $lang_path = "language/") {
614 if(file_exists($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php'))
615 include($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php');
616 else if(file_exists($lang_path.'phpmailer.lang-en.php'))
617 include($this->PluginDir.$lang_path.'phpmailer.lang-en.php');
618 else
620 $this->SetError("Could not load language file");
621 return false;
623 $this->language = $PHPMAILER_LANG;
625 return true;
628 /////////////////////////////////////////////////
629 // MESSAGE CREATION METHODS
630 /////////////////////////////////////////////////
633 * Creates recipient headers.
634 * @access private
635 * @return string
637 function AddrAppend($type, $addr) {
638 $addr_str = $type . ": ";
639 $addr_str .= $this->AddrFormat($addr[0]);
640 if(count($addr) > 1)
642 for($i = 1; $i < count($addr); $i++)
643 $addr_str .= ", " . $this->AddrFormat($addr[$i]);
645 $addr_str .= $this->LE;
647 return $addr_str;
651 * Formats an address correctly.
652 * @access private
653 * @return string
655 function AddrFormat($addr) {
656 if(empty($addr[1]))
657 $formatted = $addr[0];
658 else
660 $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .
661 $addr[0] . ">";
664 return $formatted;
668 * Wraps message for use with mailers that do not
669 * automatically perform wrapping and for quoted-printable.
670 * Original written by philippe.
671 * @access private
672 * @return string
674 function WrapText($message, $length, $qp_mode = false) {
675 $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
677 $message = $this->FixEOL($message);
678 if (substr($message, -1) == $this->LE)
679 $message = substr($message, 0, -1);
681 $line = explode($this->LE, $message);
682 $message = "";
683 for ($i=0 ;$i < count($line); $i++)
685 $line_part = explode(" ", $line[$i]);
686 $buf = "";
687 for ($e = 0; $e<count($line_part); $e++)
689 $word = $line_part[$e];
690 if ($qp_mode and (strlen($word) > $length))
692 $space_left = $length - strlen($buf) - 1;
693 if ($e != 0)
695 if ($space_left > 20)
697 $len = $space_left;
698 if (substr($word, $len - 1, 1) == "=")
699 $len--;
700 elseif (substr($word, $len - 2, 1) == "=")
701 $len -= 2;
702 $part = substr($word, 0, $len);
703 $word = substr($word, $len);
704 $buf .= " " . $part;
705 $message .= $buf . sprintf("=%s", $this->LE);
707 else
709 $message .= $buf . $soft_break;
711 $buf = "";
713 while (strlen($word) > 0)
715 $len = $length;
716 if (substr($word, $len - 1, 1) == "=")
717 $len--;
718 elseif (substr($word, $len - 2, 1) == "=")
719 $len -= 2;
720 $part = substr($word, 0, $len);
721 $word = substr($word, $len);
723 if (strlen($word) > 0)
724 $message .= $part . sprintf("=%s", $this->LE);
725 else
726 $buf = $part;
729 else
731 $buf_o = $buf;
732 $buf .= ($e == 0) ? $word : (" " . $word);
734 if (strlen($buf) > $length and $buf_o != "")
736 $message .= $buf_o . $soft_break;
737 $buf = $word;
741 $message .= $buf . $this->LE;
744 return $message;
748 * Set the body wrapping.
749 * @access private
750 * @return void
752 function SetWordWrap() {
753 if($this->WordWrap < 1)
754 return;
756 switch($this->message_type)
758 case "alt":
759 // fall through
760 case "alt_attachments":
761 $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
762 break;
763 default:
764 $this->Body = $this->WrapText($this->Body, $this->WordWrap);
765 break;
770 * Assembles message header.
771 * @access private
772 * @return string
774 function CreateHeader() {
775 $result = "";
777 // Set the boundaries
778 $uniq_id = md5(uniqid(time()));
779 $this->boundary[1] = "b1_" . $uniq_id;
780 $this->boundary[2] = "b2_" . $uniq_id;
782 $result .= $this->HeaderLine("Date", $this->RFCDate());
783 if($this->Sender == "")
784 $result .= $this->HeaderLine("Return-Path", trim($this->From));
785 else
786 $result .= $this->HeaderLine("Return-Path", trim($this->Sender));
788 // To be created automatically by mail()
789 if($this->Mailer != "mail")
791 if(count($this->to) > 0)
792 $result .= $this->AddrAppend("To", $this->to);
793 else if (count($this->cc) == 0)
794 $result .= $this->HeaderLine("To", "undisclosed-recipients:;");
795 if(count($this->cc) > 0)
796 $result .= $this->AddrAppend("Cc", $this->cc);
799 $from = array();
800 $from[0][0] = trim($this->From);
801 $from[0][1] = $this->FromName;
802 $result .= $this->AddrAppend("From", $from);
804 // sendmail and mail() extract Bcc from the header before sending
805 if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0))
806 $result .= $this->AddrAppend("Bcc", $this->bcc);
808 if(count($this->ReplyTo) > 0)
809 $result .= $this->AddrAppend("Reply-to", $this->ReplyTo);
811 // mail() sets the subject itself
812 if($this->Mailer != "mail")
813 $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject)));
815 $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
816 $result .= $this->HeaderLine("X-Priority", $this->Priority);
817 $result .= $this->HeaderLine("X-Mailer", "PHPMailer [version " . $this->Version . "]");
819 if($this->ConfirmReadingTo != "")
821 $result .= $this->HeaderLine("Disposition-Notification-To",
822 "<" . trim($this->ConfirmReadingTo) . ">");
825 // Add custom headers
826 for($index = 0; $index < count($this->CustomHeader); $index++)
828 $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]),
829 $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
831 $result .= $this->HeaderLine("MIME-Version", "1.0");
833 switch($this->message_type)
835 case "plain":
836 $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding);
837 $result .= sprintf("Content-Type: %s; charset=\"%s\"",
838 $this->ContentType, $this->CharSet);
839 break;
840 case "attachments":
841 // fall through
842 case "alt_attachments":
843 if($this->InlineImageExists())
845 $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s",
846 "multipart/related", $this->LE, $this->LE,
847 $this->boundary[1], $this->LE);
849 else
851 $result .= $this->HeaderLine("Content-Type", "multipart/mixed;");
852 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
854 break;
855 case "alt":
856 $result .= $this->HeaderLine("Content-Type", "multipart/alternative;");
857 $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
858 break;
861 if($this->Mailer != "mail")
862 $result .= $this->LE.$this->LE;
864 return $result;
868 * Assembles the message body. Returns an empty string on failure.
869 * @access private
870 * @return string
872 function CreateBody() {
873 $result = "";
875 $this->SetWordWrap();
877 switch($this->message_type)
879 case "alt":
880 $result .= $this->GetBoundary($this->boundary[1], "",
881 "text/plain", "");
882 $result .= $this->EncodeString($this->AltBody, $this->Encoding);
883 $result .= $this->LE.$this->LE;
884 $result .= $this->GetBoundary($this->boundary[1], "",
885 "text/html", "");
887 $result .= $this->EncodeString($this->Body, $this->Encoding);
888 $result .= $this->LE.$this->LE;
890 $result .= $this->EndBoundary($this->boundary[1]);
891 break;
892 case "plain":
893 $result .= $this->EncodeString($this->Body, $this->Encoding);
894 break;
895 case "attachments":
896 $result .= $this->GetBoundary($this->boundary[1], "", "", "");
897 $result .= $this->EncodeString($this->Body, $this->Encoding);
898 $result .= $this->LE;
900 $result .= $this->AttachAll();
901 break;
902 case "alt_attachments":
903 $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
904 $result .= sprintf("Content-Type: %s;%s" .
905 "\tboundary=\"%s\"%s",
906 "multipart/alternative", $this->LE,
907 $this->boundary[2], $this->LE.$this->LE);
909 // Create text body
910 $result .= $this->GetBoundary($this->boundary[2], "",
911 "text/plain", "") . $this->LE;
913 $result .= $this->EncodeString($this->AltBody, $this->Encoding);
914 $result .= $this->LE.$this->LE;
916 // Create the HTML body
917 $result .= $this->GetBoundary($this->boundary[2], "",
918 "text/html", "") . $this->LE;
920 $result .= $this->EncodeString($this->Body, $this->Encoding);
921 $result .= $this->LE.$this->LE;
923 $result .= $this->EndBoundary($this->boundary[2]);
925 $result .= $this->AttachAll();
926 break;
928 if($this->IsError())
929 $result = "";
931 return $result;
935 * Returns the start of a message boundary.
936 * @access private
938 function GetBoundary($boundary, $charSet, $contentType, $encoding) {
939 $result = "";
940 if($charSet == "") { $charSet = $this->CharSet; }
941 if($contentType == "") { $contentType = $this->ContentType; }
942 if($encoding == "") { $encoding = $this->Encoding; }
944 $result .= $this->TextLine("--" . $boundary);
945 $result .= sprintf("Content-Type: %s; charset = \"%s\"",
946 $contentType, $charSet);
947 $result .= $this->LE;
948 $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding);
949 $result .= $this->LE;
951 return $result;
955 * Returns the end of a message boundary.
956 * @access private
958 function EndBoundary($boundary) {
959 return $this->LE . "--" . $boundary . "--" . $this->LE;
963 * Sets the message type.
964 * @access private
965 * @return void
967 function SetMessageType() {
968 if(count($this->attachment) < 1 && strlen($this->AltBody) < 1)
969 $this->message_type = "plain";
970 else
972 if(count($this->attachment) > 0)
973 $this->message_type = "attachments";
974 if(strlen($this->AltBody) > 0 && count($this->attachment) < 1)
975 $this->message_type = "alt";
976 if(strlen($this->AltBody) > 0 && count($this->attachment) > 0)
977 $this->message_type = "alt_attachments";
982 * Returns a formatted header line.
983 * @access private
984 * @return string
986 function HeaderLine($name, $value) {
987 return $name . ": " . $value . $this->LE;
991 * Returns a formatted mail line.
992 * @access private
993 * @return string
995 function TextLine($value) {
996 return $value . $this->LE;
999 /////////////////////////////////////////////////
1000 // ATTACHMENT METHODS
1001 /////////////////////////////////////////////////
1004 * Adds an attachment from a path on the filesystem.
1005 * Returns false if the file could not be found
1006 * or accessed.
1007 * @param string $path Path to the attachment.
1008 * @param string $name Overrides the attachment name.
1009 * @param string $encoding File encoding (see $Encoding).
1010 * @param string $type File extension (MIME) type.
1011 * @return bool
1013 function AddAttachment($path, $name = "", $encoding = "base64",
1014 $type = "application/octet-stream") {
1015 if(!@is_file($path))
1017 $this->SetError($this->Lang("file_access") . $path);
1018 return false;
1021 $filename = basename($path);
1022 if($name == "")
1023 $name = $filename;
1025 $cur = count($this->attachment);
1026 $this->attachment[$cur][0] = $path;
1027 $this->attachment[$cur][1] = $filename;
1028 $this->attachment[$cur][2] = $name;
1029 $this->attachment[$cur][3] = $encoding;
1030 $this->attachment[$cur][4] = $type;
1031 $this->attachment[$cur][5] = false; // isStringAttachment
1032 $this->attachment[$cur][6] = "attachment";
1033 $this->attachment[$cur][7] = 0;
1035 return true;
1039 * Attaches all fs, string, and binary attachments to the message.
1040 * Returns an empty string on failure.
1041 * @access private
1042 * @return string
1044 function AttachAll() {
1045 // Return text of body
1046 $mime = array();
1048 // Add all attachments
1049 for($i = 0; $i < count($this->attachment); $i++)
1051 // Check for string attachment
1052 $bString = $this->attachment[$i][5];
1053 if ($bString)
1054 $string = $this->attachment[$i][0];
1055 else
1056 $path = $this->attachment[$i][0];
1058 $filename = $this->attachment[$i][1];
1059 $name = $this->attachment[$i][2];
1060 $encoding = $this->attachment[$i][3];
1061 $type = $this->attachment[$i][4];
1062 $disposition = $this->attachment[$i][6];
1063 $cid = $this->attachment[$i][7];
1065 $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1066 $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
1067 $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1069 if($disposition == "inline")
1070 $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1072 $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s",
1073 $disposition, $name, $this->LE.$this->LE);
1075 // Encode as string attachment
1076 if($bString)
1078 $mime[] = $this->EncodeString($string, $encoding);
1079 if($this->IsError()) { return ""; }
1080 $mime[] = $this->LE.$this->LE;
1082 else
1084 $mime[] = $this->EncodeFile($path, $encoding);
1085 if($this->IsError()) { return ""; }
1086 $mime[] = $this->LE.$this->LE;
1090 $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1092 return join("", $mime);
1096 * Encodes attachment in requested format. Returns an
1097 * empty string on failure.
1098 * @access private
1099 * @return string
1101 function EncodeFile ($path, $encoding = "base64") {
1102 if(!@$fd = fopen($path, "rb"))
1104 $this->SetError($this->Lang("file_open") . $path);
1105 return "";
1107 $magic_quotes = get_magic_quotes_runtime();
1108 set_magic_quotes_runtime(0);
1109 $file_buffer = fread($fd, filesize($path));
1110 $file_buffer = $this->EncodeString($file_buffer, $encoding);
1111 fclose($fd);
1112 set_magic_quotes_runtime($magic_quotes);
1114 return $file_buffer;
1118 * Encodes string to requested format. Returns an
1119 * empty string on failure.
1120 * @access private
1121 * @return string
1123 function EncodeString ($str, $encoding = "base64") {
1124 $encoded = "";
1125 switch(strtolower($encoding)) {
1126 case "base64":
1127 // chunk_split is found in PHP >= 3.0.6
1128 $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1129 break;
1130 case "7bit":
1131 case "8bit":
1132 $encoded = $this->FixEOL($str);
1133 if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1134 $encoded .= $this->LE;
1135 break;
1136 case "binary":
1137 $encoded = $str;
1138 break;
1139 case "quoted-printable":
1140 $encoded = $this->EncodeQP($str);
1141 break;
1142 default:
1143 $this->SetError($this->Lang("encoding") . $encoding);
1144 break;
1146 return $encoded;
1150 * Encode a header string to best of Q, B, quoted or none.
1151 * @access private
1152 * @return string
1154 function EncodeHeader ($str, $position = 'text') {
1155 $x = 0;
1157 switch (strtolower($position)) {
1158 case 'phrase':
1159 if (!preg_match('/[\200-\377]/', $str)) {
1160 // Can't use addslashes as we don't know what value has magic_quotes_sybase.
1161 $encoded = addcslashes($str, "\0..\37\177\\\"");
1163 if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str))
1164 return ($encoded);
1165 else
1166 return ("\"$encoded\"");
1168 $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1169 break;
1170 case 'comment':
1171 $x = preg_match_all('/[()"]/', $str, $matches);
1172 // Fall-through
1173 case 'text':
1174 default:
1175 $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1176 break;
1179 if ($x == 0)
1180 return ($str);
1182 $maxlen = 75 - 7 - strlen($this->CharSet);
1183 // Try to select the encoding which should produce the shortest output
1184 if (strlen($str)/3 < $x) {
1185 $encoding = 'B';
1186 $encoded = base64_encode($str);
1187 $maxlen -= $maxlen % 4;
1188 $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1189 } else {
1190 $encoding = 'Q';
1191 $encoded = $this->EncodeQ($str, $position);
1192 $encoded = $this->WrapText($encoded, $maxlen, true);
1193 $encoded = str_replace("=".$this->LE, "\n", trim($encoded));
1196 $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1197 $encoded = trim(str_replace("\n", $this->LE, $encoded));
1199 return $encoded;
1203 * Encode string to quoted-printable.
1204 * @access private
1205 * @return string
1207 function EncodeQP ($str) {
1208 $encoded = $this->FixEOL($str);
1209 if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1210 $encoded .= $this->LE;
1212 // Replace every high ascii, control and = characters
1213 $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
1214 "'='.sprintf('%02X', ord('\\1'))", $encoded);
1215 // Replace every spaces and tabs when it's the last character on a line
1216 $encoded = preg_replace("/([\011\040])".$this->LE."/e",
1217 "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
1219 // Maximum line length of 76 characters before CRLF (74 + space + '=')
1220 $encoded = $this->WrapText($encoded, 74, true);
1222 return $encoded;
1226 * Encode string to q encoding.
1227 * @access private
1228 * @return string
1230 function EncodeQ ($str, $position = "text") {
1231 // There should not be any EOL in the string
1232 $encoded = preg_replace("[\r\n]", "", $str);
1234 switch (strtolower($position)) {
1235 case "phrase":
1236 $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1237 break;
1238 case "comment":
1239 $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1240 case "text":
1241 default:
1242 // Replace every high ascii, control =, ? and _ characters
1243 $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1244 "'='.sprintf('%02X', ord('\\1'))", $encoded);
1245 break;
1248 // Replace every spaces to _ (more readable than =20)
1249 $encoded = str_replace(" ", "_", $encoded);
1251 return $encoded;
1255 * Adds a string or binary attachment (non-filesystem) to the list.
1256 * This method can be used to attach ascii or binary data,
1257 * such as a BLOB record from a database.
1258 * @param string $string String attachment data.
1259 * @param string $filename Name of the attachment.
1260 * @param string $encoding File encoding (see $Encoding).
1261 * @param string $type File extension (MIME) type.
1262 * @return void
1264 function AddStringAttachment($string, $filename, $encoding = "base64",
1265 $type = "application/octet-stream") {
1266 // Append to $attachment array
1267 $cur = count($this->attachment);
1268 $this->attachment[$cur][0] = $string;
1269 $this->attachment[$cur][1] = $filename;
1270 $this->attachment[$cur][2] = $filename;
1271 $this->attachment[$cur][3] = $encoding;
1272 $this->attachment[$cur][4] = $type;
1273 $this->attachment[$cur][5] = true; // isString
1274 $this->attachment[$cur][6] = "attachment";
1275 $this->attachment[$cur][7] = 0;
1279 * Adds an embedded attachment. This can include images, sounds, and
1280 * just about any other document. Make sure to set the $type to an
1281 * image type. For JPEG images use "image/jpeg" and for GIF images
1282 * use "image/gif".
1283 * @param string $path Path to the attachment.
1284 * @param string $cid Content ID of the attachment. Use this to identify
1285 * the Id for accessing the image in an HTML form.
1286 * @param string $name Overrides the attachment name.
1287 * @param string $encoding File encoding (see $Encoding).
1288 * @param string $type File extension (MIME) type.
1289 * @return bool
1291 function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64",
1292 $type = "application/octet-stream") {
1294 if(!@is_file($path))
1296 $this->SetError($this->Lang("file_access") . $path);
1297 return false;
1300 $filename = basename($path);
1301 if($name == "")
1302 $name = $filename;
1304 // Append to $attachment array
1305 $cur = count($this->attachment);
1306 $this->attachment[$cur][0] = $path;
1307 $this->attachment[$cur][1] = $filename;
1308 $this->attachment[$cur][2] = $name;
1309 $this->attachment[$cur][3] = $encoding;
1310 $this->attachment[$cur][4] = $type;
1311 $this->attachment[$cur][5] = false; // isStringAttachment
1312 $this->attachment[$cur][6] = "inline";
1313 $this->attachment[$cur][7] = $cid;
1315 return true;
1319 * Returns true if an inline attachment is present.
1320 * @access private
1321 * @return bool
1323 function InlineImageExists() {
1324 $result = false;
1325 for($i = 0; $i < count($this->attachment); $i++)
1327 if($this->attachment[$i][6] == "inline")
1329 $result = true;
1330 break;
1334 return $result;
1337 /////////////////////////////////////////////////
1338 // MESSAGE RESET METHODS
1339 /////////////////////////////////////////////////
1342 * Clears all recipients assigned in the TO array. Returns void.
1343 * @return void
1345 function ClearAddresses() {
1346 $this->to = array();
1350 * Clears all recipients assigned in the CC array. Returns void.
1351 * @return void
1353 function ClearCCs() {
1354 $this->cc = array();
1358 * Clears all recipients assigned in the BCC array. Returns void.
1359 * @return void
1361 function ClearBCCs() {
1362 $this->bcc = array();
1366 * Clears all recipients assigned in the ReplyTo array. Returns void.
1367 * @return void
1369 function ClearReplyTos() {
1370 $this->ReplyTo = array();
1374 * Clears all recipients assigned in the TO, CC and BCC
1375 * array. Returns void.
1376 * @return void
1378 function ClearAllRecipients() {
1379 $this->to = array();
1380 $this->cc = array();
1381 $this->bcc = array();
1385 * Clears all previously set filesystem, string, and binary
1386 * attachments. Returns void.
1387 * @return void
1389 function ClearAttachments() {
1390 $this->attachment = array();
1394 * Clears all custom headers. Returns void.
1395 * @return void
1397 function ClearCustomHeaders() {
1398 $this->CustomHeader = array();
1402 /////////////////////////////////////////////////
1403 // MISCELLANEOUS METHODS
1404 /////////////////////////////////////////////////
1407 * Adds the error message to the error container.
1408 * Returns void.
1409 * @access private
1410 * @return void
1412 function SetError($msg) {
1413 $this->error_count++;
1414 $this->ErrorInfo = $msg;
1418 * Returns the proper RFC 822 formatted date.
1419 * @access private
1420 * @return string
1422 function RFCDate() {
1423 $tz = date("Z");
1424 $tzs = ($tz < 0) ? "-" : "+";
1425 $tz = abs($tz);
1426 $tz = ($tz/3600)*100 + ($tz%3600)/60;
1427 $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz);
1429 return $result;
1433 * Returns the appropriate server variable. Should work with both
1434 * PHP 4.1.0+ as well as older versions. Returns an empty string
1435 * if nothing is found.
1436 * @access private
1437 * @return mixed
1439 function ServerVar($varName) {
1440 global $HTTP_SERVER_VARS;
1441 global $HTTP_ENV_VARS;
1443 if(!isset($_SERVER))
1445 $_SERVER = $HTTP_SERVER_VARS;
1446 if(!isset($_SERVER["REMOTE_ADDR"]))
1447 $_SERVER = $HTTP_ENV_VARS; // must be Apache
1450 if(isset($_SERVER[$varName]))
1451 return $_SERVER[$varName];
1452 else
1453 return "";
1457 * Returns the server hostname or 'localhost.localdomain' if unknown.
1458 * @access private
1459 * @return string
1461 function ServerHostname() {
1462 if ($this->Hostname != "")
1463 $result = $this->Hostname;
1464 elseif ($this->ServerVar('SERVER_NAME') != "")
1465 $result = $this->ServerVar('SERVER_NAME');
1466 else
1467 $result = "localhost.localdomain";
1469 return $result;
1473 * Returns a message in the appropriate language.
1474 * @access private
1475 * @return string
1477 function Lang($key) {
1478 if(count($this->language) < 1)
1479 $this->SetLanguage("en"); // set the default language
1481 if(isset($this->language[$key]))
1482 return $this->language[$key];
1483 else
1484 return "Language string failed to load: " . $key;
1488 * Returns true if an error occurred.
1489 * @return bool
1491 function IsError() {
1492 return ($this->error_count > 0);
1496 * Changes every end of line from CR or LF to CRLF.
1497 * @access private
1498 * @return string
1500 function FixEOL($str) {
1501 $str = str_replace("\r\n", "\n", $str);
1502 $str = str_replace("\r", "\n", $str);
1503 $str = str_replace("\n", $this->LE, $str);
1504 return $str;
1508 * Adds a custom header.
1509 * @return void
1511 function AddCustomHeader($custom_header) {
1512 $this->CustomHeader[] = explode(":", $custom_header, 2);