/src/sb/Email/Writer.php

https://github.com/surebert/surebert-framework · PHP · 240 lines · 125 code · 41 blank · 74 comment · 26 complexity · 934075860de732a9cdea07625ae5b302 MD5 · raw file

  1. <?php
  2. /**
  3. * Used to send plain text emails, HTML emails, or plain text and html emails
  4. * with attachments both inline and not REQUIRES sb_Email.php and sb_Files
  5. * (<-unless you specify the mime types on attachments manually)
  6. *
  7. * If DEBUG_EMAIL constant is defined, then all email goes to that address.
  8. *
  9. * @author paul.visco@roswellpark.org
  10. * @package Email
  11. *
  12. */
  13. namespace sb\Email;
  14. class Writer
  15. {
  16. /**
  17. * An instance of sb_Logger for logging the emails sent
  18. * @var sb_Logger
  19. */
  20. public $logger;
  21. /**
  22. * Determines if the body of the emails are logged in the log
  23. * @var boolean
  24. */
  25. public $log_body = true;
  26. /**
  27. * An instance of \sb\Email which describes the email being sent
  28. *
  29. * @var \sb\Email
  30. */
  31. protected $emails = Array();
  32. /**
  33. * The ip address of the sender
  34. * @var string
  35. */
  36. protected $remote_addr = '127.0.0.1';
  37. /**
  38. * The http host of the server sending the email, defaults to php_uname('n') if $_SERVER['HTTP_HOST'] is not set
  39. * @var string
  40. */
  41. protected $http_host = 'localhost';
  42. /**
  43. * Creates a new outbox to send from
  44. *
  45. * @param \sb\Logger $logger optional
  46. *
  47. * <code>
  48. * //instanciate the email writer
  49. * $myEmailWriter = new \sb\Email_Writer();
  50. *
  51. * //add an instance of \sb\Email to the outbox, you can add as many as you want
  52. * $myEmailWriter->addEmailToOutbox($myMail);
  53. *
  54. * //then send, you could add more emails before sending
  55. * var_dump($myEmailWriter->send());
  56. *
  57. * </code>
  58. */
  59. public function __construct($logger = null, $remote_addr = '', $http_host = '')
  60. {
  61. if ($logger instanceOf \sb\Logger\Base) {
  62. $this->logger = $logger;
  63. } elseif (isset(\App::$logger) && \App::$logger instanceof Logger_Base) {
  64. $this->logger = \App::$logger;
  65. } else {
  66. $this->logger = new \sb\Logger\FileSystem();
  67. }
  68. $this->remote_addr = (!empty($remote_addr)) ? $remote_addr :
  69. \sb\Gateway::$remote_addr;
  70. $this->http_host = (!empty($http_host)) ? $http_host :
  71. (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : php_uname('n'));
  72. }
  73. /**
  74. * Sends the emails in the $emails array that were attached using
  75. * addEmailToOutbox, logs progress if log file is specified
  76. *
  77. */
  78. public function send($email = 0)
  79. {
  80. if ($email instanceof Email) {
  81. $this->addEmailToOutbox($email);
  82. }
  83. $sent_emails = 0;
  84. foreach ($this->emails as &$email) {
  85. //all email goes to DEBUG_EMAIL if specified
  86. if (defined("DEBUG_EMAIL")) {
  87. $email->debug_info = "\n\nDEBUG MODE: Should be sent to: " . $email->to . " when not in debug mode!";
  88. $email->debug_info .= "\nDEBUG MODE: Should be sent from: " . $email->from . " when not in debug mode!";
  89. $email->to = \DEBUG_EMAIL;
  90. $email->from = \DEBUG_EMAIL;
  91. if (!empty($email->reply_to)) {
  92. $email->debug_info .= "\nDEBUG MODE: Should reply-to: "
  93. . $email->reply_to . " when not in debug mode!";
  94. $email->reply_to = \DEBUG_EMAIL;
  95. }
  96. if (!empty($email->cc)) {
  97. $email->debug_info .= "\nDEBUG MODE: Should be be CCed to: "
  98. . implode(", ", $email->cc) . " when not in debug mode!";
  99. $email->cc = Array();
  100. }
  101. if (!empty($email->bcc)) {
  102. $email->debug_info .= "\nDEBUG MODE: Should be be BCCed to: "
  103. . implode(", ", $email->bcc) . " when not in debug mode!";
  104. $email->bcc = Array();
  105. }
  106. $email->body .= $email->debug_info;
  107. if (!empty($email->body_HTML)) {
  108. $email->body_HTML .= nl2br($email->debug_info);
  109. }
  110. }
  111. $email->to = $email->to ? $email->to : null;
  112. $email->constructMultipartMessage();
  113. //sanitize sender params
  114. if($email->from && preg_match("~<(.*?)>~", $email->from, $match)){
  115. $sender = $match[1];
  116. } else {
  117. $sender = $email->from;
  118. }
  119. $sender = filter_var($sender, FILTER_SANITIZE_EMAIL);
  120. $params = sprintf('-f%s', escapeshellcmd($sender));
  121. if (mail($email->to, $email->subject, $email->body, $email->_header_text, $params)) {
  122. $email->sent = 1;
  123. $sent_emails++;
  124. $this->logEmail($email, true);
  125. } else {
  126. $this->logEmail($email, false);
  127. }
  128. }
  129. $emails_cnt = count($this->emails);
  130. $this->emails = Array();
  131. if ($sent_emails == $emails_cnt) {
  132. return true;
  133. } else {
  134. return false;
  135. }
  136. }
  137. /**
  138. * Adds an email to the outbox which is sent with the send method
  139. *
  140. * @param \sb\Email $email
  141. * @return boolean false if it has injectors, true if added to outbox
  142. */
  143. public function addEmailToOutbox(\sb\Email $email)
  144. {
  145. if ($this->checkHeadersForInjection($email)) {
  146. return 0;
  147. } else {
  148. $this->emails[] = $email;
  149. return true;
  150. }
  151. }
  152. /**
  153. * Logs the sending of emails if logging is enable by specifying the log_file property
  154. *
  155. * @param $email \sb\Email
  156. * @param $sent Boolean, was the email sent or not
  157. */
  158. private function logEmail($email, $sent)
  159. {
  160. $message = "\nEmail sent at " . date('m/d/y h:i:s');
  161. $message .= "\nFrom:" . $email->from . '@' . $this->remote_addr;
  162. $message .= "\nTo: " . $email->to;
  163. foreach ($email->cc as $cc) {
  164. $message .="\nCc:" . $cc;
  165. }
  166. foreach ($email->bcc as $bcc) {
  167. $message .="\nBcc:" . $bcc;
  168. }
  169. $message .= "\nSubject: " . $email->subject;
  170. $message .= "\nAttachments: " . count($email->attachments) . ' ';
  171. if ($this->log_body) {
  172. $message .= "\nBody: " . $email->body;
  173. $message .= "\nBody_HTML: " . $email->body_HTML;
  174. }
  175. $names = Array();
  176. foreach ($email->attachments as $attachment) {
  177. $names[] = $attachment->name;
  178. }
  179. $message .= "(" . \implode(",", $names) . ")";
  180. if ($sent) {
  181. return $this->logger->sbEmailWriterSent($message);
  182. } else {
  183. return $this->logger->sbEmailWriterError($message);
  184. }
  185. }
  186. /**
  187. * Checks email for injections in from and to addr
  188. *
  189. * @param \sb\Email $email
  190. * @return boolean
  191. */
  192. private function checkHeadersForInjection(\sb\Email $email)
  193. {
  194. if (($email->to && \preg_match("~\r|:~i", $email->to)) || ($email->from && preg_match("~\r|:~i", $email->from))) {
  195. return true;
  196. }
  197. return false;
  198. }
  199. }