PageRenderTime 74ms CodeModel.GetById 37ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/phpmailer/class.phpmailer.php

https://bitbucket.org/ceu/moodle_demo
PHP | 1569 lines | 989 code | 162 blank | 418 comment | 144 complexity | 6fac01946f77bba1aff7a5894e1c0f70 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, LGPL-2.1
  1. <?php
  2. ////////////////////////////////////////////////////
  3. // PHPMailer - PHP email class
  4. //
  5. // Class for sending email using either
  6. // sendmail, PHP mail(), or SMTP. Methods are
  7. // based upon the standard AspEmail(tm) classes.
  8. //
  9. // Copyright (C) 2001 - 2003 Brent R. Matzelle
  10. //
  11. // License: LGPL, see LICENSE
  12. ////////////////////////////////////////////////////
  13. /**
  14. * PHPMailer - PHP email transport class
  15. * @package PHPMailer
  16. * @author Brent R. Matzelle
  17. * @copyright 2001 - 2003 Brent R. Matzelle
  18. */
  19. class PHPMailer
  20. {
  21. /////////////////////////////////////////////////
  22. // PUBLIC VARIABLES
  23. /////////////////////////////////////////////////
  24. /**
  25. * Email priority (1 = High, 3 = Normal, 5 = low).
  26. * @var int
  27. */
  28. var $Priority = 3;
  29. /**
  30. * Sets the CharSet of the message.
  31. * @var string
  32. */
  33. var $CharSet = "iso-8859-1";
  34. /**
  35. * Sets the Content-type of the message.
  36. * @var string
  37. */
  38. var $ContentType = "text/plain";
  39. /**
  40. * Sets the Encoding of the message. Options for this are "8bit",
  41. * "7bit", "binary", "base64", and "quoted-printable".
  42. * @var string
  43. */
  44. var $Encoding = "8bit";
  45. /**
  46. * Holds the most recent mailer error message.
  47. * @var string
  48. */
  49. var $ErrorInfo = "";
  50. /**
  51. * Sets the From email address for the message.
  52. * @var string
  53. */
  54. var $From = "root@localhost";
  55. /**
  56. * Sets the From name of the message.
  57. * @var string
  58. */
  59. var $FromName = "Root User";
  60. /**
  61. * Sets the Sender email (Return-Path) of the message. If not empty,
  62. * will be sent via -f to sendmail or as 'MAIL FROM' in smtp mode.
  63. * @var string
  64. */
  65. var $Sender = "";
  66. /**
  67. * Sets the Subject of the message.
  68. * @var string
  69. */
  70. var $Subject = "";
  71. /**
  72. * Sets the Body of the message. This can be either an HTML or text body.
  73. * If HTML then run IsHTML(true).
  74. * @var string
  75. */
  76. var $Body = "";
  77. /**
  78. * Sets the text-only body of the message. This automatically sets the
  79. * email to multipart/alternative. This body can be read by mail
  80. * clients that do not have HTML email capability such as mutt. Clients
  81. * that can read HTML will view the normal Body.
  82. * @var string
  83. */
  84. var $AltBody = "";
  85. /**
  86. * Sets word wrapping on the body of the message to a given number of
  87. * characters.
  88. * @var int
  89. */
  90. var $WordWrap = 0;
  91. /**
  92. * Method to send mail: ("mail", "sendmail", or "smtp").
  93. * @var string
  94. */
  95. var $Mailer = "mail";
  96. /**
  97. * Sets the path of the sendmail program.
  98. * @var string
  99. */
  100. var $Sendmail = "/usr/sbin/sendmail";
  101. /**
  102. * Path to PHPMailer plugins. This is now only useful if the SMTP class
  103. * is in a different directory than the PHP include path.
  104. * @var string
  105. */
  106. var $PluginDir = "";
  107. /**
  108. * Holds PHPMailer version.
  109. * @var string
  110. */
  111. var $Version = "1.73";
  112. /**
  113. * Sets the email address that a reading confirmation will be sent.
  114. * @var string
  115. */
  116. var $ConfirmReadingTo = "";
  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. // SMTP VARIABLES
  126. /////////////////////////////////////////////////
  127. /**
  128. * Sets the SMTP hosts. All hosts must be separated by a
  129. * semicolon. You can also specify a different port
  130. * for each host by using this format: [hostname:port]
  131. * (e.g. "smtp1.example.com:25;smtp2.example.com").
  132. * Hosts will be tried in order.
  133. * @var string
  134. */
  135. var $Host = "localhost";
  136. /**
  137. * Sets the default SMTP server port.
  138. * @var int
  139. */
  140. var $Port = 25;
  141. /**
  142. * Sets the SMTP HELO of the message (Default is $Hostname).
  143. * @var string
  144. */
  145. var $Helo = "";
  146. /**
  147. * Sets SMTP authentication. Utilizes the Username and Password variables.
  148. * @var bool
  149. */
  150. var $SMTPAuth = false;
  151. /**
  152. * Sets SMTP username.
  153. * @var string
  154. */
  155. var $Username = "";
  156. /**
  157. * Sets SMTP password.
  158. * @var string
  159. */
  160. var $Password = "";
  161. /**
  162. * Sets the SMTP server timeout in seconds. This function will not
  163. * work with the win32 version.
  164. * @var int
  165. */
  166. var $Timeout = 10;
  167. /**
  168. * Sets SMTP class debugging on or off.
  169. * @var bool
  170. */
  171. var $SMTPDebug = false;
  172. /**
  173. * Prevents the SMTP connection from being closed after each mail
  174. * sending. If this is set to true then to close the connection
  175. * requires an explicit call to SmtpClose().
  176. * @var bool
  177. */
  178. var $SMTPKeepAlive = false;
  179. /**#@+
  180. * @access private
  181. */
  182. var $smtp = NULL;
  183. var $to = array();
  184. var $cc = array();
  185. var $bcc = array();
  186. var $ReplyTo = array();
  187. var $attachment = array();
  188. var $CustomHeader = array();
  189. var $message_type = "";
  190. var $boundary = array();
  191. var $language = array();
  192. var $error_count = 0;
  193. var $LE = "\n";
  194. /**#@-*/
  195. /////////////////////////////////////////////////
  196. // VARIABLE METHODS
  197. /////////////////////////////////////////////////
  198. /**
  199. * Constructor
  200. * Hack for Moodle as class may be included from various locations
  201. * SE 20041001
  202. * @param void
  203. * @return void
  204. */
  205. function PHPMailer () {
  206. global $CFG;
  207. $this->PluginDir = $CFG->libdir.'/phpmailer/';
  208. }
  209. /**
  210. * Sets message type to HTML.
  211. * @param bool $bool
  212. * @return void
  213. */
  214. function IsHTML($bool) {
  215. if($bool == true)
  216. $this->ContentType = "text/html";
  217. else
  218. $this->ContentType = "text/plain";
  219. }
  220. /**
  221. * Sets Mailer to send message using SMTP.
  222. * @return void
  223. */
  224. function IsSMTP() {
  225. $this->Mailer = "smtp";
  226. }
  227. /**
  228. * Sets Mailer to send message using PHP mail() function.
  229. * @return void
  230. */
  231. function IsMail() {
  232. $this->Mailer = "mail";
  233. }
  234. /**
  235. * Sets Mailer to send message using the $Sendmail program.
  236. * @return void
  237. */
  238. function IsSendmail() {
  239. $this->Mailer = "sendmail";
  240. }
  241. /**
  242. * Sets Mailer to send message using the qmail MTA.
  243. * @return void
  244. */
  245. function IsQmail() {
  246. $this->Sendmail = "/var/qmail/bin/sendmail";
  247. $this->Mailer = "sendmail";
  248. }
  249. /////////////////////////////////////////////////
  250. // RECIPIENT METHODS
  251. /////////////////////////////////////////////////
  252. /**
  253. * Adds a "To" address.
  254. * @param string $address
  255. * @param string $name
  256. * @return void
  257. */
  258. function AddAddress($address, $name = "") {
  259. $cur = count($this->to);
  260. $this->to[$cur][0] = trim($address);
  261. $this->to[$cur][1] = $name;
  262. }
  263. /**
  264. * Adds a "Cc" address. Note: this function works
  265. * with the SMTP mailer on win32, not with the "mail"
  266. * mailer.
  267. * @param string $address
  268. * @param string $name
  269. * @return void
  270. */
  271. function AddCC($address, $name = "") {
  272. $cur = count($this->cc);
  273. $this->cc[$cur][0] = trim($address);
  274. $this->cc[$cur][1] = $name;
  275. }
  276. /**
  277. * Adds a "Bcc" address. Note: this function works
  278. * with the SMTP mailer on win32, not with the "mail"
  279. * mailer.
  280. * @param string $address
  281. * @param string $name
  282. * @return void
  283. */
  284. function AddBCC($address, $name = "") {
  285. $cur = count($this->bcc);
  286. $this->bcc[$cur][0] = trim($address);
  287. $this->bcc[$cur][1] = $name;
  288. }
  289. /**
  290. * Adds a "Reply-to" address.
  291. * @param string $address
  292. * @param string $name
  293. * @return void
  294. */
  295. function AddReplyTo($address, $name = "") {
  296. $cur = count($this->ReplyTo);
  297. $this->ReplyTo[$cur][0] = trim($address);
  298. $this->ReplyTo[$cur][1] = $name;
  299. }
  300. /////////////////////////////////////////////////
  301. // MAIL SENDING METHODS
  302. /////////////////////////////////////////////////
  303. /**
  304. * Creates message and assigns Mailer. If the message is
  305. * not sent successfully then it returns false. Use the ErrorInfo
  306. * variable to view description of the error.
  307. * @return bool
  308. */
  309. function Send() {
  310. $header = "";
  311. $body = "";
  312. $result = true;
  313. if((count($this->to) + count($this->cc) + count($this->bcc)) < 1)
  314. {
  315. $this->SetError($this->Lang("provide_address"));
  316. return false;
  317. }
  318. // Set whether the message is multipart/alternative
  319. if(!empty($this->AltBody))
  320. $this->ContentType = "multipart/alternative";
  321. $this->error_count = 0; // reset errors
  322. $this->SetMessageType();
  323. $header .= $this->CreateHeader();
  324. $body = $this->CreateBody();
  325. if($body == "") { return false; }
  326. // Choose the mailer
  327. switch($this->Mailer)
  328. {
  329. case "sendmail":
  330. $result = $this->SendmailSend($header, $body);
  331. break;
  332. case "mail":
  333. $result = $this->MailSend($header, $body);
  334. break;
  335. case "smtp":
  336. $result = $this->SmtpSend($header, $body);
  337. break;
  338. default:
  339. $this->SetError($this->Mailer . $this->Lang("mailer_not_supported"));
  340. $result = false;
  341. break;
  342. }
  343. return $result;
  344. }
  345. /**
  346. * Sends mail using the $Sendmail program.
  347. * @access private
  348. * @return bool
  349. */
  350. function SendmailSend($header, $body) {
  351. if ($this->Sender != "")
  352. $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
  353. else
  354. $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
  355. if(!@$mail = popen($sendmail, "w"))
  356. {
  357. $this->SetError($this->Lang("execute") . $this->Sendmail);
  358. return false;
  359. }
  360. fputs($mail, $header);
  361. fputs($mail, $body);
  362. $result = pclose($mail) >> 8 & 0xFF;
  363. if($result != 0)
  364. {
  365. $this->SetError($this->Lang("execute") . $this->Sendmail);
  366. return false;
  367. }
  368. return true;
  369. }
  370. /**
  371. * Sends mail using the PHP mail() function.
  372. * @access private
  373. * @return bool
  374. */
  375. function MailSend($header, $body) {
  376. $to = "";
  377. for($i = 0; $i < count($this->to); $i++)
  378. {
  379. if($i != 0) { $to .= ", "; }
  380. $to .= $this->to[$i][0];
  381. }
  382. if ($this->Sender != "" && strlen(ini_get("safe_mode"))< 1)
  383. {
  384. $old_from = ini_get("sendmail_from");
  385. ini_set("sendmail_from", $this->Sender);
  386. $params = sprintf("-oi -f %s", $this->Sender);
  387. $rt = @mail($to, $this->EncodeHeader($this->Subject), $body,
  388. $header, $params);
  389. }
  390. else
  391. $rt = @mail($to, $this->EncodeHeader($this->Subject), $body, $header);
  392. if (isset($old_from))
  393. ini_set("sendmail_from", $old_from);
  394. if(!$rt)
  395. {
  396. $this->SetError($this->Lang("instantiate"));
  397. return false;
  398. }
  399. return true;
  400. }
  401. /**
  402. * Sends mail via SMTP using PhpSMTP (Author:
  403. * Chris Ryan). Returns bool. Returns false if there is a
  404. * bad MAIL FROM, RCPT, or DATA input.
  405. * @access private
  406. * @return bool
  407. */
  408. function SmtpSend($header, $body) {
  409. include_once($this->PluginDir."class.smtp.php");
  410. $error = "";
  411. $bad_rcpt = array();
  412. if(!$this->SmtpConnect())
  413. return false;
  414. $smtp_from = ($this->Sender == "") ? $this->From : $this->Sender;
  415. if(!$this->smtp->Mail($smtp_from))
  416. {
  417. $error = $this->Lang("from_failed") . $smtp_from;
  418. $this->SetError($error);
  419. $this->smtp->Reset();
  420. return false;
  421. }
  422. // Attempt to send attach all recipients
  423. for($i = 0; $i < count($this->to); $i++)
  424. {
  425. if(!$this->smtp->Recipient($this->to[$i][0]))
  426. $bad_rcpt[] = $this->to[$i][0];
  427. }
  428. for($i = 0; $i < count($this->cc); $i++)
  429. {
  430. if(!$this->smtp->Recipient($this->cc[$i][0]))
  431. $bad_rcpt[] = $this->cc[$i][0];
  432. }
  433. for($i = 0; $i < count($this->bcc); $i++)
  434. {
  435. if(!$this->smtp->Recipient($this->bcc[$i][0]))
  436. $bad_rcpt[] = $this->bcc[$i][0];
  437. }
  438. if(count($bad_rcpt) > 0) // Create error message
  439. {
  440. for($i = 0; $i < count($bad_rcpt); $i++)
  441. {
  442. if($i != 0) { $error .= ", "; }
  443. $error .= $bad_rcpt[$i];
  444. }
  445. $error = $this->Lang("recipients_failed") . $error;
  446. $this->SetError($error);
  447. $this->smtp->Reset();
  448. return false;
  449. }
  450. if(!$this->smtp->Data($header . $body))
  451. {
  452. $this->SetError($this->Lang("data_not_accepted"));
  453. $this->smtp->Reset();
  454. return false;
  455. }
  456. if($this->SMTPKeepAlive == true)
  457. $this->smtp->Reset();
  458. else
  459. $this->SmtpClose();
  460. return true;
  461. }
  462. /**
  463. * Initiates a connection to an SMTP server. Returns false if the
  464. * operation failed.
  465. * @access private
  466. * @return bool
  467. */
  468. function SmtpConnect() {
  469. if($this->smtp == NULL) { $this->smtp = new SMTP(); }
  470. $this->smtp->do_debug = $this->SMTPDebug;
  471. $hosts = explode(";", $this->Host);
  472. $index = 0;
  473. $connection = ($this->smtp->Connected());
  474. // Retry while there is no connection
  475. while($index < count($hosts) && $connection == false)
  476. {
  477. if(strstr($hosts[$index], ":"))
  478. list($host, $port) = explode(":", $hosts[$index]);
  479. else
  480. {
  481. $host = $hosts[$index];
  482. $port = $this->Port;
  483. }
  484. if($this->smtp->Connect($host, $port, $this->Timeout))
  485. {
  486. if ($this->Helo != '')
  487. $this->smtp->Hello($this->Helo);
  488. else
  489. $this->smtp->Hello($this->ServerHostname());
  490. if($this->SMTPAuth)
  491. {
  492. if(!$this->smtp->Authenticate($this->Username,
  493. $this->Password))
  494. {
  495. $this->SetError($this->Lang("authenticate"));
  496. $this->smtp->Reset();
  497. $connection = false;
  498. }
  499. }
  500. $connection = true;
  501. }
  502. $index++;
  503. }
  504. if(!$connection)
  505. $this->SetError($this->Lang("connect_host"));
  506. return $connection;
  507. }
  508. /**
  509. * Closes the active SMTP session if one exists.
  510. * @return void
  511. */
  512. function SmtpClose() {
  513. if($this->smtp != NULL)
  514. {
  515. if($this->smtp->Connected())
  516. {
  517. $this->smtp->Quit();
  518. $this->smtp->Close();
  519. }
  520. }
  521. }
  522. /**
  523. * Sets the language for all class error messages. Returns false
  524. * if it cannot load the language file. The default language type
  525. * is English.
  526. * SE 20041001: Added '$this->PluginDir' for Moodle compatibility
  527. *
  528. * @param string $lang_type Type of language (e.g. Portuguese: "br")
  529. * @param string $lang_path Path to the language file directory
  530. * @access public
  531. * @return bool
  532. */
  533. function SetLanguage($lang_type, $lang_path = "language/") {
  534. if(file_exists($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php'))
  535. include($this->PluginDir.$lang_path.'phpmailer.lang-'.$lang_type.'.php');
  536. else if(file_exists($lang_path.'phpmailer.lang-en.php'))
  537. include($this->PluginDir.$lang_path.'phpmailer.lang-en.php');
  538. else
  539. {
  540. $this->SetError("Could not load language file");
  541. return false;
  542. }
  543. $this->language = $PHPMAILER_LANG;
  544. return true;
  545. }
  546. /////////////////////////////////////////////////
  547. // MESSAGE CREATION METHODS
  548. /////////////////////////////////////////////////
  549. /**
  550. * Creates recipient headers.
  551. * @access private
  552. * @return string
  553. */
  554. function AddrAppend($type, $addr) {
  555. $addr_str = $type . ": ";
  556. $addr_str .= $this->AddrFormat($addr[0]);
  557. if(count($addr) > 1)
  558. {
  559. for($i = 1; $i < count($addr); $i++)
  560. $addr_str .= ", " . $this->AddrFormat($addr[$i]);
  561. }
  562. $addr_str .= $this->LE;
  563. return $addr_str;
  564. }
  565. /**
  566. * Formats an address correctly.
  567. * @access private
  568. * @return string
  569. */
  570. function AddrFormat($addr) {
  571. if(empty($addr[1]))
  572. $formatted = preg_replace('/[\r\n]+/', '', $addr[0]); // Moodle modification
  573. else
  574. {
  575. $formatted = $this->EncodeHeader($addr[1], 'phrase') . " <" .
  576. preg_replace('/[\r\n]+/', '', $addr[0]) . ">"; // Moodle modification
  577. }
  578. return $formatted;
  579. }
  580. /**
  581. * Wraps message for use with mailers that do not
  582. * automatically perform wrapping and for quoted-printable.
  583. * Original written by philippe.
  584. * @access private
  585. * @return string
  586. */
  587. function WrapText($message, $length, $qp_mode = false) {
  588. $soft_break = ($qp_mode) ? sprintf(" =%s", $this->LE) : $this->LE;
  589. $message = $this->FixEOL($message);
  590. if (substr($message, -1) == $this->LE)
  591. $message = substr($message, 0, -1);
  592. $line = explode($this->LE, $message);
  593. $message = "";
  594. for ($i=0 ;$i < count($line); $i++)
  595. {
  596. $line_part = explode(" ", $line[$i]);
  597. $buf = "";
  598. for ($e = 0; $e<count($line_part); $e++)
  599. {
  600. $word = $line_part[$e];
  601. if ($qp_mode and (strlen($word) > $length))
  602. {
  603. $space_left = $length - strlen($buf) - 1;
  604. if ($e != 0)
  605. {
  606. if ($space_left > 20)
  607. {
  608. $len = $space_left;
  609. if (substr($word, $len - 1, 1) == "=")
  610. $len--;
  611. elseif (substr($word, $len - 2, 1) == "=")
  612. $len -= 2;
  613. $part = substr($word, 0, $len);
  614. $word = substr($word, $len);
  615. $buf .= " " . $part;
  616. $message .= $buf . sprintf("=%s", $this->LE);
  617. }
  618. else
  619. {
  620. $message .= $buf . $soft_break;
  621. }
  622. $buf = "";
  623. }
  624. while (strlen($word) > 0)
  625. {
  626. $len = $length;
  627. if (substr($word, $len - 1, 1) == "=")
  628. $len--;
  629. elseif (substr($word, $len - 2, 1) == "=")
  630. $len -= 2;
  631. $part = substr($word, 0, $len);
  632. $word = substr($word, $len);
  633. if (strlen($word) > 0)
  634. $message .= $part . sprintf("=%s", $this->LE);
  635. else
  636. $buf = $part;
  637. }
  638. }
  639. else
  640. {
  641. $buf_o = $buf;
  642. $buf .= ($e == 0) ? $word : (" " . $word);
  643. if (strlen($buf) > $length and $buf_o != "")
  644. {
  645. $message .= $buf_o . $soft_break;
  646. $buf = $word;
  647. }
  648. }
  649. }
  650. $message .= $buf . $this->LE;
  651. }
  652. return $message;
  653. }
  654. /**
  655. * Set the body wrapping.
  656. * @access private
  657. * @return void
  658. */
  659. function SetWordWrap() {
  660. if($this->WordWrap < 1)
  661. return;
  662. switch($this->message_type)
  663. {
  664. case "alt":
  665. // fall through
  666. case "alt_attachments":
  667. $this->AltBody = $this->WrapText($this->AltBody, $this->WordWrap);
  668. break;
  669. default:
  670. $this->Body = $this->WrapText($this->Body, $this->WordWrap);
  671. break;
  672. }
  673. }
  674. /**
  675. * Assembles message header.
  676. * @access private
  677. * @return string
  678. */
  679. function CreateHeader() {
  680. $result = "";
  681. // Set the boundaries
  682. $uniq_id = md5(uniqid(time()));
  683. $this->boundary[1] = "b1_" . $uniq_id;
  684. $this->boundary[2] = "b2_" . $uniq_id;
  685. $result .= $this->HeaderLine("Date", $this->RFCDate());
  686. if($this->Sender == "")
  687. $result .= $this->HeaderLine("Return-Path", trim(preg_replace('/[\r\n]+/', '', $this->From))); // Moodle modification
  688. else
  689. $result .= $this->HeaderLine("Return-Path", trim(preg_replace('/[\r\n]+/', '', $this->Sender))); // Moodle modification
  690. // To be created automatically by mail()
  691. if($this->Mailer != "mail")
  692. {
  693. if(count($this->to) > 0)
  694. $result .= $this->AddrAppend("To", $this->to);
  695. else if (count($this->cc) == 0)
  696. $result .= $this->HeaderLine("To", "undisclosed-recipients:;");
  697. if(count($this->cc) > 0)
  698. $result .= $this->AddrAppend("Cc", $this->cc);
  699. }
  700. $from = array();
  701. $from[0][0] = trim($this->From);
  702. $from[0][1] = $this->FromName;
  703. $result .= $this->AddrAppend("From", $from);
  704. // sendmail and mail() extract Bcc from the header before sending
  705. if((($this->Mailer == "sendmail") || ($this->Mailer == "mail")) && (count($this->bcc) > 0))
  706. $result .= $this->AddrAppend("Bcc", $this->bcc);
  707. if(count($this->ReplyTo) > 0)
  708. $result .= $this->AddrAppend("Reply-to", $this->ReplyTo);
  709. // mail() sets the subject itself
  710. if($this->Mailer != "mail")
  711. $result .= $this->HeaderLine("Subject", $this->EncodeHeader(trim($this->Subject)));
  712. /**
  713. * BEGIN original phpmailer code
  714. *
  715. * Commented out is the original line we are replacing.
  716. * Vy-Shane Sin Fat <vy-shane At moodle.com>, 14 Feb 2007.
  717. */
  718. //$result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
  719. /**
  720. * END original phpmailer code
  721. */
  722. /**
  723. * BEGIN custom Moodle code
  724. *
  725. * This change is made necessary by MDL-3681. The Moodle forum module
  726. * adds Message-ID as a custom header for each forum post mailout.
  727. * This is used to help email clients display the messages in a
  728. * threaded view. However, phpmailer also adds it's own Message-ID
  729. * to every email that it sends. We want this to happen only if we
  730. * haven't defined our own custom Message-ID for the email.
  731. *
  732. * Vy-Shane Sin Fat <vy-shane At moodle.com>, 14 Feb 2007.
  733. */
  734. $needmessageid = true;
  735. for($i=0; $i<count($this->CustomHeader); $i++)
  736. {
  737. if (strtolower(trim($this->CustomHeader[$i][0])) == 'message-id') {
  738. $needmessageid = false;
  739. break;
  740. }
  741. }
  742. if ($needmessageid) {
  743. $result .= sprintf("Message-ID: <%s@%s>%s", $uniq_id, $this->ServerHostname(), $this->LE);
  744. }
  745. /**
  746. * END custom Moodle code
  747. */
  748. $result .= $this->HeaderLine("X-Priority", $this->Priority);
  749. $result .= $this->HeaderLine("X-Mailer", "PHPMailer [version " . $this->Version . "]");
  750. if($this->ConfirmReadingTo != "")
  751. {
  752. $result .= $this->HeaderLine("Disposition-Notification-To",
  753. "<" . trim($this->ConfirmReadingTo) . ">");
  754. }
  755. // Add custom headers
  756. for($index = 0; $index < count($this->CustomHeader); $index++)
  757. {
  758. $result .= $this->HeaderLine(trim($this->CustomHeader[$index][0]),
  759. $this->EncodeHeader(trim($this->CustomHeader[$index][1])));
  760. }
  761. $result .= $this->HeaderLine("MIME-Version", "1.0");
  762. switch($this->message_type)
  763. {
  764. case "plain":
  765. $result .= $this->HeaderLine("Content-Transfer-Encoding", $this->Encoding);
  766. $result .= sprintf("Content-Type: %s; charset=\"%s\"",
  767. $this->ContentType, $this->CharSet);
  768. break;
  769. case "attachments":
  770. // fall through
  771. case "alt_attachments":
  772. if($this->InlineImageExists())
  773. {
  774. $result .= sprintf("Content-Type: %s;%s\ttype=\"text/html\";%s\tboundary=\"%s\"%s",
  775. "multipart/related", $this->LE, $this->LE,
  776. $this->boundary[1], $this->LE);
  777. }
  778. else
  779. {
  780. $result .= $this->HeaderLine("Content-Type", "multipart/mixed;");
  781. $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
  782. }
  783. break;
  784. case "alt":
  785. $result .= $this->HeaderLine("Content-Type", "multipart/alternative;");
  786. $result .= $this->TextLine("\tboundary=\"" . $this->boundary[1] . '"');
  787. break;
  788. }
  789. if($this->Mailer != "mail")
  790. $result .= $this->LE.$this->LE;
  791. return $result;
  792. }
  793. /**
  794. * Assembles the message body. Returns an empty string on failure.
  795. * @access private
  796. * @return string
  797. */
  798. function CreateBody() {
  799. $result = "";
  800. $this->SetWordWrap();
  801. switch($this->message_type)
  802. {
  803. case "alt":
  804. $result .= $this->GetBoundary($this->boundary[1], "",
  805. "text/plain", "");
  806. $result .= $this->EncodeString($this->AltBody, $this->Encoding);
  807. $result .= $this->LE.$this->LE;
  808. $result .= $this->GetBoundary($this->boundary[1], "",
  809. "text/html", "");
  810. $result .= $this->EncodeString($this->Body, $this->Encoding);
  811. $result .= $this->LE.$this->LE;
  812. $result .= $this->EndBoundary($this->boundary[1]);
  813. break;
  814. case "plain":
  815. $result .= $this->EncodeString($this->Body, $this->Encoding);
  816. break;
  817. case "attachments":
  818. $result .= $this->GetBoundary($this->boundary[1], "", "", "");
  819. $result .= $this->EncodeString($this->Body, $this->Encoding);
  820. $result .= $this->LE;
  821. $result .= $this->AttachAll();
  822. break;
  823. case "alt_attachments":
  824. $result .= sprintf("--%s%s", $this->boundary[1], $this->LE);
  825. $result .= sprintf("Content-Type: %s;%s" .
  826. "\tboundary=\"%s\"%s",
  827. "multipart/alternative", $this->LE,
  828. $this->boundary[2], $this->LE.$this->LE);
  829. // Create text body
  830. $result .= $this->GetBoundary($this->boundary[2], "",
  831. "text/plain", "") . $this->LE;
  832. $result .= $this->EncodeString($this->AltBody, $this->Encoding);
  833. $result .= $this->LE.$this->LE;
  834. // Create the HTML body
  835. $result .= $this->GetBoundary($this->boundary[2], "",
  836. "text/html", "") . $this->LE;
  837. $result .= $this->EncodeString($this->Body, $this->Encoding);
  838. $result .= $this->LE.$this->LE;
  839. $result .= $this->EndBoundary($this->boundary[2]);
  840. $result .= $this->AttachAll();
  841. break;
  842. }
  843. if($this->IsError())
  844. $result = "";
  845. return $result;
  846. }
  847. /**
  848. * Returns the start of a message boundary.
  849. * @access private
  850. */
  851. function GetBoundary($boundary, $charSet, $contentType, $encoding) {
  852. $result = "";
  853. if($charSet == "") { $charSet = $this->CharSet; }
  854. if($contentType == "") { $contentType = $this->ContentType; }
  855. if($encoding == "") { $encoding = $this->Encoding; }
  856. $result .= $this->TextLine("--" . $boundary);
  857. $result .= sprintf("Content-Type: %s; charset = \"%s\"",
  858. $contentType, $charSet);
  859. $result .= $this->LE;
  860. $result .= $this->HeaderLine("Content-Transfer-Encoding", $encoding);
  861. $result .= $this->LE;
  862. return $result;
  863. }
  864. /**
  865. * Returns the end of a message boundary.
  866. * @access private
  867. */
  868. function EndBoundary($boundary) {
  869. return $this->LE . "--" . $boundary . "--" . $this->LE;
  870. }
  871. /**
  872. * Sets the message type.
  873. * @access private
  874. * @return void
  875. */
  876. function SetMessageType() {
  877. if(count($this->attachment) < 1 && strlen($this->AltBody) < 1)
  878. $this->message_type = "plain";
  879. else
  880. {
  881. if(count($this->attachment) > 0)
  882. $this->message_type = "attachments";
  883. if(strlen($this->AltBody) > 0 && count($this->attachment) < 1)
  884. $this->message_type = "alt";
  885. if(strlen($this->AltBody) > 0 && count($this->attachment) > 0)
  886. $this->message_type = "alt_attachments";
  887. }
  888. }
  889. /**
  890. * Returns a formatted header line.
  891. * @access private
  892. * @return string
  893. */
  894. function HeaderLine($name, $value) {
  895. return $name . ": " . $value . $this->LE;
  896. }
  897. /**
  898. * Returns a formatted mail line.
  899. * @access private
  900. * @return string
  901. */
  902. function TextLine($value) {
  903. return $value . $this->LE;
  904. }
  905. /////////////////////////////////////////////////
  906. // ATTACHMENT METHODS
  907. /////////////////////////////////////////////////
  908. /**
  909. * Adds an attachment from a path on the filesystem.
  910. * Returns false if the file could not be found
  911. * or accessed.
  912. * @param string $path Path to the attachment.
  913. * @param string $name Overrides the attachment name.
  914. * @param string $encoding File encoding (see $Encoding).
  915. * @param string $type File extension (MIME) type.
  916. * @return bool
  917. */
  918. function AddAttachment($path, $name = "", $encoding = "base64",
  919. $type = "application/octet-stream") {
  920. if(!@is_file($path))
  921. {
  922. $this->SetError($this->Lang("file_access") . $path);
  923. return false;
  924. }
  925. $filename = basename($path);
  926. if($name == "")
  927. $name = $filename;
  928. $cur = count($this->attachment);
  929. $this->attachment[$cur][0] = $path;
  930. $this->attachment[$cur][1] = $filename;
  931. $this->attachment[$cur][2] = $name;
  932. $this->attachment[$cur][3] = $encoding;
  933. $this->attachment[$cur][4] = $type;
  934. $this->attachment[$cur][5] = false; // isStringAttachment
  935. $this->attachment[$cur][6] = "attachment";
  936. $this->attachment[$cur][7] = 0;
  937. return true;
  938. }
  939. /**
  940. * Attaches all fs, string, and binary attachments to the message.
  941. * Returns an empty string on failure.
  942. * @access private
  943. * @return string
  944. */
  945. function AttachAll() {
  946. // Return text of body
  947. $mime = array();
  948. // Add all attachments
  949. for($i = 0; $i < count($this->attachment); $i++)
  950. {
  951. // Check for string attachment
  952. $bString = $this->attachment[$i][5];
  953. if ($bString)
  954. $string = $this->attachment[$i][0];
  955. else
  956. $path = $this->attachment[$i][0];
  957. $filename = $this->attachment[$i][1];
  958. $name = $this->attachment[$i][2];
  959. $encoding = $this->attachment[$i][3];
  960. $type = $this->attachment[$i][4];
  961. $disposition = $this->attachment[$i][6];
  962. $cid = $this->attachment[$i][7];
  963. $mime[] = sprintf("--%s%s", $this->boundary[1], $this->LE);
  964. $mime[] = sprintf("Content-Type: %s; name=\"%s\"%s", $type, $name, $this->LE);
  965. $mime[] = sprintf("Content-Transfer-Encoding: %s%s", $encoding, $this->LE);
  966. if($disposition == "inline")
  967. $mime[] = sprintf("Content-ID: <%s>%s", $cid, $this->LE);
  968. $mime[] = sprintf("Content-Disposition: %s; filename=\"%s\"%s",
  969. $disposition, $name, $this->LE.$this->LE);
  970. // Encode as string attachment
  971. if($bString)
  972. {
  973. $mime[] = $this->EncodeString($string, $encoding);
  974. if($this->IsError()) { return ""; }
  975. $mime[] = $this->LE.$this->LE;
  976. }
  977. else
  978. {
  979. $mime[] = $this->EncodeFile($path, $encoding);
  980. if($this->IsError()) { return ""; }
  981. $mime[] = $this->LE.$this->LE;
  982. }
  983. }
  984. $mime[] = sprintf("--%s--%s", $this->boundary[1], $this->LE);
  985. return join("", $mime);
  986. }
  987. /**
  988. * Encodes attachment in requested format. Returns an
  989. * empty string on failure.
  990. * @access private
  991. * @return string
  992. */
  993. function EncodeFile ($path, $encoding = "base64") {
  994. if(!@$fd = fopen($path, "rb"))
  995. {
  996. $this->SetError($this->Lang("file_open") . $path);
  997. return "";
  998. }
  999. $magic_quotes = get_magic_quotes_runtime();
  1000. set_magic_quotes_runtime(0);
  1001. $file_buffer = fread($fd, filesize($path));
  1002. $file_buffer = $this->EncodeString($file_buffer, $encoding);
  1003. fclose($fd);
  1004. set_magic_quotes_runtime($magic_quotes);
  1005. return $file_buffer;
  1006. }
  1007. /**
  1008. * Encodes string to requested format. Returns an
  1009. * empty string on failure.
  1010. * @access private
  1011. * @return string
  1012. */
  1013. function EncodeString ($str, $encoding = "base64") {
  1014. $encoded = "";
  1015. switch(strtolower($encoding)) {
  1016. case "base64":
  1017. // chunk_split is found in PHP >= 3.0.6
  1018. $encoded = chunk_split(base64_encode($str), 76, $this->LE);
  1019. break;
  1020. case "7bit":
  1021. case "8bit":
  1022. $encoded = $this->FixEOL($str);
  1023. if (substr($encoded, -(strlen($this->LE))) != $this->LE)
  1024. $encoded .= $this->LE;
  1025. break;
  1026. case "binary":
  1027. $encoded = $str;
  1028. break;
  1029. case "quoted-printable":
  1030. $encoded = $this->EncodeQP($str);
  1031. break;
  1032. default:
  1033. $this->SetError($this->Lang("encoding") . $encoding);
  1034. break;
  1035. }
  1036. return $encoded;
  1037. }
  1038. /**
  1039. * Encode a header string to best of Q, B, quoted or none.
  1040. * @access private
  1041. * @return string
  1042. */
  1043. function EncodeHeader ($str, $position = 'text') {
  1044. /// Start Moodle Hack - do our own multibyte-safe header encoding and cleanup
  1045. $str = str_replace("\r", '', $str);
  1046. $str = str_replace("\n", '', $str);
  1047. $textlib = textlib_get_instance();
  1048. $encoded = $textlib->encode_mimeheader($str, $this->CharSet);
  1049. if ($encoded !== false) {
  1050. $encoded = str_replace("\n", $this->LE, $encoded);
  1051. if ($position == 'phrase') {
  1052. return ("\"$encoded\"");
  1053. }
  1054. return $encoded;
  1055. }
  1056. // try the old way that does not handle binary-safe line splitting in mime header
  1057. /// End Moodle Hack
  1058. $x = 0;
  1059. switch (strtolower($position)) {
  1060. case 'phrase':
  1061. if (!preg_match('/[\200-\377]/', $str)) {
  1062. // Can't use addslashes as we don't know what value has magic_quotes_sybase.
  1063. $encoded = addcslashes($str, "\0..\37\177\\\"");
  1064. if (($str == $encoded) && !preg_match('/[^A-Za-z0-9!#$%&\'*+\/=?^_`{|}~ -]/', $str))
  1065. return ($encoded);
  1066. else
  1067. return ("\"$encoded\"");
  1068. }
  1069. $x = preg_match_all('/[^\040\041\043-\133\135-\176]/', $str, $matches);
  1070. break;
  1071. case 'comment':
  1072. $x = preg_match_all('/[()"]/', $str, $matches);
  1073. // Fall-through
  1074. case 'text':
  1075. default:
  1076. $x += preg_match_all('/[\000-\010\013\014\016-\037\177-\377]/', $str, $matches);
  1077. break;
  1078. }
  1079. if ($x == 0)
  1080. return ($str);
  1081. $maxlen = 75 - 7 - strlen($this->CharSet);
  1082. // Try to select the encoding which should produce the shortest output
  1083. if (strlen($str)/3 < $x) {
  1084. $encoding = 'B';
  1085. $encoded = base64_encode($str);
  1086. $maxlen -= $maxlen % 4;
  1087. $encoded = trim(chunk_split($encoded, $maxlen, "\n"));
  1088. } else {
  1089. $encoding = 'Q';
  1090. $encoded = $this->EncodeQ($str, $position);
  1091. $encoded = $this->WrapText($encoded, $maxlen, true);
  1092. $encoded = str_replace("=".$this->LE, "\n", trim($encoded));
  1093. }
  1094. $encoded = preg_replace('/^(.*)$/m', " =?".$this->CharSet."?$encoding?\\1?=", $encoded);
  1095. $encoded = trim(str_replace("\n", $this->LE, $encoded));
  1096. return $encoded;
  1097. }
  1098. /**
  1099. * Encode string to quoted-printable.
  1100. * @access private
  1101. * @return string
  1102. */
  1103. function EncodeQP ($str) {
  1104. $encoded = $this->FixEOL($str);
  1105. if (substr($encoded, -(strlen($this->LE))) != $this->LE)
  1106. $encoded .= $this->LE;
  1107. // Replace every high ascii, control and = characters
  1108. $encoded = preg_replace('/([\000-\010\013\014\016-\037\075\177-\377])/e',
  1109. "'='.sprintf('%02X', ord('\\1'))", $encoded);
  1110. // Replace every spaces and tabs when it's the last character on a line
  1111. $encoded = preg_replace("/([\011\040])".$this->LE."/e",
  1112. "'='.sprintf('%02X', ord('\\1')).'".$this->LE."'", $encoded);
  1113. // Maximum line length of 76 characters before CRLF (74 + space + '=')
  1114. $encoded = $this->WrapText($encoded, 74, true);
  1115. return $encoded;
  1116. }
  1117. /**
  1118. * Encode string to q encoding.
  1119. * @access private
  1120. * @return string
  1121. */
  1122. function EncodeQ ($str, $position = "text") {
  1123. // There should not be any EOL in the string
  1124. $encoded = preg_replace("[\r\n]", "", $str);
  1125. switch (strtolower($position)) {
  1126. case "phrase":
  1127. $encoded = preg_replace("/([^A-Za-z0-9!*+\/ -])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
  1128. break;
  1129. case "comment":
  1130. $encoded = preg_replace("/([\(\)\"])/e", "'='.sprintf('%02X', ord('\\1'))", $encoded);
  1131. case "text":
  1132. default:
  1133. // Replace every high ascii, control =, ? and _ characters
  1134. $encoded = preg_replace('/([\000-\011\013\014\016-\037\075\077\137\177-\377])/e',
  1135. "'='.sprintf('%02X', ord('\\1'))", $encoded);
  1136. break;
  1137. }
  1138. // Replace every spaces to _ (more readable than =20)
  1139. $encoded = str_replace(" ", "_", $encoded);
  1140. return $encoded;
  1141. }
  1142. /**
  1143. * Adds a string or binary attachment (non-filesystem) to the list.
  1144. * This method can be used to attach ascii or binary data,
  1145. * such as a BLOB record from a database.
  1146. * @param string $string String attachment data.
  1147. * @param string $filename Name of the attachment.
  1148. * @param string $encoding File encoding (see $Encoding).
  1149. * @param string $type File extension (MIME) type.
  1150. * @return void
  1151. */
  1152. function AddStringAttachment($string, $filename, $encoding = "base64",
  1153. $type = "application/octet-stream") {
  1154. // Append to $attachment array
  1155. $cur = count($this->attachment);
  1156. $this->attachment[$cur][0] = $string;
  1157. $this->attachment[$cur][1] = $filename;
  1158. $this->attachment[$cur][2] = $filename;
  1159. $this->attachment[$cur][3] = $encoding;
  1160. $this->attachment[$cur][4] = $type;
  1161. $this->attachment[$cur][5] = true; // isString
  1162. $this->attachment[$cur][6] = "attachment";
  1163. $this->attachment[$cur][7] = 0;
  1164. }
  1165. /**
  1166. * Adds an embedded attachment. This can include images, sounds, and
  1167. * just about any other document. Make sure to set the $type to an
  1168. * image type. For JPEG images use "image/jpeg" and for GIF images
  1169. * use "image/gif".
  1170. * @param string $path Path to the attachment.
  1171. * @param string $cid Content ID of the attachment. Use this to identify
  1172. * the Id for accessing the image in an HTML form.
  1173. * @param string $name Overrides the attachment name.
  1174. * @param string $encoding File encoding (see $Encoding).
  1175. * @param string $type File extension (MIME) type.
  1176. * @return bool
  1177. */
  1178. function AddEmbeddedImage($path, $cid, $name = "", $encoding = "base64",
  1179. $type = "application/octet-stream") {
  1180. if(!@is_file($path))
  1181. {
  1182. $this->SetError($this->Lang("file_access") . $path);
  1183. return false;
  1184. }
  1185. $filename = basename($path);
  1186. if($name == "")
  1187. $name = $filename;
  1188. // Append to $attachment array
  1189. $cur = count($this->attachment);
  1190. $this->attachment[$cur][0] = $path;
  1191. $this->attachment[$cur][1] = $filename;
  1192. $this->attachment[$cur][2] = $name;
  1193. $this->attachment[$cur][3] = $encoding;
  1194. $this->attachment[$cur][4] = $type;
  1195. $this->attachment[$cur][5] = false; // isStringAttachment
  1196. $this->attachment[$cur][6] = "inline";
  1197. $this->attachment[$cur][7] = $cid;
  1198. return true;
  1199. }
  1200. /**
  1201. * Returns true if an inline attachment is present.
  1202. * @access private
  1203. * @return bool
  1204. */
  1205. function InlineImageExists() {
  1206. $result = false;
  1207. for($i = 0; $i < count($this->attachment); $i++)
  1208. {
  1209. if($this->attachment[$i][6] == "inline")
  1210. {
  1211. $result = true;
  1212. break;
  1213. }
  1214. }
  1215. return $result;
  1216. }
  1217. /////////////////////////////////////////////////
  1218. // MESSAGE RESET METHODS
  1219. /////////////////////////////////////////////////
  1220. /**
  1221. * Clears all recipients assigned in the TO array. Returns void.
  1222. * @return void
  1223. */
  1224. function ClearAddresses() {
  1225. $this->to = array();
  1226. }
  1227. /**
  1228. * Clears all recipients assigned in the CC array. Returns void.
  1229. * @return void
  1230. */
  1231. function ClearCCs() {
  1232. $this->cc = array();
  1233. }
  1234. /**
  1235. * Clears all recipients assigned in the BCC array. Returns void.
  1236. * @return void
  1237. */
  1238. function ClearBCCs() {
  1239. $this->bcc = array();
  1240. }
  1241. /**
  1242. * Clears all recipients assigned in the ReplyTo array. Returns void.
  1243. * @return void
  1244. */
  1245. function ClearReplyTos() {
  1246. $this->ReplyTo = array();
  1247. }
  1248. /**
  1249. * Clears all recipients assigned in the TO, CC and BCC
  1250. * array. Returns void.
  1251. * @return void
  1252. */
  1253. function ClearAllRecipients() {
  1254. $this->to = array();
  1255. $this->cc = array();
  1256. $this->bcc = array();
  1257. }
  1258. /**
  1259. * Clears all previously set filesystem, string, and binary
  1260. * attachments. Returns void.
  1261. * @return void
  1262. */
  1263. function ClearAttachments() {
  1264. $this->attachment = array();
  1265. }
  1266. /**
  1267. * Clears all custom headers. Returns void.
  1268. * @return void
  1269. */
  1270. function ClearCustomHeaders() {
  1271. $this->CustomHeader = array();
  1272. }
  1273. /////////////////////////////////////////////////
  1274. // MISCELLANEOUS METHODS
  1275. /////////////////////////////////////////////////
  1276. /**
  1277. * Adds the error message to the error container.
  1278. * Returns void.
  1279. * @access private
  1280. * @return void
  1281. */
  1282. function SetError($msg) {
  1283. $this->error_count++;
  1284. $this->ErrorInfo = $msg;
  1285. }
  1286. /**
  1287. * Returns the proper RFC 822 formatted date.
  1288. * @access private
  1289. * @return string
  1290. */
  1291. function RFCDate() {
  1292. $tz = date("Z");
  1293. $tzs = ($tz < 0) ? "-" : "+";
  1294. $tz = abs($tz);
  1295. $tz = (($tz - ($tz%3600) )/3600)*100 + ($tz%3600)/60; // moodle change - MDL-12596
  1296. $result = sprintf("%s %s%04d", date("D, j M Y H:i:s"), $tzs, $tz);
  1297. return $result;
  1298. }
  1299. /**
  1300. * Returns the appropriate server variable. Should work with both
  1301. * PHP 4.1.0+ as well as older versions. Returns an empty string
  1302. * if nothing is found.
  1303. * @access private
  1304. * @return mixed
  1305. */
  1306. function ServerVar($varName) {
  1307. global $HTTP_SERVER_VARS;
  1308. global $HTTP_ENV_VARS;
  1309. if(!isset($_SERVER))
  1310. {
  1311. $_SERVER = $HTTP_SERVER_VARS;
  1312. if(!isset($_SERVER["REMOTE_ADDR"]))
  1313. $_SERVER = $HTTP_ENV_VARS; // must be Apache
  1314. }
  1315. if(isset($_SERVER[$varName]))
  1316. return $_SERVER[$varName];
  1317. else
  1318. return "";
  1319. }
  1320. /**
  1321. * Returns the server hostname or 'localhost.localdomain' if unknown.
  1322. * @access private
  1323. * @return string
  1324. */
  1325. function ServerHostname() {
  1326. if ($this->Hostname != "")
  1327. $result = $this->Hostname;
  1328. elseif ($this->ServerVar('SERVER_NAME') != "")
  1329. $result = $this->ServerVar('SERVER_NAME');
  1330. else
  1331. $result = "localhost.localdomain";
  1332. return $result;
  1333. }
  1334. /**
  1335. * Returns a message in the appropriate language.
  1336. * @access private
  1337. * @return string
  1338. */
  1339. function Lang($key) {
  1340. if(count($this->language) < 1)
  1341. $this->SetLanguage("en"); // set the default language
  1342. if(isset($this->language[$key]))
  1343. return $this->language[$key];
  1344. else
  1345. return "Language string failed to load: " . $key;
  1346. }
  1347. /**
  1348. * Returns true if an error occurred.
  1349. * @return bool
  1350. */
  1351. function IsError() {
  1352. return ($this->error_count > 0);
  1353. }
  1354. /**
  1355. * Changes every end of line from CR or LF to CRLF.
  1356. * @access private
  1357. * @return string
  1358. */
  1359. function FixEOL($str) {
  1360. $str = str_replace("\r\n", "\n", $str);
  1361. $str = str_replace("\r", "\n", $str);
  1362. $str = str_replace("\n", $this->LE, $str);
  1363. return $str;
  1364. }
  1365. /**
  1366. * Adds a custom header.
  1367. * @return void
  1368. */
  1369. function AddCustomHeader($custom_header) {
  1370. $this->CustomHeader[] = explode(":", $custom_header, 2);
  1371. }
  1372. }
  1373. ?>