/** * @param string $password * Will encrypt and set the password * and update db when changing the password of * an existing admin */ public function setPassword($password) { $this->password = Util::encryptPass($password); if ($this->id != 0) { phpList::DB()->query(sprintf('UPDATE %s SET password = "******", passwordchanged = CURRENT_TIMESTAMP WHERE id = %s', Config::getTableName('admin'), $this->password, $this->id)); } }
/** * Load additional data for this campaign * @param CampaignEntity $campaign */ private function loadCampaignData(CampaignEntity &$campaign) { $default = array('google_track' => $this->config->get('always_add_googletracking')); ## when loading an old campaign that hasn't got data stored in campaign data, load it from the campaign table $prevMsgData = $this->db->query(sprintf('SELECT * FROM %s WHERE id = %d', $this->config->getTableName('message'), $campaign->id))->fetch(\PDO::FETCH_ASSOC); $campaigndata = array('template' => $this->config->get('defaultmessagetemplate'), 'sendformat' => 'HTML', 'message' => '', 'forwardmessage' => '', 'textmessage' => '', 'rsstemplate' => '', 'embargo' => new \DateTime(), 'repeatinterval' => 0, 'repeatuntil' => new \DateTime(), 'requeueinterval' => 0, 'requeueuntil' => new \DateTime(), 'finishsending' => date_create(time() + $this->config->get('DEFAULT_MESSAGEAGE')), 'fromfield' => '', 'subject' => '', 'forwardsubject' => '', 'footer' => $this->config->get('messagefooter'), 'forwardfooter' => $this->config->get('forwardfooter'), 'status' => '', 'tofield' => '', 'replyto' => '', 'targetlist' => '', 'criteria_match' => '', 'sendurl' => '', 'sendmethod' => 'inputhere', 'testtarget' => '', 'notify_start' => $this->config->get('notifystart_default'), 'notify_end' => $this->config->get('notifyend_default'), 'google_track' => $default['google_track'] == 'true' || $default['google_track'] === true || $default['google_track'] == '1', 'excludelist' => array()); if (is_array($prevMsgData)) { foreach ($prevMsgData as $key => $val) { $campaigndata[$key] = $val; } } $result = $this->db->query(sprintf('SELECT * FROM %s WHERE id = %d', $this->config->getTableName('messagedata'), $campaign->id)); while ($row = $result->fetch(\PDO::FETCH_ASSOC)) { if (strpos($row['data'], 'SER:') === 0) { $data = substr($row['data'], 4); $data = @unserialize(stripslashes($data)); } else { $data = stripslashes($row['data']); } if (!in_array($row['name'], array('astext', 'ashtml', 'astextandhtml', 'aspdf', 'astextandpdf'))) { ## don't overwrite counters in the campaign table from the data table $campaigndata[stripslashes($row['name'])] = $data; } } /*Is a DateTime object now * foreach (array('embargo','repeatuntil','requeueuntil') as $datefield) { if (!is_array($campaigndata[$datefield])) { $campaigndata[$datefield] = array('year' => date('Y'),'month' => date('m'),'day' => date('d'),'hour' => date('H'),'minute' => date('i')); } }*/ // Load lists that were targetted with campaign... $result = $this->db->query(sprintf('SELECT list.name,list.id FROM %s AS listmessage, %s AS list WHERE listmessage.messageid = %d AND listmessage.listid = list.id', $this->config->getTableName('listmessage'), $this->config->getTableName('list'), $campaign->id)); while ($lst = $result->fetch(\PDO::FETCH_ASSOC)) { $campaigndata['targetlist'][$lst['id']] = 1; } ## backwards, check that the content has a url and use it to fill the sendurl if (empty($campaigndata['sendurl'])) { ## can't do "ungreedy matching, in case the URL has placeholders, but this can potentially ## throw problems if (preg_match('/\\[URL:(.*)\\]/i', $campaigndata['message'], $regs)) { $campaigndata['sendurl'] = $regs[1]; } } if (empty($campaigndata['sendurl']) && !empty($campaigndata['message'])) { # if there's a message and no url, make sure to show the editor, and not the URL input $campaigndata['sendmethod'] = 'inputhere'; } ### parse the from field into it's components - email and name $parsed_email = Util::parseEmailAndName($campaigndata['fromname'], $this->config->get('message_from_address', $this->config->get('admin_address'))); $campaigndata['fromname'] = $parsed_email['name']; $campaigndata['fromemail'] = $parsed_email['email']; ## if the name ends up being empty, copy the email if (empty($campaigndata['fromname'])) { $campaigndata['fromname'] = $campaigndata['fromemail']; } if (!empty($campaigndata['targetlist']['unselect'])) { unset($campaigndata['targetlist']['unselect']); } if (!empty($campaigndata['excludelist']['unselect'])) { unset($campaigndata['excludelist']['unselect']); } $campaign->campaigndata = $campaigndata; }
public static function sendMail($to, $subject, $message, $skipblacklistcheck = 0) { if (Config::TEST) { return 1; } # do a quick check on mail injection attempt, @@@ needs more work if (preg_match("/\n/", $to)) { //TODO: convert to new logger phpList::log()->notice('Error: invalid recipient, containing newlines, email blocked'); return 0; } if (preg_match("/\n/", $subject)) { phpList::log()->notice('Error: invalid subject, containing newlines, email blocked'); return 0; } if (!$to) { phpList::log()->notice("Error: empty To: in message with subject {$subject} to send"); return 0; } elseif (!$subject) { phpList::log()->notice("Error: empty Subject: in message to send to {$to}"); return 0; } if (!$skipblacklistcheck && Util::isEmailBlacklisted($to)) { phpList::log()->notice("Error, {$to} is blacklisted, not sending"); Util::blacklistSubscriberByEmail($to); Subscriber::addHistory('Marked Blacklisted', 'Found subscriber in blacklist while trying to send an email, marked black listed', Subscriber::getSubscriberByEmailAddress($to)->id); return 0; } return phpListMailer::sendMailPhpMailer($to, $subject, $message); }
/** * Find which subscriber this message was sent to * @param string $text * @return bool|Subscriber */ private function findSubscriber($text) { $subscriber = false; $subscriber_id = ''; preg_match('/X-ListMember: (.*)\\R/iU', $text, $match); if (is_array($match) && isset($match[1])) { $subscriber_id = trim($match[1]); } else { # older version use X-User preg_match('/X-User: (.*)\\R/iU', $text, $match); if (is_array($match) && isset($match[1])) { $subscriber_id = trim($match[1]); } } if ($subscriber_id != '') { # some versions used the email to identify the subscribers, some the userid and others the uniqid # use backward compatible way to find subscriber if (strpos($subscriber_id, '@') !== false) { $subscriber = Subscriber::getSubscriberByEmailAddress($subscriber_id); } elseif (preg_match('/^\\d$/', $subscriber_id)) { $subscriber = Subscriber::getSubscriber($subscriber_id); } elseif (!empty($subscriber_id)) { $subscriber = Subscriber::getSubscriberByUniqueId($subscriber_id); } } if ($subscriber === false) { ### if we didn't find any, parse anything looking like an email address and check if it's a subscriber. ## this is probably fairly time consuming, but as the process is only done once every so often ## that should not be too bad preg_match_all('/[\\S]+@[\\S\\.]+/', $text, $regs); foreach ($regs[0] as $match) { $subscriberObj = Subscriber::getSubscriberByEmailAddress(Util::cleanEmail($match)); if ($subscriberObj !== false) { return $subscriberObj; } } } return $subscriber; }
/** * 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; }
/** * Send statistics to phplist server * @param Campaign $campaign */ private function sendCampaignStats($campaign) { $msg = ''; if (Config::NOSTATSCOLLECTION) { return; } $msg .= "phpList version " . PHPLIST_VERSION . "\n"; $diff = Util::timeDiff($campaign->sendstart, $campaign->sent); if ($campaign->processed > 10 && $diff != 'very little time') { $msg .= "\n" . 'Time taken: ' . $diff; foreach (array('entered', 'processed', 'sendstart', 'sent', 'htmlformatted', 'sendformat', 'template', 'astext', 'ashtml', 'astextandhtml', 'aspdf', 'astextandpdf') as $item) { $msg .= "\n" . $item . ' => ' . $campaign->{$item}; } $mailto = Config::get('stats_collection_address', '*****@*****.**'); mail($mailto, 'PHPlist stats', $msg); } }