/** * Сборщик мусора */ protected function garbageCollect() { // Удаление старых неподтвержденных подписчиков $delDate = new DateTime(); // 1 неделя $delDate->sub(new DateInterval('P1W')); $items = subscribe_model_Subscriber::find(array(array('email_valid', 0), array('created', $delDate->format('Y-m-d H:i:s'), '<='))); if (!empty($items)) { foreach ($items as $itemRow) { $itemRow->delete(); } } }
/** * Редактирование рассылки * @return string * @throws Exception */ public function editAction() { global $cot_extrafields, $admintitle, $adminpath; $id = cot_import('id', 'G', 'INT'); // id Рассылки $act = cot_import('act', 'G', 'ALP'); if (empty($act)) { $act = cot_import('act', 'P', 'ALP'); } $adminpath[] = array(cot_url('admin', array('m' => 'subscribe')), cot::$L['subscribe_subscribes']); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.edit.first') as $pl) { include $pl; } /* ===== */ if (!$id) { $item = new subscribe_model_Subscribe(); $admintitle = cot::$L['subscribe_add_new']; $adminpath[] = array(cot_url('admin', array('m' => 'subscribe', 'a' => 'edit')), $admintitle); } else { $item = subscribe_model_Subscribe::getById($id); if (!$item) { cot_error(cot::$L['subscribe_err_not_found']); cot_redirect(cot_url('admin', array('m' => 'subscribe'), '', true)); } if ($act == 'clone') { $id = null; $item = clone $item; $admintitle = cot::$L['subscribe_add_new']; $adminpath[] = array(cot_url('admin', array('m' => 'subscribe', 'a' => 'edit')), $admintitle); } else { $admintitle = $item->title . " [" . cot::$L['Edit'] . "]"; $adminpath[] = array(cot_url('admin', array('m' => 'subscribe', 'a' => 'edit', 'id' => $item->id)), $admintitle); } } // Сохранение if ($act == 'save') { unset($_POST['id'], $_POST['user'], $_POST['x'], $_POST['act']); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.save.first') as $pl) { include $pl; } /* ===== */ $data = $_POST; $data['next_run'] = cot_import_date('next_run'); if (!empty($data['next_run'])) { $data['next_run'] = date('Y-m-d H:i:s', $data['next_run']); } $item->setData($data); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.save.validate') as $pl) { include $pl; } /* ===== */ // There is some errors if (!$item->validate() || cot_error_found()) { $urlParams = array('m' => 'subscribe', 'a' => 'edit'); if ($item->id > 0) { $urlParams['id'] = $item->id; } cot_redirect(cot_url('admin', $urlParams, '', true)); } $isNew = $item->id == 0; // Перерасчет времени следующего запуска // Делать это в админке при редактировании рассылки и при выполнении рассылки // А то могут быть коллизии $recalculate = true; if (!empty($item->next_run)) { $tmp = strtotime($item->next_run); if ($tmp > cot::$sys['now']) { $recalculate = false; } } if ($recalculate) { $item->next_run = $item->getNextRunDate(); } // Сохранение if ($item->save()) { cot_message(cot::$L['Saved']); $urlParams = array('m' => 'subscribe', 'a' => 'edit', 'id' => $item->id); $redirectUrl = cot_url('admin', $urlParams, '', true); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.save.done') as $pl) { include $pl; } /* ===== */ // Редирект на станицу рассылки cot_redirect($redirectUrl); } } // 'input_textarea_editor', 'input_textarea_medieditor', 'input_textarea_minieditor', '' $editor = 'input_textarea_editor'; /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.edit.main') as $pl) { include $pl; } /* ===== */ $nextRun = 0; if (!empty($item->next_run)) { $nextRun = strtotime($item->next_run); } $formElements = array('hidden' => array('element' => cot_inputbox('hidden', 'act', 'save')), 'title' => array('element' => cot_inputbox('text', 'title', $item->rawValue('title')), 'required' => true, 'label' => subscribe_model_Subscribe::fieldLabel('title')), 'alias' => array('element' => cot_inputbox('text', 'alias', $item->rawValue('alias')), 'label' => subscribe_model_Subscribe::fieldLabel('alias')), 'admin_note' => array('element' => cot_textarea('admin_note', $item->rawValue('admin_note'), 5, 120, ''), 'label' => subscribe_model_Subscribe::fieldLabel('admin_note')), 'from_mail' => array('element' => cot_inputbox('text', 'from_mail', $item->rawValue('from_mail')), 'label' => subscribe_model_Subscribe::fieldLabel('from_mail'), 'hint' => cot::$L['subscribe_from_mail_hint']), 'from_title' => array('element' => cot_inputbox('text', 'from_title', $item->rawValue('from_title')), 'label' => subscribe_model_Subscribe::fieldLabel('from_title')), 'subject' => array('element' => cot_inputbox('text', 'subject', $item->rawValue('subject')), 'label' => subscribe_model_Subscribe::fieldLabel('subject')), 'description' => array('element' => cot_textarea('description', $item->rawValue('description'), 5, 120, '', $editor), 'label' => subscribe_model_Subscribe::fieldLabel('description')), 'content_url' => array('element' => cot_inputbox('text', 'content_url', $item->rawValue('content_url')), 'label' => subscribe_model_Subscribe::fieldLabel('content_url'), 'hint' => cot::$L['subscribe_content_url_hint']), 'text' => array('element' => cot_textarea('text', $item->rawValue('text'), 5, 120, '', $editor), 'label' => subscribe_model_Subscribe::fieldLabel('text'), 'hint' => cot::$L['subscribe_text_hint']), 'next_run' => array('element' => cot_selectbox_date($nextRun, 'long', 'next_run'), 'label' => subscribe_model_Subscribe::fieldLabel('next_run'), 'hint' => cot::$L['subscribe_next_run_hint'] . " " . cot::$usr['timetext']), 'sched_mday' => array('element' => cot_inputbox('text', 'sched_mday', $item->rawValue('sched_mday')), 'label' => subscribe_model_Subscribe::fieldLabel('sched_mday'), 'hint' => cot::$L['subscribe_sched_mday_hint']), 'sched_wday' => array('element' => cot_inputbox('text', 'sched_wday', $item->rawValue('sched_wday')), 'label' => subscribe_model_Subscribe::fieldLabel('sched_wday'), 'hint' => cot::$L['subscribe_sched_wday_hint']), 'sched_time' => array('element' => cot_inputbox('text', 'sched_time', $item->rawValue('sched_time')), 'label' => subscribe_model_Subscribe::fieldLabel('sched_time'), 'hint' => cot::$L['subscribe_sched_time_hint']), 'active' => array('element' => cot_checkbox($item->rawValue('active'), 'active', subscribe_model_Subscribe::fieldLabel('active'))), 'periodical' => array('element' => cot_checkbox($item->rawValue('periodical'), 'periodical', subscribe_model_Subscribe::fieldLabel('periodical'))), 'sort' => array('element' => cot_inputbox('text', 'sort', $item->rawValue('sort')), 'label' => subscribe_model_Subscribe::fieldLabel('sort'))); if (!empty($cot_extrafields[cot::$db->subscribe])) { // Extra fields for subscribe foreach ($cot_extrafields[cot::$db->subscribe] as $exfld) { $fName = $exfld['field_name']; $formElements[$fName] = array('element' => cot_build_extrafields($fName, $exfld, $item->rawValue($fName))); if ($exfld['field_type'] !== 'checkbox') { isset(cot::$L['subscribe_' . $exfld['field_name'] . '_title']) ? cot::$L['subscribe_' . $exfld['field_name'] . '_title'] : subscribe_model_Subscribe::fieldLabel($fName); } } } $subscribers = subscribe_model_Subscriber::count(array(array('subscribe', $item->id))); $activeSubscribers = subscribe_model_Subscriber::count(array(array('subscribe', $item->id), array('active', 1))); $actionParams = array('m' => 'subscribe', 'a' => 'edit'); if ($item->id > 0) { $actionParams['id'] = $item->id; } $template = array('subscribe', 'admin', 'edit'); $view = new View(); $view->page_title = $admintitle; $view->item = $item; $view->subscribers = $subscribers; $view->activeSubscribers = $activeSubscribers; $view->formElements = $formElements; $view->formAction = cot_url('admin', $actionParams); /* === Hook === */ foreach (cot_getextplugins('subscribe.admin.edit.view') as $pl) { include $pl; } /* ===== */ return $view->render($template); }
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(); }
/** * Запуск обработки очереди * php cli.php --a subscribe.main.runQueue > subscribeQueue.log * php /path/to/your/site/cli.php --a subscribe.main.runQueue > /path/to/your/site/log/subscribeQueue.log */ public function runQueueAction() { echo "---------------------------------------------------------------------------\n"; // Проверка процессов, выполнение которых могло завершиться ошибкой $pidFile = cot::$cfg['modules_dir'] . '/subscribe/inc/queue.txt'; if (!file_exists($pidFile)) { file_put_contents($pidFile, '0'); } if (!is_writeable($pidFile)) { echo "[ERROR] Can't set blocking. File '{$pidFile}' is not writable\n"; ob_flush(); exit; } $pingTime = intval(file_get_contents($pidFile)); if ($pingTime > 0 && cot::$sys['now'] - $pingTime < 300) { // 5 минут // Выполняется другой процесс echo "Other sending process is running\n"; ob_flush(); exit; } // Получаем список писем: $condition = array(); $limit = (int) cot::$cfg['subscribe']['queueCount']; // $items = subscribe_model_Queue::find($condition, $limit, 0, array(array('id', 'asc'))); // Сэкономим память. Ощутимо на большом количестве подписчиков if ($limit > 0) { $limit = "LIMIT {$limit}"; } $stmtItems = cot::$db->query("SELECT * FROM " . subscribe_model_Queue::tableName() . " ORDER BY `id` ASC {$limit}"); $count = $stmtItems->rowCount(); if (!$count) { echo "There are no emails to send at this time\n"; ob_flush(); exit; } echo "Emails count: " . $count . "\n"; // Реальная отправка писем $sender = new subscribe_sender_Cotmail(); /* === Hook === */ foreach (cot_getextplugins('subscribe.queue.run.main') as $pl) { include $pl; } /* ===== */ /* === Hook - Part1 : Set === */ $extp = cot_getextplugins('subscribe.queue.run.loop'); /* ===== */ $errors = 0; $i = 0; while ($item = $stmtItems->fetch()) { echo " - Processing: " . trim($item['name'] . ' ' . $item['email']) . " ..."; ob_flush(); $execute = true; /* === Hook - Part2 : Include === */ foreach ($extp as $pl) { include $pl; } /* ===== */ // Блокировка // Текущее системное время, а не то что было на момент старта скрипта file_put_contents($pidFile, time()); if ($execute) { $data = array('subscribe' => $item['subscribe'], 'subscriber' => $item['subscriber'], 'subject' => $item['subject'], 'fromName' => $item['from_name'], 'fromEmail' => $item['from_email'], 'toEmail' => $item['to_email'], 'toName' => $item['to_name'], 'body' => $item['body']); $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['to_email']}\n"; ob_flush(); // Зафиксировать в базе ошибку отправки сообщения if ($item['subscriber'] > 0) { $tmpData = array('last_error' => mb_substr("{$errCode}: {$errMsg}", 0, 253)); cot::$db->update(subscribe_model_Subscriber::tableName(), $tmpData, "id={$item['subscriber']}"); } echo "\n------------\n"; ob_flush(); } // Убираем обработанный элемент из очереди cot::$db->delete(subscribe_model_Queue::tableName(), "id={$item['id']}"); if (!$isError) { echo " done\n"; $i++; } unset($item); if ($i % 100 == 0) { gc_collect_cycles(); } } } $stmtItems->closeCursor(); // Освободим блокировку file_put_contents($pidFile, '0'); echo "{$i} letters send\n"; return ''; }
/** * Отписаться от рассылки */ public function unsubscribeAction() { $code = cot_import('code', 'G', 'TXT'); if (!$code) { cot_die_message('404'); } $title = cot::$L['subscribe_unsubscribe']; $subscriber = subscribe_model_Subscriber::fetchOne(array(array('unsubscr_code', $code))); if (!$subscriber) { cot_error(cot::$L['subscribe_err_wrong_unsubscribe_code']); } cot::$sys['sublocation'] = $title; cot::$out['subtitle'] = $title; if ($subscriber) { $title .= ': ' . $subscriber->subscribe->title; cot::$sys['sublocation'] = $title; cot::$out['subtitle'] = $title; $subscriber->active = 0; $subscriber->save(); cot_message(sprintf(cot::$L['subscribe_msg_you_unsubscribed'], $subscriber->subscribe->title)); } $template = array('subscribe', 'unsubscribe'); $view = new View(); $view->page_title = $title; $view->subscriber = $subscriber; /* === Hook === */ foreach (cot_getextplugins('subscribe.unsubscribe.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', 'n' => 'user'); 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; } } if (!$id) { cot_error(cot::$L['subscribe_err_subscriber_not_found']); cot_redirect(cot_url('admin', $backUrlParams)); } $item = subscribe_model_Subscriber::getById($id); if (!$item) { cot_error(cot::$L['subscribe_err_subscriber_not_found']); cot_redirect(cot_url('admin', $backUrlParams)); } $email = $item->email; $item->delete(); cot_message(sprintf(cot::$L['subscribe_subscriber_deleted'], $email)); cot_redirect(cot_url('admin', $backUrlParams, '', true)); }