PageRenderTime 26ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/frontend/core/engine/mailer.php

http://github.com/forkcms/forkcms
PHP | 304 lines | 149 code | 51 blank | 104 comment | 27 complexity | ba7672bfab0cc1613829d1d9a34e4539 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of Fork CMS.
  4. *
  5. * For the full copyright and license information, please view the license
  6. * file that was distributed with this source code.
  7. */
  8. /**
  9. * This class will send mails
  10. *
  11. * @author Tijs Verkoyen <tijs@sumocoders.be>
  12. * @author Dieter Vanden Eynde <dieter@dieterve.be>
  13. * @author Sam Tubbax <sam@sumocoders.be>
  14. */
  15. class FrontendMailer
  16. {
  17. /**
  18. * Adds an email to the queue.
  19. *
  20. * @param string $subject The subject for the email.
  21. * @param string $template The template to use.
  22. * @param array[optional] $variables Variables that should be assigned in the email.
  23. * @param string[optional] $toEmail The to-address for the email.
  24. * @param string[optional] $toName The to-name for the email.
  25. * @param string[optional] $fromEmail The from-address for the mail.
  26. * @param string[optional] $fromName The from-name for the mail.
  27. * @param string[optional] $replyToEmail The replyto-address for the mail.
  28. * @param string[optional] $replyToName The replyto-name for the mail.
  29. * @param bool[optional] $queue Should the mail be queued?
  30. * @param int[optional] $sendOn When should the email be send, only used when $queue is true.
  31. * @param bool[optional] $isRawHTML If this is true $template will be handled as raw HTML, so no parsing of $variables is done.
  32. * @param string[optional] $plainText The plain text version.
  33. * @param array[optional] $attachments Paths to attachments to include.
  34. * @return int
  35. */
  36. public static function addEmail($subject, $template, array $variables = null, $toEmail = null, $toName = null, $fromEmail = null, $fromName = null, $replyToEmail = null, $replyToName = null, $queue = false, $sendOn = null, $isRawHTML = false, $plainText = null, array $attachments = null)
  37. {
  38. $subject = (string) strip_tags($subject);
  39. $template = (string) $template;
  40. // set defaults
  41. $to = FrontendModel::getModuleSetting('core', 'mailer_to');
  42. $from = FrontendModel::getModuleSetting('core', 'mailer_from');
  43. $replyTo = FrontendModel::getModuleSetting('core', 'mailer_reply_to');
  44. $utm = array('utm_source' => 'mail', 'utm_medium' => 'email', 'utm_campaign' => SpoonFilter::urlise($subject));
  45. // set recipient/sender headers
  46. $email['to_email'] = ($toEmail === null) ? (string) $to['email'] : $toEmail;
  47. $email['to_name'] = ($toName === null) ? (string) $to['name'] : $toName;
  48. $email['from_email'] = ($fromEmail === null) ? (string) $from['email'] : $fromEmail;
  49. $email['from_name'] = ($fromName === null) ? (string) $from['name'] : $fromName;
  50. $email['reply_to_email'] = ($replyToEmail === null) ? (string) $replyTo['email'] : $replyToEmail;
  51. $email['reply_to_name'] = ($replyToName === null) ? (string) $replyTo['name'] : $replyToName;
  52. // validate
  53. if(!SpoonFilter::isEmail($email['to_email'])) throw new FrontendException('Invalid e-mail address for recipient.');
  54. if(!SpoonFilter::isEmail($email['from_email'])) throw new FrontendException('Invalid e-mail address for sender.');
  55. if(!SpoonFilter::isEmail($email['reply_to_email'])) throw new FrontendException('Invalid e-mail address for reply-to address.');
  56. // build array
  57. $email['subject'] = SpoonFilter::htmlentitiesDecode($subject);
  58. if($isRawHTML) $email['html'] = $template;
  59. else $email['html'] = self::getTemplateContent($template, $variables);
  60. if($plainText !== null) $email['plain_text'] = $plainText;
  61. $email['created_on'] = FrontendModel::getUTCDate();
  62. // init var
  63. $matches = array();
  64. // get internal links
  65. preg_match_all('|href="/(.*)"|i', $email['html'], $matches);
  66. // any links?
  67. if(!empty($matches[0]))
  68. {
  69. // init vars
  70. $search = array();
  71. $replace = array();
  72. // loop the links
  73. foreach($matches[0] as $key => $link)
  74. {
  75. $search[] = $link;
  76. $replace[] = 'href="' . SITE_URL . '/' . $matches[1][$key] . '"';
  77. }
  78. // replace
  79. $email['html'] = str_replace($search, $replace, $email['html']);
  80. }
  81. // init var
  82. $matches = array();
  83. // get internal urls
  84. preg_match_all('|src="/(.*)"|i', $email['html'], $matches);
  85. // any links?
  86. if(!empty($matches[0]))
  87. {
  88. // init vars
  89. $search = array();
  90. $replace = array();
  91. // loop the links
  92. foreach($matches[0] as $key => $link)
  93. {
  94. $search[] = $link;
  95. $replace[] = 'src="' . SITE_URL . '/' . $matches[1][$key] . '"';
  96. }
  97. // replace
  98. $email['html'] = str_replace($search, $replace, $email['html']);
  99. }
  100. // init var
  101. $matches = array();
  102. // match links
  103. preg_match_all('/href="(http:\/\/(.*))"/iU', $email['html'], $matches);
  104. // any links?
  105. if(isset($matches[0]) && !empty($matches[0]))
  106. {
  107. // init vars
  108. $searchLinks = array();
  109. $replaceLinks = array();
  110. // loop old links
  111. foreach($matches[1] as $i => $link)
  112. {
  113. $searchLinks[] = $matches[0][$i];
  114. $replaceLinks[] = 'href="' . FrontendModel::addURLParameters($link, $utm) . '"';
  115. }
  116. // replace
  117. $email['html'] = str_replace($searchLinks, $replaceLinks, $email['html']);
  118. }
  119. // attachments added
  120. if(!empty($attachments))
  121. {
  122. // add attachments one by one
  123. foreach($attachments as $attachment)
  124. {
  125. // only add existing files
  126. if(SpoonFile::exists($attachment)) $email['attachments'][] = $attachment;
  127. }
  128. // serialize :)
  129. if(!empty($email['attachments'])) $email['attachments'] = serialize($email['attachments']);
  130. }
  131. // set send date
  132. if($queue)
  133. {
  134. if($sendOn === null) $email['send_on'] = FrontendModel::getUTCDate('Y-m-d H') . ':00:00';
  135. else $email['send_on'] = FrontendModel::getUTCDate('Y-m-d H:i:s', (int) $sendOn);
  136. }
  137. // insert the email into the database
  138. $id = FrontendModel::getDB(true)->insert('emails', $email);
  139. // trigger event
  140. FrontendModel::triggerEvent('core', 'after_email_queued', array('id' => $id));
  141. // if queue was not enabled, send this mail right away
  142. if(!$queue) self::send($id);
  143. // return
  144. return $id;
  145. }
  146. /**
  147. * Get all queued mail ids
  148. *
  149. * @return array
  150. */
  151. public static function getQueuedMailIds()
  152. {
  153. return (array) FrontendModel::getDB()->getColumn(
  154. 'SELECT e.id
  155. FROM emails AS e
  156. WHERE e.send_on < ?',
  157. array(FrontendModel::getUTCDate())
  158. );
  159. }
  160. /**
  161. * Returns the content from a given template
  162. *
  163. * @param string $template The template to use.
  164. * @param array[optional] $variables The variabled to assign.
  165. * @return string
  166. */
  167. private static function getTemplateContent($template, $variables = null)
  168. {
  169. // new template instance
  170. $tpl = new FrontendTemplate(false);
  171. // set some options
  172. $tpl->setForceCompile(true);
  173. // variables were set
  174. if(!empty($variables)) $tpl->assign($variables);
  175. // grab the content
  176. $content = $tpl->getContent($template);
  177. // replace internal links/images
  178. $search = array('href="/', 'src="/');
  179. $replace = array('href="' . SITE_URL . '/', 'src="' . SITE_URL . '/');
  180. $content = str_replace($search, $replace, $content);
  181. // require CSSToInlineStyles
  182. require_once 'external/css_to_inline_styles.php';
  183. // create instance
  184. $cssToInlineStyles = new CSSToInlineStyles();
  185. // set some properties
  186. $cssToInlineStyles->setHTML($content);
  187. $cssToInlineStyles->setUseInlineStylesBlock(true);
  188. $cssToInlineStyles->setEncoding(SPOON_CHARSET);
  189. // return the content
  190. return (string) $cssToInlineStyles->convert();
  191. }
  192. /**
  193. * Send an email
  194. *
  195. * @param int $id The id of the mail to send.
  196. */
  197. public static function send($id)
  198. {
  199. $id = (int) $id;
  200. // get db
  201. $db = FrontendModel::getDB(true);
  202. // get record
  203. $emailRecord = (array) $db->getRecord(
  204. 'SELECT *
  205. FROM emails AS e
  206. WHERE e.id = ?',
  207. array($id)
  208. );
  209. // mailer type
  210. $mailerType = FrontendModel::getModuleSetting('core', 'mailer_type', 'mail');
  211. // create new SpoonEmail-instance
  212. $email = new SpoonEmail();
  213. $email->setTemplateCompileDirectory(FRONTEND_CACHE_PATH . '/compiled_templates');
  214. // send via SMTP
  215. if($mailerType == 'smtp')
  216. {
  217. // get settings
  218. $SMTPServer = FrontendModel::getModuleSetting('core', 'smtp_server');
  219. $SMTPPort = FrontendModel::getModuleSetting('core', 'smtp_port', 25);
  220. $SMTPUsername = FrontendModel::getModuleSetting('core', 'smtp_username');
  221. $SMTPPassword = FrontendModel::getModuleSetting('core', 'smtp_password');
  222. // set server and connect with SMTP
  223. $email->setSMTPConnection($SMTPServer, $SMTPPort, 10);
  224. // set authentication if needed
  225. if($SMTPUsername !== null && $SMTPPassword !== null) $email->setSMTPAuth($SMTPUsername, $SMTPPassword);
  226. }
  227. // set some properties
  228. $email->setFrom($emailRecord['from_email'], $emailRecord['from_name']);
  229. $email->addRecipient($emailRecord['to_email'], $emailRecord['to_name']);
  230. $email->setReplyTo($emailRecord['reply_to_email']);
  231. $email->setSubject($emailRecord['subject']);
  232. $email->setHTMLContent($emailRecord['html']);
  233. $email->setCharset(SPOON_CHARSET);
  234. $email->setContentTransferEncoding('base64');
  235. if($emailRecord['plain_text'] != '') $email->setPlainContent($emailRecord['plain_text']);
  236. // attachments added
  237. if(isset($emailRecord['attachments']) && $emailRecord['attachments'] !== null)
  238. {
  239. // unserialize
  240. $attachments = (array) unserialize($emailRecord['attachments']);
  241. // add attachments to email
  242. foreach($attachments as $attachment) $email->addAttachment($attachment);
  243. }
  244. // send the email
  245. if($email->send())
  246. {
  247. // remove the email
  248. $db->delete('emails', 'id = ?', array($id));
  249. // trigger event
  250. FrontendModel::triggerEvent('core', 'after_email_sent', array('id' => $id));
  251. }
  252. }
  253. }