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.22';
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:
2505: public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
2506: {
2507: try {
2508: if (!@is_file($path)) {
2509: throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
2510: }
2511:
2512:
2513: if ($type == '') {
2514: $type = self::filenameToType($path);
2515: }
2516:
2517: $filename = basename($path);
2518: if ($name == '') {
2519: $name = $filename;
2520: }
2521:
2522: $this->attachment[] = array(
2523: 0 => $path,
2524: 1 => $filename,
2525: 2 => $name,
2526: 3 => $encoding,
2527: 4 => $type,
2528: 5 => false,
2529: 6 => $disposition,
2530: 7 => 0
2531: );
2532:
2533: } catch (phpmailerException $exc) {
2534: $this->setError($exc->getMessage());
2535: $this->edebug($exc->getMessage());
2536: if ($this->exceptions) {
2537: throw $exc;
2538: }
2539: return false;
2540: }
2541: return true;
2542: }
2543:
2544: 2545: 2546: 2547:
2548: public function getAttachments()
2549: {
2550: return $this->attachment;
2551: }
2552:
2553: 2554: 2555: 2556: 2557: 2558: 2559: 2560:
2561: protected function attachAll($disposition_type, $boundary)
2562: {
2563:
2564: $mime = array();
2565: $cidUniq = array();
2566: $incl = array();
2567:
2568:
2569: foreach ($this->attachment as $attachment) {
2570:
2571: if ($attachment[6] == $disposition_type) {
2572:
2573: $string = '';
2574: $path = '';
2575: $bString = $attachment[5];
2576: if ($bString) {
2577: $string = $attachment[0];
2578: } else {
2579: $path = $attachment[0];
2580: }
2581:
2582: $inclhash = md5(serialize($attachment));
2583: if (in_array($inclhash, $incl)) {
2584: continue;
2585: }
2586: $incl[] = $inclhash;
2587: $name = $attachment[2];
2588: $encoding = $attachment[3];
2589: $type = $attachment[4];
2590: $disposition = $attachment[6];
2591: $cid = $attachment[7];
2592: if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
2593: continue;
2594: }
2595: $cidUniq[$cid] = true;
2596:
2597: $mime[] = sprintf('--%s%s', $boundary, $this->LE);
2598:
2599: if (!empty($name)) {
2600: $mime[] = sprintf(
2601: 'Content-Type: %s; name="%s"%s',
2602: $type,
2603: $this->encodeHeader($this->secureHeader($name)),
2604: $this->LE
2605: );
2606: } else {
2607: $mime[] = sprintf(
2608: 'Content-Type: %s%s',
2609: $type,
2610: $this->LE
2611: );
2612: }
2613:
2614: if ($encoding != '7bit') {
2615: $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
2616: }
2617:
2618: if ($disposition == 'inline') {
2619: $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
2620: }
2621:
2622:
2623:
2624:
2625:
2626: if (!(empty($disposition))) {
2627: $encoded_name = $this->encodeHeader($this->secureHeader($name));
2628: if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
2629: $mime[] = sprintf(
2630: 'Content-Disposition: %s; filename="%s"%s',
2631: $disposition,
2632: $encoded_name,
2633: $this->LE . $this->LE
2634: );
2635: } else {
2636: if (!empty($encoded_name)) {
2637: $mime[] = sprintf(
2638: 'Content-Disposition: %s; filename=%s%s',
2639: $disposition,
2640: $encoded_name,
2641: $this->LE . $this->LE
2642: );
2643: } else {
2644: $mime[] = sprintf(
2645: 'Content-Disposition: %s%s',
2646: $disposition,
2647: $this->LE . $this->LE
2648: );
2649: }
2650: }
2651: } else {
2652: $mime[] = $this->LE;
2653: }
2654:
2655:
2656: if ($bString) {
2657: $mime[] = $this->encodeString($string, $encoding);
2658: if ($this->isError()) {
2659: return '';
2660: }
2661: $mime[] = $this->LE . $this->LE;
2662: } else {
2663: $mime[] = $this->encodeFile($path, $encoding);
2664: if ($this->isError()) {
2665: return '';
2666: }
2667: $mime[] = $this->LE . $this->LE;
2668: }
2669: }
2670: }
2671:
2672: $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
2673:
2674: return implode('', $mime);
2675: }
2676:
2677: 2678: 2679: 2680: 2681: 2682: 2683: 2684: 2685:
2686: protected function encodeFile($path, $encoding = 'base64')
2687: {
2688: try {
2689: if (!is_readable($path)) {
2690: throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
2691: }
2692: $magic_quotes = get_magic_quotes_runtime();
2693: if ($magic_quotes) {
2694: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2695: set_magic_quotes_runtime(false);
2696: } else {
2697:
2698:
2699:
2700: ini_set('magic_quotes_runtime', false);
2701: }
2702: }
2703: $file_buffer = file_get_contents($path);
2704: $file_buffer = $this->encodeString($file_buffer, $encoding);
2705: if ($magic_quotes) {
2706: if (version_compare(PHP_VERSION, '5.3.0', '<')) {
2707: set_magic_quotes_runtime($magic_quotes);
2708: } else {
2709: ini_set('magic_quotes_runtime', $magic_quotes);
2710: }
2711: }
2712: return $file_buffer;
2713: } catch (Exception $exc) {
2714: $this->setError($exc->getMessage());
2715: return '';
2716: }
2717: }
2718:
2719: 2720: 2721: 2722: 2723: 2724: 2725: 2726:
2727: public function encodeString($str, $encoding = 'base64')
2728: {
2729: $encoded = '';
2730: switch (strtolower($encoding)) {
2731: case 'base64':
2732: $encoded = chunk_split(base64_encode($str), 76, $this->LE);
2733: break;
2734: case '7bit':
2735: case '8bit':
2736: $encoded = $this->fixEOL($str);
2737:
2738: if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
2739: $encoded .= $this->LE;
2740: }
2741: break;
2742: case 'binary':
2743: $encoded = $str;
2744: break;
2745: case 'quoted-printable':
2746: $encoded = $this->encodeQP($str);
2747: break;
2748: default:
2749: $this->setError($this->lang('encoding') . $encoding);
2750: break;
2751: }
2752: return $encoded;
2753: }
2754:
2755: 2756: 2757: 2758: 2759: 2760: 2761: 2762:
2763: public function encodeHeader($str, $position = 'text')
2764: {
2765: $matchcount = 0;
2766: switch (strtolower($position)) {
2767: case 'phrase':
2768: if (!preg_match('/[\200-\377]/', $str)) {
2769:
2770: $encoded = addcslashes($str, "\0..\37\177\\\"");
2771: if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
2772: return ($encoded);
2773: } else {
2774: return ("\"$encoded\"");
2775: }
2776: }
2777: $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
2778: break;
2779:
2780: case 'comment':
2781: $matchcount = preg_match_all('/[()"]/', $str, $matches);
2782:
2783: case 'text':
2784: default:
2785: $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
2786: break;
2787: }
2788:
2789:
2790: if ($matchcount == 0) {
2791: return ($str);
2792: }
2793:
2794: $maxlen = 75 - 7 - strlen($this->CharSet);
2795:
2796: if ($matchcount > strlen($str) / 3) {
2797:
2798: $encoding = 'B';
2799: if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
2800:
2801:
2802: $encoded = $this->base64EncodeWrapMB($str, "\n");
2803: } else {
2804: $encoded = base64_encode($str);
2805: $maxlen -= $maxlen % 4;
2806: $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
2807: }
2808: } else {
2809: $encoding = 'Q';
2810: $encoded = $this->encodeQ($str, $position);
2811: $encoded = $this->wrapText($encoded, $maxlen, true);
2812: $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
2813: }
2814:
2815: $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
2816: $encoded = trim(str_replace("\n", $this->LE, $encoded));
2817:
2818: return $encoded;
2819: }
2820:
2821: 2822: 2823: 2824: 2825: 2826:
2827: public function hasMultiBytes($str)
2828: {
2829: if (function_exists('mb_strlen')) {
2830: return (strlen($str) > mb_strlen($str, $this->CharSet));
2831: } else {
2832: return false;
2833: }
2834: }
2835:
2836: 2837: 2838: 2839: 2840:
2841: public function has8bitChars($text)
2842: {
2843: return (boolean)preg_match('/[\x80-\xFF]/', $text);
2844: }
2845:
2846: 2847: 2848: 2849: 2850: 2851: 2852: 2853: 2854: 2855:
2856: public function base64EncodeWrapMB($str, $linebreak = null)
2857: {
2858: $start = '=?' . $this->CharSet . '?B?';
2859: $end = '?=';
2860: $encoded = '';
2861: if ($linebreak === null) {
2862: $linebreak = $this->LE;
2863: }
2864:
2865: $mb_length = mb_strlen($str, $this->CharSet);
2866:
2867: $length = 75 - strlen($start) - strlen($end);
2868:
2869: $ratio = $mb_length / strlen($str);
2870:
2871: $avgLength = floor($length * $ratio * .75);
2872:
2873: for ($i = 0; $i < $mb_length; $i += $offset) {
2874: $lookBack = 0;
2875: do {
2876: $offset = $avgLength - $lookBack;
2877: $chunk = mb_substr($str, $i, $offset, $this->CharSet);
2878: $chunk = base64_encode($chunk);
2879: $lookBack++;
2880: } while (strlen($chunk) > $length);
2881: $encoded .= $chunk . $linebreak;
2882: }
2883:
2884:
2885: $encoded = substr($encoded, 0, -strlen($linebreak));
2886: return $encoded;
2887: }
2888:
2889: 2890: 2891: 2892: 2893: 2894: 2895: 2896: 2897:
2898: public function encodeQP($string, $line_max = 76)
2899: {
2900:
2901: if (function_exists('quoted_printable_encode')) {
2902: return quoted_printable_encode($string);
2903: }
2904:
2905: $string = str_replace(
2906: array('%20', '%0D%0A.', '%0D%0A', '%'),
2907: array(' ', "\r\n=2E", "\r\n", '='),
2908: rawurlencode($string)
2909: );
2910: return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
2911: }
2912:
2913: 2914: 2915: 2916: 2917: 2918: 2919: 2920: 2921: 2922:
2923: public function encodeQPphp(
2924: $string,
2925: $line_max = 76,
2926: $space_conv = false
2927: ) {
2928: return $this->encodeQP($string, $line_max);
2929: }
2930:
2931: 2932: 2933: 2934: 2935: 2936: 2937: 2938:
2939: public function encodeQ($str, $position = 'text')
2940: {
2941:
2942: $pattern = '';
2943: $encoded = str_replace(array("\r", "\n"), '', $str);
2944: switch (strtolower($position)) {
2945: case 'phrase':
2946:
2947: $pattern = '^A-Za-z0-9!*+\/ -';
2948: break;
2949:
2950: case 'comment':
2951:
2952: $pattern = '\(\)"';
2953:
2954:
2955: case 'text':
2956: default:
2957:
2958:
2959: $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
2960: break;
2961: }
2962: $matches = array();
2963: if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
2964:
2965:
2966: $eqkey = array_search('=', $matches[0]);
2967: if (false !== $eqkey) {
2968: unset($matches[0][$eqkey]);
2969: array_unshift($matches[0], '=');
2970: }
2971: foreach (array_unique($matches[0]) as $char) {
2972: $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
2973: }
2974: }
2975:
2976: return str_replace(' ', '_', $encoded);
2977: }
2978:
2979: 2980: 2981: 2982: 2983: 2984: 2985: 2986: 2987: 2988: 2989:
2990: public function addStringAttachment(
2991: $string,
2992: $filename,
2993: $encoding = 'base64',
2994: $type = '',
2995: $disposition = 'attachment'
2996: ) {
2997:
2998: if ($type == '') {
2999: $type = self::filenameToType($filename);
3000: }
3001:
3002: $this->attachment[] = array(
3003: 0 => $string,
3004: 1 => $filename,
3005: 2 => basename($filename),
3006: 3 => $encoding,
3007: 4 => $type,
3008: 5 => true,
3009: 6 => $disposition,
3010: 7 => 0
3011: );
3012: }
3013:
3014: 3015: 3016: 3017: 3018: 3019: 3020: 3021: 3022: 3023: 3024: 3025: 3026: 3027: 3028: 3029: 3030:
3031: public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
3032: {
3033: if (!@is_file($path)) {
3034: $this->setError($this->lang('file_access') . $path);
3035: return false;
3036: }
3037:
3038:
3039: if ($type == '') {
3040: $type = self::filenameToType($path);
3041: }
3042:
3043: $filename = basename($path);
3044: if ($name == '') {
3045: $name = $filename;
3046: }
3047:
3048:
3049: $this->attachment[] = array(
3050: 0 => $path,
3051: 1 => $filename,
3052: 2 => $name,
3053: 3 => $encoding,
3054: 4 => $type,
3055: 5 => false,
3056: 6 => $disposition,
3057: 7 => $cid
3058: );
3059: return true;
3060: }
3061:
3062: 3063: 3064: 3065: 3066: 3067: 3068: 3069: 3070: 3071: 3072: 3073: 3074: 3075:
3076: public function addStringEmbeddedImage(
3077: $string,
3078: $cid,
3079: $name = '',
3080: $encoding = 'base64',
3081: $type = '',
3082: $disposition = 'inline'
3083: ) {
3084:
3085: if ($type == '' and !empty($name)) {
3086: $type = self::filenameToType($name);
3087: }
3088:
3089:
3090: $this->attachment[] = array(
3091: 0 => $string,
3092: 1 => $name,
3093: 2 => $name,
3094: 3 => $encoding,
3095: 4 => $type,
3096: 5 => true,
3097: 6 => $disposition,
3098: 7 => $cid
3099: );
3100: return true;
3101: }
3102:
3103: 3104: 3105: 3106: 3107:
3108: public function inlineImageExists()
3109: {
3110: foreach ($this->attachment as $attachment) {
3111: if ($attachment[6] == 'inline') {
3112: return true;
3113: }
3114: }
3115: return false;
3116: }
3117:
3118: 3119: 3120: 3121:
3122: public function attachmentExists()
3123: {
3124: foreach ($this->attachment as $attachment) {
3125: if ($attachment[6] == 'attachment') {
3126: return true;
3127: }
3128: }
3129: return false;
3130: }
3131:
3132: 3133: 3134: 3135:
3136: public function alternativeExists()
3137: {
3138: return !empty($this->AltBody);
3139: }
3140:
3141: 3142: 3143: 3144: 3145: 3146:
3147: public function clearQueuedAddresses($kind)
3148: {
3149: $RecipientsQueue = $this->RecipientsQueue;
3150: foreach ($RecipientsQueue as $address => $params) {
3151: if ($params[0] == $kind) {
3152: unset($this->RecipientsQueue[$address]);
3153: }
3154: }
3155: }
3156:
3157: 3158: 3159: 3160:
3161: public function clearAddresses()
3162: {
3163: foreach ($this->to as $to) {
3164: unset($this->all_recipients[strtolower($to[0])]);
3165: }
3166: $this->to = array();
3167: $this->clearQueuedAddresses('to');
3168: }
3169:
3170: 3171: 3172: 3173:
3174: public function clearCCs()
3175: {
3176: foreach ($this->cc as $cc) {
3177: unset($this->all_recipients[strtolower($cc[0])]);
3178: }
3179: $this->cc = array();
3180: $this->clearQueuedAddresses('cc');
3181: }
3182:
3183: 3184: 3185: 3186:
3187: public function clearBCCs()
3188: {
3189: foreach ($this->bcc as $bcc) {
3190: unset($this->all_recipients[strtolower($bcc[0])]);
3191: }
3192: $this->bcc = array();
3193: $this->clearQueuedAddresses('bcc');
3194: }
3195:
3196: 3197: 3198: 3199:
3200: public function clearReplyTos()
3201: {
3202: $this->ReplyTo = array();
3203: $this->ReplyToQueue = array();
3204: }
3205:
3206: 3207: 3208: 3209:
3210: public function clearAllRecipients()
3211: {
3212: $this->to = array();
3213: $this->cc = array();
3214: $this->bcc = array();
3215: $this->all_recipients = array();
3216: $this->RecipientsQueue = array();
3217: }
3218:
3219: 3220: 3221: 3222:
3223: public function clearAttachments()
3224: {
3225: $this->attachment = array();
3226: }
3227:
3228: 3229: 3230: 3231:
3232: public function clearCustomHeaders()
3233: {
3234: $this->CustomHeader = array();
3235: }
3236:
3237: 3238: 3239: 3240: 3241: 3242:
3243: protected function setError($msg)
3244: {
3245: $this->error_count++;
3246: if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
3247: $lasterror = $this->smtp->getError();
3248: if (!empty($lasterror['error'])) {
3249: $msg .= $this->lang('smtp_error') . $lasterror['error'];
3250: if (!empty($lasterror['detail'])) {
3251: $msg .= ' Detail: '. $lasterror['detail'];
3252: }
3253: if (!empty($lasterror['smtp_code'])) {
3254: $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
3255: }
3256: if (!empty($lasterror['smtp_code_ex'])) {
3257: $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
3258: }
3259: }
3260: }
3261: $this->ErrorInfo = $msg;
3262: }
3263:
3264: 3265: 3266: 3267: 3268: 3269:
3270: public static function rfcDate()
3271: {
3272:
3273:
3274: date_default_timezone_set(@date_default_timezone_get());
3275: return date('D, j M Y H:i:s O');
3276: }
3277:
3278: 3279: 3280: 3281: 3282: 3283:
3284: protected function serverHostname()
3285: {
3286: $result = 'localhost.localdomain';
3287: if (!empty($this->Hostname)) {
3288: $result = $this->Hostname;
3289: } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
3290: $result = $_SERVER['SERVER_NAME'];
3291: } elseif (function_exists('gethostname') && gethostname() !== false) {
3292: $result = gethostname();
3293: } elseif (php_uname('n') !== false) {
3294: $result = php_uname('n');
3295: }
3296: return $result;
3297: }
3298:
3299: 3300: 3301: 3302: 3303: 3304:
3305: protected function lang($key)
3306: {
3307: if (count($this->language) < 1) {
3308: $this->setLanguage('en');
3309: }
3310:
3311: if (array_key_exists($key, $this->language)) {
3312: if ($key == 'smtp_connect_failed') {
3313:
3314:
3315:
3316: return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
3317: }
3318: return $this->language[$key];
3319: } else {
3320:
3321: return $key;
3322: }
3323: }
3324:
3325: 3326: 3327: 3328: 3329:
3330: public function isError()
3331: {
3332: return ($this->error_count > 0);
3333: }
3334:
3335: 3336: 3337: 3338: 3339: 3340: 3341:
3342: public function fixEOL($str)
3343: {
3344:
3345: $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
3346:
3347: if ($this->LE !== "\n") {
3348: $nstr = str_replace("\n", $this->LE, $nstr);
3349: }
3350: return $nstr;
3351: }
3352:
3353: 3354: 3355: 3356: 3357: 3358: 3359: 3360: 3361:
3362: public function addCustomHeader($name, $value = null)
3363: {
3364: if ($value === null) {
3365:
3366: $this->CustomHeader[] = explode(':', $name, 2);
3367: } else {
3368: $this->CustomHeader[] = array($name, $value);
3369: }
3370: }
3371:
3372: 3373: 3374: 3375:
3376: public function getCustomHeaders()
3377: {
3378: return $this->CustomHeader;
3379: }
3380:
3381: 3382: 3383: 3384: 3385: 3386: 3387: 3388: 3389: 3390: 3391: 3392: 3393: 3394: 3395: 3396:
3397: public function msgHTML($message, $basedir = '', $advanced = false)
3398: {
3399: preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
3400: if (array_key_exists(2, $images)) {
3401: if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
3402:
3403: $basedir .= '/';
3404: }
3405: foreach ($images[2] as $imgindex => $url) {
3406:
3407: if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
3408: $data = substr($url, strpos($url, ','));
3409: if ($match[2]) {
3410: $data = base64_decode($data);
3411: } else {
3412: $data = rawurldecode($data);
3413: }
3414: $cid = md5($url) . '@phpmailer.0';
3415: if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
3416: $message = str_replace(
3417: $images[0][$imgindex],
3418: $images[1][$imgindex] . '="cid:' . $cid . '"',
3419: $message
3420: );
3421: }
3422: continue;
3423: }
3424: if (
3425:
3426: !empty($basedir)
3427:
3428: && (strpos($url, '..') === false)
3429:
3430: && substr($url, 0, 4) !== 'cid:'
3431:
3432: && !preg_match('#^[a-z][a-z0-9+.-]*:?//#i', $url)
3433: ) {
3434: $filename = basename($url);
3435: $directory = dirname($url);
3436: if ($directory == '.') {
3437: $directory = '';
3438: }
3439: $cid = md5($url) . '@phpmailer.0';
3440: if (strlen($directory) > 1 && substr($directory, -1) != '/') {
3441: $directory .= '/';
3442: }
3443: if ($this->addEmbeddedImage(
3444: $basedir . $directory . $filename,
3445: $cid,
3446: $filename,
3447: 'base64',
3448: self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
3449: )
3450: ) {
3451: $message = preg_replace(
3452: '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
3453: $images[1][$imgindex] . '="cid:' . $cid . '"',
3454: $message
3455: );
3456: }
3457: }
3458: }
3459: }
3460: $this->isHTML(true);
3461:
3462: $this->Body = $this->normalizeBreaks($message);
3463: $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
3464: if (!$this->alternativeExists()) {
3465: $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
3466: self::CRLF . self::CRLF;
3467: }
3468: return $this->Body;
3469: }
3470:
3471: 3472: 3473: 3474: 3475: 3476: 3477: 3478: 3479: 3480: 3481: 3482: 3483: 3484: 3485: 3486: 3487: 3488: 3489: 3490:
3491: public function html2text($html, $advanced = false)
3492: {
3493: if (is_callable($advanced)) {
3494: return call_user_func($advanced, $html);
3495: }
3496: return html_entity_decode(
3497: trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
3498: ENT_QUOTES,
3499: $this->CharSet
3500: );
3501: }
3502:
3503: 3504: 3505: 3506: 3507: 3508: 3509:
3510: public static function _mime_types($ext = '')
3511: {
3512: $mimes = array(
3513: 'xl' => 'application/excel',
3514: 'js' => 'application/javascript',
3515: 'hqx' => 'application/mac-binhex40',
3516: 'cpt' => 'application/mac-compactpro',
3517: 'bin' => 'application/macbinary',
3518: 'doc' => 'application/msword',
3519: 'word' => 'application/msword',
3520: 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
3521: 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
3522: 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
3523: 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
3524: 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
3525: 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
3526: 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
3527: 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
3528: 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
3529: 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
3530: 'class' => 'application/octet-stream',
3531: 'dll' => 'application/octet-stream',
3532: 'dms' => 'application/octet-stream',
3533: 'exe' => 'application/octet-stream',
3534: 'lha' => 'application/octet-stream',
3535: 'lzh' => 'application/octet-stream',
3536: 'psd' => 'application/octet-stream',
3537: 'sea' => 'application/octet-stream',
3538: 'so' => 'application/octet-stream',
3539: 'oda' => 'application/oda',
3540: 'pdf' => 'application/pdf',
3541: 'ai' => 'application/postscript',
3542: 'eps' => 'application/postscript',
3543: 'ps' => 'application/postscript',
3544: 'smi' => 'application/smil',
3545: 'smil' => 'application/smil',
3546: 'mif' => 'application/vnd.mif',
3547: 'xls' => 'application/vnd.ms-excel',
3548: 'ppt' => 'application/vnd.ms-powerpoint',
3549: 'wbxml' => 'application/vnd.wap.wbxml',
3550: 'wmlc' => 'application/vnd.wap.wmlc',
3551: 'dcr' => 'application/x-director',
3552: 'dir' => 'application/x-director',
3553: 'dxr' => 'application/x-director',
3554: 'dvi' => 'application/x-dvi',
3555: 'gtar' => 'application/x-gtar',
3556: 'php3' => 'application/x-httpd-php',
3557: 'php4' => 'application/x-httpd-php',
3558: 'php' => 'application/x-httpd-php',
3559: 'phtml' => 'application/x-httpd-php',
3560: 'phps' => 'application/x-httpd-php-source',
3561: 'swf' => 'application/x-shockwave-flash',
3562: 'sit' => 'application/x-stuffit',
3563: 'tar' => 'application/x-tar',
3564: 'tgz' => 'application/x-tar',
3565: 'xht' => 'application/xhtml+xml',
3566: 'xhtml' => 'application/xhtml+xml',
3567: 'zip' => 'application/zip',
3568: 'mid' => 'audio/midi',
3569: 'midi' => 'audio/midi',
3570: 'mp2' => 'audio/mpeg',
3571: 'mp3' => 'audio/mpeg',
3572: 'mpga' => 'audio/mpeg',
3573: 'aif' => 'audio/x-aiff',
3574: 'aifc' => 'audio/x-aiff',
3575: 'aiff' => 'audio/x-aiff',
3576: 'ram' => 'audio/x-pn-realaudio',
3577: 'rm' => 'audio/x-pn-realaudio',
3578: 'rpm' => 'audio/x-pn-realaudio-plugin',
3579: 'ra' => 'audio/x-realaudio',
3580: 'wav' => 'audio/x-wav',
3581: 'bmp' => 'image/bmp',
3582: 'gif' => 'image/gif',
3583: 'jpeg' => 'image/jpeg',
3584: 'jpe' => 'image/jpeg',
3585: 'jpg' => 'image/jpeg',
3586: 'png' => 'image/png',
3587: 'tiff' => 'image/tiff',
3588: 'tif' => 'image/tiff',
3589: 'eml' => 'message/rfc822',
3590: 'css' => 'text/css',
3591: 'html' => 'text/html',
3592: 'htm' => 'text/html',
3593: 'shtml' => 'text/html',
3594: 'log' => 'text/plain',
3595: 'text' => 'text/plain',
3596: 'txt' => 'text/plain',
3597: 'rtx' => 'text/richtext',
3598: 'rtf' => 'text/rtf',
3599: 'vcf' => 'text/vcard',
3600: 'vcard' => 'text/vcard',
3601: 'xml' => 'text/xml',
3602: 'xsl' => 'text/xml',
3603: 'mpeg' => 'video/mpeg',
3604: 'mpe' => 'video/mpeg',
3605: 'mpg' => 'video/mpeg',
3606: 'mov' => 'video/quicktime',
3607: 'qt' => 'video/quicktime',
3608: 'rv' => 'video/vnd.rn-realvideo',
3609: 'avi' => 'video/x-msvideo',
3610: 'movie' => 'video/x-sgi-movie'
3611: );
3612: if (array_key_exists(strtolower($ext), $mimes)) {
3613: return $mimes[strtolower($ext)];
3614: }
3615: return 'application/octet-stream';
3616: }
3617:
3618: 3619: 3620: 3621: 3622: 3623: 3624:
3625: public static function filenameToType($filename)
3626: {
3627:
3628: $qpos = strpos($filename, '?');
3629: if (false !== $qpos) {
3630: $filename = substr($filename, 0, $qpos);
3631: }
3632: $pathinfo = self::mb_pathinfo($filename);
3633: return self::_mime_types($pathinfo['extension']);
3634: }
3635:
3636: 3637: 3638: 3639: 3640: 3641: 3642: 3643: 3644: 3645: 3646:
3647: public static function mb_pathinfo($path, $options = null)
3648: {
3649: $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
3650: $pathinfo = array();
3651: if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
3652: if (array_key_exists(1, $pathinfo)) {
3653: $ret['dirname'] = $pathinfo[1];
3654: }
3655: if (array_key_exists(2, $pathinfo)) {
3656: $ret['basename'] = $pathinfo[2];
3657: }
3658: if (array_key_exists(5, $pathinfo)) {
3659: $ret['extension'] = $pathinfo[5];
3660: }
3661: if (array_key_exists(3, $pathinfo)) {
3662: $ret['filename'] = $pathinfo[3];
3663: }
3664: }
3665: switch ($options) {
3666: case PATHINFO_DIRNAME:
3667: case 'dirname':
3668: return $ret['dirname'];
3669: case PATHINFO_BASENAME:
3670: case 'basename':
3671: return $ret['basename'];
3672: case PATHINFO_EXTENSION:
3673: case 'extension':
3674: return $ret['extension'];
3675: case PATHINFO_FILENAME:
3676: case 'filename':
3677: return $ret['filename'];
3678: default:
3679: return $ret;
3680: }
3681: }
3682:
3683: 3684: 3685: 3686: 3687: 3688: 3689: 3690: 3691: 3692: 3693: 3694: 3695: 3696:
3697: public function set($name, $value = '')
3698: {
3699: if (property_exists($this, $name)) {
3700: $this->$name = $value;
3701: return true;
3702: } else {
3703: $this->setError($this->lang('variable_set') . $name);
3704: return false;
3705: }
3706: }
3707:
3708: 3709: 3710: 3711: 3712: 3713:
3714: public function secureHeader($str)
3715: {
3716: return trim(str_replace(array("\r", "\n"), '', $str));
3717: }
3718:
3719: 3720: 3721: 3722: 3723: 3724: 3725: 3726: 3727: 3728:
3729: public static function normalizeBreaks($text, $breaktype = "\r\n")
3730: {
3731: return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
3732: }
3733:
3734: 3735: 3736: 3737: 3738: 3739: 3740: 3741:
3742: public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
3743: {
3744: $this->sign_cert_file = $cert_filename;
3745: $this->sign_key_file = $key_filename;
3746: $this->sign_key_pass = $key_pass;
3747: $this->sign_extracerts_file = $extracerts_filename;
3748: }
3749:
3750: 3751: 3752: 3753: 3754: 3755:
3756: public function DKIM_QP($txt)
3757: {
3758: $line = '';
3759: for ($i = 0; $i < strlen($txt); $i++) {
3760: $ord = ord($txt[$i]);
3761: if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
3762: $line .= $txt[$i];
3763: } else {
3764: $line .= '=' . sprintf('%02X', $ord);
3765: }
3766: }
3767: return $line;
3768: }
3769:
3770: 3771: 3772: 3773: 3774: 3775: 3776:
3777: public function DKIM_Sign($signHeader)
3778: {
3779: if (!defined('PKCS7_TEXT')) {
3780: if ($this->exceptions) {
3781: throw new phpmailerException($this->lang('extension_missing') . 'openssl');
3782: }
3783: return '';
3784: }
3785: $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
3786: if ('' != $this->DKIM_passphrase) {
3787: $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
3788: } else {
3789: $privKey = openssl_pkey_get_private($privKeyStr);
3790: }
3791:
3792:
3793: if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
3794: in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
3795: if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
3796: openssl_pkey_free($privKey);
3797: return base64_encode($signature);
3798: }
3799: } else {
3800: $pinfo = openssl_pkey_get_details($privKey);
3801: $hash = hash('sha256', $signHeader);
3802:
3803:
3804: $t = '3031300d060960864801650304020105000420' . $hash;
3805: $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
3806: $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
3807:
3808: if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
3809: openssl_pkey_free($privKey);
3810: return base64_encode($signature);
3811: }
3812: }
3813: openssl_pkey_free($privKey);
3814: return '';
3815: }
3816:
3817: 3818: 3819: 3820: 3821: 3822:
3823: public function DKIM_HeaderC($signHeader)
3824: {
3825: $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
3826: $lines = explode("\r\n", $signHeader);
3827: foreach ($lines as $key => $line) {
3828: list($heading, $value) = explode(':', $line, 2);
3829: $heading = strtolower($heading);
3830: $value = preg_replace('/\s{2,}/', ' ', $value);
3831: $lines[$key] = $heading . ':' . trim($value);
3832: }
3833: $signHeader = implode("\r\n", $lines);
3834: return $signHeader;
3835: }
3836:
3837: 3838: 3839: 3840: 3841: 3842:
3843: public function DKIM_BodyC($body)
3844: {
3845: if ($body == '') {
3846: return "\r\n";
3847: }
3848:
3849: $body = str_replace("\r\n", "\n", $body);
3850: $body = str_replace("\n", "\r\n", $body);
3851:
3852: while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
3853: $body = substr($body, 0, strlen($body) - 2);
3854: }
3855: return $body;
3856: }
3857:
3858: 3859: 3860: 3861: 3862: 3863: 3864: 3865:
3866: public function DKIM_Add($headers_line, $subject, $body)
3867: {
3868: $DKIMsignatureType = 'rsa-sha256';
3869: $DKIMcanonicalization = 'relaxed/simple';
3870: $DKIMquery = 'dns/txt';
3871: $DKIMtime = time();
3872: $subject_header = "Subject: $subject";
3873: $headers = explode($this->LE, $headers_line);
3874: $from_header = '';
3875: $to_header = '';
3876: $date_header = '';
3877: $current = '';
3878: foreach ($headers as $header) {
3879: if (strpos($header, 'From:') === 0) {
3880: $from_header = $header;
3881: $current = 'from_header';
3882: } elseif (strpos($header, 'To:') === 0) {
3883: $to_header = $header;
3884: $current = 'to_header';
3885: } elseif (strpos($header, 'Date:') === 0) {
3886: $date_header = $header;
3887: $current = 'date_header';
3888: } else {
3889: if (!empty($$current) && strpos($header, ' =?') === 0) {
3890: $$current .= $header;
3891: } else {
3892: $current = '';
3893: }
3894: }
3895: }
3896: $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
3897: $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
3898: $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
3899: $subject = str_replace(
3900: '|',
3901: '=7C',
3902: $this->DKIM_QP($subject_header)
3903: );
3904: $body = $this->DKIM_BodyC($body);
3905: $DKIMlen = strlen($body);
3906: $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body)));
3907: if ('' == $this->DKIM_identity) {
3908: $ident = '';
3909: } else {
3910: $ident = ' i=' . $this->DKIM_identity . ';';
3911: }
3912: $dkimhdrs = 'DKIM-Signature: v=1; a=' .
3913: $DKIMsignatureType . '; q=' .
3914: $DKIMquery . '; l=' .
3915: $DKIMlen . '; s=' .
3916: $this->DKIM_selector .
3917: ";\r\n" .
3918: "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
3919: "\th=From:To:Date:Subject;\r\n" .
3920: "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
3921: "\tz=$from\r\n" .
3922: "\t|$to\r\n" .
3923: "\t|$date\r\n" .
3924: "\t|$subject;\r\n" .
3925: "\tbh=" . $DKIMb64 . ";\r\n" .
3926: "\tb=";
3927: $toSign = $this->DKIM_HeaderC(
3928: $from_header . "\r\n" .
3929: $to_header . "\r\n" .
3930: $date_header . "\r\n" .
3931: $subject_header . "\r\n" .
3932: $dkimhdrs
3933: );
3934: $signed = $this->DKIM_Sign($toSign);
3935: return $dkimhdrs . $signed . "\r\n";
3936: }
3937:
3938: 3939: 3940: 3941: 3942: 3943:
3944: public static function hasLineLongerThanMax($str)
3945: {
3946:
3947: return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
3948: }
3949:
3950: 3951: 3952: 3953: 3954: 3955:
3956: public function getToAddresses()
3957: {
3958: return $this->to;
3959: }
3960:
3961: 3962: 3963: 3964: 3965: 3966:
3967: public function getCcAddresses()
3968: {
3969: return $this->cc;
3970: }
3971:
3972: 3973: 3974: 3975: 3976: 3977:
3978: public function getBccAddresses()
3979: {
3980: return $this->bcc;
3981: }
3982:
3983: 3984: 3985: 3986: 3987: 3988:
3989: public function getReplyToAddresses()
3990: {
3991: return $this->ReplyTo;
3992: }
3993:
3994: 3995: 3996: 3997: 3998: 3999:
4000: public function getAllRecipientAddresses()
4001: {
4002: return $this->all_recipients;
4003: }
4004:
4005: 4006: 4007: 4008: 4009: 4010: 4011: 4012: 4013: 4014:
4015: protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
4016: {
4017: if (!empty($this->action_function) && is_callable($this->action_function)) {
4018: $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
4019: call_user_func_array($this->action_function, $params);
4020: }
4021: }
4022: }
4023:
4024: 4025: 4026: 4027:
4028: class phpmailerException extends Exception
4029: {
4030: 4031: 4032: 4033:
4034: public function errorMessage()
4035: {
4036: $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
4037: return $errorMsg;
4038: }
4039: }
4040: