yagami0x

Untitled

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