1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23:
24:
25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36:
37:
38: if (version_compare(PHP_VERSION, '5.0.0', '<') ) exit("Sorry, this version of PHPMailer will only run on PHP version 5 or greater!\n");
39:
40: class Net_PHPMailer {
41:
42:
43:
44:
45:
46: 47: 48: 49:
50: public $Priority = 3;
51:
52: 53: 54: 55:
56: public $CharSet = 'iso-8859-1';
57:
58: 59: 60: 61:
62: public $ContentType = 'text/plain';
63:
64: 65: 66: 67: 68:
69: public $Encoding = '8bit';
70:
71: 72: 73: 74:
75: public $ErrorInfo = '';
76:
77: 78: 79: 80:
81: public $From = 'root@localhost';
82:
83: 84: 85: 86:
87: public $FromName = 'Root User';
88:
89: 90: 91: 92: 93:
94: public $Sender = '';
95:
96: 97: 98: 99:
100: public $Subject = '';
101:
102: 103: 104: 105: 106:
107: public $Body = '';
108:
109: 110: 111: 112: 113: 114: 115:
116: public $AltBody = '';
117:
118: 119: 120: 121: 122:
123: protected $MIMEBody = '';
124:
125: 126: 127: 128: 129:
130: protected $MIMEHeader = '';
131:
132: 133: 134: 135: 136:
137: protected $SentMIMEMessage = '';
138:
139: 140: 141: 142: 143:
144: public $WordWrap = 0;
145:
146: 147: 148: 149:
150: public $Mailer = 'mail';
151:
152: 153: 154: 155:
156: public $Sendmail = '/usr/sbin/sendmail';
157:
158: 159: 160: 161: 162:
163: public $PluginDir = '';
164:
165: 166: 167: 168:
169: public $ConfirmReadingTo = '';
170:
171: 172: 173: 174: 175: 176:
177: public $Hostname = '';
178:
179: 180: 181: 182: 183:
184: public $MessageID = '';
185:
186:
187:
188:
189:
190: 191: 192: 193: 194: 195: 196: 197:
198: public $Host = 'localhost';
199:
200: 201: 202: 203:
204: public $Port = 25;
205:
206: 207: 208: 209:
210: public $Helo = '';
211:
212: 213: 214: 215: 216:
217: public $SMTPSecure = '';
218:
219: 220: 221: 222:
223: public $SMTPAuth = false;
224:
225: 226: 227: 228:
229: public $Username = '';
230:
231: 232: 233: 234:
235: public $Password = '';
236:
237: 238: 239: 240: 241:
242: public $Timeout = 10;
243:
244: 245: 246: 247:
248: public $SMTPDebug = false;
249:
250: 251: 252: 253: 254: 255:
256: public $SMTPKeepAlive = false;
257:
258: 259: 260: 261: 262:
263: public $SingleTo = false;
264:
265: 266: 267: 268:
269: public $SingleToArray = array();
270:
271: 272: 273: 274:
275: public $LE = "\n";
276:
277: 278: 279: 280:
281: public $DKIM_selector = 'phpmailer';
282:
283: 284: 285: 286: 287:
288: public $DKIM_identity = '';
289:
290: 291: 292: 293:
294: public $DKIM_passphrase = '';
295:
296: 297: 298: 299: 300:
301: public $DKIM_domain = '';
302:
303: 304: 305: 306: 307:
308: public $DKIM_private = '';
309:
310: 311: 312: 313: 314: 315: 316: 317: 318: 319: 320:
321: public $action_function = '';
322:
323: 324: 325: 326:
327: public $Version = '5.2.1';
328:
329: 330: 331: 332:
333: public $XMailer = '';
334:
335:
336:
337:
338:
339: protected $smtp = NULL;
340: protected $to = array();
341: protected $cc = array();
342: protected $bcc = array();
343: protected $ReplyTo = array();
344: protected $all_recipients = array();
345: protected $attachment = array();
346: protected $CustomHeader = array();
347: protected $message_type = '';
348: protected $boundary = array();
349: protected $language = array();
350: protected $error_count = 0;
351: protected $sign_cert_file = '';
352: protected $sign_key_file = '';
353: protected $sign_key_pass = '';
354: protected $exceptions = false;
355:
356:
357:
358:
359:
360: const STOP_MESSAGE = 0;
361: const STOP_CONTINUE = 1;
362: const STOP_CRITICAL = 2;
363:
364:
365:
366:
367:
368: 369: 370: 371:
372: public function __construct($exceptions = false) {
373: $this->exceptions = ($exceptions == true);
374: }
375:
376: 377: 378: 379: 380:
381: public function IsHTML($ishtml = true) {
382: if ($ishtml) {
383: $this->ContentType = 'text/html';
384: } else {
385: $this->ContentType = 'text/plain';
386: }
387: }
388:
389: 390: 391: 392:
393: public function IsSMTP() {
394: $this->Mailer = 'smtp';
395: }
396:
397: 398: 399: 400:
401: public function IsMail() {
402: $this->Mailer = 'mail';
403: }
404:
405: 406: 407: 408:
409: public function IsSendmail() {
410: if (!stristr(ini_get('sendmail_path'), 'sendmail')) {
411: $this->Sendmail = '/var/qmail/bin/sendmail';
412: }
413: $this->Mailer = 'sendmail';
414: }
415:
416: 417: 418: 419:
420: public function IsQmail() {
421: if (stristr(ini_get('sendmail_path'), 'qmail')) {
422: $this->Sendmail = '/var/qmail/bin/sendmail';
423: }
424: $this->Mailer = 'sendmail';
425: }
426:
427:
428:
429:
430:
431: 432: 433: 434: 435: 436:
437: public function AddAddress($address, $name = '') {
438: return $this->AddAnAddress('to', $address, $name);
439: }
440:
441: 442: 443: 444: 445: 446: 447:
448: public function AddCC($address, $name = '') {
449: return $this->AddAnAddress('cc', $address, $name);
450: }
451:
452: 453: 454: 455: 456: 457: 458:
459: public function AddBCC($address, $name = '') {
460: return $this->AddAnAddress('bcc', $address, $name);
461: }
462:
463: 464: 465: 466: 467: 468:
469: public function AddReplyTo($address, $name = '') {
470: return $this->AddAnAddress('Reply-To', $address, $name);
471: }
472:
473: 474: 475: 476: 477: 478: 479: 480: 481:
482: protected function AddAnAddress($kind, $address, $name = '') {
483: if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
484: $this->SetError($this->Lang('Invalid recipient array').': '.$kind);
485: if ($this->exceptions) {
486: throw new Exception('Invalid recipient array: ' . $kind);
487: }
488: if ($this->SMTPDebug) {
489: echo $this->Lang('Invalid recipient array').': '.$kind;
490: }
491: return false;
492: }
493: $address = trim($address);
494: $name = trim(preg_replace('/[\r\n]+/', '', $name));
495: if (!self::ValidateAddress($address)) {
496: $this->SetError($this->Lang('invalid_address').': '. $address);
497: if ($this->exceptions) {
498: throw new Exception($this->Lang('invalid_address').': '.$address);
499: }
500: if ($this->SMTPDebug) {
501: echo $this->Lang('invalid_address').': '.$address;
502: }
503: return false;
504: }
505: if ($kind != 'Reply-To') {
506: if (!isset($this->all_recipients[strtolower($address)])) {
507: array_push($this->$kind, array($address, $name));
508: $this->all_recipients[strtolower($address)] = true;
509: return true;
510: }
511: } else {
512: if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
513: $this->ReplyTo[strtolower($address)] = array($address, $name);
514: return true;
515: }
516: }
517: return false;
518: }
519:
520: 521: 522: 523: 524: 525:
526: public function SetFrom($address, $name = '', $auto = 1) {
527: $address = trim($address);
528: $name = trim(preg_replace('/[\r\n]+/', '', $name));
529: if (!self::ValidateAddress($address)) {
530: $this->SetError($this->Lang('invalid_address').': '. $address);
531: if ($this->exceptions) {
532: throw new Exception($this->Lang('invalid_address').': '.$address);
533: }
534: if ($this->SMTPDebug) {
535: echo $this->Lang('invalid_address').': '.$address;
536: }
537: return false;
538: }
539: $this->From = $address;
540: $this->FromName = $name;
541: if ($auto) {
542: if (empty($this->ReplyTo)) {
543: $this->AddAnAddress('Reply-To', $address, $name);
544: }
545: if (empty($this->Sender)) {
546: $this->Sender = $address;
547: }
548: }
549: return true;
550: }
551:
552: 553: 554: 555: 556: 557: 558: 559: 560: 561: 562:
563: public static function ValidateAddress($address) {
564: if (function_exists('filter_var')) {
565: if(filter_var($address, FILTER_VALIDATE_EMAIL) === FALSE) {
566: return false;
567: } else {
568: return true;
569: }
570: } else {
571: return preg_match('/^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!\.)){0,61}[a-zA-Z0-9_-]?\.)+[a-zA-Z0-9_](?:[a-zA-Z0-9_\-](?!$)){0,61}[a-zA-Z0-9_]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/', $address);
572: }
573: }
574:
575:
576:
577:
578:
579: 580: 581: 582: 583: 584:
585: public function Send() {
586: try {
587: if(!$this->PreSend()) return false;
588: return $this->PostSend();
589: } catch (Exception $e) {
590: $this->SentMIMEMessage = '';
591: $this->SetError($e->getMessage());
592: if ($this->exceptions) {
593: throw $e;
594: }
595: return false;
596: }
597: }
598:
599: protected function PreSend() {
600: try {
601: $mailHeader = "";
602: if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
603: throw new Exception($this->Lang('provide_address'), self::STOP_CRITICAL);
604: }
605:
606:
607: if(!empty($this->AltBody)) {
608: $this->ContentType = 'multipart/alternative';
609: }
610:
611: $this->error_count = 0;
612: $this->SetMessageType();
613:
614: if (empty($this->Body)) {
615: throw new Exception($this->Lang('empty_message'), self::STOP_CRITICAL);
616: }
617:
618: $this->MIMEHeader = $this->CreateHeader();
619: $this->MIMEBody = $this->CreateBody();
620:
621:
622:
623: if ($this->Mailer == 'mail') {
624: if (count($this->to) > 0) {
625: $mailHeader .= $this->AddrAppend("To", $this->to);
626: } else {
627: $mailHeader .= $this->HeaderLine("To", "undisclosed-recipients:;");
628: }
629: $mailHeader .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader(trim($this->Subject))));
630:
631:
632:
633: }
634:
635:
636: if ($this->DKIM_domain && $this->DKIM_private) {
637: $header_dkim = $this->DKIM_Add($this->MIMEHeader, $this->EncodeHeader($this->SecureHeader($this->Subject)), $this->MIMEBody);
638: $this->MIMEHeader = str_replace("\r\n", "\n", $header_dkim) . $this->MIMEHeader;
639: }
640:
641: $this->SentMIMEMessage = sprintf("%s%s\r\n\r\n%s",$this->MIMEHeader,$mailHeader,$this->MIMEBody);
642: return true;
643:
644: } catch (Exception $e) {
645: $this->SetError($e->getMessage());
646: if ($this->exceptions) {
647: throw $e;
648: }
649: return false;
650: }
651: }
652:
653: protected function PostSend() {
654: try {
655:
656: switch($this->Mailer) {
657: case 'sendmail':
658: return $this->SendmailSend($this->MIMEHeader, $this->MIMEBody);
659: case 'smtp':
660: return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
661: case 'mail':
662: return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
663: default:
664: return $this->MailSend($this->MIMEHeader, $this->MIMEBody);
665: }
666:
667: } catch (Exception $e) {
668: $this->SetError($e->getMessage());
669: if ($this->exceptions) {
670: throw $e;
671: }
672: if ($this->SMTPDebug) {
673: echo $e->getMessage()."\n";
674: }
675: return false;
676: }
677: }
678:
679: 680: 681: 682: 683: 684: 685:
686: protected function SendmailSend($header, $body) {
687: if ($this->Sender != '') {
688: $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
689: } else {
690: $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
691: }
692: if ($this->SingleTo === true) {
693: foreach ($this->SingleToArray as $key => $val) {
694: if(!@$mail = popen($sendmail, 'w')) {
695: throw new Exception($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
696: }
697: fputs($mail, "To: " . $val . "\n");
698: fputs($mail, $header);
699: fputs($mail, $body);
700: $result = pclose($mail);
701:
702: $isSent = ($result == 0) ? 1 : 0;
703: $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
704: if($result != 0) {
705: throw new Exception($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
706: }
707: }
708: } else {
709: if(!@$mail = popen($sendmail, 'w')) {
710: throw new Exception($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
711: }
712: fputs($mail, $header);
713: fputs($mail, $body);
714: $result = pclose($mail);
715:
716: $isSent = ($result == 0) ? 1 : 0;
717: $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
718: if($result != 0) {
719: throw new Exception($this->Lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
720: }
721: }
722: return true;
723: }
724:
725: 726: 727: 728: 729: 730: 731:
732: protected function MailSend($header, $body) {
733: $toArr = array();
734: foreach($this->to as $t) {
735: $toArr[] = $this->AddrFormat($t);
736: }
737: $to = implode(', ', $toArr);
738:
739: if (empty($this->Sender)) {
740: $params = "-oi ";
741: } else {
742: $params = sprintf("-oi -f %s", $this->Sender);
743: }
744: if ($this->Sender != '' and !ini_get('safe_mode')) {
745: $old_from = ini_get('sendmail_from');
746: ini_set('sendmail_from', $this->Sender);
747: if ($this->SingleTo === true && count($toArr) > 1) {
748: foreach ($toArr as $key => $val) {
749: $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
750:
751: $isSent = ($rt == 1) ? 1 : 0;
752: $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
753: }
754: } else {
755: $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
756:
757: $isSent = ($rt == 1) ? 1 : 0;
758: $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
759: }
760: } else {
761: if ($this->SingleTo === true && count($toArr) > 1) {
762: foreach ($toArr as $key => $val) {
763: $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
764:
765: $isSent = ($rt == 1) ? 1 : 0;
766: $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
767: }
768: } else {
769: $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
770:
771: $isSent = ($rt == 1) ? 1 : 0;
772: $this->doCallback($isSent, $to, $this->cc, $this->bcc, $this->Subject, $body);
773: }
774: }
775: if (isset($old_from)) {
776: ini_set('sendmail_from', $old_from);
777: }
778: if(!$rt) {
779: throw new Exception($this->Lang('instantiate'), self::STOP_CRITICAL);
780: }
781: return true;
782: }
783:
784: 785: 786: 787: 788: 789: 790: 791: 792:
793: protected function SmtpSend($header, $body) {
794: require_once $this->PluginDir . 'SMTP.class.php';
795: $bad_rcpt = array();
796:
797: if(!$this->SmtpConnect()) {
798: throw new Exception($this->Lang('smtp_connect_failed'), self::STOP_CRITICAL);
799: }
800: $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender;
801: if(!$this->smtp->Mail($smtp_from)) {
802: throw new Exception($this->Lang('from_failed') . $smtp_from, self::STOP_CRITICAL);
803: }
804:
805:
806: foreach($this->to as $to) {
807: if (!$this->smtp->Recipient($to[0])) {
808: $bad_rcpt[] = $to[0];
809:
810: $isSent = 0;
811: $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
812: } else {
813:
814: $isSent = 1;
815: $this->doCallback($isSent, $to[0], '', '', $this->Subject, $body);
816: }
817: }
818: foreach($this->cc as $cc) {
819: if (!$this->smtp->Recipient($cc[0])) {
820: $bad_rcpt[] = $cc[0];
821:
822: $isSent = 0;
823: $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
824: } else {
825:
826: $isSent = 1;
827: $this->doCallback($isSent, '', $cc[0], '', $this->Subject, $body);
828: }
829: }
830: foreach($this->bcc as $bcc) {
831: if (!$this->smtp->Recipient($bcc[0])) {
832: $bad_rcpt[] = $bcc[0];
833:
834: $isSent = 0;
835: $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
836: } else {
837:
838: $isSent = 1;
839: $this->doCallback($isSent, '', '', $bcc[0], $this->Subject, $body);
840: }
841: }
842:
843:
844: if (count($bad_rcpt) > 0 ) {
845: $badaddresses = implode(', ', $bad_rcpt);
846: throw new Exception($this->Lang('recipients_failed') . $badaddresses);
847: }
848: if(!$this->smtp->Data($header . $body)) {
849: throw new Exception($this->Lang('data_not_accepted'), self::STOP_CRITICAL);
850: }
851: if($this->SMTPKeepAlive == true) {
852: $this->smtp->Reset();
853: }
854: return true;
855: }
856:
857: 858: 859: 860: 861: 862: 863:
864: public function SmtpConnect() {
865: if(is_null($this->smtp)) {
866: $this->smtp = new Net_SMTP();
867: }
868:
869: $this->smtp->do_debug = $this->SMTPDebug;
870: $hosts = explode(';', $this->Host);
871: $index = 0;
872: $connection = $this->smtp->Connected();
873:
874:
875: try {
876: while($index < count($hosts) && !$connection) {
877: $hostinfo = array();
878: if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
879: $host = $hostinfo[1];
880: $port = $hostinfo[2];
881: } else {
882: $host = $hosts[$index];
883: $port = $this->Port;
884: }
885:
886: $tls = ($this->SMTPSecure == 'tls');
887: $ssl = ($this->SMTPSecure == 'ssl');
888:
889: if ($this->smtp->Connect(($ssl ? 'ssl://':'').$host, $port, $this->Timeout)) {
890:
891: $hello = ($this->Helo != '' ? $this->Helo : $this->ServerHostname());
892: $this->smtp->Hello($hello);
893:
894: if ($tls) {
895: if (!$this->smtp->StartTLS()) {
896: throw new Exception($this->Lang('tls'));
897: }
898:
899:
900: $this->smtp->Hello($hello);
901: }
902:
903: $connection = true;
904: if ($this->SMTPAuth) {
905: if (!$this->smtp->Authenticate($this->Username, $this->Password)) {
906: throw new Exception($this->Lang('authenticate'));
907: }
908: }
909: }
910: $index++;
911: if (!$connection) {
912: throw new Exception($this->Lang('connect_host'));
913: }
914: }
915: } catch (Exception $e) {
916: $this->smtp->Reset();
917: if ($this->exceptions) {
918: throw $e;
919: }
920: }
921: return true;
922: }
923:
924: 925: 926: 927:
928: public function SmtpClose() {
929: if(!is_null($this->smtp)) {
930: if($this->smtp->Connected()) {
931: $this->smtp->Quit();
932: $this->smtp->Close();
933: }
934: }
935: }
936:
937: 938: 939: 940: 941: 942: 943:
944: function SetLanguage($langcode = 'en', $lang_path = 'language/') {
945:
946: $PHPMAILER_LANG = array(
947: 'provide_address' => 'You must provide at least one recipient email address.',
948: 'mailer_not_supported' => ' mailer is not supported.',
949: 'execute' => 'Could not execute: ',
950: 'instantiate' => 'Could not instantiate mail function.',
951: 'authenticate' => 'SMTP Error: Could not authenticate.',
952: 'from_failed' => 'The following From address failed: ',
953: 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
954: 'data_not_accepted' => 'SMTP Error: Data not accepted.',
955: 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
956: 'file_access' => 'Could not access file: ',
957: 'file_open' => 'File Error: Could not open file: ',
958: 'encoding' => 'Unknown encoding: ',
959: 'signing' => 'Signing Error: ',
960: 'smtp_error' => 'SMTP server error: ',
961: 'empty_message' => 'Message body empty',
962: 'invalid_address' => 'Invalid address',
963: 'variable_set' => 'Cannot set or reset variable: '
964: );
965:
966: $l = true;
967: if ($langcode != 'en') {
968: $l = @include $lang_path.'phpmailer.lang-'.$langcode.'.php';
969: }
970: $this->language = $PHPMAILER_LANG;
971: return ($l == true);
972: }
973:
974: 975: 976: 977:
978: public function GetTranslations() {
979: return $this->language;
980: }
981:
982:
983:
984:
985:
986: 987: 988: 989: 990:
991: public function AddrAppend($type, $addr) {
992: $addr_str = $type . ': ';
993: $addresses = array();
994: foreach ($addr as $a) {
995: $addresses[] = $this->AddrFormat($a);
996: }
997: $addr_str .= implode(', ', $addresses);
998: $addr_str .= $this->LE;
999:
1000: return $addr_str;
1001: }
1002:
1003: 1004: 1005: 1006: 1007:
1008: public function AddrFormat($addr) {
1009: if (empty($addr[1])) {
1010: return $this->SecureHeader($addr[0]);
1011: } else {
1012: return $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">";
1013: }
1014: }
1015:
1016: 1017: 1018: 1019: 1020: 1021: 1022: 1023: 1024: 1025:
1026: public function WrapText($message, $length, $qp_mode = false) {
1027: $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
1028:
1029:
1030: $is_utf8 = (strtolower($this->CharSet) == "utf-8");
1031:
1032: $message = $this->FixEOL($message);
1033: if (substr($message, -1) == $this->LE) {
1034: $message = substr($message, 0, -1);
1035: }
1036:
1037: $line = explode($this->LE, $message);
1038: $message = '';
1039: for ($i = 0 ;$i < count($line); $i++) {
1040: $line_part = explode(' ', $line[$i]);
1041: $buf = '';
1042: for ($e = 0; $e<count($line_part); $e++) {
1043: $word = $line_part[$e];
1044: if ($qp_mode and (strlen($word) > $length)) {
1045: $space_left = $length - strlen($buf) - 1;
1046: if ($e != 0) {
1047: if ($space_left > 20) {
1048: $len = $space_left;
1049: if ($is_utf8) {
1050: $len = $this->UTF8CharBoundary($word, $len);
1051: } elseif (substr($word, $len - 1, 1) == "=") {
1052: $len--;
1053: } elseif (substr($word, $len - 2, 1) == "=") {
1054: $len -= 2;
1055: }
1056: $part = substr($word, 0, $len);
1057: $word = substr($word, $len);
1058: $buf .= ' ' . $part;
1059: $message .= $buf . sprintf("=%s", $this->LE);
1060: } else {
1061: $message .= $buf . $soft_break;
1062: }
1063: $buf = '';
1064: }
1065: while (strlen($word) > 0) {
1066: $len = $length;
1067: if ($is_utf8) {
1068: $len = $this->UTF8CharBoundary($word, $len);
1069: } elseif (substr($word, $len - 1, 1) == "=") {
1070: $len--;
1071: } elseif (substr($word, $len - 2, 1) == "=") {
1072: $len -= 2;
1073: }
1074: $part = substr($word, 0, $len);
1075: $word = substr($word, $len);
1076:
1077: if (strlen($word) > 0) {
1078: $message .= $part . sprintf("=%s", $this->LE);
1079: } else {
1080: $buf = $part;
1081: }
1082: }
1083: } else {
1084: $buf_o = $buf;
1085: $buf .= ($e == 0) ? $word : (' ' . $word);
1086:
1087: if (strlen($buf) > $length and $buf_o != '') {
1088: $message .= $buf_o . $soft_break;
1089: $buf = $word;
1090: }
1091: }
1092: }
1093: $message .= $buf . $this->LE;
1094: }
1095:
1096: return $message;
1097: }
1098:
1099: 1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107:
1108: public function UTF8CharBoundary($encodedText, $maxLength) {
1109: $foundSplitPos = false;
1110: $lookBack = 3;
1111: while (!$foundSplitPos) {
1112: $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1113: $encodedCharPos = strpos($lastChunk, "=");
1114: if ($encodedCharPos !== false) {
1115:
1116:
1117: $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1118: $dec = hexdec($hex);
1119: if ($dec < 128) {
1120:
1121:
1122: $maxLength = ($encodedCharPos == 0) ? $maxLength :
1123: $maxLength - ($lookBack - $encodedCharPos);
1124: $foundSplitPos = true;
1125: } elseif ($dec >= 192) {
1126:
1127: $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1128: $foundSplitPos = true;
1129: } elseif ($dec < 192) {
1130: $lookBack += 3;
1131: }
1132: } else {
1133:
1134: $foundSplitPos = true;
1135: }
1136: }
1137: return $maxLength;
1138: }
1139:
1140:
1141: 1142: 1143: 1144: 1145:
1146: public function SetWordWrap() {
1147: if($this->WordWrap < 1) {
1148: return;
1149: }
1150:
1151: switch($this->message_type) {
1152: case 'alt':
1153: case 'alt_inline':
1154: case 'alt_attach':
1155: case 'alt_inline_attach':
1156: $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
1157: break;
1158: default:
1159: $this->Body = $this->WrapText($this->Body, $this->WordWrap);
1160: break;
1161: }
1162: }
1163:
1164: 1165: 1166: 1167: 1168:
1169: public function CreateHeader() {
1170: $result = '';
1171:
1172:
1173: $uniq_id = md5(uniqid(time()));
1174: $this->boundary[1] = 'b1_' . $uniq_id;
1175: $this->boundary[2] = 'b2_' . $uniq_id;
1176: $this->boundary[3] = 'b3_' . $uniq_id;
1177:
1178: $result .= $this->HeaderLine('Date', self::RFCDate());
1179: if($this->Sender == '') {
1180: $result .= $this->HeaderLine('Return-Path', trim($this->From));
1181: } else {
1182: $result .= $this->HeaderLine('Return-Path', trim($this->Sender));
1183: }
1184:
1185:
1186: if($this->Mailer != 'mail') {
1187: if ($this->SingleTo === true) {
1188: foreach($this->to as $t) {
1189: $this->SingleToArray[] = $this->AddrFormat($t);
1190: }
1191: } else {
1192: if(count($this->to) > 0) {
1193: $result .= $this->AddrAppend('To', $this->to);
1194: } elseif (count($this->cc) == 0) {
1195: $result .= $this->HeaderLine('To', 'undisclosed-recipients:;');
1196: }
1197: }
1198: }
1199:
1200: $from = array();
1201: $from[0][0] = trim($this->From);
1202: $from[0][1] = $this->FromName;
1203: $result .= $this->AddrAppend('From', $from);
1204:
1205:
1206: if(count($this->cc) > 0) {
1207: $result .= $this->AddrAppend('Cc', $this->cc);
1208: }
1209:
1210:
1211: if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) {
1212: $result .= $this->AddrAppend('Bcc', $this->bcc);
1213: }
1214:
1215: if(count($this->ReplyTo) > 0) {
1216: $result .= $this->AddrAppend('Reply-To', $this->ReplyTo);
1217: }
1218:
1219:
1220: if($this->Mailer != 'mail') {
1221: $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject)));
1222: }
1223:
1224: if($this->MessageID != '') {
1225: $result .= $this->HeaderLine('Message-ID', $this->MessageID);
1226: } else {
1227: $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
1228: }
1229: $result .= $this->HeaderLine('X-Priority', $this->Priority);
1230: if($this->XMailer) {
1231: $result .= $this->HeaderLine('X-Mailer', $this->XMailer);
1232: } else {
1233: $result .= $this->HeaderLine('X-Mailer', 'PHPMailer '.$this->Version.' (http://code.google.com/a/apache-extras.org/p/phpmailer/)');
1234: }
1235:
1236: if($this->ConfirmReadingTo != '') {
1237: $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
1238: }
1239:
1240:
1241: for($index = 0; $index < count($this->CustomHeader); $index++) {
1242: $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
1243: }
1244: if (!$this->sign_key_file) {
1245: $result .= $this->HeaderLine('MIME-Version', '1.0');
1246: $result .= $this->GetMailMIME();
1247: }
1248:
1249: return $result;
1250: }
1251:
1252: 1253: 1254: 1255: 1256:
1257: public function GetMailMIME() {
1258: $result = '';
1259: switch($this->message_type) {
1260: case 'plain':
1261: $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding);
1262: $result .= $this->TextLine('Content-Type: '.$this->ContentType.'; charset="'.$this->CharSet.'"');
1263: break;
1264: case 'inline':
1265: $result .= $this->HeaderLine('Content-Type', 'multipart/related;');
1266: $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1267: break;
1268: case 'attach':
1269: case 'inline_attach':
1270: case 'alt_attach':
1271: case 'alt_inline_attach':
1272: $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;');
1273: $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1274: break;
1275: case 'alt':
1276: case 'alt_inline':
1277: $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1278: $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
1279: break;
1280: }
1281:
1282: if($this->Mailer != 'mail') {
1283: $result .= $this->LE.$this->LE;
1284: }
1285:
1286: return $result;
1287: }
1288:
1289: 1290: 1291: 1292: 1293:
1294: public function GetSentMIMEMessage() {
1295: return $this->SentMIMEMessage;
1296: }
1297:
1298:
1299: 1300: 1301: 1302: 1303:
1304: public function CreateBody() {
1305: $body = '';
1306:
1307: if ($this->sign_key_file) {
1308: $body .= $this->GetMailMIME();
1309: }
1310:
1311: $this->SetWordWrap();
1312:
1313: switch($this->message_type) {
1314: case 'plain':
1315: $body .= $this->EncodeString($this->Body, $this->Encoding);
1316: break;
1317: case 'inline':
1318: $body .= $this->GetBoundary($this->boundary[1], '', '', '');
1319: $body .= $this->EncodeString($this->Body, $this->Encoding);
1320: $body .= $this->LE.$this->LE;
1321: $body .= $this->AttachAll("inline", $this->boundary[1]);
1322: break;
1323: case 'attach':
1324: $body .= $this->GetBoundary($this->boundary[1], '', '', '');
1325: $body .= $this->EncodeString($this->Body, $this->Encoding);
1326: $body .= $this->LE.$this->LE;
1327: $body .= $this->AttachAll("attachment", $this->boundary[1]);
1328: break;
1329: case 'inline_attach':
1330: $body .= $this->TextLine("--" . $this->boundary[1]);
1331: $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
1332: $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
1333: $body .= $this->LE;
1334: $body .= $this->GetBoundary($this->boundary[2], '', '', '');
1335: $body .= $this->EncodeString($this->Body, $this->Encoding);
1336: $body .= $this->LE.$this->LE;
1337: $body .= $this->AttachAll("inline", $this->boundary[2]);
1338: $body .= $this->LE;
1339: $body .= $this->AttachAll("attachment", $this->boundary[1]);
1340: break;
1341: case 'alt':
1342: $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
1343: $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1344: $body .= $this->LE.$this->LE;
1345: $body .= $this->GetBoundary($this->boundary[1], '', 'text/html', '');
1346: $body .= $this->EncodeString($this->Body, $this->Encoding);
1347: $body .= $this->LE.$this->LE;
1348: $body .= $this->EndBoundary($this->boundary[1]);
1349: break;
1350: case 'alt_inline':
1351: $body .= $this->GetBoundary($this->boundary[1], '', 'text/plain', '');
1352: $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1353: $body .= $this->LE.$this->LE;
1354: $body .= $this->TextLine("--" . $this->boundary[1]);
1355: $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
1356: $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
1357: $body .= $this->LE;
1358: $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
1359: $body .= $this->EncodeString($this->Body, $this->Encoding);
1360: $body .= $this->LE.$this->LE;
1361: $body .= $this->AttachAll("inline", $this->boundary[2]);
1362: $body .= $this->LE;
1363: $body .= $this->EndBoundary($this->boundary[1]);
1364: break;
1365: case 'alt_attach':
1366: $body .= $this->TextLine("--" . $this->boundary[1]);
1367: $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1368: $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
1369: $body .= $this->LE;
1370: $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
1371: $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1372: $body .= $this->LE.$this->LE;
1373: $body .= $this->GetBoundary($this->boundary[2], '', 'text/html', '');
1374: $body .= $this->EncodeString($this->Body, $this->Encoding);
1375: $body .= $this->LE.$this->LE;
1376: $body .= $this->EndBoundary($this->boundary[2]);
1377: $body .= $this->LE;
1378: $body .= $this->AttachAll("attachment", $this->boundary[1]);
1379: break;
1380: case 'alt_inline_attach':
1381: $body .= $this->TextLine("--" . $this->boundary[1]);
1382: $body .= $this->HeaderLine('Content-Type', 'multipart/alternative;');
1383: $body .= $this->TextLine("\tboundary=\"" . $this->boundary[2] . '"');
1384: $body .= $this->LE;
1385: $body .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '');
1386: $body .= $this->EncodeString($this->AltBody, $this->Encoding);
1387: $body .= $this->LE.$this->LE;
1388: $body .= $this->TextLine("--" . $this->boundary[2]);
1389: $body .= $this->HeaderLine('Content-Type', 'multipart/related;');
1390: $body .= $this->TextLine("\tboundary=\"" . $this->boundary[3] . '"');
1391: $body .= $this->LE;
1392: $body .= $this->GetBoundary($this->boundary[3], '', 'text/html', '');
1393: $body .= $this->EncodeString($this->Body, $this->Encoding);
1394: $body .= $this->LE.$this->LE;
1395: $body .= $this->AttachAll("inline", $this->boundary[3]);
1396: $body .= $this->LE;
1397: $body .= $this->EndBoundary($this->boundary[2]);
1398: $body .= $this->LE;
1399: $body .= $this->AttachAll("attachment", $this->boundary[1]);
1400: break;
1401: }
1402:
1403: if ($this->IsError()) {
1404: $body = '';
1405: } elseif ($this->sign_key_file) {
1406: try {
1407: $file = tempnam('', 'mail');
1408: file_put_contents($file, $body);
1409: $signed = tempnam("", "signed");
1410: if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), NULL)) {
1411: @unlink($file);
1412: $body = file_get_contents($signed);
1413: @unlink($signed);
1414: } else {
1415: @unlink($file);
1416: @unlink($signed);
1417: throw new Exception($this->Lang("signing").openssl_error_string());
1418: }
1419: } catch (Exception $e) {
1420: $body = '';
1421: if ($this->exceptions) {
1422: throw $e;
1423: }
1424: }
1425: }
1426:
1427: return $body;
1428: }
1429:
1430: 1431: 1432: 1433: 1434:
1435: protected function GetBoundary($boundary, $charSet, $contentType, $encoding) {
1436: $result = '';
1437: if($charSet == '') {
1438: $charSet = $this->CharSet;
1439: }
1440: if($contentType == '') {
1441: $contentType = $this->ContentType;
1442: }
1443: if($encoding == '') {
1444: $encoding = $this->Encoding;
1445: }
1446: $result .= $this->TextLine('--' . $boundary);
1447: $result .= sprintf("Content-Type: %s; charset=\"%s\"", $contentType, $charSet);
1448: $result .= $this->LE;
1449: $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding);
1450: $result .= $this->LE;
1451:
1452: return $result;
1453: }
1454:
1455: 1456: 1457: 1458: 1459:
1460: protected function EndBoundary($boundary) {
1461: return $this->LE . '--' . $boundary . '--' . $this->LE;
1462: }
1463:
1464: 1465: 1466: 1467: 1468:
1469: protected function SetMessageType() {
1470: $this->message_type = array();
1471: if($this->AlternativeExists()) $this->message_type[] = "alt";
1472: if($this->InlineImageExists()) $this->message_type[] = "inline";
1473: if($this->AttachmentExists()) $this->message_type[] = "attach";
1474: $this->message_type = implode("_", $this->message_type);
1475: if($this->message_type == "") $this->message_type = "plain";
1476: }
1477:
1478: 1479: 1480: 1481: 1482:
1483: public function HeaderLine($name, $value) {
1484: return $name . ': ' . $value . $this->LE;
1485: }
1486:
1487: 1488: 1489: 1490: 1491:
1492: public function TextLine($value) {
1493: return $value . $this->LE;
1494: }
1495:
1496:
1497:
1498:
1499:
1500: 1501: 1502: 1503: 1504: 1505: 1506: 1507: 1508: 1509:
1510: public function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1511: try {
1512: if ( !@is_file($path) ) {
1513: throw new Exception($this->Lang('file_access') . $path, self::STOP_CONTINUE);
1514: }
1515: $filename = basename($path);
1516: if ( $name == '' ) {
1517: $name = $filename;
1518: }
1519:
1520: $this->attachment[] = array(
1521: 0 => $path,
1522: 1 => $filename,
1523: 2 => $name,
1524: 3 => $encoding,
1525: 4 => $type,
1526: 5 => false,
1527: 6 => 'attachment',
1528: 7 => 0
1529: );
1530:
1531: } catch (Exception $e) {
1532: $this->SetError($e->getMessage());
1533: if ($this->exceptions) {
1534: throw $e;
1535: }
1536: if ($this->SMTPDebug) {
1537: echo $e->getMessage()."\n";
1538: }
1539: if ( $e->getCode() == self::STOP_CRITICAL ) {
1540: return false;
1541: }
1542: }
1543: return true;
1544: }
1545:
1546: 1547: 1548: 1549:
1550: public function GetAttachments() {
1551: return $this->attachment;
1552: }
1553:
1554: 1555: 1556: 1557: 1558: 1559:
1560: protected function AttachAll($disposition_type, $boundary) {
1561:
1562: $mime = array();
1563: $cidUniq = array();
1564: $incl = array();
1565:
1566:
1567: foreach ($this->attachment as $attachment) {
1568:
1569: if($attachment[6] == $disposition_type) {
1570:
1571: $bString = $attachment[5];
1572: if ($bString) {
1573: $string = $attachment[0];
1574: } else {
1575: $path = $attachment[0];
1576: }
1577:
1578: $inclhash = md5(serialize($attachment));
1579: if (in_array($inclhash, $incl)) { continue; }
1580: $incl[] = $inclhash;
1581: $filename = $attachment[1];
1582: $name = $attachment[2];
1583: $encoding = $attachment[3];
1584: $type = $attachment[4];
1585: $disposition = $attachment[6];
1586: $cid = $attachment[7];
1587: if ( $disposition == 'inline' && isset($cidUniq[$cid]) ) { continue; }
1588: $cidUniq[$cid] = true;
1589:
1590: $mime[] = sprintf("--%s%s", $boundary, $this->LE);
1591: $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE);
1592: $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
1593:
1594: if($disposition == 'inline') {
1595: $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
1596: }
1597:
1598: $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE);
1599:
1600:
1601: if($bString) {
1602: $mime[] = $this->EncodeString($string, $encoding);
1603: if($this->IsError()) {
1604: return '';
1605: }
1606: $mime[] = $this->LE.$this->LE;
1607: } else {
1608: $mime[] = $this->EncodeFile($path, $encoding);
1609: if($this->IsError()) {
1610: return '';
1611: }
1612: $mime[] = $this->LE.$this->LE;
1613: }
1614: }
1615: }
1616:
1617: $mime[] = sprintf("--%s--%s", $boundary, $this->LE);
1618:
1619: return implode("", $mime);
1620: }
1621:
1622: 1623: 1624: 1625: 1626: 1627: 1628: 1629: 1630:
1631: protected function EncodeFile($path, $encoding = 'base64') {
1632: try {
1633: if (!is_readable($path)) {
1634: throw new Exception($this->Lang('file_open') . $path, self::STOP_CONTINUE);
1635: }
1636: if (function_exists('get_magic_quotes')) {
1637: function get_magic_quotes() {
1638: return false;
1639: }
1640: }
1641: $magic_quotes = get_magic_quotes_runtime();
1642: if ($magic_quotes) {
1643: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
1644: set_magic_quotes_runtime(0);
1645: } else {
1646: ini_set('magic_quotes_runtime', 0);
1647: }
1648: }
1649: $file_buffer = file_get_contents($path);
1650: $file_buffer = $this->EncodeString($file_buffer, $encoding);
1651: if ($magic_quotes) {
1652: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
1653: set_magic_quotes_runtime($magic_quotes);
1654: } else {
1655: ini_set('magic_quotes_runtime', $magic_quotes);
1656: }
1657: }
1658: return $file_buffer;
1659: } catch (Exception $e) {
1660: $this->SetError($e->getMessage());
1661: return '';
1662: }
1663: }
1664:
1665: 1666: 1667: 1668: 1669: 1670: 1671: 1672:
1673: public function EncodeString($str, $encoding = 'base64') {
1674: $encoded = '';
1675: switch(strtolower($encoding)) {
1676: case 'base64':
1677: $encoded = chunk_split(base64_encode($str), 76, $this->LE);
1678: break;
1679: case '7bit':
1680: case '8bit':
1681: $encoded = $this->FixEOL($str);
1682:
1683: if (substr($encoded, -(strlen($this->LE))) != $this->LE)
1684: $encoded .= $this->LE;
1685: break;
1686: case 'binary':
1687: $encoded = $str;
1688: break;
1689: case 'quoted-printable':
1690: $encoded = $this->EncodeQP($str);
1691: break;
1692: default:
1693: $this->SetError($this->Lang('encoding') . $encoding);
1694: break;
1695: }
1696: return $encoded;
1697: }
1698:
1699: 1700: 1701: 1702: 1703:
1704: public function EncodeHeader($str, $position = 'text') {
1705: $x = 0;
1706:
1707: switch (strtolower($position)) {
1708: case 'phrase':
1709: if (!preg_match('/[\200-\377]/', $str)) {
1710:
1711: $encoded = addcslashes($str, "\0..\37\177\\\"");
1712: if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
1713: return ($encoded);
1714: } else {
1715: return ("\"$encoded\"");
1716: }
1717: }
1718: $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
1719: break;
1720: case 'comment':
1721: $x = preg_match_all('/[()"]/', $str, $matches);
1722:
1723: case 'text':
1724: default:
1725: $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
1726: break;
1727: }
1728:
1729: if ($x == 0) {
1730: return ($str);
1731: }
1732:
1733: $maxlen = 75 - 7 - strlen($this->CharSet);
1734:
1735: if (strlen($str)/3 < $x) {
1736: $encoding = 'B';
1737: if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) {
1738:
1739:
1740: $encoded = $this->Base64EncodeWrapMB($str);
1741: } else {
1742: $encoded = base64_encode($str);
1743: $maxlen -= $maxlen % 4;
1744: $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
1745: }
1746: } else {
1747: $encoding = 'Q';
1748: $encoded = $this->EncodeQ($str, $position);
1749: $encoded = $this->WrapText($encoded, $maxlen, true);
1750: $encoded = str_replace('='.$this->LE, "\n", trim($encoded));
1751: }
1752:
1753: $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
1754: $encoded = trim(str_replace("\n", $this->LE, $encoded));
1755:
1756: return $encoded;
1757: }
1758:
1759: 1760: 1761: 1762: 1763: 1764:
1765: public function HasMultiBytes($str) {
1766: if (function_exists('mb_strlen')) {
1767: return (strlen($str) > mb_strlen($str, $this->CharSet));
1768: } else {
1769: return false;
1770: }
1771: }
1772:
1773: 1774: 1775: 1776: 1777: 1778: 1779: 1780:
1781: public function Base64EncodeWrapMB($str) {
1782: $start = "=?".$this->CharSet."?B?";
1783: $end = "?=";
1784: $encoded = "";
1785:
1786: $mb_length = mb_strlen($str, $this->CharSet);
1787:
1788: $length = 75 - strlen($start) - strlen($end);
1789:
1790: $ratio = $mb_length / strlen($str);
1791:
1792: $offset = $avgLength = floor($length * $ratio * .75);
1793:
1794: for ($i = 0; $i < $mb_length; $i += $offset) {
1795: $lookBack = 0;
1796:
1797: do {
1798: $offset = $avgLength - $lookBack;
1799: $chunk = mb_substr($str, $i, $offset, $this->CharSet);
1800: $chunk = base64_encode($chunk);
1801: $lookBack++;
1802: }
1803: while (strlen($chunk) > $length);
1804:
1805: $encoded .= $chunk . $this->LE;
1806: }
1807:
1808:
1809: $encoded = substr($encoded, 0, -strlen($this->LE));
1810: return $encoded;
1811: }
1812:
1813: 1814: 1815: 1816: 1817: 1818: 1819: 1820:
1821: public function EncodeQPphp( $input = '', $line_max = 76, $space_conv = false) {
1822: $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
1823: $lines = preg_split('/(?:\r\n|\r|\n)/', $input);
1824: $eol = "\r\n";
1825: $escape = '=';
1826: $output = '';
1827: while( list(, $line) = each($lines) ) {
1828: $linlen = strlen($line);
1829: $newline = '';
1830: for($i = 0; $i < $linlen; $i++) {
1831: $c = substr( $line, $i, 1 );
1832: $dec = ord( $c );
1833: if ( ( $i == 0 ) && ( $dec == 46 ) ) {
1834: $c = '=2E';
1835: }
1836: if ( $dec == 32 ) {
1837: if ( $i == ( $linlen - 1 ) ) {
1838: $c = '=20';
1839: } else if ( $space_conv ) {
1840: $c = '=20';
1841: }
1842: } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) {
1843: $h2 = floor($dec/16);
1844: $h1 = floor($dec%16);
1845: $c = $escape.$hex[$h2].$hex[$h1];
1846: }
1847: if ( (strlen($newline) + strlen($c)) >= $line_max ) {
1848: $output .= $newline.$escape.$eol;
1849: $newline = '';
1850:
1851: if ( $dec == 46 ) {
1852: $c = '=2E';
1853: }
1854: }
1855: $newline .= $c;
1856: }
1857: $output .= $newline.$eol;
1858: }
1859: return $output;
1860: }
1861:
1862: 1863: 1864: 1865: 1866: 1867: 1868: 1869: 1870: 1871: 1872: 1873:
1874: public function EncodeQP($string, $line_max = 76, $space_conv = false) {
1875: if (function_exists('quoted_printable_encode')) {
1876: return quoted_printable_encode($string);
1877: }
1878: $filters = stream_get_filters();
1879: if (!in_array('convert.*', $filters)) {
1880: return $this->EncodeQPphp($string, $line_max, $space_conv);
1881: }
1882: $fp = fopen('php://temp/', 'r+');
1883: $string = preg_replace('/\r\n?/', $this->LE, $string);
1884: $params = array('line-length' => $line_max, 'line-break-chars' => $this->LE);
1885: $s = stream_filter_append($fp, 'convert.quoted-printable-encode', STREAM_FILTER_READ, $params);
1886: fputs($fp, $string);
1887: rewind($fp);
1888: $out = stream_get_contents($fp);
1889: stream_filter_remove($s);
1890: $out = preg_replace('/^\./m', '=2E', $out);
1891: fclose($fp);
1892: return $out;
1893: }
1894:
1895: 1896: 1897: 1898: 1899: 1900: 1901: 1902:
1903: public function EncodeQ($str, $position = 'text') {
1904:
1905: $encoded = preg_replace('/[\r\n]*/', '', $str);
1906:
1907: switch (strtolower($position)) {
1908: case 'phrase':
1909: $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1910: break;
1911: case 'comment':
1912: $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
1913: case 'text':
1914: default:
1915:
1916:
1917: $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
1918: "'='.sprintf('%02X', ord(stripslashes('\\1')))", $encoded);
1919: break;
1920: }
1921:
1922:
1923: $encoded = str_replace(' ', '_', $encoded);
1924:
1925: return $encoded;
1926: }
1927:
1928: 1929: 1930: 1931: 1932: 1933: 1934: 1935: 1936: 1937:
1938: public function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') {
1939:
1940: $this->attachment[] = array(
1941: 0 => $string,
1942: 1 => $filename,
1943: 2 => basename($filename),
1944: 3 => $encoding,
1945: 4 => $type,
1946: 5 => true,
1947: 6 => 'attachment',
1948: 7 => 0
1949: );
1950: }
1951:
1952: 1953: 1954: 1955: 1956: 1957: 1958: 1959: 1960: 1961: 1962: 1963: 1964:
1965: public function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') {
1966:
1967: if ( !@is_file($path) ) {
1968: $this->SetError($this->Lang('file_access') . $path);
1969: return false;
1970: }
1971:
1972: $filename = basename($path);
1973: if ( $name == '' ) {
1974: $name = $filename;
1975: }
1976:
1977:
1978: $this->attachment[] = array(
1979: 0 => $path,
1980: 1 => $filename,
1981: 2 => $name,
1982: 3 => $encoding,
1983: 4 => $type,
1984: 5 => false,
1985: 6 => 'inline',
1986: 7 => $cid
1987: );
1988:
1989: return true;
1990: }
1991:
1992: public function AddStringEmbeddedImage($string, $cid, $filename = '', $encoding = 'base64', $type = 'application/octet-stream') {
1993:
1994: $this->attachment[] = array(
1995: 0 => $string,
1996: 1 => $filename,
1997: 2 => basename($filename),
1998: 3 => $encoding,
1999: 4 => $type,
2000: 5 => true,
2001: 6 => 'inline',
2002: 7 => $cid
2003: );
2004: }
2005:
2006: 2007: 2008: 2009: 2010:
2011: public function InlineImageExists() {
2012: foreach($this->attachment as $attachment) {
2013: if ($attachment[6] == 'inline') {
2014: return true;
2015: }
2016: }
2017: return false;
2018: }
2019:
2020: public function AttachmentExists() {
2021: foreach($this->attachment as $attachment) {
2022: if ($attachment[6] == 'attachment') {
2023: return true;
2024: }
2025: }
2026: return false;
2027: }
2028:
2029: public function AlternativeExists() {
2030: return strlen($this->AltBody)>0;
2031: }
2032:
2033:
2034:
2035:
2036:
2037: 2038: 2039: 2040:
2041: public function ClearAddresses() {
2042: foreach($this->to as $to) {
2043: unset($this->all_recipients[strtolower($to[0])]);
2044: }
2045: $this->to = array();
2046: }
2047:
2048: 2049: 2050: 2051:
2052: public function ClearCCs() {
2053: foreach($this->cc as $cc) {
2054: unset($this->all_recipients[strtolower($cc[0])]);
2055: }
2056: $this->cc = array();
2057: }
2058:
2059: 2060: 2061: 2062:
2063: public function ClearBCCs() {
2064: foreach($this->bcc as $bcc) {
2065: unset($this->all_recipients[strtolower($bcc[0])]);
2066: }
2067: $this->bcc = array();
2068: }
2069:
2070: 2071: 2072: 2073:
2074: public function ClearReplyTos() {
2075: $this->ReplyTo = array();
2076: }
2077:
2078: 2079: 2080: 2081: 2082:
2083: public function ClearAllRecipients() {
2084: $this->to = array();
2085: $this->cc = array();
2086: $this->bcc = array();
2087: $this->all_recipients = array();
2088: }
2089:
2090: 2091: 2092: 2093: 2094:
2095: public function ClearAttachments() {
2096: $this->attachment = array();
2097: }
2098:
2099: 2100: 2101: 2102:
2103: public function ClearCustomHeaders() {
2104: $this->CustomHeader = array();
2105: }
2106:
2107:
2108:
2109:
2110:
2111: 2112: 2113: 2114: 2115:
2116: protected function SetError($msg) {
2117: $this->error_count++;
2118: if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
2119: $lasterror = $this->smtp->getError();
2120: if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
2121: $msg .= '<p>' . $this->Lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
2122: }
2123: }
2124: $this->ErrorInfo = $msg;
2125: }
2126:
2127: 2128: 2129: 2130: 2131: 2132:
2133: public static function RFCDate() {
2134: $tz = date('Z');
2135: $tzs = ($tz < 0) ? '-' : '+';
2136: $tz = abs($tz);
2137: $tz = (int)($tz/3600)*100 + ($tz%3600)/60;
2138: $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz);
2139:
2140: return $result;
2141: }
2142:
2143: 2144: 2145: 2146: 2147:
2148: protected function ServerHostname() {
2149: if (!empty($this->Hostname)) {
2150: $result = $this->Hostname;
2151: } elseif (isset($_SERVER['SERVER_NAME'])) {
2152: $result = $_SERVER['SERVER_NAME'];
2153: } else {
2154: $result = 'localhost.localdomain';
2155: }
2156:
2157: return $result;
2158: }
2159:
2160: 2161: 2162: 2163: 2164:
2165: protected function Lang($key) {
2166: if(count($this->language) < 1) {
2167: $this->SetLanguage('en');
2168: }
2169:
2170: if(isset($this->language[$key])) {
2171: return $this->language[$key];
2172: } else {
2173: return 'Language string failed to load: ' . $key;
2174: }
2175: }
2176:
2177: 2178: 2179: 2180: 2181:
2182: public function IsError() {
2183: return ($this->error_count > 0);
2184: }
2185:
2186: 2187: 2188: 2189: 2190:
2191: public function FixEOL($str) {
2192: $str = str_replace("\r\n", "\n", $str);
2193: $str = str_replace("\r", "\n", $str);
2194: $str = str_replace("\n", $this->LE, $str);
2195: return $str;
2196: }
2197:
2198: 2199: 2200: 2201: 2202:
2203: public function AddCustomHeader($custom_header) {
2204: $this->CustomHeader[] = explode(':', $custom_header, 2);
2205: }
2206:
2207: 2208: 2209: 2210: 2211:
2212: public function MsgHTML($message, $basedir = '') {
2213: preg_match_all("/(src|background)=[\"'](.*)[\"']/Ui", $message, $images);
2214: if(isset($images[2])) {
2215: foreach($images[2] as $i => $url) {
2216:
2217: if (!preg_match('#^[A-z]+://#', $url)) {
2218: $filename = basename($url);
2219: $directory = dirname($url);
2220: ($directory == '.') ? $directory='': '';
2221: $cid = 'cid:' . md5($filename);
2222: $ext = pathinfo($filename, PATHINFO_EXTENSION);
2223: $mimeType = self::_mime_types($ext);
2224: if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; }
2225: if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; }
2226: if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType) ) {
2227: $message = preg_replace("/".$images[1][$i]."=[\"']".preg_quote($url, '/')."[\"']/Ui", $images[1][$i]."=\"".$cid."\"", $message);
2228: }
2229: }
2230: }
2231: }
2232: $this->IsHTML(true);
2233: $this->Body = $message;
2234: if (empty($this->AltBody)) {
2235: $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message)));
2236: if (!empty($textMsg)) {
2237: $this->AltBody = html_entity_decode($textMsg, ENT_QUOTES, $this->CharSet);
2238: }
2239: }
2240: if (empty($this->AltBody)) {
2241: $this->AltBody = 'To view this email message, open it in a program that understands HTML!' . "\n\n";
2242: }
2243: return $message;
2244: }
2245:
2246: 2247: 2248: 2249: 2250: 2251: 2252:
2253: public static function _mime_types($ext = '') {
2254: $mimes = array(
2255: 'hqx' => 'application/mac-binhex40',
2256: 'cpt' => 'application/mac-compactpro',
2257: 'doc' => 'application/msword',
2258: 'bin' => 'application/macbinary',
2259: 'dms' => 'application/octet-stream',
2260: 'lha' => 'application/octet-stream',
2261: 'lzh' => 'application/octet-stream',
2262: 'exe' => 'application/octet-stream',
2263: 'class' => 'application/octet-stream',
2264: 'psd' => 'application/octet-stream',
2265: 'so' => 'application/octet-stream',
2266: 'sea' => 'application/octet-stream',
2267: 'dll' => 'application/octet-stream',
2268: 'oda' => 'application/oda',
2269: 'pdf' => 'application/pdf',
2270: 'ai' => 'application/postscript',
2271: 'eps' => 'application/postscript',
2272: 'ps' => 'application/postscript',
2273: 'smi' => 'application/smil',
2274: 'smil' => 'application/smil',
2275: 'mif' => 'application/vnd.mif',
2276: 'xls' => 'application/vnd.ms-excel',
2277: 'ppt' => 'application/vnd.ms-powerpoint',
2278: 'wbxml' => 'application/vnd.wap.wbxml',
2279: 'wmlc' => 'application/vnd.wap.wmlc',
2280: 'dcr' => 'application/x-director',
2281: 'dir' => 'application/x-director',
2282: 'dxr' => 'application/x-director',
2283: 'dvi' => 'application/x-dvi',
2284: 'gtar' => 'application/x-gtar',
2285: 'php' => 'application/x-httpd-php',
2286: 'php4' => 'application/x-httpd-php',
2287: 'php3' => 'application/x-httpd-php',
2288: 'phtml' => 'application/x-httpd-php',
2289: 'phps' => 'application/x-httpd-php-source',
2290: 'js' => 'application/x-javascript',
2291: 'swf' => 'application/x-shockwave-flash',
2292: 'sit' => 'application/x-stuffit',
2293: 'tar' => 'application/x-tar',
2294: 'tgz' => 'application/x-tar',
2295: 'xhtml' => 'application/xhtml+xml',
2296: 'xht' => 'application/xhtml+xml',
2297: 'zip' => 'application/zip',
2298: 'mid' => 'audio/midi',
2299: 'midi' => 'audio/midi',
2300: 'mpga' => 'audio/mpeg',
2301: 'mp2' => 'audio/mpeg',
2302: 'mp3' => 'audio/mpeg',
2303: 'aif' => 'audio/x-aiff',
2304: 'aiff' => 'audio/x-aiff',
2305: 'aifc' => 'audio/x-aiff',
2306: 'ram' => 'audio/x-pn-realaudio',
2307: 'rm' => 'audio/x-pn-realaudio',
2308: 'rpm' => 'audio/x-pn-realaudio-plugin',
2309: 'ra' => 'audio/x-realaudio',
2310: 'rv' => 'video/vnd.rn-realvideo',
2311: 'wav' => 'audio/x-wav',
2312: 'bmp' => 'image/bmp',
2313: 'gif' => 'image/gif',
2314: 'jpeg' => 'image/jpeg',
2315: 'jpg' => 'image/jpeg',
2316: 'jpe' => 'image/jpeg',
2317: 'png' => 'image/png',
2318: 'tiff' => 'image/tiff',
2319: 'tif' => 'image/tiff',
2320: 'css' => 'text/css',
2321: 'html' => 'text/html',
2322: 'htm' => 'text/html',
2323: 'shtml' => 'text/html',
2324: 'txt' => 'text/plain',
2325: 'text' => 'text/plain',
2326: 'log' => 'text/plain',
2327: 'rtx' => 'text/richtext',
2328: 'rtf' => 'text/rtf',
2329: 'xml' => 'text/xml',
2330: 'xsl' => 'text/xml',
2331: 'mpeg' => 'video/mpeg',
2332: 'mpg' => 'video/mpeg',
2333: 'mpe' => 'video/mpeg',
2334: 'qt' => 'video/quicktime',
2335: 'mov' => 'video/quicktime',
2336: 'avi' => 'video/x-msvideo',
2337: 'movie' => 'video/x-sgi-movie',
2338: 'doc' => 'application/msword',
2339: 'word' => 'application/msword',
2340: 'xl' => 'application/excel',
2341: 'eml' => 'message/rfc822'
2342: );
2343: return (!isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)];
2344: }
2345:
2346: 2347: 2348: 2349: 2350: 2351: 2352: 2353: 2354: 2355: 2356: 2357:
2358: public function set($name, $value = '') {
2359: try {
2360: if (isset($this->$name) ) {
2361: $this->$name = $value;
2362: } else {
2363: throw new Exception($this->Lang('variable_set') . $name, self::STOP_CRITICAL);
2364: }
2365: } catch (Exception $e) {
2366: $this->SetError($e->getMessage());
2367: if ($e->getCode() == self::STOP_CRITICAL) {
2368: return false;
2369: }
2370: }
2371: return true;
2372: }
2373:
2374: 2375: 2376: 2377: 2378: 2379:
2380: public function SecureHeader($str) {
2381: $str = str_replace("\r", '', $str);
2382: $str = str_replace("\n", '', $str);
2383: return trim($str);
2384: }
2385:
2386: 2387: 2388: 2389: 2390: 2391: 2392:
2393: public function Sign($cert_filename, $key_filename, $key_pass) {
2394: $this->sign_cert_file = $cert_filename;
2395: $this->sign_key_file = $key_filename;
2396: $this->sign_key_pass = $key_pass;
2397: }
2398:
2399: 2400: 2401: 2402: 2403: 2404: 2405:
2406: public function DKIM_QP($txt) {
2407: $tmp = '';
2408: $line = '';
2409: for ($i = 0; $i < strlen($txt); $i++) {
2410: $ord = ord($txt[$i]);
2411: if ( ((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E)) ) {
2412: $line .= $txt[$i];
2413: } else {
2414: $line .= "=".sprintf("%02X", $ord);
2415: }
2416: }
2417: return $line;
2418: }
2419:
2420: 2421: 2422: 2423: 2424: 2425:
2426: public function DKIM_Sign($s) {
2427: $privKeyStr = file_get_contents($this->DKIM_private);
2428: if ($this->DKIM_passphrase != '') {
2429: $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
2430: } else {
2431: $privKey = $privKeyStr;
2432: }
2433: if (openssl_sign($s, $signature, $privKey)) {
2434: return base64_encode($signature);
2435: }
2436: }
2437:
2438: 2439: 2440: 2441: 2442: 2443:
2444: public function DKIM_HeaderC($s) {
2445: $s = preg_replace("/\r\n\s+/", " ", $s);
2446: $lines = explode("\r\n", $s);
2447: foreach ($lines as $key => $line) {
2448: list($heading, $value) = explode(":", $line, 2);
2449: $heading = strtolower($heading);
2450: $value = preg_replace("/\s+/", " ", $value) ;
2451: $lines[$key] = $heading.":".trim($value) ;
2452: }
2453: $s = implode("\r\n", $lines);
2454: return $s;
2455: }
2456:
2457: 2458: 2459: 2460: 2461: 2462:
2463: public function DKIM_BodyC($body) {
2464: if ($body == '') return "\r\n";
2465:
2466: $body = str_replace("\r\n", "\n", $body);
2467: $body = str_replace("\n", "\r\n", $body);
2468:
2469: while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
2470: $body = substr($body, 0, strlen($body) - 2);
2471: }
2472: return $body;
2473: }
2474:
2475: 2476: 2477: 2478: 2479: 2480: 2481: 2482:
2483: public function DKIM_Add($headers_line, $subject, $body) {
2484: $DKIMsignatureType = 'rsa-sha1';
2485: $DKIMcanonicalization = 'relaxed/simple';
2486: $DKIMquery = 'dns/txt';
2487: $DKIMtime = time() ;
2488: $subject_header = "Subject: $subject";
2489: $headers = explode($this->LE, $headers_line);
2490: foreach($headers as $header) {
2491: if (strpos($header, 'From:') === 0) {
2492: $from_header = $header;
2493: } elseif (strpos($header, 'To:') === 0) {
2494: $to_header = $header;
2495: }
2496: }
2497: $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
2498: $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
2499: $subject = str_replace('|', '=7C', $this->DKIM_QP($subject_header)) ;
2500: $body = $this->DKIM_BodyC($body);
2501: $DKIMlen = strlen($body) ;
2502: $DKIMb64 = base64_encode(pack("H*", sha1($body))) ;
2503: $ident = ($this->DKIM_identity == '')? '' : " i=" . $this->DKIM_identity . ";";
2504: $dkimhdrs = "DKIM-Signature: v=1; a=" . $DKIMsignatureType . "; q=" . $DKIMquery . "; l=" . $DKIMlen . "; s=" . $this->DKIM_selector . ";\r\n".
2505: "\tt=" . $DKIMtime . "; c=" . $DKIMcanonicalization . ";\r\n".
2506: "\th=From:To:Subject;\r\n".
2507: "\td=" . $this->DKIM_domain . ";" . $ident . "\r\n".
2508: "\tz=$from\r\n".
2509: "\t|$to\r\n".
2510: "\t|$subject;\r\n".
2511: "\tbh=" . $DKIMb64 . ";\r\n".
2512: "\tb=";
2513: $toSign = $this->DKIM_HeaderC($from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs);
2514: $signed = $this->DKIM_Sign($toSign);
2515: return "X-PHPMAILER-DKIM: phpmailer.worxware.com\r\n".$dkimhdrs.$signed."\r\n";
2516: }
2517:
2518: protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body) {
2519: if (!empty($this->action_function) && function_exists($this->action_function)) {
2520: $params = array($isSent, $to, $cc, $bcc, $subject, $body);
2521: call_user_func_array($this->action_function, $params);
2522: }
2523: }
2524: }
2525: ?>
2526: