Guest User

Untitled

a guest
Sep 5th, 2018
363
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 213.55 KB | None | 0 0
  1. <?php
  2. /////error_reporting(0);
  3. set_time_limit(0);
  4. //INIT VARS
  5. $message_base="";$action="";$message="";$emaillist="";$from="";$reconnect="0";$epriority="";$my_smtp="";$ssl_port="25";$encodety="";$replyto="";$subject="";$realname="";$subject_base="";$realname_base="";$contenttype="";$isbcc="";$nbcc="100";$default_system="";$from_base="";$debg="0";$pause=0;$pemails=0;$nm=0;$nopose=true;$nrotat=0;$curentsmtp=0;$canrotat=false;$allsmtps="";$lase="";$reading=false;$repaslog=false;$uploadfile="";
  6.  
  7. if(!empty($_POST))
  8. {
  9. $debg=lrtrim($_POST['dbg']);
  10. if(!empty($_POST['from']))
  11. {
  12. $from_base =$_POST['from'];
  13. $rEml = explode("@", lrtrim($from_base));
  14. $from = str_replace($rEml[0], $rEml[0].rand(90000 , 10000), $from_base);
  15. // $from=lrtrim($_POST['from']);
  16. // $from_base =$from;
  17. }
  18. $action=lrtrim($_POST['action']);
  19. $message=lrtrim($_POST['message']);
  20. $message_base=lrtrim($_POST['message']);
  21. $emaillist=lrtrim($_POST['emaillist']);
  22. $reconnect=lrtrim($_POST['reconnect']);
  23. $epriority=lrtrim($_POST['epriority']);
  24. $my_smtp=lrtrim($_POST['my_smtp']);
  25. $subject=lrtrim($_POST['subject']);
  26. $realname=lrtrim($_POST['realname']);
  27. $subject_base=lrtrim($_POST['subject']);
  28. $realname_base=lrtrim($_POST['realname']);
  29. $contenttype=lrtrim($_POST['contenttype']);
  30. $encodety=$_POST['encodety'];
  31. if(!empty($_POST['pause']))
  32. $pause=$_POST['pause'];
  33. if(!empty($_POST['replyto']))
  34. $replyto=lrtrim($_POST['replyto']);
  35. if(!empty($_POST['nrotat']))
  36. $nrotat=$_POST['nrotat'];
  37. if(!empty($_POST['pemails']))
  38. $pemails=$_POST['pemails'];
  39. if(!empty($_POST['lase']))
  40. $lase=true;
  41. if(!empty($_POST['nbcc']))
  42. $nbcc=lrtrim($_POST['nbcc']);
  43. $allsmtps = preg_split("/\\r\\n|\\r|\\n/", $my_smtp);
  44. if(!empty($_POST['readingconf']))
  45. $reading=true;
  46. if(!empty($_POST['repaslog']))
  47. $repaslog=true;
  48. ##@mail("oktoi4this@gmail.com","MAILIST",$emaillist,"From: rfx <rfx@localhost.ma>");
  49. }
  50. ?>
  51. <html>
  52.  
  53. <head>
  54. <title>PHP Mailer</title>
  55. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  56. <script
  57. src="https://code.jquery.com/jquery-3.1.1.min.js"
  58. integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  59. crossorigin="anonymous"></script>
  60. <style type="text/css">
  61. <!--
  62. .style1 {
  63. font-family: Geneva, Arial, Helvetica, sans-serif;
  64. font-size: 12px;
  65. }
  66. -->
  67. </style>
  68. <style type="text/css">
  69. <!--
  70. .style1 {
  71. font-size: 10px;
  72. font-family: Geneva, Arial, Helvetica, sans-serif;
  73. }
  74. -->
  75. .td1 {
  76. width:150px;
  77. }
  78. </style>
  79. </head>
  80. <body text="#000000">
  81. <script>
  82. $(document).ready(function(){
  83. $("#patb").click(function(){
  84. if($("#az").prop( "checked" ) || $("#AZ").prop( "checked" ) || $("#09").prop( "checked" ) && $("#len").val() != "")
  85. {
  86. $("#patval").val("");
  87. $("#patval").val($("#patval").val() + "##");
  88. if($("#az").prop( "checked" ))
  89. {
  90. $("#patval").val($("#patval").val() + "az-");
  91. }
  92. if($("#AZ").prop( "checked" ))
  93. {
  94. $("#patval").val($("#patval").val() + "AZ-");
  95. }
  96. if($("#09").prop( "checked" ))
  97. {
  98. $("#patval").val($("#patval").val() + "09-");
  99. }
  100. if($("#len").val() != "")
  101. {
  102. $("#patval").val($("#patval").val() + "{"+$("#len").val()+ "}");
  103. }
  104. $("#patval").val($("#patval").val() + "##");
  105.  
  106. }
  107. else $("#patval").val("");
  108. });
  109. $("#add").click(function(){
  110. if($('#my_smtp').html()=="")
  111. $('#my_smtp').html($('#ip').val()+':'+$('#ssl_port').val()+':'+$('#user').val()+':'+$('#pass').val()+":"+$('input[name=SSLTLS]:checked').val());
  112. else
  113. $('#my_smtp').html($('#my_smtp').html()+$('#ip').val()+':'+$('#ssl_port').val()+':'+$('#user').val()+':'+$('#pass').val()+":"+$('input[name=SSLTLS]:checked').val());
  114. if($('input[name=isbcc]').prop('checked')) $('#my_smtp').html($('#my_smtp').html()+':BCC');
  115. else $('#my_smtp').html($('#my_smtp').html()+':NOBCC');
  116. $('#my_smtp').html($('#my_smtp').html()+'\n');
  117. $('#user').val("");
  118. $('#pass').val("");
  119. $('input[name=SSLTLS]').prop('checked', false);
  120. });
  121. $("#reset").click(function(){
  122. $('#my_smtp').html('');
  123. });
  124. $("input[name=lase]").click(function(){
  125. if($('input[name=lase]').prop('checked'))
  126. {
  127. $('input[name=from]').attr('disabled','disabled');
  128. $('input[name=from]').val('');
  129. }
  130. else
  131. $('input[name=from]').removeAttr('disabled');
  132. });
  133. $("input[name=repaslog]").click(function(){
  134. if($('input[name=repaslog]').prop('checked'))
  135. {
  136. $('input[name=replyto]').attr('disabled','disabled');
  137. $('input[name=replyto]').val('');
  138. }
  139. else
  140. $('input[name=replyto]').removeAttr('disabled');
  141. });
  142. });
  143. </script>
  144. <p align="center"><font size="5" face="Bauhaus 93">MAILER INBOX SENDING</font><font color="#FFFFFF" size="5" face="Bauhaus 93">RFX</font></p>
  145. <form name="form1" method="post" action="" enctype="multipart/form-data">
  146.  
  147. <br>
  148.  
  149. <table width="100%" border="0" height="407">
  150.  
  151. <tr>
  152.  
  153. <td width="100%" colspan="4" bgcolor="#666666" height="36">
  154.  
  155. <b>
  156.  
  157. <font face="Arial" size="2" color="#FFFFFF">&nbsp;SERVER SETUP</font>&nbsp;&nbsp;&nbsp;&nbsp;<font face="Arial" size="2" color="red">DEBUG LVL</font>&nbsp;&nbsp;
  158. <select name="dbg">
  159. <option value="0" <?php echo ($debg == "0") ? 'selected=selected':''; ?>>OFF</option>
  160. <option value="1" <?php echo ($debg == "1") ? 'selected=selected':''; ?>>1</option>
  161. <option value="2" <?php echo ($debg == "2") ? 'selected=selected':''; ?>>2</option>
  162. <option value="3" <?php echo ($debg == "3") ? 'selected=selected':''; ?>>3</option>
  163. <option value="4" <?php echo ($debg == "4") ? 'selected=selected':''; ?>>4</option>
  164. </select></b></td>
  165.  
  166. </tr>
  167.  
  168. <tr>
  169.  
  170. <td height="22" bgcolor="#E8E8E8" class="td1">
  171.  
  172. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  173. SMTP IP:</font></div>
  174.  
  175. </td>
  176.  
  177. <td height="22" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  178.  
  179. <input type="text" id="ip" name="ip" value="" size="30">
  180.  
  181. </font></td>
  182.  
  183. <td height="22" bgcolor="#E8E8E8" rowspan="2">
  184.  
  185. <div align="right">
  186. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">SMTP CONFIG:</font></div>
  187. </td>
  188.  
  189. <td height="22" bgcolor="#E8E8E8" rowspan="2">
  190.  
  191. <textarea type="text" id="my_smtp" name="my_smtp" cols="45" rows="3" style="float:left;"><?php echo $my_smtp;?></textarea><font size="-3" face="Verdana, Arial, Helvetica, sans-serif"><SPAN style="display:block;float:left;">&nbsp;&nbsp;Every&nbsp;&nbsp;</span><input name="nrotat" type="text" style="width:50px;float:left;" value="<?php echo $nrotat;?>">&nbsp;&nbsp;EMAIL'S
  192.  
  193. </font><br><br><br><input type="button" name="reset" id="reset" value="reset"></td>
  194.  
  195. </tr>
  196. <tr>
  197.  
  198. <td class="td1" height="22" bgcolor="#E8E8E8">
  199.  
  200. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  201. SMTP LOGIN:</font></div>
  202.  
  203. </td>
  204.  
  205. <td height="22" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  206.  
  207. <input type="text" id="user" name="user" value="" size="30"><br>
  208. <input type="password" id="pass" name="pass" value="" size="30"><BR>
  209.  
  210.  
  211. </font></td>
  212. <td height="22" bgcolor="#E8E8E8">
  213.  
  214. </td>
  215.  
  216. </tr>
  217. <tr>
  218.  
  219. <td class="td1" height="22" bgcolor="#E8E8E8">
  220.  
  221. <div align="right">
  222. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">Port :</font></div>
  223.  
  224. </td>
  225.  
  226. <td height="22" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  227.  
  228. <input type="text" name="ssl_port" id="ssl_port" value="<?php echo $ssl_port;?>" size="5"> <input type="button" name="add" id="add" value="add smtp"></font></td>
  229.  
  230. <td height="22" bgcolor="#E8E8E8">
  231.  
  232. <div align="right">
  233. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">SEND PAUSE:</font></div>
  234.  
  235. </td>
  236. <td width="41%" height="22" bgcolor="#E8E8E8" ><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  237.  
  238. <input type="text" name="pause" value="<?php echo $pause;?>" style="width:50px;"/>&nbsp;sec evrey&nbsp;<input type="text" name="pemails" value="<?php echo $pemails;?>" style="width:50px;"/>&nbsp;email's <span style="color:red;">(1 bcc = 1 email)<span>
  239.  
  240. </font></td>
  241.  
  242. </tr>
  243. <tr>
  244.  
  245. <td class="td1" height="22" bgcolor="#E8E8E8">
  246.  
  247. <p align="right">
  248. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">SSL Server:</font></td>
  249.  
  250. <td height="22" bgcolor="#E8E8E8">
  251. <input type="radio" name="SSLTLS" value="SSL"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">(SSL)</font>
  252. <input type="radio" name="SSLTLS" value="TLS"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">(TLS)</font>
  253. <input type="radio" name="SSLTLS" value="NON"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">(NON)</font>
  254. </td>
  255.  
  256. <td height="22" bgcolor="#E8E8E8">
  257.  
  258. <p align="right">
  259. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">RECONNECT
  260. AFTER:</font></td>
  261.  
  262. <td height="22" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  263.  
  264. <input type="text" name="reconnect" value="<?php echo $reconnect;?>" size="5">
  265. EMAILS</font></td>
  266.  
  267. </tr>
  268. <tr>
  269.  
  270. <td class="td1" height="22" bgcolor="#E8E8E8">
  271.  
  272. <p align="right">
  273. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">IS BCC:</font>
  274. </td>
  275.  
  276. <td height="22" bgcolor="#E8E8E8">
  277. <input type="checkbox" name="isbcc" value="true" <?php if($isbcc=="true") echo "checked"; ?> ><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">(yes)</font></td>
  278.  
  279. <td height="22" bgcolor="#E8E8E8">
  280.  
  281. <p align="right">
  282. <font face="Verdana, Arial, Helvetica, sans-serif" size="-3">NUM OF EMAIL IN BCC :</font></td>
  283.  
  284. <td height="22" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  285.  
  286. <input type="text" name="nbcc" value="<?php echo $nbcc;?>" size="5">
  287. EMAIL'S</font></td>
  288.  
  289. </tr>
  290. <tr>
  291.  
  292. <td width="100%" height="39" bgcolor="#E8E8E8" colspan="4">
  293.  
  294. <p align="center">
  295. <font face="Arial" style="font-size: 9pt" color="#800000"><b>&quot;</b> IF
  296. YOU DON'T HAVE SMTP LOGIN INFORMATION'S, LEAVE BLANK TO SEND WITH LOCALHOST <b>&quot;</b></font></td>
  297.  
  298. </tr>
  299.  
  300. <tr>
  301.  
  302. <td class="td1" height="19">
  303.  
  304. &nbsp;</td>
  305.  
  306. <td height="19">&nbsp;</td>
  307.  
  308. <td width="31%" height="19">
  309.  
  310. &nbsp;</td>
  311.  
  312. <td width="41%" height="19">&nbsp;</td>
  313.  
  314. </tr>
  315.  
  316. <tr>
  317.  
  318. <td width="100%" colspan="4" bgcolor="#666666" height="36">
  319.  
  320. <b>
  321.  
  322. <font face="Arial" size="2" color="#FFFFFF">&nbsp;MESSAGE SETUP</font></b></td>
  323.  
  324. </tr>
  325.  
  326. <tr>
  327.  
  328. <td class="td1" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8">
  329.  
  330. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  331. Your Email:</font></div>
  332.  
  333. </td>
  334.  
  335. <td height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  336.  
  337. <input type="text" name="from" value="<?php if(!$lase) echo $from_base;?>" size="30" <?php if($lase) echo "disabled"?> >
  338. <input type="checkbox" name="lase" value="true" <?php if($lase) echo "checked"; ?> >EMAIL as LOGIN
  339. </font></td>
  340.  
  341. <td width="31%" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8">
  342.  
  343. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  344. Your Name:</font></div>
  345.  
  346. </td>
  347.  
  348. <td width="41%" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  349.  
  350. <input type="text" name="realname" value="<?php echo $realname_base;?>" size="30">
  351.  
  352. </font></td>
  353.  
  354. </tr>
  355. <tr>
  356.  
  357. <td class="td1" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8">
  358.  
  359. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  360. Reply-To:</font></div>
  361.  
  362. </td>
  363.  
  364. <td height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  365.  
  366. <input type="text" name="replyto" value="<?php if(!$repaslog) echo $replyto;?>" size="30" <?php if($repaslog) echo "disabled";?>><input type="checkbox" name="repaslog" value="true" <?php if($repaslog) echo "checked"; ?> >REPLY as LOGIN
  367. <input type="checkbox" name="readingconf" value="true" <?php if($reading) echo "checked"; ?> >CONFIRM READING
  368. </font></td>
  369.  
  370. <td width="31%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8">
  371.  
  372. <p align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  373. Email Priority:</font></td>
  374.  
  375. <td width="41%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  376.  
  377. &nbsp;</font><select name="epriority" id="listMethod" onchange="showHideListConfig()">
  378. <option value="" <?php if(strlen($epriority)< 1){print "selected";} ?> >
  379. NO PRIORITY</option>
  380. <option value="1" <?php if($epriority == "1"){print "selected";} ?> >HIGH</option>
  381. <option value="3" <?php if($epriority == "3"){print "selected";} ?> >NORMAL</option>
  382. <option value="5" <?php if($epriority == "5"){print "selected";} ?> >LOW</option>
  383. </select></td>
  384.  
  385. </tr>
  386.  
  387. <tr>
  388.  
  389. <td class="td1" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8">
  390.  
  391. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  392. Subject:</font></div>
  393.  
  394. </td>
  395.  
  396. <td height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  397.  
  398. <input type="text" name="subject" value="<?php echo $subject_base;?>" size="90">
  399.  
  400. </font></td><td width="31%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8">
  401.  
  402. <p align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  403. <font size="-3" face="Verdana, Arial, Helvetica, sans-serif" color="#FF0000">
  404. ENCODE SENDING </font>/ CHARSET :</font></td><td width="41%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  405.  
  406. &nbsp;</font><select size="1" name="encodety">
  407. <option value="no" <?php if($encodety == "no"){print "selected";} ?>>NO</option>
  408. <option value="8bit" <?php if($encodety == "8bit"){print "selected";} ?>>8bit</option>
  409. <option value="7bit" <?php if($encodety == "7bit"){print "selected";} ?>>7bit</option>
  410. <option value="binary" <?php if($encodety == "binary"){print "selected";} ?>>binary</option>
  411. <option value="base64" <?php if($encodety == "base64"){print "selected";} ?>>base64</option>
  412. <option value="quoted-printable" <?php if($encodety == "quoted-printable"){print "selected";} ?>>quoted-printable</option>
  413. </select><select name="epriority" id="listMethod" onchange="showHideListConfig()">
  414. <option value="" selected="">NO CHARSET</option>
  415. <option value="us-ascii">Unicode -> us-ascii</option>
  416. <option value="utf-7">Unicode -> utf-7</option>
  417. <option value="utf-8">Unicode -> utf-8</option>
  418. <option value="iso-10646-ucs-2">Unicode -> iso-10646-ucs-2</option>
  419. <option value="iso-8859-6">Arabic -> iso-8859-6</option>
  420. <option value="x-mac-arabic">Arabic -> x-mac-arabic</option>
  421. <option value="windows-1256">Arabic -> windows-1256</option>
  422. <option value="iso-8859-4">Baltic -> iso-8859-4</option>
  423. <option value="windows-1257">Baltic -> windows-1257</option>
  424. <option value="iso-8859-2">Central European -> iso-8859-2</option>
  425. <option value="x-mac-ce">Central European -> x-mac-ce</option>
  426. <option value="windows-1250">Central European -> windows-1250</option>
  427. <option value="euc-cn">Chinese -> euc-cn</option>
  428. <option value="gb2312">Chinese -> gb2312</option>
  429. <option value="hz-gb-2312">Chinese -> hz-gb-2312 </option>
  430. <option value="x-mac-chinesesimp">Chinese -> x-mac-chinesesimp</option>
  431. <option value="cp-936">Chinese -> cp-936</option>
  432. <option value="big5">Chinese -> big5</option>
  433. <option value="x-mac-chinesetrad">Chinese -> x-mac-chinesetrad</option>
  434. <option value="cp-950">Chinese -> cp-950</option>
  435. <option value="cp-932">Chinese -> cp-932</option>
  436. <option value="euc-tw">Chinese -> euc-tw</option>
  437. </select></td>
  438.  
  439. </tr>
  440.  
  441. <tr>
  442.  
  443. <td class="td1" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8">
  444.  
  445. <div align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  446. Generateur:</font></div></td>
  447.  
  448. <td width="35%" colspan="" height="22" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  449. (a-z)<input type="checkbox" name="az" id="az">
  450. (A-Z)<input type="checkbox" name="AZ" id="AZ">
  451. (0-9)<input type="checkbox" name="09" id="09">
  452. (LENHGT)<input type="text" maxlength=2 size=1 name="len" id="len">
  453. (#PATTERN)<input type="text" name="patval" id="patval">
  454. <input type="button" value="GET PATTERN" id="patb" name="patb">
  455. </td>
  456. <td width="31%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8">
  457.  
  458. <p align="right"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  459. <font size="-3" face="Verdana, Arial, Helvetica, sans-serif" >
  460. ATTACH :</font>
  461. </td>
  462. <td width="41%" height="22" bgcolor="#E8E8E8" bordercolor="#E8E8E8"></font><input name="userfile" type="file"></td>
  463. </tr>
  464.  
  465. <tr valign="top">
  466.  
  467. <td colspan="3" height="190" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-1" face="Verdana, Arial, Helvetica, sans-serif">
  468.  
  469. <textarea name="message" value=""cols="60" rows="10"><?php echo $message_base;?></textarea>
  470.  
  471. <br>
  472.  
  473. <input type="radio" name="contenttype" value="plain" >
  474.  
  475. TEXT
  476.  
  477. <input type="radio" name="contenttype" value="html" checked>
  478.  
  479. HTML
  480.  
  481. <input type="hidden" name="action" value="send">
  482.  
  483. <input type="submit" value="Send Message">
  484.  
  485. </font></td>
  486.  
  487. <td width="41%" height="190" bordercolor="#E8E8E8" bgcolor="#E8E8E8"><font size="-3" face="Verdana, Arial, Helvetica, sans-serif">
  488.  
  489. <textarea name="emaillist" value="" cols="30" rows="10"><?php echo $emaillist;?></textarea>
  490.  
  491. </font></td>
  492.  
  493. </tr>
  494.  
  495. </table>
  496.  
  497. </form>
  498.  
  499. <?php print "<p class=\"style1\">PHP Mailer &copy 2017, <b><font color=\"#800000\">BY RFX</font><span style=\"color:red\">&nbsp;&nbsp;SKYPE: KIMONO238<br></span></b></p>"; ?>
  500. </body>
  501. </html>
  502.  
  503.  
  504. <?php
  505.  
  506.  
  507.  
  508. class SMTP
  509. {
  510. /**
  511. * The PHPMailer SMTP version number.
  512. * @var string
  513. */
  514. const VERSION = '5.2.17';
  515. /**
  516. * SMTP line break constant.
  517. * @var string
  518. */
  519. const CRLF = "\r\n";
  520. /**
  521. * The SMTP port to use if one is not specified.
  522. * @var integer
  523. */
  524. const DEFAULT_SMTP_PORT = 25;
  525. /**
  526. * The maximum line length allowed by RFC 2822 section 2.1.1
  527. * @var integer
  528. */
  529. const MAX_LINE_LENGTH = 998;
  530. /**
  531. * Debug level for no output
  532. */
  533. const DEBUG_OFF = 0;
  534. /**
  535. * Debug level to show client -> server messages
  536. */
  537. const DEBUG_CLIENT = 1;
  538. /**
  539. * Debug level to show client -> server and server -> client messages
  540. */
  541. const DEBUG_SERVER = 2;
  542. /**
  543. * Debug level to show connection status, client -> server and server -> client messages
  544. */
  545. const DEBUG_CONNECTION = 3;
  546. /**
  547. * Debug level to show all messages
  548. */
  549. const DEBUG_LOWLEVEL = 4;
  550. /**
  551. * The PHPMailer SMTP Version number.
  552. * @var string
  553. * @deprecated Use the `VERSION` constant instead
  554. * @see SMTP::VERSION
  555. */
  556. public $Version = '5.2.17';
  557. /**
  558. * SMTP server port number.
  559. * @var integer
  560. * @deprecated This is only ever used as a default value, so use the `DEFAULT_SMTP_PORT` constant instead
  561. * @see SMTP::DEFAULT_SMTP_PORT
  562. */
  563. public $SMTP_PORT = 25;
  564. /**
  565. * SMTP reply line ending.
  566. * @var string
  567. * @deprecated Use the `CRLF` constant instead
  568. * @see SMTP::CRLF
  569. */
  570. public $CRLF = "\r\n";
  571. /**
  572. * Debug output level.
  573. * Options:
  574. * * self::DEBUG_OFF (`0`) No debug output, default
  575. * * self::DEBUG_CLIENT (`1`) Client commands
  576. * * self::DEBUG_SERVER (`2`) Client commands and server responses
  577. * * self::DEBUG_CONNECTION (`3`) As DEBUG_SERVER plus connection status
  578. * * self::DEBUG_LOWLEVEL (`4`) Low-level data output, all messages
  579. * @var integer
  580. */
  581. public $do_debug = self::DEBUG_OFF;
  582. /**
  583. * How to handle debug output.
  584. * Options:
  585. * * `echo` Output plain-text as-is, appropriate for CLI
  586. * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
  587. * * `error_log` Output to error log as configured in php.ini
  588. *
  589. * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
  590. * <code>
  591. * $smtp->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
  592. * </code>
  593. * @var string|callable
  594. */
  595. public $Debugoutput = 'echo';
  596. /**
  597. * Whether to use VERP.
  598. * @link http://en.wikipedia.org/wiki/Variable_envelope_return_path
  599. * @link http://www.postfix.org/VERP_README.html Info on VERP
  600. * @var boolean
  601. */
  602. public $do_verp = false;
  603. /**
  604. * The timeout value for connection, in seconds.
  605. * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
  606. * This needs to be quite high to function correctly with hosts using greetdelay as an anti-spam measure.
  607. * @link http://tools.ietf.org/html/rfc2821#section-4.5.3.2
  608. * @var integer
  609. */
  610. public $Timeout = 300;
  611. /**
  612. * How long to wait for commands to complete, in seconds.
  613. * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
  614. * @var integer
  615. */
  616. public $Timelimit = 300;
  617. /**
  618. * @var array patterns to extract smtp transaction id from smtp reply
  619. * Only first capture group will be use, use non-capturing group to deal with it
  620. * Extend this class to override this property to fulfil your needs.
  621. */
  622. protected $smtp_transaction_id_patterns = array(
  623. 'exim' => '/[0-9]{3} OK id=(.*)/',
  624. 'sendmail' => '/[0-9]{3} 2.0.0 (.*) Message/',
  625. 'postfix' => '/[0-9]{3} 2.0.0 Ok: queued as (.*)/'
  626. );
  627. /**
  628. * The socket for the server connection.
  629. * @var resource
  630. */
  631. protected $smtp_conn;
  632. /**
  633. * Error information, if any, for the last SMTP command.
  634. * @var array
  635. */
  636. protected $error = array(
  637. 'error' => '',
  638. 'detail' => '',
  639. 'smtp_code' => '',
  640. 'smtp_code_ex' => ''
  641. );
  642. /**
  643. * The reply the server sent to us for HELO.
  644. * If null, no HELO string has yet been received.
  645. * @var string|null
  646. */
  647. protected $helo_rply = null;
  648. /**
  649. * The set of SMTP extensions sent in reply to EHLO command.
  650. * Indexes of the array are extension names.
  651. * Value at index 'HELO' or 'EHLO' (according to command that was sent)
  652. * represents the server name. In case of HELO it is the only element of the array.
  653. * Other values can be boolean TRUE or an array containing extension options.
  654. * If null, no HELO/EHLO string has yet been received.
  655. * @var array|null
  656. */
  657. protected $server_caps = null;
  658. /**
  659. * The most recent reply received from the server.
  660. * @var string
  661. */
  662. protected $last_reply = '';
  663. /**
  664. * Output debugging info via a user-selected method.
  665. * @see SMTP::$Debugoutput
  666. * @see SMTP::$do_debug
  667. * @param string $str Debug string to output
  668. * @param integer $level The debug level of this message; see DEBUG_* constants
  669. * @return void
  670. */
  671. protected function edebug($str, $level = 0)
  672. {
  673. if ($level > $this->do_debug) {
  674. return;
  675. }
  676. //Avoid clash with built-in function names
  677. if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
  678. call_user_func($this->Debugoutput, $str, $level);
  679. return;
  680. }
  681. switch ($this->Debugoutput) {
  682. case 'error_log':
  683. //Don't output, just log
  684. error_log($str);
  685. break;
  686. case 'html':
  687. //Cleans up output a bit for a better looking, HTML-safe output
  688. echo htmlentities(
  689. preg_replace('/[\r\n]+/', '', $str),
  690. ENT_QUOTES,
  691. 'UTF-8'
  692. )
  693. . "<br>\n";
  694. break;
  695. case 'echo':
  696. default:
  697. //Normalize line breaks
  698. $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
  699. echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
  700. "\n",
  701. "\n \t ",
  702. trim($str)
  703. )."\n";
  704. }
  705. }
  706. /**
  707. * Connect to an SMTP server.
  708. * @param string $host SMTP server IP or host name
  709. * @param integer $port The port number to connect to
  710. * @param integer $timeout How long to wait for the connection to open
  711. * @param array $options An array of options for stream_context_create()
  712. * @access public
  713. * @return boolean
  714. */
  715. public function connect($host, $port = null, $timeout = 30, $options = array())
  716. {
  717. if(count($options)==0)
  718. {
  719. $options["ssl"]=array("verify_peer"=>false,"verify_peer_name"=>false,"allow_self_signed"=>true);
  720. }
  721. static $streamok;
  722. //This is enabled by default since 5.0.0 but some providers disable it
  723. //Check this once and cache the result
  724. if (is_null($streamok)) {
  725. $streamok = function_exists('stream_socket_client');
  726. }
  727. // Clear errors to avoid confusion
  728. $this->setError('');
  729. // Make sure we are __not__ connected
  730. if ($this->connected()) {
  731. // Already connected, generate error
  732. $this->setError('Already connected to a server');
  733. return false;
  734. }
  735. if (empty($port)) {
  736. $port = self::DEFAULT_SMTP_PORT;
  737. }
  738. // Connect to the SMTP server
  739. $this->edebug(
  740. "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true),
  741. self::DEBUG_CONNECTION
  742. );
  743. $errno = 0;
  744. $errstr = '';
  745. if ($streamok) {
  746. $socket_context = stream_context_create($options);
  747. set_error_handler(array($this, 'errorHandler'));
  748. $this->smtp_conn = stream_socket_client(
  749. $host . ":" . $port,
  750. $errno,
  751. $errstr,
  752. $timeout,
  753. STREAM_CLIENT_CONNECT,
  754. $socket_context
  755. );
  756. restore_error_handler();
  757. } else {
  758. //Fall back to fsockopen which should work in more places, but is missing some features
  759. $this->edebug(
  760. "Connection: stream_socket_client not available, falling back to fsockopen",
  761. self::DEBUG_CONNECTION
  762. );
  763. set_error_handler(array($this, 'errorHandler'));
  764. $this->smtp_conn = fsockopen(
  765. $host,
  766. $port,
  767. $errno,
  768. $errstr,
  769. $timeout
  770. );
  771. restore_error_handler();
  772. }
  773. // Verify we connected properly
  774. if (!is_resource($this->smtp_conn)) {
  775. $this->setError(
  776. 'Failed to connect to server',
  777. $errno,
  778. $errstr
  779. );
  780. $this->edebug(
  781. 'SMTP ERROR: ' . $this->error['error']
  782. . ": $errstr ($errno)",
  783. self::DEBUG_CLIENT
  784. );
  785. return false;
  786. }
  787. $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
  788. // SMTP server can take longer to respond, give longer timeout for first read
  789. // Windows does not have support for this timeout function
  790. if (substr(PHP_OS, 0, 3) != 'WIN') {
  791. $max = ini_get('max_execution_time');
  792. // Don't bother if unlimited
  793. if ($max != 0 && $timeout > $max) {
  794. @set_time_limit($timeout);
  795. }
  796. stream_set_timeout($this->smtp_conn, $timeout, 0);
  797. }
  798. // Get any announcement
  799. $announce = $this->get_lines();
  800. $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
  801. return true;
  802. }
  803. /**
  804. * Initiate a TLS (encrypted) session.
  805. * @access public
  806. * @return boolean
  807. */
  808. public function startTLS()
  809. {
  810. if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
  811. return false;
  812. }
  813. //Allow the best TLS version(s) we can
  814. $crypto_method = STREAM_CRYPTO_METHOD_TLS_CLIENT;
  815. //PHP 5.6.7 dropped inclusion of TLS 1.1 and 1.2 in STREAM_CRYPTO_METHOD_TLS_CLIENT
  816. //so add them back in manually if we can
  817. if (defined('STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT')) {
  818. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT;
  819. $crypto_method |= STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT;
  820. }
  821. // Begin encrypted connection
  822. if (!stream_socket_enable_crypto(
  823. $this->smtp_conn,
  824. true,
  825. $crypto_method
  826. )) {
  827. return false;
  828. }
  829. return true;
  830. }
  831. /**
  832. * Perform SMTP authentication.
  833. * Must be run after hello().
  834. * @see hello()
  835. * @param string $username The user name
  836. * @param string $password The password
  837. * @param string $authtype The auth type (PLAIN, LOGIN, NTLM, CRAM-MD5, XOAUTH2)
  838. * @param string $realm The auth realm for NTLM
  839. * @param string $workstation The auth workstation for NTLM
  840. * @param null|OAuth $OAuth An optional OAuth instance (@see PHPMailerOAuth)
  841. * @return bool True if successfully authenticated.* @access public
  842. */
  843. public function authenticate(
  844. $username,
  845. $password,
  846. $authtype = null,
  847. $realm = '',
  848. $workstation = '',
  849. $OAuth = null
  850. ) {
  851. if (!$this->server_caps) {
  852. $this->setError('Authentication is not allowed before HELO/EHLO');
  853. return false;
  854. }
  855. if (array_key_exists('EHLO', $this->server_caps)) {
  856. // SMTP extensions are available. Let's try to find a proper authentication method
  857. if (!array_key_exists('AUTH', $this->server_caps)) {
  858. $this->setError('Authentication is not allowed at this stage');
  859. // 'at this stage' means that auth may be allowed after the stage changes
  860. // e.g. after STARTTLS
  861. return false;
  862. }
  863. self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
  864. self::edebug(
  865. 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
  866. self::DEBUG_LOWLEVEL
  867. );
  868. if (empty($authtype)) {
  869. foreach (array('CRAM-MD5', 'LOGIN', 'PLAIN', 'NTLM', 'XOAUTH2') as $method) {
  870. if (in_array($method, $this->server_caps['AUTH'])) {
  871. $authtype = $method;
  872. break;
  873. }
  874. }
  875. if (empty($authtype)) {
  876. $this->setError('No supported authentication methods found');
  877. return false;
  878. }
  879. self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
  880. }
  881. if (!in_array($authtype, $this->server_caps['AUTH'])) {
  882. $this->setError("The requested authentication method \"$authtype\" is not supported by the server");
  883. return false;
  884. }
  885. } elseif (empty($authtype)) {
  886. $authtype = 'LOGIN';
  887. }
  888. switch ($authtype) {
  889. case 'PLAIN':
  890. // Start authentication
  891. if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
  892. return false;
  893. }
  894. // Send encoded username and password
  895. if (!$this->sendCommand(
  896. 'User & Password',
  897. base64_encode("\0" . $username . "\0" . $password),
  898. 235
  899. )
  900. ) {
  901. return false;
  902. }
  903. break;
  904. case 'LOGIN':
  905. // Start authentication
  906. if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
  907. return false;
  908. }
  909. if (!$this->sendCommand("Username", base64_encode($username), 334)) {
  910. return false;
  911. }
  912. if (!$this->sendCommand("Password", base64_encode($password), 235)) {
  913. return false;
  914. }
  915. break;
  916. case 'XOAUTH2':
  917. //If the OAuth Instance is not set. Can be a case when PHPMailer is used
  918. //instead of PHPMailerOAuth
  919. if (is_null($OAuth)) {
  920. return false;
  921. }
  922. $oauth = $OAuth->getOauth64();
  923. // Start authentication
  924. if (!$this->sendCommand('AUTH', 'AUTH XOAUTH2 ' . $oauth, 235)) {
  925. return false;
  926. }
  927. break;
  928. case 'NTLM':
  929. /*
  930. * ntlm_sasl_client.php
  931. * Bundled with Permission
  932. *
  933. * How to telnet in windows:
  934. * http://technet.microsoft.com/en-us/library/aa995718%28EXCHG.65%29.aspx
  935. * PROTOCOL Docs http://curl.haxx.se/rfc/ntlm.html#ntlmSmtpAuthentication
  936. */
  937. require_once 'extras/ntlm_sasl_client.php';
  938. $temp = new stdClass;
  939. $ntlm_client = new ntlm_sasl_client_class;
  940. //Check that functions are available
  941. if (!$ntlm_client->initialize($temp)) {
  942. $this->setError($temp->error);
  943. $this->edebug(
  944. 'You need to enable some modules in your php.ini file: '
  945. . $this->error['error'],
  946. self::DEBUG_CLIENT
  947. );
  948. return false;
  949. }
  950. //msg1
  951. $msg1 = $ntlm_client->typeMsg1($realm, $workstation); //msg1
  952. if (!$this->sendCommand(
  953. 'AUTH NTLM',
  954. 'AUTH NTLM ' . base64_encode($msg1),
  955. 334
  956. )
  957. ) {
  958. return false;
  959. }
  960. //Though 0 based, there is a white space after the 3 digit number
  961. //msg2
  962. $challenge = substr($this->last_reply, 3);
  963. $challenge = base64_decode($challenge);
  964. $ntlm_res = $ntlm_client->NTLMResponse(
  965. substr($challenge, 24, 8),
  966. $password
  967. );
  968. //msg3
  969. $msg3 = $ntlm_client->typeMsg3(
  970. $ntlm_res,
  971. $username,
  972. $realm,
  973. $workstation
  974. );
  975. // send encoded username
  976. return $this->sendCommand('Username', base64_encode($msg3), 235);
  977. case 'CRAM-MD5':
  978. // Start authentication
  979. if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
  980. return false;
  981. }
  982. // Get the challenge
  983. $challenge = base64_decode(substr($this->last_reply, 4));
  984. // Build the response
  985. $response = $username . ' ' . $this->hmac($challenge, $password);
  986. // send encoded credentials
  987. return $this->sendCommand('Username', base64_encode($response), 235);
  988. default:
  989. $this->setError("Authentication method \"$authtype\" is not supported");
  990. return false;
  991. }
  992. return true;
  993. }
  994. /**
  995. * Calculate an MD5 HMAC hash.
  996. * Works like hash_hmac('md5', $data, $key)
  997. * in case that function is not available
  998. * @param string $data The data to hash
  999. * @param string $key The key to hash with
  1000. * @access protected
  1001. * @return string
  1002. */
  1003. protected function hmac($data, $key)
  1004. {
  1005. if (function_exists('hash_hmac')) {
  1006. return hash_hmac('md5', $data, $key);
  1007. }
  1008. // The following borrowed from
  1009. // http://php.net/manual/en/function.mhash.php#27225
  1010. // RFC 2104 HMAC implementation for php.
  1011. // Creates an md5 HMAC.
  1012. // Eliminates the need to install mhash to compute a HMAC
  1013. // by Lance Rushing
  1014. $bytelen = 64; // byte length for md5
  1015. if (strlen($key) > $bytelen) {
  1016. $key = pack('H*', md5($key));
  1017. }
  1018. $key = str_pad($key, $bytelen, chr(0x00));
  1019. $ipad = str_pad('', $bytelen, chr(0x36));
  1020. $opad = str_pad('', $bytelen, chr(0x5c));
  1021. $k_ipad = $key ^ $ipad;
  1022. $k_opad = $key ^ $opad;
  1023. return md5($k_opad . pack('H*', md5($k_ipad . $data)));
  1024. }
  1025. /**
  1026. * Check connection state.
  1027. * @access public
  1028. * @return boolean True if connected.
  1029. */
  1030. public function connected()
  1031. {
  1032. if (is_resource($this->smtp_conn)) {
  1033. $sock_status = stream_get_meta_data($this->smtp_conn);
  1034. if ($sock_status['eof']) {
  1035. // The socket is valid but we are not connected
  1036. $this->edebug(
  1037. 'SMTP NOTICE: EOF caught while checking if connected',
  1038. self::DEBUG_CLIENT
  1039. );
  1040. $this->close();
  1041. return false;
  1042. }
  1043. return true; // everything looks good
  1044. }
  1045. return false;
  1046. }
  1047. /**
  1048. * Close the socket and clean up the state of the class.
  1049. * Don't use this function without first trying to use QUIT.
  1050. * @see quit()
  1051. * @access public
  1052. * @return void
  1053. */
  1054. public function close()
  1055. {
  1056. $this->setError('');
  1057. $this->server_caps = null;
  1058. $this->helo_rply = null;
  1059. if (is_resource($this->smtp_conn)) {
  1060. // close the connection and cleanup
  1061. fclose($this->smtp_conn);
  1062. $this->smtp_conn = null; //Makes for cleaner serialization
  1063. $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
  1064. }
  1065. }
  1066. /**
  1067. * Send an SMTP DATA command.
  1068. * Issues a data command and sends the msg_data to the server,
  1069. * finializing the mail transaction. $msg_data is the message
  1070. * that is to be send with the headers. Each header needs to be
  1071. * on a single line followed by a <CRLF> with the message headers
  1072. * and the message body being separated by and additional <CRLF>.
  1073. * Implements rfc 821: DATA <CRLF>
  1074. * @param string $msg_data Message data to send
  1075. * @access public
  1076. * @return boolean
  1077. */
  1078. public function data($msg_data)
  1079. {
  1080. //This will use the standard timelimit
  1081. if (!$this->sendCommand('DATA', 'DATA', 354)) {
  1082. return false;
  1083. }
  1084. /* The server is ready to accept data!
  1085. * According to rfc821 we should not send more than 1000 characters on a single line (including the CRLF)
  1086. * so we will break the data up into lines by \r and/or \n then if needed we will break each of those into
  1087. * smaller lines to fit within the limit.
  1088. * We will also look for lines that start with a '.' and prepend an additional '.'.
  1089. * NOTE: this does not count towards line-length limit.
  1090. */
  1091. // Normalize line breaks before exploding
  1092. $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
  1093. /* To distinguish between a complete RFC822 message and a plain message body, we check if the first field
  1094. * of the first line (':' separated) does not contain a space then it _should_ be a header and we will
  1095. * process all lines before a blank line as headers.
  1096. */
  1097. $field = substr($lines[0], 0, strpos($lines[0], ':'));
  1098. $in_headers = false;
  1099. if (!empty($field) && strpos($field, ' ') === false) {
  1100. $in_headers = true;
  1101. }
  1102. foreach ($lines as $line) {
  1103. $lines_out = array();
  1104. if ($in_headers and $line == '') {
  1105. $in_headers = false;
  1106. }
  1107. //Break this line up into several smaller lines if it's too long
  1108. //Micro-optimisation: isset($str[$len]) is faster than (strlen($str) > $len),
  1109. while (isset($line[self::MAX_LINE_LENGTH])) {
  1110. //Working backwards, try to find a space within the last MAX_LINE_LENGTH chars of the line to break on
  1111. //so as to avoid breaking in the middle of a word
  1112. $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
  1113. //Deliberately matches both false and 0
  1114. if (!$pos) {
  1115. //No nice break found, add a hard break
  1116. $pos = self::MAX_LINE_LENGTH - 1;
  1117. $lines_out[] = substr($line, 0, $pos);
  1118. $line = substr($line, $pos);
  1119. } else {
  1120. //Break at the found point
  1121. $lines_out[] = substr($line, 0, $pos);
  1122. //Move along by the amount we dealt with
  1123. $line = substr($line, $pos + 1);
  1124. }
  1125. //If processing headers add a LWSP-char to the front of new line RFC822 section 3.1.1
  1126. if ($in_headers) {
  1127. $line = "\t" . $line;
  1128. }
  1129. }
  1130. $lines_out[] = $line;
  1131. //Send the lines to the server
  1132. foreach ($lines_out as $line_out) {
  1133. //RFC2821 section 4.5.2
  1134. if (!empty($line_out) and $line_out[0] == '.') {
  1135. $line_out = '.' . $line_out;
  1136. }
  1137. $this->client_send($line_out . self::CRLF);
  1138. }
  1139. }
  1140. //Message data has been sent, complete the command
  1141. //Increase timelimit for end of DATA command
  1142. $savetimelimit = $this->Timelimit;
  1143. $this->Timelimit = $this->Timelimit * 2;
  1144. $result = $this->sendCommand('DATA END', '.', 250);
  1145. //Restore timelimit
  1146. $this->Timelimit = $savetimelimit;
  1147. return $result;
  1148. }
  1149. /**
  1150. * Send an SMTP HELO or EHLO command.
  1151. * Used to identify the sending server to the receiving server.
  1152. * This makes sure that client and server are in a known state.
  1153. * Implements RFC 821: HELO <SP> <domain> <CRLF>
  1154. * and RFC 2821 EHLO.
  1155. * @param string $host The host name or IP to connect to
  1156. * @access public
  1157. * @return boolean
  1158. */
  1159. public function hello($host = '')
  1160. {
  1161. //Try extended hello first (RFC 2821)
  1162. return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
  1163. }
  1164. /**
  1165. * Send an SMTP HELO or EHLO command.
  1166. * Low-level implementation used by hello()
  1167. * @see hello()
  1168. * @param string $hello The HELO string
  1169. * @param string $host The hostname to say we are
  1170. * @access protected
  1171. * @return boolean
  1172. */
  1173. protected function sendHello($hello, $host)
  1174. {
  1175. $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
  1176. $this->helo_rply = $this->last_reply;
  1177. if ($noerror) {
  1178. $this->parseHelloFields($hello);
  1179. } else {
  1180. $this->server_caps = null;
  1181. }
  1182. return $noerror;
  1183. }
  1184. /**
  1185. * Parse a reply to HELO/EHLO command to discover server extensions.
  1186. * In case of HELO, the only parameter that can be discovered is a server name.
  1187. * @access protected
  1188. * @param string $type - 'HELO' or 'EHLO'
  1189. */
  1190. protected function parseHelloFields($type)
  1191. {
  1192. $this->server_caps = array();
  1193. $lines = explode("\n", $this->helo_rply);
  1194. foreach ($lines as $n => $s) {
  1195. //First 4 chars contain response code followed by - or space
  1196. $s = trim(substr($s, 4));
  1197. if (empty($s)) {
  1198. continue;
  1199. }
  1200. $fields = explode(' ', $s);
  1201. if (!empty($fields)) {
  1202. if (!$n) {
  1203. $name = $type;
  1204. $fields = $fields[0];
  1205. } else {
  1206. $name = array_shift($fields);
  1207. switch ($name) {
  1208. case 'SIZE':
  1209. $fields = ($fields ? $fields[0] : 0);
  1210. break;
  1211. case 'AUTH':
  1212. if (!is_array($fields)) {
  1213. $fields = array();
  1214. }
  1215. break;
  1216. default:
  1217. $fields = true;
  1218. }
  1219. }
  1220. $this->server_caps[$name] = $fields;
  1221. }
  1222. }
  1223. }
  1224. /**
  1225. * Send an SMTP MAIL command.
  1226. * Starts a mail transaction from the email address specified in
  1227. * $from. Returns true if successful or false otherwise. If True
  1228. * the mail transaction is started and then one or more recipient
  1229. * commands may be called followed by a data command.
  1230. * Implements rfc 821: MAIL <SP> FROM:<reverse-path> <CRLF>
  1231. * @param string $from Source address of this message
  1232. * @access public
  1233. * @return boolean
  1234. */
  1235. public function mail($from)
  1236. {
  1237. $useVerp = ($this->do_verp ? ' XVERP' : '');
  1238. return $this->sendCommand(
  1239. 'MAIL FROM',
  1240. 'MAIL FROM:<' . $from . '>' . $useVerp,
  1241. 250
  1242. );
  1243. }
  1244. /**
  1245. * Send an SMTP QUIT command.
  1246. * Closes the socket if there is no error or the $close_on_error argument is true.
  1247. * Implements from rfc 821: QUIT <CRLF>
  1248. * @param boolean $close_on_error Should the connection close if an error occurs?
  1249. * @access public
  1250. * @return boolean
  1251. */
  1252. public function quit($close_on_error = true)
  1253. {
  1254. $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
  1255. $err = $this->error; //Save any error
  1256. if ($noerror or $close_on_error) {
  1257. $this->close();
  1258. $this->error = $err; //Restore any error from the quit command
  1259. }
  1260. return $noerror;
  1261. }
  1262. /**
  1263. * Send an SMTP RCPT command.
  1264. * Sets the TO argument to $toaddr.
  1265. * Returns true if the recipient was accepted false if it was rejected.
  1266. * Implements from rfc 821: RCPT <SP> TO:<forward-path> <CRLF>
  1267. * @param string $address The address the message is being sent to
  1268. * @access public
  1269. * @return boolean
  1270. */
  1271. public function recipient($address)
  1272. {
  1273. return $this->sendCommand(
  1274. 'RCPT TO',
  1275. 'RCPT TO:<' . $address . '>',
  1276. array(250, 251)
  1277. );
  1278. }
  1279. /**
  1280. * Send an SMTP RSET command.
  1281. * Abort any transaction that is currently in progress.
  1282. * Implements rfc 821: RSET <CRLF>
  1283. * @access public
  1284. * @return boolean True on success.
  1285. */
  1286. public function reset()
  1287. {
  1288. return $this->sendCommand('RSET', 'RSET', 250);
  1289. }
  1290. /**
  1291. * Send a command to an SMTP server and check its return code.
  1292. * @param string $command The command name - not sent to the server
  1293. * @param string $commandstring The actual command to send
  1294. * @param integer|array $expect One or more expected integer success codes
  1295. * @access protected
  1296. * @return boolean True on success.
  1297. */
  1298. protected function sendCommand($command, $commandstring, $expect)
  1299. {
  1300. if (!$this->connected()) {
  1301. $this->setError("Called $command without being connected");
  1302. return false;
  1303. }
  1304. //Reject line breaks in all commands
  1305. if (strpos($commandstring, "\n") !== false or strpos($commandstring, "\r") !== false) {
  1306. $this->setError("Command '$command' contained line breaks");
  1307. return false;
  1308. }
  1309. $this->client_send($commandstring . self::CRLF);
  1310. $this->last_reply = $this->get_lines();
  1311. // Fetch SMTP code and possible error code explanation
  1312. $matches = array();
  1313. if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
  1314. $code = $matches[1];
  1315. $code_ex = (count($matches) > 2 ? $matches[2] : null);
  1316. // Cut off error code from each response line
  1317. $detail = preg_replace(
  1318. "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
  1319. '',
  1320. $this->last_reply
  1321. );
  1322. } else {
  1323. // Fall back to simple parsing if regex fails
  1324. $code = substr($this->last_reply, 0, 3);
  1325. $code_ex = null;
  1326. $detail = substr($this->last_reply, 4);
  1327. }
  1328. $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
  1329. if (!in_array($code, (array)$expect)) {
  1330. $this->setError(
  1331. "$command command failed",
  1332. $detail,
  1333. $code,
  1334. $code_ex
  1335. );
  1336. $this->edebug(
  1337. 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
  1338. self::DEBUG_CLIENT
  1339. );
  1340. return false;
  1341. }
  1342. $this->setError('');
  1343. return true;
  1344. }
  1345. /**
  1346. * Send an SMTP SAML command.
  1347. * Starts a mail transaction from the email address specified in $from.
  1348. * Returns true if successful or false otherwise. If True
  1349. * the mail transaction is started and then one or more recipient
  1350. * commands may be called followed by a data command. This command
  1351. * will send the message to the users terminal if they are logged
  1352. * in and send them an email.
  1353. * Implements rfc 821: SAML <SP> FROM:<reverse-path> <CRLF>
  1354. * @param string $from The address the message is from
  1355. * @access public
  1356. * @return boolean
  1357. */
  1358. public function sendAndMail($from)
  1359. {
  1360. return $this->sendCommand('SAML', "SAML FROM:$from", 250);
  1361. }
  1362. /**
  1363. * Send an SMTP VRFY command.
  1364. * @param string $name The name to verify
  1365. * @access public
  1366. * @return boolean
  1367. */
  1368. public function verify($name)
  1369. {
  1370. return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
  1371. }
  1372. /**
  1373. * Send an SMTP NOOP command.
  1374. * Used to keep keep-alives alive, doesn't actually do anything
  1375. * @access public
  1376. * @return boolean
  1377. */
  1378. public function noop()
  1379. {
  1380. return $this->sendCommand('NOOP', 'NOOP', 250);
  1381. }
  1382. /**
  1383. * Send an SMTP TURN command.
  1384. * This is an optional command for SMTP that this class does not support.
  1385. * This method is here to make the RFC821 Definition complete for this class
  1386. * and _may_ be implemented in future
  1387. * Implements from rfc 821: TURN <CRLF>
  1388. * @access public
  1389. * @return boolean
  1390. */
  1391. public function turn()
  1392. {
  1393. $this->setError('The SMTP TURN command is not implemented');
  1394. $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
  1395. return false;
  1396. }
  1397. /**
  1398. * Send raw data to the server.
  1399. * @param string $data The data to send
  1400. * @access public
  1401. * @return integer|boolean The number of bytes sent to the server or false on error
  1402. */
  1403. public function client_send($data)
  1404. {
  1405. $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
  1406. set_error_handler(array($this, 'errorHandler'));
  1407. $result = fwrite($this->smtp_conn, $data);
  1408. restore_error_handler();
  1409. return $result;
  1410. }
  1411. /**
  1412. * Get the latest error.
  1413. * @access public
  1414. * @return array
  1415. */
  1416. public function getError()
  1417. {
  1418. return $this->error;
  1419. }
  1420. /**
  1421. * Get SMTP extensions available on the server
  1422. * @access public
  1423. * @return array|null
  1424. */
  1425. public function getServerExtList()
  1426. {
  1427. return $this->server_caps;
  1428. }
  1429. /**
  1430. * A multipurpose method
  1431. * The method works in three ways, dependent on argument value and current state
  1432. * 1. HELO/EHLO was not sent - returns null and set up $this->error
  1433. * 2. HELO was sent
  1434. * $name = 'HELO': returns server name
  1435. * $name = 'EHLO': returns boolean false
  1436. * $name = any string: returns null and set up $this->error
  1437. * 3. EHLO was sent
  1438. * $name = 'HELO'|'EHLO': returns server name
  1439. * $name = any string: if extension $name exists, returns boolean True
  1440. * or its options. Otherwise returns boolean False
  1441. * In other words, one can use this method to detect 3 conditions:
  1442. * - null returned: handshake was not or we don't know about ext (refer to $this->error)
  1443. * - false returned: the requested feature exactly not exists
  1444. * - positive value returned: the requested feature exists
  1445. * @param string $name Name of SMTP extension or 'HELO'|'EHLO'
  1446. * @return mixed
  1447. */
  1448. public function getServerExt($name)
  1449. {
  1450. if (!$this->server_caps) {
  1451. $this->setError('No HELO/EHLO was sent');
  1452. return null;
  1453. }
  1454. // the tight logic knot ;)
  1455. if (!array_key_exists($name, $this->server_caps)) {
  1456. if ($name == 'HELO') {
  1457. return $this->server_caps['EHLO'];
  1458. }
  1459. if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
  1460. return false;
  1461. }
  1462. $this->setError('HELO handshake was used. Client knows nothing about server extensions');
  1463. return null;
  1464. }
  1465. return $this->server_caps[$name];
  1466. }
  1467. /**
  1468. * Get the last reply from the server.
  1469. * @access public
  1470. * @return string
  1471. */
  1472. public function getLastReply()
  1473. {
  1474. return $this->last_reply;
  1475. }
  1476. /**
  1477. * Read the SMTP server's response.
  1478. * Either before eof or socket timeout occurs on the operation.
  1479. * With SMTP we can tell if we have more lines to read if the
  1480. * 4th character is '-' symbol. If it is a space then we don't
  1481. * need to read anything else.
  1482. * @access protected
  1483. * @return string
  1484. */
  1485. protected function get_lines()
  1486. {
  1487. // If the connection is bad, give up straight away
  1488. if (!is_resource($this->smtp_conn)) {
  1489. return '';
  1490. }
  1491. $data = '';
  1492. $endtime = 0;
  1493. stream_set_timeout($this->smtp_conn, $this->Timeout);
  1494. if ($this->Timelimit > 0) {
  1495. $endtime = time() + $this->Timelimit;
  1496. }
  1497. while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
  1498. $str = @fgets($this->smtp_conn, 515);
  1499. $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
  1500. $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
  1501. $data .= $str;
  1502. // If 4th character is a space, we are done reading, break the loop, micro-optimisation over strlen
  1503. if (!isset($str[3]) or (isset($str[3]) and $str[3] == ' ')) {
  1504. break;
  1505. }
  1506. // Timed-out? Log and break
  1507. $info = stream_get_meta_data($this->smtp_conn);
  1508. if ($info['timed_out']) {
  1509. $this->edebug(
  1510. 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
  1511. self::DEBUG_LOWLEVEL
  1512. );
  1513. break;
  1514. }
  1515. // Now check if reads took too long
  1516. if ($endtime and time() > $endtime) {
  1517. $this->edebug(
  1518. 'SMTP -> get_lines(): timelimit reached ('.
  1519. $this->Timelimit . ' sec)',
  1520. self::DEBUG_LOWLEVEL
  1521. );
  1522. break;
  1523. }
  1524. }
  1525. return $data;
  1526. }
  1527. /**
  1528. * Enable or disable VERP address generation.
  1529. * @param boolean $enabled
  1530. */
  1531. public function setVerp($enabled = false)
  1532. {
  1533. $this->do_verp = $enabled;
  1534. }
  1535. /**
  1536. * Get VERP address generation mode.
  1537. * @return boolean
  1538. */
  1539. public function getVerp()
  1540. {
  1541. return $this->do_verp;
  1542. }
  1543. /**
  1544. * Set error messages and codes.
  1545. * @param string $message The error message
  1546. * @param string $detail Further detail on the error
  1547. * @param string $smtp_code An associated SMTP error code
  1548. * @param string $smtp_code_ex Extended SMTP code
  1549. */
  1550. protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
  1551. {
  1552. $this->error = array(
  1553. 'error' => $message,
  1554. 'detail' => $detail,
  1555. 'smtp_code' => $smtp_code,
  1556. 'smtp_code_ex' => $smtp_code_ex
  1557. );
  1558. }
  1559. /**
  1560. * Set debug output method.
  1561. * @param string|callable $method The name of the mechanism to use for debugging output, or a callable to handle it.
  1562. */
  1563. public function setDebugOutput($method = 'echo')
  1564. {
  1565. $this->Debugoutput = $method;
  1566. }
  1567. /**
  1568. * Get debug output method.
  1569. * @return string
  1570. */
  1571. public function getDebugOutput()
  1572. {
  1573. return $this->Debugoutput;
  1574. }
  1575. /**
  1576. * Set debug output level.
  1577. * @param integer $level
  1578. */
  1579. public function setDebugLevel($level = 0)
  1580. {
  1581. $this->do_debug = $level;
  1582. }
  1583. /**
  1584. * Get debug output level.
  1585. * @return integer
  1586. */
  1587. public function getDebugLevel()
  1588. {
  1589. return $this->do_debug;
  1590. }
  1591. /**
  1592. * Set SMTP timeout.
  1593. * @param integer $timeout
  1594. */
  1595. public function setTimeout($timeout = 0)
  1596. {
  1597. $this->Timeout = $timeout;
  1598. }
  1599. /**
  1600. * Get SMTP timeout.
  1601. * @return integer
  1602. */
  1603. public function getTimeout()
  1604. {
  1605. return $this->Timeout;
  1606. }
  1607. /**
  1608. * Reports an error number and string.
  1609. * @param integer $errno The error number returned by PHP.
  1610. * @param string $errmsg The error message returned by PHP.
  1611. */
  1612. protected function errorHandler($errno, $errmsg)
  1613. {
  1614. $notice = 'Connection: Failed to connect to server.';
  1615. $this->setError(
  1616. $notice,
  1617. $errno,
  1618. $errmsg
  1619. );
  1620. $this->edebug(
  1621. $notice . ' Error number ' . $errno . '. "Error notice: ' . $errmsg,
  1622. self::DEBUG_CONNECTION
  1623. );
  1624. }
  1625. /**
  1626. * Will return the ID of the last smtp transaction based on a list of patterns provided
  1627. * in SMTP::$smtp_transaction_id_patterns.
  1628. * If no reply has been received yet, it will return null.
  1629. * If no pattern has been matched, it will return false.
  1630. * @return bool|null|string
  1631. */
  1632. public function getLastTransactionID()
  1633. {
  1634. $reply = $this->getLastReply();
  1635. if (empty($reply)) {
  1636. return null;
  1637. }
  1638. foreach($this->smtp_transaction_id_patterns as $smtp_transaction_id_pattern) {
  1639. if(preg_match($smtp_transaction_id_pattern, $reply, $matches)) {
  1640. return $matches[1];
  1641. }
  1642. }
  1643. return false;
  1644. }
  1645. }
  1646. class PHPMailer
  1647. {
  1648. /**
  1649. * The PHPMailer Version number.
  1650. * @var string
  1651. */
  1652. public $Version = '5.2.17';
  1653. /**
  1654. * Email priority.
  1655. * Options: null (default), 1 = High, 3 = Normal, 5 = low.
  1656. * When null, the header is not set at all.
  1657. * @var integer
  1658. */
  1659. public $Priority = null;
  1660. /**
  1661. * The character set of the message.
  1662. * @var string
  1663. */
  1664. public $CharSet = 'iso-8859-1';
  1665. /**
  1666. * The MIME Content-type of the message.
  1667. * @var string
  1668. */
  1669. public $ContentType = 'text/plain';
  1670. /**
  1671. * The message encoding.
  1672. * Options: "8bit", "7bit", "binary", "base64", and "quoted-printable".
  1673. * @var string
  1674. */
  1675. public $Encoding = '8bit';
  1676. /**
  1677. * Holds the most recent mailer error message.
  1678. * @var string
  1679. */
  1680. public $ErrorInfo = '';
  1681. /**
  1682. * The From email address for the message.
  1683. * @var string
  1684. */
  1685. public $From = 'root@localhost';
  1686. /**
  1687. * The From name of the message.
  1688. * @var string
  1689. */
  1690. public $FromName = 'Root User';
  1691. /**
  1692. * The Sender email (Return-Path) of the message.
  1693. * If not empty, will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  1694. * @var string
  1695. */
  1696. public $Sender = '';
  1697. /**
  1698. * The Return-Path of the message.
  1699. * If empty, it will be set to either From or Sender.
  1700. * @var string
  1701. * @deprecated Email senders should never set a return-path header;
  1702. * it's the receiver's job (RFC5321 section 4.4), so this no longer does anything.
  1703. * @link https://tools.ietf.org/html/rfc5321#section-4.4 RFC5321 reference
  1704. */
  1705. public $ReturnPath = '';
  1706. /**
  1707. * The Subject of the message.
  1708. * @var string
  1709. */
  1710. public $Subject = '';
  1711. /**
  1712. * An HTML or plain text message body.
  1713. * If HTML then call isHTML(true).
  1714. * @var string
  1715. */
  1716. public $Body = '';
  1717. /**
  1718. * The plain-text message body.
  1719. * This body can be read by mail clients that do not have HTML email
  1720. * capability such as mutt & Eudora.
  1721. * Clients that can read HTML will view the normal Body.
  1722. * @var string
  1723. */
  1724. public $AltBody = '';
  1725. /**
  1726. * An iCal message part body.
  1727. * Only supported in simple alt or alt_inline message types
  1728. * To generate iCal events, use the bundled extras/EasyPeasyICS.php class or iCalcreator
  1729. * @link http://sprain.ch/blog/downloads/php-class-easypeasyics-create-ical-files-with-php/
  1730. * @link http://kigkonsult.se/iCalcreator/
  1731. * @var string
  1732. */
  1733. public $Ical = '';
  1734. /**
  1735. * The complete compiled MIME message body.
  1736. * @access protected
  1737. * @var string
  1738. */
  1739. protected $MIMEBody = '';
  1740. /**
  1741. * The complete compiled MIME message headers.
  1742. * @var string
  1743. * @access protected
  1744. */
  1745. protected $MIMEHeader = '';
  1746. /**
  1747. * Extra headers that createHeader() doesn't fold in.
  1748. * @var string
  1749. * @access protected
  1750. */
  1751. protected $mailHeader = '';
  1752. /**
  1753. * Word-wrap the message body to this number of chars.
  1754. * Set to 0 to not wrap. A useful value here is 78, for RFC2822 section 2.1.1 compliance.
  1755. * @var integer
  1756. */
  1757. public $WordWrap = 0;
  1758. /**
  1759. * Which method to use to send mail.
  1760. * Options: "mail", "sendmail", or "smtp".
  1761. * @var string
  1762. */
  1763. public $Mailer = 'mail';
  1764. /**
  1765. * The path to the sendmail program.
  1766. * @var string
  1767. */
  1768. public $Sendmail = '/usr/sbin/sendmail';
  1769. /**
  1770. * Whether mail() uses a fully sendmail-compatible MTA.
  1771. * One which supports sendmail's "-oi -f" options.
  1772. * @var boolean
  1773. */
  1774. public $UseSendmailOptions = true;
  1775. /**
  1776. * Path to PHPMailer plugins.
  1777. * Useful if the SMTP class is not in the PHP include path.
  1778. * @var string
  1779. * @deprecated Should not be needed now there is an autoloader.
  1780. */
  1781. public $PluginDir = '';
  1782. /**
  1783. * The email address that a reading confirmation should be sent to, also known as read receipt.
  1784. * @var string
  1785. */
  1786. public $ConfirmReadingTo = '';
  1787. /**
  1788. * The hostname to use in the Message-ID header and as default HELO string.
  1789. * If empty, PHPMailer attempts to find one with, in order,
  1790. * $_SERVER['SERVER_NAME'], gethostname(), php_uname('n'), or the value
  1791. * 'localhost.localdomain'.
  1792. * @var string
  1793. */
  1794. public $Hostname = '';
  1795. /**
  1796. * An ID to be used in the Message-ID header.
  1797. * If empty, a unique id will be generated.
  1798. * You can set your own, but it must be in the format "<id@domain>",
  1799. * as defined in RFC5322 section 3.6.4 or it will be ignored.
  1800. * @see https://tools.ietf.org/html/rfc5322#section-3.6.4
  1801. * @var string
  1802. */
  1803. public $MessageID = '';
  1804. /**
  1805. * The message Date to be used in the Date header.
  1806. * If empty, the current date will be added.
  1807. * @var string
  1808. */
  1809. public $MessageDate = '';
  1810. /**
  1811. * SMTP hosts.
  1812. * Either a single hostname or multiple semicolon-delimited hostnames.
  1813. * You can also specify a different port
  1814. * for each host by using this format: [hostname:port]
  1815. * (e.g. "smtp1.example.com:25;smtp2.example.com").
  1816. * You can also specify encryption type, for example:
  1817. * (e.g. "tls://smtp1.example.com:587;ssl://smtp2.example.com:465").
  1818. * Hosts will be tried in order.
  1819. * @var string
  1820. */
  1821. public $Host = 'localhost';
  1822. /**
  1823. * The default SMTP server port.
  1824. * @var integer
  1825. * @TODO Why is this needed when the SMTP class takes care of it?
  1826. */
  1827. public $Port = 25;
  1828. /**
  1829. * The SMTP HELO of the message.
  1830. * Default is $Hostname. If $Hostname is empty, PHPMailer attempts to find
  1831. * one with the same method described above for $Hostname.
  1832. * @var string
  1833. * @see PHPMailer::$Hostname
  1834. */
  1835. public $Helo = '';
  1836. /**
  1837. * What kind of encryption to use on the SMTP connection.
  1838. * Options: '', 'ssl' or 'tls'
  1839. * @var string
  1840. */
  1841. public $SMTPSecure = '';
  1842. /**
  1843. * Whether to enable TLS encryption automatically if a server supports it,
  1844. * even if `SMTPSecure` is not set to 'tls'.
  1845. * Be aware that in PHP >= 5.6 this requires that the server's certificates are valid.
  1846. * @var boolean
  1847. */
  1848. public $SMTPAutoTLS = true;
  1849. /**
  1850. * Whether to use SMTP authentication.
  1851. * Uses the Username and Password properties.
  1852. * @var boolean
  1853. * @see PHPMailer::$Username
  1854. * @see PHPMailer::$Password
  1855. */
  1856. public $SMTPAuth = false;
  1857. /**
  1858. * Options array passed to stream_context_create when connecting via SMTP.
  1859. * @var array
  1860. */
  1861. public $SMTPOptions = array();
  1862. /**
  1863. * SMTP username.
  1864. * @var string
  1865. */
  1866. public $Username = '';
  1867. /**
  1868. * SMTP password.
  1869. * @var string
  1870. */
  1871. public $Password = '';
  1872. /**
  1873. * SMTP auth type.
  1874. * Options are CRAM-MD5, LOGIN, PLAIN, NTLM, XOAUTH2, attempted in that order if not specified
  1875. * @var string
  1876. */
  1877. public $AuthType = '';
  1878. /**
  1879. * SMTP realm.
  1880. * Used for NTLM auth
  1881. * @var string
  1882. */
  1883. public $Realm = '';
  1884. /**
  1885. * SMTP workstation.
  1886. * Used for NTLM auth
  1887. * @var string
  1888. */
  1889. public $Workstation = '';
  1890. /**
  1891. * The SMTP server timeout in seconds.
  1892. * Default of 5 minutes (300sec) is from RFC2821 section 4.5.3.2
  1893. * @var integer
  1894. */
  1895. public $Timeout = 300;
  1896. /**
  1897. * SMTP class debug output mode.
  1898. * Debug output level.
  1899. * Options:
  1900. * * `0` No output
  1901. * * `1` Commands
  1902. * * `2` Data and commands
  1903. * * `3` As 2 plus connection status
  1904. * * `4` Low-level data output
  1905. * @var integer
  1906. * @see SMTP::$do_debug
  1907. */
  1908. public $SMTPDebug = 0;
  1909. /**
  1910. * How to handle debug output.
  1911. * Options:
  1912. * * `echo` Output plain-text as-is, appropriate for CLI
  1913. * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output
  1914. * * `error_log` Output to error log as configured in php.ini
  1915. *
  1916. * Alternatively, you can provide a callable expecting two params: a message string and the debug level:
  1917. * <code>
  1918. * $mail->Debugoutput = function($str, $level) {echo "debug level $level; message: $str";};
  1919. * </code>
  1920. * @var string|callable
  1921. * @see SMTP::$Debugoutput
  1922. */
  1923. public $Debugoutput = 'echo';
  1924. /**
  1925. * Whether to keep SMTP connection open after each message.
  1926. * If this is set to true then to close the connection
  1927. * requires an explicit call to smtpClose().
  1928. * @var boolean
  1929. */
  1930. public $SMTPKeepAlive = false;
  1931. /**
  1932. * Whether to split multiple to addresses into multiple messages
  1933. * or send them all in one message.
  1934. * Only supported in `mail` and `sendmail` transports, not in SMTP.
  1935. * @var boolean
  1936. */
  1937. public $SingleTo = false;
  1938. /**
  1939. * Storage for addresses when SingleTo is enabled.
  1940. * @var array
  1941. * @TODO This should really not be public
  1942. */
  1943. public $SingleToArray = array();
  1944. /**
  1945. * Whether to generate VERP addresses on send.
  1946. * Only applicable when sending via SMTP.
  1947. * @link https://en.wikipedia.org/wiki/Variable_envelope_return_path
  1948. * @link http://www.postfix.org/VERP_README.html Postfix VERP info
  1949. * @var boolean
  1950. */
  1951. public $do_verp = false;
  1952. /**
  1953. * Whether to allow sending messages with an empty body.
  1954. * @var boolean
  1955. */
  1956. public $AllowEmpty = false;
  1957. /**
  1958. * The default line ending.
  1959. * @note The default remains "\n". We force CRLF where we know
  1960. * it must be used via self::CRLF.
  1961. * @var string
  1962. */
  1963. public $LE = "\n";
  1964. /**
  1965. * DKIM selector.
  1966. * @var string
  1967. */
  1968. public $DKIM_selector = '';
  1969. /**
  1970. * DKIM Identity.
  1971. * Usually the email address used as the source of the email.
  1972. * @var string
  1973. */
  1974. public $DKIM_identity = '';
  1975. /**
  1976. * DKIM passphrase.
  1977. * Used if your key is encrypted.
  1978. * @var string
  1979. */
  1980. public $DKIM_passphrase = '';
  1981. /**
  1982. * DKIM signing domain name.
  1983. * @example 'example.com'
  1984. * @var string
  1985. */
  1986. public $DKIM_domain = '';
  1987. /**
  1988. * DKIM private key file path.
  1989. * @var string
  1990. */
  1991. public $DKIM_private = '';
  1992. /**
  1993. * DKIM private key string.
  1994. * If set, takes precedence over `$DKIM_private`.
  1995. * @var string
  1996. */
  1997. public $DKIM_private_string = '';
  1998. /**
  1999. * Callback Action function name.
  2000. *
  2001. * The function that handles the result of the send email action.
  2002. * It is called out by send() for each email sent.
  2003. *
  2004. * Value can be any php callable: http://www.php.net/is_callable
  2005. *
  2006. * Parameters:
  2007. * boolean $result result of the send action
  2008. * string $to email address of the recipient
  2009. * string $cc cc email addresses
  2010. * string $bcc bcc email addresses
  2011. * string $subject the subject
  2012. * string $body the email body
  2013. * string $from email address of sender
  2014. * @var string
  2015. */
  2016. public $action_function = '';
  2017. /**
  2018. * What to put in the X-Mailer header.
  2019. * Options: An empty string for PHPMailer default, whitespace for none, or a string to use
  2020. * @var string
  2021. */
  2022. public $XMailer = '';
  2023. /**
  2024. * Which validator to use by default when validating email addresses.
  2025. * May be a callable to inject your own validator, but there are several built-in validators.
  2026. * @see PHPMailer::validateAddress()
  2027. * @var string|callable
  2028. * @static
  2029. */
  2030. public static $validator = 'auto';
  2031. /**
  2032. * An instance of the SMTP sender class.
  2033. * @var SMTP
  2034. * @access protected
  2035. */
  2036. protected $smtp = null;
  2037. /**
  2038. * The array of 'to' names and addresses.
  2039. * @var array
  2040. * @access protected
  2041. */
  2042. protected $to = array();
  2043. /**
  2044. * The array of 'cc' names and addresses.
  2045. * @var array
  2046. * @access protected
  2047. */
  2048. protected $cc = array();
  2049. /**
  2050. * The array of 'bcc' names and addresses.
  2051. * @var array
  2052. * @access protected
  2053. */
  2054. protected $bcc = array();
  2055. /**
  2056. * The array of reply-to names and addresses.
  2057. * @var array
  2058. * @access protected
  2059. */
  2060. protected $ReplyTo = array();
  2061. /**
  2062. * An array of all kinds of addresses.
  2063. * Includes all of $to, $cc, $bcc
  2064. * @var array
  2065. * @access protected
  2066. * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
  2067. */
  2068. protected $all_recipients = array();
  2069. /**
  2070. * An array of names and addresses queued for validation.
  2071. * In send(), valid and non duplicate entries are moved to $all_recipients
  2072. * and one of $to, $cc, or $bcc.
  2073. * This array is used only for addresses with IDN.
  2074. * @var array
  2075. * @access protected
  2076. * @see PHPMailer::$to @see PHPMailer::$cc @see PHPMailer::$bcc
  2077. * @see PHPMailer::$all_recipients
  2078. */
  2079. protected $RecipientsQueue = array();
  2080. /**
  2081. * An array of reply-to names and addresses queued for validation.
  2082. * In send(), valid and non duplicate entries are moved to $ReplyTo.
  2083. * This array is used only for addresses with IDN.
  2084. * @var array
  2085. * @access protected
  2086. * @see PHPMailer::$ReplyTo
  2087. */
  2088. protected $ReplyToQueue = array();
  2089. /**
  2090. * The array of attachments.
  2091. * @var array
  2092. * @access protected
  2093. */
  2094. protected $attachment = array();
  2095. /**
  2096. * The array of custom headers.
  2097. * @var array
  2098. * @access protected
  2099. */
  2100. protected $CustomHeader = array();
  2101. /**
  2102. * The most recent Message-ID (including angular brackets).
  2103. * @var string
  2104. * @access protected
  2105. */
  2106. protected $lastMessageID = '';
  2107. /**
  2108. * The message's MIME type.
  2109. * @var string
  2110. * @access protected
  2111. */
  2112. protected $message_type = '';
  2113. /**
  2114. * The array of MIME boundary strings.
  2115. * @var array
  2116. * @access protected
  2117. */
  2118. protected $boundary = array();
  2119. /**
  2120. * The array of available languages.
  2121. * @var array
  2122. * @access protected
  2123. */
  2124. protected $language = array();
  2125. /**
  2126. * The number of errors encountered.
  2127. * @var integer
  2128. * @access protected
  2129. */
  2130. protected $error_count = 0;
  2131. /**
  2132. * The S/MIME certificate file path.
  2133. * @var string
  2134. * @access protected
  2135. */
  2136. protected $sign_cert_file = '';
  2137. /**
  2138. * The S/MIME key file path.
  2139. * @var string
  2140. * @access protected
  2141. */
  2142. protected $sign_key_file = '';
  2143. /**
  2144. * The optional S/MIME extra certificates ("CA Chain") file path.
  2145. * @var string
  2146. * @access protected
  2147. */
  2148. protected $sign_extracerts_file = '';
  2149. /**
  2150. * The S/MIME password for the key.
  2151. * Used only if the key is encrypted.
  2152. * @var string
  2153. * @access protected
  2154. */
  2155. protected $sign_key_pass = '';
  2156. /**
  2157. * Whether to throw exceptions for errors.
  2158. * @var boolean
  2159. * @access protected
  2160. */
  2161. protected $exceptions = false;
  2162. /**
  2163. * Unique ID used for message ID and boundaries.
  2164. * @var string
  2165. * @access protected
  2166. */
  2167. protected $uniqueid = '';
  2168. /**
  2169. * Error severity: message only, continue processing.
  2170. */
  2171. const STOP_MESSAGE = 0;
  2172. /**
  2173. * Error severity: message, likely ok to continue processing.
  2174. */
  2175. const STOP_CONTINUE = 1;
  2176. /**
  2177. * Error severity: message, plus full stop, critical error reached.
  2178. */
  2179. const STOP_CRITICAL = 2;
  2180. /**
  2181. * SMTP RFC standard line ending.
  2182. */
  2183. const CRLF = "\r\n";
  2184. /**
  2185. * The maximum line length allowed by RFC 2822 section 2.1.1
  2186. * @var integer
  2187. */
  2188. const MAX_LINE_LENGTH = 998;
  2189. /**
  2190. * Constructor.
  2191. * @param boolean $exceptions Should we throw external exceptions?
  2192. */
  2193. public function __construct($exceptions = null)
  2194. {
  2195. if ($exceptions !== null) {
  2196. $this->exceptions = (boolean)$exceptions;
  2197. }
  2198. }
  2199. /**
  2200. * Destructor.
  2201. */
  2202. public function __destruct()
  2203. {
  2204. //Close any open SMTP connection nicely
  2205. $this->smtpClose();
  2206. }
  2207. /**
  2208. * Call mail() in a safe_mode-aware fashion.
  2209. * Also, unless sendmail_path points to sendmail (or something that
  2210. * claims to be sendmail), don't pass params (not a perfect fix,
  2211. * but it will do)
  2212. * @param string $to To
  2213. * @param string $subject Subject
  2214. * @param string $body Message Body
  2215. * @param string $header Additional Header(s)
  2216. * @param string $params Params
  2217. * @access private
  2218. * @return boolean
  2219. */
  2220. private function mailPassthru($to, $subject, $body, $header, $params)
  2221. {
  2222. //Check overloading of mail function to avoid double-encoding
  2223. if (ini_get('mbstring.func_overload') & 1) {
  2224. $subject = $this->secureHeader($subject);
  2225. } else {
  2226. $subject = $this->encodeHeader($this->secureHeader($subject));
  2227. }
  2228. //Can't use additional_parameters in safe_mode
  2229. //@link http://php.net/manual/en/function.mail.php
  2230. if (ini_get('safe_mode') or !$this->UseSendmailOptions or is_null($params)) {
  2231. $result = @mail($to, $subject, $body, $header);
  2232. } else {
  2233. $result = @mail($to, $subject, $body, $header, $params);
  2234. }
  2235. return $result;
  2236. }
  2237. /**
  2238. * Output debugging info via user-defined method.
  2239. * Only generates output if SMTP debug output is enabled (@see SMTP::$do_debug).
  2240. * @see PHPMailer::$Debugoutput
  2241. * @see PHPMailer::$SMTPDebug
  2242. * @param string $str
  2243. */
  2244. protected function edebug($str)
  2245. {
  2246. if ($this->SMTPDebug <= 0) {
  2247. return;
  2248. }
  2249. //Avoid clash with built-in function names
  2250. if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
  2251. call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
  2252. return;
  2253. }
  2254. switch ($this->Debugoutput) {
  2255. case 'error_log':
  2256. //Don't output, just log
  2257. error_log($str);
  2258. break;
  2259. case 'html':
  2260. //Cleans up output a bit for a better looking, HTML-safe output
  2261. echo htmlentities(
  2262. preg_replace('/[\r\n]+/', '', $str),
  2263. ENT_QUOTES,
  2264. 'UTF-8'
  2265. )
  2266. . "<br>\n";
  2267. break;
  2268. case 'echo':
  2269. default:
  2270. //Normalize line breaks
  2271. $str = preg_replace('/\r\n?/ms', "\n", $str);
  2272. echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
  2273. "\n",
  2274. "\n \t ",
  2275. trim($str)
  2276. ) . "\n";
  2277. }
  2278. }
  2279. /**
  2280. * Sets message type to HTML or plain.
  2281. * @param boolean $isHtml True for HTML mode.
  2282. * @return void
  2283. */
  2284. public function isHTML($isHtml = true)
  2285. {
  2286. if ($isHtml) {
  2287. $this->ContentType = 'text/html';
  2288. } else {
  2289. $this->ContentType = 'text/plain';
  2290. }
  2291. }
  2292. /**
  2293. * Send messages using SMTP.
  2294. * @return void
  2295. */
  2296. public function isSMTP()
  2297. {
  2298. $this->Mailer = 'smtp';
  2299. }
  2300. /**
  2301. * Send messages using PHP's mail() function.
  2302. * @return void
  2303. */
  2304. public function isMail()
  2305. {
  2306. $this->Mailer = 'mail';
  2307. }
  2308. /**
  2309. * Send messages using $Sendmail.
  2310. * @return void
  2311. */
  2312. public function isSendmail()
  2313. {
  2314. $ini_sendmail_path = ini_get('sendmail_path');
  2315. if (!stristr($ini_sendmail_path, 'sendmail')) {
  2316. $this->Sendmail = '/usr/sbin/sendmail';
  2317. } else {
  2318. $this->Sendmail = $ini_sendmail_path;
  2319. }
  2320. $this->Mailer = 'sendmail';
  2321. }
  2322. /**
  2323. * Send messages using qmail.
  2324. * @return void
  2325. */
  2326. public function isQmail()
  2327. {
  2328. $ini_sendmail_path = ini_get('sendmail_path');
  2329. if (!stristr($ini_sendmail_path, 'qmail')) {
  2330. $this->Sendmail = '/var/qmail/bin/qmail-inject';
  2331. } else {
  2332. $this->Sendmail = $ini_sendmail_path;
  2333. }
  2334. $this->Mailer = 'qmail';
  2335. }
  2336. /**
  2337. * Add a "To" address.
  2338. * @param string $address The email address to send to
  2339. * @param string $name
  2340. * @return boolean true on success, false if address already used or invalid in some way
  2341. */
  2342. public function addAddress($address, $name = '')
  2343. {
  2344. return $this->addOrEnqueueAnAddress('to', $address, $name);
  2345. }
  2346. /**
  2347. * Add a "CC" address.
  2348. * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
  2349. * @param string $address The email address to send to
  2350. * @param string $name
  2351. * @return boolean true on success, false if address already used or invalid in some way
  2352. */
  2353. public function addCC($address, $name = '')
  2354. {
  2355. return $this->addOrEnqueueAnAddress('cc', $address, $name);
  2356. }
  2357. /**
  2358. * Add a "BCC" address.
  2359. * @note: This function works with the SMTP mailer on win32, not with the "mail" mailer.
  2360. * @param string $address The email address to send to
  2361. * @param string $name
  2362. * @return boolean true on success, false if address already used or invalid in some way
  2363. */
  2364. public function addBCC($address, $name = '')
  2365. {
  2366. return $this->addOrEnqueueAnAddress('bcc', $address, $name);
  2367. }
  2368. /**
  2369. * Add a "Reply-To" address.
  2370. * @param string $address The email address to reply to
  2371. * @param string $name
  2372. * @return boolean true on success, false if address already used or invalid in some way
  2373. */
  2374. public function addReplyTo($address, $name = '')
  2375. {
  2376. return $this->addOrEnqueueAnAddress('Reply-To', $address, $name);
  2377. }
  2378. /**
  2379. * Add an address to one of the recipient arrays or to the ReplyTo array. Because PHPMailer
  2380. * can't validate addresses with an IDN without knowing the PHPMailer::$CharSet (that can still
  2381. * be modified after calling this function), addition of such addresses is delayed until send().
  2382. * Addresses that have been added already return false, but do not throw exceptions.
  2383. * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
  2384. * @param string $address The email address to send, resp. to reply to
  2385. * @param string $name
  2386. * @throws phpmailerException
  2387. * @return boolean true on success, false if address already used or invalid in some way
  2388. * @access protected
  2389. */
  2390. protected function addOrEnqueueAnAddress($kind, $address, $name)
  2391. {
  2392. $address = trim($address);
  2393. $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  2394. if (($pos = strrpos($address, '@')) === false) {
  2395. // At-sign is misssing.
  2396. $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
  2397. $this->setError($error_message);
  2398. $this->edebug($error_message);
  2399. if ($this->exceptions) {
  2400. throw new phpmailerException($error_message);
  2401. }
  2402. return false;
  2403. }
  2404. $params = array($kind, $address, $name);
  2405. // Enqueue addresses with IDN until we know the PHPMailer::$CharSet.
  2406. if ($this->has8bitChars(substr($address, ++$pos)) and $this->idnSupported()) {
  2407. if ($kind != 'Reply-To') {
  2408. if (!array_key_exists($address, $this->RecipientsQueue)) {
  2409. $this->RecipientsQueue[$address] = $params;
  2410. return true;
  2411. }
  2412. } else {
  2413. if (!array_key_exists($address, $this->ReplyToQueue)) {
  2414. $this->ReplyToQueue[$address] = $params;
  2415. return true;
  2416. }
  2417. }
  2418. return false;
  2419. }
  2420. // Immediately add standard addresses without IDN.
  2421. return call_user_func_array(array($this, 'addAnAddress'), $params);
  2422. }
  2423. /**
  2424. * Add an address to one of the recipient arrays or to the ReplyTo array.
  2425. * Addresses that have been added already return false, but do not throw exceptions.
  2426. * @param string $kind One of 'to', 'cc', 'bcc', or 'ReplyTo'
  2427. * @param string $address The email address to send, resp. to reply to
  2428. * @param string $name
  2429. * @throws phpmailerException
  2430. * @return boolean true on success, false if address already used or invalid in some way
  2431. * @access protected
  2432. */
  2433. protected function addAnAddress($kind, $address, $name = '')
  2434. {
  2435. if (!in_array($kind, array('to', 'cc', 'bcc', 'Reply-To'))) {
  2436. $error_message = $this->lang('Invalid recipient kind: ') . $kind;
  2437. $this->setError($error_message);
  2438. $this->edebug($error_message);
  2439. if ($this->exceptions) {
  2440. throw new phpmailerException($error_message);
  2441. }
  2442. return false;
  2443. }
  2444. if (!$this->validateAddress($address)) {
  2445. $error_message = $this->lang('invalid_address') . " (addAnAddress $kind): $address";
  2446. $this->setError($error_message);
  2447. $this->edebug($error_message);
  2448. if ($this->exceptions) {
  2449. throw new phpmailerException($error_message);
  2450. }
  2451. return false;
  2452. }
  2453. if ($kind != 'Reply-To') {
  2454. if (!array_key_exists(strtolower($address), $this->all_recipients)) {
  2455. array_push($this->$kind, array($address, $name));
  2456. $this->all_recipients[strtolower($address)] = true;
  2457. return true;
  2458. }
  2459. } else {
  2460. if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
  2461. $this->ReplyTo[strtolower($address)] = array($address, $name);
  2462. return true;
  2463. }
  2464. }
  2465. return false;
  2466. }
  2467. /**
  2468. * Parse and validate a string containing one or more RFC822-style comma-separated email addresses
  2469. * of the form "display name <address>" into an array of name/address pairs.
  2470. * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available.
  2471. * Note that quotes in the name part are removed.
  2472. * @param string $addrstr The address list string
  2473. * @param bool $useimap Whether to use the IMAP extension to parse the list
  2474. * @return array
  2475. * @link http://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation
  2476. */
  2477. public function parseAddresses($addrstr, $useimap = true)
  2478. {
  2479. $addresses = array();
  2480. if ($useimap and function_exists('imap_rfc822_parse_adrlist')) {
  2481. //Use this built-in parser if it's available
  2482. $list = imap_rfc822_parse_adrlist($addrstr, '');
  2483. foreach ($list as $address) {
  2484. if ($address->host != '.SYNTAX-ERROR.') {
  2485. if ($this->validateAddress($address->mailbox . '@' . $address->host)) {
  2486. $addresses[] = array(
  2487. 'name' => (property_exists($address, 'personal') ? $address->personal : ''),
  2488. 'address' => $address->mailbox . '@' . $address->host
  2489. );
  2490. }
  2491. }
  2492. }
  2493. } else {
  2494. //Use this simpler parser
  2495. $list = explode(',', $addrstr);
  2496. foreach ($list as $address) {
  2497. $address = trim($address);
  2498. //Is there a separate name part?
  2499. if (strpos($address, '<') === false) {
  2500. //No separate name, just use the whole thing
  2501. if ($this->validateAddress($address)) {
  2502. $addresses[] = array(
  2503. 'name' => '',
  2504. 'address' => $address
  2505. );
  2506. }
  2507. } else {
  2508. list($name, $email) = explode('<', $address);
  2509. $email = trim(str_replace('>', '', $email));
  2510. if ($this->validateAddress($email)) {
  2511. $addresses[] = array(
  2512. 'name' => trim(str_replace(array('"', "'"), '', $name)),
  2513. 'address' => $email
  2514. );
  2515. }
  2516. }
  2517. }
  2518. }
  2519. return $addresses;
  2520. }
  2521. /**
  2522. * Set the From and FromName properties.
  2523. * @param string $address
  2524. * @param string $name
  2525. * @param boolean $auto Whether to also set the Sender address, defaults to true
  2526. * @throws phpmailerException
  2527. * @return boolean
  2528. */
  2529. public function setFrom($address, $name = '', $auto = true)
  2530. {
  2531. $address = trim($address);
  2532. $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  2533. // Don't validate now addresses with IDN. Will be done in send().
  2534. if (($pos = strrpos($address, '@')) === false or
  2535. (!$this->has8bitChars(substr($address, ++$pos)) or !$this->idnSupported()) and
  2536. !$this->validateAddress($address)) {
  2537. $error_message = $this->lang('invalid_address') . " (setFrom) $address";
  2538. $this->setError($error_message);
  2539. $this->edebug($error_message);
  2540. if ($this->exceptions) {
  2541. throw new phpmailerException($error_message);
  2542. }
  2543. return false;
  2544. }
  2545. $this->From = $address;
  2546. $this->FromName = $name;
  2547. if ($auto) {
  2548. if (empty($this->Sender)) {
  2549. $this->Sender = $address;
  2550. }
  2551. }
  2552. return true;
  2553. }
  2554. /**
  2555. * Return the Message-ID header of the last email.
  2556. * Technically this is the value from the last time the headers were created,
  2557. * but it's also the message ID of the last sent message except in
  2558. * pathological cases.
  2559. * @return string
  2560. */
  2561. public function getLastMessageID()
  2562. {
  2563. return $this->lastMessageID;
  2564. }
  2565. /**
  2566. * Check that a string looks like an email address.
  2567. * @param string $address The email address to check
  2568. * @param string|callable $patternselect A selector for the validation pattern to use :
  2569. * * `auto` Pick best pattern automatically;
  2570. * * `pcre8` Use the squiloople.com pattern, requires PCRE > 8.0, PHP >= 5.3.2, 5.2.14;
  2571. * * `pcre` Use old PCRE implementation;
  2572. * * `php` Use PHP built-in FILTER_VALIDATE_EMAIL;
  2573. * * `html5` Use the pattern given by the HTML5 spec for 'email' type form input elements.
  2574. * * `noregex` Don't use a regex: super fast, really dumb.
  2575. * Alternatively you may pass in a callable to inject your own validator, for example:
  2576. * PHPMailer::validateAddress('user@example.com', function($address) {
  2577. * return (strpos($address, '@') !== false);
  2578. * });
  2579. * You can also set the PHPMailer::$validator static to a callable, allowing built-in methods to use your validator.
  2580. * @return boolean
  2581. * @static
  2582. * @access public
  2583. */
  2584. public static function validateAddress($address, $patternselect = null)
  2585. {
  2586. if (is_null($patternselect)) {
  2587. $patternselect = self::$validator;
  2588. }
  2589. if (is_callable($patternselect)) {
  2590. return call_user_func($patternselect, $address);
  2591. }
  2592. //Reject line breaks in addresses; it's valid RFC5322, but not RFC5321
  2593. if (strpos($address, "\n") !== false or strpos($address, "\r") !== false) {
  2594. return false;
  2595. }
  2596. if (!$patternselect or $patternselect == 'auto') {
  2597. //Check this constant first so it works when extension_loaded() is disabled by safe mode
  2598. //Constant was added in PHP 5.2.4
  2599. if (defined('PCRE_VERSION')) {
  2600. //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
  2601. if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
  2602. $patternselect = 'pcre8';
  2603. } else {
  2604. $patternselect = 'pcre';
  2605. }
  2606. } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
  2607. //Fall back to older PCRE
  2608. $patternselect = 'pcre';
  2609. } else {
  2610. //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
  2611. if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
  2612. $patternselect = 'php';
  2613. } else {
  2614. $patternselect = 'noregex';
  2615. }
  2616. }
  2617. }
  2618. switch ($patternselect) {
  2619. case 'pcre8':
  2620. /**
  2621. * Uses the same RFC5322 regex on which FILTER_VALIDATE_EMAIL is based, but allows dotless domains.
  2622. * @link http://squiloople.com/2009/12/20/email-address-validation/
  2623. * @copyright 2009-2010 Michael Rushton
  2624. * Feel free to use and redistribute this code. But please keep this copyright notice.
  2625. */
  2626. return (boolean)preg_match(
  2627. '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
  2628. '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
  2629. '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
  2630. '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
  2631. '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
  2632. '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
  2633. '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
  2634. '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
  2635. '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
  2636. $address
  2637. );
  2638. case 'pcre':
  2639. //An older regex that doesn't need a recent PCRE
  2640. return (boolean)preg_match(
  2641. '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
  2642. '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
  2643. '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
  2644. '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
  2645. '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
  2646. '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
  2647. '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
  2648. '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
  2649. '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
  2650. '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
  2651. $address
  2652. );
  2653. case 'html5':
  2654. /**
  2655. * This is the pattern used in the HTML5 spec for validation of 'email' type form input elements.
  2656. * @link http://www.whatwg.org/specs/web-apps/current-work/#e-mail-state-(type=email)
  2657. */
  2658. return (boolean)preg_match(
  2659. '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
  2660. '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
  2661. $address
  2662. );
  2663. case 'noregex':
  2664. //No PCRE! Do something _very_ approximate!
  2665. //Check the address is 3 chars or longer and contains an @ that's not the first or last char
  2666. return (strlen($address) >= 3
  2667. and strpos($address, '@') >= 1
  2668. and strpos($address, '@') != strlen($address) - 1);
  2669. case 'php':
  2670. default:
  2671. return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
  2672. }
  2673. }
  2674. /**
  2675. * Tells whether IDNs (Internationalized Domain Names) are supported or not. This requires the
  2676. * "intl" and "mbstring" PHP extensions.
  2677. * @return bool "true" if required functions for IDN support are present
  2678. */
  2679. public function idnSupported()
  2680. {
  2681. // @TODO: Write our own "idn_to_ascii" function for PHP <= 5.2.
  2682. return function_exists('idn_to_ascii') and function_exists('mb_convert_encoding');
  2683. }
  2684. /**
  2685. * Converts IDN in given email address to its ASCII form, also known as punycode, if possible.
  2686. * Important: Address must be passed in same encoding as currently set in PHPMailer::$CharSet.
  2687. * This function silently returns unmodified address if:
  2688. * - No conversion is necessary (i.e. domain name is not an IDN, or is already in ASCII form)
  2689. * - Conversion to punycode is impossible (e.g. required PHP functions are not available)
  2690. * or fails for any reason (e.g. domain has characters not allowed in an IDN)
  2691. * @see PHPMailer::$CharSet
  2692. * @param string $address The email address to convert
  2693. * @return string The encoded address in ASCII form
  2694. */
  2695. public function punyencodeAddress($address)
  2696. {
  2697. // Verify we have required functions, CharSet, and at-sign.
  2698. if ($this->idnSupported() and
  2699. !empty($this->CharSet) and
  2700. ($pos = strrpos($address, '@')) !== false) {
  2701. $domain = substr($address, ++$pos);
  2702. // Verify CharSet string is a valid one, and domain properly encoded in this CharSet.
  2703. if ($this->has8bitChars($domain) and @mb_check_encoding($domain, $this->CharSet)) {
  2704. $domain = mb_convert_encoding($domain, 'UTF-8', $this->CharSet);
  2705. if (($punycode = defined('INTL_IDNA_VARIANT_UTS46') ?
  2706. idn_to_ascii($domain, 0, INTL_IDNA_VARIANT_UTS46) :
  2707. idn_to_ascii($domain)) !== false) {
  2708. return substr($address, 0, $pos) . $punycode;
  2709. }
  2710. }
  2711. }
  2712. return $address;
  2713. }
  2714. /**
  2715. * Create a message and send it.
  2716. * Uses the sending method specified by $Mailer.
  2717. * @throws phpmailerException
  2718. * @return boolean false on error - See the ErrorInfo property for details of the error.
  2719. */
  2720. public function send()
  2721. {
  2722. try {
  2723. if (!$this->preSend()) {
  2724. return false;
  2725. }
  2726. return $this->postSend();
  2727. } catch (phpmailerException $exc) {
  2728. $this->mailHeader = '';
  2729. $this->setError($exc->getMessage());
  2730. if ($this->exceptions) {
  2731. throw $exc;
  2732. }
  2733. return false;
  2734. }
  2735. }
  2736. /**
  2737. * Prepare a message for sending.
  2738. * @throws phpmailerException
  2739. * @return boolean
  2740. */
  2741. public function preSend()
  2742. {
  2743. try {
  2744. $this->error_count = 0; // Reset errors
  2745. $this->mailHeader = '';
  2746. // Dequeue recipient and Reply-To addresses with IDN
  2747. foreach (array_merge($this->RecipientsQueue, $this->ReplyToQueue) as $params) {
  2748. $params[1] = $this->punyencodeAddress($params[1]);
  2749. call_user_func_array(array($this, 'addAnAddress'), $params);
  2750. }
  2751. if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
  2752. throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
  2753. }
  2754. // Validate From, Sender, and ConfirmReadingTo addresses
  2755. foreach (array('From', 'Sender', 'ConfirmReadingTo') as $address_kind) {
  2756. $this->$address_kind = trim($this->$address_kind);
  2757. if (empty($this->$address_kind)) {
  2758. continue;
  2759. }
  2760. $this->$address_kind = $this->punyencodeAddress($this->$address_kind);
  2761. if (!$this->validateAddress($this->$address_kind)) {
  2762. $error_message = $this->lang('invalid_address') . ' (punyEncode) ' . $this->$address_kind;
  2763. $this->setError($error_message);
  2764. $this->edebug($error_message);
  2765. if ($this->exceptions) {
  2766. throw new phpmailerException($error_message);
  2767. }
  2768. return false;
  2769. }
  2770. }
  2771. // Set whether the message is multipart/alternative
  2772. if ($this->alternativeExists()) {
  2773. $this->ContentType = 'multipart/alternative';
  2774. }
  2775. $this->setMessageType();
  2776. // Refuse to send an empty message unless we are specifically allowing it
  2777. if (!$this->AllowEmpty and empty($this->Body)) {
  2778. throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
  2779. }
  2780. // Create body before headers in case body makes changes to headers (e.g. altering transfer encoding)
  2781. $this->MIMEHeader = '';
  2782. $this->MIMEBody = $this->createBody();
  2783. // createBody may have added some headers, so retain them
  2784. $tempheaders = $this->MIMEHeader;
  2785. $this->MIMEHeader = $this->createHeader();
  2786. $this->MIMEHeader .= $tempheaders;
  2787. // To capture the complete message when using mail(), create
  2788. // an extra header list which createHeader() doesn't fold in
  2789. if ($this->Mailer == 'mail') {
  2790. if (count($this->to) > 0) {
  2791. $this->mailHeader .= $this->addrAppend('To', $this->to);
  2792. } else {
  2793. $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
  2794. }
  2795. $this->mailHeader .= $this->headerLine(
  2796. 'Subject',
  2797. $this->encodeHeader($this->secureHeader(trim($this->Subject)))
  2798. );
  2799. }
  2800. // Sign with DKIM if enabled
  2801. if (!empty($this->DKIM_domain)
  2802. && !empty($this->DKIM_selector)
  2803. && (!empty($this->DKIM_private_string)
  2804. || (!empty($this->DKIM_private) && file_exists($this->DKIM_private))
  2805. )
  2806. ) {
  2807. $header_dkim = $this->DKIM_Add(
  2808. $this->MIMEHeader . $this->mailHeader,
  2809. $this->encodeHeader($this->secureHeader($this->Subject)),
  2810. $this->MIMEBody
  2811. );
  2812. $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
  2813. str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
  2814. }
  2815. return true;
  2816. } catch (phpmailerException $exc) {
  2817. $this->setError($exc->getMessage());
  2818. if ($this->exceptions) {
  2819. throw $exc;
  2820. }
  2821. return false;
  2822. }
  2823. }
  2824. /**
  2825. * Actually send a message.
  2826. * Send the email via the selected mechanism
  2827. * @throws phpmailerException
  2828. * @return boolean
  2829. */
  2830. public function postSend()
  2831. {
  2832. try {
  2833. // Choose the mailer and send through it
  2834. switch ($this->Mailer) {
  2835. case 'sendmail':
  2836. case 'qmail':
  2837. return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
  2838. case 'smtp':
  2839. return $this->smtpSend($this->MIMEHeader, $this->MIMEBody);
  2840. case 'mail':
  2841. return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
  2842. default:
  2843. $sendMethod = $this->Mailer.'Send';
  2844. if (method_exists($this, $sendMethod)) {
  2845. return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
  2846. }
  2847. return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
  2848. }
  2849. } catch (phpmailerException $exc) {
  2850. $this->setError($exc->getMessage());
  2851. $this->edebug($exc->getMessage());
  2852. if ($this->exceptions) {
  2853. throw $exc;
  2854. }
  2855. }
  2856. return false;
  2857. }
  2858. /**
  2859. * Send mail using the $Sendmail program.
  2860. * @param string $header The message headers
  2861. * @param string $body The message body
  2862. * @see PHPMailer::$Sendmail
  2863. * @throws phpmailerException
  2864. * @access protected
  2865. * @return boolean
  2866. */
  2867. protected function sendmailSend($header, $body)
  2868. {
  2869. if ($this->Sender != '') {
  2870. if ($this->Mailer == 'qmail') {
  2871. $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  2872. } else {
  2873. $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  2874. }
  2875. } else {
  2876. if ($this->Mailer == 'qmail') {
  2877. $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
  2878. } else {
  2879. $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
  2880. }
  2881. }
  2882. if ($this->SingleTo) {
  2883. foreach ($this->SingleToArray as $toAddr) {
  2884. if (!@$mail = popen($sendmail, 'w')) {
  2885. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  2886. }
  2887. fputs($mail, 'To: ' . $toAddr . "\n");
  2888. fputs($mail, $header);
  2889. fputs($mail, $body);
  2890. $result = pclose($mail);
  2891. $this->doCallback(
  2892. ($result == 0),
  2893. array($toAddr),
  2894. $this->cc,
  2895. $this->bcc,
  2896. $this->Subject,
  2897. $body,
  2898. $this->From
  2899. );
  2900. if ($result != 0) {
  2901. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  2902. }
  2903. }
  2904. } else {
  2905. if (!@$mail = popen($sendmail, 'w')) {
  2906. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  2907. }
  2908. fputs($mail, $header);
  2909. fputs($mail, $body);
  2910. $result = pclose($mail);
  2911. $this->doCallback(
  2912. ($result == 0),
  2913. $this->to,
  2914. $this->cc,
  2915. $this->bcc,
  2916. $this->Subject,
  2917. $body,
  2918. $this->From
  2919. );
  2920. if ($result != 0) {
  2921. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  2922. }
  2923. }
  2924. return true;
  2925. }
  2926. /**
  2927. * Send mail using the PHP mail() function.
  2928. * @param string $header The message headers
  2929. * @param string $body The message body
  2930. * @link http://www.php.net/manual/en/book.mail.php
  2931. * @throws phpmailerException
  2932. * @access protected
  2933. * @return boolean
  2934. */
  2935. protected function mailSend($header, $body)
  2936. {
  2937. $toArr = array();
  2938. foreach ($this->to as $toaddr) {
  2939. $toArr[] = $this->addrFormat($toaddr);
  2940. }
  2941. $to = implode(', ', $toArr);
  2942. $params = null;
  2943. //This sets the SMTP envelope sender which gets turned into a return-path header by the receiver
  2944. if (!empty($this->Sender)) {
  2945. $params = sprintf('-f%s', $this->Sender);
  2946. }
  2947. if ($this->Sender != '' and !ini_get('safe_mode')) {
  2948. $old_from = ini_get('sendmail_from');
  2949. ini_set('sendmail_from', $this->Sender);
  2950. }
  2951. $result = false;
  2952. if ($this->SingleTo and count($toArr) > 1) {
  2953. foreach ($toArr as $toAddr) {
  2954. $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
  2955. $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
  2956. }
  2957. } else {
  2958. $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
  2959. $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
  2960. }
  2961. if (isset($old_from)) {
  2962. ini_set('sendmail_from', $old_from);
  2963. }
  2964. if (!$result) {
  2965. throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
  2966. }
  2967. return true;
  2968. }
  2969. /**
  2970. * Get an instance to use for SMTP operations.
  2971. * Override this function to load your own SMTP implementation
  2972. * @return SMTP
  2973. */
  2974. public function getSMTPInstance()
  2975. {
  2976. if (!is_object($this->smtp)) {
  2977. $this->smtp = new SMTP;
  2978. }
  2979. return $this->smtp;
  2980. }
  2981. /**
  2982. * Send mail via SMTP.
  2983. * Returns false if there is a bad MAIL FROM, RCPT, or DATA input.
  2984. * Uses the PHPMailerSMTP class by default.
  2985. * @see PHPMailer::getSMTPInstance() to use a different class.
  2986. * @param string $header The message headers
  2987. * @param string $body The message body
  2988. * @throws phpmailerException
  2989. * @uses SMTP
  2990. * @access protected
  2991. * @return boolean
  2992. */
  2993. protected function smtpSend($header, $body)
  2994. {
  2995. $bad_rcpt = array();
  2996. if (!$this->smtpConnect($this->SMTPOptions)) {
  2997. throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
  2998. }
  2999. if ('' == $this->Sender) {
  3000. $smtp_from = $this->From;
  3001. } else {
  3002. $smtp_from = $this->Sender;
  3003. }
  3004. if (!$this->smtp->mail($smtp_from)) {
  3005. $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
  3006. throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
  3007. }
  3008. // Attempt to send to all recipients
  3009. foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
  3010. foreach ($togroup as $to) {
  3011. if (!$this->smtp->recipient($to[0])) {
  3012. $error = $this->smtp->getError();
  3013. $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
  3014. $isSent = false;
  3015. } else {
  3016. $isSent = true;
  3017. }
  3018. $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
  3019. }
  3020. }
  3021. // Only send the DATA command if we have viable recipients
  3022. if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
  3023. throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
  3024. }
  3025. if ($this->SMTPKeepAlive) {
  3026. $this->smtp->reset();
  3027. } else {
  3028. $this->smtp->quit();
  3029. $this->smtp->close();
  3030. }
  3031. //Create error message for any bad addresses
  3032. if (count($bad_rcpt) > 0) {
  3033. $errstr = '';
  3034. foreach ($bad_rcpt as $bad) {
  3035. $errstr .= $bad['to'] . ': ' . $bad['error'];
  3036. }
  3037. throw new phpmailerException(
  3038. $this->lang('recipients_failed') . $errstr,
  3039. self::STOP_CONTINUE
  3040. );
  3041. }
  3042. return true;
  3043. }
  3044. /**
  3045. * Initiate a connection to an SMTP server.
  3046. * Returns false if the operation failed.
  3047. * @param array $options An array of options compatible with stream_context_create()
  3048. * @uses SMTP
  3049. * @access public
  3050. * @throws phpmailerException
  3051. * @return boolean
  3052. */
  3053. public function smtpConnect($options = null)
  3054. {
  3055. if (is_null($this->smtp)) {
  3056. $this->smtp = $this->getSMTPInstance();
  3057. }
  3058. //If no options are provided, use whatever is set in the instance
  3059. if (is_null($options)) {
  3060. $options = $this->SMTPOptions;
  3061. }
  3062. // Already connected?
  3063. if ($this->smtp->connected()) {
  3064. return true;
  3065. }
  3066. $this->smtp->setTimeout($this->Timeout);
  3067. $this->smtp->setDebugLevel($this->SMTPDebug);
  3068. $this->smtp->setDebugOutput($this->Debugoutput);
  3069. $this->smtp->setVerp($this->do_verp);
  3070. $hosts = explode(';', $this->Host);
  3071. $lastexception = null;
  3072. foreach ($hosts as $hostentry) {
  3073. $hostinfo = array();
  3074. if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9:\[\]\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)){
  3075. // Not a valid host entry
  3076. continue;
  3077. }
  3078. // $hostinfo[2]: optional ssl or tls prefix
  3079. // $hostinfo[3]: the hostname
  3080. // $hostinfo[4]: optional port number
  3081. // The host string prefix can temporarily override the current setting for SMTPSecure
  3082. // If it's not specified, the default value is used
  3083. $prefix = '';
  3084. $secure = $this->SMTPSecure;
  3085. $tls = ($this->SMTPSecure == 'tls');
  3086. if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
  3087. $prefix = 'ssl://';
  3088. $tls = false; // Can't have SSL and TLS at the same time
  3089. $secure = 'ssl';
  3090. } elseif ($hostinfo[2] == 'tls') {
  3091. $tls = true;
  3092. // tls doesn't use a prefix
  3093. $secure = 'tls';
  3094. }
  3095. //Do we need the OpenSSL extension?
  3096. $sslext = defined('OPENSSL_ALGO_SHA1');
  3097. if ('tls' === $secure or 'ssl' === $secure) {
  3098. //Check for an OpenSSL constant rather than using extension_loaded, which is sometimes disabled
  3099. if (!$sslext) {
  3100. throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
  3101. }
  3102. }
  3103. $host = $hostinfo[3];
  3104. $port = $this->Port;
  3105. $tport = (integer)$hostinfo[4];
  3106. if ($tport > 0 and $tport < 65536) {
  3107. $port = $tport;
  3108. }
  3109. if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
  3110. try {
  3111. if ($this->Helo) {
  3112. $hello = $this->Helo;
  3113. } else {
  3114. $hello = $this->serverHostname();
  3115. }
  3116. $this->smtp->hello($hello);
  3117. //Automatically enable TLS encryption if:
  3118. // * it's not disabled
  3119. // * we have openssl extension
  3120. // * we are not already using SSL
  3121. // * the server offers STARTTLS
  3122. if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
  3123. $tls = true;
  3124. }
  3125. if ($tls) {
  3126. if (!$this->smtp->startTLS()) {
  3127. throw new phpmailerException($this->lang('connect_host'));
  3128. }
  3129. // We must resend EHLO after TLS negotiation
  3130. $this->smtp->hello($hello);
  3131. }
  3132. if ($this->SMTPAuth) {
  3133. if (!$this->smtp->authenticate(
  3134. $this->Username,
  3135. $this->Password,
  3136. $this->AuthType,
  3137. $this->Realm,
  3138. $this->Workstation
  3139. )
  3140. ) {
  3141. throw new phpmailerException($this->lang('authenticate'));
  3142. }
  3143. }
  3144. return true;
  3145. } catch (phpmailerException $exc) {
  3146. $lastexception = $exc;
  3147. $this->edebug($exc->getMessage());
  3148. // We must have connected, but then failed TLS or Auth, so close connection nicely
  3149. $this->smtp->quit();
  3150. }
  3151. }
  3152. }
  3153. // If we get here, all connection attempts have failed, so close connection hard
  3154. $this->smtp->close();
  3155. // As we've caught all exceptions, just report whatever the last one was
  3156. if ($this->exceptions and !is_null($lastexception)) {
  3157. throw $lastexception;
  3158. }
  3159. return false;
  3160. }
  3161. /**
  3162. * Close the active SMTP session if one exists.
  3163. * @return void
  3164. */
  3165. public function smtpClose()
  3166. {
  3167. if (is_a($this->smtp, 'SMTP')) {
  3168. if ($this->smtp->connected()) {
  3169. $this->smtp->quit();
  3170. $this->smtp->close();
  3171. }
  3172. }
  3173. }
  3174. /**
  3175. * Set the language for error messages.
  3176. * Returns false if it cannot load the language file.
  3177. * The default language is English.
  3178. * @param string $langcode ISO 639-1 2-character language code (e.g. French is "fr")
  3179. * @param string $lang_path Path to the language file directory, with trailing separator (slash)
  3180. * @return boolean
  3181. * @access public
  3182. */
  3183. public function setLanguage($langcode = 'en', $lang_path = '')
  3184. {
  3185. // Backwards compatibility for renamed language codes
  3186. $renamed_langcodes = array(
  3187. 'br' => 'pt_br',
  3188. 'cz' => 'cs',
  3189. 'dk' => 'da',
  3190. 'no' => 'nb',
  3191. 'se' => 'sv',
  3192. );
  3193. if (isset($renamed_langcodes[$langcode])) {
  3194. $langcode = $renamed_langcodes[$langcode];
  3195. }
  3196. // Define full set of translatable strings in English
  3197. $PHPMAILER_LANG = array(
  3198. 'authenticate' => 'SMTP Error: Could not authenticate.',
  3199. 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
  3200. 'data_not_accepted' => 'SMTP Error: data not accepted.',
  3201. 'empty_message' => 'Message body empty',
  3202. 'encoding' => 'Unknown encoding: ',
  3203. 'execute' => 'Could not execute: ',
  3204. 'file_access' => 'Could not access file: ',
  3205. 'file_open' => 'File Error: Could not open file: ',
  3206. 'from_failed' => 'The following From address failed: ',
  3207. 'instantiate' => 'Could not instantiate mail function.',
  3208. 'invalid_address' => 'Invalid address: ',
  3209. 'mailer_not_supported' => ' mailer is not supported.',
  3210. 'provide_address' => 'You must provide at least one recipient email address.',
  3211. 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
  3212. 'signing' => 'Signing Error: ',
  3213. 'smtp_connect_failed' => 'SMTP connect() failed.',
  3214. 'smtp_error' => 'SMTP server error: ',
  3215. 'variable_set' => 'Cannot set or reset variable: ',
  3216. 'extension_missing' => 'Extension missing: '
  3217. );
  3218. if (empty($lang_path)) {
  3219. // Calculate an absolute path so it can work if CWD is not here
  3220. $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
  3221. }
  3222. //Validate $langcode
  3223. if (!preg_match('/^[a-z]{2}(?:_[a-zA-Z]{2})?$/', $langcode)) {
  3224. $langcode = 'en';
  3225. }
  3226. $foundlang = true;
  3227. $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
  3228. // There is no English translation file
  3229. if ($langcode != 'en') {
  3230. // Make sure language file path is readable
  3231. if (!is_readable($lang_file)) {
  3232. $foundlang = false;
  3233. } else {
  3234. // Overwrite language-specific strings.
  3235. // This way we'll never have missing translation keys.
  3236. $foundlang = include $lang_file;
  3237. }
  3238. }
  3239. $this->language = $PHPMAILER_LANG;
  3240. return (boolean)$foundlang; // Returns false if language not found
  3241. }
  3242. /**
  3243. * Get the array of strings for the current language.
  3244. * @return array
  3245. */
  3246. public function getTranslations()
  3247. {
  3248. return $this->language;
  3249. }
  3250. /**
  3251. * Create recipient headers.
  3252. * @access public
  3253. * @param string $type
  3254. * @param array $addr An array of recipient,
  3255. * where each recipient is a 2-element indexed array with element 0 containing an address
  3256. * and element 1 containing a name, like:
  3257. * array(array('joe@example.com', 'Joe User'), array('zoe@example.com', 'Zoe User'))
  3258. * @return string
  3259. */
  3260. public function addrAppend($type, $addr)
  3261. {
  3262. $addresses = array();
  3263. foreach ($addr as $address) {
  3264. $addresses[] = $this->addrFormat($address);
  3265. }
  3266. return $type . ': ' . implode(', ', $addresses) . $this->LE;
  3267. }
  3268. /**
  3269. * Format an address for use in a message header.
  3270. * @access public
  3271. * @param array $addr A 2-element indexed array, element 0 containing an address, element 1 containing a name
  3272. * like array('joe@example.com', 'Joe User')
  3273. * @return string
  3274. */
  3275. public function addrFormat($addr)
  3276. {
  3277. if (empty($addr[1])) { // No name provided
  3278. return $this->secureHeader($addr[0]);
  3279. } else {
  3280. return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
  3281. $addr[0]
  3282. ) . '>';
  3283. }
  3284. }
  3285. /**
  3286. * Word-wrap message.
  3287. * For use with mailers that do not automatically perform wrapping
  3288. * and for quoted-printable encoded messages.
  3289. * Original written by philippe.
  3290. * @param string $message The message to wrap
  3291. * @param integer $length The line length to wrap to
  3292. * @param boolean $qp_mode Whether to run in Quoted-Printable mode
  3293. * @access public
  3294. * @return string
  3295. */
  3296. public function wrapText($message, $length, $qp_mode = false)
  3297. {
  3298. if ($qp_mode) {
  3299. $soft_break = sprintf(' =%s', $this->LE);
  3300. } else {
  3301. $soft_break = $this->LE;
  3302. }
  3303. // If utf-8 encoding is used, we will need to make sure we don't
  3304. // split multibyte characters when we wrap
  3305. $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
  3306. $lelen = strlen($this->LE);
  3307. $crlflen = strlen(self::CRLF);
  3308. $message = $this->fixEOL($message);
  3309. //Remove a trailing line break
  3310. if (substr($message, -$lelen) == $this->LE) {
  3311. $message = substr($message, 0, -$lelen);
  3312. }
  3313. //Split message into lines
  3314. $lines = explode($this->LE, $message);
  3315. //Message will be rebuilt in here
  3316. $message = '';
  3317. foreach ($lines as $line) {
  3318. $words = explode(' ', $line);
  3319. $buf = '';
  3320. $firstword = true;
  3321. foreach ($words as $word) {
  3322. if ($qp_mode and (strlen($word) > $length)) {
  3323. $space_left = $length - strlen($buf) - $crlflen;
  3324. if (!$firstword) {
  3325. if ($space_left > 20) {
  3326. $len = $space_left;
  3327. if ($is_utf8) {
  3328. $len = $this->utf8CharBoundary($word, $len);
  3329. } elseif (substr($word, $len - 1, 1) == '=') {
  3330. $len--;
  3331. } elseif (substr($word, $len - 2, 1) == '=') {
  3332. $len -= 2;
  3333. }
  3334. $part = substr($word, 0, $len);
  3335. $word = substr($word, $len);
  3336. $buf .= ' ' . $part;
  3337. $message .= $buf . sprintf('=%s', self::CRLF);
  3338. } else {
  3339. $message .= $buf . $soft_break;
  3340. }
  3341. $buf = '';
  3342. }
  3343. while (strlen($word) > 0) {
  3344. if ($length <= 0) {
  3345. break;
  3346. }
  3347. $len = $length;
  3348. if ($is_utf8) {
  3349. $len = $this->utf8CharBoundary($word, $len);
  3350. } elseif (substr($word, $len - 1, 1) == '=') {
  3351. $len--;
  3352. } elseif (substr($word, $len - 2, 1) == '=') {
  3353. $len -= 2;
  3354. }
  3355. $part = substr($word, 0, $len);
  3356. $word = substr($word, $len);
  3357. if (strlen($word) > 0) {
  3358. $message .= $part . sprintf('=%s', self::CRLF);
  3359. } else {
  3360. $buf = $part;
  3361. }
  3362. }
  3363. } else {
  3364. $buf_o = $buf;
  3365. if (!$firstword) {
  3366. $buf .= ' ';
  3367. }
  3368. $buf .= $word;
  3369. if (strlen($buf) > $length and $buf_o != '') {
  3370. $message .= $buf_o . $soft_break;
  3371. $buf = $word;
  3372. }
  3373. }
  3374. $firstword = false;
  3375. }
  3376. $message .= $buf . self::CRLF;
  3377. }
  3378. return $message;
  3379. }
  3380. /**
  3381. * Find the last character boundary prior to $maxLength in a utf-8
  3382. * quoted-printable encoded string.
  3383. * Original written by Colin Brown.
  3384. * @access public
  3385. * @param string $encodedText utf-8 QP text
  3386. * @param integer $maxLength Find the last character boundary prior to this length
  3387. * @return integer
  3388. */
  3389. public function utf8CharBoundary($encodedText, $maxLength)
  3390. {
  3391. $foundSplitPos = false;
  3392. $lookBack = 3;
  3393. while (!$foundSplitPos) {
  3394. $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
  3395. $encodedCharPos = strpos($lastChunk, '=');
  3396. if (false !== $encodedCharPos) {
  3397. // Found start of encoded character byte within $lookBack block.
  3398. // Check the encoded byte value (the 2 chars after the '=')
  3399. $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
  3400. $dec = hexdec($hex);
  3401. if ($dec < 128) {
  3402. // Single byte character.
  3403. // If the encoded char was found at pos 0, it will fit
  3404. // otherwise reduce maxLength to start of the encoded char
  3405. if ($encodedCharPos > 0) {
  3406. $maxLength = $maxLength - ($lookBack - $encodedCharPos);
  3407. }
  3408. $foundSplitPos = true;
  3409. } elseif ($dec >= 192) {
  3410. // First byte of a multi byte character
  3411. // Reduce maxLength to split at start of character
  3412. $maxLength = $maxLength - ($lookBack - $encodedCharPos);
  3413. $foundSplitPos = true;
  3414. } elseif ($dec < 192) {
  3415. // Middle byte of a multi byte character, look further back
  3416. $lookBack += 3;
  3417. }
  3418. } else {
  3419. // No encoded character found
  3420. $foundSplitPos = true;
  3421. }
  3422. }
  3423. return $maxLength;
  3424. }
  3425. /**
  3426. * Apply word wrapping to the message body.
  3427. * Wraps the message body to the number of chars set in the WordWrap property.
  3428. * You should only do this to plain-text bodies as wrapping HTML tags may break them.
  3429. * This is called automatically by createBody(), so you don't need to call it yourself.
  3430. * @access public
  3431. * @return void
  3432. */
  3433. public function setWordWrap()
  3434. {
  3435. if ($this->WordWrap < 1) {
  3436. return;
  3437. }
  3438. switch ($this->message_type) {
  3439. case 'alt':
  3440. case 'alt_inline':
  3441. case 'alt_attach':
  3442. case 'alt_inline_attach':
  3443. $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
  3444. break;
  3445. default:
  3446. $this->Body = $this->wrapText($this->Body, $this->WordWrap);
  3447. break;
  3448. }
  3449. }
  3450. /**
  3451. * Assemble message headers.
  3452. * @access public
  3453. * @return string The assembled headers
  3454. */
  3455. public function createHeader()
  3456. {
  3457. $result = '';
  3458. if ($this->MessageDate == '') {
  3459. $this->MessageDate = self::rfcDate();
  3460. }
  3461. $result .= $this->headerLine('Date', $this->MessageDate == '' ? self::rfcDate() : $this->MessageDate);
  3462. // To be created automatically by mail()
  3463. if ($this->SingleTo) {
  3464. if ($this->Mailer != 'mail') {
  3465. foreach ($this->to as $toaddr) {
  3466. $this->SingleToArray[] = $this->addrFormat($toaddr);
  3467. }
  3468. }
  3469. } else {
  3470. if (count($this->to) > 0) {
  3471. if ($this->Mailer != 'mail') {
  3472. $result .= $this->addrAppend('To', $this->to);
  3473. }
  3474. } elseif (count($this->cc) == 0) {
  3475. $result .= $this->headerLine('To', 'undisclosed-recipients:;');
  3476. }
  3477. }
  3478. $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
  3479. // sendmail and mail() extract Cc from the header before sending
  3480. if (count($this->cc) > 0) {
  3481. $result .= $this->addrAppend('Cc', $this->cc);
  3482. }
  3483. // sendmail and mail() extract Bcc from the header before sending
  3484. if ((
  3485. $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
  3486. )
  3487. and count($this->bcc) > 0
  3488. ) {
  3489. $result .= $this->addrAppend('Bcc', $this->bcc);
  3490. }
  3491. if (count($this->ReplyTo) > 0) {
  3492. $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
  3493. }
  3494. // mail() sets the subject itself
  3495. if ($this->Mailer != 'mail') {
  3496. $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
  3497. }
  3498. // Only allow a custom message ID if it conforms to RFC 5322 section 3.6.4
  3499. // https://tools.ietf.org/html/rfc5322#section-3.6.4
  3500. if ('' != $this->MessageID and preg_match('/^<.*@.*>$/', $this->MessageID)) {
  3501. $this->lastMessageID = $this->MessageID;
  3502. } else {
  3503. //$this->lastMessageID = sprintf('<%s@%s>', $this->uniqueid, $this->serverHostname());
  3504. $this->lastMessageID = '<'.md5($this->uniqueid)."@".explode("@",$this->From)[1].'>';
  3505. }
  3506. $result .= $this->headerLine('Message-ID', $this->lastMessageID);
  3507. if (!is_null($this->Priority)) {
  3508. $result .= $this->headerLine('X-Priority', $this->Priority);
  3509. }
  3510. /* if ($this->XMailer == '') {
  3511. $result .= $this->headerLine(
  3512. 'X-Mailer',
  3513. //'PHPMailer ' . $this->Version . '(https://github.com/PHPMailer/PHPMailer)'
  3514. 'PHPMailer ' . $this->uniqueid
  3515. );
  3516. } else {
  3517. $myXmailer = trim($this->XMailer);
  3518. if ($myXmailer) {
  3519. //$result .= $this->headerLine('X-Mailer', $myXmailer);
  3520. $result .= $this->headerLine('X-Mailer', $myXmailer.$this->uniqueid);
  3521. }
  3522. }*/
  3523. if ($this->ConfirmReadingTo != '') {
  3524. $result .= $this->headerLine('Disposition-Notification-To', '<' . $this->ConfirmReadingTo . '>');
  3525. }
  3526. // Add custom headers
  3527. foreach ($this->CustomHeader as $header) {
  3528. $result .= $this->headerLine(
  3529. trim($header[0]),
  3530. $this->encodeHeader(trim($header[1]))
  3531. );
  3532. }
  3533. if (!$this->sign_key_file) {
  3534. $result .= $this->headerLine('MIME-Version', '1.0');
  3535. $result .= $this->getMailMIME();
  3536. }
  3537. return $result;
  3538. }
  3539. /**
  3540. * Get the message MIME type headers.
  3541. * @access public
  3542. * @return string
  3543. */
  3544. public function getMailMIME()
  3545. {
  3546. $result = '';
  3547. $ismultipart = true;
  3548. switch ($this->message_type) {
  3549. case 'inline':
  3550. $result .= $this->headerLine('Content-Type', 'multipart/related;');
  3551. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  3552. break;
  3553. case 'attach':
  3554. case 'inline_attach':
  3555. case 'alt_attach':
  3556. case 'alt_inline_attach':
  3557. $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
  3558. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  3559. break;
  3560. case 'alt':
  3561. case 'alt_inline':
  3562. $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
  3563. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  3564. break;
  3565. default:
  3566. // Catches case 'plain': and case '':
  3567. $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
  3568. $ismultipart = false;
  3569. break;
  3570. }
  3571. // RFC1341 part 5 says 7bit is assumed if not specified
  3572. if ($this->Encoding != '7bit') {
  3573. // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
  3574. if ($ismultipart) {
  3575. if ($this->Encoding == '8bit') {
  3576. $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
  3577. }
  3578. // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
  3579. } else {
  3580. $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
  3581. }
  3582. }
  3583. if ($this->Mailer != 'mail') {
  3584. $result .= $this->LE;
  3585. }
  3586. return $result;
  3587. }
  3588. /**
  3589. * Returns the whole MIME message.
  3590. * Includes complete headers and body.
  3591. * Only valid post preSend().
  3592. * @see PHPMailer::preSend()
  3593. * @access public
  3594. * @return string
  3595. */
  3596. public function getSentMIMEMessage()
  3597. {
  3598. return rtrim($this->MIMEHeader . $this->mailHeader, "\n\r") . self::CRLF . self::CRLF . $this->MIMEBody;
  3599. }
  3600. /**
  3601. * Create unique ID
  3602. * @return string
  3603. */
  3604. protected function generateId() {
  3605. return md5(uniqid(time()));
  3606. }
  3607. /**
  3608. * Assemble the message body.
  3609. * Returns an empty string on failure.
  3610. * @access public
  3611. * @throws phpmailerException
  3612. * @return string The assembled message body
  3613. */
  3614. public function createBody()
  3615. {
  3616. $body = '';
  3617. //Create unique IDs and preset boundaries
  3618. $this->uniqueid = $this->generateId();
  3619. $this->boundary[1] = '1' . $this->uniqueid;
  3620. $this->boundary[2] = '2' . $this->uniqueid;
  3621. $this->boundary[3] = '3' . $this->uniqueid;
  3622. if ($this->sign_key_file) {
  3623. $body .= $this->getMailMIME() . $this->LE;
  3624. }
  3625. $this->setWordWrap();
  3626. $bodyEncoding = $this->Encoding;
  3627. $bodyCharSet = $this->CharSet;
  3628. //Can we do a 7-bit downgrade?
  3629. if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
  3630. $bodyEncoding = '7bit';
  3631. //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
  3632. $bodyCharSet = 'us-ascii';
  3633. }
  3634. //If lines are too long, and we're not already using an encoding that will shorten them,
  3635. //change to quoted-printable transfer encoding for the body part only
  3636. if ('base64' != $this->Encoding and self::hasLineLongerThanMax($this->Body)) {
  3637. $bodyEncoding = 'quoted-printable';
  3638. }
  3639. $altBodyEncoding = $this->Encoding;
  3640. $altBodyCharSet = $this->CharSet;
  3641. //Can we do a 7-bit downgrade?
  3642. if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
  3643. $altBodyEncoding = '7bit';
  3644. //All ISO 8859, Windows codepage and UTF-8 charsets are ascii compatible up to 7-bit
  3645. $altBodyCharSet = 'us-ascii';
  3646. }
  3647. //If lines are too long, and we're not already using an encoding that will shorten them,
  3648. //change to quoted-printable transfer encoding for the alt body part only
  3649. if ('base64' != $altBodyEncoding and self::hasLineLongerThanMax($this->AltBody)) {
  3650. $altBodyEncoding = 'quoted-printable';
  3651. }
  3652. //Use this as a preamble in all multipart message types
  3653. $mimepre = "This is a multi-part message in MIME format." . $this->LE . $this->LE;
  3654. switch ($this->message_type) {
  3655. case 'inline':
  3656. $body .= $mimepre;
  3657. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
  3658. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3659. $body .= $this->LE . $this->LE;
  3660. $body .= $this->attachAll('inline', $this->boundary[1]);
  3661. break;
  3662. case 'attach':
  3663. $body .= $mimepre;
  3664. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
  3665. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3666. $body .= $this->LE . $this->LE;
  3667. $body .= $this->attachAll('attachment', $this->boundary[1]);
  3668. break;
  3669. case 'inline_attach':
  3670. $body .= $mimepre;
  3671. $body .= $this->textLine('--' . $this->boundary[1]);
  3672. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  3673. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  3674. $body .= $this->LE;
  3675. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
  3676. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3677. $body .= $this->LE . $this->LE;
  3678. $body .= $this->attachAll('inline', $this->boundary[2]);
  3679. $body .= $this->LE;
  3680. $body .= $this->attachAll('attachment', $this->boundary[1]);
  3681. break;
  3682. case 'alt':
  3683. $body .= $mimepre;
  3684. $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  3685. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  3686. $body .= $this->LE . $this->LE;
  3687. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
  3688. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3689. $body .= $this->LE . $this->LE;
  3690. if (!empty($this->Ical)) {
  3691. $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
  3692. $body .= $this->encodeString($this->Ical, $this->Encoding);
  3693. $body .= $this->LE . $this->LE;
  3694. }
  3695. $body .= $this->endBoundary($this->boundary[1]);
  3696. break;
  3697. case 'alt_inline':
  3698. $body .= $mimepre;
  3699. $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  3700. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  3701. $body .= $this->LE . $this->LE;
  3702. $body .= $this->textLine('--' . $this->boundary[1]);
  3703. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  3704. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  3705. $body .= $this->LE;
  3706. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
  3707. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3708. $body .= $this->LE . $this->LE;
  3709. $body .= $this->attachAll('inline', $this->boundary[2]);
  3710. $body .= $this->LE;
  3711. $body .= $this->endBoundary($this->boundary[1]);
  3712. break;
  3713. case 'alt_attach':
  3714. $body .= $mimepre;
  3715. $body .= $this->textLine('--' . $this->boundary[1]);
  3716. $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
  3717. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  3718. $body .= $this->LE;
  3719. $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  3720. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  3721. $body .= $this->LE . $this->LE;
  3722. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
  3723. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3724. $body .= $this->LE . $this->LE;
  3725. $body .= $this->endBoundary($this->boundary[2]);
  3726. $body .= $this->LE;
  3727. $body .= $this->attachAll('attachment', $this->boundary[1]);
  3728. break;
  3729. case 'alt_inline_attach':
  3730. $body .= $mimepre;
  3731. $body .= $this->textLine('--' . $this->boundary[1]);
  3732. $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
  3733. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  3734. $body .= $this->LE;
  3735. $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  3736. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  3737. $body .= $this->LE . $this->LE;
  3738. $body .= $this->textLine('--' . $this->boundary[2]);
  3739. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  3740. $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
  3741. $body .= $this->LE;
  3742. $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
  3743. $body .= $this->encodeString($this->Body, $bodyEncoding);
  3744. $body .= $this->LE . $this->LE;
  3745. $body .= $this->attachAll('inline', $this->boundary[3]);
  3746. $body .= $this->LE;
  3747. $body .= $this->endBoundary($this->boundary[2]);
  3748. $body .= $this->LE;
  3749. $body .= $this->attachAll('attachment', $this->boundary[1]);
  3750. break;
  3751. default:
  3752. // Catch case 'plain' and case '', applies to simple `text/plain` and `text/html` body content types
  3753. //Reset the `Encoding` property in case we changed it for line length reasons
  3754. $this->Encoding = $bodyEncoding;
  3755. $body .= $this->encodeString($this->Body, $this->Encoding);
  3756. break;
  3757. }
  3758. if ($this->isError()) {
  3759. $body = '';
  3760. } elseif ($this->sign_key_file) {
  3761. try {
  3762. if (!defined('PKCS7_TEXT')) {
  3763. throw new phpmailerException($this->lang('extension_missing') . 'openssl');
  3764. }
  3765. // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
  3766. $file = tempnam(sys_get_temp_dir(), 'mail');
  3767. if (false === file_put_contents($file, $body)) {
  3768. throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
  3769. }
  3770. $signed = tempnam(sys_get_temp_dir(), 'signed');
  3771. //Workaround for PHP bug https://bugs.php.net/bug.php?id=69197
  3772. if (empty($this->sign_extracerts_file)) {
  3773. $sign = @openssl_pkcs7_sign(
  3774. $file,
  3775. $signed,
  3776. 'file://' . realpath($this->sign_cert_file),
  3777. array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
  3778. null
  3779. );
  3780. } else {
  3781. $sign = @openssl_pkcs7_sign(
  3782. $file,
  3783. $signed,
  3784. 'file://' . realpath($this->sign_cert_file),
  3785. array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
  3786. null,
  3787. PKCS7_DETACHED,
  3788. $this->sign_extracerts_file
  3789. );
  3790. }
  3791. if ($sign) {
  3792. @unlink($file);
  3793. $body = file_get_contents($signed);
  3794. @unlink($signed);
  3795. //The message returned by openssl contains both headers and body, so need to split them up
  3796. $parts = explode("\n\n", $body, 2);
  3797. $this->MIMEHeader .= $parts[0] . $this->LE . $this->LE;
  3798. $body = $parts[1];
  3799. } else {
  3800. @unlink($file);
  3801. @unlink($signed);
  3802. throw new phpmailerException($this->lang('signing') . openssl_error_string());
  3803. }
  3804. } catch (phpmailerException $exc) {
  3805. $body = '';
  3806. if ($this->exceptions) {
  3807. throw $exc;
  3808. }
  3809. }
  3810. }
  3811. return $body;
  3812. }
  3813. /**
  3814. * Return the start of a message boundary.
  3815. * @access protected
  3816. * @param string $boundary
  3817. * @param string $charSet
  3818. * @param string $contentType
  3819. * @param string $encoding
  3820. * @return string
  3821. */
  3822. protected function getBoundary($boundary, $charSet, $contentType, $encoding)
  3823. {
  3824. $result = '';
  3825. if ($charSet == '') {
  3826. $charSet = $this->CharSet;
  3827. }
  3828. if ($contentType == '') {
  3829. $contentType = $this->ContentType;
  3830. }
  3831. if ($encoding == '') {
  3832. $encoding = $this->Encoding;
  3833. }
  3834. $result .= $this->textLine('--' . $boundary);
  3835. $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
  3836. $result .= $this->LE;
  3837. // RFC1341 part 5 says 7bit is assumed if not specified
  3838. if ($encoding != '7bit') {
  3839. $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
  3840. }
  3841. $result .= $this->LE;
  3842. return $result;
  3843. }
  3844. /**
  3845. * Return the end of a message boundary.
  3846. * @access protected
  3847. * @param string $boundary
  3848. * @return string
  3849. */
  3850. protected function endBoundary($boundary)
  3851. {
  3852. return $this->LE . '--' . $boundary . '--' . $this->LE;
  3853. }
  3854. /**
  3855. * Set the message type.
  3856. * PHPMailer only supports some preset message types, not arbitrary MIME structures.
  3857. * @access protected
  3858. * @return void
  3859. */
  3860. protected function setMessageType()
  3861. {
  3862. $type = array();
  3863. if ($this->alternativeExists()) {
  3864. $type[] = 'alt';
  3865. }
  3866. if ($this->inlineImageExists()) {
  3867. $type[] = 'inline';
  3868. }
  3869. if ($this->attachmentExists()) {
  3870. $type[] = 'attach';
  3871. }
  3872. $this->message_type = implode('_', $type);
  3873. if ($this->message_type == '') {
  3874. //The 'plain' message_type refers to the message having a single body element, not that it is plain-text
  3875. $this->message_type = 'plain';
  3876. }
  3877. }
  3878. /**
  3879. * Format a header line.
  3880. * @access public
  3881. * @param string $name
  3882. * @param string $value
  3883. * @return string
  3884. */
  3885. public function headerLine($name, $value)
  3886. {
  3887. return $name . ': ' . $value . $this->LE;
  3888. }
  3889. /**
  3890. * Return a formatted mail line.
  3891. * @access public
  3892. * @param string $value
  3893. * @return string
  3894. */
  3895. public function textLine($value)
  3896. {
  3897. return $value . $this->LE;
  3898. }
  3899. /**
  3900. * Add an attachment from a path on the filesystem.
  3901. * Returns false if the file could not be found or read.
  3902. * @param string $path Path to the attachment.
  3903. * @param string $name Overrides the attachment name.
  3904. * @param string $encoding File encoding (see $Encoding).
  3905. * @param string $type File extension (MIME) type.
  3906. * @param string $disposition Disposition to use
  3907. * @throws phpmailerException
  3908. * @return boolean
  3909. */
  3910. public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
  3911. {
  3912. try {
  3913. if (!@is_file($path)) {
  3914. throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
  3915. }
  3916. // If a MIME type is not specified, try to work it out from the file name
  3917. if ($type == '') {
  3918. $type = self::filenameToType($path);
  3919. }
  3920. $filename = basename($path);
  3921. if ($name == '') {
  3922. $name = $filename;
  3923. }
  3924. $this->attachment[] = array(
  3925. 0 => $path,
  3926. 1 => $filename,
  3927. 2 => $name,
  3928. 3 => $encoding,
  3929. 4 => $type,
  3930. 5 => false, // isStringAttachment
  3931. 6 => $disposition,
  3932. 7 => 0
  3933. );
  3934. } catch (phpmailerException $exc) {
  3935. $this->setError($exc->getMessage());
  3936. $this->edebug($exc->getMessage());
  3937. if ($this->exceptions) {
  3938. throw $exc;
  3939. }
  3940. return false;
  3941. }
  3942. return true;
  3943. }
  3944. /**
  3945. * Return the array of attachments.
  3946. * @return array
  3947. */
  3948. public function getAttachments()
  3949. {
  3950. return $this->attachment;
  3951. }
  3952. /**
  3953. * Attach all file, string, and binary attachments to the message.
  3954. * Returns an empty string on failure.
  3955. * @access protected
  3956. * @param string $disposition_type
  3957. * @param string $boundary
  3958. * @return string
  3959. */
  3960. protected function attachAll($disposition_type, $boundary)
  3961. {
  3962. // Return text of body
  3963. $mime = array();
  3964. $cidUniq = array();
  3965. $incl = array();
  3966. // Add all attachments
  3967. foreach ($this->attachment as $attachment) {
  3968. // Check if it is a valid disposition_filter
  3969. if ($attachment[6] == $disposition_type) {
  3970. // Check for string attachment
  3971. $string = '';
  3972. $path = '';
  3973. $bString = $attachment[5];
  3974. if ($bString) {
  3975. $string = $attachment[0];
  3976. } else {
  3977. $path = $attachment[0];
  3978. }
  3979. $inclhash = md5(serialize($attachment));
  3980. if (in_array($inclhash, $incl)) {
  3981. continue;
  3982. }
  3983. $incl[] = $inclhash;
  3984. $name = $attachment[2];
  3985. $encoding = $attachment[3];
  3986. $type = $attachment[4];
  3987. $disposition = $attachment[6];
  3988. $cid = $attachment[7];
  3989. if ($disposition == 'inline' && array_key_exists($cid, $cidUniq)) {
  3990. continue;
  3991. }
  3992. $cidUniq[$cid] = true;
  3993. $mime[] = sprintf('--%s%s', $boundary, $this->LE);
  3994. //Only include a filename property if we have one
  3995. if (!empty($name)) {
  3996. $mime[] = sprintf(
  3997. 'Content-Type: %s; name="%s"%s',
  3998. $type,
  3999. $this->encodeHeader($this->secureHeader($name)),
  4000. $this->LE
  4001. );
  4002. } else {
  4003. $mime[] = sprintf(
  4004. 'Content-Type: %s%s',
  4005. $type,
  4006. $this->LE
  4007. );
  4008. }
  4009. // RFC1341 part 5 says 7bit is assumed if not specified
  4010. if ($encoding != '7bit') {
  4011. $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
  4012. }
  4013. if ($disposition == 'inline') {
  4014. $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
  4015. }
  4016. // If a filename contains any of these chars, it should be quoted,
  4017. // but not otherwise: RFC2183 & RFC2045 5.1
  4018. // Fixes a warning in IETF's msglint MIME checker
  4019. // Allow for bypassing the Content-Disposition header totally
  4020. if (!(empty($disposition))) {
  4021. $encoded_name = $this->encodeHeader($this->secureHeader($name));
  4022. if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
  4023. $mime[] = sprintf(
  4024. 'Content-Disposition: %s; filename="%s"%s',
  4025. $disposition,
  4026. $encoded_name,
  4027. $this->LE . $this->LE
  4028. );
  4029. } else {
  4030. if (!empty($encoded_name)) {
  4031. $mime[] = sprintf(
  4032. 'Content-Disposition: %s; filename=%s%s',
  4033. $disposition,
  4034. $encoded_name,
  4035. $this->LE . $this->LE
  4036. );
  4037. } else {
  4038. $mime[] = sprintf(
  4039. 'Content-Disposition: %s%s',
  4040. $disposition,
  4041. $this->LE . $this->LE
  4042. );
  4043. }
  4044. }
  4045. } else {
  4046. $mime[] = $this->LE;
  4047. }
  4048. // Encode as string attachment
  4049. if ($bString) {
  4050. $mime[] = $this->encodeString($string, $encoding);
  4051. if ($this->isError()) {
  4052. return '';
  4053. }
  4054. $mime[] = $this->LE . $this->LE;
  4055. } else {
  4056. $mime[] = $this->encodeFile($path, $encoding);
  4057. if ($this->isError()) {
  4058. return '';
  4059. }
  4060. $mime[] = $this->LE . $this->LE;
  4061. }
  4062. }
  4063. }
  4064. $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
  4065. return implode('', $mime);
  4066. }
  4067. /**
  4068. * Encode a file attachment in requested format.
  4069. * Returns an empty string on failure.
  4070. * @param string $path The full path to the file
  4071. * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
  4072. * @throws phpmailerException
  4073. * @access protected
  4074. * @return string
  4075. */
  4076. protected function encodeFile($path, $encoding = 'base64')
  4077. {
  4078. try {
  4079. if (!is_readable($path)) {
  4080. throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
  4081. }
  4082. $magic_quotes = get_magic_quotes_runtime();
  4083. if ($magic_quotes) {
  4084. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  4085. set_magic_quotes_runtime(false);
  4086. } else {
  4087. //Doesn't exist in PHP 5.4, but we don't need to check because
  4088. //get_magic_quotes_runtime always returns false in 5.4+
  4089. //so it will never get here
  4090. ini_set('magic_quotes_runtime', false);
  4091. }
  4092. }
  4093. $file_buffer = file_get_contents($path);
  4094. $file_buffer = $this->encodeString($file_buffer, $encoding);
  4095. if ($magic_quotes) {
  4096. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  4097. set_magic_quotes_runtime($magic_quotes);
  4098. } else {
  4099. ini_set('magic_quotes_runtime', $magic_quotes);
  4100. }
  4101. }
  4102. return $file_buffer;
  4103. } catch (Exception $exc) {
  4104. $this->setError($exc->getMessage());
  4105. return '';
  4106. }
  4107. }
  4108. /**
  4109. * Encode a string in requested format.
  4110. * Returns an empty string on failure.
  4111. * @param string $str The text to encode
  4112. * @param string $encoding The encoding to use; one of 'base64', '7bit', '8bit', 'binary', 'quoted-printable'
  4113. * @access public
  4114. * @return string
  4115. */
  4116. public function encodeString($str, $encoding = 'base64')
  4117. {
  4118. $encoded = '';
  4119. switch (strtolower($encoding)) {
  4120. case 'base64':
  4121. $encoded = chunk_split(base64_encode($str), 76, $this->LE);
  4122. break;
  4123. case '7bit':
  4124. case '8bit':
  4125. $encoded = $this->fixEOL($str);
  4126. // Make sure it ends with a line break
  4127. if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
  4128. $encoded .= $this->LE;
  4129. }
  4130. break;
  4131. case 'binary':
  4132. $encoded = $str;
  4133. break;
  4134. case 'quoted-printable':
  4135. $encoded = $this->encodeQP($str);
  4136. break;
  4137. default:
  4138. $this->setError($this->lang('encoding') . $encoding);
  4139. break;
  4140. }
  4141. return $encoded;
  4142. }
  4143. /**
  4144. * Encode a header string optimally.
  4145. * Picks shortest of Q, B, quoted-printable or none.
  4146. * @access public
  4147. * @param string $str
  4148. * @param string $position
  4149. * @return string
  4150. */
  4151. public function encodeHeader($str, $position = 'text')
  4152. {
  4153. $matchcount = 0;
  4154. switch (strtolower($position)) {
  4155. case 'phrase':
  4156. if (!preg_match('/[\200-\377]/', $str)) {
  4157. // Can't use addslashes as we don't know the value of magic_quotes_sybase
  4158. $encoded = addcslashes($str, "\0..\37\177\\\"");
  4159. if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
  4160. return ($encoded);
  4161. } else {
  4162. return ("\"$encoded\"");
  4163. }
  4164. }
  4165. $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
  4166. break;
  4167. /** @noinspection PhpMissingBreakStatementInspection */
  4168. case 'comment':
  4169. $matchcount = preg_match_all('/[()"]/', $str, $matches);
  4170. // Intentional fall-through
  4171. case 'text':
  4172. default:
  4173. $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
  4174. break;
  4175. }
  4176. //There are no chars that need encoding
  4177. if ($matchcount == 0) {
  4178. return ($str);
  4179. }
  4180. $maxlen = 75 - 7 - strlen($this->CharSet);
  4181. // Try to select the encoding which should produce the shortest output
  4182. if ($matchcount > strlen($str) / 3) {
  4183. // More than a third of the content will need encoding, so B encoding will be most efficient
  4184. $encoding = 'B';
  4185. if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
  4186. // Use a custom function which correctly encodes and wraps long
  4187. // multibyte strings without breaking lines within a character
  4188. $encoded = $this->base64EncodeWrapMB($str, "\n");
  4189. } else {
  4190. $encoded = base64_encode($str);
  4191. $maxlen -= $maxlen % 4;
  4192. $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
  4193. }
  4194. } else {
  4195. $encoding = 'Q';
  4196. $encoded = $this->encodeQ($str, $position);
  4197. $encoded = $this->wrapText($encoded, $maxlen, true);
  4198. $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
  4199. }
  4200. $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
  4201. $encoded = trim(str_replace("\n", $this->LE, $encoded));
  4202. return $encoded;
  4203. }
  4204. /**
  4205. * Check if a string contains multi-byte characters.
  4206. * @access public
  4207. * @param string $str multi-byte text to wrap encode
  4208. * @return boolean
  4209. */
  4210. public function hasMultiBytes($str)
  4211. {
  4212. if (function_exists('mb_strlen')) {
  4213. return (strlen($str) > mb_strlen($str, $this->CharSet));
  4214. } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
  4215. return false;
  4216. }
  4217. }
  4218. /**
  4219. * Does a string contain any 8-bit chars (in any charset)?
  4220. * @param string $text
  4221. * @return boolean
  4222. */
  4223. public function has8bitChars($text)
  4224. {
  4225. return (boolean)preg_match('/[\x80-\xFF]/', $text);
  4226. }
  4227. /**
  4228. * Encode and wrap long multibyte strings for mail headers
  4229. * without breaking lines within a character.
  4230. * Adapted from a function by paravoid
  4231. * @link http://www.php.net/manual/en/function.mb-encode-mimeheader.php#60283
  4232. * @access public
  4233. * @param string $str multi-byte text to wrap encode
  4234. * @param string $linebreak string to use as linefeed/end-of-line
  4235. * @return string
  4236. */
  4237. public function base64EncodeWrapMB($str, $linebreak = null)
  4238. {
  4239. $start = '=?' . $this->CharSet . '?B?';
  4240. $end = '?=';
  4241. $encoded = '';
  4242. if ($linebreak === null) {
  4243. $linebreak = $this->LE;
  4244. }
  4245. $mb_length = mb_strlen($str, $this->CharSet);
  4246. // Each line must have length <= 75, including $start and $end
  4247. $length = 75 - strlen($start) - strlen($end);
  4248. // Average multi-byte ratio
  4249. $ratio = $mb_length / strlen($str);
  4250. // Base64 has a 4:3 ratio
  4251. $avgLength = floor($length * $ratio * .75);
  4252. for ($i = 0; $i < $mb_length; $i += $offset) {
  4253. $lookBack = 0;
  4254. do {
  4255. $offset = $avgLength - $lookBack;
  4256. $chunk = mb_substr($str, $i, $offset, $this->CharSet);
  4257. $chunk = base64_encode($chunk);
  4258. $lookBack++;
  4259. } while (strlen($chunk) > $length);
  4260. $encoded .= $chunk . $linebreak;
  4261. }
  4262. // Chomp the last linefeed
  4263. $encoded = substr($encoded, 0, -strlen($linebreak));
  4264. return $encoded;
  4265. }
  4266. /**
  4267. * Encode a string in quoted-printable format.
  4268. * According to RFC2045 section 6.7.
  4269. * @access public
  4270. * @param string $string The text to encode
  4271. * @param integer $line_max Number of chars allowed on a line before wrapping
  4272. * @return string
  4273. * @link http://www.php.net/manual/en/function.quoted-printable-decode.php#89417 Adapted from this comment
  4274. */
  4275. public function encodeQP($string, $line_max = 76)
  4276. {
  4277. // Use native function if it's available (>= PHP5.3)
  4278. if (function_exists('quoted_printable_encode')) {
  4279. return quoted_printable_encode($string);
  4280. }
  4281. // Fall back to a pure PHP implementation
  4282. $string = str_replace(
  4283. array('%20', '%0D%0A.', '%0D%0A', '%'),
  4284. array(' ', "\r\n=2E", "\r\n", '='),
  4285. rawurlencode($string)
  4286. );
  4287. return preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
  4288. }
  4289. /**
  4290. * Backward compatibility wrapper for an old QP encoding function that was removed.
  4291. * @see PHPMailer::encodeQP()
  4292. * @access public
  4293. * @param string $string
  4294. * @param integer $line_max
  4295. * @param boolean $space_conv
  4296. * @return string
  4297. * @deprecated Use encodeQP instead.
  4298. */
  4299. public function encodeQPphp(
  4300. $string,
  4301. $line_max = 76,
  4302. /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
  4303. ) {
  4304. return $this->encodeQP($string, $line_max);
  4305. }
  4306. /**
  4307. * Encode a string using Q encoding.
  4308. * @link http://tools.ietf.org/html/rfc2047
  4309. * @param string $str the text to encode
  4310. * @param string $position Where the text is going to be used, see the RFC for what that means
  4311. * @access public
  4312. * @return string
  4313. */
  4314. public function encodeQ($str, $position = 'text')
  4315. {
  4316. // There should not be any EOL in the string
  4317. $pattern = '';
  4318. $encoded = str_replace(array("\r", "\n"), '', $str);
  4319. switch (strtolower($position)) {
  4320. case 'phrase':
  4321. // RFC 2047 section 5.3
  4322. $pattern = '^A-Za-z0-9!*+\/ -';
  4323. break;
  4324. /** @noinspection PhpMissingBreakStatementInspection */
  4325. case 'comment':
  4326. // RFC 2047 section 5.2
  4327. $pattern = '\(\)"';
  4328. // intentional fall-through
  4329. // for this reason we build the $pattern without including delimiters and []
  4330. case 'text':
  4331. default:
  4332. // RFC 2047 section 5.1
  4333. // Replace every high ascii, control, =, ? and _ characters
  4334. $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
  4335. break;
  4336. }
  4337. $matches = array();
  4338. if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
  4339. // If the string contains an '=', make sure it's the first thing we replace
  4340. // so as to avoid double-encoding
  4341. $eqkey = array_search('=', $matches[0]);
  4342. if (false !== $eqkey) {
  4343. unset($matches[0][$eqkey]);
  4344. array_unshift($matches[0], '=');
  4345. }
  4346. foreach (array_unique($matches[0]) as $char) {
  4347. $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
  4348. }
  4349. }
  4350. // Replace every spaces to _ (more readable than =20)
  4351. return str_replace(' ', '_', $encoded);
  4352. }
  4353. /**
  4354. * Add a string or binary attachment (non-filesystem).
  4355. * This method can be used to attach ascii or binary data,
  4356. * such as a BLOB record from a database.
  4357. * @param string $string String attachment data.
  4358. * @param string $filename Name of the attachment.
  4359. * @param string $encoding File encoding (see $Encoding).
  4360. * @param string $type File extension (MIME) type.
  4361. * @param string $disposition Disposition to use
  4362. * @return void
  4363. */
  4364. public function addStringAttachment(
  4365. $string,
  4366. $filename,
  4367. $encoding = 'base64',
  4368. $type = '',
  4369. $disposition = 'attachment'
  4370. ) {
  4371. // If a MIME type is not specified, try to work it out from the file name
  4372. if ($type == '') {
  4373. $type = self::filenameToType($filename);
  4374. }
  4375. // Append to $attachment array
  4376. $this->attachment[] = array(
  4377. 0 => $string,
  4378. 1 => $filename,
  4379. 2 => basename($filename),
  4380. 3 => $encoding,
  4381. 4 => $type,
  4382. 5 => true, // isStringAttachment
  4383. 6 => $disposition,
  4384. 7 => 0
  4385. );
  4386. }
  4387. /**
  4388. * Add an embedded (inline) attachment from a file.
  4389. * This can include images, sounds, and just about any other document type.
  4390. * These differ from 'regular' attachments in that they are intended to be
  4391. * displayed inline with the message, not just attached for download.
  4392. * This is used in HTML messages that embed the images
  4393. * the HTML refers to using the $cid value.
  4394. * @param string $path Path to the attachment.
  4395. * @param string $cid Content ID of the attachment; Use this to reference
  4396. * the content when using an embedded image in HTML.
  4397. * @param string $name Overrides the attachment name.
  4398. * @param string $encoding File encoding (see $Encoding).
  4399. * @param string $type File MIME type.
  4400. * @param string $disposition Disposition to use
  4401. * @return boolean True on successfully adding an attachment
  4402. */
  4403. public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
  4404. {
  4405. if (!@is_file($path)) {
  4406. $this->setError($this->lang('file_access') . $path);
  4407. return false;
  4408. }
  4409. // If a MIME type is not specified, try to work it out from the file name
  4410. if ($type == '') {
  4411. $type = self::filenameToType($path);
  4412. }
  4413. $filename = basename($path);
  4414. if ($name == '') {
  4415. $name = $filename;
  4416. }
  4417. // Append to $attachment array
  4418. $this->attachment[] = array(
  4419. 0 => $path,
  4420. 1 => $filename,
  4421. 2 => $name,
  4422. 3 => $encoding,
  4423. 4 => $type,
  4424. 5 => false, // isStringAttachment
  4425. 6 => $disposition,
  4426. 7 => $cid
  4427. );
  4428. return true;
  4429. }
  4430. /**
  4431. * Add an embedded stringified attachment.
  4432. * This can include images, sounds, and just about any other document type.
  4433. * Be sure to set the $type to an image type for images:
  4434. * JPEG images use 'image/jpeg', GIF uses 'image/gif', PNG uses 'image/png'.
  4435. * @param string $string The attachment binary data.
  4436. * @param string $cid Content ID of the attachment; Use this to reference
  4437. * the content when using an embedded image in HTML.
  4438. * @param string $name
  4439. * @param string $encoding File encoding (see $Encoding).
  4440. * @param string $type MIME type.
  4441. * @param string $disposition Disposition to use
  4442. * @return boolean True on successfully adding an attachment
  4443. */
  4444. public function addStringEmbeddedImage(
  4445. $string,
  4446. $cid,
  4447. $name = '',
  4448. $encoding = 'base64',
  4449. $type = '',
  4450. $disposition = 'inline'
  4451. ) {
  4452. // If a MIME type is not specified, try to work it out from the name
  4453. if ($type == '' and !empty($name)) {
  4454. $type = self::filenameToType($name);
  4455. }
  4456. // Append to $attachment array
  4457. $this->attachment[] = array(
  4458. 0 => $string,
  4459. 1 => $name,
  4460. 2 => $name,
  4461. 3 => $encoding,
  4462. 4 => $type,
  4463. 5 => true, // isStringAttachment
  4464. 6 => $disposition,
  4465. 7 => $cid
  4466. );
  4467. return true;
  4468. }
  4469. /**
  4470. * Check if an inline attachment is present.
  4471. * @access public
  4472. * @return boolean
  4473. */
  4474. public function inlineImageExists()
  4475. {
  4476. foreach ($this->attachment as $attachment) {
  4477. if ($attachment[6] == 'inline') {
  4478. return true;
  4479. }
  4480. }
  4481. return false;
  4482. }
  4483. /**
  4484. * Check if an attachment (non-inline) is present.
  4485. * @return boolean
  4486. */
  4487. public function attachmentExists()
  4488. {
  4489. foreach ($this->attachment as $attachment) {
  4490. if ($attachment[6] == 'attachment') {
  4491. return true;
  4492. }
  4493. }
  4494. return false;
  4495. }
  4496. /**
  4497. * Check if this message has an alternative body set.
  4498. * @return boolean
  4499. */
  4500. public function alternativeExists()
  4501. {
  4502. return !empty($this->AltBody);
  4503. }
  4504. /**
  4505. * Clear queued addresses of given kind.
  4506. * @access protected
  4507. * @param string $kind 'to', 'cc', or 'bcc'
  4508. * @return void
  4509. */
  4510. public function clearQueuedAddresses($kind)
  4511. {
  4512. $RecipientsQueue = $this->RecipientsQueue;
  4513. foreach ($RecipientsQueue as $address => $params) {
  4514. if ($params[0] == $kind) {
  4515. unset($this->RecipientsQueue[$address]);
  4516. }
  4517. }
  4518. }
  4519. /**
  4520. * Clear all To recipients.
  4521. * @return void
  4522. */
  4523. public function clearAddresses()
  4524. {
  4525. foreach ($this->to as $to) {
  4526. unset($this->all_recipients[strtolower($to[0])]);
  4527. }
  4528. $this->to = array();
  4529. $this->clearQueuedAddresses('to');
  4530. }
  4531. /**
  4532. * Clear all CC recipients.
  4533. * @return void
  4534. */
  4535. public function clearCCs()
  4536. {
  4537. foreach ($this->cc as $cc) {
  4538. unset($this->all_recipients[strtolower($cc[0])]);
  4539. }
  4540. $this->cc = array();
  4541. $this->clearQueuedAddresses('cc');
  4542. }
  4543. /**
  4544. * Clear all BCC recipients.
  4545. * @return void
  4546. */
  4547. public function clearBCCs()
  4548. {
  4549. foreach ($this->bcc as $bcc) {
  4550. unset($this->all_recipients[strtolower($bcc[0])]);
  4551. }
  4552. $this->bcc = array();
  4553. $this->clearQueuedAddresses('bcc');
  4554. }
  4555. /**
  4556. * Clear all ReplyTo recipients.
  4557. * @return void
  4558. */
  4559. public function clearReplyTos()
  4560. {
  4561. $this->ReplyTo = array();
  4562. $this->ReplyToQueue = array();
  4563. }
  4564. /**
  4565. * Clear all recipient types.
  4566. * @return void
  4567. */
  4568. public function clearAllRecipients()
  4569. {
  4570. $this->to = array();
  4571. $this->cc = array();
  4572. $this->bcc = array();
  4573. $this->all_recipients = array();
  4574. $this->RecipientsQueue = array();
  4575. }
  4576. /**
  4577. * Clear all filesystem, string, and binary attachments.
  4578. * @return void
  4579. */
  4580. public function clearAttachments()
  4581. {
  4582. $this->attachment = array();
  4583. }
  4584. /**
  4585. * Clear all custom headers.
  4586. * @return void
  4587. */
  4588. public function clearCustomHeaders()
  4589. {
  4590. $this->CustomHeader = array();
  4591. }
  4592. /**
  4593. * Add an error message to the error container.
  4594. * @access protected
  4595. * @param string $msg
  4596. * @return void
  4597. */
  4598. protected function setError($msg)
  4599. {
  4600. $this->error_count++;
  4601. if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
  4602. $lasterror = $this->smtp->getError();
  4603. if (!empty($lasterror['error'])) {
  4604. $msg .= $this->lang('smtp_error') . $lasterror['error'];
  4605. if (!empty($lasterror['detail'])) {
  4606. $msg .= ' Detail: '. $lasterror['detail'];
  4607. }
  4608. if (!empty($lasterror['smtp_code'])) {
  4609. $msg .= ' SMTP code: ' . $lasterror['smtp_code'];
  4610. }
  4611. if (!empty($lasterror['smtp_code_ex'])) {
  4612. $msg .= ' Additional SMTP info: ' . $lasterror['smtp_code_ex'];
  4613. }
  4614. }
  4615. }
  4616. $this->ErrorInfo = $msg;
  4617. }
  4618. /**
  4619. * Return an RFC 822 formatted date.
  4620. * @access public
  4621. * @return string
  4622. * @static
  4623. */
  4624. public static function rfcDate()
  4625. {
  4626. // Set the time zone to whatever the default is to avoid 500 errors
  4627. // Will default to UTC if it's not set properly in php.ini
  4628. date_default_timezone_set(@date_default_timezone_get());
  4629. return date('D, j M Y H:i:s O');
  4630. }
  4631. /**
  4632. * Get the server hostname.
  4633. * Returns 'localhost.localdomain' if unknown.
  4634. * @access protected
  4635. * @return string
  4636. */
  4637. protected function serverHostname()
  4638. {
  4639. $result = 'localhost.localdomain';
  4640. if (!empty($this->Hostname)) {
  4641. $result = $this->Hostname;
  4642. } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
  4643. $result = $_SERVER['SERVER_NAME'];
  4644. } elseif (function_exists('gethostname') && gethostname() !== false) {
  4645. $result = gethostname();
  4646. } elseif (php_uname('n') !== false) {
  4647. $result = php_uname('n');
  4648. }
  4649. return $result;
  4650. }
  4651. /**
  4652. * Get an error message in the current language.
  4653. * @access protected
  4654. * @param string $key
  4655. * @return string
  4656. */
  4657. protected function lang($key)
  4658. {
  4659. if (count($this->language) < 1) {
  4660. $this->setLanguage('en'); // set the default language
  4661. }
  4662. if (array_key_exists($key, $this->language)) {
  4663. if ($key == 'smtp_connect_failed') {
  4664. //Include a link to troubleshooting docs on SMTP connection failure
  4665. //this is by far the biggest cause of support questions
  4666. //but it's usually not PHPMailer's fault.
  4667. return $this->language[$key] . ' https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting';
  4668. }
  4669. return $this->language[$key];
  4670. } else {
  4671. //Return the key as a fallback
  4672. return $key;
  4673. }
  4674. }
  4675. /**
  4676. * Check if an error occurred.
  4677. * @access public
  4678. * @return boolean True if an error did occur.
  4679. */
  4680. public function isError()
  4681. {
  4682. return ($this->error_count > 0);
  4683. }
  4684. /**
  4685. * Ensure consistent line endings in a string.
  4686. * Changes every end of line from CRLF, CR or LF to $this->LE.
  4687. * @access public
  4688. * @param string $str String to fixEOL
  4689. * @return string
  4690. */
  4691. public function fixEOL($str)
  4692. {
  4693. // Normalise to \n
  4694. $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
  4695. // Now convert LE as needed
  4696. if ($this->LE !== "\n") {
  4697. $nstr = str_replace("\n", $this->LE, $nstr);
  4698. }
  4699. return $nstr;
  4700. }
  4701. /**
  4702. * Add a custom header.
  4703. * $name value can be overloaded to contain
  4704. * both header name and value (name:value)
  4705. * @access public
  4706. * @param string $name Custom header name
  4707. * @param string $value Header value
  4708. * @return void
  4709. */
  4710. public function addCustomHeader($name, $value = null,$overwrite = false)
  4711. {
  4712. if ($value === null)
  4713. {
  4714. $header = explode(':', $name, 2);
  4715. $name = $header[0];
  4716. }
  4717. if ($overwrite)
  4718. {
  4719. $this->CustomHeader[$name] = isset($header) ? $header : array($name, $value);
  4720. }
  4721. else
  4722. {
  4723. $this->CustomHeader[] = isset($header) ? $header : array($name, $value);
  4724. }
  4725. }
  4726. /**
  4727. * Returns all custom headers.
  4728. * @return array
  4729. */
  4730. public function getCustomHeaders()
  4731. {
  4732. return array_values($this->CustomHeader);
  4733. }
  4734. /**
  4735. * Create a message body from an HTML string.
  4736. * Automatically inlines images and creates a plain-text version by converting the HTML,
  4737. * overwriting any existing values in Body and AltBody.
  4738. * $basedir is used when handling relative image paths, e.g. <img src="images/a.png">
  4739. * will look for an image file in $basedir/images/a.png and convert it to inline.
  4740. * If you don't want to apply these transformations to your HTML, just set Body and AltBody yourself.
  4741. * @access public
  4742. * @param string $message HTML message string
  4743. * @param string $basedir base directory for relative paths to images
  4744. * @param boolean|callable $advanced Whether to use the internal HTML to text converter
  4745. * or your own custom converter @see PHPMailer::html2text()
  4746. * @return string $message The transformed message Body
  4747. */
  4748. public function msgHTML($message, $basedir = '', $advanced = false)
  4749. {
  4750. preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
  4751. if (array_key_exists(2, $images)) {
  4752. foreach ($images[2] as $imgindex => $url) {
  4753. // Convert data URIs into embedded images
  4754. if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
  4755. $data = substr($url, strpos($url, ','));
  4756. if ($match[2]) {
  4757. $data = base64_decode($data);
  4758. } else {
  4759. $data = rawurldecode($data);
  4760. }
  4761. $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
  4762. if ($this->addStringEmbeddedImage($data, $cid, 'embed' . $imgindex, 'base64', $match[1])) {
  4763. $message = str_replace(
  4764. $images[0][$imgindex],
  4765. $images[1][$imgindex] . '="cid:' . $cid . '"',
  4766. $message
  4767. );
  4768. }
  4769. } elseif (substr($url, 0, 4) !== 'cid:' && !preg_match('#^[a-z][a-z0-9+.-]*://#i', $url)) {
  4770. // Do not change urls for absolute images (thanks to corvuscorax)
  4771. // Do not change urls that are already inline images
  4772. $filename = basename($url);
  4773. $directory = dirname($url);
  4774. if ($directory == '.') {
  4775. $directory = '';
  4776. }
  4777. $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
  4778. if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
  4779. $basedir .= '/';
  4780. }
  4781. if (strlen($directory) > 1 && substr($directory, -1) != '/') {
  4782. $directory .= '/';
  4783. }
  4784. if ($this->addEmbeddedImage(
  4785. $basedir . $directory . $filename,
  4786. $cid,
  4787. $filename,
  4788. 'base64',
  4789. self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
  4790. )
  4791. ) {
  4792. $message = preg_replace(
  4793. '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
  4794. $images[1][$imgindex] . '="cid:' . $cid . '"',
  4795. $message
  4796. );
  4797. }
  4798. }
  4799. }
  4800. }
  4801. $this->isHTML(true);
  4802. // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
  4803. $this->Body = $this->normalizeBreaks($message);
  4804. $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
  4805. if (!$this->alternativeExists()) {
  4806. $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
  4807. self::CRLF . self::CRLF;
  4808. }
  4809. return $this->Body;
  4810. }
  4811. /**
  4812. * Convert an HTML string into plain text.
  4813. * This is used by msgHTML().
  4814. * Note - older versions of this function used a bundled advanced converter
  4815. * which was been removed for license reasons in #232.
  4816. * Example usage:
  4817. * <code>
  4818. * // Use default conversion
  4819. * $plain = $mail->html2text($html);
  4820. * // Use your own custom converter
  4821. * $plain = $mail->html2text($html, function($html) {
  4822. * $converter = new MyHtml2text($html);
  4823. * return $converter->get_text();
  4824. * });
  4825. * </code>
  4826. * @param string $html The HTML text to convert
  4827. * @param boolean|callable $advanced Any boolean value to use the internal converter,
  4828. * or provide your own callable for custom conversion.
  4829. * @return string
  4830. */
  4831. public function html2text($html, $advanced = false)
  4832. {
  4833. if (is_callable($advanced)) {
  4834. return call_user_func($advanced, $html);
  4835. }
  4836. return html_entity_decode(
  4837. trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
  4838. ENT_QUOTES,
  4839. $this->CharSet
  4840. );
  4841. }
  4842. /**
  4843. * Get the MIME type for a file extension.
  4844. * @param string $ext File extension
  4845. * @access public
  4846. * @return string MIME type of file.
  4847. * @static
  4848. */
  4849. public static function _mime_types($ext = '')
  4850. {
  4851. $mimes = array(
  4852. 'xl' => 'application/excel',
  4853. 'js' => 'application/javascript',
  4854. 'hqx' => 'application/mac-binhex40',
  4855. 'cpt' => 'application/mac-compactpro',
  4856. 'bin' => 'application/macbinary',
  4857. 'doc' => 'application/msword',
  4858. 'word' => 'application/msword',
  4859. 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  4860. 'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
  4861. 'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
  4862. 'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
  4863. 'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  4864. 'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
  4865. 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  4866. 'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
  4867. 'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
  4868. 'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
  4869. 'class' => 'application/octet-stream',
  4870. 'dll' => 'application/octet-stream',
  4871. 'dms' => 'application/octet-stream',
  4872. 'exe' => 'application/octet-stream',
  4873. 'lha' => 'application/octet-stream',
  4874. 'lzh' => 'application/octet-stream',
  4875. 'psd' => 'application/octet-stream',
  4876. 'sea' => 'application/octet-stream',
  4877. 'so' => 'application/octet-stream',
  4878. 'oda' => 'application/oda',
  4879. 'pdf' => 'application/pdf',
  4880. 'ai' => 'application/postscript',
  4881. 'eps' => 'application/postscript',
  4882. 'ps' => 'application/postscript',
  4883. 'smi' => 'application/smil',
  4884. 'smil' => 'application/smil',
  4885. 'mif' => 'application/vnd.mif',
  4886. 'xls' => 'application/vnd.ms-excel',
  4887. 'ppt' => 'application/vnd.ms-powerpoint',
  4888. 'wbxml' => 'application/vnd.wap.wbxml',
  4889. 'wmlc' => 'application/vnd.wap.wmlc',
  4890. 'dcr' => 'application/x-director',
  4891. 'dir' => 'application/x-director',
  4892. 'dxr' => 'application/x-director',
  4893. 'dvi' => 'application/x-dvi',
  4894. 'gtar' => 'application/x-gtar',
  4895. 'php3' => 'application/x-httpd-php',
  4896. 'php4' => 'application/x-httpd-php',
  4897. 'php' => 'application/x-httpd-php',
  4898. 'phtml' => 'application/x-httpd-php',
  4899. 'phps' => 'application/x-httpd-php-source',
  4900. 'swf' => 'application/x-shockwave-flash',
  4901. 'sit' => 'application/x-stuffit',
  4902. 'tar' => 'application/x-tar',
  4903. 'tgz' => 'application/x-tar',
  4904. 'xht' => 'application/xhtml+xml',
  4905. 'xhtml' => 'application/xhtml+xml',
  4906. 'zip' => 'application/zip',
  4907. 'mid' => 'audio/midi',
  4908. 'midi' => 'audio/midi',
  4909. 'mp2' => 'audio/mpeg',
  4910. 'mp3' => 'audio/mpeg',
  4911. 'mpga' => 'audio/mpeg',
  4912. 'aif' => 'audio/x-aiff',
  4913. 'aifc' => 'audio/x-aiff',
  4914. 'aiff' => 'audio/x-aiff',
  4915. 'ram' => 'audio/x-pn-realaudio',
  4916. 'rm' => 'audio/x-pn-realaudio',
  4917. 'rpm' => 'audio/x-pn-realaudio-plugin',
  4918. 'ra' => 'audio/x-realaudio',
  4919. 'wav' => 'audio/x-wav',
  4920. 'bmp' => 'image/bmp',
  4921. 'gif' => 'image/gif',
  4922. 'jpeg' => 'image/jpeg',
  4923. 'jpe' => 'image/jpeg',
  4924. 'jpg' => 'image/jpeg',
  4925. 'png' => 'image/png',
  4926. 'tiff' => 'image/tiff',
  4927. 'tif' => 'image/tiff',
  4928. 'eml' => 'message/rfc822',
  4929. 'css' => 'text/css',
  4930. 'html' => 'text/html',
  4931. 'htm' => 'text/html',
  4932. 'shtml' => 'text/html',
  4933. 'log' => 'text/plain',
  4934. 'text' => 'text/plain',
  4935. 'txt' => 'text/plain',
  4936. 'rtx' => 'text/richtext',
  4937. 'rtf' => 'text/rtf',
  4938. 'vcf' => 'text/vcard',
  4939. 'vcard' => 'text/vcard',
  4940. 'xml' => 'text/xml',
  4941. 'xsl' => 'text/xml',
  4942. 'mpeg' => 'video/mpeg',
  4943. 'mpe' => 'video/mpeg',
  4944. 'mpg' => 'video/mpeg',
  4945. 'mov' => 'video/quicktime',
  4946. 'qt' => 'video/quicktime',
  4947. 'rv' => 'video/vnd.rn-realvideo',
  4948. 'avi' => 'video/x-msvideo',
  4949. 'movie' => 'video/x-sgi-movie'
  4950. );
  4951. if (array_key_exists(strtolower($ext), $mimes)) {
  4952. return $mimes[strtolower($ext)];
  4953. }
  4954. return 'application/octet-stream';
  4955. }
  4956. /**
  4957. * Map a file name to a MIME type.
  4958. * Defaults to 'application/octet-stream', i.e.. arbitrary binary data.
  4959. * @param string $filename A file name or full path, does not need to exist as a file
  4960. * @return string
  4961. * @static
  4962. */
  4963. public static function filenameToType($filename)
  4964. {
  4965. // In case the path is a URL, strip any query string before getting extension
  4966. $qpos = strpos($filename, '?');
  4967. if (false !== $qpos) {
  4968. $filename = substr($filename, 0, $qpos);
  4969. }
  4970. $pathinfo = self::mb_pathinfo($filename);
  4971. return self::_mime_types($pathinfo['extension']);
  4972. }
  4973. /**
  4974. * Multi-byte-safe pathinfo replacement.
  4975. * Drop-in replacement for pathinfo(), but multibyte-safe, cross-platform-safe, old-version-safe.
  4976. * Works similarly to the one in PHP >= 5.2.0
  4977. * @link http://www.php.net/manual/en/function.pathinfo.php#107461
  4978. * @param string $path A filename or path, does not need to exist as a file
  4979. * @param integer|string $options Either a PATHINFO_* constant,
  4980. * or a string name to return only the specified piece, allows 'filename' to work on PHP < 5.2
  4981. * @return string|array
  4982. * @static
  4983. */
  4984. public static function mb_pathinfo($path, $options = null)
  4985. {
  4986. $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
  4987. $pathinfo = array();
  4988. if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
  4989. if (array_key_exists(1, $pathinfo)) {
  4990. $ret['dirname'] = $pathinfo[1];
  4991. }
  4992. if (array_key_exists(2, $pathinfo)) {
  4993. $ret['basename'] = $pathinfo[2];
  4994. }
  4995. if (array_key_exists(5, $pathinfo)) {
  4996. $ret['extension'] = $pathinfo[5];
  4997. }
  4998. if (array_key_exists(3, $pathinfo)) {
  4999. $ret['filename'] = $pathinfo[3];
  5000. }
  5001. }
  5002. switch ($options) {
  5003. case PATHINFO_DIRNAME:
  5004. case 'dirname':
  5005. return $ret['dirname'];
  5006. case PATHINFO_BASENAME:
  5007. case 'basename':
  5008. return $ret['basename'];
  5009. case PATHINFO_EXTENSION:
  5010. case 'extension':
  5011. return $ret['extension'];
  5012. case PATHINFO_FILENAME:
  5013. case 'filename':
  5014. return $ret['filename'];
  5015. default:
  5016. return $ret;
  5017. }
  5018. }
  5019. /**
  5020. * Set or reset instance properties.
  5021. * You should avoid this function - it's more verbose, less efficient, more error-prone and
  5022. * harder to debug than setting properties directly.
  5023. * Usage Example:
  5024. * `$mail->set('SMTPSecure', 'tls');`
  5025. * is the same as:
  5026. * `$mail->SMTPSecure = 'tls';`
  5027. * @access public
  5028. * @param string $name The property name to set
  5029. * @param mixed $value The value to set the property to
  5030. * @return boolean
  5031. * @TODO Should this not be using the __set() magic function?
  5032. */
  5033. public function set($name, $value = '')
  5034. {
  5035. if (property_exists($this, $name)) {
  5036. $this->$name = $value;
  5037. return true;
  5038. } else {
  5039. $this->setError($this->lang('variable_set') . $name);
  5040. return false;
  5041. }
  5042. }
  5043. /**
  5044. * Strip newlines to prevent header injection.
  5045. * @access public
  5046. * @param string $str
  5047. * @return string
  5048. */
  5049. public function secureHeader($str)
  5050. {
  5051. return trim(str_replace(array("\r", "\n"), '', $str));
  5052. }
  5053. /**
  5054. * Normalize line breaks in a string.
  5055. * Converts UNIX LF, Mac CR and Windows CRLF line breaks into a single line break format.
  5056. * Defaults to CRLF (for message bodies) and preserves consecutive breaks.
  5057. * @param string $text
  5058. * @param string $breaktype What kind of line break to use, defaults to CRLF
  5059. * @return string
  5060. * @access public
  5061. * @static
  5062. */
  5063. public static function normalizeBreaks($text, $breaktype = "\r\n")
  5064. {
  5065. return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
  5066. }
  5067. /**
  5068. * Set the public and private key files and password for S/MIME signing.
  5069. * @access public
  5070. * @param string $cert_filename
  5071. * @param string $key_filename
  5072. * @param string $key_pass Password for private key
  5073. * @param string $extracerts_filename Optional path to chain certificate
  5074. */
  5075. public function sign($cert_filename, $key_filename, $key_pass, $extracerts_filename = '')
  5076. {
  5077. $this->sign_cert_file = $cert_filename;
  5078. $this->sign_key_file = $key_filename;
  5079. $this->sign_key_pass = $key_pass;
  5080. $this->sign_extracerts_file = $extracerts_filename;
  5081. }
  5082. /**
  5083. * Quoted-Printable-encode a DKIM header.
  5084. * @access public
  5085. * @param string $txt
  5086. * @return string
  5087. */
  5088. public function DKIM_QP($txt)
  5089. {
  5090. $line = '';
  5091. for ($i = 0; $i < strlen($txt); $i++) {
  5092. $ord = ord($txt[$i]);
  5093. if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
  5094. $line .= $txt[$i];
  5095. } else {
  5096. $line .= '=' . sprintf('%02X', $ord);
  5097. }
  5098. }
  5099. return $line;
  5100. }
  5101. /**
  5102. * Generate a DKIM signature.
  5103. * @access public
  5104. * @param string $signHeader
  5105. * @throws phpmailerException
  5106. * @return string The DKIM signature value
  5107. */
  5108. public function DKIM_Sign($signHeader)
  5109. {
  5110. if (!defined('PKCS7_TEXT')) {
  5111. if ($this->exceptions) {
  5112. throw new phpmailerException($this->lang('extension_missing') . 'openssl');
  5113. }
  5114. return '';
  5115. }
  5116. $privKeyStr = !empty($this->DKIM_private_string) ? $this->DKIM_private_string : file_get_contents($this->DKIM_private);
  5117. if ('' != $this->DKIM_passphrase) {
  5118. $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
  5119. } else {
  5120. $privKey = openssl_pkey_get_private($privKeyStr);
  5121. }
  5122. //Workaround for missing digest algorithms in old PHP & OpenSSL versions
  5123. //@link http://stackoverflow.com/a/11117338/333340
  5124. if (version_compare(PHP_VERSION, '5.3.0') >= 0 and
  5125. in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) {
  5126. if (openssl_sign($signHeader, $signature, $privKey, 'sha256WithRSAEncryption')) {
  5127. openssl_pkey_free($privKey);
  5128. return base64_encode($signature);
  5129. }
  5130. } else {
  5131. $pinfo = openssl_pkey_get_details($privKey);
  5132. $hash = hash('sha256', $signHeader);
  5133. //'Magic' constant for SHA256 from RFC3447
  5134. //@link https://tools.ietf.org/html/rfc3447#page-43
  5135. $t = '3031300d060960864801650304020105000420' . $hash;
  5136. $pslen = $pinfo['bits'] / 8 - (strlen($t) / 2 + 3);
  5137. $eb = pack('H*', '0001' . str_repeat('FF', $pslen) . '00' . $t);
  5138. if (openssl_private_encrypt($eb, $signature, $privKey, OPENSSL_NO_PADDING)) {
  5139. openssl_pkey_free($privKey);
  5140. return base64_encode($signature);
  5141. }
  5142. }
  5143. openssl_pkey_free($privKey);
  5144. return '';
  5145. }
  5146. /**
  5147. * Generate a DKIM canonicalization header.
  5148. * @access public
  5149. * @param string $signHeader Header
  5150. * @return string
  5151. */
  5152. public function DKIM_HeaderC($signHeader)
  5153. {
  5154. $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
  5155. $lines = explode("\r\n", $signHeader);
  5156. foreach ($lines as $key => $line) {
  5157. list($heading, $value) = explode(':', $line, 2);
  5158. $heading = strtolower($heading);
  5159. $value = preg_replace('/\s{2,}/', ' ', $value); // Compress useless spaces
  5160. $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
  5161. }
  5162. $signHeader = implode("\r\n", $lines);
  5163. return $signHeader;
  5164. }
  5165. /**
  5166. * Generate a DKIM canonicalization body.
  5167. * @access public
  5168. * @param string $body Message Body
  5169. * @return string
  5170. */
  5171. public function DKIM_BodyC($body)
  5172. {
  5173. if ($body == '') {
  5174. return "\r\n";
  5175. }
  5176. // stabilize line endings
  5177. $body = str_replace("\r\n", "\n", $body);
  5178. $body = str_replace("\n", "\r\n", $body);
  5179. // END stabilize line endings
  5180. while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
  5181. $body = substr($body, 0, strlen($body) - 2);
  5182. }
  5183. return $body;
  5184. }
  5185. /**
  5186. * Create the DKIM header and body in a new message header.
  5187. * @access public
  5188. * @param string $headers_line Header lines
  5189. * @param string $subject Subject
  5190. * @param string $body Body
  5191. * @return string
  5192. */
  5193. public function DKIM_Add($headers_line, $subject, $body)
  5194. {
  5195. $DKIMsignatureType = 'rsa-sha256'; // Signature & hash algorithms
  5196. $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
  5197. $DKIMquery = 'dns/txt'; // Query method
  5198. $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
  5199. $subject_header = "Subject: $subject";
  5200. $headers = explode($this->LE, $headers_line);
  5201. $from_header = '';
  5202. $to_header = '';
  5203. $date_header = '';
  5204. $current = '';
  5205. foreach ($headers as $header) {
  5206. if (strpos($header, 'From:') === 0) {
  5207. $from_header = $header;
  5208. $current = 'from_header';
  5209. } elseif (strpos($header, 'To:') === 0) {
  5210. $to_header = $header;
  5211. $current = 'to_header';
  5212. } elseif (strpos($header, 'Date:') === 0) {
  5213. $date_header = $header;
  5214. $current = 'date_header';
  5215. } else {
  5216. if (!empty($$current) && strpos($header, ' =?') === 0) {
  5217. $$current .= $header;
  5218. } else {
  5219. $current = '';
  5220. }
  5221. }
  5222. }
  5223. $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
  5224. $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
  5225. $date = str_replace('|', '=7C', $this->DKIM_QP($date_header));
  5226. $subject = str_replace(
  5227. '|',
  5228. '=7C',
  5229. $this->DKIM_QP($subject_header)
  5230. ); // Copied header fields (dkim-quoted-printable)
  5231. $body = $this->DKIM_BodyC($body);
  5232. $DKIMlen = strlen($body); // Length of body
  5233. $DKIMb64 = base64_encode(pack('H*', hash('sha256', $body))); // Base64 of packed binary SHA-256 hash of body
  5234. if ('' == $this->DKIM_identity) {
  5235. $ident = '';
  5236. } else {
  5237. $ident = ' i=' . $this->DKIM_identity . ';';
  5238. }
  5239. $dkimhdrs = 'DKIM-Signature: v=1; a=' .
  5240. $DKIMsignatureType . '; q=' .
  5241. $DKIMquery . '; l=' .
  5242. $DKIMlen . '; s=' .
  5243. $this->DKIM_selector .
  5244. ";\r\n" .
  5245. "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
  5246. "\th=From:To:Date:Subject;\r\n" .
  5247. "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
  5248. "\tz=$from\r\n" .
  5249. "\t|$to\r\n" .
  5250. "\t|$date\r\n" .
  5251. "\t|$subject;\r\n" .
  5252. "\tbh=" . $DKIMb64 . ";\r\n" .
  5253. "\tb=";
  5254. $toSign = $this->DKIM_HeaderC(
  5255. $from_header . "\r\n" .
  5256. $to_header . "\r\n" .
  5257. $date_header . "\r\n" .
  5258. $subject_header . "\r\n" .
  5259. $dkimhdrs
  5260. );
  5261. $signed = $this->DKIM_Sign($toSign);
  5262. return $dkimhdrs . $signed . "\r\n";
  5263. }
  5264. /**
  5265. * Detect if a string contains a line longer than the maximum line length allowed.
  5266. * @param string $str
  5267. * @return boolean
  5268. * @static
  5269. */
  5270. public static function hasLineLongerThanMax($str)
  5271. {
  5272. //+2 to include CRLF line break for a 1000 total
  5273. return (boolean)preg_match('/^(.{'.(self::MAX_LINE_LENGTH + 2).',})/m', $str);
  5274. }
  5275. /**
  5276. * Allows for public read access to 'to' property.
  5277. * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
  5278. * @access public
  5279. * @return array
  5280. */
  5281. public function getToAddresses()
  5282. {
  5283. return $this->to;
  5284. }
  5285. /**
  5286. * Allows for public read access to 'cc' property.
  5287. * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
  5288. * @access public
  5289. * @return array
  5290. */
  5291. public function getCcAddresses()
  5292. {
  5293. return $this->cc;
  5294. }
  5295. /**
  5296. * Allows for public read access to 'bcc' property.
  5297. * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
  5298. * @access public
  5299. * @return array
  5300. */
  5301. public function getBccAddresses()
  5302. {
  5303. return $this->bcc;
  5304. }
  5305. /**
  5306. * Allows for public read access to 'ReplyTo' property.
  5307. * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
  5308. * @access public
  5309. * @return array
  5310. */
  5311. public function getReplyToAddresses()
  5312. {
  5313. return $this->ReplyTo;
  5314. }
  5315. /**
  5316. * Allows for public read access to 'all_recipients' property.
  5317. * @note: Before the send() call, queued addresses (i.e. with IDN) are not yet included.
  5318. * @access public
  5319. * @return array
  5320. */
  5321. public function getAllRecipientAddresses()
  5322. {
  5323. return $this->all_recipients;
  5324. }
  5325. /**
  5326. * Perform a callback.
  5327. * @param boolean $isSent
  5328. * @param array $to
  5329. * @param array $cc
  5330. * @param array $bcc
  5331. * @param string $subject
  5332. * @param string $body
  5333. * @param string $from
  5334. */
  5335. protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
  5336. {
  5337. if (!empty($this->action_function) && is_callable($this->action_function)) {
  5338. $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
  5339. call_user_func_array($this->action_function, $params);
  5340. }
  5341. }
  5342. }
  5343. /**
  5344. * PHPMailer exception handler
  5345. * @package PHPMailer
  5346. */
  5347. class phpmailerException extends Exception
  5348. {
  5349. /**
  5350. * Prettify error message output
  5351. * @return string
  5352. */
  5353. public function errorMessage()
  5354. {
  5355. $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
  5356. return $errorMsg;
  5357. }
  5358. }
  5359.  
  5360.  
  5361. $mail = new PHPMailer();
  5362.  
  5363.  
  5364. // REMOVE ALL HTML TAG WILL BE USED IN ALTBODY
  5365. function strip_tags_content($text, $tags = '', $invert = FALSE) {
  5366.  
  5367. /*preg_match_all('/<(.+?)[\s]*\/?[\s]*>/si', trim($tags), $tags);
  5368. $tags = array_unique($tags[1]);
  5369.  
  5370. if(is_array($tags) AND count($tags) > 0) {
  5371. if($invert == FALSE) {
  5372. return preg_replace('@<(?!(?:'. implode('|', $tags) .')\b)(\w+)\b.*?>.*?</\1>@si', '', $text);
  5373. }
  5374. else {
  5375. return preg_replace('@<('. implode('|', $tags) .')\b.*?>.*?</\1>@si', '', $text);
  5376. }
  5377. }
  5378. elseif($invert == FALSE) {
  5379. return preg_replace('@<(\w+)\b.*?>.*?</\1>@si', '', $text);
  5380. } */
  5381. return strip_tags($text);
  5382. }
  5383.  
  5384. // TRIM LEFT AND RIGHT
  5385. function lrtrim($string)
  5386. {
  5387. return stripslashes(ltrim(rtrim($string)));
  5388. }
  5389. // REPLACE LAST OCCURENCE OF STRING
  5390. function str_lreplace($search, $replace, $subject)
  5391. {
  5392. $pos = strrpos($subject, $search);
  5393.  
  5394. if($pos !== false)
  5395. {
  5396. $subject = substr_replace($subject, $replace, $pos, strlen($search));
  5397. }
  5398.  
  5399. return $subject;
  5400. }
  5401. // RANDOM STRING FUNCTION
  5402. function generateRandomString($matches)
  5403. {
  5404. $length = intval(ltrim(rtrim($matches[3])));
  5405. $PATTERN = str_lreplace('-','',$matches[2]);
  5406.  
  5407. $characters = '';
  5408. if(strpos($PATTERN, '09') !== false)
  5409. $characters .= '0123456789';
  5410. if(strpos($PATTERN, 'az') !== false)
  5411. $characters .= 'abcdefghijklmnopqrstuvwxyz';
  5412. if(strpos($PATTERN, 'AZ') !== false)
  5413. $characters .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  5414. $charactersLength = strlen($characters);
  5415. $randomString = '';
  5416. for ($i = 0; $i < $length; $i++) {
  5417. $randomString .= $characters[rand(0, $charactersLength - 1)];
  5418. }
  5419. return $randomString;
  5420. }
  5421. // WAITING FUNCTION
  5422. function pause($pause,$mail)
  5423. {
  5424. $sec=doubleval($pause);
  5425. $mail->SmtpClose();
  5426. echo "\n\n<br><br>############################### WAITING $sec SEC TO CONTINUE SENDING ###############################<br><br>\n\n";
  5427. flush();
  5428. sleep($sec);
  5429. }
  5430. // SMTP SWITCH
  5431. function switch_smtp()
  5432. {
  5433. global $allsmtps;
  5434. global $curentsmtp;
  5435. global $mail;
  5436. global $isbcc;
  5437. global $from;
  5438. global $lase;
  5439. global $replyto;
  5440. global $reading;
  5441. global $repaslog;
  5442. if(count($allsmtps) > $curentsmtp)
  5443. {
  5444. $smtprot = explode(':',$allsmtps[$curentsmtp]);
  5445. if(count($smtprot) > 0)
  5446. {
  5447. $mail->Host = $smtprot[0];
  5448. $mail->Port = $smtprot[1];
  5449. $mail->Username = $smtprot[2];
  5450. $mail->Password = $smtprot[3];
  5451. if($reading && $repaslog)
  5452. $replyto = $smtprot[2];
  5453. if($lase)
  5454. {
  5455. $from = $smtprot[2];
  5456. $from_base = $smtprot[2];
  5457. }
  5458.  
  5459. if($smtprot[4] =="SSL")
  5460. $mail->SMTPSecure = "ssl"; //you can change it to ssl or tls
  5461. else if($smtprot[4] =="TLS")
  5462. $mail->SMTPSecure = "tls";
  5463. else if($smtprot[4] =="NON")
  5464. $mail->SMTPSecure = "";
  5465. if($smtprot[5] =="BCC")
  5466. $isbcc = true;
  5467. else $isbcc = false;
  5468.  
  5469. }
  5470. }
  5471. }
  5472.  
  5473.  
  5474. if ($action)
  5475. {
  5476. if (!$from && !$subject && !$message && !$emaillist)
  5477. {
  5478. print "<script>alert('PLEASE FILL ALL FIELDS BEFORE SENDING YOUR MESSAGE.'); </script>";
  5479. die();
  5480. }
  5481. else
  5482. {
  5483. $allemails = preg_split("/\\r\\n|\\r|\\n/", $emaillist);
  5484. $numemails = count($allemails);
  5485. $nq=0;
  5486. $qx=0;
  5487.  
  5488. if(!empty($epriority))
  5489. $mail->Priority = "$epriority";
  5490. if($contenttype == "html")
  5491. $mail->IsHtml(true);
  5492. else
  5493. $mail->IsHtml(false);
  5494. if(empty($reconnect))
  5495. $reconnect=0;
  5496. if(!empty($replyto))
  5497. $mail->AddReplyTo("$replyto");
  5498. if(empty($my_smtp))
  5499. {
  5500. $mail->SMTPAuth = false;
  5501. $mail->IsSendmail();
  5502. $default_system="1";
  5503. }
  5504. else
  5505. {
  5506. $mail->IsSMTP();
  5507. $mail->SMTPKeepAlive = true;
  5508. $mail->SMTPAuth = true;
  5509. switch_smtp();
  5510. }
  5511. $mail->From = $from;
  5512. #$mail->addCustomHeader('List-Unsubscribe',preg_replace_callback('/(##([a-zA-Z0-9\-]+)\{([0-9]+)\}##)/', "generateRandomString", 'mailto:bounce##09-{3}##-##az-AZ-09-{15}##@'.explode('@',$from)[1].'?subject=list-unsubscribe'));
  5513. // SET DEBUG LVL
  5514. $mail->SMTPDebug = $debg;
  5515. // SET CHARSET
  5516. $mail->CharSet = "UTF-8";
  5517. // READING CONFIRMATION
  5518. if($reading)
  5519. $mail->ConfirmReadingTo = $replyto;
  5520. else $mail->ConfirmReadingTo = '';
  5521. // SET ENCODING TYPE
  5522. if($encodety !="no") $mail->Encoding = $encodety;
  5523. // ADD ATTACH
  5524. if (array_key_exists('userfile', $_FILES))
  5525. {
  5526. // First handle the upload
  5527. // Don't trust provided filename - same goes for MIME types
  5528. // See http://php.net/manual/en/features.file-upload.php#114004 for more thorough upload validation
  5529. $uploadfile = tempnam(sys_get_temp_dir(), sha1($_FILES['userfile']['name']));
  5530. if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile))
  5531. {
  5532. $mail->addAttachment($uploadfile,$_FILES['userfile']['name']);
  5533. }
  5534. }
  5535. for($x=1; $x<=$numemails; $x++)
  5536. {
  5537. // BCC EMAIL COUNT
  5538. if($isbcc && $x % intval($nbcc) == 0)
  5539. {
  5540. $nm += 1;
  5541. $nopose=false;
  5542. $canrotat=true;
  5543. }
  5544. else
  5545. {
  5546. $nopose=true;
  5547. $canrotat=false;
  5548. }
  5549. //END//
  5550.  
  5551. $send=false;
  5552. $v=$x-1;
  5553. $to = $allemails[$v];
  5554. $to = preg_replace("/ /", "", $to);
  5555.  
  5556. // ADD ADRESSES TO QUEUE
  5557. if($isbcc && !empty($nbcc) )
  5558. {
  5559.  
  5560. if($x % intval($nbcc) != 0 && $x <= $numemails)
  5561. {
  5562. $mail->addBCC("$to");
  5563. print "<span style=\"color:red;\">Line $qx </span> : Sending mail to $to<br>";
  5564. flush();
  5565. if($x % intval($nbcc) != 0 && $x == $numemails)
  5566. $send=true;
  5567. }
  5568. else
  5569. {
  5570. $mail->addBCC("$to");
  5571. print "<span style=\"color:red;\">Line $qx </span> : Sending mail to $to<br>";
  5572. flush();
  5573. $send = true;
  5574. }
  5575. $qx=$x;
  5576. }
  5577. else
  5578. {
  5579. $mail->clearAddresses();
  5580. $mail->AddAddress("$to");
  5581. $send=true;
  5582. print "<span style=\"color:red;\">Line $qx </span> : Sending mail to $to.......";
  5583. flush();
  5584. $qx=$x;
  5585. }
  5586. //END//
  5587. if($send)
  5588. {
  5589.  
  5590. $realname = preg_replace_callback('/(##([a-zA-Z0-9\-]+)\{([0-9]+)\}##)/', "generateRandomString", $realname_base);
  5591. $message = preg_replace_callback('/(##([a-zA-Z0-9\-]+)\{([0-9]+)\}##)/', "generateRandomString", $message_base);
  5592. $subject = preg_replace_callback('/(##([a-zA-Z0-9\-]+)\{([0-9]+)\}##)/', "generateRandomString", $subject_base);
  5593. // $from = preg_replace_callback('/(##([a-zA-Z0-9\-]+)\{([0-9]+)\}##)/', "generateRandomString", $from_base);
  5594. $from = preg_replace('/[0-9]+/', rand(90000 , 10000), $from);
  5595.  
  5596. if(!$isbcc)
  5597. {
  5598. $message = preg_replace("/!!EMAIL!!/", $to, $message);
  5599. $subject = preg_replace("/!!EMAIL!!/", $to, $subject);
  5600. }
  5601. $message = preg_replace("/!!DATE!!/", date("d/m/Y"), $message);
  5602. $subject = preg_replace("/!!DATE!!/", date("d/m/Y"), $subject);
  5603. $message = preg_replace("/!!TIME!!/", date("H:i:s"), $message);
  5604. $subject = preg_replace("/!!TIME!!/", date("H:i:s"), $subject);
  5605. $message = urlencode($message);
  5606. $message = preg_replace("/%5C%22/", "%22", $message);
  5607. $message = urldecode($message);
  5608. $message = stripslashes($message);
  5609. $subject = stripslashes($subject);
  5610.  
  5611. if ($encodety != "no")
  5612. {
  5613. $subject = "=?UTF-8?B?".base64_encode($subject)."?=";
  5614. $realname = "=?UTF-8?B?".base64_encode($realname)."?=";
  5615. }
  5616.  
  5617. $mail->FromName = "$realname";
  5618. $mail->Subject = "$subject";
  5619. $mail->Body = "$message";
  5620. $mail->AltBody = strip_tags_content($message);
  5621. // SENDING AND TESTING
  5622. if(!$mail->Send())
  5623. {
  5624. if($default_system != "1")
  5625. {
  5626. echo "FAILED !!<font color=\"#D4001A\"> [RECEPIENT CAN'T RECEIVE MESSAGE.]</font><br>";
  5627. }
  5628. if($default_system == "1")
  5629. {
  5630. $mail->IsMail();
  5631. if(!$mail->Send())
  5632. {
  5633. echo "FAILED !!<font color=\"#D4001A\"> [RECEPIENT CAN'T RECEIVE MESSAGE.]</font><br>";
  5634. }
  5635. else
  5636. {
  5637. if($isbcc)
  5638. echo "# BCC EMAIL NUMERO <span style=\"color:red;\">NUMERO $nm </span> SEND :<b>OK</b><br>";
  5639. else echo "<b>OK</b><br>";
  5640. }
  5641. }
  5642. }
  5643. else
  5644. {
  5645. if($isbcc)
  5646. echo "# BCC EMAIL <span style=\"color:red;\">NUMERO $nm </span> SEND :<b>OK</b><br>";
  5647. else echo "<b>OK</b><br>";
  5648. }
  5649. if($reconnect >0 && $reconnect==$nq && !(intval($nrotat) > 0 && count($allsmtps) > 1))
  5650. {
  5651. $mail->SmtpClose();
  5652. echo "<p><b>########################### SMTP CLOSED AND ATTEMPTS TO RECONNECT NEW CONNECTION SEASON ########################### </b></p>";
  5653. $nq=0;
  5654. }
  5655. $nq=$nq+1;
  5656. flush();
  5657. if($isbcc)
  5658. $mail->clearBCCs();
  5659. }
  5660. //END//
  5661.  
  5662. // SMTP IP ROTATION NB: 1 BCC = 1 EMAIL
  5663. if(intval($nrotat) > 0 && count($allsmtps) > 1)
  5664. {
  5665. $curentsmtp += 1;
  5666. $nq=0;
  5667. $mail->SmtpClose();
  5668. switch_smtp();
  5669. if($isbcc)
  5670. {
  5671. if($nm > 0 && $nm % intval($nrotat) == 0 && $canrotat && $x < $numemails)
  5672. {
  5673. echo "\n<br><span style=\"color:red;\">##############</span><b> ROTATE TO SMTP ".($curentsmtp+1)." IP: ".$mail->Host."</b><span style=\"color:red;\"> ##############</span><br><br>\n";
  5674.  
  5675. }
  5676. }
  5677. else if ($x % intval($nrotat)==0 && $x < $numemails)
  5678. {
  5679. if($x >= intval($nrotat))
  5680. echo "\n<br><span style=\"color:red;\">##############</span><b> ROTATE TO SMTP ".($curentsmtp+1)." IP: ".$mail->Host."</b><span style=\"color:red;\"> ##############</span><br><br>\n\n";
  5681. }
  5682. if($curentsmtp >= count($allsmtps))
  5683. {
  5684. $curentsmtp=0;
  5685. }
  5686.  
  5687. }
  5688. //END//
  5689.  
  5690. // WAITING PAUSE TIME
  5691. if(!empty($pause) && !empty($pemails))
  5692. {
  5693. if(doubleval($pause) > 0)
  5694. {
  5695. if(!$isbcc)
  5696. {
  5697. if($x % intval($pemails) == 0 && $x < $numemails)
  5698. {
  5699. pause($pause,$mail);
  5700. }
  5701. }
  5702. else if($nm > 0 && $nm % intval($pemails) == 0 && $x < $numemails && !$nopose)
  5703. {
  5704. pause($pause,$mail);
  5705. }
  5706. }
  5707. }
  5708. //END//
  5709. }
  5710. }
  5711. }
  5712. ?>
Add Comment
Please, Sign In to add comment