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.21';
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: if ($this->MessageDate == '') {
2028: $this->MessageDate = self::rfcDate();
2029: }
2030: $result .= $this->headerLine('Date', $this->MessageDate);
2031:
2032:
2033: if ($this->SingleTo) {
2034: if ($this->Mailer != 'mail') {
2035: foreach ($this->to as $toaddr) {
2036: $this->SingleToArray[] = $this->addrFormat($toaddr);
2037: }
2038: }
2039: } else {
2040: if (count($this->to) > 0) {
2041: if ($this->Mailer != 'mail') {
2042: $result .= $this->addrAppend('To', $this->to);
2043: }
2044: } elseif (count($this->cc) == 0) {
2045: $result .= $this->headerLine('To', 'undisclosed-recipients:;');
2046: }
2047: }
2048:
2049: $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
2050:
2051:
2052: if (count($this->cc) > 0) {
2053: $result .= $this->addrAppend('Cc', $this->cc);
2054: }
2055:
2056:
2057: if ((
2058: $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
2059: )
2060: and count($this->bcc) > 0
2061: ) {
2062: $result .= $this->addrAppend('Bcc', $this->bcc);
2063: }
2064:
2065: if (count($this->ReplyTo) > 0) {
2066: $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
2067: }
2068:
2069:
2070: if ($this->Mailer != 'mail') {
2071: $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
2072: }
2073:
2074:
2075:
2076: if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
2077: $this->lastMessageID = $this->MessageID;
2078: } else {
2079: $this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
2080: }
2081: $result .= $this->headerLine('Message-ID', $this->lastMessageID);
2082: if (!is_null($this->Priority)) {
2083: $result .= $this->headerLine('X-Priority', $this->Priority);
2084: }
2085: if ($this->XMailer == '') {
2086: $result .= $this->headerLine(
2087: 'X-Mailer',
2088: 'PHPMailer ' . $this->Version . ' (https://github.com/PHPMailer/PHPMailer)'
2089: );
2090: } else {
2091: $myXmailer = trim($this->XMailer);
2092: if ($myXmailer) {
2093: $result .= $this->headerLine('X-Mailer', $myXmailer);
2094: }
2095: }
2096:
2097: if ($this->ConfirmReadingTo != '') {
2098: $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
2099: }
2100:
2101:
2102: foreach ($this->CustomHeader as $header) {
2103: $result .= $this->headerLine(
2104: trim($header[0]),
2105: $this->encodeHeader(trim($header[1]))
2106: );
2107: }
2108: if (!$this->sign_key_file) {
2109: $result .= $this->headerLine('MIME-Version', '1.0');
2110: $result .= $this->getMailMIME();
2111: }
2112:
2113: return $result;
2114: }
2115:
2116: 2117: 2118: 2119: 2120:
2121: public function getMailMIME()
2122: {
2123: $result = '';
2124: $ismultipart = true;
2125: switch ($this->message_type) {
2126: case 'inline':
2127: $result .= $this->headerLine('Content-Type', 'multipart/related;');
2128: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2129: break;
2130: case 'attach':
2131: case 'inline_attach':
2132: case 'alt_attach':
2133: case 'alt_inline_attach':
2134: $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
2135: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2136: break;
2137: case 'alt':
2138: case 'alt_inline':
2139: $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
2140: $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
2141: break;
2142: default:
2143:
2144: $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
2145: $ismultipart = false;
2146: break;
2147: }
2148:
2149: if ($this->Encoding != '7bit') {
2150:
2151: if ($ismultipart) {
2152: if ($this->Encoding == '8bit') {
2153: $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
2154: }
2155:
2156: } else {
2157: $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
2158: }
2159: }
2160:
2161: if ($this->Mailer != 'mail') {
2162: $result .= $this->LE;
2163: }
2164:
2165: return $result;
2166: }
2167:
2168: 2169: 2170: 2171: 2172: 2173: 2174: 2175:
2176: public function getSentMIMEMessage()
2177: {
2178: return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
2179: }
2180:
2181: 2182: 2183: 2184:
2185: protected function generateId() {
2186: return md5(uniqid(time()));
2187: }
2188:
2189: 2190: 2191: 2192: 2193: 2194: 2195:
2196: public function createBody()
2197: {
2198: $body = '';
2199:
2200: $this->uniqueid = $this->generateId();
2201: $this->boundary[1] = 'b1_' . $this->uniqueid;
2202: $this->boundary[2] = 'b2_' . $this->uniqueid;
2203: $this->boundary[3] = 'b3_' . $this->uniqueid;
2204:
2205: if ($this->sign_key_file) {
2206: $body .= $this->getMailMIME() . $this->LE;
2207: }
2208:
2209: $this->setWordWrap();
2210:
2211: $bodyEncoding = $this->Encoding;
2212: $bodyCharSet = $this->CharSet;
2213:
2214: if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
2215: $bodyEncoding = '7bit';
2216:
2217: $bodyCharSet = 'us-ascii';
2218: }
2219:
2220:
2221: if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
2222: $bodyEncoding = 'quoted-printable';
2223: }
2224:
2225: $altBodyEncoding = $this->Encoding;
2226: $altBodyCharSet = $this->CharSet;
2227:
2228: if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
2229: $altBodyEncoding = '7bit';
2230:
2231: $altBodyCharSet = 'us-ascii';
2232: }
2233:
2234:
2235: if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
2236: $altBodyEncoding = 'quoted-printable';
2237: }
2238:
2239: $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
2240: switch ($this->message_type) {
2241: case 'inline':
2242: $body .= $mimepre;
2243: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2244: $body .= $this->encodeString($this->Body, $bodyEncoding);
2245: $body .= $this->LE . $this->LE;
2246: $body .= $this->attachAll('inline', $this->boundary[1]);
2247: break;
2248: case 'attach':
2249: $body .= $mimepre;
2250: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
2251: $body .= $this->encodeString($this->Body, $bodyEncoding);
2252: $body .= $this->LE . $this->LE;
2253: $body .= $this->attachAll('attachment', $this->boundary[1]);
2254: break;
2255: case 'inline_attach':
2256: $body .= $mimepre;
2257: $body .= $this->textLine('--' . $this->boundary[1]);
2258: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2259: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2260: $body .= $this->LE;
2261: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
2262: $body .= $this->encodeString($this->Body, $bodyEncoding);
2263: $body .= $this->LE . $this->LE;
2264: $body .= $this->attachAll('inline', $this->boundary[2]);
2265: $body .= $this->LE;
2266: $body .= $this->attachAll('attachment', $this->boundary[1]);
2267: break;
2268: case 'alt':
2269: $body .= $mimepre;
2270: $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2271: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2272: $body .= $this->LE . $this->LE;
2273: $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
2274: $body .= $this->encodeString($this->Body, $bodyEncoding);
2275: $body .= $this->LE . $this->LE;
2276: if (!empty($this->Ical)) {
2277: $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
2278: $body .= $this->encodeString($this->Ical, $this->Encoding);
2279: $body .= $this->LE . $this->LE;
2280: }
2281: $body .= $this->endBoundary($this->boundary[1]);
2282: break;
2283: case 'alt_inline':
2284: $body .= $mimepre;
2285: $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2286: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2287: $body .= $this->LE . $this->LE;
2288: $body .= $this->textLine('--' . $this->boundary[1]);
2289: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2290: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2291: $body .= $this->LE;
2292: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2293: $body .= $this->encodeString($this->Body, $bodyEncoding);
2294: $body .= $this->LE . $this->LE;
2295: $body .= $this->attachAll('inline', $this->boundary[2]);
2296: $body .= $this->LE;
2297: $body .= $this->endBoundary($this->boundary[1]);
2298: break;
2299: case 'alt_attach':
2300: $body .= $mimepre;
2301: $body .= $this->textLine('--' . $this->boundary[1]);
2302: $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2303: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2304: $body .= $this->LE;
2305: $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2306: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2307: $body .= $this->LE . $this->LE;
2308: $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
2309: $body .= $this->encodeString($this->Body, $bodyEncoding);
2310: $body .= $this->LE . $this->LE;
2311: $body .= $this->endBoundary($this->boundary[2]);
2312: $body .= $this->LE;
2313: $body .= $this->attachAll('attachment', $this->boundary[1]);
2314: break;
2315: case 'alt_inline_attach':
2316: $body .= $mimepre;
2317: $body .= $this->textLine('--' . $this->boundary[1]);
2318: $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
2319: $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
2320: $body .= $this->LE;
2321: $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
2322: $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
2323: $body .= $this->LE . $this->LE;
2324: $body .= $this->textLine('--' . $this->boundary[2]);
2325: $body .= $this->headerLine('Content-Type', 'multipart/related;');
2326: $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
2327: $body .= $this->LE;
2328: $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
2329: $body .= $this->encodeString($this->Body, $bodyEncoding);
2330: $body .= $this->LE . $this->LE;
2331: $body .= $this->attachAll('inline', $this->boundary[3]);
2332: $body .= $this->LE;
2333: $body .= $this->endBoundary($this->boundary[2]);
2334: $body .= $this->LE;
2335: $body .= $this->attachAll('attachment', $this->boundary[1]);
2336: break;
2337: default:
2338:
2339:
2340: $this->Encoding = $bodyEncoding;
2341: $body .= $this->encodeString($this->Body, $this->Encoding);
2342: break;
2343: }
2344:
2345: if ($this->isError()) {
2346: $body = '';
2347: } elseif ($this->sign_key_file) {
2348: try {
2349: if (!defined('PKCS7_TEXT')) {
2350: throw new phpmailerException($this->lang('extension_missing') . 'openssl');
2351: }
2352:
2353: $file = tempnam(sys_get_temp_dir(), 'mail');
2354: if (false === file_put_contents($file, $body)) {
2355: throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
2356: }
2357: $signed = tempnam(sys_get_temp_dir(), 'signed');
2358:
2359: if (empty($this->sign_extracerts_file)) {
2360: $sign = @openssl_pkcs7_sign(
2361: $file,
2362: $signed,
2363: 'file://' . realpath($this->sign_cert_file),
2364: array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2365: null
2366: );
2367: } else {
2368: $sign = @openssl_pkcs7_sign(
2369: $file,
2370: $signed,
2371: 'file://' . realpath($this->sign_cert_file),
2372: array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
2373: null,
2374: PKCS7_DETACHED,
2375: $this->sign_extracerts_file
2376: );
2377: }
2378: if ($sign) {
2379: @unlink($file);
2380: $body = file_get_contents($signed);
2381: @unlink($signed);
2382:
2383: $parts = explode("\n\n", $body, 2);
2384: $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
2385: $body = $parts[1];
2386: } else {
2387: @unlink($file);
2388: @unlink($signed);
2389: throw new phpmailerException($this->lang('signing') . openssl_error_string());
2390: }
2391: } catch (phpmailerException $exc) {
2392: $body = '';
2393: if ($this->exceptions) {
2394: throw $exc;
2395: }
2396: }
2397: }
2398: return $body;
2399: }
2400:
2401: 2402: 2403: 2404: 2405: 2406: 2407: 2408: 2409:
2410: protected function getBoundary($boundary, $charSet, $contentType, $encoding)
2411: {
2412: $result = '';
2413: if ($charSet == '') {
2414: $charSet = $this->CharSet;
2415: }
2416: if ($contentType == '') {
2417: $contentType = $this->ContentType;
2418: }
2419: if ($encoding == '') {
2420: $encoding = $this->Encoding;
2421: }
2422: $result .= $this->textLine('--' . $boundary);
2423: $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
2424: $result .= $this->LE;
2425:
2426: if ($encoding != '7bit') {
2427: $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
2428: }
2429: $result .= $this->LE;
2430:
2431: return $result;
2432: }
2433:
2434: 2435: 2436: 2437: 2438: 2439:
2440: protected function endBoundary($boundary)
2441: {
2442: return $this->LE . '--' . $boundary . '--' . $this->LE;
2443: }
2444:
2445: 2446: 2447: 2448: 2449: 2450:
2451: protected function setMessageType()
2452: {
2453: $type = array();
2454: if ($this->alternativeExists()) {
2455: $type[] = 'alt';
2456: }
2457: if ($this->inlineImageExists()) {
2458: $type[] = 'inline';
2459: }
2460: if ($this->attachmentExists()) {
2461: $type[] = 'attach';
2462: }
2463: $this->message_type = implode('_', $type);
2464: if ($this->message_type == '') {
2465:
2466: $this->message_type = 'plain';
2467: }
2468: }
2469:
2470: 2471: 2472: 2473: 2474: 2475: 2476:
2477: public function headerLine($name, $value)
2478: {
2479: return $name . ': ' . $value . $this->LE;
2480: }
2481:
2482: 2483: 2484: 2485: 2486: 2487:
2488: public function textLine($value)
2489: {
2490: return $value . $this->LE;
2491: }
2492:
2493: 2494: 2495: 2496: 2497: 2498: 2499: 2500: 2501: 2502: 2503:
2504: public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2505: {
2506: try {
2507: if (!@is_file($path)) {
2508: throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2509: }
2510:
2511:
2512: if ($type == '') {
2513: $type = self::filenameToType($path);
2514: }
2515:
2516: $filename = basename($path);
2517: if ($name == '') {
2518: $name = $filename;
2519: }
2520:
2521: $this->attachment[] = array(
2522: 0 => $path,
2523: 1 => $filename,
2524: 2 => $name,
2525: 3 => $encoding,
2526: 4 => $type,
2527: 5 => false,
2528: 6 => $disposition,
2529: 7 => 0
2530: );
2531:
2532: } catch (phpmailerException $exc) {
2533: $this->setError($exc->getMessage());
2534: $this->edebug($exc->getMessage());
2535: if ($this->exceptions) {
2536: throw $exc;
2537: }
2538: return false;
2539: }
2540: return true;
2541: }
2542:
2543: 2544: 2545: 2546:
2547: public function getAttachments()
2548: {
2549: return $this->attachment;
2550: }
2551:
2552: 2553: 2554: 2555: 2556: 2557: 2558: 2559:
2560: protected function attachAll($disposition_type, $boundary)
2561: {
2562:
2563: $mime = array();
2564: $cidUniq = array();
2565: $incl = array();
2566:
2567:
2568: foreach ($this->attachment as $attachment) {
2569:
2570: if ($attachment[6] == $disposition_type) {
2571:
2572: $string = '';
2573: $path = '';
2574: $bString = $attachment[5];
2575: if ($bString) {
2576: $string = $attachment[0];
2577: } else {
2578: $path = $attachment[0];
2579: }
2580:
2581: $inclhash = md5(serialize($attachment));
2582: if (in_array($inclhash, $incl)) {
2583: continue;
2584: }
2585: $incl[] = $inclhash;
2586: $name = $attachment[2];
2587: $encoding = $attachment[3];
2588: $type = $attachment[4];
2589: $disposition = $attachment[6];
2590: $cid = $attachment[7];
2591: if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2592: continue;
2593: }
2594: $cidUniq[$cid] = true;
2595:
2596: $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2597:
2598: if (!empty($name)) {
2599: $mime[] = sprintf(
2600: 'Content-Type: %s; name="%s"%s',
2601: $type,
2602: $this->encodeHeader($this->secureHeader($name)),
2603: $this->LE
2604: );
2605: } else {
2606: $mime[] = sprintf(
2607: 'Content-Type: %s%s',
2608: $type,
2609: $this->LE
2610: );
2611: }
2612:
2613: if ($encoding != '7bit') {
2614: $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2615: }
2616:
2617: if ($disposition == 'inline') {
2618: $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2619: }
2620:
2621:
2622:
2623:
2624:
2625: if (!(empty($disposition))) {
2626: $encoded_name = $this->encodeHeader($this->secureHeader($name));
2627: if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2628: $mime[] = sprintf(
2629: 'Content-Disposition: %s; filename="%s"%s',
2630: $disposition,
2631: $encoded_name,
2632: $this->LE . $this->LE
2633: );
2634: } else {
2635: if (!empty($encoded_name)) {
2636: $mime[] = sprintf(
2637: 'Content-Disposition: %s; filename=%s%s',
2638: $disposition,
2639: $encoded_name,
2640: $this->LE . $this->LE
2641: );
2642: } else {
2643: $mime[] = sprintf(
2644: 'Content-Disposition: %s%s',
2645: $disposition,
2646: $this->LE . $this->LE
2647: );
2648: }
2649: }
2650: } else {
2651: $mime[] = $this->LE;
2652: }
2653:
2654:
2655: if ($bString) {
2656: $mime[] = $this->encodeString($string, $encoding);
2657: if ($this->isError()) {
2658: return '';
2659: }
2660: $mime[] = $this->LE . $this->LE;
2661: } else {
2662: $mime[] = $this->encodeFile($path, $encoding);
2663: if ($this->isError()) {
2664: return '';
2665: }
2666: $mime[] = $this->LE . $this->LE;
2667: }
2668: }
2669: }
2670:
2671: $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2672:
2673: return implode('', $mime);
2674: }
2675:
2676: 2677: 2678: 2679: 2680: 2681: 2682: 2683: 2684:
2685: protected function encodeFile($path, $encoding = 'base64')
2686: {
2687: try {
2688: if (!is_readable($path)) {
2689: throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2690: }
2691: $magic_quotes = get_magic_quotes_runtime();
2692: if ($magic_quotes) {
2693: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2694: set_magic_quotes_runtime(false);
2695: } else {
2696:
2697:
2698:
2699: ini_set('magic_quotes_runtime', false);
2700: }
2701: }
2702: $file_buffer = file_get_contents($path);
2703: $file_buffer = $this->encodeString($file_buffer, $encoding);
2704: if ($magic_quotes) {
2705: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2706: set_magic_quotes_runtime($magic_quotes);
2707: } else {
2708: ini_set('magic_quotes_runtime', $magic_quotes);
2709: }
2710: }
2711: return $file_buffer;
2712: } catch (Exception $exc) {
2713: $this->setError($exc->getMessage());
2714: return '';
2715: }
2716: }
2717:
2718: 2719: 2720: 2721: 2722: 2723: 2724: 2725:
2726: public function encodeString($str, $encoding = 'base64')
2727: {
2728: $encoded = '';
2729: switch (strtolower($encoding)) {
2730: case 'base64':
2731: $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2732: break;
2733: case '7bit':
2734: case '8bit':
2735: $encoded = $this->fixEOL($str);
2736:
2737: if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2738: $encoded .= $this->LE;
2739: }
2740: break;
2741: case 'binary':
2742: $encoded = $str;
2743: break;
2744: case 'quoted-printable':
2745: $encoded = $this->encodeQP($str);
2746: break;
2747: default:
2748: $this->setError($this->lang('encoding') . $encoding);
2749: break;
2750: }
2751: return $encoded;
2752: }
2753:
2754: 2755: 2756: 2757: 2758: 2759: 2760: 2761:
2762: public function encodeHeader($str, $position = 'text')
2763: {
2764: $matchcount = 0;
2765: switch (strtolower($position)) {
2766: case 'phrase':
2767: if (!preg_match('/[\200-\377]/', $str)) {
2768:
2769: $encoded = addcslashes($str, "\0..\37\177\\\"");
2770: if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2771: return ($encoded);
2772: } else {
2773: return ("\"$encoded\"");
2774: }
2775: }
2776: $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2777: break;
2778:
2779: case 'comment':
2780: $matchcount = preg_match_all('/[()"]/', $str, $matches);
2781:
2782: case 'text':
2783: default:
2784: $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2785: break;
2786: }
2787:
2788:
2789: if ($matchcount == 0) {
2790: return ($str);
2791: }
2792:
2793: $maxlen = 75 - 7 - strlen($this->CharSet);
2794:
2795: if ($matchcount > strlen($str) / 3) {
2796:
2797: $encoding = 'B';
2798: if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2799:
2800:
2801: $encoded = $this->base64EncodeWrapMB($str, "\n");
2802: } else {
2803: $encoded = base64_encode($str);
2804: $maxlen -= $maxlen % 4;
2805: $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2806: }
2807: } else {
2808: $encoding = 'Q';
2809: $encoded = $this->encodeQ($str, $position);
2810: $encoded = $this->wrapText($encoded, $maxlen, true);
2811: $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2812: }
2813:
2814: $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2815: $encoded = trim(str_replace("\n", $this->LE, $encoded));
2816:
2817: return $encoded;
2818: }
2819:
2820: 2821: 2822: 2823: 2824: 2825:
2826: public function hasMultiBytes($str)
2827: {
2828: if (function_exists('mb_strlen')) {
2829: return (strlen($str) > mb_strlen($str, $this->CharSet));
2830: } else {
2831: return false;
2832: }
2833: }
2834:
2835: 2836: 2837: 2838: 2839:
2840: public function has8bitChars($text)
2841: {
2842: return (boolean)preg_match('/[\x80-\xFF]/', $text);
2843: }
2844:
2845: 2846: 2847: 2848: 2849: 2850: 2851: 2852: 2853: 2854:
2855: public function base64EncodeWrapMB($str, $linebreak = null)
2856: {
2857: $start = '=?' . $this->CharSet . '?B?';
2858: $end = '?=';
2859: $encoded = '';
2860: if ($linebreak === null) {
2861: $linebreak = $this->LE;
2862: }
2863:
2864: $mb_length = mb_strlen($str, $this->CharSet);
2865:
2866: $length = 75 - strlen($start) - strlen($end);
2867:
2868: $ratio = $mb_length / strlen($str);
2869:
2870: $avgLength = floor($length * $ratio * .75);
2871:
2872: for ($i = 0; $i < $mb_length; $i += $offset) {
2873: $lookBack = 0;
2874: do {
2875: $offset = $avgLength - $lookBack;
2876: $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2877: $chunk = base64_encode($chunk);
2878: $lookBack++;
2879: } while (strlen($chunk) > $length);
2880: $encoded .= $chunk . $linebreak;
2881: }
2882:
2883:
2884: $encoded = substr($encoded, 0, -strlen($linebreak));
2885: return $encoded;
2886: }
2887:
2888: 2889: 2890: 2891: 2892: 2893: 2894: 2895: 2896:
2897: public function encodeQP($string, $line_max = 76)
2898: {
2899:
2900: if (function_exists('quoted_printable_encode')) {
2901: return quoted_printable_encode($string);
2902: }
2903:
2904: $string = str_replace(
2905: array('%20', '%0D%0A.', '%0D%0A', '%'),
2906: array(' ', "\r\n=2E", "\r\n", '='),
2907: rawurlencode($string)
2908: );
2909: return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2910: }
2911:
2912: 2913: 2914: 2915: 2916: 2917: 2918: 2919: 2920: 2921:
2922: public function encodeQPphp(
2923: $string,
2924: $line_max = 76,
2925: $space_conv = false
2926: ) {
2927: return $this->encodeQP($string, $line_max);
2928: }
2929:
2930: 2931: 2932: 2933: 2934: 2935: 2936: 2937:
2938: public function encodeQ($str, $position = 'text')
2939: {
2940:
2941: $pattern = '';
2942: $encoded = str_replace(array("\r", "\n"), '', $str);
2943: switch (strtolower($position)) {
2944: case 'phrase':
2945:
2946: $pattern = '^A-Za-z0-9!*+\/ -';
2947: break;
2948:
2949: case 'comment':
2950:
2951: $pattern = '\(\)"';
2952:
2953:
2954: case 'text':
2955: default:
2956:
2957:
2958: $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2959: break;
2960: }
2961: $matches = array();
2962: if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2963:
2964:
2965: $eqkey = array_search('=', $matches[0]);
2966: if (false !== $eqkey) {
2967: unset($matches[0][$eqkey]);
2968: array_unshift($matches[0], '=');
2969: }
2970: foreach (array_unique($matches[0]) as $char) {
2971: $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2972: }
2973: }
2974:
2975: return str_replace(' ', '_', $encoded);
2976: }
2977:
2978: 2979: 2980: 2981: 2982: 2983: 2984: 2985: 2986: 2987: 2988:
2989: public function addStringAttachment(
2990: $string,
2991: $filename,
2992: $encoding = 'base64',
2993: $type = '',
2994: $disposition = 'attachment'
2995: ) {
2996:
2997: if ($type == '') {
2998: $type = self::filenameToType($filename);
2999: }
3000:
3001: $this->attachment[] = array(
3002: 0 => $string,
3003: 1 => $filename,
3004: 2 => basename($filename),
3005: 3 => $encoding,
3006: 4 => $type,
3007: 5 => true,
3008: 6 => $disposition,
3009: 7 => 0
3010: );
3011: }
3012:
3013: 3014: 3015: 3016: 3017: 3018: 3019: 3020: 3021: 3022: 3023: 3024: 3025: 3026: 3027: 3028:
3029: public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3030: {
3031: if (!@is_file($path)) {
3032: $this->setError($this->lang('file_access') . $path);
3033: return false;
3034: }
3035:
3036:
3037: if ($type == '') {
3038: $type = self::filenameToType($path);
3039: }
3040:
3041: $filename = basename($path);
3042: if ($name == '') {
3043: $name = $filename;
3044: }
3045:
3046:
3047: $this->attachment[] = array(
3048: 0 => $path,
3049: 1 => $filename,
3050: 2 => $name,
3051: 3 => $encoding,
3052: 4 => $type,
3053: 5 => false,
3054: 6 => $disposition,
3055: 7 => $cid
3056: );
3057: return true;
3058: }
3059:
3060: 3061: 3062: 3063: 3064: 3065: 3066: 3067: 3068: 3069: 3070: 3071: 3072: 3073:
3074: public function addStringEmbeddedImage(
3075: $string,
3076: $cid,
3077: $name = '',
3078: $encoding = 'base64',
3079: $type = '',
3080: $disposition = 'inline'
3081: ) {
3082:
3083: if ($type == '' and !empty($name)) {
3084: $type = self::filenameToType($name);
3085: }
3086:
3087:
3088: $this->attachment[] = array(
3089: 0 => $string,
3090: 1 => $name,
3091: 2 => $name,
3092: 3 => $encoding,
3093: 4 => $type,
3094: 5 => true,
3095: 6 => $disposition,
3096: 7 => $cid
3097: );
3098: return true;
3099: }
3100:
3101: 3102: 3103: 3104: 3105:
3106: public function inlineImageExists()
3107: {
3108: foreach ($this->attachment as $attachment) {
3109: if ($attachment[6] == 'inline') {
3110: return true;
3111: }
3112: }
3113: return false;
3114: }
3115:
3116: 3117: 3118: 3119:
3120: public function attachmentExists()
3121: {
3122: foreach ($this->attachment as $attachment) {
3123: if ($attachment[6] == 'attachment') {
3124: return true;
3125: }
3126: }
3127: return false;
3128: }
3129:
3130: 3131: 3132: 3133:
3134: public function alternativeExists()
3135: {
3136: return !empty($this->AltBody);
3137: }
3138:
3139: 3140: 3141: 3142: 3143: 3144:
3145: public function clearQueuedAddresses($kind)
3146: {
3147: $RecipientsQueue = $this->RecipientsQueue;
3148: foreach ($RecipientsQueue as $address => $params) {
3149: if ($params[0] == $kind) {
3150: unset($this->RecipientsQueue[$address]);
3151: }
3152: }
3153: }
3154:
3155: 3156: 3157: 3158:
3159: public function clearAddresses()
3160: {
3161: foreach ($this->to as $to) {
3162: unset($this->all_recipients[strtolower($to[0])]);
3163: }
3164: $this->to = array();
3165: $this->clearQueuedAddresses('to');
3166: }
3167:
3168: 3169: 3170: 3171:
3172: public function clearCCs()
3173: {
3174: foreach ($this->cc as $cc) {
3175: unset($this->all_recipients[strtolower($cc[0])]);
3176: }
3177: $this->cc = array();
3178: $this->clearQueuedAddresses('cc');
3179: }
3180:
3181: 3182: 3183: 3184:
3185: public function clearBCCs()
3186: {
3187: foreach ($this->bcc as $bcc) {
3188: unset($this->all_recipients[strtolower($bcc[0])]);
3189: }
3190: $this->bcc = array();
3191: $this->clearQueuedAddresses('bcc');
3192: }
3193:
3194: 3195: 3196: 3197:
3198: public function clearReplyTos()
3199: {
3200: $this->ReplyTo = array();
3201: $this->ReplyToQueue = array();
3202: }
3203:
3204: 3205: 3206: 3207:
3208: public function clearAllRecipients()
3209: {
3210: $this->to = array();
3211: $this->cc = array();
3212: $this->bcc = array();
3213: $this->all_recipients = array();
3214: $this->RecipientsQueue = array();
3215: }
3216:
3217: 3218: 3219: 3220:
3221: public function clearAttachments()
3222: {
3223: $this->attachment = array();
3224: }
3225:
3226: 3227: 3228: 3229:
3230: public function clearCustomHeaders()
3231: {
3232: $this->CustomHeader = array();
3233: }
3234:
3235: 3236: 3237: 3238: 3239: 3240:
3241: protected function setError($msg)
3242: {
3243: $this->error_count++;
3244: if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3245: $lasterror = $this->smtp->getError();
3246: if (!empty($lasterror['error'])) {
3247: $msg .= $this->lang('smtp_error') . $lasterror['error'];
3248: if (!empty($lasterror['detail'])) {
3249: $msg .= ' Detail: '. $lasterror['detail'];
3250: }
3251: if (!empty($lasterror['smtp_code'])) {
3252: $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3253: }
3254: if (!empty($lasterror['smtp_code_ex'])) {
3255: $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3256: }
3257: }
3258: }
3259: $this->ErrorInfo = $msg;
3260: }
3261:
3262: 3263: 3264: 3265: 3266: 3267:
3268: public static function rfcDate()
3269: {
3270:
3271:
3272: date_default_timezone_set(@date_default_timezone_get());
3273: return date('D, j M Y H:i:s O');
3274: }
3275:
3276: 3277: 3278: 3279: 3280: 3281:
3282: protected function serverHostname()
3283: {
3284: $result = 'localhost.localdomain';
3285: if (!empty($this->Hostname)) {
3286: $result = $this->Hostname;
3287: } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3288: $result = $_SERVER['SERVER_NAME'];
3289: } elseif (function_exists('gethostname') && gethostname() !== false) {
3290: $result = gethostname();
3291: } elseif (php_uname('n') !== false) {
3292: $result = php_uname('n');
3293: }
3294: return $result;
3295: }
3296:
3297: 3298: 3299: 3300: 3301: 3302:
3303: protected function lang($key)
3304: {
3305: if (count($this->language) < 1) {
3306: $this->setLanguage('en');
3307: }
3308:
3309: if (array_key_exists($key, $this->language)) {
3310: if ($key == 'smtp_connect_failed') {
3311:
3312:
3313:
3314: return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3315: }
3316: return $this->language[$key];
3317: } else {
3318:
3319: return $key;
3320: }
3321: }
3322:
3323: 3324: 3325: 3326: 3327:
3328: public function isError()
3329: {
3330: return ($this->error_count > 0);
3331: }
3332:
3333: 3334: 3335: 3336: 3337: 3338: 3339:
3340: public function fixEOL($str)
3341: {
3342:
3343: $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3344:
3345: if ($this->LE !== "\n") {
3346: $nstr = str_replace("\n", $this->LE, $nstr);
3347: }
3348: return $nstr;
3349: }
3350:
3351: 3352: 3353: 3354: 3355: 3356: 3357: 3358: 3359:
3360: public function addCustomHeader($name, $value = null)
3361: {
3362: if ($value === null) {
3363:
3364: $this->CustomHeader[] = explode(':', $name, 2);
3365: } else {
3366: $this->CustomHeader[] = array($name, $value);
3367: }
3368: }
3369:
3370: 3371: 3372: 3373:
3374: public function getCustomHeaders()
3375: {
3376: return $this->CustomHeader;
3377: }
3378:
3379: 3380: 3381: 3382: 3383: 3384: 3385: 3386: 3387: 3388: 3389: 3390: 3391: 3392:
3393: public function msgHTML($message, $basedir = '', $advanced = false)
3394: {
3395: preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3396: if (array_key_exists(2, $images)) {
3397: foreach ($images[2] as $imgindex => $url) {
3398:
3399: if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3400: $data = substr($url, strpos($url, ','));
3401: if ($match[2]) {
3402: $data = base64_decode($data);
3403: } else {
3404: $data = rawurldecode($data);
3405: }
3406: $cid = md5($url) . '@phpmailer.0';
3407: if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3408: $message = str_replace(
3409: $images[0][$imgindex],
3410: $images[1][$imgindex] . '="cid:' . $cid . '"',
3411: $message
3412: );
3413: }
3414: } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) {
3415:
3416:
3417: $filename = basename($url);
3418: $directory = dirname($url);
3419: if ($directory == '.') {
3420: $directory = '';
3421: }
3422: $cid = md5($url) . '@phpmailer.0';
3423: if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3424: $basedir .= '/';
3425: }
3426: if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3427: $directory .= '/';
3428: }
3429: if ($this->addEmbeddedImage(
3430: $basedir . $directory . $filename,
3431: $cid,
3432: $filename,
3433: 'base64',
3434: self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3435: )
3436: ) {
3437: $message = preg_replace(
3438: '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3439: $images[1][$imgindex] . '="cid:' . $cid . '"',
3440: $message
3441: );
3442: }
3443: }
3444: }
3445: }
3446: $this->isHTML(true);
3447:
3448: $this->Body = $this->normalizeBreaks($message);
3449: $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3450: if (!$this->alternativeExists()) {
3451: $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3452: self::CRLF . self::CRLF;
3453: }
3454: return $this->Body;
3455: }
3456:
3457: 3458: 3459: 3460: 3461: 3462: 3463: 3464: 3465: 3466: 3467: 3468: 3469: 3470: 3471: 3472: 3473: 3474: 3475: 3476:
3477: public function html2text($html, $advanced = false)
3478: {
3479: if (is_callable($advanced)) {
3480: return call_user_func($advanced, $html);
3481: }
3482: return html_entity_decode(
3483: trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3484: ENT_QUOTES,
3485: $this->CharSet
3486: );
3487: }
3488:
3489: 3490: 3491: 3492: 3493: 3494: 3495:
3496: public static function _mime_types($ext = '')
3497: {
3498: $mimes = array(
3499: 'xl' => 'application/excel',
3500: 'js' => 'application/javascript',
3501: 'hqx' => 'application/mac-binhex40',
3502: 'cpt' => 'application/mac-compactpro',
3503: 'bin' => 'application/macbinary',
3504: 'doc' => 'application/msword',
3505: 'word' => 'application/msword',
3506: 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3507: 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3508: 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3509: 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3510: 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3511: 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3512: 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3513: 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3514: 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
3515: 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3516: 'class' => 'application/octet-stream',
3517: 'dll' => 'application/octet-stream',
3518: 'dms' => 'application/octet-stream',
3519: 'exe' => 'application/octet-stream',
3520: 'lha' => 'application/octet-stream',
3521: 'lzh' => 'application/octet-stream',
3522: 'psd' => 'application/octet-stream',
3523: 'sea' => 'application/octet-stream',
3524: 'so' => 'application/octet-stream',
3525: 'oda' => 'application/oda',
3526: 'pdf' => 'application/pdf',
3527: 'ai' => 'application/postscript',
3528: 'eps' => 'application/postscript',
3529: 'ps' => 'application/postscript',
3530: 'smi' => 'application/smil',
3531: 'smil' => 'application/smil',
3532: 'mif' => 'application/vnd.mif',
3533: 'xls' => 'application/vnd.ms-excel',
3534: 'ppt' => 'application/vnd.ms-powerpoint',
3535: 'wbxml' => 'application/vnd.wap.wbxml',
3536: 'wmlc' => 'application/vnd.wap.wmlc',
3537: 'dcr' => 'application/x-director',
3538: 'dir' => 'application/x-director',
3539: 'dxr' => 'application/x-director',
3540: 'dvi' => 'application/x-dvi',
3541: 'gtar' => 'application/x-gtar',
3542: 'php3' => 'application/x-httpd-php',
3543: 'php4' => 'application/x-httpd-php',
3544: 'php' => 'application/x-httpd-php',
3545: 'phtml' => 'application/x-httpd-php',
3546: 'phps' => 'application/x-httpd-php-source',
3547: 'swf' => 'application/x-shockwave-flash',
3548: 'sit' => 'application/x-stuffit',
3549: 'tar' => 'application/x-tar',
3550: 'tgz' => 'application/x-tar',
3551: 'xht' => 'application/xhtml+xml',
3552: 'xhtml' => 'application/xhtml+xml',
3553: 'zip' => 'application/zip',
3554: 'mid' => 'audio/midi',
3555: 'midi' => 'audio/midi',
3556: 'mp2' => 'audio/mpeg',
3557: 'mp3' => 'audio/mpeg',
3558: 'mpga' => 'audio/mpeg',
3559: 'aif' => 'audio/x-aiff',
3560: 'aifc' => 'audio/x-aiff',
3561: 'aiff' => 'audio/x-aiff',
3562: 'ram' => 'audio/x-pn-realaudio',
3563: 'rm' => 'audio/x-pn-realaudio',
3564: 'rpm' => 'audio/x-pn-realaudio-plugin',
3565: 'ra' => 'audio/x-realaudio',
3566: 'wav' => 'audio/x-wav',
3567: 'bmp' => 'image/bmp',
3568: 'gif' => 'image/gif',
3569: 'jpeg' => 'image/jpeg',
3570: 'jpe' => 'image/jpeg',
3571: 'jpg' => 'image/jpeg',
3572: 'png' => 'image/png',
3573: 'tiff' => 'image/tiff',
3574: 'tif' => 'image/tiff',
3575: 'eml' => 'message/rfc822',
3576: 'css' => 'text/css',
3577: 'html' => 'text/html',
3578: 'htm' => 'text/html',
3579: 'shtml' => 'text/html',
3580: 'log' => 'text/plain',
3581: 'text' => 'text/plain',
3582: 'txt' => 'text/plain',
3583: 'rtx' => 'text/richtext',
3584: 'rtf' => 'text/rtf',
3585: 'vcf' => 'text/vcard',
3586: 'vcard' => 'text/vcard',
3587: 'xml' => 'text/xml',
3588: 'xsl' => 'text/xml',
3589: 'mpeg' => 'video/mpeg',
3590: 'mpe' => 'video/mpeg',
3591: 'mpg' => 'video/mpeg',
3592: 'mov' => 'video/quicktime',
3593: 'qt' => 'video/quicktime',
3594: 'rv' => 'video/vnd.rn-realvideo',
3595: 'avi' => 'video/x-msvideo',
3596: 'movie' => 'video/x-sgi-movie'
3597: );
3598: if (array_key_exists(strtolower($ext), $mimes)) {
3599: return $mimes[strtolower($ext)];
3600: }
3601: return 'application/octet-stream';
3602: }
3603:
3604: 3605: 3606: 3607: 3608: 3609: 3610:
3611: public static function filenameToType($filename)
3612: {
3613:
3614: $qpos = strpos($filename, '?');
3615: if (false !== $qpos) {
3616: $filename = substr($filename, 0, $qpos);
3617: }
3618: $pathinfo = self::mb_pathinfo($filename);
3619: return self::_mime_types($pathinfo['extension']);
3620: }
3621:
3622: 3623: 3624: 3625: 3626: 3627: 3628: 3629: 3630: 3631: 3632:
3633: public static function mb_pathinfo($path, $options = null)
3634: {
3635: $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3636: $pathinfo = array();
3637: if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3638: if (array_key_exists(1, $pathinfo)) {
3639: $ret['dirname'] = $pathinfo[1];
3640: }
3641: if (array_key_exists(2, $pathinfo)) {
3642: $ret['basename'] = $pathinfo[2];
3643: }
3644: if (array_key_exists(5, $pathinfo)) {
3645: $ret['extension'] = $pathinfo[5];
3646: }
3647: if (array_key_exists(3, $pathinfo)) {
3648: $ret['filename'] = $pathinfo[3];
3649: }
3650: }
3651: switch ($options) {
3652: case PATHINFO_DIRNAME:
3653: case 'dirname':
3654: return $ret['dirname'];
3655: case PATHINFO_BASENAME:
3656: case 'basename':
3657: return $ret['basename'];
3658: case PATHINFO_EXTENSION:
3659: case 'extension':
3660: return $ret['extension'];
3661: case PATHINFO_FILENAME:
3662: case 'filename':
3663: return $ret['filename'];
3664: default:
3665: return $ret;
3666: }
3667: }
3668:
3669: 3670: 3671: 3672: 3673: 3674: 3675: 3676: 3677: 3678: 3679: 3680: 3681: 3682:
3683: public function set($name, $value = '')
3684: {
3685: if (property_exists($this, $name)) {
3686: $this->$name = $value;
3687: return true;
3688: } else {
3689: $this->setError($this->lang('variable_set') . $name);
3690: return false;
3691: }
3692: }
3693:
3694: 3695: 3696: 3697: 3698: 3699:
3700: public function secureHeader($str)
3701: {
3702: return trim(str_replace(array("\r", "\n"), '', $str));
3703: }
3704:
3705: 3706: 3707: 3708: 3709: 3710: 3711: 3712: 3713: 3714:
3715: public static function normalizeBreaks($text, $breaktype = "\r\n")
3716: {
3717: return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3718: }
3719:
3720: 3721: 3722: 3723: 3724: 3725: 3726: 3727:
3728: public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3729: {
3730: $this->sign_cert_file = $cert_filename;
3731: $this->sign_key_file = $key_filename;
3732: $this->sign_key_pass = $key_pass;
3733: $this->sign_extracerts_file = $extracerts_filename;
3734: }
3735:
3736: 3737: 3738: 3739: 3740: 3741:
3742: public function DKIM_QP($txt)
3743: {
3744: $line = '';
3745: for ($i = 0; $i < strlen($txt); $i++) {
3746: $ord = ord($txt[$i]);
3747: if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3748: $line .= $txt[$i];
3749: } else {
3750: $line .= '=' . sprintf('%02X', $ord);
3751: }
3752: }
3753: return $line;
3754: }
3755:
3756: 3757: 3758: 3759: 3760: 3761: 3762:
3763: public function DKIM_Sign($signHeader)
3764: {
3765: if (!defined('PKCS7_TEXT')) {
3766: if ($this->exceptions) {
3767: throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3768: }
3769: return '';
3770: }
3771: $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3772: if ('' != $this->DKIM_passphrase) {
3773: $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3774: } else {
3775: $privKey = openssl_pkey_get_private($privKeyStr);
3776: }
3777:
3778:
3779: if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3780: in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3781: if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3782: openssl_pkey_free($privKey);
3783: return base64_encode($signature);
3784: }
3785: } else {
3786: $pinfo = openssl_pkey_get_details($privKey);
3787: $hash = hash('sha256', $signHeader);
3788:
3789:
3790: $t = '3031300d060960864801650304020105000420' . $hash;
3791: $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3792: $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3793:
3794: if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3795: openssl_pkey_free($privKey);
3796: return base64_encode($signature);
3797: }
3798: }
3799: openssl_pkey_free($privKey);
3800: return '';
3801: }
3802:
3803: 3804: 3805: 3806: 3807: 3808:
3809: public function DKIM_HeaderC($signHeader)
3810: {
3811: $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3812: $lines = explode("\r\n", $signHeader);
3813: foreach ($lines as $key => $line) {
3814: list($heading, $value) = explode(':', $line, 2);
3815: $heading = strtolower($heading);
3816: $value = preg_replace('/\s{2,}/', ' ', $value);
3817: $lines[$key] = $heading . ':' . trim($value);
3818: }
3819: $signHeader = implode("\r\n", $lines);
3820: return $signHeader;
3821: }
3822:
3823: 3824: 3825: 3826: 3827: 3828:
3829: public function DKIM_BodyC($body)
3830: {
3831: if ($body == '') {
3832: return "\r\n";
3833: }
3834:
3835: $body = str_replace("\r\n", "\n", $body);
3836: $body = str_replace("\n", "\r\n", $body);
3837:
3838: while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3839: $body = substr($body, 0, strlen($body) - 2);
3840: }
3841: return $body;
3842: }
3843:
3844: 3845: 3846: 3847: 3848: 3849: 3850: 3851:
3852: public function DKIM_Add($headers_line, $subject, $body)
3853: {
3854: $DKIMsignatureType = 'rsa-sha256';
3855: $DKIMcanonicalization = 'relaxed/simple';
3856: $DKIMquery = 'dns/txt';
3857: $DKIMtime = time();
3858: $subject_header = "Subject: $subject";
3859: $headers = explode($this->LE, $headers_line);
3860: $from_header = '';
3861: $to_header = '';
3862: $date_header = '';
3863: $current = '';
3864: foreach ($headers as $header) {
3865: if (strpos($header, 'From:') === 0) {
3866: $from_header = $header;
3867: $current = 'from_header';
3868: } elseif (strpos($header, 'To:') === 0) {
3869: $to_header = $header;
3870: $current = 'to_header';
3871: } elseif (strpos($header, 'Date:') === 0) {
3872: $date_header = $header;
3873: $current = 'date_header';
3874: } else {
3875: if (!empty($$current) && strpos($header, ' =?') === 0) {
3876: $$current .= $header;
3877: } else {
3878: $current = '';
3879: }
3880: }
3881: }
3882: $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3883: $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3884: $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3885: $subject = str_replace(
3886: '|',
3887: '=7C',
3888: $this->DKIM_QP($subject_header)
3889: );
3890: $body = $this->DKIM_BodyC($body);
3891: $DKIMlen = strlen($body);
3892: $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
3893: if ('' == $this->DKIM_identity) {
3894: $ident = '';
3895: } else {
3896: $ident = ' i=' . $this->DKIM_identity . ';';
3897: }
3898: $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3899: $DKIMsignatureType . '; q=' .
3900: $DKIMquery . '; l=' .
3901: $DKIMlen . '; s=' .
3902: $this->DKIM_selector .
3903: ";\r\n" .
3904: "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3905: "\th=From:To:Date:Subject;\r\n" .
3906: "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3907: "\tz=$from\r\n" .
3908: "\t|$to\r\n" .
3909: "\t|$date\r\n" .
3910: "\t|$subject;\r\n" .
3911: "\tbh=" . $DKIMb64 . ";\r\n" .
3912: "\tb=";
3913: $toSign = $this->DKIM_HeaderC(
3914: $from_header . "\r\n" .
3915: $to_header . "\r\n" .
3916: $date_header . "\r\n" .
3917: $subject_header . "\r\n" .
3918: $dkimhdrs
3919: );
3920: $signed = $this->DKIM_Sign($toSign);
3921: return $dkimhdrs . $signed . "\r\n";
3922: }
3923:
3924: 3925: 3926: 3927: 3928: 3929:
3930: public static function hasLineLongerThanMax($str)
3931: {
3932:
3933: return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3934: }
3935:
3936: 3937: 3938: 3939: 3940: 3941:
3942: public function getToAddresses()
3943: {
3944: return $this->to;
3945: }
3946:
3947: 3948: 3949: 3950: 3951: 3952:
3953: public function getCcAddresses()
3954: {
3955: return $this->cc;
3956: }
3957:
3958: 3959: 3960: 3961: 3962: 3963:
3964: public function getBccAddresses()
3965: {
3966: return $this->bcc;
3967: }
3968:
3969: 3970: 3971: 3972: 3973: 3974:
3975: public function getReplyToAddresses()
3976: {
3977: return $this->ReplyTo;
3978: }
3979:
3980: 3981: 3982: 3983: 3984: 3985:
3986: public function getAllRecipientAddresses()
3987: {
3988: return $this->all_recipients;
3989: }
3990:
3991: 3992: 3993: 3994: 3995: 3996: 3997: 3998: 3999: 4000:
4001: protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4002: {
4003: if (!empty($this->action_function) && is_callable($this->action_function)) {
4004: $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4005: call_user_func_array($this->action_function, $params);
4006: }
4007: }
4008: }
4009:
4010: 4011: 4012: 4013:
4014: class phpmailerException extends Exception
4015: {
4016: 4017: 4018: 4019:
4020: public function errorMessage()
4021: {
4022: $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
4023: return $errorMsg;
4024: }
4025: }
4026: