/** * Run the controller */ public function run() { global $objPage; $pageId = $this->getPageIdFromUrl(); $objRootPage = null; // Load a website root page object if there is no page ID if ($pageId === null) { $objRootPage = $this->getRootPageFromUrl(); /** @var \PageRoot $objHandler */ $objHandler = new $GLOBALS['TL_PTY']['root'](); $pageId = $objHandler->generate($objRootPage->id, true, true); } elseif ($pageId === false) { $this->User->authenticate(); /** @var \PageError404 $objHandler */ $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId); } elseif (\Config::get('rewriteURL') && strncmp(\Environment::get('request'), 'index.php/', 10) === 0) { $this->User->authenticate(); /** @var \PageError403 $objHandler */ $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId); } // Get the current page object(s) $objPage = \PageModel::findPublishedByIdOrAlias($pageId); // Check the URL and language of each page if there are multiple results if ($objPage !== null && $objPage->count() > 1) { $objNewPage = null; $arrPages = array(); // Order by domain and language while ($objPage->next()) { /** @var \PageModel $objModel */ $objModel = $objPage->current(); $objCurrentPage = $objModel->loadDetails(); $domain = $objCurrentPage->domain ?: '*'; $arrPages[$domain][$objCurrentPage->rootLanguage] = $objCurrentPage; // Also store the fallback language if ($objCurrentPage->rootIsFallback) { $arrPages[$domain]['*'] = $objCurrentPage; } } $strHost = \Environment::get('host'); // Look for a root page whose domain name matches the host name if (isset($arrPages[$strHost])) { $arrLangs = $arrPages[$strHost]; } else { $arrLangs = $arrPages['*'] ?: array(); // empty domain } // Use the first result (see #4872) if (!\Config::get('addLanguageToUrl')) { $objNewPage = current($arrLangs); } elseif (($lang = \Input::get('language')) != '' && isset($arrLangs[$lang])) { $objNewPage = $arrLangs[$lang]; } // Store the page object if (is_object($objNewPage)) { $objPage = $objNewPage; } } // Throw a 404 error if the page could not be found or the result is still ambiguous if ($objPage === null || $objPage instanceof \Model\Collection && $objPage->count() != 1) { $this->User->authenticate(); $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId); } // Make sure $objPage is a Model if ($objPage instanceof \Model\Collection) { $objPage = $objPage->current(); } // If the page has an alias, it can no longer be called via ID (see #7661) if ($objPage->alias != '' && preg_match('#^' . $objPage->id . '[$/.]#', \Environment::get('relativeRequest'))) { $this->User->authenticate(); $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId); } // Load a website root page object (will redirect to the first active regular page) if ($objPage->type == 'root') { $objHandler = new $GLOBALS['TL_PTY']['root'](); $objHandler->generate($objPage->id); } // Inherit the settings from the parent pages if it has not been done yet if (!is_bool($objPage->protected)) { $objPage->loadDetails(); } // Set the admin e-mail address if ($objPage->adminEmail != '') { list($GLOBALS['TL_ADMIN_NAME'], $GLOBALS['TL_ADMIN_EMAIL']) = \StringUtil::splitFriendlyEmail($objPage->adminEmail); } else { list($GLOBALS['TL_ADMIN_NAME'], $GLOBALS['TL_ADMIN_EMAIL']) = \StringUtil::splitFriendlyEmail(\Config::get('adminEmail')); } // Exit if the root page has not been published (see #2425) // Do not try to load the 404 page, it can cause an infinite loop! if (!BE_USER_LOGGED_IN && !$objPage->rootIsPublic) { header('HTTP/1.1 404 Not Found'); die_nicely('be_no_page', 'Page not found'); } // Check wether the language matches the root page language if (\Config::get('addLanguageToUrl') && \Input::get('language') != $objPage->rootLanguage) { $this->User->authenticate(); $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId); } // Check whether there are domain name restrictions if ($objPage->domain != '') { // Load an error 404 page object if ($objPage->domain != \Environment::get('host')) { $this->User->authenticate(); $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($objPage->id, $objPage->domain, \Environment::get('host')); } } // Authenticate the user if (!$this->User->authenticate() && $objPage->protected && !BE_USER_LOGGED_IN) { $objHandler = new $GLOBALS['TL_PTY']['error_403'](); $objHandler->generate($pageId, $objRootPage); } // Check the user groups if the page is protected if ($objPage->protected && !BE_USER_LOGGED_IN) { $arrGroups = $objPage->groups; // required for empty() if (!is_array($arrGroups) || empty($arrGroups) || !count(array_intersect($arrGroups, $this->User->groups))) { $this->log('Page "' . $pageId . '" can only be accessed by groups "' . implode(', ', (array) $objPage->groups) . '" (current user groups: ' . implode(', ', $this->User->groups) . ')', __METHOD__, TL_ERROR); $objHandler = new $GLOBALS['TL_PTY']['error_403'](); $objHandler->generate($pageId, $objRootPage); } } // Load the page object depending on its type $objHandler = new $GLOBALS['TL_PTY'][$objPage->type](); // Backup some globals (see #7659) $arrHead = $GLOBALS['TL_HEAD']; $arrBody = $GLOBALS['TL_BODY']; $arrMootools = $GLOBALS['TL_MOOTOOLS']; $arrJquery = $GLOBALS['TL_JQUERY']; try { // Generate the page switch ($objPage->type) { case 'root': case 'error_404': $objHandler->generate($pageId); break; case 'error_403': $objHandler->generate($pageId, $objRootPage); break; default: $objHandler->generate($objPage, true); break; } } catch (\UnusedArgumentsException $e) { // Restore the globals (see #7659) $GLOBALS['TL_HEAD'] = $arrHead; $GLOBALS['TL_BODY'] = $arrBody; $GLOBALS['TL_MOOTOOLS'] = $arrMootools; $GLOBALS['TL_JQUERY'] = $arrJquery; // Render the error page (see #5570) $objHandler = new $GLOBALS['TL_PTY']['error_404'](); $objHandler->generate($pageId, null, null, true); } // Stop the script (see #4565) exit; }
/** * Split a friendly-name e-address and return name and e-mail as array * * @param string $strEmail A friendly-name e-mail address * * @return array An array with name and e-mail address * * @deprecated Use StringUtil::splitFriendlyEmail() instead */ public static function splitFriendlyName($strEmail) { return \StringUtil::splitFriendlyEmail($strEmail); }
/** * Load system configuration into page object * * @param \Database\Result|\PageModel $objPage * * @return \Database\Result */ public static function loadPageConfig($objPage) { // Use the global date format if none is set if ($objPage->dateFormat == '') { $objPage->dateFormat = $GLOBALS['TL_CONFIG']['dateFormat']; } if ($objPage->timeFormat == '') { $objPage->timeFormat = $GLOBALS['TL_CONFIG']['timeFormat']; } if ($objPage->datimFormat == '') { $objPage->datimFormat = $GLOBALS['TL_CONFIG']['datimFormat']; } // Set the admin e-mail address if ($objPage->adminEmail != '') { list($GLOBALS['TL_ADMIN_NAME'], $GLOBALS['TL_ADMIN_EMAIL']) = \StringUtil::splitFriendlyEmail($objPage->adminEmail); } else { list($GLOBALS['TL_ADMIN_NAME'], $GLOBALS['TL_ADMIN_EMAIL']) = \StringUtil::splitFriendlyEmail($GLOBALS['TL_CONFIG']['adminEmail']); } // Define the static URL constants define('TL_FILES_URL', $objPage->staticFiles != '' && !$GLOBALS['TL_CONFIG']['debugMode'] ? $objPage->staticFiles . TL_PATH . '/' : ''); define('TL_SCRIPT_URL', $objPage->staticSystem != '' && !$GLOBALS['TL_CONFIG']['debugMode'] ? $objPage->staticSystem . TL_PATH . '/' : ''); define('TL_PLUGINS_URL', $objPage->staticPlugins != '' && !$GLOBALS['TL_CONFIG']['debugMode'] ? $objPage->staticPlugins . TL_PATH . '/' : ''); $objLayout = \Database::getInstance()->prepare("\n SELECT l.*, t.templates\n FROM tl_layout l\n LEFT JOIN tl_theme t ON l.pid=t.id\n WHERE l.id=?\n ORDER BY l.id=? DESC\n ")->limit(1)->execute($objPage->layout, $objPage->layout); if ($objLayout->numRows) { // Get the page layout $objPage->template = strlen($objLayout->template) ? $objLayout->template : 'fe_page'; $objPage->templateGroup = $objLayout->templates; // Store the output format list($strFormat, $strVariant) = explode('_', $objLayout->doctype); $objPage->outputFormat = $strFormat; $objPage->outputVariant = $strVariant; } $GLOBALS['TL_LANGUAGE'] = $objPage->language; return $objPage; }
/** * Extract the e-mail addresses from the func_get_args() arguments * * @param array $arrRecipients The recipients array * * @return array An array of e-mail addresses */ protected function compileRecipients($arrRecipients) { $arrReturn = array(); foreach ($arrRecipients as $varRecipients) { if (!is_array($varRecipients)) { $varRecipients = \StringUtil::splitCsv($varRecipients); } // Support friendly name addresses and internationalized domain names foreach ($varRecipients as $v) { list($strName, $strEmail) = \StringUtil::splitFriendlyEmail($v); $strName = trim($strName, ' "'); $strEmail = \Idna::encodeEmail($strEmail); if ($strName != '') { $arrReturn[$strEmail] = $strName; } else { $arrReturn[] = $strEmail; } } } return $arrReturn; }
/** * Renturn a form to choose an existing style sheet and import it * @param \DataContainer * @return string */ public function send(\DataContainer $objDc) { if (TL_MODE == 'BE') { $GLOBALS['TL_CSS'][] = 'system/modules/newsletter_content/assets/css/style.css'; if ($this->isFlexible) { $GLOBALS['TL_CSS'][] = 'system/modules/newsletter_content/assets/css/style-flexible.css'; } } $objNewsletter = $this->Database->prepare("SELECT n.*, c.useSMTP, c.smtpHost, c.smtpPort, c.smtpUser, c.smtpPass FROM tl_newsletter n LEFT JOIN tl_newsletter_channel c ON n.pid=c.id WHERE n.id=?")->limit(1)->execute($objDc->id); // Return if there is no newsletter if ($objNewsletter->numRows < 1) { return ''; } // Overwrite the SMTP configuration if ($objNewsletter->useSMTP) { $GLOBALS['TL_CONFIG']['useSMTP'] = true; $GLOBALS['TL_CONFIG']['smtpHost'] = $objNewsletter->smtpHost; $GLOBALS['TL_CONFIG']['smtpUser'] = $objNewsletter->smtpUser; $GLOBALS['TL_CONFIG']['smtpPass'] = $objNewsletter->smtpPass; $GLOBALS['TL_CONFIG']['smtpEnc'] = $objNewsletter->smtpEnc; $GLOBALS['TL_CONFIG']['smtpPort'] = $objNewsletter->smtpPort; } // Add default sender address if ($objNewsletter->sender == '') { list($objNewsletter->senderName, $objNewsletter->sender) = \StringUtil::splitFriendlyEmail($GLOBALS['TL_CONFIG']['adminEmail']); } $arrAttachments = array(); $blnAttachmentsFormatError = false; // Add attachments if ($objNewsletter->addFile) { $files = deserialize($objNewsletter->files); if (!empty($files) && is_array($files)) { $objFiles = \FilesModel::findMultipleByUuids($files); if ($objFiles === null) { if (!\Validator::isUuid($files[0])) { $blnAttachmentsFormatError = true; \Message::addError($GLOBALS['TL_LANG']['ERR']['version2format']); } } else { while ($objFiles->next()) { if (is_file(TL_ROOT . '/' . $objFiles->path)) { $arrAttachments[] = $objFiles->path; } } } } } // Get content $html = ''; $objContentElements = \ContentModel::findPublishedByPidAndTable($objNewsletter->id, 'tl_newsletter'); if ($objContentElements !== null) { if (!defined('NEWSLETTER_CONTENT_PREVIEW')) { define('NEWSLETTER_CONTENT_PREVIEW', true); } while ($objContentElements->next()) { $html .= $this->getContentElement($objContentElements->id); } } // Replace insert tags $text = $this->replaceInsertTags($objNewsletter->text); $html = $this->replaceInsertTags($html); // Convert relative URLs $html = $this->convertRelativeUrls($html); // Set back to object $objNewsletter->content = $html; // Send newsletter if (!$blnAttachmentsFormatError && \Input::get('token') != '' && \Input::get('token') == $this->Session->get('tl_newsletter_send')) { $referer = preg_replace('/&(amp;)?(start|mpc|token|recipient|preview)=[^&]*/', '', \Environment::get('request')); // Preview if (isset($_GET['preview'])) { // Check the e-mail address if (!\Validator::isEmail(\Input::get('recipient', true))) { $_SESSION['TL_PREVIEW_MAIL_ERROR'] = true; $this->redirect($referer); } // get preview recipient $arrRecipient = array(); $strEmail = urldecode(\Input::get('recipient', true)); $objRecipient = $this->Database->prepare("SELECT * FROM tl_member m WHERE email=? ORDER BY email")->limit(1)->execute($strEmail); if ($objRecipient->num_rows < 1) { $arrRecipient['email'] = $strEmail; } else { $arrRecipient = $objRecipient->row(); } $arrRecipient = array_merge($arrRecipient, array('extra' => '&preview=1', 'tracker_png' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $strEmail . '&preview=1&t=png', 'tracker_gif' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $strEmail . '&preview=1&t=gif', 'tracker_css' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $strEmail . '&preview=1&t=css', 'tracker_js' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $strEmail . '&preview=1&t=js')); // Send $objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments); $objNewsletter->email = $strEmail; $this->sendNewsletter($objEmail, $objNewsletter, $arrRecipient, $text, $html); // Redirect \Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], 1)); $this->redirect($referer); } // Get the total number of recipients $objTotal = $this->Database->prepare("SELECT COUNT(DISTINCT email) AS count FROM tl_newsletter_recipients WHERE pid=? AND active=1")->execute($objNewsletter->pid); // Return if there are no recipients if ($objTotal->count < 1) { $this->Session->set('tl_newsletter_send', null); \Message::addError($GLOBALS['TL_LANG']['tl_newsletter']['error']); $this->redirect($referer); } $intTotal = $objTotal->count; // Get page and timeout $intTimeout = \Input::get('timeout') > 0 ? \Input::get('timeout') : 1; $intStart = \Input::get('start') ? \Input::get('start') : 0; $intPages = \Input::get('mpc') ? \Input::get('mpc') : 10; // Get recipients $objRecipients = $this->Database->prepare("SELECT *, r.email FROM tl_newsletter_recipients r LEFT JOIN tl_member m ON(r.email=m.email) WHERE r.pid=? AND r.active=1 GROUP BY r.email ORDER BY r.email")->limit($intPages, $intStart)->execute($objNewsletter->pid); echo '<div style="font-family:Verdana,sans-serif;font-size:11px;line-height:16px;margin-bottom:12px">'; // Send newsletter if ($objRecipients->numRows > 0) { // Update status if ($intStart == 0) { $this->Database->prepare("UPDATE tl_newsletter SET sent=1, date=? WHERE id=?")->execute(time(), $objNewsletter->id); $_SESSION['REJECTED_RECIPIENTS'] = array(); } while ($objRecipients->next()) { $objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments); $objNewsletter->email = $objRecipients->email; $arrRecipient = array_merge($objRecipients->row(), array('tracker_png' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $objRecipients->email . '&t=png', 'tracker_gif' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $objRecipients->email . '&t=gif', 'tracker_css' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $objRecipients->email . '&t=css', 'tracker_js' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $objRecipients->email . '&t=js')); $this->sendNewsletter($objEmail, $objNewsletter, $arrRecipient, $text, $html); echo 'Sending newsletter to <strong>' . $objRecipients->email . '</strong><br>'; } } echo '<div style="margin-top:12px">'; // Redirect back home if ($objRecipients->numRows < 1 || $intStart + $intPages >= $intTotal) { $this->Session->set('tl_newsletter_send', null); // Deactivate rejected addresses if (!empty($_SESSION['REJECTED_RECIPIENTS'])) { $intRejected = count($_SESSION['REJECTED_RECIPIENTS']); \Message::addInfo(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['rejected'], $intRejected)); $intTotal -= $intRejected; foreach ($_SESSION['REJECTED_RECIPIENTS'] as $strRecipient) { $this->Database->prepare("UPDATE tl_newsletter_recipients SET active='' WHERE email=?")->execute($strRecipient); $this->log('Recipient address "' . $strRecipient . '" was rejected and has been deactivated', __METHOD__, TL_ERROR); } } $this->Database->prepare("UPDATE tl_newsletter SET recipients=?, rejected=? WHERE id=?")->execute($intTotal, $intRejected, $objNewsletter->id); \Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], $intTotal)); echo '<script>setTimeout(\'window.location="' . \Environment::get('base') . $referer . '"\',1000)</script>'; echo '<a href="' . \Environment::get('base') . $referer . '">Please click here to proceed if you are not using JavaScript</a>'; } else { $url = preg_replace('/&(amp;)?(start|mpc|recipient)=[^&]*/', '', \Environment::get('request')) . '&start=' . ($intStart + $intPages) . '&mpc=' . $intPages; echo '<script>setTimeout(\'window.location="' . \Environment::get('base') . $url . '"\',' . $intTimeout * 1000 . ')</script>'; echo '<a href="' . \Environment::get('base') . $url . '">Please click here to proceed if you are not using JavaScript</a>'; } echo '</div></div>'; exit; } $strToken = md5(uniqid(mt_rand(), true)); $this->Session->set('tl_newsletter_send', $strToken); $sprintf = $objNewsletter->senderName != '' ? $objNewsletter->senderName . ' <%s>' : '%s'; $this->import('BackendUser', 'User'); // prepare preview $preview = $text; if (!$objNewsletter->sendText) { // Default template if ($objNewsletter->template == '') { $objNewsletter->template = 'mail_default'; } // Load the mail template $objTemplate = new \BackendTemplate($objNewsletter->template); $objTemplate->setData($objNewsletter->row()); $objTemplate->title = $objNewsletter->subject; $objTemplate->body = $html; $objTemplate->charset = $GLOBALS['TL_CONFIG']['characterSet']; $objTemplate->css = $css; // Backwards compatibility // Parse template $preview = $objTemplate->parse(); } // Replace inserttags $arrName = explode(' ', $this->User->name); $preview = $this->replaceInsertTags($preview); $preview = $this->prepareLinkTracking($preview, $objNewsletter->id, $this->User->email, '&preview=1'); $preview = $this->parseSimpleTokens($preview, array('firstname' => $arrName[0], 'lastname' => $arrName[sizeof($arrName) - 1], 'street' => 'Königsbrücker Str. 9', 'postal' => '01099', 'city' => 'Dresden', 'phone' => '0351 30966184', 'email' => $this->User->email, 'tracker_png' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $this->User->email . '&preview=1&t=png', 'tracker_gif' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $this->User->email . '&preview=1&t=gif', 'tracker_css' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $this->User->email . '&preview=1&t=css', 'tracker_js' => \Environment::get('base') . 'tracking/?n=' . $objNewsletter->id . '&e=' . $this->User->email . '&preview=1&t=js')); // Create cache folder if (!file_exists(TL_ROOT . '/system/cache/newsletter')) { mkdir(TL_ROOT . '/system/cache/newsletter'); file_put_contents(TL_ROOT . '/system/cache/newsletter/.htaccess', '<IfModule !mod_authz_core.c> Order allow,deny Allow from all </IfModule> <IfModule mod_authz_core.c> Require all granted </IfModule>'); } // Cache preview file_put_contents(TL_ROOT . '/system/cache/newsletter/' . $objNewsletter->alias . '.html', preg_replace('/^\\s+|\\n|\\r|\\s+$/m', '', $preview)); // Preview newsletter $return = ' <div id="tl_buttons"> <a href="' . $this->getReferer(true) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> </div> <h2 class="sub_headline">' . sprintf($GLOBALS['TL_LANG']['tl_newsletter']['send'][1], $objNewsletter->id) . '</h2> ' . \Message::generate() . ' <form action="' . ampersand(\Environment::get('script'), true) . '" id="tl_newsletter_send" class="tl_form" method="get"> <div class="tl_formbody_edit tl_newsletter_send"> <input type="hidden" name="do" value="' . \Input::get('do') . '"> <input type="hidden" name="table" value="' . \Input::get('table') . '"> <input type="hidden" name="key" value="' . \Input::get('key') . '"> <input type="hidden" name="id" value="' . \Input::get('id') . '"> <input type="hidden" name="token" value="' . $strToken . '"> <table class="prev_header"> <tr class="row_0"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['from'] . '</td> <td class="col_1">' . sprintf($sprintf, $objNewsletter->sender) . '</td> </tr> <tr class="row_1"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['subject'][0] . '</td> <td class="col_1">' . $objNewsletter->subject . '</td> </tr> <tr class="row_2"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['template'][0] . '</td> <td class="col_1">' . $objNewsletter->template . '</td> </tr>' . (!empty($arrAttachments) && is_array($arrAttachments) ? ' <tr class="row_3"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['attachments'] . '</td> <td class="col_1">' . implode(', ', $arrAttachments) . '</td> </tr>' : '') . ' </table>' . (!$objNewsletter->sendText ? ' <iframe class="preview_html" id="preview_html" seamless border="0" width="703px" height="503px" style="padding:0" src="system/cache/newsletter/' . $objNewsletter->alias . '.html"></iframe> ' : '') . ' <div class="preview_text"> ' . nl2br_html5($text) . ' </div> <div class="tl_tbox"> <div class="w50"> <h3><label for="ctrl_mpc">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][0] . '</label></h3> <input type="text" name="mpc" id="ctrl_mpc" value="10" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] && $GLOBALS['TL_CONFIG']['showHelp'] ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_timeout">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][0] . '</label></h3> <input type="text" name="timeout" id="ctrl_timeout" value="1" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] && $GLOBALS['TL_CONFIG']['showHelp'] ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_start">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][0] . '</label></h3> <input type="text" name="start" id="ctrl_start" value="0" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['start'][1] && $GLOBALS['TL_CONFIG']['showHelp'] ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_recipient">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][0] . '</label></h3> <input type="text" name="recipient" id="ctrl_recipient" value="' . $this->User->email . '" class="tl_text" onfocus="Backend.getScrollOffset()">' . (isset($_SESSION['TL_PREVIEW_MAIL_ERROR']) ? ' <div class="tl_error">' . $GLOBALS['TL_LANG']['ERR']['email'] . '</div>' : ($GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] && $GLOBALS['TL_CONFIG']['showHelp'] ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] . '</p>' : '')) . ' </div> <div class="clear"></div> </div> </div>'; // Do not send the newsletter if there is an attachment format error if (!$blnAttachmentsFormatError) { $return .= ' <div class="tl_formbody_submit"> <div class="tl_submit_container"> <input type="submit" name="preview" class="tl_submit" accesskey="p" value="' . specialchars($GLOBALS['TL_LANG']['tl_newsletter']['preview']) . '"> <input type="submit" id="send" class="tl_submit" accesskey="s" value="' . specialchars($GLOBALS['TL_LANG']['tl_newsletter']['send'][0]) . '" onclick="return confirm(\'' . str_replace("'", "\\'", $GLOBALS['TL_LANG']['tl_newsletter']['sendConfirm']) . '\')"> </div> </div>'; } $return .= ' </form>'; unset($_SESSION['TL_PREVIEW_MAIL_ERROR']); return $return; }
/** * Renturn a form to choose an existing style sheet and import it * * @param \DataContainer $dc * * @return string */ public function send(\DataContainer $dc) { $objNewsletter = $this->Database->prepare("SELECT n.*, c.useSMTP, c.smtpHost, c.smtpPort, c.smtpUser, c.smtpPass FROM tl_newsletter n LEFT JOIN tl_newsletter_channel c ON n.pid=c.id WHERE n.id=?")->limit(1)->execute($dc->id); // Return if there is no newsletter if ($objNewsletter->numRows < 1) { return ''; } // Overwrite the SMTP configuration if ($objNewsletter->useSMTP) { \Config::set('useSMTP', true); \Config::set('smtpHost', $objNewsletter->smtpHost); \Config::set('smtpUser', $objNewsletter->smtpUser); \Config::set('smtpPass', $objNewsletter->smtpPass); \Config::set('smtpEnc', $objNewsletter->smtpEnc); \Config::set('smtpPort', $objNewsletter->smtpPort); } // Add default sender address if ($objNewsletter->sender == '') { list($objNewsletter->senderName, $objNewsletter->sender) = \StringUtil::splitFriendlyEmail(\Config::get('adminEmail')); } $arrAttachments = array(); $blnAttachmentsFormatError = false; // Add attachments if ($objNewsletter->addFile) { $files = deserialize($objNewsletter->files); if (!empty($files) && is_array($files)) { $objFiles = \FilesModel::findMultipleByUuids($files); if ($objFiles === null) { if (!\Validator::isUuid($files[0])) { $blnAttachmentsFormatError = true; \Message::addError($GLOBALS['TL_LANG']['ERR']['version2format']); } } else { while ($objFiles->next()) { if (is_file(TL_ROOT . '/' . $objFiles->path)) { $arrAttachments[] = $objFiles->path; } } } } } // Replace insert tags $html = $this->replaceInsertTags($objNewsletter->content, false); $text = $this->replaceInsertTags($objNewsletter->text, false); // Convert relative URLs if ($objNewsletter->externalImages) { $html = $this->convertRelativeUrls($html); } // Send newsletter if (!$blnAttachmentsFormatError && \Input::get('token') != '' && \Input::get('token') == $this->Session->get('tl_newsletter_send')) { $referer = preg_replace('/&(amp;)?(start|mpc|token|recipient|preview)=[^&]*/', '', \Environment::get('request')); // Preview if (isset($_GET['preview'])) { // Check the e-mail address if (!\Validator::isEmail(\Input::get('recipient', true))) { $_SESSION['TL_PREVIEW_MAIL_ERROR'] = true; $this->redirect($referer); } $arrRecipient['email'] = urldecode(\Input::get('recipient', true)); // Send $objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments); $this->sendNewsletter($objEmail, $objNewsletter, $arrRecipient, $text, $html); // Redirect \Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], 1)); $this->redirect($referer); } // Get the total number of recipients $objTotal = $this->Database->prepare("SELECT COUNT(DISTINCT email) AS count FROM tl_newsletter_recipients WHERE pid=? AND active=1")->execute($objNewsletter->pid); // Return if there are no recipients if ($objTotal->count < 1) { $this->Session->set('tl_newsletter_send', null); \Message::addError($GLOBALS['TL_LANG']['tl_newsletter']['error']); $this->redirect($referer); } $intTotal = $objTotal->count; // Get page and timeout $intTimeout = \Input::get('timeout') > 0 ? \Input::get('timeout') : 1; $intStart = \Input::get('start') ? \Input::get('start') : 0; $intPages = \Input::get('mpc') ? \Input::get('mpc') : 10; // Get recipients $objRecipients = $this->Database->prepare("SELECT *, r.email FROM tl_newsletter_recipients r LEFT JOIN tl_member m ON(r.email=m.email) WHERE r.pid=? AND r.active=1 GROUP BY r.email ORDER BY r.email")->limit($intPages, $intStart)->execute($objNewsletter->pid); echo '<div style="font-family:Verdana,sans-serif;font-size:11px;line-height:16px;margin-bottom:12px">'; // Send newsletter if ($objRecipients->numRows > 0) { // Update status if ($intStart == 0) { $this->Database->prepare("UPDATE tl_newsletter SET sent=1, date=? WHERE id=?")->execute(time(), $objNewsletter->id); $_SESSION['REJECTED_RECIPIENTS'] = array(); } while ($objRecipients->next()) { $objEmail = $this->generateEmailObject($objNewsletter, $arrAttachments); $this->sendNewsletter($objEmail, $objNewsletter, $objRecipients->row(), $text, $html); echo 'Sending newsletter to <strong>' . $objRecipients->email . '</strong><br>'; } } echo '<div style="margin-top:12px">'; // Redirect back home if ($objRecipients->numRows < 1 || $intStart + $intPages >= $intTotal) { $this->Session->set('tl_newsletter_send', null); // Deactivate rejected addresses if (!empty($_SESSION['REJECTED_RECIPIENTS'])) { $intRejected = count($_SESSION['REJECTED_RECIPIENTS']); \Message::addInfo(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['rejected'], $intRejected)); $intTotal -= $intRejected; foreach ($_SESSION['REJECTED_RECIPIENTS'] as $strRecipient) { $this->Database->prepare("UPDATE tl_newsletter_recipients SET active='' WHERE email=?")->execute($strRecipient); $this->log('Recipient address "' . $strRecipient . '" was rejected and has been deactivated', __METHOD__, TL_ERROR); } } \Message::addConfirmation(sprintf($GLOBALS['TL_LANG']['tl_newsletter']['confirm'], $intTotal)); echo '<script>setTimeout(\'window.location="' . \Environment::get('base') . $referer . '"\',1000)</script>'; echo '<a href="' . \Environment::get('base') . $referer . '">Please click here to proceed if you are not using JavaScript</a>'; } else { $url = preg_replace('/&(amp;)?(start|mpc|recipient)=[^&]*/', '', \Environment::get('request')) . '&start=' . ($intStart + $intPages) . '&mpc=' . $intPages; echo '<script>setTimeout(\'window.location="' . \Environment::get('base') . $url . '"\',' . $intTimeout * 1000 . ')</script>'; echo '<a href="' . \Environment::get('base') . $url . '">Please click here to proceed if you are not using JavaScript</a>'; } echo '</div></div>'; exit; } $strToken = md5(uniqid(mt_rand(), true)); $this->Session->set('tl_newsletter_send', $strToken); $sprintf = $objNewsletter->senderName != '' ? $objNewsletter->senderName . ' <%s>' : '%s'; $this->import('BackendUser', 'User'); // Preview newsletter $return = ' <div id="tl_buttons"> <a href="' . $this->getReferer(true) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> </div> ' . \Message::generate() . ' <form action="' . TL_SCRIPT . '" id="tl_newsletter_send" class="tl_form" method="get"> <div class="tl_formbody_edit tl_newsletter_send"> <input type="hidden" name="do" value="' . \Input::get('do') . '"> <input type="hidden" name="table" value="' . \Input::get('table') . '"> <input type="hidden" name="key" value="' . \Input::get('key') . '"> <input type="hidden" name="id" value="' . \Input::get('id') . '"> <input type="hidden" name="token" value="' . $strToken . '"> <table class="prev_header"> <tr class="row_0"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['from'] . '</td> <td class="col_1">' . sprintf($sprintf, $objNewsletter->sender) . '</td> </tr> <tr class="row_1"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['subject'][0] . '</td> <td class="col_1">' . $objNewsletter->subject . '</td> </tr> <tr class="row_2"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['template'][0] . '</td> <td class="col_1">' . $objNewsletter->template . '</td> </tr>' . (!empty($arrAttachments) && is_array($arrAttachments) ? ' <tr class="row_3"> <td class="col_0">' . $GLOBALS['TL_LANG']['tl_newsletter']['attachments'] . '</td> <td class="col_1">' . implode(', ', $arrAttachments) . '</td> </tr>' : '') . ' </table>' . (!$objNewsletter->sendText ? ' <div class="preview_html"> ' . $html . ' </div>' : '') . ' <div class="preview_text"> <pre style="white-space:pre-wrap">' . $text . '</pre> </div> <div class="tl_tbox"> <div class="w50"> <h3><label for="ctrl_mpc">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][0] . '</label></h3> <input type="text" name="mpc" id="ctrl_mpc" value="10" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] && \Config::get('showHelp') ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['mailsPerCycle'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_timeout">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][0] . '</label></h3> <input type="text" name="timeout" id="ctrl_timeout" value="1" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] && \Config::get('showHelp') ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['timeout'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_start">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][0] . '</label></h3> <input type="text" name="start" id="ctrl_start" value="0" class="tl_text" onfocus="Backend.getScrollOffset()">' . ($GLOBALS['TL_LANG']['tl_newsletter']['start'][1] && \Config::get('showHelp') ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['start'][1] . '</p>' : '') . ' </div> <div class="w50"> <h3><label for="ctrl_recipient">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][0] . '</label></h3> <input type="text" name="recipient" id="ctrl_recipient" value="' . $this->User->email . '" class="tl_text" onfocus="Backend.getScrollOffset()">' . (isset($_SESSION['TL_PREVIEW_MAIL_ERROR']) ? ' <div class="tl_error">' . $GLOBALS['TL_LANG']['ERR']['email'] . '</div>' : ($GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] && \Config::get('showHelp') ? ' <p class="tl_help tl_tip">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][1] . '</p>' : '')) . ' </div> <div class="clear"></div> </div> </div>'; // Do not send the newsletter if there is an attachment format error if (!$blnAttachmentsFormatError) { $return .= ' <div class="tl_formbody_submit"> <div class="tl_submit_container"> <input type="submit" name="preview" class="tl_submit" accesskey="p" value="' . specialchars($GLOBALS['TL_LANG']['tl_newsletter']['preview']) . '"> <input type="submit" id="send" class="tl_submit" accesskey="s" value="' . specialchars($GLOBALS['TL_LANG']['tl_newsletter']['send'][0]) . '" onclick="return confirm(\'' . str_replace("'", "\\'", $GLOBALS['TL_LANG']['tl_newsletter']['sendConfirm']) . '\')"> </div> </div>'; } $return .= ' </form>'; unset($_SESSION['TL_PREVIEW_MAIL_ERROR']); return $return; }
/** * Recursively validate an input variable * * @param mixed $varInput The user input * * @return mixed The original or modified user input */ protected function validator($varInput) { if (is_array($varInput)) { foreach ($varInput as $k => $v) { $varInput[$k] = $this->validator($v); } return $varInput; } if (!$this->doNotTrim) { $varInput = trim($varInput); } if ($varInput == '') { if (!$this->mandatory) { return ''; } else { if ($this->strLabel == '') { $this->addError($GLOBALS['TL_LANG']['ERR']['mdtryNoLabel']); } else { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['mandatory'], $this->strLabel)); } } } if ($this->minlength && $varInput != '' && utf8_strlen($varInput) < $this->minlength) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['minlength'], $this->strLabel, $this->minlength)); } if ($this->maxlength && $varInput != '' && utf8_strlen($varInput) > $this->maxlength) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['maxlength'], $this->strLabel, $this->maxlength)); } if ($this->minval && is_numeric($varInput) && $varInput < $this->minval) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['minval'], $this->strLabel, $this->minval)); } if ($this->maxval && is_numeric($varInput) && $varInput > $this->maxval) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['maxval'], $this->strLabel, $this->maxval)); } if ($this->rgxp != '') { switch ($this->rgxp) { // Special validation rule for style sheets case strncmp($this->rgxp, 'digit_', 6) === 0: $textual = explode('_', $this->rgxp); array_shift($textual); if (in_array($varInput, $textual) || strncmp($varInput, '$', 1) === 0) { break; } // DO NOT ADD A break; STATEMENT HERE // Numeric characters (including full stop [.] and minus [-]) // DO NOT ADD A break; STATEMENT HERE // Numeric characters (including full stop [.] and minus [-]) case 'digit': // Support decimal commas and convert them automatically (see #3488) if (substr_count($varInput, ',') == 1 && strpos($varInput, '.') === false) { $varInput = str_replace(',', '.', $varInput); } if (!\Validator::isNumeric($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['digit'], $this->strLabel)); } break; // Natural numbers (positive integers) // Natural numbers (positive integers) case 'natural': if (!\Validator::isNatural($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['natural'], $this->strLabel)); } break; // Alphabetic characters (including full stop [.] minus [-] and space [ ]) // Alphabetic characters (including full stop [.] minus [-] and space [ ]) case 'alpha': if (!\Validator::isAlphabetic($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['alpha'], $this->strLabel)); } break; // Alphanumeric characters (including full stop [.] minus [-], underscore [_] and space [ ]) // Alphanumeric characters (including full stop [.] minus [-], underscore [_] and space [ ]) case 'alnum': if (!\Validator::isAlphanumeric($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['alnum'], $this->strLabel)); } break; // Do not allow any characters that are usually encoded by class Input [=<>()#/]) // Do not allow any characters that are usually encoded by class Input [=<>()#/]) case 'extnd': if (!\Validator::isExtendedAlphanumeric(html_entity_decode($varInput))) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['extnd'], $this->strLabel)); } break; // Check whether the current value is a valid date format // Check whether the current value is a valid date format case 'date': if (!\Validator::isDate($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['date'], \Date::getInputFormat(\Date::getNumericDateFormat()))); } else { // Validate the date (see #5086) try { new \Date($varInput, \Date::getNumericDateFormat()); } catch (\OutOfBoundsException $e) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varInput)); } } break; // Check whether the current value is a valid time format // Check whether the current value is a valid time format case 'time': if (!\Validator::isTime($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['time'], \Date::getInputFormat(\Date::getNumericTimeFormat()))); } break; // Check whether the current value is a valid date and time format // Check whether the current value is a valid date and time format case 'datim': if (!\Validator::isDatim($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['dateTime'], \Date::getInputFormat(\Date::getNumericDatimFormat()))); } else { // Validate the date (see #5086) try { new \Date($varInput, \Date::getNumericDatimFormat()); } catch (\OutOfBoundsException $e) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varInput)); } } break; // Check whether the current value is a valid friendly name e-mail address // Check whether the current value is a valid friendly name e-mail address case 'friendly': list($strName, $varInput) = \StringUtil::splitFriendlyEmail($varInput); // no break; // Check whether the current value is a valid e-mail address // no break; // Check whether the current value is a valid e-mail address case 'email': if (!\Validator::isEmail($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['email'], $this->strLabel)); } if ($this->rgxp == 'friendly' && $strName != '') { $varInput = $strName . ' [' . $varInput . ']'; } break; // Check whether the current value is list of valid e-mail addresses // Check whether the current value is list of valid e-mail addresses case 'emails': $arrEmails = trimsplit(',', $varInput); foreach ($arrEmails as $strEmail) { $strEmail = \Idna::encodeEmail($strEmail); if (!\Validator::isEmail($strEmail)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['emails'], $this->strLabel)); break; } } break; // Check whether the current value is a valid URL // Check whether the current value is a valid URL case 'url': if (!\Validator::isUrl($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['url'], $this->strLabel)); } break; // Check whether the current value is a valid alias // Check whether the current value is a valid alias case 'alias': if (!\Validator::isAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['alias'], $this->strLabel)); } break; // Check whether the current value is a valid folder URL alias // Check whether the current value is a valid folder URL alias case 'folderalias': if (!\Validator::isFolderAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['folderalias'], $this->strLabel)); } break; // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) case 'phone': if (!\Validator::isPhone(html_entity_decode($varInput))) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['phone'], $this->strLabel)); } break; // Check whether the current value is a percent value // Check whether the current value is a percent value case 'prcnt': if (!\Validator::isPercent($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['prcnt'], $this->strLabel)); } break; // Check whether the current value is a locale // Check whether the current value is a locale case 'locale': if (!\Validator::isLocale($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['locale'], $this->strLabel)); } break; // Check whether the current value is a language code // Check whether the current value is a language code case 'language': if (!\Validator::isLanguage($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['language'], $this->strLabel)); } break; // Check whether the current value is a Google+ ID or vanity name // Check whether the current value is a Google+ ID or vanity name case 'google+': if (!\Validator::isGooglePlusId($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidGoogleId'], $this->strLabel)); } break; // HOOK: pass unknown tags to callback functions // HOOK: pass unknown tags to callback functions default: if (isset($GLOBALS['TL_HOOKS']['addCustomRegexp']) && is_array($GLOBALS['TL_HOOKS']['addCustomRegexp'])) { foreach ($GLOBALS['TL_HOOKS']['addCustomRegexp'] as $callback) { $this->import($callback[0]); $break = $this->{$callback[0]}->{$callback[1]}($this->rgxp, $varInput, $this); // Stop the loop if a callback returned true if ($break === true) { break; } } } break; } } if ($this->isHexColor && $varInput != '' && strncmp($varInput, '$', 1) !== 0) { $varInput = preg_replace('/[^a-f0-9]+/i', '', $varInput); } if ($this->nospace && preg_match('/[\\t ]+/', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['noSpace'], $this->strLabel)); } if ($this->spaceToUnderscore) { $varInput = preg_replace('/\\s+/', '_', trim($varInput)); } if (is_bool($this->trailingSlash) && $varInput != '') { $varInput = preg_replace('/\\/+$/', '', $varInput) . ($this->trailingSlash ? '/' : ''); } return $varInput; }