public static function sendReport($subject, $message) { $report_addresses = explode(',', Config::get('report_address')); foreach ($report_addresses as $address) { phpListMailer::sendMail($address, Config::get('installation_name') . ' ' . $subject, $message); } /*TODO: enable plugins foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->sendReport(Config::get('installation_name').' '.$subject,$message); }*/ }
/** * @throws \Exception */ public function startProcessing() { $this->preflightCheck(); # lets not do this unless we do some locking first register_shutdown_function(array(&$this, 'processBouncesShutdown')); ignore_user_abort(1); if (Config::get('commandline', false) !== false && Config::get('commandline_force', false) !== false) { # force set, so kill other processes phpList::log()->info('Force set, killing other send processes', ['page' => 'procesbounces']); $this->process_id = Process::getPageLock('BounceProcessor', true); } else { $this->process_id = Process::getPageLock('BounceProcessor'); } if (empty($this->process_id)) { return; } switch (Config::BOUNCE_PROTOCOL) { case 'pop': $this->processPop(Config::BOUNCE_MAILBOX_HOST, Config::BOUNCE_MAILBOX_USER, Config::BOUNCE_MAILBOX_PASSWORD); break; case 'mbox': $this->processMbox(Config::BOUNCE_MAILBOX); break; default: phpList::log()->critical(s('bounce_protocol not supported'), ['page' => 'processbounces']); return; } # now we have filled database with all available bounces ## reprocess the unidentified ones, as the bounce detection has improved, so it might catch more phpList::log()->info('reprocessing', ['page' => 'procesbounces']); $reparsed = $count = 0; $reidentified = 0; $result = phpList::DB()->query(sprintf('SELECT * FROM %s WHERE status = "unidentified bounce"', Config::getTableName('bounce'))); $total = $result->rowCount(); phpList::log()->info(s('%d bounces to reprocess', $total), ['page' => 'procesbounces']); while ($bounce = $result->fetch(\PDO::FETCH_ASSOC)) { $count++; if ($count % 25 == 0) { Output::cl_progress(s('%d out of %d processed', $count, $total)); } $bounceBody = $this->decodeBody($bounce->header, $bounce->data); $subscriber = $this->findSubscriber($bounceBody); $campaign_id = $this->findCampaignId($bounceBody); if ($subscriber !== false || !empty($campaign_id)) { $reparsed++; if ($this->processBounceData($bounce['id'], $campaign_id, $subscriber->id)) { $reidentified++; } } } phpList::log()->info(s('%d out of %d processed', $count, $total), ['page' => 'procesbounces']); if (Config::VERBOSE) { $this->output(s('%d bounces were re-processed and %d bounces were re-identified', $reparsed, $reidentified)); } $advanced_report = ''; if (Config::USE_ADVANCED_BOUNCEHANDLING) { $this->output(s('Processing bounces based on active bounce rules')); $bouncerules = BounceRule::getAllBounceRules(); $matched = 0; $notmatched = 0; //$limit = ' limit 10'; //$limit = ' limit 10000'; $limit = ''; # @@ not sure whether this one would make sense # $result = Sql_Query(sprintf('select * from %s as bounce, %s as umb,%s as user where bounce.id = umb.bounce # and user.id = umb.user and !user.confirmed and !user.blacklisted %s', # $GLOBALS['tables']['bounce'],$GLOBALS['tables']['user_message_bounce'],$GLOBALS['tables']['user'],$limit)); $result = phpList::DB()->query(sprintf('SELECT * FROM %s AS bounce, %s AS umb WHERE bounce.id = umb.bounce %s', Config::getTableName('bounce'), Config::getTableName('user_message_bounce'), $limit)); while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { $alive = Process::checkLock($this->process_id); if ($alive) { Process::keepLock($this->process_id); } else { $this->bounceProcessError(s('Process Killed by other process')); } # output('Subscriber '.$row['user']); $rule = BounceRule::matchedBounceRules($row['data'], $bouncerules); # output('Action '.$rule['action']); # output('Rule'.$rule['id']); if ($rule && is_array($rule)) { if ($row['user']) { $subscriber = Subscriber::getSubscriber($row['user']); } $report_linkroot = Config::get('admin_scheme') . '://' . Config::get('website') . Config::get('adminpages'); phpList::DB()->query(sprintf('UPDATE %s SET count = count + 1 WHERE id = %d', Config::getTableName('bounceregex'), $rule['id'])); phpList::DB()->query(sprintf('INSERT IGNORE INTO %s (regex,bounce) VALUES(%d,%d)', Config::getTableName('bounceregex_bounce'), $rule['id'], $row['bounce'])); switch ($rule['action']) { case 'deletesubscriber': phpList::log()->notice('Subscriber ' . $subscriber->getEmailAddress() . ' deleted by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' deleted by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->delete(); break; case 'unconfirmsubscriber': phpList::log()->notice('Subscriber ' . $subscriber->getEmailAddress() . ' unconfirmed by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $subscriber->confirmed = 0; $subscriber->update(); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' made unconfirmed by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->addHistory(s('Auto Unconfirmed'), s('Subscriber auto unconfirmed for') . " " . s('bounce rule') . ' ' . $rule['id'], $subscriber->id); Util::addSubscriberStatistics('auto unsubscribe', 1); break; case 'deletesubscriberandbounce': phpList::log()->notice('Subscriber ' . $row['user'] . ' deleted by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' deleted by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->delete(); Bounce::deleteBounce($row['bounce']); break; case 'unconfirmsubscriberanddeletebounce': phpList::log()->notice('Subscriber ' . $subscriber->getEmailAddress() . ' unconfirmed by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $subscriber->confirmed = 0; $subscriber->update(); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' made unconfirmed by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->addHistory(s('Auto unconfirmed'), s('Subscriber auto unconfirmed for') . " " . s("bounce rule") . ' ' . $rule['id'], $subscriber->id); Util::addSubscriberStatistics('auto unsubscribe', 1); Bounce::deleteBounce($row['bounce']); break; case 'blacklistsubscriber': phpList::log()->notice('Subscriber ' . $subscriber->getEmailAddress() . ' blacklisted by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $subscriber->blacklistSubscriber($subscriber->getEmailAddress(), s("Auto Blacklisted"), s("Subscriber auto blacklisted for") . " " . s("bounce rule") . ' ' . $rule['id']); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' blacklisted by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->addHistory(s("Auto Unsubscribed"), s("Subscriber auto unsubscribed for") . " " . s("bounce rule") . ' ' . $rule['id'], $subscriber->id); Util::addSubscriberStatistics('auto blacklist', 1); break; case 'blacklistsubscriberanddeletebounce': phpList::log()->notice('Subscriber ' . $subscriber->getEmailAddress() . ' blacklisted by bounce rule ' . PageLink2('bouncerule&id=' . $rule['id'], $rule['id'])); $subscriber->blacklistSubscriber($subscriber->getEmailAddress(), s("Auto Blacklisted"), s("Subscriber auto blacklisted for") . " " . s("bounce rule") . ' ' . $rule['id']); $advanced_report .= 'Subscriber ' . $subscriber->getEmailAddress() . ' blacklisted by bounce rule ' . $rule['id'] . "\n"; $advanced_report .= 'Subscriber: ' . $report_linkroot . '/?page=subscriber&id=' . $subscriber->id . "\n"; $advanced_report .= 'Rule: ' . $report_linkroot . '/?page=bouncerule&id=' . $rule['id'] . "\n"; $subscriber->addHistory(s("Auto Unsubscribed"), s("Subscriber auto unsubscribed for") . " " . s("bounce rule") . ' ' . $rule['id'], $subscriber->id); Util::addSubscriberStatistics('auto blacklist', 1); Bounce::deleteBounce($row['bounce']); break; case 'deletebounce': Bounce::deleteBounce($row['bounce']); break; } $matched++; } else { $notmatched++; } } $this->output($matched . ' ' . s('bounces processed by advanced processing')); $this->output($notmatched . ' ' . s('bounces were not matched by advanced processing rules')); } # have a look who should be flagged as unconfirmed $this->output(s("Identifying consecutive bounces")); # we only need subscriber who are confirmed at the moment $subscriberid_result = phpList::DB()->query(sprintf('SELECT DISTINCT umb.user FROM %s AS umb, %s AS u WHERE u.id = umb.user AND u.confirmed', Config::getTableName('user_message_bounce'), Config::getTableName('user', true))); if ($subscriberid_result->rowCount() <= 0) { $this->output(s("Nothing to do")); } $subscribercnt = 0; $unsubscribed_subscribers = ""; while ($subscriber = $subscriberid_result->fetch(\PDO::FETCH_ASSOC)) { Process::keepLock($this->process_id); set_time_limit(600); $msg_req = phpList::DB()->query(sprintf('SELECT * FROM %s AS um LEFT JOIN %s AS umb ON (um.messageid = umb.message AND userid = user) WHERE userid = %d AND um.status = "sent" ORDER BY entered DESC', Config::getTableName('usermessage'), Config::getTableName('user_message_bounce'), $subscriber[0])); /* $cnt = 0; $alive = 1;$removed = 0; while ($alive && !$removed && $bounce = Sql_Fetch_Array($msg_req)) { $alive = checkLock($process_id); if ($alive) keepLock($process_id); else ProcessError(s("Process Killed by other process")); if (sprintf('%d',$bounce['bounce']) == $bounce['bounce']) { $cnt++; if ($cnt >= $bounce_unsubscribe_threshold) { $removed = 1; output(sprintf('unsubscribing %d -> %d bounces',$subscriber[0],$cnt)); $subscriberurl = PageLink2("user&id=$subscriber[0]",$subscriber[0]); logEvent(s("Subscriber")." $subscriberurl ".s("has consecutive bounces")." ($cnt) ".s("over threshold, user marked unconfirmed")); $emailreq = Sql_Fetch_Row_Query("select email from {$tables['user']} where id = $subscriber[0]"); addSubscriberHistory($emailreq[0],s("Auto Unsubscribed"),s("Subscriber auto unsubscribed for")." $cnt ".s("consecutive bounces")); Sql_Query(sprintf('update %s set confirmed = 0 where id = %d',$tables['user'],$subscriber[0])); addSubscriberStatistics('auto unsubscribe',1); $email_req = Sql_Fetch_Row_Query(sprintf('select email from %s where id = %d',$tables['user'],$subscriber[0])); $unsubscribed_users .= $email_req[0] . " [$subscriber[0]] ($cnt)\n"; } } elseif ($bounce['bounce'] == "") { $cnt = 0; } }*/ #$alive = 1;$removed = 0; DT 051105 $cnt = 0; $alive = 1; $removed = $msgokay = $unconfirmed = $unsubscribed = 0; #while ($alive && !$removed && $bounce = Sql_Fetch_Array($msg_req)) { DT 051105 while ($alive && !$removed && !$msgokay && ($bounce = $msg_req->fetch(\PDO::FETCH_ASSOC))) { $alive = Process::checkLock($this->process_id); if ($alive) { Process::keepLock($this->process_id); } else { $this->bounceProcessError('Process Killed by other process'); } if (sprintf('%d', $bounce['bounce']) == $bounce['bounce']) { $cnt++; if ($cnt >= Config::BOUNCE_UNSUBSCRIBE_THRESHOLD) { if (!$unsubscribed) { $this->output(sprintf('unsubscribing %d -> %d bounces', $subscriber[0], $cnt)); $subscriberurl = PageLink2("user&id={$subscriber['0']}", $subscriber[0]); phpList::log()->notice(s('Subscriber (url:%s) has consecutive bounces (%d) over threshold (%d), user marked unconfirmed', $subscriberurl, $cnt, Config::BOUNCE_UNSUBSCRIBE_THRESHOLD)); Subscriber::addHistory(s('Auto Unconfirmed'), s('Subscriber auto unconfirmed for %d consecutive bounces', $cnt), $subscriber[0]); phpList::DB()->query(sprintf('UPDATE %s SET confirmed = 0 WHERE id = %d', Config::getTableName('user', true), $subscriber[0])); $email_req = phpList::DB()->query(sprintf('SELECT email FROM %s WHERE id = %d', Config::getTableName('user', true), $subscriber[0])); $unsubscribed_subscribers .= $email_req[0] . "\t\t({$cnt})\t\t" . Config::get('scheme') . '://' . Config::get('website') . Config::get('adminpages') . '/?page=user&id=' . $subscriber[0] . "\n"; $unsubscribed = 1; } if (Config::get('BLACKLIST_EMAIL_ON_BOUNCE') && $cnt >= Config::get('BLACKLIST_EMAIL_ON_BOUNCE')) { $removed = 1; #0012262: blacklist email when email bounces phpList::log()->info(s('%d consecutive bounces, threshold reached, blacklisting subscriber', $cnt), ['page' => 'procesbounces']); Subscriber::blacklistSubscriber($subscriber[0], s('%d consecutive bounces, threshold reached', $cnt)); } } } elseif ($bounce['bounce'] == '') { #$cnt = 0; DT 051105 $cnt = 0; $msgokay = 1; #DT 051105 - escaping loop if message received okay } } if ($subscribercnt % 5 == 0) { # output(s("Identifying consecutive bounces")); phpList::log()->info(s('processed %d out of %d subscribers', $subscribercnt, $total), ['page' => 'procesbounces']); } $subscribercnt++; } #output(s("Identifying consecutive bounces")); $this->output("\n" . s('total of %d subscribers processed', $total) . ' '); /* $report = ''; if (phpList::log()->getReport()) { $report .= s('Report:')."\n" . phpList::log()->getReport() . "\n"; } if ($advanced_report) { $report .= s('Report of advanced bounce processing:')."\n$advanced_report\n"; } if ($unsubscribed_subscribers) { $report .= "\n".s('Below are subscribers who have been marked unconfirmed. The in () is the number of consecutive bounces.')."\n"; $report .= "\n$unsubscribed_subscribers"; } else { # don't send a report email, if only some bounces were downloaded, but no subscribers unsubscribed. $report = ''; } # shutdown will take care of reporting #finish("info",$report); */ # IMAP errors following when Notices are on are a PHP bug # http://bugs.php.net/bug.php?id=7207 }
/** * Delete expired tokens from the database */ public static function deleteOldTokens() { phpList::DB()->query(sprintf('DELETE FROM %s WHERE date_add( date, INTERVAL %s) < CURRENT_TIMESTAMP', Config::getTableName('admin_password_request'), Config::get('password_change_timeframe')), 1); phpList::DB()->query(sprintf('DELETE FROM %s WHERE expires < CURRENT_TIMESTAMP', Config::getTableName('admintoken')), 1); }
public static function getPageLock($page, $force = false) { $commandline = Config::get('commandline', false); if ($commandline && $page == 'processqueue') { //TODO: implement memcached_enabled config if (Config::get('memcached_enabled', false)) { ## multi-send requires a valid memcached setup $max = Config::get('MAX_SENDPROCESSES'); } else { $max = 1; } } else { $max = 1; } ## allow killing other processes if ($force) { phpList::DB()->query(sprintf('DELETE FROM %s WHERE page = "%s"', Config::getTableName('sendprocess'), $page)); } $running_processes = self::getRunningProcesses($page); phpList::log()->info($running_processes['count'] . ' out of ' . $max . ' active processes', ['page' => 'process']); $waited = 0; # while ($running_res['age'] && $count >= $max) { # a process is already running while ($running_processes['count'] >= $max) { # don't check age, as it may be 0 # cl_output('running process: '.$running_res['age'].' '.$max); if ($running_processes['result']['age'] > 600) { # some sql queries can take quite a while #cl_output($running_res['id'].' is old '.$running_res['age']); # process has been inactive for too long, kill it phpList::DB()->query(sprintf('UPDATE %s SET alive = 0 WHERE id = %d', Config::getTableName('sendprocess'), $running_processes['result']['id'])); } elseif ((int) $running_processes['count'] >= (int) $max) { phpList::log()->log(sprintf(s('A process for this page is already running and it was still alive %s seconds ago'), $running_processes['result']['age']), ['page' => 'process']); sleep(1); # to log the messages in the correct order if ($commandline) { phpList::log()->info(s('Running commandline, quitting. We\'ll find out what to do in the next run.'), ['page' => 'process']); exit; } phpList::log()->info(s('Sleeping for 20 seconds, aborting will quit'), ['page' => 'process']); flush(); ignore_user_abort(0); sleep(20); } $waited++; if ($waited > 10) { # we have waited 10 cycles, abort and quit script phpList::log()->info(s('We have been waiting too long, I guess the other process is still going ok'), ['page' => 'process']); return false; } } $processIdentifier = $_SERVER['REMOTE_ADDR']; if ($commandline) { $processIdentifier = Config::get('SENDPROCESS_SERVERNAME') . ':' . getmypid(); } phpList::DB()->query(sprintf('INSERT INTO %s (started, page, alive, ipaddress) VALUES(CURRENT_TIMESTAMP, "%s", 1, "%s")', Config::getTableName('sendprocess'), $page, $processIdentifier)); $send_process_id = phpList::DB()->insertedId(); ignore_user_abort(1); # cl_output('Got pagelock '.$send_process_id ); return $send_process_id; }
/** * Load campaign in memory cache * @param Campaign $campaign * @param bool $forwardContent * @return bool */ public static function precacheCampaign($campaign, $forwardContent = false) { $domain = Config::get('domain'); /** * @var Campaign $cached_campaign */ $cached_campaign =& Cache::getCachedCampaign($campaign); ## the reply to is actually not in use if (preg_match('/([^ ]+@[^ ]+)/', $campaign->replyto, $regs)) { # if there is an email in the from, rewrite it as "name <email>" $campaign->replyto = str_replace($regs[0], '', $campaign->replyto); $cached_campaign->replytoemail = $regs[0]; # if the email has < and > take them out here $cached_campaign->replytoemail = str_replace(array('<', '>'), '', $cached_campaign->replytoemail); //$cached->replytoemail = str_replace('>', '', $cached->replytoemail); # make sure there are no quotes around the name $cached_campaign->replytoname = str_replace('"', '', ltrim(rtrim($campaign->replyto))); } elseif (strpos($campaign->replyto, ' ')) { # if there is a space, we need to add the email $cached_campaign->replytoname = $campaign->replyto; $cached_campaign->replytoemail = "listmaster@{$domain}"; } else { if (!empty($campaign->replyto)) { $cached_campaign->replytoemail = "{$campaign->replyto}@{$domain}"; ## makes more sense not to add the domain to the word, but the help says it does ## so let's keep it for now $cached_campaign->replytoname = "{$campaign->replyto}@{$domain}"; } } //$cached_campaign->fromname = $campaign->fromname; //$cached_campaign->fromemail = $campaign->fromemail; $cached_campaign->to = $campaign->tofield; #0013076: different content when forwarding 'to a friend' $cached_campaign->subject = $forwardContent ? stripslashes($campaign->forwardsubject) : $campaign->subject; #0013076: different content when forwarding 'to a friend' $cached_campaign->content = $forwardContent ? stripslashes($campaign->forwardcampaign) : $campaign->campaign; if (Config::USE_MANUAL_TEXT_PART && !$forwardContent) { $cached_campaign->textcontent = $campaign->textcampaign; } else { $cached_campaign->textcontent = ''; } #var_dump($cached);exit; #0013076: different content when forwarding 'to a friend' $cached_campaign->footer = $forwardContent ? stripslashes($campaign->forwardfooter) : $campaign->footer; if (strip_tags($cached_campaign->footer) != $cached_campaign->footer) { $cached_campaign->textfooter = String::HTML2Text($cached_campaign->footer); $cached_campaign->htmlfooter = $cached_campaign->footer; } else { $cached_campaign->textfooter = $cached_campaign->footer; $cached_campaign->htmlfooter = PrepareCampaign::parseText($cached_campaign->footer); } $cached_campaign->htmlformatted = strip_tags($cached_campaign->content) != $cached_campaign->content; //$cached_campaign->sendformat = $campaign->sendformat; ## @@ put this here, so it can become editable per email sent out at a later stage $cached_campaign->html_charset = 'UTF-8'; #Config::get('html_charset'); ## @@ need to check on validity of charset /*if (!$cached_campaign->html_charset) { $cached_campaign->html_charset = 'UTF-8'; #'iso-8859-1'; }*/ $cached_campaign->text_charset = 'UTF-8'; #Config::get('text_charset'); /*if (!$cached_campaign->text_charset) { $cached_campaign->text_charset = 'UTF-8'; #'iso-8859-1'; }*/ ## if we are sending a URL that contains subscriber attributes, we cannot pre-parse the campaign here ## but that has quite some impact on speed. So check if that's the case and apply $cached_campaign->subscriberspecific_url = preg_match('/\\[.+\\]/', $campaign->sendurl); if (!$cached_campaign->subscriberspecific_url) { ## Fetch external content here, because URL does not contain placeholders if (Config::get('canFetchUrl') && preg_match('/\\[URL:([^\\s]+)\\]/i', $cached_campaign->content, $regs)) { $remote_content = Util::fetchUrl($regs[1]); # $remote_content = fetchUrl($campaign['sendurl'],array()); # @@ don't use this # $remote_content = includeStyles($remote_content); if ($remote_content) { $cached_campaign->content = str_replace($regs[0], $remote_content, $cached_campaign->content); # $cached[$campaign_id]['content'] = $remote_content; $cached_campaign->htmlformatted = strip_tags($remote_content) != $remote_content; } else { #print Error(s('unable to fetch web page for sending')); phpList::log()->notice("Error fetching URL: " . $campaign->sendurl . ' cannot proceed'); return false; } } if (Config::VERBOSE && Config::get('getspeedstats', false) !== false) { phpList::log()->debug('fetch URL end', ['page' => 'preparecampaign']); } /* print $campaign->sendurl; print $remote_content;exit; */ } // end if not subscriberspecific url /*if ($cached_campaign->htmlformatted) { # $cached->content = String::compressContent($cached->content); }*/ //$cached_campaign->google_track = $campaign->google_track; /* else { print $campaign->sendurl; exit; } */ if (Config::VERBOSE && Config::get('getspeedstats', false) !== false) { phpList::log()->debug('parse config start', ['page' => 'preparecampaign']); } /* * this is not a good idea, as it'll replace eg "unsubscribeurl" with a general one instead of personalised * if (is_array($GLOBALS['default_config'])) { foreach($GLOBALS['default_config'] as $key => $val) { if (is_array($val)) { $cached[$campaign_id]['content'] = str_ireplace("[$key]",Config::get($key),$cached[$campaign_id]['content']); $cached->textcontent = str_ireplace("[$key]",Config::get($key),$cached->textcontent); $cached->textfooter = str_ireplace("[$key]",Config::get($key),$cached[$campaign_id]['textfooter']); $cached->htmlfooter = str_ireplace("[$key]",Config::get($key),$cached[$campaign_id]['htmlfooter']); } } } */ if (Config::VERBOSE && Config::get('getspeedstats', false) !== false) { phpList::log()->debug('parse config end', ['page' => 'preparecampaign']); } /*TODO: figure out what this does foreach ($campaign as $key => $val) { if (!is_array($val)) { $cached_campaign->content = str_ireplace("[$key]", $val, $cached_campaign->content); $cached_campaign->textcontent = str_ireplace("[$key]", $val, $cached_campaign->textcontent); $cached_campaign->textfooter = str_ireplace("[$key]", $val, $cached_campaign->textfooter); $cached_campaign->htmlfooter = str_ireplace("[$key]", $val, $cached_campaign->htmlfooter); } }*/ if (preg_match("/##LISTOWNER=(.*)/", $cached_campaign->content, $regs)) { $cached_campaign->listowner = $regs[1]; $cached_campaign->content = str_replace($regs[0], '', $cached_campaign->content); } else { $cached_campaign->listowner = 0; } if (!empty($cached_campaign->listowner)) { $att_result = phpList::DB()->query(sprintf('SELECT name,value FROM %s AS aa, %s AS a_a WHERE aa.id = a_a.adminattributeid AND aa.adminid = %d', Config::getTableName('adminattribute'), Config::getTableName('admin_attribute'), $cached_campaign->listowner)); while ($att = $att_result->fetch(\PDO::FETCH_ASSOC)) { $cached_campaign->content = preg_replace('#\\[LISTOWNER.' . strtoupper(preg_quote($att['name'])) . '\\]#', $att['value'], $cached_campaign->content); } } $baseurl = Config::get('website'); if (Config::UPLOADIMAGES_DIR != null) { ## escape subdirectories, otherwise this renders empty $dir = str_replace('/', '\\/', Config::UPLOADIMAGES_DIR); $cached_campaign->content = preg_replace('/<img(.*)src="\\/' . $dir . '(.*)>/iU', '<img\\1src="' . Config::get('public_scheme') . '://' . $baseurl . '/' . Config::UPLOADIMAGES_DIR . '\\2>', $cached_campaign->content); } //if (defined('FCKIMAGES_DIR') && FCKIMAGES_DIR) { //$cached[$campaign_id]['content'] = preg_replace('/<img(.*)src="\/lists\/'.FCKIMAGES_DIR.'(.*)>/iU','<img\\1src="'.$GLOBALS['public_scheme'].'://'.$baseurl.'/lists/'.FCKIMAGES_DIR.'\\2>',$cached[$campaign_id]['content']); //} return true; }
/** * Shutdown function for execution on shutdown * @link http://php.net/manual/en/function.register-shutdown-function.php */ public function shutdown() { # phpList::log()->debug( "Script status: ".connection_status(), ['page' => 'porcessqueue']); # with PHP 4.2.1 buggy. http://bugs.php.net/bug.php?id=17774 phpList::log()->debug(s('Script stage') . ': ' . $this->script_stage, ['page' => 'porcessqueue']); $some = $this->processed; #$this->sent;# || $this->invalid || $this->notsent; if (!$some) { phpList::log()->debug(s('Finished, Nothing to do'), ['page' => 'porcessqueue']); $this->nothingtodo = 1; } $totaltime = Timer::get('process_queue')->elapsed(true); if ($totaltime > 0) { $msgperhour = 3600 / $totaltime * $this->sent; } else { $msgperhour = s('Calculating'); } if ($this->sent) { phpList::log()->debug(sprintf('%d %s %01.2f %s (%d %s)', $this->sent, s('campaigns sent in'), $totaltime, s('seconds'), $msgperhour, s('msgs/hr')), ['page' => 'processqueue']); } if ($this->invalid > 0) { phpList::log()->debug(s('%d invalid email addresses', $this->invalid), ['page' => 'porcessqueue']); } if ($this->failed_sent > 0) { phpList::log()->debug(s('%d failed (will retry later)', $this->failed_sent), ['page' => 'porcessqueue']); foreach ($this->counters as $label => $value) { # phpList::log()->debug(sprintf('%d %s',$value,s($label)),1,'progress', ['page' => 'porcessqueue']); phpList::log()->info(sprintf('%d %s', $value, s($label)), ['page' => 'processqueue']); } } if ($this->unconfirmed > 0) { phpList::log()->debug(sprintf(s('%d emails unconfirmed (not sent)'), $this->unconfirmed), ['page' => 'porcessqueue']); } /* * TODO: enable plugins foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->processSendStats($this->sent,$this->invalid,$this->failed_sent,$this->unconfirmed,$this->counters); } */ Cache::flushClickTrackCache(); Process::releaseLock($this->send_process_id); //finish("info",$report,$this->script_stage); //function finish ($flag,$campaign,$this->script_stage) { $subject = s('Maillist Processing info'); if (!$this->nothingtodo) { phpList::log()->info(s('Finished this run'), ['page' => 'progress']); phpList::log()->info(s('%s of %s done', $this->sent, $this->counters['total_subscribers_for_campaign ' . $this->current_campaign->id]), ['page' => 'progress']); } //TODO:enable plugins /* if (!Config::TEST && !$this->nothingtodo && Config::get(('END_QUEUE_PROCESSING_REPORT'))) { foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->sendReport($subject,$campaign); } } */ if ($this->script_stage < 5 && !$this->nothingtodo) { phpList::log()->info(s('Warning: script never reached stage 5') . "\n" . s('This may be caused by a too slow or too busy server') . " \n"); //TODO: remove globals } elseif ($this->script_stage == 5 && (!$this->nothingtodo || isset($GLOBALS['wait']))) { # if the script timed out in stage 5, reload the page to continue with the rest $this->reload++; if (!Config::get('commandline') && $this->num_per_batch && $this->batch_period) { if ($this->sent + 10 < $this->original_num_per_batch) { phpList::log()->debug(s('Less than batch size were sent, so reloading imminently'), ['page' => 'porcessqueue']); $delaytime = 10; } else { // TODO: we should actually want batch period minus time already spent. // might be nice to calculate that at some point phpList::log()->info(sprintf(s('Waiting for %d seconds before reloading'), $this->batch_period), ['page' => 'processqueue']); $delaytime = $this->batch_period; } sleep($delaytime); /*Output::customPrintf( '<script type="text/javascript"> document.location = "./?page=pageaction&action=processqueue&ajaxed=true&reload=%d&lastsent=%d&lastskipped=%d"; </script>', $this->reload, $this->sent, $this->notsent );*/ } else { /*Output::customPrintf( '<script type="text/javascript"> document.location = "./?page=pageaction&action=processqueue&ajaxed=true&reload=%d&lastsent=%d&lastskipped=%d"; </script>', $this->reload, $this->sent, $this->notsent );*/ } } elseif ($this->script_stage == 6 || $this->nothingtodo) { /* * TODO: enable plugins foreach ($GLOBALS['plugins'] as $pluginname => $plugin) { $plugin->campaignQueueFinished(); }*/ phpList::log()->debug(s('Finished, All done'), 0, ['page' => 'porcessqueue']); } else { phpList::log()->debug(s('Script finished, but not all campaigns have been sent yet.'), ['page' => 'porcessqueue']); } if (!Config::get('commandline') && empty($_GET['ajaxed'])) { include_once "footer.inc"; } elseif (Config::get('commandline')) { @ob_end_clean(); } exit; }