private function getTemplateImages($templateid, $filename) { if (basename($filename) == 'powerphplist.png') { $templateid = 0; } $result = phpList::DB()->query(sprintf('SELECT data FROM %s WHERE template = %s AND (filename = "%s" or filename = "%s")', Config::getTableName('templateimage'), $templateid, $filename, basename($filename))); return $result->fetchColumn(0); }
/** * PHP >= 5.4.0<br/> * Write session data * @link http://php.net/manual/en/sessionhandlerinterafce.write.php * @param string $session_id The session id. * @param string $session_data <p> * The encoded session data. This data is the * result of the PHP internally encoding * the $_SESSION superglobal to a serialized * string and passing it as this parameter. * Please note sessions use an alternative serialization method. * </p> * @return bool <p> * The return value (usually TRUE on success, FALSE on failure). * Note this value is returned internally to PHP for processing. * </p> */ public function write($session_id, $session_data) { $session_id = addslashes($session_id); $session_data = addslashes($session_data); $session_exists = phpList::DB()->query(sprintf('SELECT COUNT(*) FROM %s WHERE sessionid = \'%s\'', Config::SESSION_TABLENAME, addslashes($session_id)))->fetchColumn(0); if ($session_exists <= 0) { $retval = phpList::DB()->query(sprintf('INSERT INTO %s (sessionid,lastactive,data) VALUES("%s",UNIX_TIMESTAMP(NOW()),"%s")', Config::SESSION_TABLENAME, $session_id, $session_data)); } else { $retval = phpList::DB()->query(sprintf('UPDATE %s SET data = "%s", lastactive = UNIX_TIMESTAMP(NOW()) WHERE sessionid = "%s"', Config::SESSION_TABLENAME, $session_id, $session_data)); if ($retval->rowCount() <= 0) { //TODO: correct error handling phpList::log()->notice('unable to update session data for session ' . $session_id); sendError('unable to update session data for session ' . $session_id); } } return $retval; }
/** * Porcess the bounce data and update the database * @param Bounce $bounce * @param int $campaign_id * @param Subscriber $subscriber * @return bool */ private function processBounceData($bounce, $campaign_id, $subscriber) { if ($campaign_id === 'systemmessage' && $subscriber !== false) { $bounce->status = 'bounced system message'; $bounce->comment = sprintf('%s marked unconfirmed', $subscriber->id); $bounce->update(); phpList::log()->notice($subscriber->id . ' ' . s('system message bounced, subscriber marked unconfirmed')); $subscriber->addHistory(s('Bounced system message'), sprintf('<br/>%s<br/><a href="./?page=bounce&id=%d">%s</a>', s('Subscriber marked unconfirmed'), $bounce->id, s('View Bounce')), $subscriber->id); $subscriber->confirmed = 0; $subscriber->update(); } elseif (!empty($campaign_id) && $subscriber !== false) { $bounce->connectMeToSubscriberAndMessage($subscriber, $campaign_id); } elseif ($subscriber !== false) { $bounce->status = 'bounced unidentified message'; $bounce->comment = $subscriber->id . ' bouncecount increased'; $bounce->update(); $subscriber->bouncecount++; $subscriber->update(); } elseif ($campaign_id === 'systemmessage') { $bounce->status = 'bounced system message'; $bounce->comment = 'unknown subscriber'; $bounce->update(); phpList::log()->notice($subscriber->id . ' ' . s('system message bounced, but unknown subscriber')); } elseif ($campaign_id) { $bounce->status = sprintf('bounced list message %d', $campaign_id); $bounce->comment = 'unknown subscriber'; $bounce->update(); phpList::DB()->query(sprintf('UPDATE %s SET bouncecount = bouncecount + 1 WHERE id = %d', Config::getTableName('message'), $campaign_id)); } else { $bounce->status = 'unidentified bounce'; $bounce->comment = 'not processed'; $bounce->update(); return false; } return true; }
/** * Check if a form token is valid * @param string $token * @return bool */ public function verifyToken($token) { if (empty($token)) { return false; } ## @@@TODO for now ignore the error. This will cause a block on editing admins if the table doesn't exist. $result = phpList::DB()->prepare(sprintf('SELECT id FROM %s WHERE adminid = %d AND value = :token AND expires > CURRENT_TIMESTAMP', Config::getTableName('admintoken'), $this->id)); $result->execute(array(':token' => $token)); return $result->rowCount() > 0; }
public static function releaseLock($processid) { if (!$processid) { return; } phpList::DB()->query('DELETE FROM %s WHERE id = %d', Config::getTableName('sendprocess'), $processid); }
public static function flushClickTrackCache() { if (count(Cache::$_instance->linktrack_sent_cache) == 0) { return; } foreach (Cache::$_instance->linktrack_sent_cache as $mid => $numsent) { foreach ($numsent as $fwdid => $fwdtotal) { if (Config::VERBOSE) { phpList::log()->debug("Flushing clicktrack stats for {$mid}: {$fwdid} => {$fwdtotal}", ['page' => 'cache']); } phpList::DB()->query(sprintf('UPDATE %s SET total = %d WHERE messageid = %d AND forwardid = %d', Config::getTableName('linktrack_ml'), $fwdtotal, $mid, $fwdid)); } } }
/** * 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; }
/** * Check if restrictions have been set * @param int $max * @return array */ private function checkRestrictions($max = 0) { $maxbatch = -1; $minbatchperiod = -1; # check for batch limits $restrictions = array(); $restrictions['rules'] = ''; $restrictions['locked'] = false; if ($fp = @fopen('/etc/phplist.conf', 'r')) { $contents = fread($fp, filesize('/etc/phplist.conf')); fclose($fp); $lines = explode("\n", $contents); $restrictions['rules'] = s('The following restrictions have been set by your ISP:') . "\n"; foreach ($lines as $line) { list($key, $val) = explode("=", $line); switch ($key) { case 'maxbatch': $maxbatch = sprintf('%d', $val); $restrictions['rules'] .= "{$key} = {$val}\n"; break; case 'minbatchperiod': $minbatchperiod = sprintf('%d', $val); $restrictions['rules'] .= "{$key} = {$val}\n"; break; case 'lockfile': $restrictions['locked'] = is_file($val); } } } if (Config::MAILQUEUE_BATCH_SIZE) { if ($maxbatch > 0) { $this->num_per_batch = min(Config::MAILQUEUE_BATCH_SIZE, $maxbatch); } else { $this->num_per_batch = sprintf('%d', Config::MAILQUEUE_BATCH_SIZE); } } else { if ($maxbatch > 0) { $this->num_per_batch = $maxbatch; } } if (Config::MAILQUEUE_BATCH_PERIOD) { if ($minbatchperiod > 0) { $this->batch_period = max(Config::MAILQUEUE_BATCH_PERIOD, $minbatchperiod); } else { $this->batch_period = Config::MAILQUEUE_BATCH_PERIOD; } } ## force batch processing in small batches when called from the web interface /* * bad idea, we shouldn't touch the batch settings, in case they are very specific for * ISP restrictions, instead limit webpage processing by time (below) * if (empty($GLOBALS['commandline'])) { $this->num_per_batch = min($this->num_per_batch,100); $this->batch_period = max($this->batch_period,1); } elseif (isset($cline['m'])) { $cl_num_per_batch = sprintf('%d',$cline['m']); ## don't block when the param is not a number if (!empty($cl_num_per_batch)) { $this->num_per_batch = $cl_num_per_batch; } Output::cl_output("Batch set with commandline to $this->num_per_batch"); } */ $max_process_queue_time = 0; if (Config::MAX_PROCESSQUEUE_TIME > 0) { $max_process_queue_time = (int) Config::MAX_PROCESSQUEUE_TIME; } # in-page processing force to a minute max, and make sure there's a batch size if (Config::get('commandline', false) === false) { $max_process_queue_time = min($max_process_queue_time, 60); if ($this->num_per_batch <= 0) { $this->num_per_batch = 10000; } } $restrictions['max_process_queue_time'] = $max_process_queue_time; if (Config::VERBOSE && $max_process_queue_time) { phpList::log()->debug(s('Maximum time for queue processing') . ': ' . $max_process_queue_time, ['page' => 'porcessqueue']); } if ($max > 0) { phpList::log()->info('Max to send is ' . $max . ' num per batch is ' . $this->num_per_batch, ['page' => 'processqueue']); $clinemax = (int) $max; ## slow down just before max if ($clinemax < 20) { $this->num_per_batch = min(2, $clinemax, $this->num_per_batch); } elseif ($clinemax < 200) { $this->num_per_batch = min(20, $clinemax, $this->num_per_batch); } else { $this->num_per_batch = min($clinemax, $this->num_per_batch); } phpList::log()->info('Max to send is ' . $max . ' setting num per batch to ' . $this->num_per_batch, ['page' => 'processqueue']); } if (ini_get('safe_mode')) { # keep an eye on timeouts $this->safemode = true; $this->num_per_batch = min(100, $this->num_per_batch); phpList::log()->notice(s('Running in safe mode') . "\n" . s('In safe mode, batches are set to a maximum of 100'), ['page' => 'processqueue']); } $recently_sent = 0; $this->original_num_per_batch = $this->num_per_batch; if ($this->num_per_batch && $this->batch_period) { # check how many were sent in the last batch period and subtract that # amount from this batch /* phpList::log()->debug(sprintf('select count(*) from %s where entered > date_sub(current_timestamp,interval %d second) and status = "sent"', $tables['usermessage'],$this->batch_period)); */ $result = phpList::DB()->query(sprintf('SELECT COUNT(*) FROM %s WHERE entered > date_sub(CURRENT_TIMESTAMP,INTERVAL %d second) AND status = "sent"', Config::getTableName('usermessage'), $this->batch_period)); $recently_sent = $result->fetchColumn(0); phpList::log()->info('Recently sent : ' . $recently_sent, ['page' => 'processqueue']); $this->num_per_batch -= $recently_sent; # if this ends up being 0 or less, don't send anything at all if ($this->num_per_batch == 0) { $this->num_per_batch = -1; } } $restrictions['recently_sent'] = $recently_sent; return $restrictions; }