* @copyright Since 2013 Ovidiu Cimpean * @license Do not edit, modify or copy this file * * @version Release: 4 */ class NewsletterProTask extends ObjectModel { public $id_newsletter_pro_smtp; public $id_newsletter_pro_tpl_history; public $date_start; public $date_modified; public $active; public $template; public $send_method; public $started; public $status; public $sleep; public $pause; public $emails_count; public $emails_error; public $emails_success; public $emails_completed; public $done; public $error_msg; /** * variables. */ private $log; private $num_sent = 0; /** * This variable is used into the function send proccess. * * @var object */ private $task_step; /** * 24000. */ const MAX_EXECUTION_TIME = 24000; const STATUS_DEFAULT = 0; const WRITE_LOG = 0; const STATUS_IN_PROGRESS = 1; public static $definition = [ 'table' => 'newsletter_pro_task', 'primary' => 'id_newsletter_pro_task', 'fields' => [ 'id_newsletter_pro_smtp' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true], 'id_newsletter_pro_tpl_history' => ['type' => self::TYPE_INT, 'validate' => 'isUnsignedId', 'required' => true], 'date_start' => ['type' => self::TYPE_DATE, 'validate' => 'isDateFormat'], 'date_modified' => ['type' => self::TYPE_DATE, 'validate' => 'isDateFormat'], 'active' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'template' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true], 'send_method' => ['type' => self::TYPE_STRING, 'validate' => 'isString', 'required' => true], 'started' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'status' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'sleep' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'pause' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'emails_count' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'emails_error' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'emails_success' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'emails_completed' => ['type' => self::TYPE_INT, 'validate' => 'isInt'], 'done' => ['type' => self::TYPE_BOOL, 'validate' => 'isBool'], 'error_msg' => ['type' => self::TYPE_HTML, 'validate' => 'isString'], ], ]; public function __construct($id = null) { // set defaults values $this->active = 1; $this->error_msg = serialize([]); $this->log = []; $this->one_mb = 1048576; $this->memory_limit = (int) ini_get('memory_limit') * $this->one_mb; $current_mem = memory_get_usage(true); if ((int) ini_get('memory_limit') <= 0) { $this->memory_limit = $current_mem + $this->one_mb * 24 + 1; } parent::__construct($id); if (Validate::isLoadedObject($this)) { $this->log(sprintf(NewsletterPro::getInstance()->l('Task id : %s'), $this->id)); $this->log(sprintf(NewsletterPro::getInstance()->l('Send method : %s'), $this->send_method)); $this->log(sprintf(NewsletterPro::getInstance()->l('Total emails : %s'), $this->emails_count)); $this->log(sprintf(NewsletterPro::getInstance()->l('Sent success : %s'), $this->emails_success)); $this->log(sprintf(NewsletterPro::getInstance()->l('Sent errors : %s'), $this->emails_error)); $this->log(sprintf(NewsletterPro::getInstance()->l('Sent completed : %s')."\n", $this->emails_completed)); } else { $this->log(NewsletterPro::getInstance()->l('No task has been loaded.')); } } public static function newInstance($id = null) { return new self($id); } public function add($autodate = true, $null_values = false) { return parent::add($autodate, $null_values); } public function update($null_values = false) { $this->date_modified = date('Y-m-d H:i:s'); return parent::update($null_values); } public function updateFields($fields = []) { $fields_default = [ 'date_modified' => pSQL(date('Y-m-d H:i:s')), ]; return Db::getInstance()->update('newsletter_pro_task', array_merge($fields_default, $fields), '`id_newsletter_pro_task` = '.(int) $this->id); } public function delete() { $evaluate = NewsletterProEvaluate::newInstance(); foreach ($this->getStepsIds() as $id) { $task_step = NewsletterProTaskStep::newInstance($id); $evaluate->add($task_step->delete()); } return parent::delete() && $evaluate->success(); } public function log($value) { $this->log[] = $value; } public function displayLog($separator = "\n") { echo '
';
echo join($separator, $this->log).$separator;
echo '';
return $this;
}
public function uniqueLog()
{
$this->log = array_unique($this->log);
return $this;
}
public function emptyLog()
{
$this->log = [];
return $this;
}
public function getStepsIds($step_active = false, $limit = 0)
{
$results = Db::getInstance()->executeS('
SELECT `id_newsletter_pro_task_step` FROM `'._DB_PREFIX_.'newsletter_pro_task_step`
WHERE `id_newsletter_pro_task` = '.(int) $this->id.'
'.($step_active ? ' AND `step_active` = 1' : '').'
ORDER BY `id_newsletter_pro_task_step`
'.($limit > 0 ? ' LIMIT '.(int) $limit : '').'
');
return array_map([$this, 'getStepsIdsCallback'], $results);
}
private function getStepsIdsCallback($row)
{
return !empty($row) ? $row['id_newsletter_pro_task_step'] : false;
}
/**
* @param DateTime|string|null $dateTime
*
* @return NewsletterProTask|false
*/
public static function getTask($dateTime = null)
{
if (is_null($dateTime)) {
$dateTime = new DateTime('now');
} else {
if (is_string($dateTime)) {
$dateTime = new DateTime($dateTime);
} elseif (!($dateTime instanceof DateTime)) {
throw new Exception('Invalid task date.');
}
}
$id = (int) Db::getInstance()->getValue('
SELECT `id_newsletter_pro_task` FROM `'._DB_PREFIX_.'newsletter_pro_task`
WHERE `date_start` <= "'.pSQL($dateTime->format('Y-m-d H:i:s')).'"
AND (
DATE(`date_start`) = "'.pSQL($dateTime->format('Y-m-d')).'" OR
`started` = 1
)
AND `active` = 1
AND `done` = 0
ORDER BY `date_start` ASC;
');
$task = new self($id);
if (Validate::isLoadedObject($task)) {
return $task;
}
return false;
}
/**
* Sent the task.
*
* @return int Number of newsletters sent
*/
public function send()
{
if (0 == (int) $this->started) {
$this->started = 1;
$this->update();
}
ignore_user_abort(true);
set_time_limit(0);
@ini_set('max_execution_time', self::MAX_EXECUTION_TIME);
register_shutdown_function([$this, 'sendShutdownFunctionCallback']);
$tlog = _NEWSLETTER_PRO_DIR_.'/logs/task.log';
// update task status
$this->status = self::STATUS_IN_PROGRESS;
$this->update();
$this->task_step = $this->getCurrentStep();
if ($this->task_step) {
$emails_to_send = $this->task_step->getEmailsToSend();
$emails_sent = $this->task_step->getEmailsSent();
foreach ($emails_to_send as $index => $email) {
if ((bool) pqnp_config('TASK_MEMORY_CHECK_ENABLED')) {
$current_mem = memory_get_usage(true);
if ($current_mem + $this->one_mb * 24 >= $this->memory_limit) {
exit('Exit during the memory limt. If the tasks don\'t start sending try to put this command "configuration -set TASK_MEMORY_CHECK_ENABLED 0" into the Terminal tab and press enter.');
exit;
}
}
if (!$this->taskExists()) {
exit;
}
if ($this->isTaskPaused()) {
exit;
}
$template = NewsletterProTemplate::newHistory($this->id_newsletter_pro_tpl_history, $email)->load();
if ($template->user) {
// exclude emails
$exclude_email = false;
$to_info = NewsletterProMail::getEmailInfo($template->user->to());
$to_email = $to_info['email'];
if (NewsletterProEmailExclusion::newInstance()->emailExists($to_email)) {
$exclude_email = true;
}
// build forwarders
$forward = NewsletterProSendManager::buildForward($this->id_newsletter_pro_tpl_history, 'history', $template->user->to());
$message = $template->message();
$title = $message['title'];
$body = $message['body'];
$send_manager = NewsletterProSendManager::getInstance();
$send_manager->setTemplateNameForAttachment($template->name);
try {
$send = $send_manager->sendNewsletter($title, $body, $template->user->to(), [
'user' => $template->user,
'id_smtp' => (int) $this->id_newsletter_pro_smtp,
'send_method' => $this->send_method,
], $forward, false, $exclude_email);
} catch (Exception $e) {
$send = [$e->getMessage()];
// $send = false;
}
if (!is_array($send) && true == $send) {
$emails_sent[] = [
'email' => $template->user->email,
'status' => true,
];
++$this->emails_success;
++$this->num_sent;
$this->log(NewsletterPro::getInstance()->l('Success').' : '.(string) $template->user->email);
if (self::WRITE_LOG) {
$msgSucc = NewsletterPro::getInstance()->l('Success').' : '.(string) $template->user->email;
if ($h = fopen($tlog, 'a+')) {
fwrite($h, date('Y-m-d H:i:s').' '.$msgSucc."\n");
fclose($h);
}
}
} else {
$emails_sent[] = [
'email' => $template->user->email,
'status' => false,
];
++$this->emails_error;
$this->appendError([
'smtp' => join('';
echo "\n";
echo NewsletterPro::getInstance()->l('PHP max execution time exceeded. Access the script again to continue the sending process.');
echo '';
} else {
echo $ob_content;
}
if (Validate::isLoadedObject($this)) {
$this->status = self::STATUS_DEFAULT;
$this->update();
}
if (isset($this->task_step) && Validate::isLoadedObject($this->task_step)) {
$this->task_step->update();
}
}
public function sendTaskAjax()
{
$errors = [];
if (NewsletterProTask::taskInProgress()) {
$errors[] = NewsletterPro::getInstance()->l('Cannot send multiple tasks in the same time.');
}
@ob_end_clean();
@ob_start();
echo Tools::jsonEncode([
'status' => empty($errors),
'errors' => $errors,
]);
$size = ob_get_length();
header("Content-Length: $size");
header('Connection: close');
@ob_end_flush();
@ob_flush();
flush();
if (session_id()) {
session_write_close();
}
if (empty($errors)) {
// run in background
$this->send();
}
}
public function isInProgress()
{
return $this->status;
}
/**
* The the current task step or the next step if the current step does not have emails addresses.
*
* @return object/boolean
*/
public function getCurrentStep()
{
$steps_id = $this->getStepsIds(true, 1);
if ($steps_id) {
$task_step = NewsletterProTaskStep::newInstance($steps_id[0]);
$emails_to_send = $task_step->getEmailsToSend();
if (empty($emails_to_send)) {
$task_step->step_active = 0;
// if there are no step emails, write step_active = 0
if ($task_step->update()) {
return $this->getCurrentStep();
}
} else {
return $task_step;
}
} else {
// if there are no steps, siable the task
$this->activ = 0;
$this->update();
}
return false;
}
/**
* Task exist.
*
* @param int $id
*
* @return int
*/
public function taskExists()
{
return Db::getInstance()->getValue(
'
SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `id_newsletter_pro_task`='.(int) $this->id
);
}
/**
* Is task paused.
*
* @param int $id
*
* @return bool
*/
public function isTaskPaused()
{
$this->pause = (int) Db::getInstance()->getValue(
'
SELECT `pause` FROM `'._DB_PREFIX_.'newsletter_pro_task` WHERE `id_newsletter_pro_task`='.(int) $this->id
);
return $this->pause;
}
private function appendError($error_msg)
{
$error_msg_db = NewsletterProTools::unSerialize($this->error_msg);
$error_msg_write = array_merge($error_msg_db, $error_msg);
$this->error_msg = serialize($error_msg_write);
return $this->update();
}
/**
* Task in progress.
*
* @return bool
*/
public static function taskInProgress()
{
return Db::getInstance()->getValue('
SELECT count(*) FROM `'._DB_PREFIX_.'newsletter_pro_task`
WHERE `status` = '.(int) self::STATUS_IN_PROGRESS.'
AND `done` = 0
') ? true : false;
}
public static function getTaskInProgress()
{
$task_id = (int) Db::getInstance()->getValue('
SELECT `id_newsletter_pro_task` FROM `'._DB_PREFIX_.'newsletter_pro_task`
WHERE `status` = '.(int) self::STATUS_IN_PROGRESS.'
AND `done` = 0
');
$task = NewsletterProTask::newInstance($task_id);
if (Validate::isLoadedObject($task)) {
if ($task->getCurrentStep()) {
return $task;
}
}
return false;
}
public function pauseTask()
{
return (int) Db::getInstance()->update('newsletter_pro_task', [
'pause' => 1,
], '`id_newsletter_pro_task` = '.(int) $this->id, 1);
}
public static function exportPrivacy($email)
{
$response = new NewsletterProPrivacyDataResponse(NewsletterProPrivacyDataResponse::TYPE_EXPORT, 'newsletter_pro_task', $email);
try {
// nothing to export
} catch (Exception $e) {
$response->addException($e);
}
return $response;
}
public static function privacySerach($email)
{
$response = new NewsletterProPrivacyDataResponse(NewsletterProPrivacyDataResponse::TYPE_SEARCH, 'newsletter_pro_task', $email);
try {
$count = (int) Db::getInstance()->getValue('
SELECT COUNT(*) FROM `'._DB_PREFIX_.'newsletter_pro_task`
WHERE `error_msg` REGEXP "'.pSQL(preg_quote($email)).'[^A-Za-z0-9]"
');
$response->addToCount($count);
} catch (Exception $e) {
$response->addException($e);
}
return $response;
}
public static function clearPrivacy($email)
{
$response = new NewsletterProPrivacyDataResponse(NewsletterProPrivacyDataResponse::TYPE_CLEAR, 'newsletter_pro_task', $email);
try {
if (Db::getInstance()->update('newsletter_pro_task', [
'error_msg' => serialize([]),
], '`error_msg` REGEXP "'.pSQL(preg_quote($email)).'[^A-Za-z0-9]"')) {
$response->addToCount(Db::getInstance()->Affected_Rows());
}
} catch (Exception $e) {
$response->addException($e);
}
return $response;
}
}