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