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: class PHPMailer
29: {
30: 31: 32: 33:
34: public $Version = '5.2.23';
35:
36: 37: 38: 39: 40: 41:
42: public $Priority = null;
43:
44: 45: 46: 47:
48: public $CharSet = 'iso-8859-1';
49:
50: 51: 52: 53:
54: public $ContentType = 'text/plain';
55:
56: 57: 58: 59: 60:
61: public $Encoding = '8bit';
62:
63: 64: 65: 66:
67: public $ErrorInfo = '';
68:
69: 70: 71: 72:
73: public $From = 'root@localhost';
74:
75: 76: 77: 78:
79: public $FromName = 'Root User';
80:
81: 82: 83: 84: 85:
86: public $Sender = '';
87:
88: 89: 90: 91: 92: 93: 94: 95:
96: public $ReturnPath = '';
97:
98: 99: 100: 101:
102: public $Subject = '';
103:
104: 105: 106: 107: 108:
109: public $Body = '';
110:
111: 112: 113: 114: 115: 116: 117:
118: public $AltBody = '';
119:
120: 121: 122: 123: 124: 125: 126: 127:
128: public $Ical = '';
129:
130: 131: 132: 133: 134:
135: protected $MIMEBody = '';
136:
137: 138: 139: 140: 141:
142: protected $MIMEHeader = '';
143:
144: 145: 146: 147: 148:
149: protected $mailHeader = '';
150:
151: 152: 153: 154: 155:
156: public $WordWrap = 0;
157:
158: 159: 160: 161: 162:
163: public $Mailer = 'mail';
164:
165: 166: 167: 168:
169: public $Sendmail = '/usr/sbin/sendmail';
170:
171: 172: 173: 174: 175:
176: public $UseSendmailOptions = true;
177:
178: 179: 180: 181: 182: 183:
184: public $PluginDir = '';
185:
186: 187: 188: 189:
190: public $ConfirmReadingTo = '';
191:
192: 193: 194: 195: 196: 197: 198:
199: public $Hostname = '';
200:
201: 202: 203: 204: 205: 206: 207: 208:
209: public $MessageID = '';
210:
211: 212: 213: 214: 215:
216: public $MessageDate = '';
217:
218: 219: 220: 221: 222: 223: 224: 225: 226: 227: 228:
229: public $Host = 'localhost';
230:
231: 232: 233: 234: 235:
236: public $Port = 25;
237:
238: 239: 240: 241: 242: 243: 244:
245: public $Helo = '';
246:
247: 248: 249: 250: 251:
252: public $SMTPSecure = '';
253:
254: 255: 256: 257: 258: 259:
260: public $SMTPAutoTLS = true;
261:
262: 263: 264: 265: 266: 267: 268:
269: public $SMTPAuth = false;
270:
271: 272: 273: 274:
275: public $SMTPOptions = array();
276:
277: 278: 279: 280:
281: public $Username = '';
282:
283: 284: 285: 286:
287: public $Password = '';
288:
289: 290: 291: 292: 293:
294: public $AuthType = '';
295:
296: 297: 298: 299: 300:
301: public $Realm = '';
302:
303: 304: 305: 306: 307:
308: public $Workstation = '';
309:
310: 311: 312: 313: 314:
315: public $Timeout = 300;
316:
317: 318: 319: 320: 321: 322: 323: 324: 325: 326: 327: 328:
329: public $SMTPDebug = 0;
330:
331: 332: 333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344:
345: public $Debugoutput = 'echo';
346:
347: 348: 349: 350: 351: 352:
353: public $SMTPKeepAlive = false;
354:
355: 356: 357: 358: 359: 360:
361: public $SingleTo = false;
362:
363: 364: 365: 366: 367:
368: public $SingleToArray = array();
369:
370: 371: 372: 373: 374: 375: 376:
377: public $do_verp = false;
378:
379: 380: 381: 382:
383: public $AllowEmpty = false;
384:
385: 386: 387: 388: 389: 390:
391: public $LE = "\n";
392:
393: 394: 395: 396:
397: public $DKIM_selector = '';
398:
399: 400: 401: 402: 403:
404: public $DKIM_identity = '';
405:
406: 407: 408: 409: 410:
411: public $DKIM_passphrase = '';
412:
413: 414: 415: 416: 417:
418: public $DKIM_domain = '';
419:
420: 421: 422: 423:
424: public $DKIM_private = '';
425:
426: 427: 428: 429: 430:
431: public $DKIM_private_string = '';
432:
433: 434: 435: 436: 437: 438: 439: 440: 441: 442: 443: 444: 445: 446: 447: 448: 449: 450:
451: public $action_function = '';
452:
453: 454: 455: 456: 457:
458: public $XMailer = '';
459:
460: 461: 462: 463: 464: 465: 466:
467: public static $validator = 'auto';
468:
469: 470: 471: 472: 473:
474: protected $smtp = null;
475:
476: 477: 478: 479: 480:
481: protected $to = array();
482:
483: 484: 485: 486: 487:
488: protected $cc = array();
489:
490: 491: 492: 493: 494:
495: protected $bcc = array();
496:
497: 498: 499: 500: 501:
502: protected $ReplyTo = array();
503:
504: 505: 506: 507: 508: 509: 510:
511: protected $all_recipients = array();
512:
513: 514: 515: 516: 517: 518: 519: 520: 521: 522:
523: protected $RecipientsQueue = array();
524:
525: 526: 527: 528: 529: 530: 531: 532:
533: protected $ReplyToQueue = array();
534:
535: 536: 537: 538: 539:
540: protected $attachment = array();
541:
542: 543: 544: 545: 546:
547: protected $CustomHeader = array();
548:
549: 550: 551: 552: 553:
554: protected $lastMessageID = '';
555:
556: 557: 558: 559: 560:
561: protected $message_type = '';
562:
563: 564: 565: 566: 567:
568: protected $boundary = array();
569:
570: 571: 572: 573: 574:
575: protected $language = array();
576:
577: 578: 579: 580: 581:
582: protected $error_count = 0;
583:
584: 585: 586: 587: 588:
589: protected $sign_cert_file = '';
590:
591: 592: 593: 594: 595:
596: protected $sign_key_file = '';
597:
598: 599: 600: 601: 602:
603: protected $sign_extracerts_file = '';
604:
605: 606: 607: 608: 609: 610:
611: protected $sign_key_pass = '';
612:
613: 614: 615: 616: 617:
618: protected $exceptions = false;
619:
620: 621: 622: 623: 624:
625: protected $uniqueid = '';
626:
627: 628: 629:
630: const STOP_MESSAGE = 0;
631:
632: 633: 634:
635: const STOP_CONTINUE = 1;
636:
637: 638: 639:
640: const STOP_CRITICAL = 2;
641:
642: 643: 644:
645: const CRLF = "\r\n";
646:
647: 648: 649: 650:
651: const MAX_LINE_LENGTH = 998;
652:
653: 654: 655: 656:
657: public function __construct($exceptions = null)
658: {
659: if ($exceptions !== null) {
660: $this->exceptions = (boolean)$exceptions;
661: }
662: }
663:
664: 665: 666:
667: public function __destruct()
668: {
669:
670: $this->smtpClose();
671: }
672:
673: 674: 675: 676: 677: 678: 679: 680: 681: 682: 683: 684: 685:
686: private function mailPassthru($to, $subject, $body, $header, $params)
687: {
688:
689: if (ini_get('mbstring.func_overload') & 1) {
690: $subject = $this->secureHeader($subject);
691: } else {
692: $subject = $this->encodeHeader($this->secureHeader($subject));
693: }
694:
695:
696:
697: if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
698: $result = @mail($to, $subject, $body, $header);
699: } else {
700: $result = @mail($to, $subject, $body, $header, $params);
701: }
702: return $result;
703: }
704: 705: 706: 707: 708: 709: 710:
711: protected function edebug($str)
712: {
713: if ($this->SMTPDebug <= 0) {
714: return;
715: }
716:
717: if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
718: call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
719: return;
720: }
721: switch ($this->Debugoutput) {
722: case 'error_log':
723:
724: error_log($str);
725: break;
726: case 'html':
727:
728: echo htmlentities(
729: preg_replace('/[\r\n]+/', '', $str),
730: ENT_QUOTES,
731: 'UTF-8'
732: )
733: . "<br>\n";
734: break;
735: case 'echo':
736: default:
737:
738: $str = preg_replace('/\r\n?/ms', "\n", $str);
739: echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
740: "\n",
741: "\n \t ",
742: trim($str)
743: ) . "\n";
744: }
745: }
746:
747: 748: 749: 750: 751:
752: public function isHTML($isHtml = true)
753: {
754: if ($isHtml) {
755: $this->ContentType = 'text/html';
756: } else {
757: $this->ContentType = 'text/plain';
758: }
759: }
760:
761: 762: 763: 764:
765: public function isSMTP()
766: {
767: $this->Mailer = 'smtp';
768: }
769:
770: 771: 772: 773:
774: public function isMail()
775: {
776: $this->Mailer = 'mail';
777: }
778:
779: 780: 781: 782:
783: public function isSendmail()
784: {
785: $ini_sendmail_path = ini_get('sendmail_path');
786:
787: if (!stristr($ini_sendmail_path, 'sendmail')) {
788: $this->Sendmail = '/usr/sbin/sendmail';
789: } else {
790: $this->Sendmail = $ini_sendmail_path;
791: }
792: $this->Mailer = 'sendmail';
793: }
794:
795: 796: 797: 798:
799: public function isQmail()
800: {
801: $ini_sendmail_path = ini_get('sendmail_path');
802:
803: if (!stristr($ini_sendmail_path, 'qmail')) {
804: $this->Sendmail = '/var/qmail/bin/qmail-inject';
805: } else {
806: $this->Sendmail = $ini_sendmail_path;
807: }
808: $this->Mailer = 'qmail';
809: }
810:
811: 812: 813: 814: 815: 816:
817: public function addAddress($address, $name = '')
818: {
819: return $this->addOrEnqueueAnAddress('to', $address, $name);
820: }
821:
822: 823: 824: 825: 826: 827: 828:
829: public function addCC($address, $name = '')
830: {
831: return $this->addOrEnqueueAnAddress('cc', $address, $name);
832: }
833:
834: 835: 836: 837: 838: 839: 840:
841: public function addBCC($address, $name = '')
842: {
843: return $this->addOrEnqueueAnAddress('bcc', $address, $name);
844: }
845:
846: 847: 848: 849: 850: 851:
852: public function addReplyTo($address, $name = '')
853: {
854: return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
855: }
856:
857: 858: 859: 860: 861: 862: 863: 864: 865: 866: 867: 868:
869: protected function addOrEnqueueAnAddress($kind, $address, $name)
870: {
871: $address = trim($address);
872: $name = trim(preg_replace('/[\r\n]+/', '', $name));
873: if (($pos = strrpos($address, '@')) === false) {
874:
875: $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
876: $this->setError($error_message);
877: $this->edebug($error_message);
878: if ($this->exceptions) {
879: throw new phpmailerException($error_message);
880: }
881: return false;
882: }
883: $params = array($kind, $address, $name);
884:
885: if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
886: if ($kind != 'Reply-To') {
887: if (!array_key_exists($address, $this->RecipientsQueue)) {
888: $this->RecipientsQueue[$address] = $params;
889: return true;
890: }
891: } else {
892: if (!array_key_exists($address, $this->ReplyToQueue)) {
893: $this->ReplyToQueue[$address] = $params;
894: return true;
895: }
896: }
897: return false;
898: }
899:
900: return call_user_func_array(array($this, 'addAnAddress'), $params);
901: }
902:
903: 904: 905: 906: 907: 908: 909: 910: 911: 912:
913: protected function addAnAddress($kind, $address, $name = '')
914: {
915: if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
916: $error_message = $this->lang('Invalid recipient kind: ') . $kind;
917: $this->setError($error_message);
918: $this->edebug($error_message);
919: if ($this->exceptions) {
920: throw new phpmailerException($error_message);
921: }
922: return false;
923: }
924: if (!$this->validateAddress($address)) {
925: $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
926: $this->setError($error_message);
927: $this->edebug($error_message);
928: if ($this->exceptions) {
929: throw new phpmailerException($error_message);
930: }
931: return false;
932: }
933: if ($kind != 'Reply-To') {
934: if (!array_key_exists(strtolower($address), $this->all_recipients)) {
935: array_push($this->$kind, array($address, $name));
936: $this->all_recipients[strtolower($address)] = true;
937: return true;
938: }
939: } else {
940: if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
941: $this->ReplyTo[strtolower($address)] = array($address, $name);
942: return true;
943: }
944: }
945: return false;
946: }
947:
948: 949: 950: 951: 952: 953: 954: 955: 956: 957:
958: public function parseAddresses($addrstr, $useimap = true)
959: {
960: $addresses = array();
961: if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
962:
963: $list = imap_rfc822_parse_adrlist($addrstr, '');
964: foreach ($list as $address) {
965: if ($address->host != '.SYNTAX-ERROR.') {
966: if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
967: $addresses[] = array(
968: 'name' => (property_exists($address, 'personal') ? $address->personal : ''),
969: 'address' => $address->mailbox . '@' . $address->host
970: );
971: }
972: }
973: }
974: } else {
975:
976: $list = explode(',', $addrstr);
977: foreach ($list as $address) {
978: $address = trim($address);
979:
980: if (strpos($address, '<') === false) {
981:
982: if ($this->validateAddress($address)) {
983: $addresses[] = array(
984: 'name' => '',
985: 'address' => $address
986: );
987: }
988: } else {
989: list($name, $email) = explode('<', $address);
990: $email = trim(str_replace('>', '', $email));
991: if ($this->validateAddress($email)) {
992: $addresses[] = array(
993: 'name' => trim(str_replace(array('"', "'"), '', $name)),
994: 'address' => $email
995: );
996: }
997: }
998: }
999: }
1000: return $addresses;
1001: }
1002:
1003: 1004: 1005: 1006: 1007: 1008: 1009: 1010:
1011: public function setFrom($address, $name = '', $auto = true)
1012: {
1013: $address = trim($address);
1014: $name = trim(preg_replace('/[\r\n]+/', '', $name));
1015:
1016: if (($pos = strrpos($address, '@')) === false or
1017: (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
1018: !$this->validateAddress($address)) {
1019: $error_message = $this->lang('invalid_address') . " (setFrom) $address";
1020: $this->setError($error_message);
1021: $this->edebug($error_message);
1022: if ($this->exceptions) {
1023: throw new phpmailerException($error_message);
1024: }
1025: return false;
1026: }
1027: $this->From = $address;
1028: $this->FromName = $name;
1029: if ($auto) {
1030: if (empty($this->Sender)) {
1031: $this->Sender = $address;
1032: }
1033: }
1034: return true;
1035: }
1036:
1037: 1038: 1039: 1040: 1041: 1042: 1043:
1044: public function getLastMessageID()
1045: {
1046: return $this->lastMessageID;
1047: }
1048:
1049: 1050: 1051: 1052: 1053: 1054: 1055: 1056: 1057: 1058: 1059: 1060: 1061: 1062: 1063: 1064: 1065: 1066: 1067:
1068: public static function validateAddress($address, $patternselect = null)
1069: {
1070: if (is_null($patternselect)) {
1071: $patternselect = self::$validator;
1072: }
1073: if (is_callable($patternselect)) {
1074: return call_user_func($patternselect, $address);
1075: }
1076:
1077: if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
1078: return false;
1079: }
1080: if (!$patternselect or $patternselect == 'auto') {
1081:
1082:
1083: if (defined('PCRE_VERSION')) {
1084:
1085: if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
1086: $patternselect = 'pcre8';
1087: } else {
1088: $patternselect = 'pcre';
1089: }
1090: } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
1091:
1092: $patternselect = 'pcre';
1093: } else {
1094:
1095: if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
1096: $patternselect = 'php';
1097: } else {
1098: $patternselect = 'noregex';
1099: }
1100: }
1101: }
1102: switch ($patternselect) {
1103: case 'pcre8':
1104: 1105: 1106: 1107: 1108: 1109:
1110: return (boolean)preg_match(
1111: '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
1112: '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
1113: '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
1114: '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
1115: '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
1116: '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
1117: '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
1118: '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1119: '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
1120: $address
1121: );
1122: case 'pcre':
1123:
1124: return (boolean)preg_match(
1125: '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
1126: '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
1127: '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
1128: '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
1129: '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
1130: '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
1131: '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
1132: '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
1133: '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
1134: '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
1135: $address
1136: );
1137: case 'html5':
1138: 1139: 1140: 1141:
1142: return (boolean)preg_match(
1143: '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
1144: '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
1145: $address
1146: );
1147: case 'noregex':
1148:
1149:
1150: return (strlen($address) >= 3
1151: and strpos($address, '@') >= 1
1152: and strpos($address, '@') != strlen($address) - 1);
1153: case 'php':
1154: default:
1155: return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
1156: }
1157: }
1158:
1159: 1160: 1161: 1162: 1163:
1164: public function idnSupported()
1165: {
1166:
1167: return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
1168: }
1169:
1170: 1171: 1172: 1173: 1174: 1175: 1176: 1177: 1178: 1179: 1180:
1181: public function punyencodeAddress($address)
1182: {
1183:
1184: if ($this->idnSupported() and
1185: !empty($this->CharSet) and
1186: ($pos = strrpos($address, '@')) !== false) {
1187: $domain = substr($address, ++$pos);
1188:
1189: if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
1190: $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
1191: if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
1192: idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
1193: idn_to_ascii($domain)) !== false) {
1194: return substr($address, 0, $pos) . $punycode;
1195: }
1196: }
1197: }
1198: return $address;
1199: }
1200:
1201: 1202: 1203: 1204: 1205: 1206:
1207: public function send()
1208: {
1209: try {
1210: if (!$this->preSend()) {
1211: return false;
1212: }
1213: return $this->postSend();
1214: } catch (phpmailerException $exc) {
1215: $this->mailHeader = '';
1216: $this->setError($exc->getMessage());
1217: if ($this->exceptions) {
1218: throw $exc;
1219: }
1220: return false;
1221: }
1222: }
1223:
1224: 1225: 1226: 1227: 1228:
1229: public function preSend()
1230: {
1231: try {
1232: $this->error_count = 0;
1233: $this->mailHeader = '';
1234:
1235:
1236: foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
1237: $params[1] = $this->punyencodeAddress($params[1]);
1238: call_user_func_array(array($this, 'addAnAddress'), $params);
1239: }
1240: if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
1241: throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
1242: }
1243:
1244:
1245: foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
1246: $this->$address_kind = trim($this->$address_kind);
1247: if (empty($this->$address_kind)) {
1248: continue;
1249: }
1250: $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
1251: if (!$this->validateAddress($this->$address_kind)) {
1252: $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
1253: $this->setError($error_message);
1254: $this->edebug($error_message);
1255: if ($this->exceptions) {
1256: throw new phpmailerException($error_message);
1257: }
1258: return false;
1259: }
1260: }
1261:
1262:
1263: if ($this->alternativeExists()) {
1264: $this->ContentType = 'multipart/alternative';
1265: }
1266:
1267: $this->setMessageType();
1268:
1269: if (!$this->AllowEmpty and empty($this->Body)) {
1270: throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
1271: }
1272:
1273:
1274: $this->MIMEHeader = '';
1275: $this->MIMEBody = $this->createBody();
1276:
1277: $tempheaders = $this->MIMEHeader;
1278: $this->MIMEHeader = $this->createHeader();
1279: $this->MIMEHeader .= $tempheaders;
1280:
1281:
1282:
1283: if ($this->Mailer == 'mail') {
1284: if (count($this->to) > 0) {
1285: $this->mailHeader .= $this->addrAppend('To', $this->to);
1286: } else {
1287: $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
1288: }
1289: $this->mailHeader .= $this->headerLine(
1290: 'Subject',
1291: $this->encodeHeader($this->secureHeader(trim($this->Subject)))
1292: );
1293: }
1294:
1295:
1296: if (!empty($this->DKIM_domain)
1297: && !empty($this->DKIM_selector)
1298: && (!empty($this->DKIM_private_string)
1299: || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
1300: )
1301: ) {
1302: $header_dkim = $this->DKIM_Add(
1303: $this->MIMEHeader . $this->mailHeader,
1304: $this->encodeHeader($this->secureHeader($this->Subject)),
1305: $this->MIMEBody
1306: );
1307: $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
1308: str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
1309: }
1310: return true;
1311: } catch (phpmailerException $exc) {
1312: $this->setError($exc->getMessage());
1313: if ($this->exceptions) {
1314: throw $exc;
1315: }
1316: return false;
1317: }
1318: }
1319:
1320: 1321: 1322: 1323: 1324: 1325:
1326: public function postSend()
1327: {
1328: try {
1329:
1330: switch ($this->Mailer) {
1331: case 'sendmail':
1332: case 'qmail':
1333: return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
1334: case 'smtp':
1335: return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
1336: case 'mail':
1337: return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1338: default:
1339: $sendMethod = $this->Mailer.'Send';
1340: if (method_exists($this, $sendMethod)) {
1341: return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
1342: }
1343:
1344: return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
1345: }
1346: } catch (phpmailerException $exc) {
1347: $this->setError($exc->getMessage());
1348: $this->edebug($exc->getMessage());
1349: if ($this->exceptions) {
1350: throw $exc;
1351: }
1352: }
1353: return false;
1354: }
1355:
1356: 1357: 1358: 1359: 1360: 1361: 1362: 1363: 1364:
1365: protected function sendmailSend($header, $body)
1366: {
1367:
1368: if (!empty($this->Sender) and self::isShellSafe($this->Sender)) {
1369: if ($this->Mailer == 'qmail') {
1370: $sendmailFmt = '%s -f%s';
1371: } else {
1372: $sendmailFmt = '%s -oi -f%s -t';
1373: }
1374: } else {
1375: if ($this->Mailer == 'qmail') {
1376: $sendmailFmt = '%s';
1377: } else {
1378: $sendmailFmt = '%s -oi -t';
1379: }
1380: }
1381:
1382:
1383: $sendmail = sprintf($sendmailFmt, escapeshellcmd($this->Sendmail), $this->Sender);
1384:
1385: if ($this->SingleTo) {
1386: foreach ($this->SingleToArray as $toAddr) {
1387: if (!@$mail = popen($sendmail, 'w')) {
1388: throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1389: }
1390: fputs($mail, 'To: ' . $toAddr . "\n");
1391: fputs($mail, $header);
1392: fputs($mail, $body);
1393: $result = pclose($mail);
1394: $this->doCallback(
1395: ($result == 0),
1396: array($toAddr),
1397: $this->cc,
1398: $this->bcc,
1399: $this->Subject,
1400: $body,
1401: $this->From
1402: );
1403: if ($result != 0) {
1404: throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1405: }
1406: }
1407: } else {
1408: if (!@$mail = popen($sendmail, 'w')) {
1409: throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1410: }
1411: fputs($mail, $header);
1412: fputs($mail, $body);
1413: $result = pclose($mail);
1414: $this->doCallback(
1415: ($result == 0),
1416: $this->to,
1417: $this->cc,
1418: $this->bcc,
1419: $this->Subject,
1420: $body,
1421: $this->From
1422: );
1423: if ($result != 0) {
1424: throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
1425: }
1426: }
1427: return true;
1428: }
1429:
1430: 1431: 1432: 1433: 1434: 1435: 1436: 1437: 1438:
1439: protected static function isShellSafe($string)
1440: {
1441:
1442: if (escapeshellcmd($string) !== $string
1443: or !in_array(escapeshellarg($string), array("'$string'", "\"$string\""))
1444: ) {
1445: return false;
1446: }
1447:
1448: $length = strlen($string);
1449:
1450: for ($i = 0; $i < $length; $i++) {
1451: $c = $string[$i];
1452:
1453:
1454:
1455:
1456: if (!ctype_alnum($c) && strpos('@_-.', $c) === false) {
1457: return false;
1458: }
1459: }
1460:
1461: return true;
1462: }
1463:
1464: 1465: 1466: 1467: 1468: 1469: 1470: 1471: 1472:
1473: protected function mailSend($header, $body)
1474: {
1475: $toArr = array();
1476: foreach ($this->to as $toaddr) {
1477: $toArr[] = $this->addrFormat($toaddr);
1478: }
1479: $to = implode(', ', $toArr);
1480:
1481: $params = null;
1482:
1483: if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1484:
1485: if (self::isShellSafe($this->Sender)) {
1486: $params = sprintf('-f%s', $this->Sender);
1487: }
1488: }
1489: if (!empty($this->Sender) and !ini_get('safe_mode') and $this->validateAddress($this->Sender)) {
1490: $old_from = ini_get('sendmail_from');
1491: ini_set('sendmail_from', $this->Sender);
1492: }
1493: $result = false;
1494: if ($this->SingleTo and count($toArr) > 1) {
1495: foreach ($toArr as $toAddr) {
1496: $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
1497: $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1498: }
1499: } else {
1500: $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
1501: $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
1502: }
1503: if (isset($old_from)) {
1504: ini_set('sendmail_from', $old_from);
1505: }
1506: if (!$result) {
1507: throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
1508: }
1509: return true;
1510: }
1511:
1512: 1513: 1514: 1515: 1516:
1517: public function getSMTPInstance()
1518: {
1519: if (!is_object($this->smtp)) {
1520: $this->smtp = new SMTP;
1521: }
1522: return $this->smtp;
1523: }
1524:
1525: 1526: 1527: 1528: 1529: 1530: 1531: 1532: 1533: 1534: 1535: 1536:
1537: protected function smtpSend($header, $body)
1538: {
1539: $bad_rcpt = array();
1540: if (!$this->smtpConnect($this->SMTPOptions)) {
1541: throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
1542: }
1543: if (!empty($this->Sender) and $this->validateAddress($this->Sender)) {
1544: $smtp_from = $this->Sender;
1545: } else {
1546: $smtp_from = $this->From;
1547: }
1548: if (!$this->smtp->mail($smtp_from)) {
1549: $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
1550: throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
1551: }
1552:
1553:
1554: foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
1555: foreach ($togroup as $to) {
1556: if (!$this->smtp->recipient($to[0])) {
1557: $error = $this->smtp->getError();
1558: $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
1559: $isSent = false;
1560: } else {
1561: $isSent = true;
1562: }
1563: $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
1564: }
1565: }
1566:
1567:
1568: if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
1569: throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
1570: }
1571: if ($this->SMTPKeepAlive) {
1572: $this->smtp->reset();
1573: } else {
1574: $this->smtp->quit();
1575: $this->smtp->close();
1576: }
1577:
1578: if (count($bad_rcpt) > 0) {
1579: $errstr = '';
1580: foreach ($bad_rcpt as $bad) {
1581: $errstr .= $bad['to'] . ': ' . $bad['error'];
1582: }
1583: throw new phpmailerException(
1584: $this->lang('recipients_failed') . $errstr,
1585: self::STOP_CONTINUE
1586: );
1587: }
1588: return true;
1589: }
1590:
1591: 1592: 1593: 1594: 1595: 1596: 1597: 1598: 1599:
1600: public function smtpConnect($options = null)
1601: {
1602: if (is_null($this->smtp)) {
1603: $this->smtp = $this->getSMTPInstance();
1604: }
1605:
1606:
1607: if (is_null($options)) {
1608: $options = $this->SMTPOptions;
1609: }
1610:
1611:
1612: if ($this->smtp->connected()) {
1613: return true;
1614: }
1615:
1616: $this->smtp->setTimeout($this->Timeout);
1617: $this->smtp->setDebugLevel($this->SMTPDebug);
1618: $this->smtp->setDebugOutput($this->Debugoutput);
1619: $this->smtp->setVerp($this->do_verp);
1620: $hosts = explode(';', $this->Host);
1621: $lastexception = null;
1622:
1623: foreach ($hosts as $hostentry) {
1624: $hostinfo = array();
1625: if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
1626:
1627: continue;
1628: }
1629:
1630:
1631:
1632:
1633:
1634: $prefix = '';
1635: $secure = $this->SMTPSecure;
1636: $tls = ($this->SMTPSecure == 'tls');
1637: if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
1638: $prefix = 'ssl://';
1639: $tls = false;
1640: $secure = 'ssl';
1641: } elseif ($hostinfo[2] == 'tls') {
1642: $tls = true;
1643:
1644: $secure = 'tls';
1645: }
1646:
1647: $sslext = defined('OPENSSL_ALGO_SHA1');
1648: if ('tls' === $secure or 'ssl' === $secure) {
1649:
1650: if (!$sslext) {
1651: throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
1652: }
1653: }
1654: $host = $hostinfo[3];
1655: $port = $this->Port;
1656: $tport = (integer)$hostinfo[4];
1657: if ($tport > 0 and $tport < 65536) {
1658: $port = $tport;
1659: }
1660: if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
1661: try {
1662: if ($this->Helo) {
1663: $hello = $this->Helo;
1664: } else {
1665: $hello = $this->serverHostname();
1666: }
1667: $this->smtp->hello($hello);
1668:
1669:
1670:
1671:
1672:
1673: if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
1674: $tls = true;
1675: }
1676: if ($tls) {
1677: if (!$this->smtp->startTLS()) {
1678: throw new phpmailerException($this->lang('connect_host'));
1679: }
1680:
1681: $this->smtp->hello($hello);
1682: }
1683: if ($this->SMTPAuth) {
1684: if (!$this->smtp->authenticate(
1685: $this->Username,
1686: $this->Password,
1687: $this->AuthType,
1688: $this->Realm,
1689: $this->Workstation
1690: )
1691: ) {
1692: throw new phpmailerException($this->lang('authenticate'));
1693: }
1694: }
1695: return true;
1696: } catch (phpmailerException $exc) {
1697: $lastexception = $exc;
1698: $this->edebug($exc->getMessage());
1699:
1700: $this->smtp->quit();
1701: }
1702: }
1703: }
1704:
1705: $this->smtp->close();
1706:
1707: if ($this->exceptions and !is_null($lastexception)) {
1708: throw $lastexception;
1709: }
1710: return false;
1711: }
1712:
1713: 1714: 1715: 1716:
1717: public function smtpClose()
1718: {
1719: if (is_a($this->smtp, 'SMTP')) {
1720: if ($this->smtp->connected()) {
1721: $this->smtp->quit();
1722: $this->smtp->close();
1723: }
1724: }
1725: }
1726:
1727: 1728: 1729: 1730: 1731: 1732: 1733: 1734: 1735:
1736: public function setLanguage($langcode = 'en', $lang_path = '')
1737: {
1738:
1739: $renamed_langcodes = array(
1740: 'br' => 'pt_br',
1741: 'cz' => 'cs',
1742: 'dk' => 'da',
1743: 'no' => 'nb',
1744: 'se' => 'sv',
1745: );
1746:
1747: if (isset($renamed_langcodes[$langcode])) {
1748: $langcode = $renamed_langcodes[$langcode];
1749: }
1750:
1751:
1752: $PHPMAILER_LANG = array(
1753: 'authenticate' => 'SMTP Error: Could not authenticate.',
1754: 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
1755: 'data_not_accepted' => 'SMTP Error: data not accepted.',
1756: 'empty_message' => 'Message body empty',
1757: 'encoding' => 'Unknown encoding: ',
1758: 'execute' => 'Could not execute: ',
1759: 'file_access' => 'Could not access file: ',
1760: 'file_open' => 'File Error: Could not open file: ',
1761: 'from_failed' => 'The following From address failed: ',
1762: 'instantiate' => 'Could not instantiate mail function.',
1763: 'invalid_address' => 'Invalid address: ',
1764: 'mailer_not_supported' => ' mailer is not supported.',
1765: 'provide_address' => 'You must provide at least one recipient email address.',
1766: 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
1767: 'signing' => 'Signing Error: ',
1768: 'smtp_connect_failed' => 'SMTP connect() failed.',
1769: 'smtp_error' => 'SMTP server error: ',
1770: 'variable_set' => 'Cannot set or reset variable: ',
1771: 'extension_missing' => 'Extension missing: '
1772: );
1773: if (empty($lang_path)) {
1774:
1775: $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
1776: }
1777:
1778: if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
1779: $langcode = 'en';
1780: }
1781: $foundlang = true;
1782: $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
1783:
1784: if ($langcode != 'en') {
1785:
1786: if (!is_readable($lang_file)) {
1787: $foundlang = false;
1788: } else {
1789:
1790:
1791: $foundlang = include $lang_file;
1792: }
1793: }
1794: $this->language = $PHPMAILER_LANG;
1795: return (boolean)$foundlang;
1796: }
1797:
1798: 1799: 1800: 1801:
1802: public function getTranslations()
1803: {
1804: return $this->language;
1805: }
1806:
1807: 1808: 1809: 1810: 1811: 1812: 1813: 1814: 1815: 1816:
1817: public function addrAppend($type, $addr)
1818: {
1819: $addresses = array();
1820: foreach ($addr as $address) {
1821: $addresses[] = $this->addrFormat($address);
1822: }
1823: return $type . ': ' . implode(', ', $addresses) . $this->LE;
1824: }
1825:
1826: 1827: 1828: 1829: 1830: 1831: 1832:
1833: public function addrFormat($addr)
1834: {
1835: if (empty($addr[1])) {
1836: return $this->secureHeader($addr[0]);
1837: } else {
1838: return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
1839: $addr[0]
1840: ) . '>';
1841: }
1842: }
1843:
1844: 1845: 1846: 1847: 1848: 1849: 1850: 1851: 1852: 1853: 1854:
1855: public function wrapText($message, $length, $qp_mode = false)
1856: {
1857: if ($qp_mode) {
1858: $soft_break = sprintf(' =%s', $this->LE);
1859: } else {
1860: $soft_break = $this->LE;
1861: }
1862:
1863:
1864: $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
1865: $lelen = strlen($this->LE);
1866: $crlflen = strlen(self::CRLF);
1867:
1868: $message = $this->fixEOL($message);
1869:
1870: if (substr($message, -$lelen) == $this->LE) {
1871: $message = substr($message, 0, -$lelen);
1872: }
1873:
1874:
1875: $lines = explode($this->LE, $message);
1876:
1877: $message = '';
1878: foreach ($lines as $line) {
1879: $words = explode(' ', $line);
1880: $buf = '';
1881: $firstword = true;
1882: foreach ($words as $word) {
1883: if ($qp_mode and (strlen($word) > $length)) {
1884: $space_left = $length - strlen($buf) - $crlflen;
1885: if (!$firstword) {
1886: if ($space_left > 20) {
1887: $len = $space_left;
1888: if ($is_utf8) {
1889: $len = $this->utf8CharBoundary($word, $len);
1890: } elseif (substr($word, $len - 1, 1) == '=') {
1891: $len--;
1892: } elseif (substr($word, $len - 2, 1) == '=') {
1893: $len -= 2;
1894: }
1895: $part = substr($word, 0, $len);
1896: $word = substr($word, $len);
1897: $buf .= ' ' . $part;
1898: $message .= $buf . sprintf('=%s', self::CRLF);
1899: } else {
1900: $message .= $buf . $soft_break;
1901: }
1902: $buf = '';
1903: }
1904: while (strlen($word) > 0) {
1905: if ($length <= 0) {
1906: break;
1907: }
1908: $len = $length;
1909: if ($is_utf8) {
1910: $len = $this->utf8CharBoundary($word, $len);
1911: } elseif (substr($word, $len - 1, 1) == '=') {
1912: $len--;
1913: } elseif (substr($word, $len - 2, 1) == '=') {
1914: $len -= 2;
1915: }
1916: $part = substr($word, 0, $len);
1917: $word = substr($word, $len);
1918:
1919: if (strlen($word) > 0) {
1920: $message .= $part . sprintf('=%s', self::CRLF);
1921: } else {
1922: $buf = $part;
1923: }
1924: }
1925: } else {
1926: $buf_o = $buf;
1927: if (!$firstword) {
1928: $buf .= ' ';
1929: }
1930: $buf .= $word;
1931:
1932: if (strlen($buf) > $length and $buf_o != '') {
1933: $message .= $buf_o . $soft_break;
1934: $buf = $word;
1935: }
1936: }
1937: $firstword = false;
1938: }
1939: $message .= $buf . self::CRLF;
1940: }
1941:
1942: return $message;
1943: }
1944:
1945: 1946: 1947: 1948: 1949: 1950: 1951: 1952: 1953:
1954: public function utf8CharBoundary($encodedText, $maxLength)
1955: {
1956: $foundSplitPos = false;
1957: $lookBack = 3;
1958: while (!$foundSplitPos) {
1959: $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
1960: $encodedCharPos = strpos($lastChunk, '=');
1961: if (false !== $encodedCharPos) {
1962:
1963:
1964: $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
1965: $dec = hexdec($hex);
1966: if ($dec < 128) {
1967:
1968:
1969:
1970: if ($encodedCharPos > 0) {
1971: $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1972: }
1973: $foundSplitPos = true;
1974: } elseif ($dec >= 192) {
1975:
1976:
1977: $maxLength = $maxLength - ($lookBack - $encodedCharPos);
1978: $foundSplitPos = true;
1979: } elseif ($dec < 192) {
1980:
1981: $lookBack += 3;
1982: }
1983: } else {
1984:
1985: $foundSplitPos = true;
1986: }
1987: }
1988: return $maxLength;
1989: }
1990:
1991: 1992: 1993: 1994: 1995: 1996: 1997: 1998:
1999: public function setWordWrap()
2000: {
2001: if ($this->WordWrap < 1) {
2002: return;
2003: }
2004:
2005: switch ($this->message_type) {
2006: case 'alt':
2007: case 'alt_inline':
2008: case 'alt_attach':
2009: case 'alt_inline_attach':
2010: $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
2011: break;
2012: default:
2013: $this->Body = $this->wrapText($this->Body, $this->WordWrap);
2014: break;
2015: }
2016: }
2017:
2018: 2019: 2020: 2021: 2022:
2023: public function createHeader()
2024: {
2025: $result = '';
2026:
2027: $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
2028:
2029:
2030: if ($this->SingleTo) {
2031: if ($this->Mailer != 'mail') {
2032: foreach ($this->to as $toaddr) {
2033: $this->SingleToArray[] = $this->addrFormat($toaddr);
2034: }
2035: }
2036: } else {
2037: if (count($this->to) > 0) {
2038: if ($this->Mailer != 'mail') {
2039: $result .= $this->addrAppend('To', $this->to);
2040: }
2041: } elseif (count($this->cc) == 0) {
2042: $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2043: }
2044: }
2045:
2046: $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2047:
2048:
2049: if (count($this->cc) > 0) {
2050: $result .= $this->addrAppend('Cc', $this->cc);
2051: }
2052:
2053:
2054: if ((
2055: $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2056: )
2057: and count($this->bcc) > 0
2058: ) {
2059: $result .= $this->addrAppend('Bcc', $this->bcc);
2060: }
2061:
2062: if (count($this->ReplyTo) > 0) {
2063: $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2064: }
2065:
2066:
2067: if ($this->Mailer != 'mail') {
2068: $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2069: }
2070:
2071:
2072:
2073: if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2074: $this->lastMessageID = $this->MessageID;
2075: } else {
2076: $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2077: }
2078: $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2079: if (!is_null($this->Priority)) {
2080: $result .= $this->headerLine('X-Priority', $this->Priority);
2081: }
2082: if ($this->XMailer == '') {
2083: $result .= $this->headerLine(
2084: 'X-Mailer',
2085: 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2086: );
2087: } else {
2088: $myXmailer = trim($this->XMailer);
2089: if ($myXmailer) {
2090: $result .= $this->headerLine('X-Mailer', $myXmailer);
2091: }
2092: }
2093:
2094: if ($this->ConfirmReadingTo != '') {
2095: $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2096: }
2097:
2098:
2099: foreach ($this->CustomHeader as $header) {
2100: $result .= $this->headerLine(
2101: trim($header[0]),
2102: $this->encodeHeader(trim($header[1]))
2103: );
2104: }
2105: if (!$this->sign_key_file) {
2106: $result .= $this->headerLine('MIME-Version', '1.0');
2107: $result .= $this->getMailMIME();
2108: }
2109:
2110: return $result;
2111: }
2112:
2113: 2114: 2115: 2116: 2117:
2118: public function getMailMIME()
2119: {
2120: $result = '';
2121: $ismultipart = true;
2122: switch ($this->message_type) {
2123: case 'inline':
2124: $result .= $this->headerLine('Content-Type', 'multipart/related;');
2125: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2126: break;
2127: case 'attach':
2128: case 'inline_attach':
2129: case 'alt_attach':
2130: case 'alt_inline_attach':
2131: $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2132: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2133: break;
2134: case 'alt':
2135: case 'alt_inline':
2136: $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2137: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2138: break;
2139: default:
2140:
2141: $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2142: $ismultipart = false;
2143: break;
2144: }
2145:
2146: if ($this->Encoding != '7bit') {
2147:
2148: if ($ismultipart) {
2149: if ($this->Encoding == '8bit') {
2150: $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2151: }
2152:
2153: } else {
2154: $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2155: }
2156: }
2157:
2158: if ($this->Mailer != 'mail') {
2159: $result .= $this->LE;
2160: }
2161:
2162: return $result;
2163: }
2164:
2165: 2166: 2167: 2168: 2169: 2170: 2171: 2172:
2173: public function getSentMIMEMessage()
2174: {
2175: return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2176: }
2177:
2178: 2179: 2180: 2181:
2182: protected function generateId() {
2183: return md5(uniqid(time()));
2184: }
2185:
2186: 2187: 2188: 2189: 2190: 2191: 2192:
2193: public function createBody()
2194: {
2195: $body = '';
2196:
2197: $this->uniqueid = $this->generateId();
2198: $this->boundary[1] = 'b1_' . $this->uniqueid;
2199: $this->boundary[2] = 'b2_' . $this->uniqueid;
2200: $this->boundary[3] = 'b3_' . $this->uniqueid;
2201:
2202: if ($this->sign_key_file) {
2203: $body .= $this->getMailMIME() . $this->LE;
2204: }
2205:
2206: $this->setWordWrap();
2207:
2208: $bodyEncoding = $this->Encoding;
2209: $bodyCharSet = $this->CharSet;
2210:
2211: if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2212: $bodyEncoding = '7bit';
2213:
2214: $bodyCharSet = 'us-ascii';
2215: }
2216:
2217:
2218: if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2219: $bodyEncoding = 'quoted-printable';
2220: }
2221:
2222: $altBodyEncoding = $this->Encoding;
2223: $altBodyCharSet = $this->CharSet;
2224:
2225: if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2226: $altBodyEncoding = '7bit';
2227:
2228: $altBodyCharSet = 'us-ascii';
2229: }
2230:
2231:
2232: if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2233: $altBodyEncoding = 'quoted-printable';
2234: }
2235:
2236: $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2237: switch ($this->message_type) {
2238: case 'inline':
2239: $body .= $mimepre;
2240: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2241: $body .= $this->encodeString($this->Body, $bodyEncoding);
2242: $body .= $this->LE . $this->LE;
2243: $body .= $this->attachAll('inline', $this->boundary[1]);
2244: break;
2245: case 'attach':
2246: $body .= $mimepre;
2247: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2248: $body .= $this->encodeString($this->Body, $bodyEncoding);
2249: $body .= $this->LE . $this->LE;
2250: $body .= $this->attachAll('attachment', $this->boundary[1]);
2251: break;
2252: case 'inline_attach':
2253: $body .= $mimepre;
2254: $body .= $this->textLine('--' . $this->boundary[1]);
2255: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2256: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2257: $body .= $this->LE;
2258: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2259: $body .= $this->encodeString($this->Body, $bodyEncoding);
2260: $body .= $this->LE . $this->LE;
2261: $body .= $this->attachAll('inline', $this->boundary[2]);
2262: $body .= $this->LE;
2263: $body .= $this->attachAll('attachment', $this->boundary[1]);
2264: break;
2265: case 'alt':
2266: $body .= $mimepre;
2267: $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2268: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2269: $body .= $this->LE . $this->LE;
2270: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2271: $body .= $this->encodeString($this->Body, $bodyEncoding);
2272: $body .= $this->LE . $this->LE;
2273: if (!empty($this->Ical)) {
2274: $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2275: $body .= $this->encodeString($this->Ical, $this->Encoding);
2276: $body .= $this->LE . $this->LE;
2277: }
2278: $body .= $this->endBoundary($this->boundary[1]);
2279: break;
2280: case 'alt_inline':
2281: $body .= $mimepre;
2282: $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2283: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2284: $body .= $this->LE . $this->LE;
2285: $body .= $this->textLine('--' . $this->boundary[1]);
2286: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2287: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2288: $body .= $this->LE;
2289: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2290: $body .= $this->encodeString($this->Body, $bodyEncoding);
2291: $body .= $this->LE . $this->LE;
2292: $body .= $this->attachAll('inline', $this->boundary[2]);
2293: $body .= $this->LE;
2294: $body .= $this->endBoundary($this->boundary[1]);
2295: break;
2296: case 'alt_attach':
2297: $body .= $mimepre;
2298: $body .= $this->textLine('--' . $this->boundary[1]);
2299: $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2300: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2301: $body .= $this->LE;
2302: $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2303: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2304: $body .= $this->LE . $this->LE;
2305: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2306: $body .= $this->encodeString($this->Body, $bodyEncoding);
2307: $body .= $this->LE . $this->LE;
2308: $body .= $this->endBoundary($this->boundary[2]);
2309: $body .= $this->LE;
2310: $body .= $this->attachAll('attachment', $this->boundary[1]);
2311: break;
2312: case 'alt_inline_attach':
2313: $body .= $mimepre;
2314: $body .= $this->textLine('--' . $this->boundary[1]);
2315: $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2316: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2317: $body .= $this->LE;
2318: $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2319: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2320: $body .= $this->LE . $this->LE;
2321: $body .= $this->textLine('--' . $this->boundary[2]);
2322: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2323: $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2324: $body .= $this->LE;
2325: $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2326: $body .= $this->encodeString($this->Body, $bodyEncoding);
2327: $body .= $this->LE . $this->LE;
2328: $body .= $this->attachAll('inline', $this->boundary[3]);
2329: $body .= $this->LE;
2330: $body .= $this->endBoundary($this->boundary[2]);
2331: $body .= $this->LE;
2332: $body .= $this->attachAll('attachment', $this->boundary[1]);
2333: break;
2334: default:
2335:
2336:
2337: $this->Encoding = $bodyEncoding;
2338: $body .= $this->encodeString($this->Body, $this->Encoding);
2339: break;
2340: }
2341:
2342: if ($this->isError()) {
2343: $body = '';
2344: } elseif ($this->sign_key_file) {
2345: try {
2346: if (!defined('PKCS7_TEXT')) {
2347: throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2348: }
2349:
2350: $file = tempnam(sys_get_temp_dir(), 'mail');
2351: if (false === file_put_contents($file, $body)) {
2352: throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2353: }
2354: $signed = tempnam(sys_get_temp_dir(), 'signed');
2355:
2356: if (empty($this->sign_extracerts_file)) {
2357: $sign = @openssl_pkcs7_sign(
2358: $file,
2359: $signed,
2360: 'file://' . realpath($this->sign_cert_file),
2361: array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2362: null
2363: );
2364: } else {
2365: $sign = @openssl_pkcs7_sign(
2366: $file,
2367: $signed,
2368: 'file://' . realpath($this->sign_cert_file),
2369: array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2370: null,
2371: PKCS7_DETACHED,
2372: $this->sign_extracerts_file
2373: );
2374: }
2375: if ($sign) {
2376: @unlink($file);
2377: $body = file_get_contents($signed);
2378: @unlink($signed);
2379:
2380: $parts = explode("\n\n", $body, 2);
2381: $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2382: $body = $parts[1];
2383: } else {
2384: @unlink($file);
2385: @unlink($signed);
2386: throw new phpmailerException($this->lang('signing') . openssl_error_string());
2387: }
2388: } catch (phpmailerException $exc) {
2389: $body = '';
2390: if ($this->exceptions) {
2391: throw $exc;
2392: }
2393: }
2394: }
2395: return $body;
2396: }
2397:
2398: 2399: 2400: 2401: 2402: 2403: 2404: 2405: 2406:
2407: protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2408: {
2409: $result = '';
2410: if ($charSet == '') {
2411: $charSet = $this->CharSet;
2412: }
2413: if ($contentType == '') {
2414: $contentType = $this->ContentType;
2415: }
2416: if ($encoding == '') {
2417: $encoding = $this->Encoding;
2418: }
2419: $result .= $this->textLine('--' . $boundary);
2420: $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2421: $result .= $this->LE;
2422:
2423: if ($encoding != '7bit') {
2424: $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2425: }
2426: $result .= $this->LE;
2427:
2428: return $result;
2429: }
2430:
2431: 2432: 2433: 2434: 2435: 2436:
2437: protected function endBoundary($boundary)
2438: {
2439: return $this->LE . '--' . $boundary . '--' . $this->LE;
2440: }
2441:
2442: 2443: 2444: 2445: 2446: 2447:
2448: protected function setMessageType()
2449: {
2450: $type = array();
2451: if ($this->alternativeExists()) {
2452: $type[] = 'alt';
2453: }
2454: if ($this->inlineImageExists()) {
2455: $type[] = 'inline';
2456: }
2457: if ($this->attachmentExists()) {
2458: $type[] = 'attach';
2459: }
2460: $this->message_type = implode('_', $type);
2461: if ($this->message_type == '') {
2462:
2463: $this->message_type = 'plain';
2464: }
2465: }
2466:
2467: 2468: 2469: 2470: 2471: 2472: 2473:
2474: public function headerLine($name, $value)
2475: {
2476: return $name . ': ' . $value . $this->LE;
2477: }
2478:
2479: 2480: 2481: 2482: 2483: 2484:
2485: public function textLine($value)
2486: {
2487: return $value . $this->LE;
2488: }
2489:
2490: 2491: 2492: 2493: 2494: 2495: 2496: 2497: 2498: 2499: 2500: 2501:
2502: public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2503: {
2504: try {
2505: if (!@is_file($path)) {
2506: throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2507: }
2508:
2509:
2510: if ($type == '') {
2511: $type = self::filenameToType($path);
2512: }
2513:
2514: $filename = basename($path);
2515: if ($name == '') {
2516: $name = $filename;
2517: }
2518:
2519: $this->attachment[] = array(
2520: 0 => $path,
2521: 1 => $filename,
2522: 2 => $name,
2523: 3 => $encoding,
2524: 4 => $type,
2525: 5 => false,
2526: 6 => $disposition,
2527: 7 => 0
2528: );
2529:
2530: } catch (phpmailerException $exc) {
2531: $this->setError($exc->getMessage());
2532: $this->edebug($exc->getMessage());
2533: if ($this->exceptions) {
2534: throw $exc;
2535: }
2536: return false;
2537: }
2538: return true;
2539: }
2540:
2541: 2542: 2543: 2544:
2545: public function getAttachments()
2546: {
2547: return $this->attachment;
2548: }
2549:
2550: 2551: 2552: 2553: 2554: 2555: 2556: 2557:
2558: protected function attachAll($disposition_type, $boundary)
2559: {
2560:
2561: $mime = array();
2562: $cidUniq = array();
2563: $incl = array();
2564:
2565:
2566: foreach ($this->attachment as $attachment) {
2567:
2568: if ($attachment[6] == $disposition_type) {
2569:
2570: $string = '';
2571: $path = '';
2572: $bString = $attachment[5];
2573: if ($bString) {
2574: $string = $attachment[0];
2575: } else {
2576: $path = $attachment[0];
2577: }
2578:
2579: $inclhash = md5(serialize($attachment));
2580: if (in_array($inclhash, $incl)) {
2581: continue;
2582: }
2583: $incl[] = $inclhash;
2584: $name = $attachment[2];
2585: $encoding = $attachment[3];
2586: $type = $attachment[4];
2587: $disposition = $attachment[6];
2588: $cid = $attachment[7];
2589: if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2590: continue;
2591: }
2592: $cidUniq[$cid] = true;
2593:
2594: $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2595:
2596: if (!empty($name)) {
2597: $mime[] = sprintf(
2598: 'Content-Type: %s; name="%s"%s',
2599: $type,
2600: $this->encodeHeader($this->secureHeader($name)),
2601: $this->LE
2602: );
2603: } else {
2604: $mime[] = sprintf(
2605: 'Content-Type: %s%s',
2606: $type,
2607: $this->LE
2608: );
2609: }
2610:
2611: if ($encoding != '7bit') {
2612: $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2613: }
2614:
2615: if ($disposition == 'inline') {
2616: $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2617: }
2618:
2619:
2620:
2621:
2622:
2623: if (!(empty($disposition))) {
2624: $encoded_name = $this->encodeHeader($this->secureHeader($name));
2625: if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2626: $mime[] = sprintf(
2627: 'Content-Disposition: %s; filename="%s"%s',
2628: $disposition,
2629: $encoded_name,
2630: $this->LE . $this->LE
2631: );
2632: } else {
2633: if (!empty($encoded_name)) {
2634: $mime[] = sprintf(
2635: 'Content-Disposition: %s; filename=%s%s',
2636: $disposition,
2637: $encoded_name,
2638: $this->LE . $this->LE
2639: );
2640: } else {
2641: $mime[] = sprintf(
2642: 'Content-Disposition: %s%s',
2643: $disposition,
2644: $this->LE . $this->LE
2645: );
2646: }
2647: }
2648: } else {
2649: $mime[] = $this->LE;
2650: }
2651:
2652:
2653: if ($bString) {
2654: $mime[] = $this->encodeString($string, $encoding);
2655: if ($this->isError()) {
2656: return '';
2657: }
2658: $mime[] = $this->LE . $this->LE;
2659: } else {
2660: $mime[] = $this->encodeFile($path, $encoding);
2661: if ($this->isError()) {
2662: return '';
2663: }
2664: $mime[] = $this->LE . $this->LE;
2665: }
2666: }
2667: }
2668:
2669: $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2670:
2671: return implode('', $mime);
2672: }
2673:
2674: 2675: 2676: 2677: 2678: 2679: 2680: 2681: 2682:
2683: protected function encodeFile($path, $encoding = 'base64')
2684: {
2685: try {
2686: if (!is_readable($path)) {
2687: throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2688: }
2689: $magic_quotes = get_magic_quotes_runtime();
2690: if ($magic_quotes) {
2691: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2692: set_magic_quotes_runtime(false);
2693: } else {
2694:
2695:
2696:
2697: ini_set('magic_quotes_runtime', false);
2698: }
2699: }
2700: $file_buffer = file_get_contents($path);
2701: $file_buffer = $this->encodeString($file_buffer, $encoding);
2702: if ($magic_quotes) {
2703: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2704: set_magic_quotes_runtime($magic_quotes);
2705: } else {
2706: ini_set('magic_quotes_runtime', $magic_quotes);
2707: }
2708: }
2709: return $file_buffer;
2710: } catch (Exception $exc) {
2711: $this->setError($exc->getMessage());
2712: return '';
2713: }
2714: }
2715:
2716: 2717: 2718: 2719: 2720: 2721: 2722: 2723:
2724: public function encodeString($str, $encoding = 'base64')
2725: {
2726: $encoded = '';
2727: switch (strtolower($encoding)) {
2728: case 'base64':
2729: $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2730: break;
2731: case '7bit':
2732: case '8bit':
2733: $encoded = $this->fixEOL($str);
2734:
2735: if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2736: $encoded .= $this->LE;
2737: }
2738: break;
2739: case 'binary':
2740: $encoded = $str;
2741: break;
2742: case 'quoted-printable':
2743: $encoded = $this->encodeQP($str);
2744: break;
2745: default:
2746: $this->setError($this->lang('encoding') . $encoding);
2747: break;
2748: }
2749: return $encoded;
2750: }
2751:
2752: 2753: 2754: 2755: 2756: 2757: 2758: 2759:
2760: public function encodeHeader($str, $position = 'text')
2761: {
2762: $matchcount = 0;
2763: switch (strtolower($position)) {
2764: case 'phrase':
2765: if (!preg_match('/[\200-\377]/', $str)) {
2766:
2767: $encoded = addcslashes($str, "\0..\37\177\\\"");
2768: if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2769: return ($encoded);
2770: } else {
2771: return ("\"$encoded\"");
2772: }
2773: }
2774: $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2775: break;
2776:
2777: case 'comment':
2778: $matchcount = preg_match_all('/[()"]/', $str, $matches);
2779:
2780: case 'text':
2781: default:
2782: $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2783: break;
2784: }
2785:
2786:
2787: if ($matchcount == 0) {
2788: return ($str);
2789: }
2790:
2791: $maxlen = 75 - 7 - strlen($this->CharSet);
2792:
2793: if ($matchcount > strlen($str) / 3) {
2794:
2795: $encoding = 'B';
2796: if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2797:
2798:
2799: $encoded = $this->base64EncodeWrapMB($str, "\n");
2800: } else {
2801: $encoded = base64_encode($str);
2802: $maxlen -= $maxlen % 4;
2803: $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2804: }
2805: } else {
2806: $encoding = 'Q';
2807: $encoded = $this->encodeQ($str, $position);
2808: $encoded = $this->wrapText($encoded, $maxlen, true);
2809: $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2810: }
2811:
2812: $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2813: $encoded = trim(str_replace("\n", $this->LE, $encoded));
2814:
2815: return $encoded;
2816: }
2817:
2818: 2819: 2820: 2821: 2822: 2823:
2824: public function hasMultiBytes($str)
2825: {
2826: if (function_exists('mb_strlen')) {
2827: return (strlen($str) > mb_strlen($str, $this->CharSet));
2828: } else {
2829: return false;
2830: }
2831: }
2832:
2833: 2834: 2835: 2836: 2837:
2838: public function has8bitChars($text)
2839: {
2840: return (boolean)preg_match('/[\x80-\xFF]/', $text);
2841: }
2842:
2843: 2844: 2845: 2846: 2847: 2848: 2849: 2850: 2851: 2852:
2853: public function base64EncodeWrapMB($str, $linebreak = null)
2854: {
2855: $start = '=?' . $this->CharSet . '?B?';
2856: $end = '?=';
2857: $encoded = '';
2858: if ($linebreak === null) {
2859: $linebreak = $this->LE;
2860: }
2861:
2862: $mb_length = mb_strlen($str, $this->CharSet);
2863:
2864: $length = 75 - strlen($start) - strlen($end);
2865:
2866: $ratio = $mb_length / strlen($str);
2867:
2868: $avgLength = floor($length * $ratio * .75);
2869:
2870: for ($i = 0; $i < $mb_length; $i += $offset) {
2871: $lookBack = 0;
2872: do {
2873: $offset = $avgLength - $lookBack;
2874: $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2875: $chunk = base64_encode($chunk);
2876: $lookBack++;
2877: } while (strlen($chunk) > $length);
2878: $encoded .= $chunk . $linebreak;
2879: }
2880:
2881:
2882: $encoded = substr($encoded, 0, -strlen($linebreak));
2883: return $encoded;
2884: }
2885:
2886: 2887: 2888: 2889: 2890: 2891: 2892: 2893: 2894:
2895: public function encodeQP($string, $line_max = 76)
2896: {
2897:
2898: if (function_exists('quoted_printable_encode')) {
2899: return quoted_printable_encode($string);
2900: }
2901:
2902: $string = str_replace(
2903: array('%20', '%0D%0A.', '%0D%0A', '%'),
2904: array(' ', "\r\n=2E", "\r\n", '='),
2905: rawurlencode($string)
2906: );
2907: return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2908: }
2909:
2910: 2911: 2912: 2913: 2914: 2915: 2916: 2917: 2918: 2919:
2920: public function encodeQPphp(
2921: $string,
2922: $line_max = 76,
2923: $space_conv = false
2924: ) {
2925: return $this->encodeQP($string, $line_max);
2926: }
2927:
2928: 2929: 2930: 2931: 2932: 2933: 2934: 2935:
2936: public function encodeQ($str, $position = 'text')
2937: {
2938:
2939: $pattern = '';
2940: $encoded = str_replace(array("\r", "\n"), '', $str);
2941: switch (strtolower($position)) {
2942: case 'phrase':
2943:
2944: $pattern = '^A-Za-z0-9!*+\/ -';
2945: break;
2946:
2947: case 'comment':
2948:
2949: $pattern = '\(\)"';
2950:
2951:
2952: case 'text':
2953: default:
2954:
2955:
2956: $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2957: break;
2958: }
2959: $matches = array();
2960: if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2961:
2962:
2963: $eqkey = array_search('=', $matches[0]);
2964: if (false !== $eqkey) {
2965: unset($matches[0][$eqkey]);
2966: array_unshift($matches[0], '=');
2967: }
2968: foreach (array_unique($matches[0]) as $char) {
2969: $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2970: }
2971: }
2972:
2973: return str_replace(' ', '_', $encoded);
2974: }
2975:
2976: 2977: 2978: 2979: 2980: 2981: 2982: 2983: 2984: 2985: 2986:
2987: public function addStringAttachment(
2988: $string,
2989: $filename,
2990: $encoding = 'base64',
2991: $type = '',
2992: $disposition = 'attachment'
2993: ) {
2994:
2995: if ($type == '') {
2996: $type = self::filenameToType($filename);
2997: }
2998:
2999: $this->attachment[] = array(
3000: 0 => $string,
3001: 1 => $filename,
3002: 2 => basename($filename),
3003: 3 => $encoding,
3004: 4 => $type,
3005: 5 => true,
3006: 6 => $disposition,
3007: 7 => 0
3008: );
3009: }
3010:
3011: 3012: 3013: 3014: 3015: 3016: 3017: 3018: 3019: 3020: 3021: 3022: 3023: 3024: 3025: 3026: 3027:
3028: public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3029: {
3030: if (!@is_file($path)) {
3031: $this->setError($this->lang('file_access') . $path);
3032: return false;
3033: }
3034:
3035:
3036: if ($type == '') {
3037: $type = self::filenameToType($path);
3038: }
3039:
3040: $filename = basename($path);
3041: if ($name == '') {
3042: $name = $filename;
3043: }
3044:
3045:
3046: $this->attachment[] = array(
3047: 0 => $path,
3048: 1 => $filename,
3049: 2 => $name,
3050: 3 => $encoding,
3051: 4 => $type,
3052: 5 => false,
3053: 6 => $disposition,
3054: 7 => $cid
3055: );
3056: return true;
3057: }
3058:
3059: 3060: 3061: 3062: 3063: 3064: 3065: 3066: 3067: 3068: 3069: 3070: 3071: 3072:
3073: public function addStringEmbeddedImage(
3074: $string,
3075: $cid,
3076: $name = '',
3077: $encoding = 'base64',
3078: $type = '',
3079: $disposition = 'inline'
3080: ) {
3081:
3082: if ($type == '' and !empty($name)) {
3083: $type = self::filenameToType($name);
3084: }
3085:
3086:
3087: $this->attachment[] = array(
3088: 0 => $string,
3089: 1 => $name,
3090: 2 => $name,
3091: 3 => $encoding,
3092: 4 => $type,
3093: 5 => true,
3094: 6 => $disposition,
3095: 7 => $cid
3096: );
3097: return true;
3098: }
3099:
3100: 3101: 3102: 3103: 3104:
3105: public function inlineImageExists()
3106: {
3107: foreach ($this->attachment as $attachment) {
3108: if ($attachment[6] == 'inline') {
3109: return true;
3110: }
3111: }
3112: return false;
3113: }
3114:
3115: 3116: 3117: 3118:
3119: public function attachmentExists()
3120: {
3121: foreach ($this->attachment as $attachment) {
3122: if ($attachment[6] == 'attachment') {
3123: return true;
3124: }
3125: }
3126: return false;
3127: }
3128:
3129: 3130: 3131: 3132:
3133: public function alternativeExists()
3134: {
3135: return !empty($this->AltBody);
3136: }
3137:
3138: 3139: 3140: 3141: 3142: 3143:
3144: public function clearQueuedAddresses($kind)
3145: {
3146: $RecipientsQueue = $this->RecipientsQueue;
3147: foreach ($RecipientsQueue as $address => $params) {
3148: if ($params[0] == $kind) {
3149: unset($this->RecipientsQueue[$address]);
3150: }
3151: }
3152: }
3153:
3154: 3155: 3156: 3157:
3158: public function clearAddresses()
3159: {
3160: foreach ($this->to as $to) {
3161: unset($this->all_recipients[strtolower($to[0])]);
3162: }
3163: $this->to = array();
3164: $this->clearQueuedAddresses('to');
3165: }
3166:
3167: 3168: 3169: 3170:
3171: public function clearCCs()
3172: {
3173: foreach ($this->cc as $cc) {
3174: unset($this->all_recipients[strtolower($cc[0])]);
3175: }
3176: $this->cc = array();
3177: $this->clearQueuedAddresses('cc');
3178: }
3179:
3180: 3181: 3182: 3183:
3184: public function clearBCCs()
3185: {
3186: foreach ($this->bcc as $bcc) {
3187: unset($this->all_recipients[strtolower($bcc[0])]);
3188: }
3189: $this->bcc = array();
3190: $this->clearQueuedAddresses('bcc');
3191: }
3192:
3193: 3194: 3195: 3196:
3197: public function clearReplyTos()
3198: {
3199: $this->ReplyTo = array();
3200: $this->ReplyToQueue = array();
3201: }
3202:
3203: 3204: 3205: 3206:
3207: public function clearAllRecipients()
3208: {
3209: $this->to = array();
3210: $this->cc = array();
3211: $this->bcc = array();
3212: $this->all_recipients = array();
3213: $this->RecipientsQueue = array();
3214: }
3215:
3216: 3217: 3218: 3219:
3220: public function clearAttachments()
3221: {
3222: $this->attachment = array();
3223: }
3224:
3225: 3226: 3227: 3228:
3229: public function clearCustomHeaders()
3230: {
3231: $this->CustomHeader = array();
3232: }
3233:
3234: 3235: 3236: 3237: 3238: 3239:
3240: protected function setError($msg)
3241: {
3242: $this->error_count++;
3243: if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3244: $lasterror = $this->smtp->getError();
3245: if (!empty($lasterror['error'])) {
3246: $msg .= $this->lang('smtp_error') . $lasterror['error'];
3247: if (!empty($lasterror['detail'])) {
3248: $msg .= ' Detail: '. $lasterror['detail'];
3249: }
3250: if (!empty($lasterror['smtp_code'])) {
3251: $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3252: }
3253: if (!empty($lasterror['smtp_code_ex'])) {
3254: $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3255: }
3256: }
3257: }
3258: $this->ErrorInfo = $msg;
3259: }
3260:
3261: 3262: 3263: 3264: 3265: 3266:
3267: public static function rfcDate()
3268: {
3269:
3270:
3271: date_default_timezone_set(@date_default_timezone_get());
3272: return date('D, j M Y H:i:s O');
3273: }
3274:
3275: 3276: 3277: 3278: 3279: 3280:
3281: protected function serverHostname()
3282: {
3283: $result = 'localhost.localdomain';
3284: if (!empty($this->Hostname)) {
3285: $result = $this->Hostname;
3286: } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3287: $result = $_SERVER['SERVER_NAME'];
3288: } elseif (function_exists('gethostname') && gethostname() !== false) {
3289: $result = gethostname();
3290: } elseif (php_uname('n') !== false) {
3291: $result = php_uname('n');
3292: }
3293: return $result;
3294: }
3295:
3296: 3297: 3298: 3299: 3300: 3301:
3302: protected function lang($key)
3303: {
3304: if (count($this->language) < 1) {
3305: $this->setLanguage('en');
3306: }
3307:
3308: if (array_key_exists($key, $this->language)) {
3309: if ($key == 'smtp_connect_failed') {
3310:
3311:
3312:
3313: return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3314: }
3315: return $this->language[$key];
3316: } else {
3317:
3318: return $key;
3319: }
3320: }
3321:
3322: 3323: 3324: 3325: 3326:
3327: public function isError()
3328: {
3329: return ($this->error_count > 0);
3330: }
3331:
3332: 3333: 3334: 3335: 3336: 3337: 3338:
3339: public function fixEOL($str)
3340: {
3341:
3342: $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3343:
3344: if ($this->LE !== "\n") {
3345: $nstr = str_replace("\n", $this->LE, $nstr);
3346: }
3347: return $nstr;
3348: }
3349:
3350: 3351: 3352: 3353: 3354: 3355: 3356: 3357: 3358:
3359: public function addCustomHeader($name, $value = null)
3360: {
3361: if ($value === null) {
3362:
3363: $this->CustomHeader[] = explode(':', $name, 2);
3364: } else {
3365: $this->CustomHeader[] = array($name, $value);
3366: }
3367: }
3368:
3369: 3370: 3371: 3372:
3373: public function getCustomHeaders()
3374: {
3375: return $this->CustomHeader;
3376: }
3377:
3378: 3379: 3380: 3381: 3382: 3383: 3384: 3385: 3386: 3387: 3388: 3389: 3390: 3391: 3392: 3393:
3394: public function msgHTML($message, $basedir = '', $advanced = false)
3395: {
3396: preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3397: if (array_key_exists(2, $images)) {
3398: if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3399:
3400: $basedir .= '/';
3401: }
3402: foreach ($images[2] as $imgindex => $url) {
3403:
3404: if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3405: $data = substr($url, strpos($url, ','));
3406: if ($match[2]) {
3407: $data = base64_decode($data);
3408: } else {
3409: $data = rawurldecode($data);
3410: }
3411: $cid = md5($url) . '@phpmailer.0';
3412: if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3413: $message = str_replace(
3414: $images[0][$imgindex],
3415: $images[1][$imgindex] . '="cid:' . $cid . '"',
3416: $message
3417: );
3418: }
3419: continue;
3420: }
3421: if (
3422:
3423: !empty($basedir)
3424:
3425: && (strpos($url, '..') === false)
3426:
3427: && substr($url, 0, 4) !== 'cid:'
3428:
3429: && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
3430: ) {
3431: $filename = basename($url);
3432: $directory = dirname($url);
3433: if ($directory == '.') {
3434: $directory = '';
3435: }
3436: $cid = md5($url) . '@phpmailer.0';
3437: if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3438: $directory .= '/';
3439: }
3440: if ($this->addEmbeddedImage(
3441: $basedir . $directory . $filename,
3442: $cid,
3443: $filename,
3444: 'base64',
3445: self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3446: )
3447: ) {
3448: $message = preg_replace(
3449: '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3450: $images[1][$imgindex] . '="cid:' . $cid . '"',
3451: $message
3452: );
3453: }
3454: }
3455: }
3456: }
3457: $this->isHTML(true);
3458:
3459: $this->Body = $this->normalizeBreaks($message);
3460: $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3461: if (!$this->alternativeExists()) {
3462: $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3463: self::CRLF . self::CRLF;
3464: }
3465: return $this->Body;
3466: }
3467:
3468: 3469: 3470: 3471: 3472: 3473: 3474: 3475: 3476: 3477: 3478: 3479: 3480: 3481: 3482: 3483: 3484: 3485: 3486: 3487:
3488: public function html2text($html, $advanced = false)
3489: {
3490: if (is_callable($advanced)) {
3491: return call_user_func($advanced, $html);
3492: }
3493: return html_entity_decode(
3494: trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3495: ENT_QUOTES,
3496: $this->CharSet
3497: );
3498: }
3499:
3500: 3501: 3502: 3503: 3504: 3505: 3506:
3507: public static function _mime_types($ext = '')
3508: {
3509: $mimes = array(
3510: 'xl' => 'application/excel',
3511: 'js' => 'application/javascript',
3512: 'hqx' => 'application/mac-binhex40',
3513: 'cpt' => 'application/mac-compactpro',
3514: 'bin' => 'application/macbinary',
3515: 'doc' => 'application/msword',
3516: 'word' => 'application/msword',
3517: 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3518: 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3519: 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3520: 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3521: 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3522: 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3523: 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3524: 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3525: 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
3526: 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3527: 'class' => 'application/octet-stream',
3528: 'dll' => 'application/octet-stream',
3529: 'dms' => 'application/octet-stream',
3530: 'exe' => 'application/octet-stream',
3531: 'lha' => 'application/octet-stream',
3532: 'lzh' => 'application/octet-stream',
3533: 'psd' => 'application/octet-stream',
3534: 'sea' => 'application/octet-stream',
3535: 'so' => 'application/octet-stream',
3536: 'oda' => 'application/oda',
3537: 'pdf' => 'application/pdf',
3538: 'ai' => 'application/postscript',
3539: 'eps' => 'application/postscript',
3540: 'ps' => 'application/postscript',
3541: 'smi' => 'application/smil',
3542: 'smil' => 'application/smil',
3543: 'mif' => 'application/vnd.mif',
3544: 'xls' => 'application/vnd.ms-excel',
3545: 'ppt' => 'application/vnd.ms-powerpoint',
3546: 'wbxml' => 'application/vnd.wap.wbxml',
3547: 'wmlc' => 'application/vnd.wap.wmlc',
3548: 'dcr' => 'application/x-director',
3549: 'dir' => 'application/x-director',
3550: 'dxr' => 'application/x-director',
3551: 'dvi' => 'application/x-dvi',
3552: 'gtar' => 'application/x-gtar',
3553: 'php3' => 'application/x-httpd-php',
3554: 'php4' => 'application/x-httpd-php',
3555: 'php' => 'application/x-httpd-php',
3556: 'phtml' => 'application/x-httpd-php',
3557: 'phps' => 'application/x-httpd-php-source',
3558: 'swf' => 'application/x-shockwave-flash',
3559: 'sit' => 'application/x-stuffit',
3560: 'tar' => 'application/x-tar',
3561: 'tgz' => 'application/x-tar',
3562: 'xht' => 'application/xhtml+xml',
3563: 'xhtml' => 'application/xhtml+xml',
3564: 'zip' => 'application/zip',
3565: 'mid' => 'audio/midi',
3566: 'midi' => 'audio/midi',
3567: 'mp2' => 'audio/mpeg',
3568: 'mp3' => 'audio/mpeg',
3569: 'mpga' => 'audio/mpeg',
3570: 'aif' => 'audio/x-aiff',
3571: 'aifc' => 'audio/x-aiff',
3572: 'aiff' => 'audio/x-aiff',
3573: 'ram' => 'audio/x-pn-realaudio',
3574: 'rm' => 'audio/x-pn-realaudio',
3575: 'rpm' => 'audio/x-pn-realaudio-plugin',
3576: 'ra' => 'audio/x-realaudio',
3577: 'wav' => 'audio/x-wav',
3578: 'bmp' => 'image/bmp',
3579: 'gif' => 'image/gif',
3580: 'jpeg' => 'image/jpeg',
3581: 'jpe' => 'image/jpeg',
3582: 'jpg' => 'image/jpeg',
3583: 'png' => 'image/png',
3584: 'tiff' => 'image/tiff',
3585: 'tif' => 'image/tiff',
3586: 'eml' => 'message/rfc822',
3587: 'css' => 'text/css',
3588: 'html' => 'text/html',
3589: 'htm' => 'text/html',
3590: 'shtml' => 'text/html',
3591: 'log' => 'text/plain',
3592: 'text' => 'text/plain',
3593: 'txt' => 'text/plain',
3594: 'rtx' => 'text/richtext',
3595: 'rtf' => 'text/rtf',
3596: 'vcf' => 'text/vcard',
3597: 'vcard' => 'text/vcard',
3598: 'xml' => 'text/xml',
3599: 'xsl' => 'text/xml',
3600: 'mpeg' => 'video/mpeg',
3601: 'mpe' => 'video/mpeg',
3602: 'mpg' => 'video/mpeg',
3603: 'mov' => 'video/quicktime',
3604: 'qt' => 'video/quicktime',
3605: 'rv' => 'video/vnd.rn-realvideo',
3606: 'avi' => 'video/x-msvideo',
3607: 'movie' => 'video/x-sgi-movie'
3608: );
3609: if (array_key_exists(strtolower($ext), $mimes)) {
3610: return $mimes[strtolower($ext)];
3611: }
3612: return 'application/octet-stream';
3613: }
3614:
3615: 3616: 3617: 3618: 3619: 3620: 3621:
3622: public static function filenameToType($filename)
3623: {
3624:
3625: $qpos = strpos($filename, '?');
3626: if (false !== $qpos) {
3627: $filename = substr($filename, 0, $qpos);
3628: }
3629: $pathinfo = self::mb_pathinfo($filename);
3630: return self::_mime_types($pathinfo['extension']);
3631: }
3632:
3633: 3634: 3635: 3636: 3637: 3638: 3639: 3640: 3641: 3642: 3643:
3644: public static function mb_pathinfo($path, $options = null)
3645: {
3646: $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3647: $pathinfo = array();
3648: if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3649: if (array_key_exists(1, $pathinfo)) {
3650: $ret['dirname'] = $pathinfo[1];
3651: }
3652: if (array_key_exists(2, $pathinfo)) {
3653: $ret['basename'] = $pathinfo[2];
3654: }
3655: if (array_key_exists(5, $pathinfo)) {
3656: $ret['extension'] = $pathinfo[5];
3657: }
3658: if (array_key_exists(3, $pathinfo)) {
3659: $ret['filename'] = $pathinfo[3];
3660: }
3661: }
3662: switch ($options) {
3663: case PATHINFO_DIRNAME:
3664: case 'dirname':
3665: return $ret['dirname'];
3666: case PATHINFO_BASENAME:
3667: case 'basename':
3668: return $ret['basename'];
3669: case PATHINFO_EXTENSION:
3670: case 'extension':
3671: return $ret['extension'];
3672: case PATHINFO_FILENAME:
3673: case 'filename':
3674: return $ret['filename'];
3675: default:
3676: return $ret;
3677: }
3678: }
3679:
3680: 3681: 3682: 3683: 3684: 3685: 3686: 3687: 3688: 3689: 3690: 3691: 3692: 3693:
3694: public function set($name, $value = '')
3695: {
3696: if (property_exists($this, $name)) {
3697: $this->$name = $value;
3698: return true;
3699: } else {
3700: $this->setError($this->lang('variable_set') . $name);
3701: return false;
3702: }
3703: }
3704:
3705: 3706: 3707: 3708: 3709: 3710:
3711: public function secureHeader($str)
3712: {
3713: return trim(str_replace(array("\r", "\n"), '', $str));
3714: }
3715:
3716: 3717: 3718: 3719: 3720: 3721: 3722: 3723: 3724: 3725:
3726: public static function normalizeBreaks($text, $breaktype = "\r\n")
3727: {
3728: return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3729: }
3730:
3731: 3732: 3733: 3734: 3735: 3736: 3737: 3738:
3739: public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3740: {
3741: $this->sign_cert_file = $cert_filename;
3742: $this->sign_key_file = $key_filename;
3743: $this->sign_key_pass = $key_pass;
3744: $this->sign_extracerts_file = $extracerts_filename;
3745: }
3746:
3747: 3748: 3749: 3750: 3751: 3752:
3753: public function DKIM_QP($txt)
3754: {
3755: $line = '';
3756: for ($i = 0; $i < strlen($txt); $i++) {
3757: $ord = ord($txt[$i]);
3758: if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3759: $line .= $txt[$i];
3760: } else {
3761: $line .= '=' . sprintf('%02X', $ord);
3762: }
3763: }
3764: return $line;
3765: }
3766:
3767: 3768: 3769: 3770: 3771: 3772: 3773:
3774: public function DKIM_Sign($signHeader)
3775: {
3776: if (!defined('PKCS7_TEXT')) {
3777: if ($this->exceptions) {
3778: throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3779: }
3780: return '';
3781: }
3782: $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3783: if ('' != $this->DKIM_passphrase) {
3784: $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3785: } else {
3786: $privKey = openssl_pkey_get_private($privKeyStr);
3787: }
3788:
3789:
3790: if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3791: in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3792: if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3793: openssl_pkey_free($privKey);
3794: return base64_encode($signature);
3795: }
3796: } else {
3797: $pinfo = openssl_pkey_get_details($privKey);
3798: $hash = hash('sha256', $signHeader);
3799:
3800:
3801: $t = '3031300d060960864801650304020105000420' . $hash;
3802: $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3803: $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3804:
3805: if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3806: openssl_pkey_free($privKey);
3807: return base64_encode($signature);
3808: }
3809: }
3810: openssl_pkey_free($privKey);
3811: return '';
3812: }
3813:
3814: 3815: 3816: 3817: 3818: 3819:
3820: public function DKIM_HeaderC($signHeader)
3821: {
3822: $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3823: $lines = explode("\r\n", $signHeader);
3824: foreach ($lines as $key => $line) {
3825: list($heading, $value) = explode(':', $line, 2);
3826: $heading = strtolower($heading);
3827: $value = preg_replace('/\s{2,}/', ' ', $value);
3828: $lines[$key] = $heading . ':' . trim($value);
3829: }
3830: $signHeader = implode("\r\n", $lines);
3831: return $signHeader;
3832: }
3833:
3834: 3835: 3836: 3837: 3838: 3839:
3840: public function DKIM_BodyC($body)
3841: {
3842: if ($body == '') {
3843: return "\r\n";
3844: }
3845:
3846: $body = str_replace("\r\n", "\n", $body);
3847: $body = str_replace("\n", "\r\n", $body);
3848:
3849: while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3850: $body = substr($body, 0, strlen($body) - 2);
3851: }
3852: return $body;
3853: }
3854:
3855: 3856: 3857: 3858: 3859: 3860: 3861: 3862:
3863: public function DKIM_Add($headers_line, $subject, $body)
3864: {
3865: $DKIMsignatureType = 'rsa-sha256';
3866: $DKIMcanonicalization = 'relaxed/simple';
3867: $DKIMquery = 'dns/txt';
3868: $DKIMtime = time();
3869: $subject_header = "Subject: $subject";
3870: $headers = explode($this->LE, $headers_line);
3871: $from_header = '';
3872: $to_header = '';
3873: $date_header = '';
3874: $current = '';
3875: foreach ($headers as $header) {
3876: if (strpos($header, 'From:') === 0) {
3877: $from_header = $header;
3878: $current = 'from_header';
3879: } elseif (strpos($header, 'To:') === 0) {
3880: $to_header = $header;
3881: $current = 'to_header';
3882: } elseif (strpos($header, 'Date:') === 0) {
3883: $date_header = $header;
3884: $current = 'date_header';
3885: } else {
3886: if (!empty($$current) && strpos($header, ' =?') === 0) {
3887: $$current .= $header;
3888: } else {
3889: $current = '';
3890: }
3891: }
3892: }
3893: $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3894: $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3895: $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3896: $subject = str_replace(
3897: '|',
3898: '=7C',
3899: $this->DKIM_QP($subject_header)
3900: );
3901: $body = $this->DKIM_BodyC($body);
3902: $DKIMlen = strlen($body);
3903: $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
3904: if ('' == $this->DKIM_identity) {
3905: $ident = '';
3906: } else {
3907: $ident = ' i=' . $this->DKIM_identity . ';';
3908: }
3909: $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3910: $DKIMsignatureType . '; q=' .
3911: $DKIMquery . '; l=' .
3912: $DKIMlen . '; s=' .
3913: $this->DKIM_selector .
3914: ";\r\n" .
3915: "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3916: "\th=From:To:Date:Subject;\r\n" .
3917: "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3918: "\tz=$from\r\n" .
3919: "\t|$to\r\n" .
3920: "\t|$date\r\n" .
3921: "\t|$subject;\r\n" .
3922: "\tbh=" . $DKIMb64 . ";\r\n" .
3923: "\tb=";
3924: $toSign = $this->DKIM_HeaderC(
3925: $from_header . "\r\n" .
3926: $to_header . "\r\n" .
3927: $date_header . "\r\n" .
3928: $subject_header . "\r\n" .
3929: $dkimhdrs
3930: );
3931: $signed = $this->DKIM_Sign($toSign);
3932: return $dkimhdrs . $signed . "\r\n";
3933: }
3934:
3935: 3936: 3937: 3938: 3939: 3940:
3941: public static function hasLineLongerThanMax($str)
3942: {
3943:
3944: return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3945: }
3946:
3947: 3948: 3949: 3950: 3951: 3952:
3953: public function getToAddresses()
3954: {
3955: return $this->to;
3956: }
3957:
3958: 3959: 3960: 3961: 3962: 3963:
3964: public function getCcAddresses()
3965: {
3966: return $this->cc;
3967: }
3968:
3969: 3970: 3971: 3972: 3973: 3974:
3975: public function getBccAddresses()
3976: {
3977: return $this->bcc;
3978: }
3979:
3980: 3981: 3982: 3983: 3984: 3985:
3986: public function getReplyToAddresses()
3987: {
3988: return $this->ReplyTo;
3989: }
3990:
3991: 3992: 3993: 3994: 3995: 3996:
3997: public function getAllRecipientAddresses()
3998: {
3999: return $this->all_recipients;
4000: }
4001:
4002: 4003: 4004: 4005: 4006: 4007: 4008: 4009: 4010: 4011:
4012: protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4013: {
4014: if (!empty($this->action_function) && is_callable($this->action_function)) {
4015: $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4016: call_user_func_array($this->action_function, $params);
4017: }
4018: }
4019: }
4020:
4021: 4022: 4023: 4024:
4025: class phpmailerException extends Exception
4026: {
4027: 4028: 4029: 4030:
4031: public function errorMessage()
4032: {
4033: $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
4034: return $errorMsg;
4035: }
4036: }
4037: