function format_address($address) { foreach ($address as $array) { $array['name'] = trim($array['name']); $formatted[] = $array['name'] && $this->named_addresses ? '"' . mail_encode($array['name'], $this->encoding) . '" <' . $array['address'] . '>' : $array['address']; } return implode(', ', $formatted); }
/** * Process queue * Using lock file */ function process() { global $db, $config, $phpEx, $phpbb_root_path, $user; set_config('last_queue_run', time(), true); // Delete stale lock file if (file_exists($this->cache_file . '.lock') && !file_exists($this->cache_file)) { @unlink($this->cache_file . '.lock'); return; } if (!file_exists($this->cache_file) || file_exists($this->cache_file . '.lock') && filemtime($this->cache_file) > time() - $config['queue_interval']) { return; } $fp = @fopen($this->cache_file . '.lock', 'wb'); fclose($fp); @chmod($this->cache_file . '.lock', 0777); include $this->cache_file; foreach ($this->queue_data as $object => $data_ary) { @set_time_limit(0); if (!isset($data_ary['package_size'])) { $data_ary['package_size'] = 0; } $package_size = $data_ary['package_size']; $num_items = !$package_size || sizeof($data_ary['data']) < $package_size ? sizeof($data_ary['data']) : $package_size; // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs... if (sizeof($data_ary['data']) > $package_size * 2.5) { $num_items = sizeof($data_ary['data']); } switch ($object) { case 'email': // Delete the email queued objects if mailing is disabled if (!$config['email_enable']) { unset($this->queue_data['email']); continue 2; } break; case 'jabber': if (!$config['jab_enable']) { unset($this->queue_data['jabber']); continue 2; } include_once $phpbb_root_path . 'includes/functions_jabber.' . $phpEx; $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], $config['jab_password'], $config['jab_use_ssl']); if (!$this->jabber->connect()) { messenger::error('JABBER', $user->lang['ERR_JAB_CONNECT']); continue 2; } if (!$this->jabber->login()) { messenger::error('JABBER', $user->lang['ERR_JAB_AUTH']); continue 2; } break; default: return; } for ($i = 0; $i < $num_items; $i++) { // Make variables available... extract(array_shift($this->queue_data[$object]['data'])); switch ($object) { case 'email': $err_msg = ''; $to = !$to ? 'undisclosed-recipients:;' : $to; if ($config['smtp_delivery']) { $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers); } else { ob_start(); $result = $config['email_function_name']($to, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $headers); $err_msg = ob_get_clean(); } if (!$result) { @unlink($this->cache_file . '.lock'); messenger::error('EMAIL', $err_msg); continue 2; } break; case 'jabber': foreach ($addresses as $address) { if ($this->jabber->send_message($address, $msg, $subject) === false) { messenger::error('JABBER', $this->jabber->get_log()); continue 3; } } break; } } // No more data for this object? Unset it if (!sizeof($this->queue_data[$object]['data'])) { unset($this->queue_data[$object]); } // Post-object processing switch ($object) { case 'jabber': // Hang about a couple of secs to ensure the messages are // handled, then disconnect $this->jabber->disconnect(); break; } } if (!sizeof($this->queue_data)) { @unlink($this->cache_file); } else { if ($fp = @fopen($this->cache_file, 'wb')) { @flock($fp, LOCK_EX); fwrite($fp, "<?php\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); @flock($fp, LOCK_UN); fclose($fp); phpbb_chmod($this->cache_file, CHMOD_WRITE); } } @unlink($this->cache_file . '.lock'); }
/** * @brief Create an array representing the important channel information * which would be necessary to create a nomadic identity clone. This includes * most channel resources and connection information with the exception of content. * * @param int $channel_id * Channel_id to export * @param boolean $items * Include channel posts (wall items), default false * * @returns array * See function for details */ function identity_basic_export($channel_id, $items = false) { /* * Red basic channel export */ $ret = array(); $ret['compatibility'] = array('project' => PLATFORM_NAME, 'version' => RED_VERSION, 'database' => DB_UPDATE_VERSION); $r = q("select * from channel where channel_id = %d limit 1", intval($channel_id)); if ($r) { $ret['channel'] = $r[0]; } $r = q("select * from profile where uid = %d", intval($channel_id)); if ($r) { $ret['profile'] = $r; } $xchans = array(); $r = q("select * from abook where abook_channel = %d ", intval($channel_id)); if ($r) { $ret['abook'] = $r; foreach ($r as $rr) { $xchans[] = $rr['abook_xchan']; } stringify_array_elms($xchans); } if ($xchans) { $r = q("select * from xchan where xchan_hash in ( " . implode(',', $xchans) . " ) "); if ($r) { $ret['xchan'] = $r; } $r = q("select * from hubloc where hubloc_hash in ( " . implode(',', $xchans) . " ) "); if ($r) { $ret['hubloc'] = $r; } } $r = q("select * from `groups` where uid = %d ", intval($channel_id)); if ($r) { $ret['group'] = $r; } $r = q("select * from group_member where uid = %d ", intval($channel_id)); if ($r) { $ret['group_member'] = $r; } $r = q("select * from pconfig where uid = %d", intval($channel_id)); if ($r) { $ret['config'] = $r; } $r = q("select type, data, os_storage from photo where scale = 4 and profile = 1 and uid = %d limit 1", intval($channel_id)); if ($r) { $ret['photo'] = array('type' => $r[0]['type'], 'data' => $r[0]['os_storage'] ? base64url_encode(file_get_contents($r[0]['data'])) : base64url_encode($r[0]['data'])); } // All other term types will be included in items, if requested. $r = q("select * from term where type in (%d,%d) and uid = %d", intval(TERM_SAVEDSEARCH), intval(TERM_THING), intval($channel_id)); if ($r) { $ret['term'] = $r; } // add psuedo-column obj_baseurl to aid in relocations $r = q("select obj.*, '%s' as obj_baseurl from obj where obj_channel = %d", dbesc(z_root()), intval($channel_id)); if ($r) { $ret['obj'] = $r; } $r = q("select * from app where app_channel = %d", intval($channel_id)); if ($r) { $ret['app'] = $r; } $r = q("select * from chatroom where cr_uid = %d", intval($channel_id)); if ($r) { $ret['chatroom'] = $r; } $r = q("select * from event where uid = %d", intval($channel_id)); if ($r) { $ret['event'] = $r; } $r = q("select * from item where resource_type = 'event' and uid = %d", intval($channel_id)); if ($r) { $ret['event_item'] = array(); xchan_query($r); $r = fetch_post_tags($r, true); foreach ($r as $rr) { $ret['event_item'][] = encode_item($rr, true); } } $x = menu_list($channel_id); if ($x) { $ret['menu'] = array(); for ($y = 0; $y < count($x); $y++) { $m = menu_fetch($x[$y]['menu_name'], $channel_id, $ret['channel']['channel_hash']); if ($m) { $ret['menu'][] = menu_element($m); } } } $x = menu_list($channel_id); if ($x) { $ret['menu'] = array(); for ($y = 0; $y < count($x); $y++) { $m = menu_fetch($x[$y]['menu_name'], $channel_id, $ret['channel']['channel_hash']); if ($m) { $ret['menu'][] = menu_element($m); } } } $addon = array('channel_id' => $channel_id, 'data' => $ret); call_hooks('identity_basic_export', $addon); $ret = $addon['data']; if (!$items) { return $ret; } $r = q("select * from likes where channel_id = %d", intval($channel_id)); if ($r) { $ret['likes'] = $r; } $r = q("select * from conv where uid = %d", intval($channel_id)); if ($r) { for ($x = 0; $x < count($r); $x++) { $r[$x]['subject'] = base64url_decode(str_rot47($r[$x]['subject'])); } $ret['conv'] = $r; } $r = q("select * from mail where mail.uid = %d", intval($channel_id)); if ($r) { $m = array(); foreach ($r as $rr) { xchan_mail_query($rr); $m[] = mail_encode($rr, true); } $ret['mail'] = $m; } $r = q("select item_id.*, item.mid from item_id left join item on item_id.iid = item.id where item_id.uid = %d", intval($channel_id)); if ($r) { $ret['item_id'] = $r; } //$key = get_config('system','prvkey'); /** @warning this may run into memory limits on smaller systems */ /** export three months of posts. If you want to export and import all posts you have to start with * the first year and export/import them in ascending order. * * Don't export linked resource items. we'll have to pull those out separately. */ $r = q("select * from item where item_wall = 1 and item_deleted = 0 and uid = %d and created > %s - INTERVAL %s and resource_type = '' order by created", intval($channel_id), db_utcnow(), db_quoteinterval('3 MONTH')); if ($r) { $ret['item'] = array(); xchan_query($r); $r = fetch_post_tags($r, true); foreach ($r as $rr) { $ret['item'][] = encode_item($rr, true); } } return $ret; }
/** * Process queue * Using lock file */ function process() { global $db, $config, $phpEx, $phpbb_root_path, $user; $lock = new \phpbb\lock\flock($this->cache_file); $lock->acquire(); // avoid races, check file existence once $have_cache_file = file_exists($this->cache_file); if (!$have_cache_file || $config['last_queue_run'] > time() - $config['queue_interval']) { if (!$have_cache_file) { set_config('last_queue_run', time(), true); } $lock->release(); return; } set_config('last_queue_run', time(), true); include $this->cache_file; foreach ($this->queue_data as $object => $data_ary) { @set_time_limit(0); if (!isset($data_ary['package_size'])) { $data_ary['package_size'] = 0; } $package_size = $data_ary['package_size']; $num_items = !$package_size || sizeof($data_ary['data']) < $package_size ? sizeof($data_ary['data']) : $package_size; /* * This code is commented out because it causes problems on some web hosts. * The core problem is rather restrictive email sending limits. * This code is nly useful if you have no such restrictions from the * web host and the package size setting is wrong. // If the amount of emails to be sent is way more than package_size than we need to increase it to prevent backlogs... if (sizeof($data_ary['data']) > $package_size * 2.5) { $num_items = sizeof($data_ary['data']); } */ switch ($object) { case 'email': // Delete the email queued objects if mailing is disabled if (!$config['email_enable']) { unset($this->queue_data['email']); continue 2; } break; case 'jabber': if (!$config['jab_enable']) { unset($this->queue_data['jabber']); continue 2; } include_once $phpbb_root_path . 'includes/functions_jabber.' . $phpEx; $this->jabber = new jabber($config['jab_host'], $config['jab_port'], $config['jab_username'], htmlspecialchars_decode($config['jab_password']), $config['jab_use_ssl']); if (!$this->jabber->connect()) { $messenger = new messenger(); $messenger->error('JABBER', $user->lang['ERR_JAB_CONNECT']); continue 2; } if (!$this->jabber->login()) { $messenger = new messenger(); $messenger->error('JABBER', $user->lang['ERR_JAB_AUTH']); continue 2; } break; default: $lock->release(); return; } for ($i = 0; $i < $num_items; $i++) { // Make variables available... extract(array_shift($this->queue_data[$object]['data'])); switch ($object) { case 'email': $err_msg = ''; $to = !$to ? 'undisclosed-recipients:;' : $to; if ($config['smtp_delivery']) { $result = smtpmail($addresses, mail_encode($subject), wordwrap(utf8_wordwrap($msg), 997, "\n", true), $err_msg, $headers); } else { $result = phpbb_mail($to, $subject, $msg, $headers, $this->eol, $err_msg); } if (!$result) { $messenger = new messenger(); $messenger->error('EMAIL', $err_msg); continue 2; } break; case 'jabber': foreach ($addresses as $address) { if ($this->jabber->send_message($address, $msg, $subject) === false) { $messenger = new messenger(); $messenger->error('JABBER', $this->jabber->get_log()); continue 3; } } break; } } // No more data for this object? Unset it if (!sizeof($this->queue_data[$object]['data'])) { unset($this->queue_data[$object]); } // Post-object processing switch ($object) { case 'jabber': // Hang about a couple of secs to ensure the messages are // handled, then disconnect $this->jabber->disconnect(); break; } } if (!sizeof($this->queue_data)) { @unlink($this->cache_file); } else { if ($fp = @fopen($this->cache_file, 'wb')) { fwrite($fp, "<?php\nif (!defined('IN_PHPBB')) exit;\n\$this->queue_data = unserialize(" . var_export(serialize($this->queue_data), true) . ");\n\n?>"); fclose($fp); phpbb_chmod($this->cache_file, CHMOD_READ | CHMOD_WRITE); } } $lock->release(); }
/** * Отправить HTML письмо * * @param string $to Кому * @param string $from От кого * @param string $message Письмо * @param string $subject Тема письма */ function mail_send($to, $from = '*****@*****.**', $message = '', $subject = '', $from_user = '') { // Обработаем кирилицу в поле: От кого $from_user = mail_encode($from_user, 'UTF-8'); // Обработаем кирилицу в поле: Тема письма $subject = mail_encode($subject, 'UTF-8'); // Uniqid Session $session = md5(uniqid(time())); // Установим необходимые заголовки $headers = 'MIME-Version: 1.0' . "\r\n"; $headers .= 'Content-type: text/html; charset="UTF-8"' . "\r\n"; //"Content-Type: multipart/mixed; boundary=\"".$strSid."\"\n\n"; //$strHeader .= "This is a multi-part message in MIME format.\n"; $headers .= 'From: ' . $from_user . '<' . $from . '>' . "\r\n"; // Добавим в сообщение HTML тэги $message = '<html><head><meta charset="utf-8"></head><body>' . $message . '</body></html>'; // Если письмо отправленно вернем 1 return mail($to, $subject, $message, $headers); }
function format_address($address, $header = false) { if ($header) { return $address['name'] && $this->named_addresses ? '"' . mail_encode($address['name'], $this->encoding) . '" <' . $address['address'] . '>' : $address['address']; } //return ($address['name'] && $this->named_addresses) ? '<' . $address['address'] . '> '.$address['name'] : '<' . $address['address'] . '>'; return '<' . $address['address'] . '>'; }
/** * Send out emails */ function msg_email($is_html = false) { global $config; if (empty($config['email_enable'])) { return false; } // Addresses to send to? if (empty($this->addresses) || empty($this->addresses['to']) && empty($this->addresses['cc']) && empty($this->addresses['bcc'])) { // Send was successful. ;) return true; } $contact_name = htmlspecialchars_decode($config['board_contact_name']); $board_contact = ($contact_name !== '' ? '"' . mail_encode($contact_name) . '" ' : '') . '<' . $config['board_contact'] . '>'; if (empty($this->replyto)) { $this->replyto = $board_contact; } if (empty($this->from)) { $this->from = $board_contact; } $encode_eol = $config['smtp_delivery'] ? "\r\n" : $this->eol; // Build to, cc and bcc strings $to = $cc = $bcc = ''; foreach ($this->addresses as $type => $address_ary) { if ($type == 'im') { continue; } foreach ($address_ary as $which_ary) { ${$type} .= (${$type} != '' ? ', ' : '') . ($which_ary['name'] != '' ? mail_encode($which_ary['name'], $encode_eol) . ' <' . $which_ary['email'] . '>' : $which_ary['email']); } } // Build header $headers = $this->build_header($to, $cc, $bcc, $is_html); // Send message ... $mail_to = $to == '' ? 'undisclosed-recipients:;' : $to; $err_msg = ''; if ($config['smtp_delivery']) { $result = smtpmail($this->addresses, mail_encode($this->subject), wordwrap(utf8_wordwrap($this->msg), 997, "\n", true), $err_msg, $headers); } else { $result = phpbb_mail($mail_to, $this->subject, $this->msg, $headers, $this->eol, $err_msg); } if (!$result) { $this->error('EMAIL', $err_msg); return false; } return true; }
private function mail_digests($now, $hour) { ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // // This method is what used to be mail_digests.php. It will mail all the digests for the given year, date and hour // // offset by the $hour parameter. // // // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// static $daily_digest_sql, $weekly_digest_sql; $run_successful = true; // Assume a successful run // If it was requested, get the year, month, date and hour of the digests to recreate. If it was not requested, simply use the current time. Note: // these cannot be acquired as URL key/value pairs anymore like in the mod. If used it must be as a result of a manual run of the mailer. if ($this->manual_mode && $this->config['phpbbservices_digests_test_time_use']) { $this->time = mktime($this->config['phpbbservices_digests_test_hour'], 0, 0, $this->config['phpbbservices_digests_test_month'], $this->config['phpbbservices_digests_test_day'], $this->config['phpbbservices_digests_test_year']); $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_SIMULATION_DATE_TIME', false, array(str_pad($this->config['phpbbservices_digests_test_year'], 2, '0', STR_PAD_LEFT) . '-' . str_pad($this->config['phpbbservices_digests_test_month'], 2, '0', STR_PAD_LEFT) . '-' . str_pad($this->config['phpbbservices_digests_test_day'], 2, '0', STR_PAD_LEFT), $this->config['phpbbservices_digests_test_hour'])); } else { $this->time = $now + $hour * (60 * 60); } $this->gmt_time = $this->time - (int) ($this->server_timezone * 60 * 60); // Convert server time (or requested run date) into GMT time // Get the current hour in GMT, so applicable digests can be sent out for this hour $current_hour_gmt = date('G', $this->gmt_time); // 0 thru 23 $current_hour_gmt_plus_30 = date('G', $this->gmt_time) + 0.5; if ($current_hour_gmt_plus_30 >= 24) { $current_hour_gmt_plus_30 = $current_hour_gmt_plus_30 - 24; // A very unlikely situation } // Create SQL fragment to fetch users wanting a daily digest if (!isset($daily_digest_sql)) { $daily_digest_sql = '(' . $this->db->sql_in_set('user_digest_type', array(constants::DIGESTS_DAILY_VALUE)) . ')'; } // Create SQL fragment to also fetch users wanting a weekly digest, if today is the day weekly digests should go out if (!isset($weekly_digest_sql)) { $weekly_digest_sql = date('w', $this->gmt_time) == $this->config['phpbbservices_digests_weekly_digest_day'] ? ' OR (' . $this->db->sql_in_set('user_digest_type', array(constants::DIGESTS_WEEKLY_VALUE)) . ')' : ''; } // Create SQL fragment to also fetch users wanting a monthly digest. This only happens if the current GMT day is the first of the month. $gmt_year = (int) date('Y', $this->gmt_time); $gmt_month = (int) date('n', $this->gmt_time); $gmt_day = (int) date('j', $this->gmt_time); $gmt_hour = (int) date('G', $this->gmt_time); if ($gmt_day == 1) { if ($gmt_month == 1) { $gmt_month = 12; $gmt_year--; } else { $gmt_month--; // Otherwise monthly digests are run for the previous month for the year } // Create a Unix timestamp that represents a time range for monthly digests, based on the current hour $gmt_month_last_day = date('t', mktime(0, 0, 0, $gmt_month, $gmt_day, $gmt_year)); $gmt_month_1st_begin = mktime(0, 0, 0, $gmt_month, $gmt_day, $gmt_year); $this->gmt_month_lastday_end = mktime(23, 59, 59, $gmt_month, $gmt_month_last_day, $gmt_year); $monthly_digest_sql = ' OR (' . $this->db->sql_in_set('user_digest_type', array(constants::DIGESTS_MONTHLY_VALUE)) . ')'; } else { $monthly_digest_sql = ''; $gmt_month_1st_begin = 0; // Make PhpStorm happy } $formatted_date = date('Y-m-d H', $this->gmt_time); $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_HOUR_RUN', false, array($formatted_date)); // We need to know which auth_option_id corresponds to the forum read privilege (f_read) and forum list (f_list) privilege. Why not use $this->auth->acl_get? // Because this program must get permissions for different users, so forum authentication will need to be done outside of the regular authentication // mechanism. $auth_options = array('f_read', 'f_list'); $sql = 'SELECT auth_option, auth_option_id FROM ' . ACL_OPTIONS_TABLE . ' WHERE ' . $this->db->sql_in_set('auth_option', $auth_options); $result = $this->db->sql_query($sql); while ($row = $this->db->sql_fetchrow($result)) { if ($row['auth_option'] == 'f_read') { $this->read_id = $row['auth_option_id']; } if ($row['auth_option'] == 'f_list') { $this->list_id = $row['auth_option_id']; } } $this->db->sql_freeresult($result); // Query be gone! // Get users requesting digests for the current hour. Also, grab the user's style, so the digest will have a familiar look. if ($this->config['override_user_style']) { $sql_array = array('SELECT' => 'u.*, s.*', 'FROM' => array(USERS_TABLE => 'u', STYLES_TABLE => 's'), 'WHERE' => 's.style_id = ' . $this->config['default_style'] . ' AND (' . $daily_digest_sql . $weekly_digest_sql . $monthly_digest_sql . ") \n\t\t\t\t\t\t\t\tAND (user_digest_send_hour_gmt = {$current_hour_gmt} OR user_digest_send_hour_gmt = {$current_hour_gmt_plus_30}) \n\t\t\t\t\t\t\t\tAND user_inactive_reason = 0\n\t\t\t\t\t\t\t\tAND user_digest_type <> '" . constants::DIGESTS_NONE_VALUE . "'", 'ORDER_BY' => ' user_lang'); } else { $sql_array = array('SELECT' => 'u.*, s.*', 'FROM' => array(USERS_TABLE => 'u', STYLES_TABLE => 's'), 'WHERE' => 'u.user_style = s.style_id AND (' . $daily_digest_sql . $weekly_digest_sql . $monthly_digest_sql . ") \n\t\t\t\t\t\t\t\tAND (user_digest_send_hour_gmt = {$current_hour_gmt} OR user_digest_send_hour_gmt = {$current_hour_gmt_plus_30}) \n\t\t\t\t\t\t\t\tAND user_inactive_reason = 0\n\t\t\t\t\t\t\t\tAND user_digest_type <> '" . constants::DIGESTS_NONE_VALUE . "'", 'ORDER_BY' => 'user_lang'); } $sql = $this->db->sql_build_query('SELECT', $sql_array); $result = $this->db->sql_query($sql); $rowset = $this->db->sql_fetchrowset($result); // Gets users and their metadata that are receiving digests for this hour // Fetch all the posts (no private messages) but do it just once for efficiency. These will be filtered later // to remove those posts a particular user should not see. // First, determine a maximum date range fetched: daily, weekly or monthly if ($monthly_digest_sql != '') { // In the case of monthly digests, it's important to include posts that support daily and weekly digests as well, hence dates of posts // retrieved may exceed post dates for the previous month. Logic to exclude posts past the end of the previous month in the case of // monthly digests must be handled in the create_content function to skip these. $date_limit_sql = ' AND p.post_time >= ' . $gmt_month_1st_begin . ' AND p.post_time <= ' . max($this->gmt_month_lastday_end, $this->gmt_time); } else { if ($weekly_digest_sql != '') { $this->date_limit = $this->time - 7 * 24 * 60 * 60; $date_limit_sql = ' AND p.post_time >= ' . $this->date_limit . ' AND p.post_time < ' . $this->time; } else { $this->date_limit = $this->time - 24 * 60 * 60; $date_limit_sql = ' AND p.post_time >= ' . $this->date_limit . ' AND p.post_time < ' . $this->time; } } // Now get all potential posts for all users and place them in an array for parsing. Later the mailer will filter out the stuff that should not go // in a particular digest, based on permissions and options the user selected. // Prepare SQL $sql_array = array('SELECT' => 'f.*, t.*, p.*, u.*', 'FROM' => array(POSTS_TABLE => 'p', USERS_TABLE => 'u', TOPICS_TABLE => 't', FORUMS_TABLE => 'f'), 'WHERE' => "f.forum_id = t.forum_id\n\t\t\t\t\t\t\t\tAND p.topic_id = t.topic_id \n\t\t\t\t\t\t\t\tAND p.poster_id = u.user_id\n\t\t\t\t\t\t\t\t{$date_limit_sql}\n\t\t\t\t\t\t\t\tAND p.post_visibility = 1\n\t\t\t\t\t\t\t\tAND forum_password = ''", 'ORDER_BY' => 'f.left_id, f.right_id'); // Build query $sql_posts = $this->db->sql_build_query('SELECT', $sql_array); // Execute the SQL to retrieve the relevant posts. Note, if $this->config['phpbbservices_digests_max_items'] == 0 then there is no limit on the rows returned $result_posts = $this->db->sql_query_limit($sql_posts, $this->config['phpbbservices_digests_max_items']); $rowset_posts = $this->db->sql_fetchrowset($result_posts); // Get all the posts as a set // Now that we have all the posts, time to send one digest at a time foreach ($rowset as $row) { // Each traverse through this loop sends out exactly one digest // Skip sending this digest if a full "cycle" has not elapsed since when the digest was last sent out. For example, if the user has // subscribed to a daily digest, 24 hours needs to have elapsed since the last digest went out. The digest last send time is recorded // in the database when sent out. switch ($row['user_digest_type']) { case constants::DIGESTS_DAILY_VALUE: if ($row['user_digest_last_sent'] + 60 * 60 * 24 > $now) { continue; } break; case constants::DIGESTS_WEEKLY_VALUE: if ($row['user_digest_last_sent'] + 7 * 60 * 60 * 24 > $now) { continue; } break; case constants::DIGESTS_MONTHLY_VALUE: // Calculate seconds in previous month, which depends on number of days in that month $use_year = date($now, 'Y'); $use_month = date($now, 'n') - 1; if ($use_month == 0) { $use_month = 12; $use_year--; } $use_days_in_month = cal_days_in_month(CAL_GREGORIAN, $use_month, $use_year); if ($row['user_digest_last_sent'] + $use_days_in_month * 60 * 60 * 24 > $now) { continue; } break; default: // Shouldn't happen but assume a daily digest if it did happen if ($row['user_digest_last_sent'] + 60 * 60 * 24 > $now) { continue; } break; } $this->toc = array(); // Create or empty the array containing table of contents information $this->toc_post_count = 0; // # of posts in the table of contents $this->toc_pm_count = 0; // # of private messages in the table of contents $html_messenger = new \phpbbservices\digests\includes\html_messenger(); // Set the text showing the digest type switch ($row['user_digest_type']) { case constants::DIGESTS_DAILY_VALUE: $digest_type = $this->user->lang['DIGESTS_DAILY']; break; case constants::DIGESTS_WEEKLY_VALUE: $digest_type = $this->user->lang['DIGESTS_WEEKLY']; break; case constants::DIGESTS_MONTHLY_VALUE: $digest_type = $this->user->lang['DIGESTS_MONTHLY']; break; default: // The database may be corrupted if the digest type for a subscriber is invalid. // Write an error to the log and continue to the next subscriber. $digest_type = ''; // Make PhpStorm happy $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_BAD_DIGEST_TYPE', false, array($row['user_digest_type'], $row['username'])); continue; break; } $email_subject = $this->user->lang('DIGESTS_SUBJECT_TITLE', $this->config['sitename'], $digest_type); // Set various variables and flags based on the requested digest format. Note: will always use the British English email template because it's the // only one provided with the extension and it is effectively language neutral since it renders HTML and CSS only. There are no English words // in the templates. switch ($row['user_digest_format']) { case constants::DIGESTS_TEXT_VALUE: $format = $this->user->lang['DIGESTS_FORMAT_TEXT']; $html_messenger->template('digests_text', '', $this->email_templates_path); $is_html = false; $disclaimer = str_replace(''', "'", html_entity_decode(strip_tags($this->user->lang('DIGESTS_DISCLAIMER', $this->board_url, $this->config['sitename'], $this->board_url, $this->phpEx, $this->config['board_contact'], $this->config['sitename'])))); $powered_by = $this->config['phpbbservices_digests_host']; $this->layout_with_html_tables = false; break; case constants::DIGESTS_PLAIN_VALUE: $format = $this->user->lang['DIGESTS_FORMAT_PLAIN']; $html_messenger->template('digests_plain_html', '', $this->email_templates_path); $is_html = true; $disclaimer = $this->user->lang('DIGESTS_DISCLAIMER', $this->board_url, $this->config['sitename'], $this->board_url, $this->phpEx, $this->config['board_contact'], $this->config['sitename']); $powered_by = sprintf("<a href=\"%s\">%s</a>", $this->config['phpbbservices_digests_page_url'], $this->config['phpbbservices_digests_host']); $this->layout_with_html_tables = false; break; case constants::DIGESTS_PLAIN_CLASSIC_VALUE: $format = $this->user->lang['DIGESTS_FORMAT_PLAIN_CLASSIC']; $html_messenger->template('digests_plain_html', '', $this->email_templates_path); $is_html = true; $disclaimer = $this->user->lang('DIGESTS_DISCLAIMER', $this->board_url, $this->config['sitename'], $this->board_url, $this->phpEx, $this->config['board_contact'], $this->config['sitename']); $powered_by = sprintf("<a href=\"%s\">%s</a>", $this->config['phpbbservices_digests_page_url'], $this->config['phpbbservices_digests_host']); $this->layout_with_html_tables = true; break; case constants::DIGESTS_HTML_VALUE: $format = $this->user->lang['DIGESTS_FORMAT_HTML']; $html_messenger->template('digests_html', '', $this->email_templates_path); $is_html = true; $disclaimer = $this->user->lang('DIGESTS_DISCLAIMER', $this->board_url, $this->config['sitename'], $this->board_url, $this->phpEx, $this->config['board_contact'], $this->config['sitename']); $powered_by = sprintf("<a href=\"%s\">%s</a>", $this->config['phpbbservices_digests_page_url'], $this->config['phpbbservices_digests_host']); $this->layout_with_html_tables = false; break; case constants::DIGESTS_HTML_CLASSIC_VALUE: $format = $this->user->lang['DIGESTS_FORMAT_HTML_CLASSIC']; $html_messenger->template('digests_html', '', $this->email_templates_path); $is_html = true; $disclaimer = $this->user->lang('DIGESTS_DISCLAIMER', $this->board_url, $this->config['sitename'], $this->board_url, $this->phpEx, $this->config['board_contact'], $this->config['sitename']); $powered_by = sprintf("<a href=\"%s\">%s</a>", $this->config['phpbbservices_digests_page_url'], $this->config['phpbbservices_digests_host']); $this->layout_with_html_tables = true; break; default: // The database may be corrupted if the digest format for a subscriber is invalid. // Write an error to the log and continue to the next subscriber. $format = ''; // Keep PhpStorm happy $is_html = false; // Keep PhpStorm happy $disclaimer = ''; // Keep PhpStorm happy $powered_by = ''; // Keep PhpStorm happy $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_FORMAT_ERROR', false, array($row['user_digest_type'], $row['username'])); continue; break; } // Set email header information $from_field_email = isset($this->config['phpbbservices_digests_from_email_address']) && strlen($this->config['phpbbservices_digests_from_email_address']) > 0 ? $this->config['phpbbservices_digests_from_email_address'] : $this->config['board_email']; $from_field_name = isset($this->config['phpbbservices_digests_from_email_name']) && strlen($this->config['phpbbservices_digests_from_email_name']) > 0 ? $this->config['phpbbservices_digests_from_email_name'] : $this->config['sitename'] . ' ' . $this->user->lang['DIGESTS_ROBOT']; $reply_to_field_email = isset($this->config['phpbbservices_digests_reply_to_email_address']) && strlen($this->config['phpbbservices_digests_reply_to_email_address']) > 0 ? $this->config['phpbbservices_digests_reply_to_email_address'] : $this->config['board_email']; // Admin may override where email is sent in manual mode. This won't apply if digests are stored to the store/phpbbservices/digests folder instead. if ($this->manual_mode && $this->config['phpbbservices_digests_test_send_to_admin']) { $html_messenger->to($this->email_address_override); } else { $html_messenger->to($row['user_email']); } // SMTP delivery must strip text names due to likely bug in messenger class if ($this->config['smtp_delivery']) { $html_messenger->from($from_field_email); } else { if (trim($from_field_name) !== '') { $html_messenger->from(mail_encode(htmlspecialchars_decode($from_field_name)) . ' <' . $from_field_email . '>'); } else { $html_messenger->from($from_field_email); } } $html_messenger->replyto($reply_to_field_email); $html_messenger->subject($email_subject); // Transform user_digest_send_hour_gmt to the subscriber's local time $local_send_hour = $row['user_digest_send_hour_gmt'] + (int) $this->helper->make_tz_offset($row['user_timezone'], $row['username']); if ($local_send_hour >= 24) { $local_send_hour = $local_send_hour - 24; } else { if ($local_send_hour < 0) { $local_send_hour = $local_send_hour + 24; } } if ($local_send_hour >= 24 || $local_send_hour < 0) { // The database may be corrupted if the local send hour for a subscriber is still not between 0 and 23. // Write an error to the log and continue to the next subscriber. $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_BAD_SEND_HOUR', false, array($row['user_digest_type'], $row['user_digest_send_hour_gmt'])); continue; } // Change the filter type into something human readable switch ($row['user_digest_filter_type']) { case constants::DIGESTS_ALL: $post_types = $this->user->lang['DIGESTS_POSTS_TYPE_ANY']; break; case constants::DIGESTS_FIRST: $post_types = $this->user->lang['DIGESTS_POSTS_TYPE_FIRST']; break; case constants::DIGESTS_BOOKMARKS: $post_types = $this->user->lang['DIGESTS_USE_BOOKMARKS']; break; default: // The database may be corrupted if the filter type for a subscriber is incorrect. // Write an error to the log and continue to the next subscriber. $post_types = ''; // Keep PhpStorm happy $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_FILTER_ERROR', false, array($row['user_digest_filter_type'], $row['username'])); continue; break; } // Change the sort by into something human readable switch ($row['user_digest_sortby']) { case constants::DIGESTS_SORTBY_BOARD: $sort_by = $this->user->lang['DIGESTS_SORT_USER_ORDER']; break; case constants::DIGESTS_SORTBY_STANDARD: $sort_by = $this->user->lang['DIGESTS_SORT_FORUM_TOPIC']; break; case constants::DIGESTS_SORTBY_STANDARD_DESC: $sort_by = $this->user->lang['DIGESTS_SORT_FORUM_TOPIC_DESC']; break; case constants::DIGESTS_SORTBY_POSTDATE: $sort_by = $this->user->lang['DIGESTS_SORT_POST_DATE']; break; case constants::DIGESTS_SORTBY_POSTDATE_DESC: $sort_by = $this->user->lang['DIGESTS_SORT_POST_DATE_DESC']; break; default: // The database may be corrupted if the digest sort by for a subscriber is incorrect. // Write an error to the log and continue to the next subscriber. $sort_by = ''; // Make PhpStorm happy $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_SORT_BY_ERROR', false, array($row['user_digest_sortby'], $row['username'])); continue; break; } // Send a proper content-language to the output $user_lang = $row['user_lang']; if (strpos($user_lang, '-x-') !== false) { $user_lang = substr($user_lang, 0, strpos($user_lang, '-x-')); } // Create proper message indicating number of posts allowed in digest and set a value for the maximum posts allowed in this digest if ($row['user_digest_max_posts'] == 0 && $this->config['phpbbservices_digests_max_items'] == 0) { $this->max_posts = 0; // 0 means no limit $max_posts_msg = $this->user->lang['DIGESTS_NO_LIMIT']; } else { if ($this->config['phpbbservices_digests_max_items'] != 0 && $this->config['phpbbservices_digests_max_items'] < $row['user_digest_max_posts']) { $this->max_posts = (int) $row['phpbbservices_digests_max_items']; $max_posts_msg = $this->user->lang('DIGESTS_BOARD_LIMIT', $this->config['phpbbservices_digests_max_items']); } else { $this->max_posts = (int) $row['user_digest_max_posts']; $max_posts_msg = $row['user_digest_max_posts']; } } $recipient_time = $this->gmt_time + (int) ($this->helper->make_tz_offset($row['user_timezone']) * 60 * 60); // Print the non-post and non-private message information in the digest. The actual posts and private messages require the full templating system, // because the messenger class is too dumb to do more than basic templating. Note: most language variables are handled automatically by the templating // system. $html_messenger->assign_vars(array('DIGESTS_BLOCK_IMAGES' => $row['user_digest_block_images'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_COUNT_LIMIT' => $max_posts_msg, 'DIGESTS_DISCLAIMER' => $disclaimer, 'DIGESTS_FILTER_FOES' => $row['user_digest_remove_foes'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_FILTER_TYPE' => $post_types, 'DIGESTS_FORMAT_FOOTER' => $format, 'DIGESTS_LASTVISIT_RESET' => $row['user_digest_reset_lastvisit'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_MAIL_FREQUENCY' => $digest_type, 'DIGESTS_MAX_SIZE' => $row['user_digest_max_display_words'] == 0 ? $this->user->lang['DIGESTS_NO_POST_TEXT'] : ($row['user_digest_max_display_words'] == -1 ? $this->user->lang['DIGESTS_NO_LIMIT'] : $row['user_digest_max_display_words']), 'DIGESTS_MIN_SIZE' => $row['user_digest_min_words'] == 0 ? $this->user->lang['DIGESTS_NO_CONSTRAINT'] : $row['user_digest_min_words'], 'DIGESTS_NO_POST_TEXT' => $row['user_digest_no_post_text'] == 1 ? $this->user->lang['YES'] : $this->user->lang['NO'], 'DIGESTS_POWERED_BY' => $powered_by, 'DIGESTS_REMOVE_YOURS' => $row['user_digest_show_mine'] == 0 ? $this->user->lang['YES'] : $this->user->lang['NO'], 'DIGESTS_SALUTATION' => $row['username'], 'DIGESTS_SEND_HOUR' => $this->helper->make_hour_string($local_send_hour, $row['user_dateformat']), 'DIGESTS_SEND_IF_NO_NEW_MESSAGES' => $row['user_digest_send_on_no_posts'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_SHOW_ATTACHMENTS' => $row['user_digest_attachments'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_SHOW_NEW_POSTS_ONLY' => $row['user_digest_new_posts_only'] == 1 ? $this->user->lang['YES'] : $this->user->lang['NO'], 'DIGESTS_SHOW_PMS' => $row['user_digest_show_pms'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_SORT_BY' => $sort_by, 'DIGESTS_TOC_YES_NO' => $row['user_digest_toc'] == 0 ? $this->user->lang['NO'] : $this->user->lang['YES'], 'DIGESTS_VERSION' => $this->config['phpbbservices_digests_version'], 'L_DIGESTS_INTRODUCTION' => $this->user->lang('DIGESTS_INTRODUCTION', $this->config['sitename']), 'L_DIGESTS_PUBLISH_DATE' => $this->user->lang('DIGESTS_PUBLISH_DATE', $row['username'], date(str_replace('|', '', $row['user_dateformat']), $recipient_time)), 'L_DIGESTS_TITLE' => $email_subject, 'L_DIGESTS_YOUR_DIGEST_OPTIONS' => $is_html ? $this->user->lang('DIGESTS_YOUR_DIGEST_OPTIONS', $row['username']) : str_replace(''', "'", $this->user->lang('DIGESTS_YOUR_DIGEST_OPTIONS', $row['username'])), 'S_CONTENT_DIRECTION' => $this->user->lang['DIRECTION'], 'S_USER_LANG' => $user_lang, 'T_STYLESHEET_LINK' => $this->config['phpbbservices_digests_enable_custom_stylesheets'] ? "{$this->board_url}styles/" . $this->config['phpbbservices_digests_custom_stylesheet_path'] : "{$this->board_url}styles/" . $row['style_path'] . '/theme/stylesheet.css', 'T_THEME_PATH' => "{$this->board_url}styles/" . $row['style_path'] . '/theme')); // Get any private messages for this user $this->digest_exception = false; // Count # of unread and new for this user. Counts may need to be reduced later. $total_pm_unread = 0; $total_pm_new = 0; if ($row['user_digest_show_pms']) { $sql_array = array('SELECT' => '*', 'FROM' => array(PRIVMSGS_TO_TABLE => 'pt', PRIVMSGS_TABLE => 'pm', USERS_TABLE => 'u'), 'WHERE' => 'pt.msg_id = pm.msg_id AND pt.author_id = u.user_id AND pt.user_id = ' . $row['user_id'] . ' AND (pm_unread = 1 OR pm_new = 1)', 'ORDER_BY' => 'message_time'); $pm_sql = $this->db->sql_build_query('SELECT', $sql_array); $pm_result = $this->db->sql_query($pm_sql); $pm_rowset = $this->db->sql_fetchrowset($pm_result); $this->db->sql_freeresult(); foreach ($pm_rowset as $pm_row) { if ($pm_row['pm_unread'] == 1) { $total_pm_unread++; } if ($pm_row['pm_new'] == 1) { $total_pm_new++; } } } else { // Avoid some PHP Notices... $pm_result = NULL; $pm_rowset = NULL; } // Construct the body of the digest. We use the templating system because of the advanced features missing in the // email templating system, e.g. loops and switches. Note: create_content may set the flag $this->digest_exception. $digest_content = $this->create_content($rowset_posts, $pm_rowset, $row, $is_html); // List the subscribed forums, if any if ($row['user_digest_filter_type'] == constants::DIGESTS_BOOKMARKS) { $subscribed_forums = $this->user->lang['DIGESTS_USE_BOOKMARKS']; } else { if (sizeof($this->requested_forums_names) > 0) { $subscribed_forums = implode(', ', $this->requested_forums_names); } else { // Show that all forums were selected $subscribed_forums = $this->user->lang['DIGESTS_ALL_FORUMS']; } } // Assemble a digest table of contents if ($row['user_digest_toc'] == 1) { // Create Table of Contents header for private messages if ($is_html) { // For HTML digests, the table of contents always appears in a HTML table $digest_toc = "<h2 style=\"color:#000000\">" . $this->user->lang['DIGESTS_TOC'] . "</h2>\n"; $digest_toc .= "<p><a href=\"#skip\">" . $this->user->lang['DIGESTS_SKIP'] . "</a></p>\n"; } else { $digest_toc = "____________________________________________________________\n\n" . $this->user->lang['DIGESTS_TOC'] . "\n\n"; } if ($row['user_digest_show_pms'] == 1) { // Heading for table of contents if ($is_html) { $digest_toc .= sprintf("<div class=\"content\"><table>\n<tbody>\n<tr>\n<th id=\"j1\">%s</th><th id=\"j2\">%s</th><th id=\"j3\">%s</th><th id=\"j4\">%s</th>\n</tr>\n", $this->user->lang['DIGESTS_JUMP_TO_MSG'], ucwords($this->user->lang['PRIVATE_MESSAGE'] . ' ' . $this->user->lang['SUBJECT']), $this->user->lang['DIGESTS_SENDER'], $this->user->lang['DIGESTS_DATE']); } // Add a table row for each private message if ($this->toc_pm_count > 0) { for ($i = 0; $i <= $this->toc_pm_count; $i++) { if ($is_html) { $digest_toc .= isset($this->toc['pms'][$i]) ? "<tr>\n<td headers=\"j1\" style=\"text-align: center;\"><a href=\"#m" . $this->toc['pms'][$i]['message_id'] . '">' . $this->toc['pms'][$i]['message_id'] . '</a></td><td headers="j2">' . $this->toc['pms'][$i]['message_subject'] . '</td><td headers="j3">' . $this->toc['pms'][$i]['author'] . '</td><td headers="j4">' . $this->toc['pms'][$i]['datetime'] . "</td>\n</tr>\n" : ''; } else { $digest_toc .= isset($this->toc['pms'][$i]) ? $this->toc['pms'][$i]['author'] . ' ' . $this->user->lang['DIGESTS_SENT_YOU_A_MESSAGE'] . ' ' . $this->user->lang['DIGESTS_OPEN_QUOTE'] . $this->toc['pms'][$i]['message_subject'] . $this->user->lang['DIGESTS_CLOSED_QUOTE'] . ' ' . $this->user->lang['DIGESTS_ON'] . ' ' . $this->toc['pms'][$i]['datetime'] . "\n" : ''; } } } else { $digest_toc .= $is_html ? '<tr><td colspan="4">' . $this->user->lang['DIGESTS_NO_PRIVATE_MESSAGES'] . "</td></tr>" : ($digest_toc = $this->user->lang['DIGESTS_NO_PRIVATE_MESSAGES']); } // Create Table of Contents footer for private messages $digest_toc .= $is_html ? "</tbody></table>\n<br />" : "\n"; } else { $digest_toc = null; // Avoid a PHP Notice } // Create Table of Contents header for posts if ($is_html) { // For HTML digests, the table of contents always appears in a HTML table $digest_toc .= sprintf("<table>\n<tbody>\n<tr>\n<th id=\"h1\">%s</th><th id=\"h2\">%s</th><th id=\"h3\">%s</th><th id=\"h4\">%s</th><th id=\"h5\">%s</th>\n</tr>\n", $this->user->lang['DIGESTS_JUMP_TO_POST'], $this->user->lang['FORUM'], $this->user->lang['TOPIC'], $this->user->lang['AUTHOR'], $this->user->lang['DIGESTS_DATE']); } // Add a table row for each post if ($this->toc_post_count > 0) { for ($i = 0; $i <= $this->toc_post_count; $i++) { if ($is_html) { $digest_toc .= isset($this->toc['posts'][$i]) ? "<tr>\n<td headers=\"h1\" style=\"text-align: center;\"><a href=\"#p" . $this->toc['posts'][$i]['post_id'] . '">' . $this->toc['posts'][$i]['post_id'] . '</a></td><td headers="h2">' . $this->toc['posts'][$i]['forum'] . '</td><td headers="h3">' . $this->toc['posts'][$i]['topic'] . '</td><td headers="h4">' . $this->toc['posts'][$i]['author'] . '</td><td headers="h5">' . $this->toc['posts'][$i]['datetime'] . "</td>\n</tr>\n" : ''; } else { $digest_toc .= isset($this->toc['posts'][$i]) ? $this->toc['posts'][$i]['author'] . ' ' . $this->user->lang['DIGESTS_POSTED_TO_THE_TOPIC'] . ' ' . $this->user->lang['DIGESTS_OPEN_QUOTE'] . $this->toc['posts'][$i]['topic'] . $this->user->lang['DIGESTS_CLOSED_QUOTE'] . ' ' . $this->user->lang['IN'] . ' ' . $this->user->lang['DIGESTS_OPEN_QUOTE'] . $this->toc['posts'][$i]['forum'] . $this->user->lang['DIGESTS_CLOSED_QUOTE'] . ' ' . $this->user->lang['DIGESTS_ON'] . ' ' . $this->toc['posts'][$i]['datetime'] . "\n" : ''; } } } else { $no_posts_msg = $row['user_digest_filter_type'] == constants::DIGESTS_BOOKMARKS ? $this->user->lang['DIGESTS_NO_BOOKMARKED_POSTS'] : $this->user->lang['DIGESTS_NO_POSTS']; $digest_toc .= $is_html ? '<tr><td colspan="5">' . $no_posts_msg . "</td></tr>" : $no_posts_msg; } // Create Table of Contents footer for posts $digest_toc .= $is_html ? "</tbody>\n</table></div>\n<br />" : ''; // Publish the table of contents $html_messenger->assign_vars(array('DIGESTS_TOC' => $digest_toc)); } else { $digest_toc = null; // Avoid a PHP Notice } if (!$is_html) { // This reduces extra lines in the text digests. Apparently the phpBB template engine leaves // blank lines where a template contains templates commands. $digest_content = str_replace("\n\n", "\n", $digest_content); } // Publish the digest content, marshaled elsewhere and a list of the forums subscribed to. $html_messenger->assign_vars(array('DIGESTS_CONTENT' => $digest_content, 'DIGESTS_FORUMS_WANTED' => $subscribed_forums)); // Mark private messages in the digest as read, if so instructed if (sizeof($pm_rowset) != 0 && $row['user_digest_show_pms'] == 1 && $row['user_digest_pm_mark_read'] == 1) { $sql_ary = array('pm_new' => 0, 'pm_unread' => 0, 'folder_id' => 0); $pm_read_sql = 'UPDATE ' . PRIVMSGS_TO_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id'] . ' AND (pm_unread = 1 OR pm_new = 1)'; $this->db->sql_query($pm_read_sql); // Decrement the user_unread_privmsg and user_new_privmsg count $sql_ary = array('user_unread_privmsg' => 'user_unread_privmsg - ' . $total_pm_unread, 'user_new_privmsg' => 'user_new_privmsg - ' . $total_pm_new); $pm_read_sql = 'UPDATE ' . USERS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id']; $this->db->sql_query($pm_read_sql); } $this->db->sql_freeresult($result_posts); $this->db->sql_freeresult($pm_result); if ($this->manual_mode && $this->config['phpbbservices_digests_test_spool']) { // To grab the content of the email (less mail headers) first run the mailer with the $break parameter set to true. This will keep // the mail from being sent out. The function won't fail since nothing is being sent out. $html_messenger->send(NOTIFY_EMAIL, true, $is_html, true); $email_content = $html_messenger->msg; // Save digests as file in the store/phpbbservices/digests folder instead of emailing. $suffix = $is_html ? '.html' : '.txt'; $file_name = $row['username'] . '-' . $gmt_year . '-' . str_pad($gmt_month, 2, '0', STR_PAD_LEFT) . '-' . str_pad($gmt_day, 2, '0', STR_PAD_LEFT) . '-' . str_pad($gmt_hour, 2, '0', STR_PAD_LEFT) . $suffix; $handle = @fopen($this->cache_path . $file_name, "w"); if ($handle === false) { // Since this indicates a major problem, let's abort now. It's likely a global write error. $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_FILE_OPEN_ERROR', false, array($this->cache_path)); if ($this->config['phpbbservices_digests_enable_log']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_END'); } return false; } $success = @fwrite($handle, htmlspecialchars_decode($email_content)); if ($success === false) { // Since this indicates a major problem, let's abort now. It's likely a global write error. $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_FILE_WRITE_ERROR', false, array($this->cache_path . $file_name)); if ($this->config['phpbbservices_digests_enable_log']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_END'); } return false; } $success = @fclose($handle); if ($success === false) { // Since this indicates a major problem, let's abort now $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_FILE_CLOSE_ERROR', false, array($this->cache_path . $file_name)); if ($this->config['phpbbservices_digests_enable_log']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_END'); } return false; } // Note in the log that digest was written to disk if ($this->config['phpbbservices_digests_enable_log']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_GOOD_DISK', false, array($file_name)); } } else { // Send the digest out only if there are new qualifying posts OR the user requests a digest to be sent if there are no posts OR // if there are unread private messages AND the user wants to see private messages in the digest. // Try to send this digest if ($row['user_digest_send_on_no_posts'] || $this->toc_post_count > 0 || sizeof($pm_rowset) > 0 && $row['user_digest_show_pms']) { $mail_sent = $html_messenger->send(NOTIFY_EMAIL, false, $is_html, true); if (!$mail_sent) { if ($this->config['phpbbservices_digests_show_email']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_BAD', false, array($row['username'], $row['user_email'])); } else { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_BAD_NO_EMAIL', false, array($row['username'])); } $run_successful = false; } else { if ($this->config['phpbbservices_digests_enable_log']) { if ($this->config['phpbbservices_digests_show_email']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_GOOD', false, array($this->user->lang['DIGESTS_SENT_TO'], $row['username'], $row['user_email'], $gmt_year . '-' . $gmt_month . '-' . $gmt_day, $current_hour_gmt, $this->posts_in_digest, sizeof($pm_rowset))); } else { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_GOOD_NO_EMAIL', false, array($this->user->lang['DIGESTS_SENT_TO'], $row['username'], $gmt_year . '-' . $gmt_month . '-' . $gmt_day, $current_hour_gmt, $this->posts_in_digest, sizeof($pm_rowset))); } } $sql_ary = array('user_digest_last_sent' => time()); $sql2 = 'UPDATE ' . USERS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id']; $this->db->sql_query($sql2); // If requested, update user_lastvisit if ($row['user_digest_reset_lastvisit'] == 1) { $sql_ary = array('user_lastvisit' => time()); $sql2 = 'UPDATE ' . USERS_TABLE . ' SET ' . $this->db->sql_build_array('UPDATE', $sql_ary) . ' WHERE user_id = ' . $row['user_id']; $this->db->sql_query($sql2); } } } else { // Don't send a digest, the user doesn't want one because there are no qualifying posts if ($this->config['phpbbservices_digests_show_email']) { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_NONE', false, array($row['username'], $row['user_email'])); } else { $this->phpbb_log->add('admin', $this->user->data['user_id'], $this->user->ip, 'LOG_CONFIG_DIGESTS_LOG_ENTRY_NONE_NO_EMAIL', false, array($row['username'])); } } } // Reset messenger object, bug fix provided by robdocmagic $html_messenger->reset(); } // foreach if ($this->digest_exception) { // Digest exception errors are handled by create_content but we do want to note that something odd occurred to let the calling program know // after all digests for the hour are sent. $run_successful = false; } return $run_successful; }
function msg_email() { global $config, $_CLASS; if (empty($config['email_enable'])) { return false; } $use_queue = false; if ($config['email_package_size'] && $this->use_queue) { if (empty($this->queue)) { $this->queue = new queue(); $this->queue->init('email', $config['email_package_size']); } $use_queue = true; } $to = $cc = $bcc = ''; // Build to, cc and bcc strings foreach ($this->addresses as $type => $address_ary) { if ($type == 'im') { continue; } foreach ($address_ary as $which_ary) { ${$type} .= (${$type} != '' ? ', ' : '') . ($which_ary['name'] != '' ? '"' . mail_encode($which_ary['name'], $this->encoding) . '" <' . $which_ary['email'] . '>' : $which_ary['email']); } } if (empty($this->replyto)) { $this->replyto = '<' . $config['board_email'] . '>'; } if (empty($this->from)) { $this->from = '<' . $config['board_email'] . '>'; } // Build header $headers = 'From: ' . $this->from . "\n"; $headers .= $cc != '' ? "Cc: {$cc}\n" : ''; $headers .= $bcc != '' ? "Bcc: {$bcc}\n" : ''; $headers .= 'Reply-to: ' . $this->replyto . "\n"; $headers .= 'Return-Path: <' . $config['board_email'] . ">\n"; $headers .= 'Sender: <' . $config['board_email'] . ">\n"; $headers .= "MIME-Version: 1.0\n"; $headers .= 'Message-ID: <' . md5(uniqid(time())) . "@" . $config['server_name'] . ">\n"; $headers .= 'Date: ' . gmdate('D, d M Y H:i:s T', time()) . "\n"; $headers .= "Content-type: text/plain; charset={$this->encoding}\n"; $headers .= "Content-transfer-encoding: 8bit\n"; $headers .= "X-Priority: {$this->mail_priority}\n"; $headers .= 'X-MSMail-Priority: ' . ($this->mail_priority == MAIL_LOW_PRIORITY ? 'Low' : ($this->mail_priority == MAIL_NORMAL_PRIORITY ? 'Normal' : 'High')) . "\n"; $headers .= "X-Mailer: PhpBB\n"; $headers .= "X-MimeOLE: phpBB\n"; $headers .= "X-phpBB-Origin: phpbb://" . str_replace(array('http://', 'https://'), array('', ''), generate_board_url()) . "\n"; $headers .= $this->extra_headers != '' ? $this->extra_headers : ''; // Send message ... removed $this->encode() from subject for time being if (!$use_queue) { $mail_to = $to == '' ? 'Undisclosed-Recipient:;' : $to; $err_msg = ''; $result = $config['smtp_delivery'] ? smtpmail($this->addresses, $this->subject, wordwrap($this->msg), $err_msg, $this->encoding, $headers) : @$config['email_function_name']($mail_to, $this->subject, implode("\n", preg_split("/\r?\n/", wordwrap($this->msg))), $headers); if (!$result) { $message = '<u>EMAIL ERROR</u> [ ' . ($config['smtp_delivery'] ? 'SMTP' : 'PHP') . ' ]<br /><br />' . $err_msg . '<br /><br /><u>CALLING PAGE</u><br /><br />' . (!empty($_SERVER['PHP_SELF']) ? $_SERVER['PHP_SELF'] : $_ENV['PHP_SELF']) . '<br />'; $this->error('EMAIL', $message); return false; } } else { $this->queue->put('email', array('to' => $to, 'addresses' => $this->addresses, 'subject' => $this->subject, 'msg' => $this->msg, 'encoding' => $this->encoding, 'headers' => $headers)); } return true; }
foreach ($data[attachment_data] as $filename) { $message .= " " . print_r($filename, 1) . "\n"; } $message .= "\n"; } // add signature if ($n2m_SHOW_SIG) { if ($mode != "edit") { if ($user->data[user_sig] and $data[enable_sig]) { $message .= "\nSignature:\n "; $message .= generate_text_for_edit($user->data[user_sig], $user->data[user_sig_bbcode_uid], $post_data[forum_desc_options])["text"] . "\n\n"; } } } // encode subject $subject = mail_encode(html_entity_decode($n2m_SUBJECT)); // convert all addresses to lowercase and delete any empty addresses foreach ($n2m_MAILTO as $key => $value) { if (is_null($value) or $value == "") { unset($n2m_MAILTO[$key]); } else { $n2m_MAILTO[$key] = strtolower($n2m_MAILTO[$key]); } } // insure that every address is only used once $n2m_MAILTO = array_unique($n2m_MAILTO); // Testversion, Mails an Author des Artikels verhindern // unset($n2m_MAILTO[array_search($user->data['user_email'], $n2m_MAILTO)]); // die($message); // for debugging purposes, mail will be shown in browser and not sent out if we uncomment this line // make text "flow" in plain/text $temp = $message;