PHPMailer

PHPMailer - PHP email creation and transport class.

Defined (1)

The class is defined in the following location(s).

/bp-forums/bbpress/bb-includes/backpress/class.mailer.php  
  1. class PHPMailer { 
  2.  
  3. ///////////////////////////////////////////////// 
  4. // PROPERTIES, PUBLIC 
  5. ///////////////////////////////////////////////// 
  6.  
  7. /** 
  8. * Email priority (1 = High, 3 = Normal, 5 = low). 
  9. * @var int 
  10. */ 
  11. var $Priority = 3; 
  12.  
  13. /** 
  14. * Sets the CharSet of the message. 
  15. * @var string 
  16. */ 
  17. var $CharSet = 'iso-8859-1'; 
  18.  
  19. /** 
  20. * Sets the Content-type of the message. 
  21. * @var string 
  22. */ 
  23. var $ContentType = 'text/plain'; 
  24.  
  25. /** 
  26. * Sets the Encoding of the message. Options for this are "8bit",  
  27. * "7bit", "binary", "base64", and "quoted-printable". 
  28. * @var string 
  29. */ 
  30. var $Encoding = '8bit'; 
  31.  
  32. /** 
  33. * Holds the most recent mailer error message. 
  34. * @var string 
  35. */ 
  36. var $ErrorInfo = ''; 
  37.  
  38. /** 
  39. * Sets the From email address for the message. 
  40. * @var string 
  41. */ 
  42. var $From = 'root@localhost'; 
  43.  
  44. /** 
  45. * Sets the From name of the message. 
  46. * @var string 
  47. */ 
  48. var $FromName = 'Root User'; 
  49.  
  50. /** 
  51. * Sets the Sender email (Return-Path) of the message. If not empty,  
  52. * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode. 
  53. * @var string 
  54. */ 
  55. var $Sender = ''; 
  56.  
  57. /** 
  58. * Sets the Subject of the message. 
  59. * @var string 
  60. */ 
  61. var $Subject = ''; 
  62.  
  63. /** 
  64. * Sets the Body of the message. This can be either an HTML or text body. 
  65. * If HTML then run IsHTML(true). 
  66. * @var string 
  67. */ 
  68. var $Body = ''; 
  69.  
  70. /** 
  71. * Sets the text-only body of the message. This automatically sets the 
  72. * email to multipart/alternative. This body can be read by mail 
  73. * clients that do not have HTML email capability such as mutt. Clients 
  74. * that can read HTML will view the normal Body. 
  75. * @var string 
  76. */ 
  77. var $AltBody = ''; 
  78.  
  79. /** 
  80. * Sets word wrapping on the body of the message to a given number of 
  81. * characters. 
  82. * @var int 
  83. */ 
  84. var $WordWrap = 0; 
  85.  
  86. /** 
  87. * Method to send mail: ("mail", "sendmail", or "smtp"). 
  88. * @var string 
  89. */ 
  90. var $Mailer = 'mail'; 
  91.  
  92. /** 
  93. * Sets the path of the sendmail program. 
  94. * @var string 
  95. */ 
  96. var $Sendmail = '/usr/sbin/sendmail'; 
  97.  
  98. /** 
  99. * Path to PHPMailer plugins. This is now only useful if the SMTP class 
  100. * is in a different directory than the PHP include path. 
  101. * @var string 
  102. */ 
  103. var $PluginDir = ''; 
  104.  
  105. /** 
  106. * Holds PHPMailer version. 
  107. * @var string 
  108. */ 
  109. var $Version = "2.0.4"; 
  110.  
  111. /** 
  112. * Sets the email address that a reading confirmation will be sent. 
  113. * @var string 
  114. */ 
  115. var $ConfirmReadingTo = ''; 
  116.  
  117. /** 
  118. * Sets the hostname to use in Message-Id and Received headers 
  119. * and as default HELO string. If empty, the value returned 
  120. * by SERVER_NAME is used or 'localhost.localdomain'. 
  121. * @var string 
  122. */ 
  123. var $Hostname = ''; 
  124.  
  125. /** 
  126. * Sets the message ID to be used in the Message-Id header. 
  127. * If empty, a unique id will be generated. 
  128. * @var string 
  129. */ 
  130. var $MessageID = ''; 
  131.  
  132. ///////////////////////////////////////////////// 
  133. // PROPERTIES FOR SMTP 
  134. ///////////////////////////////////////////////// 
  135.  
  136. /** 
  137. * Sets the SMTP hosts. All hosts must be separated by a 
  138. * semicolon. You can also specify a different port 
  139. * for each host by using this format: [hostname:port] 
  140. * (e.g. "smtp1.example.com:25;smtp2.example.com"). 
  141. * Hosts will be tried in order. 
  142. * @var string 
  143. */ 
  144. var $Host = 'localhost'; 
  145.  
  146. /** 
  147. * Sets the default SMTP server port. 
  148. * @var int 
  149. */ 
  150. var $Port = 25; 
  151.  
  152. /** 
  153. * Sets the SMTP HELO of the message (Default is $Hostname). 
  154. * @var string 
  155. */ 
  156. var $Helo = ''; 
  157.  
  158. /** 
  159. * Sets connection prefix. 
  160. * Options are "", "ssl" or "tls" 
  161. * @var string 
  162. */ 
  163. var $SMTPSecure = ""; 
  164.  
  165. /** 
  166. * Sets SMTP authentication. Utilizes the Username and Password variables. 
  167. * @var bool 
  168. */ 
  169. var $SMTPAuth = false; 
  170.  
  171. /** 
  172. * Sets SMTP username. 
  173. * @var string 
  174. */ 
  175. var $Username = ''; 
  176.  
  177. /** 
  178. * Sets SMTP password. 
  179. * @var string 
  180. */ 
  181. var $Password = ''; 
  182.  
  183. /** 
  184. * Sets the SMTP server timeout in seconds. This function will not 
  185. * work with the win32 version. 
  186. * @var int 
  187. */ 
  188. var $Timeout = 10; 
  189.  
  190. /** 
  191. * Sets SMTP class debugging on or off. 
  192. * @var bool 
  193. */ 
  194. var $SMTPDebug = false; 
  195.  
  196. /** 
  197. * Prevents the SMTP connection from being closed after each mail 
  198. * sending. If this is set to true then to close the connection 
  199. * requires an explicit call to SmtpClose(). 
  200. * @var bool 
  201. */ 
  202. var $SMTPKeepAlive = false; 
  203.  
  204. /** 
  205. * Provides the ability to have the TO field process individual 
  206. * emails, instead of sending to entire TO addresses 
  207. * @var bool 
  208. */ 
  209. var $SingleTo = false; 
  210.  
  211. ///////////////////////////////////////////////// 
  212. // PROPERTIES, PRIVATE 
  213. ///////////////////////////////////////////////// 
  214.  
  215. var $smtp = NULL; 
  216. var $to = array(); 
  217. var $cc = array(); 
  218. var $bcc = array(); 
  219. var $ReplyTo = array(); 
  220. var $attachment = array(); 
  221. var $CustomHeader = array(); 
  222. var $message_type = ''; 
  223. var $boundary = array(); 
  224. var $language = array(); 
  225. var $error_count = 0; 
  226. var $LE = "\n"; 
  227. var $sign_cert_file = ""; 
  228. var $sign_key_file = ""; 
  229. var $sign_key_pass = ""; 
  230.  
  231. ///////////////////////////////////////////////// 
  232. // METHODS, VARIABLES 
  233. ///////////////////////////////////////////////// 
  234.  
  235. /** 
  236. * Sets message type to HTML. 
  237. * @param bool $bool 
  238. * @return void 
  239. */ 
  240. function IsHTML($bool) { 
  241. if($bool == true) { 
  242. $this->ContentType = 'text/html'; 
  243. } else { 
  244. $this->ContentType = 'text/plain'; 
  245.  
  246. /** 
  247. * Sets Mailer to send message using SMTP. 
  248. * @return void 
  249. */ 
  250. function IsSMTP() { 
  251. $this->Mailer = 'smtp'; 
  252.  
  253. /** 
  254. * Sets Mailer to send message using PHP mail() function. 
  255. * @return void 
  256. */ 
  257. function IsMail() { 
  258. $this->Mailer = 'mail'; 
  259.  
  260. /** 
  261. * Sets Mailer to send message using the $Sendmail program. 
  262. * @return void 
  263. */ 
  264. function IsSendmail() { 
  265. $this->Mailer = 'sendmail'; 
  266.  
  267. /** 
  268. * Sets Mailer to send message using the qmail MTA. 
  269. * @return void 
  270. */ 
  271. function IsQmail() { 
  272. $this->Sendmail = '/var/qmail/bin/sendmail'; 
  273. $this->Mailer = 'sendmail'; 
  274.  
  275. ///////////////////////////////////////////////// 
  276. // METHODS, RECIPIENTS 
  277. ///////////////////////////////////////////////// 
  278.  
  279. /** 
  280. * Adds a "To" address. 
  281. * @param string $address 
  282. * @param string $name 
  283. * @return void 
  284. */ 
  285. function AddAddress($address, $name = '') { 
  286. $cur = count($this->to); 
  287. $this->to[$cur][0] = trim($address); 
  288. $this->to[$cur][1] = $name; 
  289.  
  290. /** 
  291. * Adds a "Cc" address. Note: this function works 
  292. * with the SMTP mailer on win32, not with the "mail" 
  293. * mailer. 
  294. * @param string $address 
  295. * @param string $name 
  296. * @return void 
  297. */ 
  298. function AddCC($address, $name = '') { 
  299. $cur = count($this->cc); 
  300. $this->cc[$cur][0] = trim($address); 
  301. $this->cc[$cur][1] = $name; 
  302.  
  303. /** 
  304. * Adds a "Bcc" address. Note: this function works 
  305. * with the SMTP mailer on win32, not with the "mail" 
  306. * mailer. 
  307. * @param string $address 
  308. * @param string $name 
  309. * @return void 
  310. */ 
  311. function AddBCC($address, $name = '') { 
  312. $cur = count($this->bcc); 
  313. $this->bcc[$cur][0] = trim($address); 
  314. $this->bcc[$cur][1] = $name; 
  315.  
  316. /** 
  317. * Adds a "Reply-To" address. 
  318. * @param string $address 
  319. * @param string $name 
  320. * @return void 
  321. */ 
  322. function AddReplyTo($address, $name = '') { 
  323. $cur = count($this->ReplyTo); 
  324. $this->ReplyTo[$cur][0] = trim($address); 
  325. $this->ReplyTo[$cur][1] = $name; 
  326.  
  327. ///////////////////////////////////////////////// 
  328. // METHODS, MAIL SENDING 
  329. ///////////////////////////////////////////////// 
  330.  
  331. /** 
  332. * Creates message and assigns Mailer. If the message is 
  333. * not sent successfully then it returns false. Use the ErrorInfo 
  334. * variable to view description of the error. 
  335. * @return bool 
  336. */ 
  337. function Send() { 
  338. $header = ''; 
  339. $body = ''; 
  340. $result = true; 
  341.  
  342. if((count($this->to) + count($this->cc) + count($this->bcc)) < 1) { 
  343. $this->SetError($this->Lang('provide_address')); 
  344. return false; 
  345.  
  346. /** Set whether the message is multipart/alternative */ 
  347. if(!empty($this->AltBody)) { 
  348. $this->ContentType = 'multipart/alternative'; 
  349.  
  350. $this->error_count = 0; // reset errors 
  351. $this->SetMessageType(); 
  352. $header .= $this->CreateHeader(); 
  353. $body = $this->CreateBody(); 
  354.  
  355. if($body == '') { 
  356. return false; 
  357.  
  358. /** Choose the mailer */ 
  359. switch($this->Mailer) { 
  360. case 'sendmail': 
  361. $result = $this->SendmailSend($header, $body); 
  362. break; 
  363. case 'smtp': 
  364. $result = $this->SmtpSend($header, $body); 
  365. break; 
  366. case 'mail': 
  367. $result = $this->MailSend($header, $body); 
  368. break; 
  369. default: 
  370. $result = $this->MailSend($header, $body); 
  371. break; 
  372. //$this->SetError($this->Mailer . $this->Lang('mailer_not_supported')); 
  373. //$result = false; 
  374. //break; 
  375.  
  376. return $result; 
  377.  
  378. /** 
  379. * Sends mail using the $Sendmail program. 
  380. * @access private 
  381. * @return bool 
  382. */ 
  383. function SendmailSend($header, $body) { 
  384. if ($this->Sender != '') { 
  385. $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender)); 
  386. } else { 
  387. $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail)); 
  388.  
  389. if(!@$mail = popen($sendmail, 'w')) { 
  390. $this->SetError($this->Lang('execute') . $this->Sendmail); 
  391. return false; 
  392.  
  393. fputs($mail, $header); 
  394. fputs($mail, $body); 
  395.  
  396. $result = pclose($mail); 
  397. if (version_compare(phpversion(), '4.2.3') == -1) { 
  398. $result = $result >> 8 & 0xFF; 
  399. if($result != 0) { 
  400. $this->SetError($this->Lang('execute') . $this->Sendmail); 
  401. return false; 
  402. return true; 
  403.  
  404. /** 
  405. * Sends mail using the PHP mail() function. 
  406. * @access private 
  407. * @return bool 
  408. */ 
  409. function MailSend($header, $body) { 
  410.  
  411. $to = ''; 
  412. for($i = 0; $i < count($this->to); $i++) { 
  413. if($i != 0) { $to .= ', '; } 
  414. $to .= $this->AddrFormat($this->to[$i]); 
  415.  
  416. $toArr = explode(', ', $to); 
  417.  
  418. $params = sprintf("-oi -f %s", $this->Sender); 
  419. if ($this->Sender != '' && strlen(ini_get('safe_mode')) < 1) { 
  420. $old_from = ini_get('sendmail_from'); 
  421. ini_set('sendmail_from', $this->Sender); 
  422. if ($this->SingleTo === true && count($toArr) > 1) { 
  423. foreach ($toArr as $key => $val) { 
  424. $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 
  425. } else { 
  426. $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 
  427. } else { 
  428. if ($this->SingleTo === true && count($toArr) > 1) { 
  429. foreach ($toArr as $key => $val) { 
  430. $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params); 
  431. } else { 
  432. $rt = @mail($to, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header); 
  433.  
  434. if (isset($old_from)) { 
  435. ini_set('sendmail_from', $old_from); 
  436.  
  437. if(!$rt) { 
  438. $this->SetError($this->Lang('instantiate')); 
  439. return false; 
  440.  
  441. return true; 
  442.  
  443. /** 
  444. * Sends mail via SMTP using PhpSMTP (Author: 
  445. * Chris Ryan). Returns bool. Returns false if there is a 
  446. * bad MAIL FROM, RCPT, or DATA input. 
  447. * @access private 
  448. * @return bool 
  449. */ 
  450. function SmtpSend($header, $body) { 
  451. include_once('class.mailer-smtp.php'); 
  452. $error = ''; 
  453. $bad_rcpt = array(); 
  454.  
  455. if(!$this->SmtpConnect()) { 
  456. return false; 
  457.  
  458. $smtp_from = ($this->Sender == '') ? $this->From : $this->Sender; 
  459. if(!$this->smtp->Mail($smtp_from)) { 
  460. $error = $this->Lang('from_failed') . $smtp_from; 
  461. $this->SetError($error); 
  462. $this->smtp->Reset(); 
  463. return false; 
  464.  
  465. /** Attempt to send attach all recipients */ 
  466. for($i = 0; $i < count($this->to); $i++) { 
  467. if(!$this->smtp->Recipient($this->to[$i][0])) { 
  468. $bad_rcpt[] = $this->to[$i][0]; 
  469. for($i = 0; $i < count($this->cc); $i++) { 
  470. if(!$this->smtp->Recipient($this->cc[$i][0])) { 
  471. $bad_rcpt[] = $this->cc[$i][0]; 
  472. for($i = 0; $i < count($this->bcc); $i++) { 
  473. if(!$this->smtp->Recipient($this->bcc[$i][0])) { 
  474. $bad_rcpt[] = $this->bcc[$i][0]; 
  475.  
  476. if(count($bad_rcpt) > 0) { // Create error message 
  477. for($i = 0; $i < count($bad_rcpt); $i++) { 
  478. if($i != 0) { 
  479. $error .= ', '; 
  480. $error .= $bad_rcpt[$i]; 
  481. $error = $this->Lang('recipients_failed') . $error; 
  482. $this->SetError($error); 
  483. $this->smtp->Reset(); 
  484. return false; 
  485.  
  486. if(!$this->smtp->Data($header . $body)) { 
  487. $this->SetError($this->Lang('data_not_accepted')); 
  488. $this->smtp->Reset(); 
  489. return false; 
  490. if($this->SMTPKeepAlive == true) { 
  491. $this->smtp->Reset(); 
  492. } else { 
  493. $this->SmtpClose(); 
  494.  
  495. return true; 
  496.  
  497. /** 
  498. * Initiates a connection to an SMTP server. Returns false if the 
  499. * operation failed. 
  500. * @access private 
  501. * @return bool 
  502. */ 
  503. function SmtpConnect() { 
  504. if($this->smtp == NULL) { 
  505. $this->smtp = new SMTP(); 
  506.  
  507. $this->smtp->do_debug = $this->SMTPDebug; 
  508. $hosts = explode(';', $this->Host); 
  509. $index = 0; 
  510. $connection = ($this->smtp->Connected()); 
  511.  
  512. /** Retry while there is no connection */ 
  513. while($index < count($hosts) && $connection == false) { 
  514. $hostinfo = array(); 
  515. if(preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) { 
  516. $host = $hostinfo[1]; 
  517. $port = $hostinfo[2]; 
  518. } else { 
  519. $host = $hosts[$index]; 
  520. $port = $this->Port; 
  521.  
  522. if($this->smtp->Connect(((!empty($this->SMTPSecure))?$this->SMTPSecure.'://':'').$host, $port, $this->Timeout)) { 
  523. if ($this->Helo != '') { 
  524. $this->smtp->Hello($this->Helo); 
  525. } else { 
  526. $this->smtp->Hello($this->ServerHostname()); 
  527.  
  528. $connection = true; 
  529. if($this->SMTPAuth) { 
  530. if(!$this->smtp->Authenticate($this->Username, $this->Password)) { 
  531. $this->SetError($this->Lang('authenticate')); 
  532. $this->smtp->Reset(); 
  533. $connection = false; 
  534. $index++; 
  535. if(!$connection) { 
  536. $this->SetError($this->Lang('connect_host')); 
  537.  
  538. return $connection; 
  539.  
  540. /** 
  541. * Closes the active SMTP session if one exists. 
  542. * @return void 
  543. */ 
  544. function SmtpClose() { 
  545. if($this->smtp != NULL) { 
  546. if($this->smtp->Connected()) { 
  547. $this->smtp->Quit(); 
  548. $this->smtp->Close(); 
  549.  
  550. /** 
  551. * Sets the language for all class error messages. Returns false 
  552. * if it cannot load the language file. The default language type 
  553. * is English. 
  554. * @param string $lang_type Type of language (e.g. Portuguese: "br") 
  555. * @param string $lang_path Path to the language file directory 
  556. * @access public 
  557. * @return bool 
  558. */ 
  559. function SetLanguage($lang_type, $lang_path = 'language/') { 
  560. if(file_exists($lang_path.'phpmailer.lang-'.$lang_type.'.php')) { 
  561. include($lang_path.'phpmailer.lang-'.$lang_type.'.php'); 
  562. } elseif (file_exists($lang_path.'phpmailer.lang-en.php')) { 
  563. include($lang_path.'phpmailer.lang-en.php'); 
  564. } else { 
  565. $PHPMAILER_LANG = array(); 
  566. $PHPMAILER_LANG["provide_address"] = 'You must provide at least one ' . 
  567. $PHPMAILER_LANG["mailer_not_supported"] = ' mailer is not supported.'; 
  568. $PHPMAILER_LANG["execute"] = 'Could not execute: '; 
  569. $PHPMAILER_LANG["instantiate"] = 'Could not instantiate mail function.'; 
  570. $PHPMAILER_LANG["authenticate"] = 'SMTP Error: Could not authenticate.'; 
  571. $PHPMAILER_LANG["from_failed"] = 'The following From address failed: '; 
  572. $PHPMAILER_LANG["recipients_failed"] = 'SMTP Error: The following ' . 
  573. $PHPMAILER_LANG["data_not_accepted"] = 'SMTP Error: Data not accepted.'; 
  574. $PHPMAILER_LANG["connect_host"] = 'SMTP Error: Could not connect to SMTP host.'; 
  575. $PHPMAILER_LANG["file_access"] = 'Could not access file: '; 
  576. $PHPMAILER_LANG["file_open"] = 'File Error: Could not open file: '; 
  577. $PHPMAILER_LANG["encoding"] = 'Unknown encoding: '; 
  578. $PHPMAILER_LANG["signing"] = 'Signing Error: '; 
  579. $this->language = $PHPMAILER_LANG; 
  580.  
  581. return true; 
  582.  
  583. ///////////////////////////////////////////////// 
  584. // METHODS, MESSAGE CREATION 
  585. ///////////////////////////////////////////////// 
  586.  
  587. /** 
  588. * Creates recipient headers. 
  589. * @access private 
  590. * @return string 
  591. */ 
  592. function AddrAppend($type, $addr) { 
  593. $addr_str = $type . ': '; 
  594. $addr_str .= $this->AddrFormat($addr[0]); 
  595. if(count($addr) > 1) { 
  596. for($i = 1; $i < count($addr); $i++) { 
  597. $addr_str .= ', ' . $this->AddrFormat($addr[$i]); 
  598. $addr_str .= $this->LE; 
  599.  
  600. return $addr_str; 
  601.  
  602. /** 
  603. * Formats an address correctly. 
  604. * @access private 
  605. * @return string 
  606. */ 
  607. function AddrFormat($addr) { 
  608. if(empty($addr[1])) { 
  609. $formatted = $this->SecureHeader($addr[0]); 
  610. } else { 
  611. $formatted = $this->EncodeHeader($this->SecureHeader($addr[1]), 'phrase') . " <" . $this->SecureHeader($addr[0]) . ">"; 
  612.  
  613. return $formatted; 
  614.  
  615. /** 
  616. * Wraps message for use with mailers that do not 
  617. * automatically perform wrapping and for quoted-printable. 
  618. * Original written by philippe. 
  619. * @access private 
  620. * @return string 
  621. */ 
  622. function WrapText($message, $length, $qp_mode = false) { 
  623. $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE; 
  624. // If utf-8 encoding is used, we will need to make sure we don't 
  625. // split multibyte characters when we wrap 
  626. $is_utf8 = (strtolower($this->CharSet) == "utf-8"); 
  627.  
  628. $message = $this->FixEOL($message); 
  629. if (substr($message, -1) == $this->LE) { 
  630. $message = substr($message, 0, -1); 
  631.  
  632. $line = explode($this->LE, $message); 
  633. $message = ''; 
  634. for ($i=0 ;$i < count($line); $i++) { 
  635. $line_part = explode(' ', $line[$i]); 
  636. $buf = ''; 
  637. for ($e = 0; $e<count($line_part); $e++) { 
  638. $word = $line_part[$e]; 
  639. if ($qp_mode and (strlen($word) > $length)) { 
  640. $space_left = $length - strlen($buf) - 1; 
  641. if ($e != 0) { 
  642. if ($space_left > 20) { 
  643. $len = $space_left; 
  644. if ($is_utf8) { 
  645. $len = $this->UTF8CharBoundary($word, $len); 
  646. } elseif (substr($word, $len - 1, 1) == "=") { 
  647. $len--; 
  648. } elseif (substr($word, $len - 2, 1) == "=") { 
  649. $len -= 2; 
  650. $part = substr($word, 0, $len); 
  651. $word = substr($word, $len); 
  652. $buf .= ' ' . $part; 
  653. $message .= $buf . sprintf("=%s", $this->LE); 
  654. } else { 
  655. $message .= $buf . $soft_break; 
  656. $buf = ''; 
  657. while (strlen($word) > 0) { 
  658. $len = $length; 
  659. if ($is_utf8) { 
  660. $len = $this->UTF8CharBoundary($word, $len); 
  661. } elseif (substr($word, $len - 1, 1) == "=") { 
  662. $len--; 
  663. } elseif (substr($word, $len - 2, 1) == "=") { 
  664. $len -= 2; 
  665. $part = substr($word, 0, $len); 
  666. $word = substr($word, $len); 
  667.  
  668. if (strlen($word) > 0) { 
  669. $message .= $part . sprintf("=%s", $this->LE); 
  670. } else { 
  671. $buf = $part; 
  672. } else { 
  673. $buf_o = $buf; 
  674. $buf .= ($e == 0) ? $word : (' ' . $word); 
  675.  
  676. if (strlen($buf) > $length and $buf_o != '') { 
  677. $message .= $buf_o . $soft_break; 
  678. $buf = $word; 
  679. $message .= $buf . $this->LE; 
  680.  
  681. return $message; 
  682.  
  683. /** 
  684. * Finds last character boundary prior to maxLength in a utf-8 
  685. * quoted (printable) encoded string. 
  686. * Original written by Colin Brown. 
  687. * @access private 
  688. * @param string $encodedText utf-8 QP text 
  689. * @param int $maxLength find last character boundary prior to this length 
  690. * @return int 
  691. */ 
  692. function UTF8CharBoundary($encodedText, $maxLength) { 
  693. $foundSplitPos = false; 
  694. $lookBack = 3; 
  695. while (!$foundSplitPos) { 
  696. $lastChunk = substr($encodedText, $maxLength - $lookBack, $lookBack); 
  697. $encodedCharPos = strpos($lastChunk, "="); 
  698. if ($encodedCharPos !== false) { 
  699. // Found start of encoded character byte within $lookBack block. 
  700. // Check the encoded byte value (the 2 chars after the '=') 
  701. $hex = substr($encodedText, $maxLength - $lookBack + $encodedCharPos + 1, 2); 
  702. $dec = hexdec($hex); 
  703. if ($dec < 128) { // Single byte character. 
  704. // If the encoded char was found at pos 0, it will fit 
  705. // otherwise reduce maxLength to start of the encoded char 
  706. $maxLength = ($encodedCharPos == 0) ? $maxLength : 
  707. $maxLength - ($lookBack - $encodedCharPos); 
  708. $foundSplitPos = true; 
  709. } elseif ($dec >= 192) { // First byte of a multi byte character 
  710. // Reduce maxLength to split at start of character 
  711. $maxLength = $maxLength - ($lookBack - $encodedCharPos); 
  712. $foundSplitPos = true; 
  713. } elseif ($dec < 192) { // Middle byte of a multi byte character, look further back 
  714. $lookBack += 3; 
  715. } else { 
  716. // No encoded character found 
  717. $foundSplitPos = true; 
  718. return $maxLength; 
  719.  
  720. /** 
  721. * Set the body wrapping. 
  722. * @access private 
  723. * @return void 
  724. */ 
  725. function SetWordWrap() { 
  726. if($this->WordWrap < 1) { 
  727. return; 
  728.  
  729. switch($this->message_type) { 
  730. case 'alt': 
  731. /** fall through */ 
  732. case 'alt_attachments': 
  733. $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap); 
  734. break; 
  735. default: 
  736. $this->Body = $this->WrapText($this->Body, $this->WordWrap); 
  737. break; 
  738.  
  739. /** 
  740. * Assembles message header. 
  741. * @access private 
  742. * @return string 
  743. */ 
  744. function CreateHeader() { 
  745. $result = ''; 
  746.  
  747. /** Set the boundaries */ 
  748. $uniq_id = md5(uniqid(time())); 
  749. $this->boundary[1] = 'b1_' . $uniq_id; 
  750. $this->boundary[2] = 'b2_' . $uniq_id; 
  751.  
  752. $result .= $this->HeaderLine('Date', $this->RFCDate()); 
  753. if($this->Sender == '') { 
  754. $result .= $this->HeaderLine('Return-Path', trim($this->From)); 
  755. } else { 
  756. $result .= $this->HeaderLine('Return-Path', trim($this->Sender)); 
  757.  
  758. /** To be created automatically by mail() */ 
  759. if($this->Mailer != 'mail') { 
  760. if(count($this->to) > 0) { 
  761. $result .= $this->AddrAppend('To', $this->to); 
  762. } elseif (count($this->cc) == 0) { 
  763. $result .= $this->HeaderLine('To', 'undisclosed-recipients:;'); 
  764.  
  765. $from = array(); 
  766. $from[0][0] = trim($this->From); 
  767. $from[0][1] = $this->FromName; 
  768. $result .= $this->AddrAppend('From', $from); 
  769.  
  770. /** sendmail and mail() extract Cc from the header before sending */ 
  771. if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->cc) > 0)) { 
  772. $result .= $this->AddrAppend('Cc', $this->cc); 
  773.  
  774. /** sendmail and mail() extract Bcc from the header before sending */ 
  775. if((($this->Mailer == 'sendmail') || ($this->Mailer == 'mail')) && (count($this->bcc) > 0)) { 
  776. $result .= $this->AddrAppend('Bcc', $this->bcc); 
  777.  
  778. if(count($this->ReplyTo) > 0) { 
  779. $result .= $this->AddrAppend('Reply-To', $this->ReplyTo); 
  780.  
  781. /** mail() sets the subject itself */ 
  782. if($this->Mailer != 'mail') { 
  783. $result .= $this->HeaderLine('Subject', $this->EncodeHeader($this->SecureHeader($this->Subject))); 
  784.  
  785. if($this->MessageID != '') { 
  786. $result .= $this->HeaderLine('Message-ID', $this->MessageID); 
  787. } else { 
  788. $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE); 
  789. $result .= $this->HeaderLine('X-Priority', $this->Priority); 
  790. $result .= $this->HeaderLine('X-Mailer', 'PHPMailer (phpmailer.sourceforge.net) [version ' . $this->Version . ']'); 
  791.  
  792. if($this->ConfirmReadingTo != '') { 
  793. $result .= $this->HeaderLine('Disposition-Notification-To', '<' . trim($this->ConfirmReadingTo) . '>'); 
  794.  
  795. // Add custom headers 
  796. for($index = 0; $index < count($this->CustomHeader); $index++) { 
  797. $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]), $this->EncodeHeader(trim($this->CustomHeader[$index][1]))); 
  798. if (!$this->sign_key_file) { 
  799. $result .= $this->HeaderLine('MIME-Version', '1.0'); 
  800. $result .= $this->GetMailMIME(); 
  801.  
  802. return $result; 
  803.  
  804. /** 
  805. * Returns the message MIME. 
  806. * @access private 
  807. * @return string 
  808. */ 
  809. function GetMailMIME() { 
  810. $result = ''; 
  811. switch($this->message_type) { 
  812. case 'plain': 
  813. $result .= $this->HeaderLine('Content-Transfer-Encoding', $this->Encoding); 
  814. $result .= sprintf("Content-Type: %s; charset=\"%s\"", $this->ContentType, $this->CharSet); 
  815. break; 
  816. case 'attachments': 
  817. /** fall through */ 
  818. case 'alt_attachments': 
  819. if($this->InlineImageExists()) { 
  820. $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s", 'multipart/related', $this->LE, $this->LE, $this->boundary[1], $this->LE); 
  821. } else { 
  822. $result .= $this->HeaderLine('Content-Type', 'multipart/mixed;'); 
  823. $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 
  824. break; 
  825. case 'alt': 
  826. $result .= $this->HeaderLine('Content-Type', 'multipart/alternative;'); 
  827. $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"'); 
  828. break; 
  829.  
  830. if($this->Mailer != 'mail') { 
  831. $result .= $this->LE.$this->LE; 
  832.  
  833. return $result; 
  834.  
  835. /** 
  836. * Assembles the message body. Returns an empty string on failure. 
  837. * @access private 
  838. * @return string 
  839. */ 
  840. function CreateBody() { 
  841. $result = ''; 
  842. if ($this->sign_key_file) { 
  843. $result .= $this->GetMailMIME(); 
  844.  
  845. $this->SetWordWrap(); 
  846.  
  847. switch($this->message_type) { 
  848. case 'alt': 
  849. $result .= $this->GetBoundary($this->boundary[1], '', 'text/plain', ''); 
  850. $result .= $this->EncodeString($this->AltBody, $this->Encoding); 
  851. $result .= $this->LE.$this->LE; 
  852. $result .= $this->GetBoundary($this->boundary[1], '', 'text/html', ''); 
  853. $result .= $this->EncodeString($this->Body, $this->Encoding); 
  854. $result .= $this->LE.$this->LE; 
  855. $result .= $this->EndBoundary($this->boundary[1]); 
  856. break; 
  857. case 'plain': 
  858. $result .= $this->EncodeString($this->Body, $this->Encoding); 
  859. break; 
  860. case 'attachments': 
  861. $result .= $this->GetBoundary($this->boundary[1], '', '', ''); 
  862. $result .= $this->EncodeString($this->Body, $this->Encoding); 
  863. $result .= $this->LE; 
  864. $result .= $this->AttachAll(); 
  865. break; 
  866. case 'alt_attachments': 
  867. $result .= sprintf("--%s%s", $this->boundary[1], $this->LE); 
  868. $result .= sprintf("Content-Type: %s;%s" . "\tboundary=\"%s\"%s", 'multipart/alternative', $this->LE, $this->boundary[2], $this->LE.$this->LE); 
  869. $result .= $this->GetBoundary($this->boundary[2], '', 'text/plain', '') . $this->LE; // Create text body 
  870. $result .= $this->EncodeString($this->AltBody, $this->Encoding); 
  871. $result .= $this->LE.$this->LE; 
  872. $result .= $this->GetBoundary($this->boundary[2], '', 'text/html', '') . $this->LE; // Create the HTML body 
  873. $result .= $this->EncodeString($this->Body, $this->Encoding); 
  874. $result .= $this->LE.$this->LE; 
  875. $result .= $this->EndBoundary($this->boundary[2]); 
  876. $result .= $this->AttachAll(); 
  877. break; 
  878.  
  879. if($this->IsError()) { 
  880. $result = ''; 
  881. } else if ($this->sign_key_file) { 
  882. $file = tempnam("", "mail"); 
  883. $fp = fopen($file, "w"); 
  884. fwrite($fp, $result); 
  885. fclose($fp); 
  886. $signed = tempnam("", "signed"); 
  887.  
  888. if (@openssl_pkcs7_sign($file, $signed, "file://".$this->sign_cert_file, array("file://".$this->sign_key_file, $this->sign_key_pass), null)) { 
  889. $fp = fopen($signed, "r"); 
  890. $result = fread($fp, filesize($this->sign_key_file)); 
  891. $result = ''; 
  892. while(!feof($fp)) { 
  893. $result = $result . fread($fp, 1024); 
  894. fclose($fp); 
  895. } else { 
  896. $this->SetError($this->Lang("signing").openssl_error_string()); 
  897. $result = ''; 
  898.  
  899. unlink($file); 
  900. unlink($signed); 
  901.  
  902. return $result; 
  903.  
  904. /** 
  905. * Returns the start of a message boundary. 
  906. * @access private 
  907. */ 
  908. function GetBoundary($boundary, $charSet, $contentType, $encoding) { 
  909. $result = ''; 
  910. if($charSet == '') { 
  911. $charSet = $this->CharSet; 
  912. if($contentType == '') { 
  913. $contentType = $this->ContentType; 
  914. if($encoding == '') { 
  915. $encoding = $this->Encoding; 
  916. $result .= $this->TextLine('--' . $boundary); 
  917. $result .= sprintf("Content-Type: %s; charset = \"%s\"", $contentType, $charSet); 
  918. $result .= $this->LE; 
  919. $result .= $this->HeaderLine('Content-Transfer-Encoding', $encoding); 
  920. $result .= $this->LE; 
  921.  
  922. return $result; 
  923.  
  924. /** 
  925. * Returns the end of a message boundary. 
  926. * @access private 
  927. */ 
  928. function EndBoundary($boundary) { 
  929. return $this->LE . '--' . $boundary . '--' . $this->LE; 
  930.  
  931. /** 
  932. * Sets the message type. 
  933. * @access private 
  934. * @return void 
  935. */ 
  936. function SetMessageType() { 
  937. if(count($this->attachment) < 1 && strlen($this->AltBody) < 1) { 
  938. $this->message_type = 'plain'; 
  939. } else { 
  940. if(count($this->attachment) > 0) { 
  941. $this->message_type = 'attachments'; 
  942. if(strlen($this->AltBody) > 0 && count($this->attachment) < 1) { 
  943. $this->message_type = 'alt'; 
  944. if(strlen($this->AltBody) > 0 && count($this->attachment) > 0) { 
  945. $this->message_type = 'alt_attachments'; 
  946.  
  947. /** Returns a formatted header line. 
  948. * @access private 
  949. * @return string 
  950. */ 
  951. function HeaderLine($name, $value) { 
  952. return $name . ': ' . $value . $this->LE; 
  953.  
  954. /** 
  955. * Returns a formatted mail line. 
  956. * @access private 
  957. * @return string 
  958. */ 
  959. function TextLine($value) { 
  960. return $value . $this->LE; 
  961.  
  962. ///////////////////////////////////////////////// 
  963. // CLASS METHODS, ATTACHMENTS 
  964. ///////////////////////////////////////////////// 
  965.  
  966. /** 
  967. * Adds an attachment from a path on the filesystem. 
  968. * Returns false if the file could not be found 
  969. * or accessed. 
  970. * @param string $path Path to the attachment. 
  971. * @param string $name Overrides the attachment name. 
  972. * @param string $encoding File encoding (see $Encoding). 
  973. * @param string $type File extension (MIME) type. 
  974. * @return bool 
  975. */ 
  976. function AddAttachment($path, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { 
  977. if(!@is_file($path)) { 
  978. $this->SetError($this->Lang('file_access') . $path); 
  979. return false; 
  980.  
  981. $filename = basename($path); 
  982. if($name == '') { 
  983. $name = $filename; 
  984.  
  985. $cur = count($this->attachment); 
  986. $this->attachment[$cur][0] = $path; 
  987. $this->attachment[$cur][1] = $filename; 
  988. $this->attachment[$cur][2] = $name; 
  989. $this->attachment[$cur][3] = $encoding; 
  990. $this->attachment[$cur][4] = $type; 
  991. $this->attachment[$cur][5] = false; // isStringAttachment 
  992. $this->attachment[$cur][6] = 'attachment'; 
  993. $this->attachment[$cur][7] = 0; 
  994.  
  995. return true; 
  996.  
  997. /** 
  998. * Attaches all fs, string, and binary attachments to the message. 
  999. * Returns an empty string on failure. 
  1000. * @access private 
  1001. * @return string 
  1002. */ 
  1003. function AttachAll() { 
  1004. /** Return text of body */ 
  1005. $mime = array(); 
  1006.  
  1007. /** Add all attachments */ 
  1008. for($i = 0; $i < count($this->attachment); $i++) { 
  1009. /** Check for string attachment */ 
  1010. $bString = $this->attachment[$i][5]; 
  1011. if ($bString) { 
  1012. $string = $this->attachment[$i][0]; 
  1013. } else { 
  1014. $path = $this->attachment[$i][0]; 
  1015.  
  1016. $filename = $this->attachment[$i][1]; 
  1017. $name = $this->attachment[$i][2]; 
  1018. $encoding = $this->attachment[$i][3]; 
  1019. $type = $this->attachment[$i][4]; 
  1020. $disposition = $this->attachment[$i][6]; 
  1021. $cid = $this->attachment[$i][7]; 
  1022.  
  1023. $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE); 
  1024. $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $this->EncodeHeader($this->SecureHeader($name)), $this->LE); 
  1025. $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE); 
  1026.  
  1027. if($disposition == 'inline') { 
  1028. $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE); 
  1029.  
  1030. $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s", $disposition, $this->EncodeHeader($this->SecureHeader($name)), $this->LE.$this->LE); 
  1031.  
  1032. /** Encode as string attachment */ 
  1033. if($bString) { 
  1034. $mime[] = $this->EncodeString($string, $encoding); 
  1035. if($this->IsError()) { 
  1036. return ''; 
  1037. $mime[] = $this->LE.$this->LE; 
  1038. } else { 
  1039. $mime[] = $this->EncodeFile($path, $encoding); 
  1040. if($this->IsError()) { 
  1041. return ''; 
  1042. $mime[] = $this->LE.$this->LE; 
  1043.  
  1044. $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE); 
  1045.  
  1046. return join('', $mime); 
  1047.  
  1048. /** 
  1049. * Encodes attachment in requested format. Returns an 
  1050. * empty string on failure. 
  1051. * @access private 
  1052. * @return string 
  1053. */ 
  1054. function EncodeFile ($path, $encoding = 'base64') { 
  1055. if(!@$fd = fopen($path, 'rb')) { 
  1056. $this->SetError($this->Lang('file_open') . $path); 
  1057. return ''; 
  1058. $magic_quotes = get_magic_quotes_runtime(); 
  1059. if ($magic_quotes) { 
  1060. if (version_compare(PHP_VERSION, '5.3.0', '<')) { 
  1061. set_magic_quotes_runtime(0); 
  1062. } else { 
  1063. ini_set('magic_quotes_runtime', 0); 
  1064. $file_buffer = fread($fd, filesize($path)); 
  1065. $file_buffer = $this->EncodeString($file_buffer, $encoding); 
  1066. fclose($fd); 
  1067. if ($magic_quotes) { 
  1068. if (version_compare(PHP_VERSION, '5.3.0', '<')) { 
  1069. set_magic_quotes_runtime($magic_quotes); 
  1070. } else { 
  1071. ini_set('magic_quotes_runtime', $magic_quotes); 
  1072.  
  1073. return $file_buffer; 
  1074.  
  1075. /** 
  1076. * Encodes string to requested format. Returns an 
  1077. * empty string on failure. 
  1078. * @access private 
  1079. * @return string 
  1080. */ 
  1081. function EncodeString ($str, $encoding = 'base64') { 
  1082. $encoded = ''; 
  1083. switch(strtolower($encoding)) { 
  1084. case 'base64': 
  1085. /** chunk_split is found in PHP >= 3.0.6 */ 
  1086. $encoded = chunk_split(base64_encode($str), 76, $this->LE); 
  1087. break; 
  1088. case '7bit': 
  1089. case '8bit': 
  1090. $encoded = $this->FixEOL($str); 
  1091. if (substr($encoded, -(strlen($this->LE))) != $this->LE) 
  1092. $encoded .= $this->LE; 
  1093. break; 
  1094. case 'binary': 
  1095. $encoded = $str; 
  1096. break; 
  1097. case 'quoted-printable': 
  1098. $encoded = $this->EncodeQP($str); 
  1099. break; 
  1100. default: 
  1101. $this->SetError($this->Lang('encoding') . $encoding); 
  1102. break; 
  1103. return $encoded; 
  1104.  
  1105. /** 
  1106. * Encode a header string to best of Q, B, quoted or none. 
  1107. * @access private 
  1108. * @return string 
  1109. */ 
  1110. function EncodeHeader ($str, $position = 'text') { 
  1111. $x = 0; 
  1112.  
  1113. switch (strtolower($position)) { 
  1114. case 'phrase': 
  1115. if (!preg_match('/[\200-\377]/', $str)) { 
  1116. /** Can't use addslashes as we don't know what value has magic_quotes_sybase. */ 
  1117. $encoded = addcslashes($str, "\0..\37\177\\\""); 
  1118. if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str)) { 
  1119. return ($encoded); 
  1120. } else { 
  1121. return ("\"$encoded\""); 
  1122. $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches); 
  1123. break; 
  1124. case 'comment': 
  1125. $x = preg_match_all('/[()"]/', $str, $matches); 
  1126. /** Fall-through */ 
  1127. case 'text': 
  1128. default: 
  1129. $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches); 
  1130. break; 
  1131.  
  1132. if ($x == 0) { 
  1133. return ($str); 
  1134.  
  1135. $maxlen = 75 - 7 - strlen($this->CharSet); 
  1136. /** Try to select the encoding which should produce the shortest output */ 
  1137. if (strlen($str)/3 < $x) { 
  1138. $encoding = 'B'; 
  1139. if (function_exists('mb_strlen') && $this->HasMultiBytes($str)) { 
  1140. // Use a custom function which correctly encodes and wraps long 
  1141. // multibyte strings without breaking lines within a character 
  1142. $encoded = $this->Base64EncodeWrapMB($str); 
  1143. } else { 
  1144. $encoded = base64_encode($str); 
  1145. $maxlen -= $maxlen % 4; 
  1146. $encoded = trim(chunk_split($encoded, $maxlen, "\n")); 
  1147. } else { 
  1148. $encoding = 'Q'; 
  1149. $encoded = $this->EncodeQ($str, $position); 
  1150. $encoded = $this->WrapText($encoded, $maxlen, true); 
  1151. $encoded = str_replace('='.$this->LE, "\n", trim($encoded)); 
  1152.  
  1153. $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded); 
  1154. $encoded = trim(str_replace("\n", $this->LE, $encoded)); 
  1155.  
  1156. return $encoded; 
  1157.  
  1158. /** 
  1159. * Checks if a string contains multibyte characters. 
  1160. * @access private 
  1161. * @param string $str multi-byte text to wrap encode 
  1162. * @return bool 
  1163. */ 
  1164. function HasMultiBytes($str) { 
  1165. if (function_exists('mb_strlen')) { 
  1166. return (strlen($str) > mb_strlen($str, $this->CharSet)); 
  1167. } else { // Assume no multibytes (we can't handle without mbstring functions anyway) 
  1168. return False; 
  1169.  
  1170. /** 
  1171. * Correctly encodes and wraps long multibyte strings for mail headers 
  1172. * without breaking lines within a character. 
  1173. * Adapted from a function by paravoid at http://uk.php.net/manual/en/function.mb-encode-mimeheader.php 
  1174. * @access private 
  1175. * @param string $str multi-byte text to wrap encode 
  1176. * @return string 
  1177. */ 
  1178. function Base64EncodeWrapMB($str) { 
  1179. $start = "=?".$this->CharSet."?B?"; 
  1180. $end = "?="; 
  1181. $encoded = ""; 
  1182.  
  1183. $mb_length = mb_strlen($str, $this->CharSet); 
  1184. // Each line must have length <= 75, including $start and $end 
  1185. $length = 75 - strlen($start) - strlen($end); 
  1186. // Average multi-byte ratio 
  1187. $ratio = $mb_length / strlen($str); 
  1188. // Base64 has a 4:3 ratio 
  1189. $offset = $avgLength = floor($length * $ratio * .75); 
  1190.  
  1191. for ($i = 0; $i < $mb_length; $i += $offset) { 
  1192. $lookBack = 0; 
  1193.  
  1194. do { 
  1195. $offset = $avgLength - $lookBack; 
  1196. $chunk = mb_substr($str, $i, $offset, $this->CharSet); 
  1197. $chunk = base64_encode($chunk); 
  1198. $lookBack++; 
  1199. while (strlen($chunk) > $length); 
  1200.  
  1201. $encoded .= $chunk . $this->LE; 
  1202.  
  1203. // Chomp the last linefeed 
  1204. $encoded = substr($encoded, 0, -strlen($this->LE)); 
  1205. return $encoded; 
  1206.  
  1207. /** 
  1208. * Encode string to quoted-printable. 
  1209. * @access private 
  1210. * @return string 
  1211. */ 
  1212. function EncodeQP( $input = '', $line_max = 76, $space_conv = false ) { 
  1213. $hex = array('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'); 
  1214. $lines = preg_split('/(?:\r\n|\r|\n)/', $input); 
  1215. $eol = "\r\n"; 
  1216. $escape = '='; 
  1217. $output = ''; 
  1218. while( list(, $line) = each($lines) ) { 
  1219. $linlen = strlen($line); 
  1220. $newline = ''; 
  1221. for($i = 0; $i < $linlen; $i++) { 
  1222. $c = substr( $line, $i, 1 ); 
  1223. $dec = ord( $c ); 
  1224. if ( ( $i == 0 ) && ( $dec == 46 ) ) { // convert first point in the line into =2E 
  1225. $c = '=2E'; 
  1226. if ( $dec == 32 ) { 
  1227. if ( $i == ( $linlen - 1 ) ) { // convert space at eol only 
  1228. $c = '=20'; 
  1229. } else if ( $space_conv ) { 
  1230. $c = '=20'; 
  1231. } elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required 
  1232. $h2 = floor($dec/16); 
  1233. $h1 = floor($dec%16); 
  1234. $c = $escape.$hex[$h2].$hex[$h1]; 
  1235. if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted 
  1236. $output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay 
  1237. $newline = ''; 
  1238. // check if newline first character will be point or not 
  1239. if ( $dec == 46 ) { 
  1240. $c = '=2E'; 
  1241. $newline .= $c; 
  1242. } // end of for 
  1243. $output .= $newline.$eol; 
  1244. } // end of while 
  1245. return $output; 
  1246.  
  1247. /** 
  1248. * Callback for converting to "=XX". 
  1249. * @access private 
  1250. * @return string 
  1251. */ 
  1252. function EncodeQ_callback ($matches) { 
  1253. return sprintf('=%02X', ord($matches[1])); 
  1254.  
  1255. /** 
  1256. * Encode string to q encoding. 
  1257. * @access private 
  1258. * @return string 
  1259. */ 
  1260. function EncodeQ ($str, $position = 'text') { 
  1261. /** There should not be any EOL in the string */ 
  1262. $encoded = preg_replace("/[\r\n]/", '', $str); 
  1263.  
  1264. switch (strtolower($position)) { 
  1265. case 'phrase': 
  1266. $encoded = preg_replace_callback("/([^A-Za-z0-9!*+\/ -])/",  
  1267. array('PHPMailer', 'EncodeQ_callback'), $encoded); 
  1268. break; 
  1269. case 'comment': 
  1270. $encoded = preg_replace_callback("/([\(\)\"])/",  
  1271. array('PHPMailer', 'EncodeQ_callback'), $encoded); 
  1272. break; 
  1273. case 'text': 
  1274. default: 
  1275. /** Replace every high ascii, control =, ? and _ characters */ 
  1276. $encoded = preg_replace_callback('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/',  
  1277. array('PHPMailer', 'EncodeQ_callback'), $encoded); 
  1278. break; 
  1279.  
  1280. /** Replace every spaces to _ (more readable than =20) */ 
  1281. $encoded = str_replace(' ', '_', $encoded); 
  1282.  
  1283. return $encoded; 
  1284.  
  1285. /** 
  1286. * Adds a string or binary attachment (non-filesystem) to the list. 
  1287. * This method can be used to attach ascii or binary data,  
  1288. * such as a BLOB record from a database. 
  1289. * @param string $string String attachment data. 
  1290. * @param string $filename Name of the attachment. 
  1291. * @param string $encoding File encoding (see $Encoding). 
  1292. * @param string $type File extension (MIME) type. 
  1293. * @return void 
  1294. */ 
  1295. function AddStringAttachment($string, $filename, $encoding = 'base64', $type = 'application/octet-stream') { 
  1296. /** Append to $attachment array */ 
  1297. $cur = count($this->attachment); 
  1298. $this->attachment[$cur][0] = $string; 
  1299. $this->attachment[$cur][1] = $filename; 
  1300. $this->attachment[$cur][2] = $filename; 
  1301. $this->attachment[$cur][3] = $encoding; 
  1302. $this->attachment[$cur][4] = $type; 
  1303. $this->attachment[$cur][5] = true; // isString 
  1304. $this->attachment[$cur][6] = 'attachment'; 
  1305. $this->attachment[$cur][7] = 0; 
  1306.  
  1307. /** 
  1308. * Adds an embedded attachment. This can include images, sounds, and 
  1309. * just about any other document. Make sure to set the $type to an 
  1310. * image type. For JPEG images use "image/jpeg" and for GIF images 
  1311. * use "image/gif". 
  1312. * @param string $path Path to the attachment. 
  1313. * @param string $cid Content ID of the attachment. Use this to identify 
  1314. * the Id for accessing the image in an HTML form. 
  1315. * @param string $name Overrides the attachment name. 
  1316. * @param string $encoding File encoding (see $Encoding). 
  1317. * @param string $type File extension (MIME) type. 
  1318. * @return bool 
  1319. */ 
  1320. function AddEmbeddedImage($path, $cid, $name = '', $encoding = 'base64', $type = 'application/octet-stream') { 
  1321.  
  1322. if(!@is_file($path)) { 
  1323. $this->SetError($this->Lang('file_access') . $path); 
  1324. return false; 
  1325.  
  1326. $filename = basename($path); 
  1327. if($name == '') { 
  1328. $name = $filename; 
  1329.  
  1330. /** Append to $attachment array */ 
  1331. $cur = count($this->attachment); 
  1332. $this->attachment[$cur][0] = $path; 
  1333. $this->attachment[$cur][1] = $filename; 
  1334. $this->attachment[$cur][2] = $name; 
  1335. $this->attachment[$cur][3] = $encoding; 
  1336. $this->attachment[$cur][4] = $type; 
  1337. $this->attachment[$cur][5] = false; 
  1338. $this->attachment[$cur][6] = 'inline'; 
  1339. $this->attachment[$cur][7] = $cid; 
  1340.  
  1341. return true; 
  1342.  
  1343. /** 
  1344. * Returns true if an inline attachment is present. 
  1345. * @access private 
  1346. * @return bool 
  1347. */ 
  1348. function InlineImageExists() { 
  1349. $result = false; 
  1350. for($i = 0; $i < count($this->attachment); $i++) { 
  1351. if($this->attachment[$i][6] == 'inline') { 
  1352. $result = true; 
  1353. break; 
  1354.  
  1355. return $result; 
  1356.  
  1357. ///////////////////////////////////////////////// 
  1358. // CLASS METHODS, MESSAGE RESET 
  1359. ///////////////////////////////////////////////// 
  1360.  
  1361. /** 
  1362. * Clears all recipients assigned in the TO array. Returns void. 
  1363. * @return void 
  1364. */ 
  1365. function ClearAddresses() { 
  1366. $this->to = array(); 
  1367.  
  1368. /** 
  1369. * Clears all recipients assigned in the CC array. Returns void. 
  1370. * @return void 
  1371. */ 
  1372. function ClearCCs() { 
  1373. $this->cc = array(); 
  1374.  
  1375. /** 
  1376. * Clears all recipients assigned in the BCC array. Returns void. 
  1377. * @return void 
  1378. */ 
  1379. function ClearBCCs() { 
  1380. $this->bcc = array(); 
  1381.  
  1382. /** 
  1383. * Clears all recipients assigned in the ReplyTo array. Returns void. 
  1384. * @return void 
  1385. */ 
  1386. function ClearReplyTos() { 
  1387. $this->ReplyTo = array(); 
  1388.  
  1389. /** 
  1390. * Clears all recipients assigned in the TO, CC and BCC 
  1391. * array. Returns void. 
  1392. * @return void 
  1393. */ 
  1394. function ClearAllRecipients() { 
  1395. $this->to = array(); 
  1396. $this->cc = array(); 
  1397. $this->bcc = array(); 
  1398.  
  1399. /** 
  1400. * Clears all previously set filesystem, string, and binary 
  1401. * attachments. Returns void. 
  1402. * @return void 
  1403. */ 
  1404. function ClearAttachments() { 
  1405. $this->attachment = array(); 
  1406.  
  1407. /** 
  1408. * Clears all custom headers. Returns void. 
  1409. * @return void 
  1410. */ 
  1411. function ClearCustomHeaders() { 
  1412. $this->CustomHeader = array(); 
  1413.  
  1414. ///////////////////////////////////////////////// 
  1415. // CLASS METHODS, MISCELLANEOUS 
  1416. ///////////////////////////////////////////////// 
  1417.  
  1418. /** 
  1419. * Adds the error message to the error container. 
  1420. * Returns void. 
  1421. * @access private 
  1422. * @return void 
  1423. */ 
  1424. function SetError($msg) { 
  1425. $this->error_count++; 
  1426. $this->ErrorInfo = $msg; 
  1427.  
  1428. /** 
  1429. * Returns the proper RFC 822 formatted date. 
  1430. * @access private 
  1431. * @return string 
  1432. */ 
  1433. function RFCDate() { 
  1434. $tz = date('Z'); 
  1435. $tzs = ($tz < 0) ? '-' : '+'; 
  1436. $tz = abs($tz); 
  1437. $tz = (int)($tz/3600)*100 + ($tz%3600)/60; 
  1438. $result = sprintf("%s %s%04d", date('D, j M Y H:i:s'), $tzs, $tz); 
  1439.  
  1440. return $result; 
  1441.  
  1442. /** 
  1443. * Returns the appropriate server variable. Should work with both 
  1444. * PHP 4.1.0+ as well as older versions. Returns an empty string 
  1445. * if nothing is found. 
  1446. * @access private 
  1447. * @return mixed 
  1448. */ 
  1449. function ServerVar($varName) { 
  1450. global $HTTP_SERVER_VARS; 
  1451. global $HTTP_ENV_VARS; 
  1452.  
  1453. if(!isset($_SERVER)) { 
  1454. $_SERVER = $HTTP_SERVER_VARS; 
  1455. if(!isset($_SERVER['REMOTE_ADDR'])) { 
  1456. $_SERVER = $HTTP_ENV_VARS; // must be Apache 
  1457.  
  1458. if(isset($_SERVER[$varName])) { 
  1459. return $_SERVER[$varName]; 
  1460. } else { 
  1461. return ''; 
  1462.  
  1463. /** 
  1464. * Returns the server hostname or 'localhost.localdomain' if unknown. 
  1465. * @access private 
  1466. * @return string 
  1467. */ 
  1468. function ServerHostname() { 
  1469. if ($this->Hostname != '') { 
  1470. $result = $this->Hostname; 
  1471. } elseif ($this->ServerVar('SERVER_NAME') != '') { 
  1472. $result = $this->ServerVar('SERVER_NAME'); 
  1473. } else { 
  1474. $result = 'localhost.localdomain'; 
  1475.  
  1476. return $result; 
  1477.  
  1478. /** 
  1479. * Returns a message in the appropriate language. 
  1480. * @access private 
  1481. * @return string 
  1482. */ 
  1483. function Lang($key) { 
  1484. if(count($this->language) < 1) { 
  1485. $this->SetLanguage('en'); // set the default language 
  1486.  
  1487. if(isset($this->language[$key])) { 
  1488. return $this->language[$key]; 
  1489. } else { 
  1490. return 'Language string failed to load: ' . $key; 
  1491.  
  1492. /** 
  1493. * Returns true if an error occurred. 
  1494. * @return bool 
  1495. */ 
  1496. function IsError() { 
  1497. return ($this->error_count > 0); 
  1498.  
  1499. /** 
  1500. * Changes every end of line from CR or LF to CRLF. 
  1501. * @access private 
  1502. * @return string 
  1503. */ 
  1504. function FixEOL($str) { 
  1505. $str = str_replace("\r\n", "\n", $str); 
  1506. $str = str_replace("\r", "\n", $str); 
  1507. $str = str_replace("\n", $this->LE, $str); 
  1508. return $str; 
  1509.  
  1510. /** 
  1511. * Adds a custom header. 
  1512. * @return void 
  1513. */ 
  1514. function AddCustomHeader($custom_header) { 
  1515. $this->CustomHeader[] = explode(':', $custom_header, 2); 
  1516.  
  1517. /** 
  1518. * Evaluates the message and returns modifications for inline images and backgrounds 
  1519. * @access public 
  1520. * @return $message 
  1521. */ 
  1522. function MsgHTML($message, $basedir='') { 
  1523. preg_match_all("/(src|background)=\"(.*)\"/Ui", $message, $images); 
  1524. if(isset($images[2])) { 
  1525. foreach($images[2] as $i => $url) { 
  1526. // do not change urls for absolute images (thanks to corvuscorax) 
  1527. if (!preg_match('/^[A-z][A-z]*:\/\//', $url)) { 
  1528. $filename = basename($url); 
  1529. $directory = dirname($url); 
  1530. ($directory == '.')?$directory='':''; 
  1531. $cid = 'cid:' . md5($filename); 
  1532. $fileParts = explode(".", $filename); 
  1533. $ext = $fileParts[1]; 
  1534. $mimeType = $this->_mime_types($ext); 
  1535. if ( strlen($basedir) > 1 && substr($basedir, -1) != '/') { $basedir .= '/'; } 
  1536. if ( strlen($directory) > 1 && substr($directory, -1) != '/') { $directory .= '/'; } 
  1537. if ( $this->AddEmbeddedImage($basedir.$directory.$filename, md5($filename), $filename, 'base64', $mimeType) ) { 
  1538. $message = preg_replace("/".$images[1][$i]."=\"".preg_quote($url, '/')."\"/Ui", $images[1][$i]."=\"".$cid."\"", $message); 
  1539. $this->IsHTML(true); 
  1540. $this->Body = $message; 
  1541. $textMsg = trim(strip_tags(preg_replace('/<(head|title|style|script)[^>]*>.*?<\/\\1>/s', '', $message))); 
  1542. if ( !empty($textMsg) && empty($this->AltBody) ) { 
  1543. $this->AltBody = html_entity_decode($textMsg); 
  1544. if ( empty($this->AltBody) ) { 
  1545. $this->AltBody = 'To view this email message, open the email in with HTML compatibility!' . "\n\n"; 
  1546.  
  1547. /** 
  1548. * Gets the mime type of the embedded or inline image 
  1549. * @access private 
  1550. * @return mime type of ext 
  1551. */ 
  1552. function _mime_types($ext = '') { 
  1553. $mimes = array( 
  1554. 'ai' => 'application/postscript',  
  1555. 'aif' => 'audio/x-aiff',  
  1556. 'aifc' => 'audio/x-aiff',  
  1557. 'aiff' => 'audio/x-aiff',  
  1558. 'avi' => 'video/x-msvideo',  
  1559. 'bin' => 'application/macbinary',  
  1560. 'bmp' => 'image/bmp',  
  1561. 'class' => 'application/octet-stream',  
  1562. 'cpt' => 'application/mac-compactpro',  
  1563. 'css' => 'text/css',  
  1564. 'dcr' => 'application/x-director',  
  1565. 'dir' => 'application/x-director',  
  1566. 'dll' => 'application/octet-stream',  
  1567. 'dms' => 'application/octet-stream',  
  1568. 'doc' => 'application/msword',  
  1569. 'dvi' => 'application/x-dvi',  
  1570. 'dxr' => 'application/x-director',  
  1571. 'eml' => 'message/rfc822',  
  1572. 'eps' => 'application/postscript',  
  1573. 'exe' => 'application/octet-stream',  
  1574. 'gif' => 'image/gif',  
  1575. 'gtar' => 'application/x-gtar',  
  1576. 'htm' => 'text/html',  
  1577. 'html' => 'text/html',  
  1578. 'jpe' => 'image/jpeg',  
  1579. 'jpeg' => 'image/jpeg',  
  1580. 'jpg' => 'image/jpeg',  
  1581. 'hqx' => 'application/mac-binhex40',  
  1582. 'js' => 'application/x-javascript',  
  1583. 'lha' => 'application/octet-stream',  
  1584. 'log' => 'text/plain',  
  1585. 'lzh' => 'application/octet-stream',  
  1586. 'mid' => 'audio/midi',  
  1587. 'midi' => 'audio/midi',  
  1588. 'mif' => 'application/vnd.mif',  
  1589. 'mov' => 'video/quicktime',  
  1590. 'movie' => 'video/x-sgi-movie',  
  1591. 'mp2' => 'audio/mpeg',  
  1592. 'mp3' => 'audio/mpeg',  
  1593. 'mpe' => 'video/mpeg',  
  1594. 'mpeg' => 'video/mpeg',  
  1595. 'mpg' => 'video/mpeg',  
  1596. 'mpga' => 'audio/mpeg',  
  1597. 'oda' => 'application/oda',  
  1598. 'pdf' => 'application/pdf',  
  1599. 'php' => 'application/x-httpd-php',  
  1600. 'php3' => 'application/x-httpd-php',  
  1601. 'php4' => 'application/x-httpd-php',  
  1602. 'phps' => 'application/x-httpd-php-source',  
  1603. 'phtml' => 'application/x-httpd-php',  
  1604. 'png' => 'image/png',  
  1605. 'ppt' => 'application/vnd.ms-powerpoint',  
  1606. 'ps' => 'application/postscript',  
  1607. 'psd' => 'application/octet-stream',  
  1608. 'qt' => 'video/quicktime',  
  1609. 'ra' => 'audio/x-realaudio',  
  1610. 'ram' => 'audio/x-pn-realaudio',  
  1611. 'rm' => 'audio/x-pn-realaudio',  
  1612. 'rpm' => 'audio/x-pn-realaudio-plugin',  
  1613. 'rtf' => 'text/rtf',  
  1614. 'rtx' => 'text/richtext',  
  1615. 'rv' => 'video/vnd.rn-realvideo',  
  1616. 'sea' => 'application/octet-stream',  
  1617. 'shtml' => 'text/html',  
  1618. 'sit' => 'application/x-stuffit',  
  1619. 'so' => 'application/octet-stream',  
  1620. 'smi' => 'application/smil',  
  1621. 'smil' => 'application/smil',  
  1622. 'swf' => 'application/x-shockwave-flash',  
  1623. 'tar' => 'application/x-tar',  
  1624. 'text' => 'text/plain',  
  1625. 'txt' => 'text/plain',  
  1626. 'tgz' => 'application/x-tar',  
  1627. 'tif' => 'image/tiff',  
  1628. 'tiff' => 'image/tiff',  
  1629. 'wav' => 'audio/x-wav',  
  1630. 'wbxml' => 'application/vnd.wap.wbxml',  
  1631. 'wmlc' => 'application/vnd.wap.wmlc',  
  1632. 'word' => 'application/msword',  
  1633. 'xht' => 'application/xhtml+xml',  
  1634. 'xhtml' => 'application/xhtml+xml',  
  1635. 'xl' => 'application/excel',  
  1636. 'xls' => 'application/vnd.ms-excel',  
  1637. 'xml' => 'text/xml',  
  1638. 'xsl' => 'text/xml',  
  1639. 'zip' => 'application/zip' 
  1640. ); 
  1641. return ( ! isset($mimes[strtolower($ext)])) ? 'application/octet-stream' : $mimes[strtolower($ext)]; 
  1642.  
  1643. /** 
  1644. * Set (or reset) Class Objects (variables) 
  1645. * Usage Example: 
  1646. * $page->set('X-Priority', '3'); 
  1647. * @access public 
  1648. * @param string $name Parameter Name 
  1649. * @param mixed $value Parameter Value 
  1650. * NOTE: will not work with arrays, there are no arrays to set/reset 
  1651. */ 
  1652. function set ( $name, $value = '' ) { 
  1653. if ( isset($this->$name) ) { 
  1654. $this->$name = $value; 
  1655. } else { 
  1656. $this->SetError('Cannot set or reset variable ' . $name); 
  1657. return false; 
  1658.  
  1659. /** 
  1660. * Read a file from a supplied filename and return it. 
  1661. * @access public 
  1662. * @param string $filename Parameter File Name 
  1663. */ 
  1664. function getFile($filename) { 
  1665. $return = ''; 
  1666. if ($fp = fopen($filename, 'rb')) { 
  1667. while (!feof($fp)) { 
  1668. $return .= fread($fp, 1024); 
  1669. fclose($fp); 
  1670. return $return; 
  1671. } else { 
  1672. return false; 
  1673.  
  1674. /** 
  1675. * Strips newlines to prevent header injection. 
  1676. * @access private 
  1677. * @param string $str String 
  1678. * @return string 
  1679. */ 
  1680. function SecureHeader($str) { 
  1681. $str = trim($str); 
  1682. $str = str_replace("\r", "", $str); 
  1683. $str = str_replace("\n", "", $str); 
  1684. return $str; 
  1685.  
  1686. /** 
  1687. * Set the private key file and password to sign the message. 
  1688. * @access public 
  1689. * @param string $key_filename Parameter File Name 
  1690. * @param string $key_pass Password for private key 
  1691. */ 
  1692. function Sign($cert_filename, $key_filename, $key_pass) { 
  1693. $this->sign_cert_file = $cert_filename; 
  1694. $this->sign_key_file = $key_filename; 
  1695. $this->sign_key_pass = $key_pass; 
  1696.