/** * Форма подписки на рассылку * @param $id * @param string $tpl * * @return string HTML code */ public static function form($id, $tpl = 'subscribe.widget.form') { $subscribe = subscribe_model_Subscribe::getById($id); if ($subscribe) { Resources::linkFileFooter(cot::$cfg['modules_dir'] . '/subscribe/js/subscriber.js'); } $view = new View(); $view->subscribe = $subscribe; if (empty($tpl)) { $tpl = array('subscribe', 'widget', 'form'); if (!empty($subscribe) && !empty($subscribe->alias)) { $tpl[] = $subscribe->alias; } } return $view->render($tpl, 'module'); }
/** * Список писем в очереди на отправку * @return string * @throws Exception */ public function indexAction() { global $admintitle, $adminpath, $Ls; $admintitle = cot::$L['subscribe_queue']; $adminpath[] = array(cot_url('admin', array('m' => 'subscribe', 'n' => 'queue')), $admintitle); $sort = cot_import('s', 'G', 'ALP'); // order field name $way = cot_import('w', 'G', 'ALP', 4); // order way (asc, desc) $maxrowsperpage = cot::$cfg['maxrowsperpage']; if ($maxrowsperpage < 1) { $maxrowsperpage = 1; } list($pg, $d, $durl) = cot_import_pagenav('d', $maxrowsperpage); //page number for pages list /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.queue.list.first') as $pl) { include $pl; } /* ===== */ $sort = empty($sort) ? 'id' : $sort; $way = empty($way) || !in_array($way, array('asc', 'desc')) ? 'asc' : $way; $urlParams = array('m' => 'subscribe', 'n' => 'queue'); if ($sort != 'id') { $urlParams['s'] = $sort; } if ($way != 'asc') { $urlParams['w'] = $way; } $where = array(); // Фильтры $allowedFilters = array('sid', 'to_name', 'to_email'); $f = cot_import('f', 'G', 'ARR'); $filterForm = array('hidden' => ''); if (!empty($f)) { foreach ($f as $key => $val) { if (!in_array($key, $allowedFilters)) { unset($f[$key]); } } if (!empty($f['sid'])) { $where['sid'] = array('subscribe', $f['sid']); $urlParams['f[sid]'] = $f['sid']; } if (!empty($f['to_name'])) { $where['to_name'] = array('to_name', '*' . $f['to_name'] . '*'); $urlParams['f[to_name]'] = $f['to_name']; } if (!empty($f['to_email'])) { $where['to_email'] = array('to_email', '*' . $f['to_email'] . '*'); $urlParams['f[to_email]'] = $f['to_email']; } } if (isset(cot::$cfg['plugin']['urleditor']) && cot::$cfg['plugin']['urleditor']['preset'] != 'handy') { $filterForm['hidden'] .= cot_inputbox('hidden', 'm', 'subscribe'); } $filterForm['hidden'] .= cot_inputbox('hidden', 'n', 'queue'); $condition = array(); foreach ($where as $key => $val) { $condition[] = $val; } $order = array(array($sort, $way)); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.queue.list.query') as $pl) { include $pl; } /* ===== */ $totallines = subscribe_model_Queue::count($condition); $items = null; if ($totallines > 0) { $items = subscribe_model_Queue::find($condition, $maxrowsperpage, $d, $order); } // Если передан номер страницы превышающий максимальный if (empty($items) && $totallines > 0 && $pg > 1) { $totalpages = ceil($totallines / $maxrowsperpage); $args = $urlParams; if ($totalpages > 1) { if (cot::$cfg['easypagenav']) { $args['d'] = $totalpages; } else { $args['d'] = ($totalpages - 1) * $maxrowsperpage; } } cot_redirect(cot_url('admin', $args, '', true)); } //$addNewUrl = cot_url('admin', array('m'=>'subscribe','a' => 'edit')); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.queue.list.main') as $pl) { include $pl; } /* ===== */ $pagenav = cot_pagenav('admin', $urlParams, $d, $totallines, $maxrowsperpage, 'd', '', true); if (empty($pagenav['current'])) { $pagenav['current'] = 1; } $pagenav['page'] = $pagenav['current']; if (!cot::$cfg['easypagenav']) { $pagenav['page'] = ($pagenav['current'] - 1) * $maxrowsperpage; } $subscribes = subscribe_model_Subscribe::keyValPairs(); $template = array('subscribe', 'admin', 'queue', 'list'); $view = new View(); $view->page_title = $admintitle; $view->fistNumber = $d + 1; $view->items = $items; $view->totalitems = $totallines; $view->pagenav = $pagenav; $view->subscribes = $subscribes; $view->urlParams = $urlParams; $view->filter = $f; $view->filterForm = $filterForm; /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.queue.list.view') as $pl) { include $pl; } /* ===== */ return $view->render($template); }
public function deleteAction() { $id = cot_import('id', 'G', 'INT'); $d = cot_import('d', 'G', 'INT'); $backUrlParams = array('m' => 'subscribe'); if (!empty($d)) { $backUrlParams['d'] = $d; } // Фильтры из списка $f = cot_import('f', 'G', 'ARR'); if (!empty($f)) { foreach ($f as $key => $val) { if ($key == 'id') { continue; } $backUrlParams["f[{$key}]"] = $val; } } $sort = cot_import('s', 'G', 'ALP'); // order field name $way = cot_import('w', 'G', 'ALP', 4); // order way (asc, desc) if ($sort != 'title') { $backUrlParams['s'] = $sort; } if ($way != 'asc') { $backUrlParams['w'] = $way; } if (!$id) { cot_error(cot::$L['subscribe_err_not_found']); cot_redirect(cot_url('admin', $backUrlParams)); } $item = subscribe_model_Subscribe::getById($id); if (!$item) { cot_error(cot::$L['subscribe_err_not_found']); cot_redirect(cot_url('admin', $backUrlParams)); } $title = $item->title; $item->delete(); cot_message(sprintf(cot::$L['subscribe_deleted'], $title)); cot_redirect(cot_url('admin', $backUrlParams, '', true)); }
return date('Y-m-d H:i', mktime($fst[0], $fst[1], 0, $nowDate['mon'], $nowDate['mday'] + $i, $nowDate['year'])); } protected function beforeUpdate() { $this->_data['updated'] = date('Y-m-d H:i:s', cot::$sys['now']); $this->_data['updated_by'] = cot::$usr['id']; return parent::beforeUpdate(); } protected function beforeDelete() { // Удалить всех подписчиков $items = subscribe_model_Subscriber::find(array(array('subscribe', $this->_data['id']))); if (!empty($items)) { foreach ($items as $itemRow) { $itemRow->delete(); } } return parent::beforeDelete(); } // public function beforeSave(&$data = null) { // // return parent::beforeSave($data); // } public static function fieldList() { $fields = array('id' => array('type' => 'int', 'description' => 'id', 'primary' => true), 'title' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'nullable' => false, 'description' => cot::$L['Title']), 'alias' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['Alias']), 'from_mail' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_from_mail']), 'from_title' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_from_title']), 'subject' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_subject']), 'description' => array('type' => 'text', 'default' => '', 'description' => cot::$L['subscribe_description']), 'admin_note' => array('type' => 'text', 'default' => '', 'description' => cot::$L['subscribe_admin_note']), 'content_url' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_content_url']), 'text' => array('type' => 'text', 'default' => '', 'description' => cot::$L['Text']), 'last_executed' => array('type' => 'datetime', 'default' => null, 'description' => cot::$L['subscribe_last_executed']), 'last_sent' => array('type' => 'int', 'default' => 0, 'description' => cot::$L['subscribe_last_sent']), 'next_run' => array('type' => 'datetime', 'default' => null, 'description' => cot::$L['subscribe_next_run']), 'sched_mday' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_sched_mday']), 'sched_wday' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_sched_wday']), 'sched_time' => array('type' => 'varchar', 'length' => '255', 'default' => '', 'description' => cot::$L['subscribe_sched_time']), 'active' => array('type' => 'tinyint', 'length' => '1', 'default' => 0, 'description' => cot::$L['subscribe_active']), 'periodical' => array('type' => 'tinyint', 'length' => '1', 'default' => 0, 'description' => cot::$L['subscribe_periodical']), 'running' => array('type' => 'tinyint', 'length' => '1', 'default' => 0, 'description' => cot::$L['subscribe_running']), 'sort' => array('type' => 'int', 'default' => 10, 'description' => cot::$L['subscribe_sort']), 'ping' => array('type' => 'datetime', 'default' => null), 'created' => array('type' => 'datetime', 'default' => date('Y-m-d H:i:s', cot::$sys['now']), 'description' => cot::$L['subscribe_created']), 'created_by' => array('type' => 'int', 'default' => cot::$usr['id'], 'description' => cot::$L['subscribe_created_by']), 'updated' => array('type' => 'datetime', 'default' => date('Y-m-d H:i:s', cot::$sys['now']), 'description' => cot::$L['subscribe_updated']), 'updated_by' => array('type' => 'int', 'default' => cot::$usr['id'], 'description' => cot::$L['subscribe_updated_by'])); return $fields; } } subscribe_model_Subscribe::__init();
/** * @param subscribe_model_Subscribe $subscribe * @return int количество отосланных писем */ public static function subscribeRun($subscribe) { if (empty($subscribe)) { return false; } $nowdate = date('Y-m-d H:i:s', cot::$sys['now']); // Сэкономим память. Ощутимо на большом количестве подписчиков $stmtSubscribers = cot::$db->query("SELECT * FROM " . subscribe_model_Subscriber::tableName() . "\n WHERE subscribe={$subscribe->id} AND last_executed<'{$nowdate}' AND active=1"); $count = $stmtSubscribers->rowCount(); if ($count == 0) { return 0; } $i = 0; $rpc = trim($subscribe->content_url); if ($rpc != '') { $text = file_get_contents($rpc); if (!$text || $text == '') { echo "[Error] I can not get email content from address: '{$rpc}' \n"; echo "Stopped\n\n"; ob_flush(); return false; } } else { $text = $subscribe->text; preg_match_all("/\\[URL#([a-zA-Z0-9-\\?_\\=\\:\\/\\.\\&;,]+)#]/ies", $text, $m); $_vars = array(); foreach ($m[1] as $varName) { $varurl = html_entity_decode($varName); $_vars["[URL#" . $varName . "#]"] = file_get_contents($varurl); } $text = str_replace(array_keys($_vars), $_vars, $text); $text = str_replace('[YEAR]', cot_date('Y'), $text); } echo "Subscribers count: " . $stmtSubscribers->rowCount() . "\n"; $msgView = new View(); $msgView->subscribe = $subscribe; $msgView->text = $text; $tpl = array('subscribe', 'mail'); if (!empty($subscribe->alias)) { $tpl[] = $subscribe->alias; } $fromTitle = cot::$cfg['maintitle']; if (!empty($subscribe->from_title)) { $fromTitle = $subscribe->from_title; } $fromEmail = cot::$cfg["adminemail"]; if (!empty($subscribe->from_mail)) { $fromEmail = $subscribe->from_mail; } $subject = !empty($subscribe->subject) ? $subscribe->subject : $subscribe->title; if (cot::$cfg['subscribe']['useQueue']) { $sender = new subscribe_sender_Queue(); } else { $sender = new subscribe_sender_Cotmail(); } $errors = 0; $data = array('subscribe' => $subscribe->id, 'subject' => $subject, 'fromName' => $fromTitle, 'fromEmail' => $fromEmail); while ($item = $stmtSubscribers->fetch()) { echo " - Processing: " . trim($item['name'] . ' ' . $item['email']) . " ..."; ob_flush(); // Кешируем время выполнения // Memcache было бы лучше $subscribe->ping = date('Y-m-d H:i:s'); // Текущее системное время, а не то что было на момент старта скрипта $subscribe->save(); $msgView->subscribe = $subscribe; $msgView->subscriber = $item; $msgBody = $msgView->render($tpl); $data['subscriber'] = $item['id']; $data['toEmail'] = $item['email']; $data['toName'] = $item['name']; // Поддержка тегов 'отписаться' $tmp = cot_url('subscribe', array('m' => 'user', 'a' => 'unsubscribe', 'code' => $item['unsubscr_code'])); if (!cot_url_check($tmp)) { $tmp = cot::$cfg['mainurl'] . '/' . $tmp; } $toSend = str_replace('[UNSUBSCRIBE_URL]', "<a href=\"{$tmp}\">{$tmp}</a>", $msgBody); $data['body'] = $toSend; $isError = false; try { $sender->send($data); } catch (Exception $e) { $isError = true; $errors++; $errCode = $e->getCode(); $errMsg = $e->getMessage(); echo "\n[ERROR] {$errCode}: {$errMsg}! While sending to: {$item['email']}\n"; ob_flush(); // Зафиксировать в базе ошибку отправки сообщения $tmpData = array('last_error' => mb_substr("{$errCode}: {$errMsg}", 0, 253)); cot::$db->update(subscribe_model_Subscriber::tableName(), $tmpData, "id={$item['id']}"); // TODO проанализировать ошибку, если User not found - отписать его, чтобы больше не слать ему письма // 500 - User not found // 553 - Invalid domain name // if ($errCode == 550 || $errCode == 553){ // // Зафиксировать в базе ошибку отправки сообщения // echo "Отписываю его...\n"; // ob_flush(); // $data = array( // 'subr_on' => 'false', // 'subr_last_error' => "{$errCode}: {$errMsg}", // ); // $db->update('subscriber', $data, "subr_id={$item['subr_id']}"); // // }else{ var_dump($e); echo "\n------------\n"; ob_flush(); // } } if (!$isError) { echo " done\n"; $tmpData = array('last_executed' => $nowdate, 'last_error' => ''); cot::$db->update(subscribe_model_Subscriber::tableName(), $tmpData, "id={$item['id']}"); $i++; } unset($item); if ($i % 100 == 0) { gc_collect_cycles(); } } if ($errors > 0) { echo "\nErrors count: {$errors} \n"; ob_flush(); } return $i; }
/** * Обработка Ajax запроса на подписку на рассылку * Используется виджетом * Принимает email пользователя * Допускается подписка неавторизованными пользователями (они должны подтвердить email) */ public function ajxSubscribeAction() { global $db_users; $ret = array('error' => '', 'message' => ''); $id = cot_import('id', 'P', 'INT'); $email = cot_import('email', 'P', 'TXT'); if (!$id) { $ret['error'] = cot::$L['subscribe_err_not_found']; echo json_encode($ret); exit; } $subscribe = subscribe_model_Subscribe::getById($id); if (!$subscribe) { $ret['error'] = cot::$L['subscribe_err_not_found']; echo json_encode($ret); exit; } if (!$subscribe->active) { $ret['error'] = cot::$L['subscribe_err_disabled']; echo json_encode($ret); exit; } if (empty($email)) { $ret['error'] = cot::$L['field_required'] . ': ' . cot::$L['Email']; echo json_encode($ret); exit; } $tmp = subscribe_checkEmail($email); if ($tmp !== true) { $ret['error'] = $tmp; echo json_encode($ret); exit; } $email = mb_strtolower($email); $subscriber = subscribe_model_Subscriber::fetchOne(array(array('subscribe', $id), array('email', $email))); if ($subscriber) { if ($subscriber->active) { $ret['error'] = sprintf(cot::$L['subscribe_err_user_subscribed'], $email, $subscribe->title); echo json_encode($ret); exit; } } else { $subscriber = new subscribe_model_Subscriber(); } $sql = cot::$db->query("SELECT * FROM {$db_users} WHERE user_email = ? LIMIT 1", $email); $user = $sql->fetch(); $subscriber->subscribe = $id; $subscriber->email = $email; if (!empty($user)) { $subscriber->user = $user['user_id']; $subscriber->name = cot_user_full_name($user); } $needConfirm = cot::$cfg['subscribe']['guestConfirmMail']; if (cot::$usr['id'] > 0) { if (cot::$usr['id'] == $user['user_id'] || cot::$usr['isadmin']) { $needConfirm = false; } } if ($needConfirm) { // Возможно пользователь уже подтверждал свой email $tmp = subscribe_model_Subscriber::count(array(array('email', $email), array('email_valid', 1))); if ($tmp > 0) { $needConfirm = false; } } if (!$needConfirm) { $subscriber->email_valid = 1; $subscriber->email_valid_date = date('Y-m-d H:i:s', cot::$sys['now']); $subscriber->active = 1; } // Сохранение $subscriber->save(); $ret['message'] = sprintf(cot::$L['subscribe_msg_you_subscribed'], $subscribe->title); // Письмо для поджтверждения e-mail адреса if ($needConfirm) { $confirmUrl = cot_url('subscribe', array('m' => 'user', 'a' => 'confirm', 'code' => $subscriber->unsubscr_code)); if (!cot_url_check($confirmUrl)) { $confirmUrl = cot::$cfg['mainurl'] . '/' . $confirmUrl; } $mailView = new View(); $mailView->subscriber = $subscriber; $mailView->subscribe = $subscribe; $mailView->confirmUrl = $confirmUrl; $mailTpl = array('subscribe', 'mail_confirm', cot::$usr['lang']); $mailBody = $mailView->render($mailTpl); cot_mail($email, cot::$L['subscribe_confirm'], $mailBody, '', false, null, true); $ret['message'] .= cot::$L['subscribe_wait_confirm']; } echo json_encode($ret); exit; }
public function ajxEditAction() { global $db_users; $ret = array('error' => ''); $id = cot_import('subrid', 'P', 'INT'); unset($_POST['id'], $_POST['subrid']); if ($id > 0) { $subscriber = subscribe_model_Subscriber::getById($id); if (!$subscriber) { $ret['error'] = cot::$L['subscribe_err_subscriber_not_found']; echo json_encode($ret); exit; } } else { $subscriber = new subscribe_model_Subscriber(); } if (!empty($_POST['email'])) { $_POST['email'] = mb_strtolower($_POST['email']); } $subscriber->setData($_POST); $error = array(); $subscr = null; $tmp = $subscriber->rawValue('subscribe'); if (empty($tmp)) { $error[] = cot::$L['field_required'] . ': ' . cot::$L['subscribe_subscribe']; } else { $subscr = subscribe_model_Subscribe::getById($subscriber->rawValue('subscribe')); if (!$subscr) { $error[] = cot::$L['subscribe_err_not_found']; } } $user = null; if (!empty($subscriber->user)) { $user = cot_user_data($subscriber->user); // Если получили данные пользователя, то e-mail всегда берем из профиля if (isset($user['user_email'])) { $subscriber->email = mb_strtolower($user['user_email']); } } if (empty($subscriber->email)) { $error[] = cot::$L['field_required'] . ': ' . cot::$L['Email']; } else { $tmp = subscribe_checkEmail($subscriber->email); if ($tmp !== true) { $error[] = $tmp; } if ($subscriber->rawValue('subscribe') > 0) { if (!empty($subscr)) { $cond = array(array('email', $subscriber->email), array('subscribe', $subscr->id)); if ($subscriber->id > 0) { $cond[] = array('id', $subscriber->id, '<>'); } $cnt = subscribe_model_Subscriber::count($cond); if ($cnt > 0) { $error[] = sprintf(cot::$L['subscribe_err_user_subscribed'], $subscriber->email, htmlspecialchars($subscr->title)); } } } } if (!empty($error)) { $ret['error'] = implode('<br />', $error); echo json_encode($ret); exit; } if (empty($subscriber->name) && (!empty($subscriber->email) || !empty($user))) { if (!empty($user)) { $subscriber->name = cot_user_full_name($user); } else { $sql = cot::$db->query("SELECT * FROM {$db_users} WHERE user_email = ? LIMIT 1", $subscriber->email); $user = $sql->fetch(); if (!empty($user)) { $subscriber->name = cot_user_full_name($user); if (empty($subscriber->user)) { $subscriber->user = $user['user_id']; } } } } // Админ при сохранении подтверждает e-mail if (!$subscriber->email_valid && (empty($subscriber->id) || $subscriber->active)) { $subscriber->email_valid = 1; $subscriber->email_valid_date = date('Y-m-d H:i:s', cot::$sys['now']); } // Сохранение $subscriber->save(); cot_message(cot::$L['Saved']); echo json_encode($ret); exit; }