File:
1.00.10a/server/base/phpmailer/class.phpmailer.php (
View as Code)
1: 2: /*~ class.phpmailer.php
3: .---------------------------------------------------------------------------.
4: | Software: PHPMailer - PHP email class |
5: | Version: 2.1 |
6: | Contact: via sourceforge.net support pages (also www.codeworxtech.com) |
7: | Info: http://phpmailer.sourceforge.net |
8: | Support: http://sourceforge.net/projects/phpmailer/ |
9: | ------------------------------------------------------------------------- |
10: | Author: Andy Prevost (project admininistrator) |
11: | Author: Brent R. Matzelle (original founder) |
12: | Copyright (c) 2004-2007, Andy Prevost. All Rights Reserved. |
13: | Copyright (c) 2001-2003, Brent R. Matzelle |
14: | ------------------------------------------------------------------------- |
15: | License: Distributed under the Lesser General Public License (LGPL) |
16: | http://www.gnu.org/copyleft/lesser.html |
17: | This program is distributed in the hope that it will be useful - WITHOUT |
18: | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
19: | FITNESS FOR A PARTICULAR PURPOSE. |
20: | ------------------------------------------------------------------------- |
21: | We offer a number of paid services (www.codeworxtech.com): |
22: | - Web Hosting on highly optimized fast and secure servers |
23: | - Technology Consulting |
24: | - Oursourcing (highly qualified programmers and graphic designers) |
25: '---------------------------------------------------------------------------'
26:
27: /**
28: * PHPMailer - PHP email transport class
29: * NOTE: Designed for use with PHP version 5 and up
30: * @package PHPMailer
31: * @author Andy Prevost
32: * @copyright 2004 - 2008 Andy Prevost
33: */
34:
35: class PHPMailer {
36:
37: /////////////////////////////////////////////////
38: // PROPERTIES, PUBLIC
39: /////////////////////////////////////////////////
40:
41: /**
42: * Email priority (1 = High, 3 = Normal, 5 = low).
43: * @var int
44: */
45: public $Priority = 3;
46:
47: /**
48: * Sets the CharSet of the message.
49: * @var string
50: */
51: public $CharSet = 'iso-8859-1';
52:
53: /**
54: * Sets the Content-type of the message.
55: * @var string
56: */
57: public $ContentType = 'text/plain';
58:
59: /**
60: * Sets the Encoding of the message. Options for this are "8bit",
61: * "7bit", "binary", "base64", and "quoted-printable".
62: * @var string
63: */
64: public $Encoding = '8bit';
65:
66: /**
67: * Holds the most recent mailer error message.
68: * @var string
69: */
70: public $ErrorInfo = '';
71:
72: /**
73: * Sets the From email address for the message.
74: * @var string
75: */
76: public $From = 'root@localhost';
77:
78: /**
79: * Sets the From name of the message.
80: * @var string
81: */
82: public $FromName = 'Root User';
83:
84: /**
85: * Sets the Sender email (Return-Path) of the message. If not empty,
86: * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
87: * @var string
88: */
89: public $Sender = '';
90:
91: /**
92: * Sets the Subject of the message.
93: * @var string
94: */
95: public $Subject = '';
96:
97: /**
98: * Sets the Body of the message. This can be either an HTML or text body.
99: * If HTML then run IsHTML(true).
100: * @var string
101: */
102: public $Body = '';
103:
104: /**
105: * Sets the text-only body of the message. This automatically sets the
106: * email to multipart/alternative. This body can be read by mail
107: * clients that do not have HTML email capability such as mutt. Clients
108: * that can read HTML will view the normal Body.
109: * @var string
110: */
111: public $AltBody = '';
112:
113: /**
114: * Sets word wrapping on the body of the message to a given number of
115: * characters.
116: * @var int
117: */
118: public $WordWrap = 0;
119:
120: /**
121: * Method to send mail: ("mail", "sendmail", or "smtp").
122: * @var string
123: */
124: public $Mailer = 'mail';
125:
126: /**
127: * Sets the path of the sendmail program.
128: * @var string
129: */
130: public $Sendmail = '/usr/sbin/sendmail';
131:
132: /**
133: * Path to PHPMailer plugins. This is now only useful if the SMTP class
134: * is in a different directory than the PHP include path.
135: * @var string
136: */
137: public $PluginDir = '';
138:
139: /**
140: * Holds PHPMailer version.
141: * @var string
142: */
143: public $Version = "2.1";
144:
145: /**
146: * Sets the email address that a reading confirmation will be sent.
147: * @var string
148: */
149: public $ConfirmReadingTo = '';
150:
151: /**
152: * Sets the hostname to use in Message-Id and Received headers
153: * and as default HELO string. If empty, the value returned
154: * by SERVER_NAME is used or 'localhost.localdomain'.
155: * @var string
156: */
157: public $Hostname = '';
158:
159: /**
160: * Sets the message ID to be used in the Message-Id header.
161: * If empty, a unique id will be generated.
162: * @var string
163: */
164: public $MessageID = '';
165:
166: /////////////////////////////////////////////////
167: // PROPERTIES FOR SMTP
168: /////////////////////////////////////////////////
169:
170: /**
171: * Sets the SMTP hosts. All hosts must be separated by a
172: * semicolon. You can also specify a different port
173: * for each host by using this format: [hostname:port]
174: * (e.g. "smtp1.example.com:25;smtp2.example.com").
175: * Hosts will be tried in order.
176: * @var string
177: */
178: public $Host = 'localhost';
179:
180: /**
181: * Sets the default SMTP server port.
182: * @var int
183: */
184: public $Port = 25;
185:
186: /**
187: * Sets the SMTP HELO of the message (Default is $Hostname).
188: * @var string
189: */
190: public $Helo = '';
191:
192: /**
193: * Sets connection prefix.
194: * Options are "", "ssl" or "tls"
195: * @var string
196: */
197: public $SMTPSecure = "";
198:
199: /**
200: * Sets SMTP authentication. Utilizes the Username and Password variables.
201: * @var bool
202: */
203: public $SMTPAuth = false;
204:
205: /**
206: * Sets SMTP username.
207: * @var string
208: */
209: public $Username = '';
210:
211: /**
212: * Sets SMTP password.
213: * @var string
214: */
215: public $Password = '';
216:
217: /**
218: * Sets the SMTP server timeout in seconds. This function will not
219: * work with the win32 version.
220: * @var int
221: */
222: public $Timeout = 10;
223:
224: /**
225: * Sets SMTP class debugging on or off.
226: * @var bool
227: */
228: public $SMTPDebug = false;
229:
230: /**
231: * Prevents the SMTP connection from being closed after each mail
232: * sending. If this is set to true then to close the connection
233: * requires an explicit call to SmtpClose().
234: * @var bool
235: */
236: public $SMTPKeepAlive = false;
237:
238: /**
239: * Provides the ability to have the TO field process individual
240: * emails, instead of sending to entire TO addresses
241: * @var bool
242: */
243: public $SingleTo = false;
244:
245: /////////////////////////////////////////////////
246: // PROPERTIES, PRIVATE
247: /////////////////////////////////////////////////
248:
249: private $smtp = NULL;
250: private $to = array();
251: private $cc = array();
252: private $bcc = array();
253: private $ReplyTo = array();
254: private $attachment = array();
255: private $CustomHeader = array();
256: private $message_type = '';
257: private $boundary = array();
258: private $language = array();
259: private $error_count = 0;
260: private $LE = "\n";
261: private $sign_key_file = "";
262: private $sign_key_pass = "";
263:
264: /////////////////////////////////////////////////
265: // METHODS, VARIABLES
266: /////////////////////////////////////////////////
267:
268: /**
269: * Sets message type to HTML.
270: * @param bool $bool
271: * @return void
272: */
273: public function IsHTML($bool) {
274: if($bool == true) {
275: $this->ContentType = 'text/html';
276: } else {
277: $this->ContentType = 'text/plain';
278: }
279: }
280:
281: /**
282: * Sets Mailer to send message using SMTP.
283: * @return void
284: */
285: public function IsSMTP() {
286: $this->Mailer = 'smtp';
287: }
288:
289: /**
290: * Sets Mailer to send message using PHP mail() function.
291: * @return void
292: */
293: public function IsMail() {
294: $this->Mailer = 'mail';
295: }
296:
297: /**
298: * Sets Mailer to send message using the $Sendmail program.
299: * @return void
300: */
301: public function IsSendmail() {
302: $this->Mailer = 'sendmail';
303: }
304:
305: /**
306: * Sets Mailer to send message using the qmail MTA.
307: * @return void
308: */
309: public function IsQmail() {
310: $this->Sendmail = '/var/qmail/bin/sendmail';
311: $this->Mailer = 'sendmail';
312: }
313:
314: /////////////////////////////////////////////////
315: // METHODS, RECIPIENTS
316: /////////////////////////////////////////////////
317:
318: /**
319: * Adds a "To" address.
320: * @param string $address
321: * @param string $name
322: * @return void
323: */
324: public function AddAddress($address, $name = '') {
325: $cur = count($this->to);
326: $this->to[$cur][0] = trim($address);
327: $this->to[$cur][1] = $name;
328: }
329:
330: /**
331: * Adds a "Cc" address. Note: this function works
332: * with the SMTP mailer on win32, not with the "mail"
333: * mailer.
334: * @param string $address
335: * @param string $name
336: * @return void
337: */
338: public function AddCC($address, $name = '') {
339: $cur = count($this->cc);
340: $this->cc[$cur][0] = trim($address);
341: $this->cc[$cur][1] = $name;
342: }
343:
344: /**
345: * Adds a "Bcc" address. Note: this function works
346: * with the SMTP mailer on win32, not with the "mail"
347: * mailer.
348: * @param string $address
349: * @param string $name
350: * @return void
351: */
352: public function AddBCC($address, $name = '') {
353: $cur = count($this->bcc);
354: $this->bcc[$cur][0] = trim($address);
355: $this->bcc[$cur][1] = $name;
356: }
357:
358: /**
359: * Adds a "Reply-to" address.
360: * @param string $address
361: * @param string $name
362: * @return void
363: */
364: public function AddReplyTo($address, $name = '') {
365: $cur = count($this->ReplyTo);
366: $this->ReplyTo[$cur][0] = trim($address);
367: $this->ReplyTo[$cur][1] = $name;
368: }
369:
370: /////////////////////////////////////////////////
371: // METHODS, MAIL SENDING
372: /////////////////////////////////////////////////
373:
374: /**
375: * Creates message and assigns Mailer. If the message is
376: * not sent successfully then it returns false. Use the ErrorInfo
377: * variable to view description of the error.
378: * @return bool
379: */
380: public function Send() {
381: $header = '';
382: $body = '';
383: $result = true;
384:
385: if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
386: $this->SetError($this->Lang('provide_address'));
387: return false;
388: }
389:
390: /* Set whether the message is multipart/alternative */
391: if(!empty($this->AltBody)) {
392: $this->ContentType = 'multipart/alternative';
393: }
394:
395: $this->error_count = 0; // reset errors
396: $this->SetMessageType();
397: $header .= $this->CreateHeader();
398: $body = $this->CreateBody();
399:
400: if($body == '') {
401: return false;
402: }
403:
404: /* Choose the mailer */
405: switch($this->Mailer) {
406: case 'sendmail':
407: $result = $this->SendmailSend($header, $body);
408: break;
409: case 'smtp':
410: $result = $this->SmtpSend($header, $body);
411: break;
412: case 'mail':
413: $result = $this->MailSend($header, $body);
414: break;
415: default:
416: $result = $this->MailSend($header, $body);
417: break;
418: //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported'));
419: //$result = false;
420: //break;
421: }
422:
423: return $result;
424: }
425:
426: /**
427: * Sends mail using the $Sendmail program.
428: * @access public
429: * @return bool
430: */
431: public function SendmailSend($header, $body) {
432: if ($this->Sender != '') {
433: $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
434: } else {
435: $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
436: }
437:
438: if(!@$mail = popen($sendmail, 'w')) {
439: $this->SetError($this->Lang('execute') . $this->Sendmail);
440: return false;
441: }
442:
443: fputs($mail, $header);
444: fputs($mail, $body);
445:
446: $result = pclose($mail);
447: if (version_compare(phpversion(), '4.2.3') == -1) {
448: $result = $result >> 8 & 0xFF;
449: }
450: if($result != 0) {
451: $this->SetError($this->Lang('execute') . $this->Sendmail);
452: return false;
453: }
454:
455: return true;
456: }
457:
458: /**
459: * Sends mail using the PHP mail() function.
460: * @access public
461: * @return bool
462: */
463: public function MailSend($header, $body) {
464:
465: $to = '';
466: for($i = 0; $i < count($this->to); $i++) {
467: if($i != 0) { $to .= ', '; }
468: $to .= $this->AddrFormat($this->to[$i]);
469: }
470:
471: $toArr = split(',', $to);
472:
473: $params = sprintf("-oi -f %s", $this->Sender);
474: if ($this->Sender != '' && strlen(ini_get('safe_mode'))< 1) {
475: $old_from = ini_get('sendmail_from');
476: ini_set('sendmail_from', $this->Sender);
477: if ($this->SingleTo === true && count($toArr) > 1) {
478: foreach ($toArr as $key => $val) {
479: $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
480: }
481: } else {
482: $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
483: }
484: } else {
485: if ($this->SingleTo === true && count($toArr) > 1) {
486: foreach ($toArr as $key => $val) {
487: $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
488: }
489: } else {
490: $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header);
491: }
492: }
493:
494: if (isset($old_from)) {
495: ini_set('sendmail_from', $old_from);
496: }
497:
498: if(!$rt) {
499: $this->SetError($this->Lang('instantiate'));
500: return false;
501: }
502:
503: return true;
504: }
505:
506: /**
507: * Sends mail via SMTP using PhpSMTP (Author:
508: * Chris Ryan). Returns bool. Returns false if there is a
509: * bad MAIL FROM, RCPT, or DATA input.
510: * @access public
511: * @return bool
512: */
513: public function SmtpSend($header, $body) {
514: include_once($this->PluginDir . 'class.smtp.php');
515: $error = '';
516: $bad_rcpt = array();
517:
518: if(!$this->SmtpConnect()) {
519: return false;
520: }
521:
522: $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
523: if(!$this->smtp->Mail($smtp_from)) {
524: $error = $this->Lang('from_failed') . $smtp_from;
525: $this->SetError($error);
526: $this->smtp->Reset();
527: return false;
528: }
529:
530: /* Attempt to send attach all recipients */
531: for($i = 0; $i < count($this->to); $i++) {
532: if(!$this->smtp->Recipient($this->to[$i][0])) {
533: $bad_rcpt[] = $this->to[$i][0];
534: }
535: }
536: for($i = 0; $i < count($this->cc); $i++) {
537: if(!$this->smtp->Recipient($this->cc[$i][0])) {
538: $bad_rcpt[] = $this->cc[$i][0];
539: }
540: }
541: for($i = 0; $i < count($this->bcc); $i++) {
542: if(!$this->smtp->Recipient($this->bcc[$i][0])) {
543: $bad_rcpt[] = $this->bcc[$i][0];
544: }
545: }
546:
547: if(count($bad_rcpt) > 0) { // Create error message
548: for($i = 0; $i < count($bad_rcpt); $i++) {
549: if($i != 0) {
550: $error .= ', ';
551: }
552: $error .= $bad_rcpt[$i];
553: }
554: $error = $this->Lang('recipients_failed') . $error;
555: $this->SetError($error);
556: $this->smtp->Reset();
557: return false;
558: }
559:
560: if(!$this->smtp->Data($header . $body)) {
561: $this->SetError($this->Lang('data_not_accepted'));
562: $this->smtp->Reset();
563: return false;
564: }
565: if($this->SMTPKeepAlive == true) {
566: $this->smtp->Reset();
567: } else {
568: $this->SmtpClose();
569: }
570:
571: return true;
572: }
573:
574: /**
575: * Initiates a connection to an SMTP server. Returns false if the
576: * operation failed.
577: * @access public
578: * @return bool
579: */
580: public function SmtpConnect() {
581: if($this->smtp == NULL) {
582: $this->smtp = new SMTP();
583: }
584:
585: $this->smtp->do_debug = $this->SMTPDebug;
586: $hosts = explode(';', $this->Host);
587: $index = 0;
588: $connection = ($this->smtp->Connected());
589:
590: /* Retry while there is no connection */
591: while($index < count($hosts) && $connection == false) {
592: $hostinfo = array();
593: if(eregi('^(.+):([0-9]+)$', $hosts[$index], $hostinfo)) {
594: $host = $hostinfo[1];
595: $port = $hostinfo[2];
596: } else {
597: $host = $hosts[$index];
598: $port = $this->Port;
599: }
600:
601: $tls = ($this->SMTPSecure == 'tls');
602: $ssl = ($this->SMTPSecure == 'ssl');
603:
604: if($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
605:
606: $hello = ($this->Helo != '' ? $this->Hello : $this->ServerHostname());
607: $this->smtp->Hello($hello);
608:
609: if($tls) {
610: if(!$this->smtp->StartTLS()) {
611: $this->SetError($this->Lang("tls"));
612: $this->smtp->Reset();
613: $connection = false;
614: }
615:
616: //We must resend HELLO after tls negociation
617: $this->smtp->Hello($hello);
618: }
619:
620: $connection = true;
621: if($this->SMTPAuth) {
622: if(!$this->smtp->Authenticate($this->Username, $this->Password)) {
623: $this->SetError($this->Lang('authenticate'));
624: $this->smtp->Reset();
625: $connection = false;
626: }
627: }
628: }
629: $index++;
630: }
631: if(!$connection) {
632: $this->SetError($this->Lang('connect_host'));
633: }
634:
635: return $connection;
636: }
637:
638: /**
639: * Closes the active SMTP session if one exists.
640: * @return void
641: */
642: public function SmtpClose() {
643: if($this->smtp != NULL) {
644: if($this->smtp->Connected()) {
645: $this->smtp->Quit();
646: $this->smtp->Close();
647: }
648: }
649: }
650:
651: /**
652: * Sets the language for all class error messages. Returns false
653: * if it cannot load the language file. The default language type
654: * is English.
655: * @param string $lang_type Type of language (e.g. Portuguese: "br")
656: * @param string $lang_path Path to the language file directory
657: * @access public
658: * @return bool
659: */
660: function SetLanguage($lang_type = 'en', $lang_path = 'language/') {
661: if( !(@include $lang_path.'phpmailer.lang-'.$lang_type.'.php') ) {
662: $this->SetError('Could not load language file');
663: return false;
664: }
665: $this->language = $PHPMAILER_LANG;
666: return true;
667: }
668:
669: /////////////////////////////////////////////////
670: // METHODS, MESSAGE CREATION
671: /////////////////////////////////////////////////
672:
673: /**
674: * Creates recipient headers.
675: * @access public
676: * @return string
677: */
678: public function AddrAppend($type, $addr) {
679: $addr_str = $type . ': ';
680: $addr_str .= $this->AddrFormat($addr[0]);
681: if(count($addr) > 1) {
682: for($i = 1; $i < count($addr); $i++) {
683: $addr_str .= ', ' . $this->AddrFormat($addr[$i]);
684: }
685: }
686: $addr_str .= $this->LE;
687:
688: return $addr_str;
689: }
690:
691: /**
692: * Formats an address correctly.
693: * @access public
694: * @return string
695: */
696: public function AddrFormat($addr) {
697: if(empty($addr[1])) {
698: $formatted = $this->SecureHeader($addr[0]);
699: } else {
700: $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
701: }
702:
703: return $formatted;
704: }
705:
706: /**
707: * Wraps message for use with mailers that do not
708: * automatically perform wrapping and for quoted-printable.
709: * Original written by philippe.
710: * @access public
711: * @return string
712: */
713: public function WrapText($message, $length, $qp_mode = false) {
714: $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
715: // If utf-8 encoding is used, we will need to make sure we don't
716: // split multibyte characters when we wrap
717: $is_utf8 = (strtolower($this->CharSet) == "utf-8");
718:
719: $message = $this->FixEOL($message);
720: if (substr($message, -1) == $this->LE) {
721: $message = substr($message, 0, -1);
722: }
723:
724: $line = explode($this->LE, $message);
725: $message = '';
726: for ($i=0 ;$i < count($line); $i++) {
727: $line_part = explode(' ', $line[$i]);
728: $buf = '';
729: for ($e = 0; $e730: $word = $line_part[$e];
731: if ($qp_mode and (strlen($word) > $length)) {
732: $space_left = $length - strlen($buf) - 1;
733: if ($e != 0) {
734: if ($space_left > 20) {
735: $len = $space_left;
736: if ($is_utf8) {
737: $len = $this->UTF8CharBoundary($word, $len);
738: } elseif (substr($word, $len - 1, 1) == "=") {
739: $len--;
740: } elseif (substr($word, $len - 2, 1) == "=") {
741: $len -= 2;
742: }
743: $part = substr($word, 0, $len);
744: $word = substr($word, $len);
745: $buf .= ' ' . $part;
746: $message .= $buf . sprintf("=%s", $this->LE);
747: } else {
748: $message .= $buf . $soft_break;
749: }
750: $buf = '';
751: }
752: while (strlen($word) > 0) {
753: $len = $length;
754: if ($is_utf8) {
755: $len = $this->UTF8CharBoundary($word, $len);
756: } elseif (substr($word, $len - 1, 1) == "=") {
757: $len--;
758: } elseif (substr($word, $len - 2, 1) == "=") {
759: $len -= 2;
760: }
761: $part = substr($word, 0, $len);
762: $word = substr($word, $len);
763:
764: if (strlen($word) > 0) {
765: $message .= $part . sprintf("=%s", $this->LE);
766: } else {
767: $buf = $part;
768: }
769: }
770: } else {
771: $buf_o = $buf;
772: $buf .= ($e == 0) ? $word : (' ' . $word);
773:
774: if (strlen($buf) > $length and $buf_o != '') {
775: $message .= $buf_o . $soft_break;
776: $buf = $word;
777: }
778: }
779: }
780: $message .= $buf . $this->LE;
781: }
782:
783: return $message;
784: }
785:
786: /**
787: * Finds last character boundary prior to maxLength in a utf-8
788: * quoted (printable) encoded string.
789: * Original written by Colin Brown.
790: * @access public
791: * @param string $encodedText utf-8 QP text
792: * @param int $maxLength find last character boundary prior to this length
793: * @return int
794: */
795: public function UTF8CharBoundary($encodedText, $maxLength) {
796: $foundSplitPos = false;
797: $lookBack = 3;
798: while (!$foundSplitPos) {
799: $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
800: $encodedCharPos = strpos($lastChunk, "=");
801: if ($encodedCharPos !== false) {
802: // Found start of encoded character byte within $lookBack block.
803: // Check the encoded byte value (the 2 chars after the '=')
804: $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
805: $dec = hexdec($hex);
806: if ($dec < 128) { // Single byte character.
807: // If the encoded char was found at pos 0, it will fit
808: // otherwise reduce maxLength to start of the encoded char
809: $maxLength = ($encodedCharPos == 0) ? $maxLength :
810: $maxLength - ($lookBack - $encodedCharPos);
811: $foundSplitPos = true;
812: } elseif ($dec >= 192) { // First byte of a multi byte character
813: // Reduce maxLength to split at start of character
814: $maxLength = $maxLength - ($lookBack - $encodedCharPos);
815: $foundSplitPos = true;
816: } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
817: $lookBack += 3;
818: }
819: } else {
820: // No encoded character found
821: $foundSplitPos = true;
822: }
823: }
824: return $maxLength;
825: }
826:
827:
828: /**
829: * Set the body wrapping.
830: * @access public
831: * @return void
832: */
833: public function SetWordWrap() {
834: if($this->WordWrap < 1) {
835: return;
836: }
837:
838: switch($this->message_type) {
839: case 'alt':
840: /* fall through */
841: case 'alt_attachments':
842: $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
843: break;
844: default:
845: $this->Body = $this->WrapText($this->Body, $this->WordWrap);
846: break;
847: }
848: }
849:
850: /**
851: * Assembles message header.
852: * @access public
853: * @return string
854: */
855: public function CreateHeader() {
856: $result = '';
857:
858: /* Set the boundaries */
859: $uniq_id = md5(uniqid(time()));
860: $this->boundary[1] = 'b1_' . $uniq_id;
861: $this->boundary[2] = 'b2_' . $uniq_id;
862:
863: $result .= $this->HeaderLine('Date', $this->RFCDate());
864: if($this->Sender == '') {
865: $result .= $this->HeaderLine('Return-Path', trim($this->From));
866: } else {
867: $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
868: }
869:
870: /* To be created automatically by mail() */
871: if($this->Mailer != 'mail') {
872: if(count($this->to) > 0) {
873: $result .= $this->AddrAppend('To', $this->to);
874: } elseif (count($this->cc) == 0) {
875: $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
876: }
877: if(count($this->cc) > 0) {
878: $result .= $this->AddrAppend('Cc', $this->cc);
879: }
880: }
881:
882: $from = array();
883: $from[0][0] = trim($this->From);
884: $from[0][1] = $this->FromName;
885: $result .= $this->AddrAppend('From', $from);
886:
887: /* sendmail and mail() extract Cc from the header before sending */
888: if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) {
889: $result .= $this->AddrAppend('Cc', $this->cc);
890: }
891:
892: /* sendmail and mail() extract Bcc from the header before sending */
893: if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
894: $result .= $this->AddrAppend('Bcc', $this->bcc);
895: }
896:
897: if(count($this->ReplyTo) > 0) {
898: $result .= $this->AddrAppend('Reply-to', $this->ReplyTo);
899: }
900:
901: /* mail() sets the subject itself */
902: if($this->Mailer != 'mail') {
903: $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
904: }
905:
906: if($this->MessageID != '') {
907: $result .= $this->HeaderLine('Message-ID',$this->MessageID);
908: } else {
909: $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
910: }
911: $result .= $this->HeaderLine('X-Priority', $this->Priority);
912: $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.codeworxtech.com) [version ' . $this->Version . ']');
913:
914: if($this->ConfirmReadingTo != '') {
915: $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
916: }
917:
918: // Add custom headers
919: for($index = 0; $index < count($this->CustomHeader); $index++) {
920: $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
921: }
922: //$result .= $this->HeaderLine('MIME-Version', '1.0');
923: if (!$this->sign_key_file) {
924: $result .= $this->HeaderLine('MIME-Version', '1.0');
925: $result .= $this->GetMailMIME();
926: }
927:
928: return $result;
929: }
930:
931: /**
932: * Returns the message MIME.
933: * @access public
934: * @return string
935: */
936: public function GetMailMIME() {
937: $result = '';
938: switch($this->message_type) {
939: case 'plain':
940: $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
941: $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet);
942: break;
943: case 'attachments':
944: /* fall through */
945: case 'alt_attachments':
946: if($this->InlineImageExists()){
947: $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE);
948: } else {
949: $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
950: $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
951: }
952: break;
953: case 'alt':
954: $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
955: $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
956: break;
957: }
958:
959: if($this->Mailer != 'mail') {
960: $result .= $this->LE.$this->LE;
961: }
962:
963: return $result;
964: }
965:
966: /**
967: * Assembles the message body. Returns an empty string on failure.
968: * @access public
969: * @return string
970: */
971: public function CreateBody() {
972: $result = '';
973:
974: if ($this->sign_key_file) {
975: $result .= $this->GetMailMIME();
976: }
977:
978: $this->SetWordWrap();
979:
980: switch($this->message_type) {
981: case 'alt':
982: $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
983: $result .= $this->EncodeString($this->AltBody, $this->Encoding);
984: $result .= $this->LE.$this->LE;
985: $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
986: $result .= $this->EncodeString($this->Body, $this->Encoding);
987: $result .= $this->LE.$this->LE;
988: $result .= $this->EndBoundary($this->boundary[1]);
989: break;
990: case 'plain':
991: $result .= $this->EncodeString($this->Body, $this->Encoding);
992: break;
993: case 'attachments':
994: $result .= $this->GetBoundary($this->boundary[1], '', '', '');
995: $result .= $this->EncodeString($this->Body, $this->Encoding);
996: $result .= $this->LE;
997: $result .= $this->AttachAll();
998: break;
999: case 'alt_attachments':
1000: $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
1001: $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE);
1002: $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body
1003: $result .= $this->EncodeString($this->AltBody, $this->Encoding);
1004: $result .= $this->LE.$this->LE;
1005: $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body
1006: $result .= $this->EncodeString($this->Body, $this->Encoding);
1007: $result .= $this->LE.$this->LE;
1008: $result .= $this->EndBoundary($this->boundary[2]);
1009: $result .= $this->AttachAll();
1010: break;
1011: }
1012:
1013: if($this->IsError()) {
1014: $result = '';
1015: } else if ($this->sign_key_file) {
1016: $file = tempnam("", "mail");
1017: $fp = fopen($file, "w");
1018: fwrite($fp, $result);
1019: fclose($fp);
1020: $signed = tempnam("", "signed");
1021:
1022: if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_key_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) {
1023: $fp = fopen($signed, "r");
1024: $result = fread($fp, filesize($this->sign_key_file));
1025: fclose($fp);
1026: } else {
1027: $this->SetError($this->Lang("signing").openssl_error_string());
1028: $result = '';
1029: }
1030:
1031: unlink($file);
1032: unlink($signed);
1033: }
1034:
1035: return $result;
1036: }
1037:
1038: /**
1039: * Returns the start of a message boundary.
1040: * @access public
1041: */
1042: public function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1043: $result = '';
1044: if($charSet == '') {
1045: $charSet = $this->CharSet;
1046: }
1047: if($contentType == '') {
1048: $contentType = $this->ContentType;
1049: }
1050: if($encoding == '') {
1051: $encoding = $this->Encoding;
1052: }
1053: $result .= $this->TextLine('--' . $boundary);
1054: $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet);
1055: $result .= $this->LE;
1056: $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1057: $result .= $this->LE;
1058:
1059: return $result;
1060: }
1061:
1062: /**
1063: * Returns the end of a message boundary.
1064: * @access public
1065: */
1066: public function EndBoundary($boundary) {
1067: return $this->LE . '--' . $boundary . '--' . $this->LE;
1068: }
1069:
1070: /**
1071: * Sets the message type.
1072: * @access public
1073: * @return void
1074: */
1075: public function SetMessageType() {
1076: if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) {
1077: $this->message_type = 'plain';
1078: } else {
1079: if(count($this->attachment) > 0) {
1080: $this->message_type = 'attachments';
1081: }
1082: if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) {
1083: $this->message_type = 'alt';
1084: }
1085: if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) {
1086: $this->message_type = 'alt_attachments';
1087: }
1088: }
1089: }
1090:
1091: /* Returns a formatted header line.
1092: * @access public
1093: * @return string
1094: */
1095: public function HeaderLine($name, $value) {
1096: return $name . ': ' . $value . $this->LE;
1097: }
1098:
1099: /**
1100: * Returns a formatted mail line.
1101: * @access public
1102: * @return string
1103: */
1104: public function TextLine($value) {
1105: return $value . $this->LE;
1106: }
1107:
1108: /////////////////////////////////////////////////
1109: // CLASS METHODS, ATTACHMENTS
1110: /////////////////////////////////////////////////
1111:
1112: /**
1113: * Adds an attachment from a path on the filesystem.
1114: * Returns false if the file could not be found
1115: * or accessed.
1116: * @param string $path Path to the attachment.
1117: * @param string $name Overrides the attachment name.
1118: * @param string $encoding File encoding (see $Encoding).
1119: * @param string $type File extension (MIME) type.
1120: * @return bool
1121: */
1122: public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1123: if(!@is_file($path)) {
1124: $this->SetError($this->Lang('file_access') . $path);
1125: return false;
1126: }
1127:
1128: $filename = basename($path);
1129: if($name == '') {
1130: $name = $filename;
1131: }
1132:
1133: $cur = count($this->attachment);
1134: $this->attachment[$cur][0] = $path;
1135: $this->attachment[$cur][1] = $filename;
1136: $this->attachment[$cur][2] = $name;
1137: $this->attachment[$cur][3] = $encoding;
1138: $this->attachment[$cur][4] = $type;
1139: $this->attachment[$cur][5] = false; // isStringAttachment
1140: $this->attachment[$cur][6] = 'attachment';
1141: $this->attachment[$cur][7] = 0;
1142:
1143: return true;
1144: }
1145:
1146: /**
1147: * Attaches all fs, string, and binary attachments to the message.
1148: * Returns an empty string on failure.
1149: * @access public
1150: * @return string
1151: */
1152: public function AttachAll() {
1153: /* Return text of body */
1154: $mime = array();
1155:
1156: /* Add all attachments */
1157: for($i = 0; $i < count($this->attachment); $i++) {
1158: /* Check for string attachment */
1159: $bString = $this->attachment[$i][5];
1160: if ($bString) {
1161: $string = $this->attachment[$i][0];
1162: } else {
1163: $path = $this->attachment[$i][0];
1164: }
1165:
1166: $filename = $this->attachment[$i][1];
1167: $name = $this->attachment[$i][2];
1168: $encoding = $this->attachment[$i][3];
1169: $type = $this->attachment[$i][4];
1170: $disposition = $this->attachment[$i][6];
1171: $cid = $this->attachment[$i][7];
1172:
1173: $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
1174: $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
1175: $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1176:
1177: if($disposition == 'inline') {
1178: $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1179: }
1180:
1181: $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $name, $this->LE.$this->LE);
1182:
1183: /* Encode as string attachment */
1184: if($bString) {
1185: $mime[] = $this->EncodeString($string, $encoding);
1186: if($this->IsError()) {
1187: return '';
1188: }
1189: $mime[] = $this->LE.$this->LE;
1190: } else {
1191: $mime[] = $this->EncodeFile($path, $encoding);
1192: if($this->IsError()) {
1193: return '';
1194: }
1195: $mime[] = $this->LE.$this->LE;
1196: }
1197: }
1198:
1199: $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
1200:
1201: return join('', $mime);
1202: }
1203:
1204: /**
1205: * Encodes attachment in requested format. Returns an
1206: * empty string on failure.
1207: * @access public
1208: * @return string
1209: */
1210: public function EncodeFile ($path, $encoding = 'base64') {
1211: if(!@$fd = fopen($path, 'rb')) {
1212: $this->SetError($this->Lang('file_open') . $path);
1213: return '';
1214: }
1215: $magic_quotes = get_magic_quotes_runtime();
1216: set_magic_quotes_runtime(0);
1217: $file_buffer = file_get_contents($path);
1218: $file_buffer = $this->EncodeString($file_buffer, $encoding);
1219: fclose($fd);
1220: set_magic_quotes_runtime($magic_quotes);
1221:
1222: return $file_buffer;
1223: }
1224:
1225: /**
1226: * Encodes string to requested format. Returns an
1227: * empty string on failure.
1228: * @access public
1229: * @return string
1230: */
1231: public function EncodeString ($str, $encoding = 'base64') {
1232: $encoded = '';
1233: switch(strtolower($encoding)) {
1234: case 'base64':
1235: $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1236: break;
1237: case '7bit':
1238: case '8bit':
1239: $encoded = $this->FixEOL($str);
1240: if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1241: $encoded .= $this->LE;
1242: break;
1243: case 'binary':
1244: $encoded = $str;
1245: break;
1246: case 'quoted-printable':
1247: $encoded = $this->EncodeQP($str);
1248: break;
1249: default:
1250: $this->SetError($this->Lang('encoding') . $encoding);
1251: break;
1252: }
1253: return $encoded;
1254: }
1255:
1256: /**
1257: * Encode a header string to best of Q, B, quoted or none.
1258: * @access public
1259: * @return string
1260: */
1261: public function EncodeHeader ($str, $position = 'text') {
1262: $x = 0;
1263:
1264: switch (strtolower($position)) {
1265: case 'phrase':
1266: if (!preg_match('/[\200-\377]/', $str)) {
1267: /* Can't use addslashes as we don't know what value has magic_quotes_sybase. */
1268: $encoded = addcslashes($str, "\0..\37\177\\\"");
1269: if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1270: return ($encoded);
1271: } else {
1272: return ("\"$encoded\"");
1273: }
1274: }
1275: $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1276: break;
1277: case 'comment':
1278: $x = preg_match_all('/[()"]/', $str, $matches);
1279: /* Fall-through */
1280: case 'text':
1281: default:
1282: $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1283: break;
1284: }
1285:
1286: if ($x == 0) {
1287: return ($str);
1288: }
1289:
1290: $maxlen = 75 - 7 - strlen($this->CharSet);
1291: /* Try to select the encoding which should produce the shortest output */
1292: if (strlen($str)/3 < $x) {
1293: $encoding = 'B';
1294: if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1295: // Use a custom function which correctly encodes and wraps long
1296: // multibyte strings without breaking lines within a character
1297: $encoded = $this->Base64EncodeWrapMB($str);
1298: } else {
1299: $encoded = base64_encode($str);
1300: $maxlen -= $maxlen % 4;
1301: $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1302: }
1303: } else {
1304: $encoding = 'Q';
1305: $encoded = $this->EncodeQ($str, $position);
1306: $encoded = $this->WrapText($encoded, $maxlen, true);
1307: $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1308: }
1309:
1310: $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1311: $encoded = trim(str_replace("\n", $this->LE, $encoded));
1312:
1313: return $encoded;
1314: }
1315:
1316: /**
1317: * Checks if a string contains multibyte characters.
1318: * @access public
1319: * @param string $str multi-byte text to wrap encode
1320: * @return bool
1321: */
1322: public function HasMultiBytes($str) {
1323: if (function_exists('mb_strlen')) {
1324: return (strlen($str) > mb_strlen($str, $this->CharSet));
1325: } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
1326: return False;
1327: }
1328: }
1329:
1330: /**
1331: * Correctly encodes and wraps long multibyte strings for mail headers
1332: * without breaking lines within a character.
1333: * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php
1334: * @access public
1335: * @param string $str multi-byte text to wrap encode
1336: * @return string
1337: */
1338: public function Base64EncodeWrapMB($str) {
1339: $start = "=?".$this->CharSet."?B?";
1340: $end = "?=";
1341: $encoded = "";
1342:
1343: $mb_length = mb_strlen($str, $this->CharSet);
1344: // Each line must have length <= 75, including $start and $end
1345: $length = 75 - strlen($start) - strlen($end);
1346: // Average multi-byte ratio
1347: $ratio = $mb_length / strlen($str);
1348: // Base64 has a 4:3 ratio
1349: $offset = $avgLength = floor($length * $ratio * .75);
1350:
1351: for ($i = 0; $i < $mb_length; $i += $offset) {
1352: $lookBack = 0;
1353:
1354: do {
1355: $offset = $avgLength - $lookBack;
1356: $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1357: $chunk = base64_encode($chunk);
1358: $lookBack++;
1359: }
1360: while (strlen($chunk) > $length);
1361:
1362: $encoded .= $chunk . $this->LE;
1363: }
1364:
1365: // Chomp the last linefeed
1366: $encoded = substr($encoded, 0, -strlen($this->LE));
1367: return $encoded;
1368: }
1369:
1370: /**
1371: * Encode string to quoted-printable.
1372: * @access public
1373: * @param string $string the text to encode
1374: * @param integer $line_max Number of chars allowed on a line before wrapping
1375: * @return string
1376: */
1377: public function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) {
1378: $hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
1379: $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1380: $eol = "\r\n";
1381: $escape = '=';
1382: $output = '';
1383: while( list(, $line) = each($lines) ) {
1384: $linlen = strlen($line);
1385: $newline = '';
1386: for($i = 0; $i < $linlen; $i++) {
1387: $c = substr( $line, $i, 1 );
1388: $dec = ord( $c );
1389: if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E
1390: $c = '=2E';
1391: }
1392: if ( $dec == 32 ) {
1393: if ( $i == ( $linlen - 1 ) ) { // convert space at eol only
1394: $c = '=20';
1395: } else if ( $space_conv ) {
1396: $c = '=20';
1397: }
1398: } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required
1399: $h2 = floor($dec/16);
1400: $h1 = floor($dec%16);
1401: $c = $escape.$hex[$h2].$hex[$h1];
1402: }
1403: if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted
1404: $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay
1405: $newline = '';
1406: // check if newline first character will be point or not
1407: if ( $dec == 46 ) {
1408: $c = '=2E';
1409: }
1410: }
1411: $newline .= $c;
1412: } // end of for
1413: $output .= $newline.$eol;
1414: } // end of while
1415: return trim($output);
1416: }
1417:
1418: /**
1419: * Encode string to q encoding.
1420: * @access public
1421: * @return string
1422: */
1423: public function EncodeQ ($str, $position = 'text') {
1424: /* There should not be any EOL in the string */
1425: $encoded = preg_replace("[\r\n]", '', $str);
1426:
1427: switch (strtolower($position)) {
1428: case 'phrase':
1429: $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1430: break;
1431: case 'comment':
1432: $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1433: case 'text':
1434: default:
1435: /* Replace every high ascii, control =, ? and _ characters */
1436: $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1437: "'='.sprintf('%02X', ord('\\1'))", $encoded);
1438: break;
1439: }
1440:
1441: /* Replace every spaces to _ (more readable than =20) */
1442: $encoded = str_replace(' ', '_', $encoded);
1443:
1444: return $encoded;
1445: }
1446:
1447: /**
1448: * Adds a string or binary attachment (non-filesystem) to the list.
1449: * This method can be used to attach ascii or binary data,
1450: * such as a BLOB record from a database.
1451: * @param string $string String attachment data.
1452: * @param string $filename Name of the attachment.
1453: * @param string $encoding File encoding (see $Encoding).
1454: * @param string $type File extension (MIME) type.
1455: * @return void
1456: */
1457: public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1458: /* Append to $attachment array */
1459: $cur = count($this->attachment);
1460: $this->attachment[$cur][0] = $string;
1461: $this->attachment[$cur][1] = $filename;
1462: $this->attachment[$cur][2] = $filename;
1463: $this->attachment[$cur][3] = $encoding;
1464: $this->attachment[$cur][4] = $type;
1465: $this->attachment[$cur][5] = true; // isString
1466: $this->attachment[$cur][6] = 'attachment';
1467: $this->attachment[$cur][7] = 0;
1468: }
1469:
1470: /**
1471: * Adds an embedded attachment. This can include images, sounds, and
1472: * just about any other document. Make sure to set the $type to an
1473: * image type. For JPEG images use "image/jpeg" and for GIF images
1474: * use "image/gif".
1475: * @param string $path Path to the attachment.
1476: * @param string $cid Content ID of the attachment. Use this to identify
1477: * the Id for accessing the image in an HTML form.
1478: * @param string $name Overrides the attachment name.
1479: * @param string $encoding File encoding (see $Encoding).
1480: * @param string $type File extension (MIME) type.
1481: * @return bool
1482: */
1483: public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1484:
1485: if(!@is_file($path)) {
1486: $this->SetError($this->Lang('file_access') . $path);
1487: return false;
1488: }
1489:
1490: $filename = basename($path);
1491: if($name == '') {
1492: $name = $filename;
1493: }
1494:
1495: /* Append to $attachment array */
1496: $cur = count($this->attachment);
1497: $this->attachment[$cur][0] = $path;
1498: $this->attachment[$cur][1] = $filename;
1499: $this->attachment[$cur][2] = $name;
1500: $this->attachment[$cur][3] = $encoding;
1501: $this->attachment[$cur][4] = $type;
1502: $this->attachment[$cur][5] = false;
1503: $this->attachment[$cur][6] = 'inline';
1504: $this->attachment[$cur][7] = $cid;
1505:
1506: return true;
1507: }
1508:
1509: /**
1510: * Returns true if an inline attachment is present.
1511: * @access public
1512: * @return bool
1513: */
1514: public function InlineImageExists() {
1515: $result = false;
1516: for($i = 0; $i < count($this->attachment); $i++) {
1517: if($this->attachment[$i][6] == 'inline') {
1518: $result = true;
1519: break;
1520: }
1521: }
1522:
1523: return $result;
1524: }
1525:
1526: /////////////////////////////////////////////////
1527: // CLASS METHODS, MESSAGE RESET
1528: /////////////////////////////////////////////////
1529:
1530: /**
1531: * Clears all recipients assigned in the TO array. Returns void.
1532: * @return void
1533: */
1534: public function ClearAddresses() {
1535: $this->to = array();
1536: }
1537:
1538: /**
1539: * Clears all recipients assigned in the CC array. Returns void.
1540: * @return void
1541: */
1542: public function ClearCCs() {
1543: $this->cc = array();
1544: }
1545:
1546: /**
1547: * Clears all recipients assigned in the BCC array. Returns void.
1548: * @return void
1549: */
1550: public function ClearBCCs() {
1551: $this->bcc = array();
1552: }
1553:
1554: /**
1555: * Clears all recipients assigned in the ReplyTo array. Returns void.
1556: * @return void
1557: */
1558: public function ClearReplyTos() {
1559: $this->ReplyTo = array();
1560: }
1561:
1562: /**
1563: * Clears all recipients assigned in the TO, CC and BCC
1564: * array. Returns void.
1565: * @return void
1566: */
1567: public function ClearAllRecipients() {
1568: $this->to = array();
1569: $this->cc = array();
1570: $this->bcc = array();
1571: }
1572:
1573: /**
1574: * Clears all previously set filesystem, string, and binary
1575: * attachments. Returns void.
1576: * @return void
1577: */
1578: public function ClearAttachments() {
1579: $this->attachment = array();
1580: }
1581:
1582: /**
1583: * Clears all custom headers. Returns void.
1584: * @return void
1585: */
1586: public function ClearCustomHeaders() {
1587: $this->CustomHeader = array();
1588: }
1589:
1590: /////////////////////////////////////////////////
1591: // CLASS METHODS, MISCELLANEOUS
1592: /////////////////////////////////////////////////
1593:
1594: /**
1595: * Adds the error message to the error container.
1596: * Returns void.
1597: * @access private
1598: * @return void
1599: */
1600: private function SetError($msg) {
1601: $this->error_count++;
1602: $this->ErrorInfo = $msg;
1603: }
1604:
1605: /**
1606: * Returns the proper RFC 822 formatted date.
1607: * @access private
1608: * @return string
1609: */
1610: private static function RFCDate() {
1611: $tz = date('Z');
1612: $tzs = ($tz < 0) ? '-' : '+';
1613: $tz = abs($tz);
1614: $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
1615: $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
1616:
1617: return $result;
1618: }
1619:
1620: /**
1621: * Returns the server hostname or 'localhost.localdomain' if unknown.
1622: * @access private
1623: * @return string
1624: */
1625: private function ServerHostname() {
1626: if (!empty($this->Hostname)) {
1627: $result = $this->Hostname;
1628: } elseif (isset($_SERVER['SERVER_NAME'])) {
1629: $result = $_SERVER['SERVER_NAME'];
1630: } else {
1631: $result = "localhost.localdomain";
1632: }
1633:
1634: return $result;
1635: }
1636:
1637: /**
1638: * Returns a message in the appropriate language.
1639: * @access private
1640: * @return string
1641: */
1642: private function Lang($key) {
1643: if(count($this->language) < 1) {
1644: $this->SetLanguage('en'); // set the default language
1645: }
1646:
1647: if(isset($this->language[$key])) {
1648: return $this->language[$key];
1649: } else {
1650: return 'Language string failed to load: ' . $key;
1651: }
1652: }
1653:
1654: /**
1655: * Returns true if an error occurred.
1656: * @access public
1657: * @return bool
1658: */
1659: public function IsError() {
1660: return ($this->error_count > 0);
1661: }
1662:
1663: /**
1664: * Changes every end of line from CR or LF to CRLF.
1665: * @access private
1666: * @return string
1667: */
1668: private function FixEOL($str) {
1669: $str = str_replace("\r\n", "\n", $str);
1670: $str = str_replace("\r", "\n", $str);
1671: $str = str_replace("\n", $this->LE, $str);
1672: return $str;
1673: }
1674:
1675: /**
1676: * Adds a custom header.
1677: * @access public
1678: * @return void
1679: */
1680: public function AddCustomHeader($custom_header) {
1681: $this->CustomHeader[] = explode(':', $custom_header, 2);
1682: }
1683:
1684: /**
1685: * Evaluates the message and returns modifications for inline images and backgrounds
1686: * @access public
1687: * @return $message
1688: */
1689: public function MsgHTML($message,$basedir='') {
1690: preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images);
1691: if(isset($images[2])) {
1692: foreach($images[2] as $i => $url) {
1693: // do not change urls for absolute images (thanks to corvuscorax)
1694: if (!preg_match('/^[A-z][A-z]*:\/\//',$url)) {
1695: $filename = basename($url);
1696: $directory = dirname($url);
1697: ($directory == '.')?$directory='':'';
1698: $cid = 'cid:' . md5($filename);
1699: $fileParts = split("\.", $filename);
1700: $ext = $fileParts[1];
1701: $mimeType = $this->_mime_types($ext);
1702: if ( strlen($basedir) > 1 && substr($basedir,-1) != '/') { $basedir .= '/'; }
1703: if ( strlen($directory) > 1 && substr($basedir,-1) != '/') { $directory .= '/'; }
1704: $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType);
1705: if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64',$mimeType) ) {
1706: $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message);
1707: }
1708: }
1709: }
1710: }
1711: $this->IsHTML(true);
1712: $this->Body = $message;
1713: $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s','',$message)));
1714: if ( !empty($textMsg) && empty($this->AltBody) ) {
1715: $this->AltBody = $textMsg;
1716: }
1717: if ( empty($this->AltBody) ) {
1718: $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n";
1719: }
1720: }
1721:
1722: /**
1723: * Gets the mime type of the embedded or inline image
1724: * @access public
1725: * @return mime type of ext
1726: */
1727: public function _mime_types($ext = '') {
1728: $mimes = array(
1729: 'hqx' => 'application/mac-binhex40',
1730: 'cpt' => 'application/mac-compactpro',
1731: 'doc' => 'application/msword',
1732: 'bin' => 'application/macbinary',
1733: 'dms' => 'application/octet-stream',
1734: 'lha' => 'application/octet-stream',
1735: 'lzh' => 'application/octet-stream',
1736: 'exe' => 'application/octet-stream',
1737: 'class' => 'application/octet-stream',
1738: 'psd' => 'application/octet-stream',
1739: 'so' => 'application/octet-stream',
1740: 'sea' => 'application/octet-stream',
1741: 'dll' => 'application/octet-stream',
1742: 'oda' => 'application/oda',
1743: 'pdf' => 'application/pdf',
1744: 'ai' => 'application/postscript',
1745: 'eps' => 'application/postscript',
1746: 'ps' => 'application/postscript',
1747: 'smi' => 'application/smil',
1748: 'smil' => 'application/smil',
1749: 'mif' => 'application/vnd.mif',
1750: 'xls' => 'application/vnd.ms-excel',
1751: 'ppt' => 'application/vnd.ms-powerpoint',
1752: 'wbxml' => 'application/vnd.wap.wbxml',
1753: 'wmlc' => 'application/vnd.wap.wmlc',
1754: 'dcr' => 'application/x-director',
1755: 'dir' => 'application/x-director',
1756: 'dxr' => 'application/x-director',
1757: 'dvi' => 'application/x-dvi',
1758: 'gtar' => 'application/x-gtar',
1759: 'php' => 'application/x-httpd-php',
1760: 'php4' => 'application/x-httpd-php',
1761: 'php3' => 'application/x-httpd-php',
1762: 'phtml' => 'application/x-httpd-php',
1763: 'phps' => 'application/x-httpd-php-source',
1764: 'js' => 'application/x-javascript',
1765: 'swf' => 'application/x-shockwave-flash',
1766: 'sit' => 'application/x-stuffit',
1767: 'tar' => 'application/x-tar',
1768: 'tgz' => 'application/x-tar',
1769: 'xhtml' => 'application/xhtml+xml',
1770: 'xht' => 'application/xhtml+xml',
1771: 'zip' => 'application/zip',
1772: 'mid' => 'audio/midi',
1773: 'midi' => 'audio/midi',
1774: 'mpga' => 'audio/mpeg',
1775: 'mp2' => 'audio/mpeg',
1776: 'mp3' => 'audio/mpeg',
1777: 'aif' => 'audio/x-aiff',
1778: 'aiff' => 'audio/x-aiff',
1779: 'aifc' => 'audio/x-aiff',
1780: 'ram' => 'audio/x-pn-realaudio',
1781: 'rm' => 'audio/x-pn-realaudio',
1782: 'rpm' => 'audio/x-pn-realaudio-plugin',
1783: 'ra' => 'audio/x-realaudio',
1784: 'rv' => 'video/vnd.rn-realvideo',
1785: 'wav' => 'audio/x-wav',
1786: 'bmp' => 'image/bmp',
1787: 'gif' => 'image/gif',
1788: 'jpeg' => 'image/jpeg',
1789: 'jpg' => 'image/jpeg',
1790: 'jpe' => 'image/jpeg',
1791: 'png' => 'image/png',
1792: 'tiff' => 'image/tiff',
1793: 'tif' => 'image/tiff',
1794: 'css' => 'text/css',
1795: 'html' => 'text/html',
1796: 'htm' => 'text/html',
1797: 'shtml' => 'text/html',
1798: 'txt' => 'text/plain',
1799: 'text' => 'text/plain',
1800: 'log' => 'text/plain',
1801: 'rtx' => 'text/richtext',
1802: 'rtf' => 'text/rtf',
1803: 'xml' => 'text/xml',
1804: 'xsl' => 'text/xml',
1805: 'mpeg' => 'video/mpeg',
1806: 'mpg' => 'video/mpeg',
1807: 'mpe' => 'video/mpeg',
1808: 'qt' => 'video/quicktime',
1809: 'mov' => 'video/quicktime',
1810: 'avi' => 'video/x-msvideo',
1811: 'movie' => 'video/x-sgi-movie',
1812: 'doc' => 'application/msword',
1813: 'word' => 'application/msword',
1814: 'xl' => 'application/excel',
1815: 'eml' => 'message/rfc822'
1816: );
1817: return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
1818: }
1819:
1820: /**
1821: * Set (or reset) Class Objects (variables)
1822: *
1823: * Usage Example:
1824: * $page->set('X-Priority', '3');
1825: *
1826: * @access public
1827: * @param string $name Parameter Name
1828: * @param mixed $value Parameter Value
1829: * NOTE: will not work with arrays, there are no arrays to set/reset
1830: */
1831: public function set ( $name, $value = '' ) {
1832: if ( isset($this->$name) ) {
1833: $this->$name = $value;
1834: } else {
1835: $this->SetError('Cannot set or reset variable ' . $name);
1836: return false;
1837: }
1838: }
1839:
1840: /**
1841: * Read a file from a supplied filename and return it.
1842: *
1843: * @access public
1844: * @param string $filename Parameter File Name
1845: */
1846: public function getFile($filename) {
1847: $return = '';
1848: if ($fp = fopen($filename, 'rb')) {
1849: while (!feof($fp)) {
1850: $return .= fread($fp, 1024);
1851: }
1852: fclose($fp);
1853: return $return;
1854: } else {
1855: return false;
1856: }
1857: }
1858:
1859: /**
1860: * Strips newlines to prevent header injection.
1861: * @access public
1862: * @param string $str String
1863: * @return string
1864: */
1865: public function SecureHeader($str) {
1866: $str = trim($str);
1867: $str = str_replace("\r", "", $str);
1868: $str = str_replace("\n", "", $str);
1869: return $str;
1870: }
1871:
1872: /**
1873: * Set the private key file and password to sign the message.
1874: *
1875: * @access public
1876: * @param string $key_filename Parameter File Name
1877: * @param string $key_pass Password for private key
1878: */
1879: public function Sign($key_filename, $key_pass) {
1880: $this->sign_key_file = $key_filename;
1881: $this->sign_key_pass = $key_pass;
1882: }
1883:
1884: }
1885:
1886: ?>
1887: