PageRenderTime 49ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/protected/email.php

https://bitbucket.org/yoorick/fluxbb.pe
PHP | 601 lines | 348 code | 103 blank | 150 comment | 75 complexity | 9c1421678fd9d5d358a95adfb5e1a4c3 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * Based on code of FluxBB's include/email.php
  4. *
  5. * @copyright Copyright (C) 2011-2012 Yoory Nagumanov
  6. * @copyright Copyright (C) 2008-2012 FluxBB
  7. * @copyright based on code by Rickard Andersson copyright (C) 2002-2008 PunBB
  8. * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher
  9. */
  10. require_once Pe::get('root').'include/utf8/utils/ascii.php';
  11. /**
  12. * Wrapper for email functions.
  13. */
  14. class Email extends PeComponent
  15. {
  16. // Set by constructor
  17. protected
  18. /**
  19. * Boards configuration.
  20. * @var array
  21. * @access protected
  22. */
  23. $pun_config,
  24. /**
  25. * Common language strings.
  26. * @var array
  27. * @access protected
  28. */
  29. $lang_common;
  30. // Set by methods that serve subscriptions
  31. protected
  32. /**
  33. * Database adapter object.
  34. * @var \pe\dblayer\DBLayer
  35. * @access protected
  36. */
  37. $db,
  38. /**
  39. * Current user.
  40. * @var array
  41. * @access protected
  42. */
  43. $pun_user;
  44. /**
  45. * Validate an email address
  46. *
  47. * @param string $email
  48. * @return boolean
  49. * @access public
  50. * @static
  51. */
  52. public static function isValidEmail($email)
  53. {
  54. if (strlen($email) > 80)
  55. return false;
  56. return preg_match('/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|("[^"]+"))@((\[\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\])|(([a-zA-Z\d\-]+\.)+[a-zA-Z]{2,}))$/', $email);
  57. }
  58. /**
  59. * Check if $email is banned
  60. *
  61. * @param string $email
  62. * @return boolean
  63. * @access public
  64. */
  65. public function isBannedEmail($email)
  66. {
  67. $pun_bans = Pe::get('pun_bans');
  68. foreach ($pun_bans as $cur_ban)
  69. {
  70. if ($cur_ban['email'] != '' &&
  71. ($email == $cur_ban['email'] ||
  72. (strpos($cur_ban['email'], '@') === false && stristr($email, '@'.$cur_ban['email']))))
  73. return true;
  74. }
  75. return false;
  76. }
  77. /**
  78. * Encode mail text with base64.
  79. *
  80. * Only encode with base64, if there is at least one unicode character in the string
  81. *
  82. * @param string $str
  83. * @return string
  84. * @access private
  85. */
  86. private function _encodeMailText($str)
  87. {
  88. if (utf8_is_ascii($str))
  89. return $str;
  90. return '=?UTF-8?B?'.base64_encode($str).'?=';
  91. }
  92. /**
  93. * Wrapper for PHP's mail()
  94. *
  95. * @param string $to
  96. * @param string $subject
  97. * @param string $message
  98. * @param string $reply_to_email [optional]
  99. * @param string $reply_to_name [optional]
  100. * @access public
  101. */
  102. public function punMail($to, $subject, $message, $reply_to_email = '', $reply_to_name = '')
  103. {
  104. // Default sender/return address
  105. $from_name = str_replace('"', '', $this->pun_config['o_board_title']);
  106. $from_email = $this->pun_config['o_webmaster_email'];
  107. // Do a little spring cleaning
  108. $to = pun_trim(preg_replace('#[\n\r]+#s', '', $to));
  109. $subject = pun_trim(preg_replace('#[\n\r]+#s', '', $subject));
  110. $from_email = pun_trim(preg_replace('#[\n\r:]+#s', '', $from_email));
  111. $from_name = pun_trim(preg_replace('#[\n\r:]+#s', '', str_replace('"', '', $from_name)));
  112. $reply_to_email = pun_trim(preg_replace('#[\n\r:]+#s', '', $reply_to_email));
  113. $reply_to_name = pun_trim(preg_replace('#[\n\r:]+#s', '', str_replace('"', '', $reply_to_name)));
  114. // Set up some headers to take advantage of UTF-8
  115. $from = $this->_encodeMailText($from_name).' <'.$from_email.'>';
  116. $subject = $this->_encodeMailText($subject);
  117. $headers = 'From: '.$from."\r\n".'Date: '.gmdate('r')."\r\n".'MIME-Version: 1.0'."\r\n".'Content-transfer-encoding: 8bit'."\r\n".'Content-type: text/plain; charset=utf-8'."\r\n".'X-Mailer: FluxBB Mailer';
  118. // If we specified a reply-to email, we deal with it here
  119. if (!empty($reply_to_email))
  120. {
  121. $reply_to = $this->_encodeMailText($reply_to_name).' <'.$reply_to_email.'>';
  122. $headers .= "\r\n".'Reply-To: '.$reply_to;
  123. }
  124. // Make sure all linebreaks are CRLF in message (and strip out any NULL bytes)
  125. $message = str_replace(array("\n", "\0"), array("\r\n", ''), pun_linebreaks($message));
  126. if ($this->pun_config['o_smtp_host'] != '')
  127. $this->_smtpMail($to, $subject, $message, $headers);
  128. else
  129. {
  130. // Change the linebreaks used in the headers according to OS
  131. if (strtoupper(substr(PHP_OS, 0, 3)) == 'MAC')
  132. $headers = str_replace("\r\n", "\r", $headers);
  133. else if (strtoupper(substr(PHP_OS, 0, 3)) != 'WIN')
  134. $headers = str_replace("\r\n", "\n", $headers);
  135. mail($to, $subject, $message, $headers);
  136. }
  137. }
  138. /**
  139. * Parse server responce.
  140. *
  141. * If the socket returns unexpected responce throw an exception.
  142. *
  143. * This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
  144. * They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
  145. *
  146. * @param resource $socket
  147. * @param string $expected_response
  148. * @throws PeException
  149. * @access private
  150. */
  151. private function _serverParse($socket, $expected_response)
  152. {
  153. $server_response = '';
  154. while (substr($server_response, 3, 1) != ' ')
  155. {
  156. if (!($server_response = fgets($socket, 256)))
  157. throw new PeException('Couldn\'t get mail server response codes. Please contact the forum administrator.');
  158. }
  159. if (!(substr($server_response, 0, 3) == $expected_response))
  160. throw new PeException('Unable to send email. Please contact the forum administrator with the following error message reported by the SMTP server: "'.$server_response.'"');
  161. }
  162. /**
  163. * Send email via SMTP protocol.
  164. *
  165. * This function was originally a part of the phpBB Group forum software phpBB2 (http://www.phpbb.com).
  166. * They deserve all the credit for writing it. I made small modifications for it to suit PunBB and it's coding standards.
  167. *
  168. * @param string $to
  169. * @param string $subject
  170. * @param string $message
  171. * @param string $headers [optional]
  172. * @throws PeException
  173. * @access private
  174. */
  175. private function _smtpMail($to, $subject, $message, $headers = '')
  176. {
  177. $recipients = explode(',', $to);
  178. // Sanitize the message
  179. $message = str_replace("\r\n.", "\r\n..", $message);
  180. $message = (substr($message, 0, 1) == '.' ? '.'.$message : $message);
  181. // Are we using port 25 or a custom port?
  182. if (strpos($this->pun_config['o_smtp_host'], ':') !== false)
  183. list($smtp_host, $smtp_port) = explode(':', $this->pun_config['o_smtp_host']);
  184. else
  185. {
  186. $smtp_host = $this->pun_config['o_smtp_host'];
  187. $smtp_port = 25;
  188. }
  189. if ($this->pun_config['o_smtp_ssl'] == '1')
  190. $smtp_host = 'ssl://'.$smtp_host;
  191. if (!($socket = fsockopen($smtp_host, $smtp_port, $errno, $errstr, 15)))
  192. throw new PeException('Could not connect to smtp host "'.$this->pun_config['o_smtp_host'].'" ('.$errno.') ('.$errstr.')');
  193. $this->_serverParse($socket, '220');
  194. if ($this->pun_config['o_smtp_user'] != '' && $this->pun_config['o_smtp_pass'] != '')
  195. {
  196. fwrite($socket, 'EHLO '.$smtp_host."\r\n");
  197. $this->_serverParse($socket, '250');
  198. fwrite($socket, 'AUTH LOGIN'."\r\n");
  199. $this->_serverParse($socket, '334');
  200. fwrite($socket, base64_encode($this->pun_config['o_smtp_user'])."\r\n");
  201. $this->_serverParse($socket, '334');
  202. fwrite($socket, base64_encode($this->pun_config['o_smtp_pass'])."\r\n");
  203. $this->_serverParse($socket, '235');
  204. }
  205. else
  206. {
  207. fwrite($socket, 'HELO '.$smtp_host."\r\n");
  208. $this->_serverParse($socket, '250');
  209. }
  210. fwrite($socket, 'MAIL FROM: <'.$this->pun_config['o_webmaster_email'].'>'."\r\n");
  211. $this->_serverParse($socket, '250');
  212. foreach ($recipients as $email)
  213. {
  214. fwrite($socket, 'RCPT TO: <'.$email.'>'."\r\n");
  215. $this->_serverParse($socket, '250');
  216. }
  217. fwrite($socket, 'DATA'."\r\n");
  218. $this->_serverParse($socket, '354');
  219. fwrite($socket, 'Subject: '.$subject."\r\n".'To: <'.implode('>, <', $recipients).'>'."\r\n".$headers."\r\n\r\n".$message."\r\n");
  220. fwrite($socket, '.'."\r\n");
  221. $this->_serverParse($socket, '250');
  222. fwrite($socket, 'QUIT'."\r\n");
  223. fclose($socket);
  224. }
  225. /**
  226. * Send email messages about a new post to subscribers.
  227. *
  228. * @param int $tid
  229. * @param array $cur_posting
  230. * @param string $message
  231. * @param int $new_pid
  232. * @param string $username
  233. * @access public
  234. */
  235. public function mailNewPostSubscribers($tid, $cur_posting, $message, $new_pid, $username)
  236. {
  237. $this->db = Pe::get('db');
  238. $this->pun_user = Pe::get('pun_user');
  239. // Get the post time for the previous post in this topic
  240. $result = $this->db->query('SELECT posted FROM '.$this->db->prefix.'posts WHERE topic_id='.$tid.' ORDER BY id DESC LIMIT 1, 1');
  241. $previous_post_time = $this->db->result($result);
  242. $user_ids_sql[] = 'SELECT user_id FROM '.$this->db->prefix.'topic_subscriptions WHERE topic_id='.$tid.' AND send_email=1 AND user_id!='.$this->pun_user['id'];
  243. // Select IDs of board subscribers
  244. if ($this->pun_config['o_forum_subscriptions'] == '1')
  245. $user_ids_sql[] = 'SELECT user_id FROM '.$this->db->prefix.'forum_subscriptions WHERE forum_id='.$cur_posting['id'].' AND send_email=1 AND follow_replies=1 AND user_id!='.$this->pun_user['id'];
  246. // Select IDs of category subscribers
  247. if ($this->pun_config['o_category_subscriptions'] == '1')
  248. $user_ids_sql[] = 'SELECT user_id FROM '.$this->db->prefix.'category_subscriptions WHERE cat_id='.$cur_posting['cat_id'].' AND send_email=1 AND follow_replies=1 AND user_id!='.$this->pun_user['id'];
  249. // Get any subscribed users that should be notified (banned users are excluded)
  250. $result = $this->db->query('SELECT u.id, u.email, u.notify_with_post, u.language FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'forum_perms AS fp ON (fp.forum_id='.$cur_posting['id'].' AND fp.group_id=u.group_id) LEFT JOIN '.$this->db->prefix.'online AS o ON u.id=o.user_id LEFT JOIN '.$this->db->prefix.'bans AS b ON u.username=b.username WHERE b.username IS NULL AND COALESCE(o.logged, u.last_visit)>'.$previous_post_time.' AND (fp.read_forum IS NULL OR fp.read_forum=1) AND u.id IN ('.implode(' UNION ', $user_ids_sql).')');
  251. if ($this->db->num_rows($result))
  252. {
  253. $notification_emails = array();
  254. $subscribers = array();
  255. // Loop through subscribed users and send emails
  256. while ($cur_subscriber = $this->db->fetch_assoc($result))
  257. {
  258. // Is the subscription email for $cur_subscriber['language'] cached or not?
  259. if (!isset($notification_emails[$cur_subscriber['language']]))
  260. {
  261. if (file_exists(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply.tpl'))
  262. {
  263. // Load the "new reply" template
  264. $mail_tpl = trim(file_get_contents(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply.tpl'));
  265. // Load the "new reply full" template (with post included)
  266. $mail_tpl_full = trim(file_get_contents(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_reply_full.tpl'));
  267. // The first row contains the subject (it also starts with "Subject:")
  268. $first_crlf = strpos($mail_tpl, "\n");
  269. $mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
  270. $mail_message = trim(substr($mail_tpl, $first_crlf));
  271. $first_crlf = strpos($mail_tpl_full, "\n");
  272. $mail_subject_full = trim(substr($mail_tpl_full, 8, $first_crlf-8));
  273. $mail_message_full = trim(substr($mail_tpl_full, $first_crlf));
  274. $mail_subject = str_replace('<topic_subject>', $cur_posting['subject'], $mail_subject);
  275. $mail_message = str_replace('<topic_subject>', $cur_posting['subject'], $mail_message);
  276. $mail_message = str_replace('<replier>', $username, $mail_message);
  277. $mail_message = str_replace('<post_url>', Pe::get('urlUtils')->getBaseUrl().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid, $mail_message);
  278. $mail_message = str_replace('<unsubscribe_url>', Pe::get('urlUtils')->getBaseUrl().'/misc.php?action=unsubscribe&tid='.$tid, $mail_message);
  279. $mail_message = str_replace('<board_mailer>', sprintf($this->lang_common['Mailer'], $this->pun_config['o_board_title']), $mail_message);
  280. $mail_subject_full = str_replace('<topic_subject>', $cur_posting['subject'], $mail_subject_full);
  281. $mail_message_full = str_replace('<topic_subject>', $cur_posting['subject'], $mail_message_full);
  282. $mail_message_full = str_replace('<replier>', $username, $mail_message_full);
  283. $mail_message_full = str_replace('<message>', $message, $mail_message_full);
  284. $mail_message_full = str_replace('<post_url>', Pe::get('urlUtils')->getBaseUrl().'/viewtopic.php?pid='.$new_pid.'#p'.$new_pid, $mail_message_full);
  285. $mail_message_full = str_replace('<unsubscribe_url>', Pe::get('urlUtils')->getBaseUrl().'/misc.php?action=unsubscribe&tid='.$tid, $mail_message_full);
  286. $mail_message_full = str_replace('<board_mailer>', sprintf($this->lang_common['Mailer'], $this->pun_config['o_board_title']), $mail_message_full);
  287. $notification_emails[$cur_subscriber['language']][0] = $mail_subject;
  288. $notification_emails[$cur_subscriber['language']][1] = $mail_message;
  289. $notification_emails[$cur_subscriber['language']][2] = $mail_subject_full;
  290. $notification_emails[$cur_subscriber['language']][3] = $mail_message_full;
  291. $mail_subject = $mail_message = $mail_subject_full = $mail_message_full = null;
  292. }
  293. }
  294. // We have to double check here because the templates could be missing
  295. if (isset($notification_emails[$cur_subscriber['language']]))
  296. {
  297. if ($this->pun_config['o_use_email_pool'] == '0')
  298. {
  299. if ($cur_subscriber['notify_with_post'] == '0')
  300. $this->punMail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][0], $notification_emails[$cur_subscriber['language']][1]);
  301. else
  302. $this->punMail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][2], $notification_emails[$cur_subscriber['language']][3]);
  303. }
  304. else
  305. {
  306. $subscribers[$cur_subscriber['language']][$cur_subscriber['notify_with_post']][] = $cur_subscriber;
  307. }
  308. }
  309. }
  310. if ($this->pun_config['o_use_email_pool'] == '1' && !empty($subscribers))
  311. {
  312. foreach ($subscribers as $language => $cur_subscriber_set)
  313. {
  314. if (!empty($cur_subscriber_set[0]))
  315. {
  316. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_messages (mail_subject, mail_message) VALUES (\''.$this->db->escape($notification_emails[$language][0]).'\', \''.$this->db->escape($notification_emails[$language][1]).'\')');
  317. $msg_id = $this->db->insert_id();
  318. $values = array();
  319. foreach ($cur_subscriber_set[0] as $cur_subscriber)
  320. $values[] = '('.$cur_subscriber['id'].', '.$msg_id.', \''.$this->db->escape($cur_subscriber['email']).'\')';
  321. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_recipients (user_id, pool_msg_id, email) VALUES '.implode(', ', $values));
  322. }
  323. if (!empty($cur_subscriber_set[1]))
  324. {
  325. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_messages (mail_subject, mail_message) VALUES (\''.$this->db->escape($notification_emails[$language][2]).'\', \''.$this->db->escape($notification_emails[$language][3]).'\')');
  326. $msg_id = $this->db->insert_id();
  327. $values = array();
  328. foreach ($cur_subscriber_set[1] as $cur_subscriber)
  329. $values[] = '('.$cur_subscriber['id'].', '.$msg_id.', \''.$this->db->escape($cur_subscriber['email']).'\')';
  330. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_recipients (user_id, pool_msg_id, email) VALUES '.implode(', ', $values));
  331. }
  332. }
  333. }
  334. }
  335. }
  336. /**
  337. * Send email messages about a new topic to subscribers.
  338. *
  339. * @param array $cur_posting
  340. * @param string $subject
  341. * @param string $message
  342. * @param int $new_tid
  343. * @param string $username
  344. * @access public
  345. */
  346. public function mailNewTopicSubscribers($cur_posting, $subject, $message, $new_tid, $username)
  347. {
  348. $this->db = Pe::get('db');
  349. $this->pun_user = Pe::get('pun_user');
  350. $user_ids_sql = array();
  351. // Select IDs of board subscribers
  352. if ($this->pun_config['o_forum_subscriptions'] == '1')
  353. $user_ids_sql[] = 'SELECT user_id FROM '.$this->db->prefix.'forum_subscriptions WHERE forum_id='.$cur_posting['id'].' AND send_email=1 AND user_id!='.$this->pun_user['id'];
  354. // Select IDs of category subscribers
  355. if ($this->pun_config['o_category_subscriptions'] == '1')
  356. $user_ids_sql[] = 'SELECT user_id FROM '.$this->db->prefix.'category_subscriptions WHERE cat_id='.$cur_posting['cat_id'].' AND send_email=1 AND user_id!='.$this->pun_user['id'];
  357. if (empty($user_ids_sql))
  358. return;
  359. // Get any subscribed users that should be notified (banned users are excluded)
  360. $result = $this->db->query('SELECT u.id, u.email, u.notify_with_post, u.language FROM '.$this->db->prefix.'users AS u LEFT JOIN '.$this->db->prefix.'forum_perms AS fp ON (fp.forum_id='.$cur_posting['id'].' AND fp.group_id=u.group_id) LEFT JOIN '.$this->db->prefix.'bans AS b ON u.username=b.username WHERE b.username IS NULL AND (fp.read_forum IS NULL OR fp.read_forum=1) AND u.id IN ('.implode(' UNION ', $user_ids_sql).')');
  361. if ($this->db->num_rows($result))
  362. {
  363. $notification_emails = array();
  364. $subscribers = array();
  365. // Loop through subscribed users and send emails
  366. while ($cur_subscriber = $this->db->fetch_assoc($result))
  367. {
  368. // Is the subscription email for $cur_subscriber['language'] cached or not?
  369. if (!isset($notification_emails[$cur_subscriber['language']]))
  370. {
  371. if (file_exists(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_topic.tpl'))
  372. {
  373. // Load the "new topic" template
  374. $mail_tpl = trim(file_get_contents(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_topic.tpl'));
  375. // Load the "new topic full" template (with post included)
  376. $mail_tpl_full = trim(file_get_contents(Pe::get('root').'lang/'.$cur_subscriber['language'].'/mail_templates/new_topic_full.tpl'));
  377. // The first row contains the subject (it also starts with "Subject:")
  378. $first_crlf = strpos($mail_tpl, "\n");
  379. $mail_subject = trim(substr($mail_tpl, 8, $first_crlf-8));
  380. $mail_message = trim(substr($mail_tpl, $first_crlf));
  381. $first_crlf = strpos($mail_tpl_full, "\n");
  382. $mail_subject_full = trim(substr($mail_tpl_full, 8, $first_crlf-8));
  383. $mail_message_full = trim(substr($mail_tpl_full, $first_crlf));
  384. $mail_subject = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_subject);
  385. $mail_message = str_replace('<topic_subject>', $subject, $mail_message);
  386. $mail_message = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_message);
  387. $mail_message = str_replace('<poster>', $username, $mail_message);
  388. $mail_message = str_replace('<topic_url>', Pe::get('urlUtils')->getBaseUrl().'/viewtopic.php?id='.$new_tid, $mail_message);
  389. $mail_message = str_replace('<unsubscribe_url>', Pe::get('urlUtils')->getBaseUrl().'/misc.php?action=unsubscribe&fid='.$cur_posting['id'], $mail_message);
  390. $mail_message = str_replace('<board_mailer>', sprintf($this->lang_common['Mailer'], $this->pun_config['o_board_title']), $mail_message);
  391. $mail_subject_full = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_subject_full);
  392. $mail_message_full = str_replace('<topic_subject>', $subject, $mail_message_full);
  393. $mail_message_full = str_replace('<forum_name>', $cur_posting['forum_name'], $mail_message_full);
  394. $mail_message_full = str_replace('<poster>', $username, $mail_message_full);
  395. $mail_message_full = str_replace('<message>', $message, $mail_message_full);
  396. $mail_message_full = str_replace('<topic_url>', Pe::get('urlUtils')->getBaseUrl().'/viewtopic.php?id='.$new_tid, $mail_message_full);
  397. $mail_message_full = str_replace('<unsubscribe_url>', Pe::get('urlUtils')->getBaseUrl().'/misc.php?action=unsubscribe&fid='.$cur_posting['id'], $mail_message_full);
  398. $mail_message_full = str_replace('<board_mailer>', sprintf($this->lang_common['Mailer'], $this->pun_config['o_board_title']), $mail_message_full);
  399. $notification_emails[$cur_subscriber['language']][0] = $mail_subject;
  400. $notification_emails[$cur_subscriber['language']][1] = $mail_message;
  401. $notification_emails[$cur_subscriber['language']][2] = $mail_subject_full;
  402. $notification_emails[$cur_subscriber['language']][3] = $mail_message_full;
  403. $mail_subject = $mail_message = $mail_subject_full = $mail_message_full = null;
  404. }
  405. }
  406. // We have to double check here because the templates could be missing
  407. if (isset($notification_emails[$cur_subscriber['language']]))
  408. {
  409. if ($this->pun_config['o_use_email_pool'] == '0')
  410. {
  411. if ($cur_subscriber['notify_with_post'] == '0')
  412. $this->punMail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][0], $notification_emails[$cur_subscriber['language']][1]);
  413. else
  414. $this->punMail($cur_subscriber['email'], $notification_emails[$cur_subscriber['language']][2], $notification_emails[$cur_subscriber['language']][3]);
  415. }
  416. else
  417. {
  418. $subscribers[$cur_subscriber['language']][$cur_subscriber['notify_with_post']][] = $cur_subscriber;
  419. }
  420. }
  421. }
  422. if ($this->pun_config['o_use_email_pool'] == '1' && !empty($subscribers))
  423. {
  424. foreach ($subscribers as $language => $cur_subscriber_set)
  425. {
  426. if (!empty($cur_subscriber_set[0]))
  427. {
  428. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_messages (mail_subject, mail_message) VALUES (\''.$this->db->escape($notification_emails[$language][0]).'\', \''.$this->db->escape($notification_emails[$language][1]).'\')');
  429. $msg_id = $this->db->insert_id();
  430. $values = array();
  431. foreach ($cur_subscriber_set[0] as $cur_subscriber)
  432. $values[] = '('.$cur_subscriber['id'].', '.$msg_id.', \''.$this->db->escape($cur_subscriber['email']).'\')';
  433. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_recipients (user_id, pool_msg_id, email) VALUES '.implode(', ', $values));
  434. }
  435. if (!empty($cur_subscriber_set[1]))
  436. {
  437. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_messages (mail_subject, mail_message) VALUES (\''.$this->db->escape($notification_emails[$language][2]).'\', \''.$this->db->escape($notification_emails[$language][3]).'\')');
  438. $msg_id = $this->db->insert_id();
  439. $values = array();
  440. foreach ($cur_subscriber_set[1] as $cur_subscriber)
  441. $values[] = '('.$cur_subscriber['id'].', '.$msg_id.', \''.$this->db->escape($cur_subscriber['email']).'\')';
  442. $this->db->query('INSERT INTO '.$this->db->prefix.'email_pool_recipients (user_id, pool_msg_id, email) VALUES '.implode(', ', $values));
  443. }
  444. }
  445. }
  446. }
  447. }
  448. /**
  449. * Send a batch of emails from the email pool.
  450. *
  451. * @throws PeDbException
  452. */
  453. public function cronMail()
  454. {
  455. if ($this->pun_config['o_use_email_pool'] == '0')
  456. return;
  457. $this->db = Pe::get('db');
  458. $result = $this->db->query('SELECT user_id, pool_msg_id, email FROM '.$this->db->prefix.'email_pool_recipients ORDER BY pool_msg_id ASC LIMIT '.$this->pun_config['o_email_batch_size']);
  459. // Do we have anything to send?
  460. if (!$this->db->num_rows($result))
  461. return;
  462. $recipients = array();
  463. $msg_ids = array();
  464. while ($cur_recipient = $this->db->fetch_assoc($result))
  465. {
  466. $recipients[] = $cur_recipient;
  467. $msg_ids[] = $cur_recipient['pool_msg_id'];
  468. }
  469. $msg_ids = array_unique($msg_ids);
  470. $result = $this->db->query('SELECT id, mail_subject, mail_message FROM '.$this->db->prefix.'email_pool_messages WHERE id IN ('.implode(', ', $msg_ids).')');
  471. if (!$this->db->num_rows($result))
  472. throw new PeDbException('Database tables seem to be out of sync.');
  473. $messages = array();
  474. while ($cur_message = $this->db->fetch_assoc($result))
  475. $messages[$cur_message['id']] = $cur_message;
  476. $cur_msg_id = 0;
  477. $user_ids = array();
  478. foreach ($recipients as $cur_recipient)
  479. {
  480. if ($cur_msg_id != $cur_recipient['pool_msg_id'])
  481. {
  482. // Delete recipients from the database
  483. if (!empty($user_ids))
  484. $this->db->query('DELETE FROM '.$this->db->prefix.'email_pool_recipients WHERE pool_msg_id='.$cur_msg_id.' AND user_id IN ('.implode(', ', $user_ids).')');
  485. $cur_msg_id = $cur_recipient['pool_msg_id'];
  486. $user_ids = array();
  487. }
  488. $user_ids[] = $cur_recipient['user_id'];
  489. // Send message
  490. $this->punMail($cur_recipient['email'], $messages[$cur_recipient['pool_msg_id']]['mail_subject'], $messages[$cur_recipient['pool_msg_id']]['mail_message']);
  491. }
  492. // Delete recipients from the database
  493. if (!empty($user_ids))
  494. $this->db->query('DELETE FROM '.$this->db->prefix.'email_pool_recipients WHERE pool_msg_id='.$cur_msg_id.' AND user_id IN ('.implode(', ', $user_ids).')');
  495. // Delete messages from database
  496. $this->db->query('DELETE FROM '.$this->db->prefix.'email_pool_messages WHERE id NOT IN (SELECT DISTINCT pool_msg_id FROM '.$this->db->prefix.'email_pool_recipients)');
  497. }
  498. }