The class encodes and decodes internationalized domain names according to RFC
3490. It also contains two helper methods to encode e-mails and URLs.
Usage:
echo Idna::encode('bürger.de');
echo Idna::encodeEmail('mit@bürger.de');
echo Idna::encodeUrl('http://www.bürger.de');
/** * Remove the recipient */ protected function removeSubscriber() { $varInput = Idna::encodeEmail(Input::get('email', true)); // Validate e-mail address if (!Validator::isEmail($varInput)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['email']; $this->redirect($this->generateFrontendUrl($this->objModel->getRelated('jumpTo')->row())); } $objCleverReach = new CleverReach(); switch ($this->clr_unsubscribe) { case 'inactive': foreach ($this->clr_groups as $strGroupId) { $objCleverReach->receiverSetInactive($varInput, $strGroupId); } break; case 'delete': foreach ($this->clr_groups as $strGroupId) { $objCleverReach->receiverDelete($varInput, $strGroupId); } break; case 'email': default: $objCleverReach->sendUnsubscribeMail($varInput, $this->clr_form); break; } $this->redirect($this->generateFrontendUrl($this->objModel->getRelated('jumpTo')->row())); }
/** * @param $strType * @param null $strForceLanguage */ public function __construct($strType, $strForceLanguage = null) { if (in_array($strType, $GLOBALS['TL_EMAIL'])) { $this->strType = $strType; } $this->strForceLanguage = $strForceLanguage; // Set default parameters $this->addParameter('host', Idna::decode(Environment::get('host'))); $this->addParameter('admin_name', BackendUser::getInstance()->name); }
/** * Generate the module */ protected function compile() { $this->import('FrontendUser', 'User'); // Initialize the password widget $arrField = array('name' => 'password', 'inputType' => 'text', 'label' => $GLOBALS['TL_LANG']['MSC']['password'][0], 'eval' => array('hideInput' => true, 'mandatory' => true, 'required' => true)); $objWidget = new \FormTextField(\FormTextField::getAttributesFromDca($arrField, $arrField['name'])); $objWidget->rowClass = 'row_0 row_first even'; $strFormId = 'tl_close_account_' . $this->id; // Validate widget if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); // Validate the password if (!$objWidget->hasErrors()) { // The password has been generated with crypt() if (\Encryption::test($this->User->password)) { $blnAuthenticated = \Encryption::verify($objWidget->value, $this->User->password); } else { list($strPassword, $strSalt) = explode(':', $this->User->password); $blnAuthenticated = $strSalt == '' ? $strPassword === sha1($objWidget->value) : $strPassword === sha1($strSalt . $objWidget->value); } if (!$blnAuthenticated) { $objWidget->value = ''; $objWidget->addError($GLOBALS['TL_LANG']['ERR']['invalidPass']); } } // Close account if (!$objWidget->hasErrors()) { // HOOK: send account ID if (isset($GLOBALS['TL_HOOKS']['closeAccount']) && is_array($GLOBALS['TL_HOOKS']['closeAccount'])) { foreach ($GLOBALS['TL_HOOKS']['closeAccount'] as $callback) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($this->User->id, $this->reg_close, $this); } } $objMember = \MemberModel::findByPk($this->User->id); // Remove the account if ($this->reg_close == 'close_delete') { $objMember->delete(); $this->log('User account ID ' . $this->User->id . ' (' . \Idna::decodeEmail($this->User->email) . ') has been deleted', __METHOD__, TL_ACCESS); } else { $objMember->disable = 1; $objMember->tstamp = time(); $objMember->save(); $this->log('User account ID ' . $this->User->id . ' (' . \Idna::decodeEmail($this->User->email) . ') has been deactivated', __METHOD__, TL_ACCESS); } $this->User->logout(); // Check whether there is a jumpTo page if (($objJumpTo = $this->objModel->getRelated('jumpTo')) instanceof PageModel) { $this->jumpToOrReload($objJumpTo->row()); } $this->reload(); } } $this->Template->fields = $objWidget->parse(); $this->Template->formId = $strFormId; $this->Template->action = \Environment::get('indexFreeRequest'); $this->Template->slabel = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['closeAccount']); $this->Template->rowLast = 'row_1 row_last odd'; }
/** * Format a value * * @param string $k * @param mixed $value * @param boolean $blnListSingle * * @return mixed */ protected function formatValue($k, $value, $blnListSingle = false) { $value = \StringUtil::deserialize($value); // Return if empty if (empty($value)) { return ''; } /** @var PageModel $objPage */ global $objPage; // Array if (is_array($value)) { $value = implode(', ', $value); } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['rgxp'] == 'date') { $value = \Date::parse($objPage->dateFormat, $value); } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['rgxp'] == 'time') { $value = \Date::parse($objPage->timeFormat, $value); } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['rgxp'] == 'datim') { $value = \Date::parse($objPage->datimFormat, $value); } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['rgxp'] == 'url' && preg_match('@^(https?://|ftp://)@i', $value)) { $value = \Idna::decode($value); // see #5946 $value = '<a href="' . $value . '" target="_blank">' . $value . '</a>'; } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['rgxp'] == 'email') { $value = \StringUtil::encodeEmail(\Idna::decode($value)); // see #5946 $value = '<a href="mailto:' . $value . '">' . $value . '</a>'; } elseif (is_array($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['reference'])) { $value = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['reference'][$value]; } elseif ($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['options'])) { if ($blnListSingle) { $value = $GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['options'][$value]; } else { $value = '<span class="value">[' . $value . ']</span> ' . $GLOBALS['TL_DCA'][$this->list_table]['fields'][$k]['options'][$value]; } } return $value; }
/** * Tests the isEmail() method. * * @param string $email The email * @param bool $expected The expected result * * @dataProvider emailProvider */ public function testEmail($email, $expected) { $this->assertEquals($expected, Validator::isEmail($email), 'Original: ' . $email . ' idna: ' . Idna::encodeEmail($email)); }
/** * Send an admin notification e-mail * * @param integer $intId * @param array $arrData */ protected function sendAdminNotification($intId, $arrData) { $objEmail = new \Email(); $objEmail->from = $GLOBALS['TL_ADMIN_EMAIL']; $objEmail->fromName = $GLOBALS['TL_ADMIN_NAME']; $objEmail->subject = sprintf($GLOBALS['TL_LANG']['MSC']['adminSubject'], \Idna::decode(\Environment::get('host'))); $strData = "\n\n"; // Add user details foreach ($arrData as $k => $v) { if ($k == 'password' || $k == 'tstamp' || $k == 'activation' || $k == 'dateAdded') { continue; } $v = \StringUtil::deserialize($v); if ($k == 'dateOfBirth' && strlen($v)) { $v = \Date::parse(\Config::get('dateFormat'), $v); } $strData .= $GLOBALS['TL_LANG']['tl_member'][$k][0] . ': ' . (is_array($v) ? implode(', ', $v) : $v) . "\n"; } $objEmail->text = sprintf($GLOBALS['TL_LANG']['MSC']['adminText'], $intId, $strData . "\n") . "\n"; $objEmail->sendTo($GLOBALS['TL_ADMIN_EMAIL']); $this->log('A new user (ID ' . $intId . ') has registered on the website', __METHOD__, TL_ACCESS); }
/** * Notify the subscribers of new comments * * @param CommentsModel $objComment */ public static function notifyCommentsSubscribers(CommentsModel $objComment) { // Notified already if ($objComment->notified) { return; } $objNotify = \CommentsNotifyModel::findActiveBySourceAndParent($objComment->source, $objComment->parent); // No subscriptions if ($objNotify === null) { return; } while ($objNotify->next()) { // Don't notify the commentor about his own comment if ($objNotify->email == $objComment->email) { continue; } // Prepare the URL $strUrl = \Idna::decode(\Environment::get('base')) . $objNotify->url; $objEmail = new \Email(); $objEmail->from = $GLOBALS['TL_ADMIN_EMAIL']; $objEmail->fromName = $GLOBALS['TL_ADMIN_NAME']; $objEmail->subject = sprintf($GLOBALS['TL_LANG']['MSC']['com_notifySubject'], \Idna::decode(\Environment::get('host'))); $objEmail->text = sprintf($GLOBALS['TL_LANG']['MSC']['com_notifyMessage'], $objNotify->name, $strUrl, $strUrl . '?token=' . $objNotify->tokenRemove); $objEmail->sendTo($objNotify->email); } $objComment->notified = 1; $objComment->save(); }
/** * Encode the domain in an URL * * @param string $strUrl The URL * * @return string The encoded URL * * @deprecated Deprecated since Contao 4.0, to be removed in Contao 5.0. * Use Idna::encodeUrl() instead. */ protected function idnaEncodeUrl($strUrl) { @trigger_error('Using System::idnaEncodeUrl() has been deprecated and will no longer work in Contao 5.0. Use Idna::encodeUrl() instead.', E_USER_DEPRECATED); return \Idna::encodeUrl($strUrl); }
/** * Add a new recipient * * @param string $strEmail * @param array $arrNew */ protected function addRecipient($strEmail, $arrNew) { // Remove old subscriptions that have not been activated yet if (($objOld = \NewsletterRecipientsModel::findBy(array("email=? AND active=''"), $strEmail)) !== null) { while ($objOld->next()) { $objOld->delete(); } } $time = time(); $strToken = md5(uniqid(mt_rand(), true)); // Add the new subscriptions foreach ($arrNew as $id) { $objRecipient = new \NewsletterRecipientsModel(); $objRecipient->pid = $id; $objRecipient->tstamp = $time; $objRecipient->email = $strEmail; $objRecipient->active = ''; $objRecipient->addedOn = $time; $objRecipient->ip = $this->anonymizeIp(\Environment::get('ip')); $objRecipient->token = $strToken; $objRecipient->confirmed = ''; $objRecipient->save(); // Remove the blacklist entry (see #4999) if (($objBlacklist = \NewsletterBlacklistModel::findByHashAndPid(md5($strEmail), $id)) !== null) { $objBlacklist->delete(); } } // Get the channels $objChannel = \NewsletterChannelModel::findByIds($arrNew); // Prepare the simple token data $arrData = array(); $arrData['token'] = $strToken; $arrData['domain'] = \Idna::decode(\Environment::get('host')); $arrData['link'] = \Idna::decode(\Environment::get('base')) . \Environment::get('request') . (strpos(\Environment::get('request'), '?') !== false ? '&' : '?') . 'token=' . $strToken; $arrData['channel'] = $arrData['channels'] = implode("\n", $objChannel->fetchEach('title')); // Activation e-mail $objEmail = new \Email(); $objEmail->from = $GLOBALS['TL_ADMIN_EMAIL']; $objEmail->fromName = $GLOBALS['TL_ADMIN_NAME']; $objEmail->subject = sprintf($GLOBALS['TL_LANG']['MSC']['nl_subject'], \Idna::decode(\Environment::get('host'))); $objEmail->text = \StringUtil::parseSimpleTokens($this->nl_subscribe, $arrData); $objEmail->sendTo($strEmail); // Redirect to the jumpTo page if ($this->jumpTo && ($objTarget = $this->objModel->getRelated('jumpTo')) instanceof PageModel) { /** @var PageModel $objTarget */ $this->redirect($objTarget->getFrontendUrl()); } \System::getContainer()->get('session')->getFlashBag()->set('nl_confirm', $GLOBALS['TL_LANG']['MSC']['nl_confirm']); $this->reload(); }
/** * Return 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.template AS channelTemplate, c.sender AS channelSender, c.senderName as channelSenderName 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 ''; } // Set the template if ($objNewsletter->template == '') { $objNewsletter->template = $objNewsletter->channelTemplate; } // Set the sender address if ($objNewsletter->sender == '') { $objNewsletter->sender = $objNewsletter->channelSender; } // Set the sender name if ($objNewsletter->senderName == '') { $objNewsletter->senderName = $objNewsletter->channelSenderName; } // No sender address given if ($objNewsletter->sender == '') { throw new InternalServerErrorException('No sender address given. Please check the newsletter channel settings.'); } $arrAttachments = array(); // Add attachments if ($objNewsletter->addFile) { $files = \StringUtil::deserialize($objNewsletter->files); if (!empty($files) && is_array($files)) { $objFiles = \FilesModel::findMultipleByUuids($files); if ($objFiles !== null) { 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); } /** @var SessionInterface $objSession */ $objSession = \System::getContainer()->get('session'); // Send newsletter if (\Input::get('token') != '' && \Input::get('token') == $objSession->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) { $objSession->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>' . \Idna::decodeEmail($objRecipients->email) . '</strong><br>'; } } echo '<div style="margin-top:12px">'; // Redirect back home if ($objRecipients->numRows < 1 || $intStart + $intPages >= $intTotal) { $objSession->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 "' . \Idna::decodeEmail($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)); $objSession->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="' . \StringUtil::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, \Idna::decodeEmail($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> <fieldset class="tl_tbox nolegend"> <div class="w50 widget"> <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 widget"> <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 widget"> <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 widget"> <h3><label for="ctrl_recipient">' . $GLOBALS['TL_LANG']['tl_newsletter']['sendPreviewTo'][0] . '</label></h3> <input type="text" name="recipient" id="ctrl_recipient" value="' . \Idna::decodeEmail($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> </fieldset> </div>'; $return .= ' <div class="tl_formbody_submit"> <div class="tl_submit_container"> <button type="submit" name="preview" class="tl_submit" accesskey="p">' . $GLOBALS['TL_LANG']['tl_newsletter']['preview'] . '</button> <button type="submit" id="send" class="tl_submit" accesskey="s" onclick="return confirm(\'' . str_replace("'", "\\'", $GLOBALS['TL_LANG']['tl_newsletter']['sendConfirm']) . '\')">' . $GLOBALS['TL_LANG']['tl_newsletter']['send'][0] . '</button> </div> </div> </form>'; unset($_SESSION['TL_PREVIEW_MAIL_ERROR']); return $return; }
/** * Remove the recipient * * @param string $strEmail * @param array $arrRemove */ protected function removeRecipient($strEmail, $arrRemove) { // Remove the subscriptions if (($objRemove = \NewsletterRecipientsModel::findByEmailAndPids($strEmail, $arrRemove)) !== null) { while ($objRemove->next()) { $strHash = md5($objRemove->email); // Add a blacklist entry (see #4999) if (($objBlacklist = \NewsletterBlacklistModel::findByHashAndPid($strHash, $objRemove->pid)) === null) { $objBlacklist = new \NewsletterBlacklistModel(); $objBlacklist->pid = $objRemove->pid; $objBlacklist->hash = $strHash; $objBlacklist->save(); } $objRemove->delete(); } } // Get the channels $objChannels = \NewsletterChannelModel::findByIds($arrRemove); $arrChannels = $objChannels->fetchEach('title'); // HOOK: post unsubscribe callback if (isset($GLOBALS['TL_HOOKS']['removeRecipient']) && is_array($GLOBALS['TL_HOOKS']['removeRecipient'])) { foreach ($GLOBALS['TL_HOOKS']['removeRecipient'] as $callback) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($strEmail, $arrRemove); } } // Prepare the simple token data $arrData = array(); $arrData['domain'] = \Idna::decode(\Environment::get('host')); $arrData['channel'] = $arrData['channels'] = implode("\n", $arrChannels); // Confirmation e-mail $objEmail = new \Email(); $objEmail->from = $GLOBALS['TL_ADMIN_EMAIL']; $objEmail->fromName = $GLOBALS['TL_ADMIN_NAME']; $objEmail->subject = sprintf($GLOBALS['TL_LANG']['MSC']['nl_subject'], \Idna::decode(\Environment::get('host'))); $objEmail->text = \StringUtil::parseSimpleTokens($this->nl_unsubscribe, $arrData); $objEmail->sendTo($strEmail); // Redirect to the jumpTo page if ($this->jumpTo && ($objTarget = $this->objModel->getRelated('jumpTo')) !== null) { $this->redirect($this->generateFrontendUrl($objTarget->row())); } \System::getContainer()->get('session')->getFlashBag()->set('nl_removed', $GLOBALS['TL_LANG']['MSC']['nl_removed']); $this->reload(); }
/** * Try to login the current user * * @return boolean True if the user could be logged in */ public function login() { \System::loadLanguageFile('default'); // Do not continue if username or password are missing if (empty($_POST['username']) || empty($_POST['password'])) { return false; } // Load the user object if ($this->findBy('username', \Input::post('username', true)) == false) { $blnLoaded = false; // HOOK: pass credentials to callback functions if (isset($GLOBALS['TL_HOOKS']['importUser']) && is_array($GLOBALS['TL_HOOKS']['importUser'])) { foreach ($GLOBALS['TL_HOOKS']['importUser'] as $callback) { $this->import($callback[0], 'objImport', true); $blnLoaded = $this->objImport->{$callback[1]}(\Input::post('username', true), \Input::postUnsafeRaw('password'), $this->strTable); // Load successfull if ($blnLoaded === true) { break; } } } // Return if the user still cannot be loaded if (!$blnLoaded || $this->findBy('username', \Input::post('username', true)) == false) { \Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']); $this->log('Could not find user "' . \Input::post('username', true) . '"', __METHOD__, TL_ACCESS); return false; } } $time = time(); // Set the user language if (\Input::post('language')) { $this->language = \Input::post('language'); } // Lock the account if there are too many login attempts if ($this->loginCount < 1) { $this->locked = $time; $this->loginCount = \Config::get('loginCount'); $this->save(); // Add a log entry and the error message, because checkAccountStatus() will not be called (see #4444) $this->log('User "' . $this->username . '" has been locked for ' . ceil(\Config::get('lockPeriod') / 60) . ' minutes', __METHOD__, TL_ACCESS); \Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['accountLocked'], ceil(($this->locked + \Config::get('lockPeriod') - $time) / 60))); // Send admin notification if (\Config::get('adminEmail') != '') { $objEmail = new \Email(); $objEmail->subject = $GLOBALS['TL_LANG']['MSC']['lockedAccount'][0]; $objEmail->text = sprintf($GLOBALS['TL_LANG']['MSC']['lockedAccount'][1], $this->username, TL_MODE == 'FE' ? $this->firstname . " " . $this->lastname : $this->name, \Idna::decode(\Environment::get('base')), ceil(\Config::get('lockPeriod') / 60)); $objEmail->sendTo(\Config::get('adminEmail')); } return false; } // Check the account status if ($this->checkAccountStatus() == false) { return false; } // The password has been generated with crypt() if (\Encryption::test($this->password)) { $blnAuthenticated = \Encryption::verify(\Input::postUnsafeRaw('password'), $this->password); } else { list($strPassword, $strSalt) = explode(':', $this->password); $blnAuthenticated = $strSalt == '' ? $strPassword === sha1(\Input::postUnsafeRaw('password')) : $strPassword === sha1($strSalt . \Input::postUnsafeRaw('password')); // Store a SHA-512 encrpyted version of the password if ($blnAuthenticated) { $this->password = \Encryption::hash(\Input::postUnsafeRaw('password')); } } // HOOK: pass credentials to callback functions if (!$blnAuthenticated && isset($GLOBALS['TL_HOOKS']['checkCredentials']) && is_array($GLOBALS['TL_HOOKS']['checkCredentials'])) { foreach ($GLOBALS['TL_HOOKS']['checkCredentials'] as $callback) { $this->import($callback[0], 'objAuth', true); $blnAuthenticated = $this->objAuth->{$callback[1]}(\Input::post('username', true), \Input::postUnsafeRaw('password'), $this); // Authentication successfull if ($blnAuthenticated === true) { break; } } } // Redirect if the user could not be authenticated if (!$blnAuthenticated) { --$this->loginCount; $this->save(); \Message::addError($GLOBALS['TL_LANG']['ERR']['invalidLogin']); $this->log('Invalid password submitted for username "' . $this->username . '"', __METHOD__, TL_ACCESS); return false; } $this->setUserFromDb(); // Update the record $this->lastLogin = $this->currentLogin; $this->currentLogin = $time; $this->loginCount = \Config::get('loginCount'); $this->save(); // Generate the session $this->regenerateSessionId(); $this->generateSession(); $this->log('User "' . $this->username . '" has logged in', __METHOD__, TL_ACCESS); // HOOK: post login callback if (isset($GLOBALS['TL_HOOKS']['postLogin']) && is_array($GLOBALS['TL_HOOKS']['postLogin'])) { foreach ($GLOBALS['TL_HOOKS']['postLogin'] as $callback) { $this->import($callback[0], 'objLogin', true); $this->objLogin->{$callback[1]}($this); } } return true; }
/** * Replace insert tags with their values * * @param string $strBuffer The text with the tags to be replaced * @param boolean $blnCache If false, non-cacheable tags will be replaced * * @return string The text with the replaced tags */ protected function doReplace($strBuffer, $blnCache) { /** @var PageModel $objPage */ global $objPage; // Preserve insert tags if (\Config::get('disableInsertTags')) { return \StringUtil::restoreBasicEntities($strBuffer); } $tags = preg_split('/{{([^{}]+)}}/', $strBuffer, -1, PREG_SPLIT_DELIM_CAPTURE); if (count($tags) < 2) { return \StringUtil::restoreBasicEntities($strBuffer); } $strBuffer = ''; // Create one cache per cache setting (see #7700) static $arrItCache; $arrCache =& $arrItCache[$blnCache]; for ($_rit = 0, $_cnt = count($tags); $_rit < $_cnt; $_rit += 2) { $strBuffer .= $tags[$_rit]; $strTag = $tags[$_rit + 1]; // Skip empty tags if ($strTag == '') { continue; } $flags = explode('|', $strTag); $tag = array_shift($flags); $elements = explode('::', $tag); // Load the value from cache if (isset($arrCache[$strTag]) && !in_array('refresh', $flags)) { $strBuffer .= $arrCache[$strTag]; continue; } // Skip certain elements if the output will be cached if ($blnCache) { if ($elements[0] == 'date' || $elements[0] == 'ua' || $elements[0] == 'post' || $elements[0] == 'file' && !\Validator::isStringUuid($elements[1]) || $elements[1] == 'back' || $elements[1] == 'referer' || $elements[0] == 'request_token' || $elements[0] == 'toggle_view' || strncmp($elements[0], 'cache_', 6) === 0 || in_array('uncached', $flags)) { /** @var FragmentHandler $fragmentHandler */ $fragmentHandler = \System::getContainer()->get('fragment.handler'); $strBuffer .= $fragmentHandler->render(new ControllerReference('contao.controller.insert_tags:renderAction', ['insertTag' => '{{' . $strTag . '}}']), 'esi'); continue; } } $arrCache[$strTag] = ''; // Replace the tag switch (strtolower($elements[0])) { // Date case 'date': $arrCache[$strTag] = \Date::parse($elements[1] ?: \Config::get('dateFormat')); break; // Accessibility tags // Accessibility tags case 'lang': if ($elements[1] == '') { $arrCache[$strTag] = '</span>'; } else { $arrCache[$strTag] = $arrCache[$strTag] = '<span lang="' . \StringUtil::specialchars($elements[1]) . '">'; } break; // Line break // Line break case 'br': $arrCache[$strTag] = '<br>'; break; // E-mail addresses // E-mail addresses case 'email': case 'email_open': case 'email_url': if ($elements[1] == '') { $arrCache[$strTag] = ''; break; } $strEmail = \StringUtil::encodeEmail($elements[1]); // Replace the tag switch (strtolower($elements[0])) { case 'email': $arrCache[$strTag] = '<a href="mailto:' . $strEmail . '" class="email">' . preg_replace('/\\?.*$/', '', $strEmail) . '</a>'; break; case 'email_open': $arrCache[$strTag] = '<a href="mailto:' . $strEmail . '" title="' . $strEmail . '" class="email">'; break; case 'email_url': $arrCache[$strTag] = $strEmail; break; } break; // Label tags // Label tags case 'label': $keys = explode(':', $elements[1]); if (count($keys) < 2) { $arrCache[$strTag] = ''; break; } $file = $keys[0]; // Map the key (see #7217) switch ($file) { case 'CNT': $file = 'countries'; break; case 'LNG': $file = 'languages'; break; case 'MOD': case 'FMD': $file = 'modules'; break; case 'FFL': $file = 'tl_form_field'; break; case 'CACHE': $file = 'tl_page'; break; case 'XPL': $file = 'explain'; break; case 'XPT': $file = 'exception'; break; case 'MSC': case 'ERR': case 'CTE': case 'PTY': case 'FOP': case 'CHMOD': case 'DAYS': case 'MONTHS': case 'UNITS': case 'CONFIRM': case 'DP': case 'COLS': $file = 'default'; break; } \System::loadLanguageFile($file); if (count($keys) == 2) { $arrCache[$strTag] = $GLOBALS['TL_LANG'][$keys[0]][$keys[1]]; } else { $arrCache[$strTag] = $GLOBALS['TL_LANG'][$keys[0]][$keys[1]][$keys[2]]; } break; // Front end user // Front end user case 'user': if (FE_USER_LOGGED_IN) { $this->import('FrontendUser', 'User'); $value = $this->User->{$elements[1]}; if ($value == '') { $arrCache[$strTag] = $value; break; } $this->loadDataContainer('tl_member'); if ($GLOBALS['TL_DCA']['tl_member']['fields'][$elements[1]]['inputType'] == 'password') { $arrCache[$strTag] = ''; break; } $value = \StringUtil::deserialize($value); // Decrypt the value if ($GLOBALS['TL_DCA']['tl_member']['fields'][$elements[1]]['eval']['encrypt']) { $value = \Encryption::decrypt($value); } $rgxp = $GLOBALS['TL_DCA']['tl_member']['fields'][$elements[1]]['eval']['rgxp']; $opts = $GLOBALS['TL_DCA']['tl_member']['fields'][$elements[1]]['options']; $rfrc = $GLOBALS['TL_DCA']['tl_member']['fields'][$elements[1]]['reference']; if ($rgxp == 'date') { $arrCache[$strTag] = \Date::parse(\Config::get('dateFormat'), $value); } elseif ($rgxp == 'time') { $arrCache[$strTag] = \Date::parse(\Config::get('timeFormat'), $value); } elseif ($rgxp == 'datim') { $arrCache[$strTag] = \Date::parse(\Config::get('datimFormat'), $value); } elseif (is_array($value)) { $arrCache[$strTag] = implode(', ', $value); } elseif (is_array($opts) && array_is_assoc($opts)) { $arrCache[$strTag] = isset($opts[$value]) ? $opts[$value] : $value; } elseif (is_array($rfrc)) { $arrCache[$strTag] = isset($rfrc[$value]) ? is_array($rfrc[$value]) ? $rfrc[$value][0] : $rfrc[$value] : $value; } else { $arrCache[$strTag] = $value; } // Convert special characters (see #1890) $arrCache[$strTag] = \StringUtil::specialchars($arrCache[$strTag]); } break; // Link // Link case 'link': case 'link_open': case 'link_url': case 'link_title': case 'link_target': case 'link_name': $strTarget = null; // Back link if ($elements[1] == 'back') { $strUrl = 'javascript:history.go(-1)'; $strTitle = $GLOBALS['TL_LANG']['MSC']['goBack']; // No language files if the page is cached if (!strlen($strTitle)) { $strTitle = 'Go back'; } $strName = $strTitle; } elseif (strncmp($elements[1], 'http://', 7) === 0 || strncmp($elements[1], 'https://', 8) === 0) { $strUrl = $elements[1]; $strTitle = $elements[1]; $strName = str_replace(array('http://', 'https://'), '', $elements[1]); } else { // User login page if ($elements[1] == 'login') { if (!FE_USER_LOGGED_IN) { break; } $this->import('FrontendUser', 'User'); $elements[1] = $this->User->loginPage; } $objNextPage = \PageModel::findByIdOrAlias($elements[1]); if ($objNextPage === null) { break; } // Page type specific settings (thanks to Andreas Schempp) switch ($objNextPage->type) { case 'redirect': $strUrl = $objNextPage->url; if (strncasecmp($strUrl, 'mailto:', 7) === 0) { $strUrl = \StringUtil::encodeEmail($strUrl); } break; case 'forward': if ($objNextPage->jumpTo) { /** @var PageModel $objNext */ $objNext = $objNextPage->getRelated('jumpTo'); } else { $objNext = \PageModel::findFirstPublishedRegularByPid($objNextPage->id); } if ($objNext instanceof PageModel) { $strUrl = $objNext->getFrontendUrl(); break; } // DO NOT ADD A break; STATEMENT // DO NOT ADD A break; STATEMENT default: $strUrl = $objNextPage->getFrontendUrl(); break; } $strName = $objNextPage->title; $strTarget = $objNextPage->target ? ' target="_blank"' : ''; $strTitle = $objNextPage->pageTitle ?: $objNextPage->title; } // Replace the tag switch (strtolower($elements[0])) { case 'link': $arrCache[$strTag] = sprintf('<a href="%s" title="%s"%s>%s</a>', $strUrl, \StringUtil::specialchars($strTitle), $strTarget, $strName); break; case 'link_open': $arrCache[$strTag] = sprintf('<a href="%s" title="%s"%s>', $strUrl, \StringUtil::specialchars($strTitle), $strTarget); break; case 'link_url': $arrCache[$strTag] = $strUrl; break; case 'link_title': $arrCache[$strTag] = \StringUtil::specialchars($strTitle); break; case 'link_target': $arrCache[$strTag] = $strTarget; break; case 'link_name': $arrCache[$strTag] = $strName; break; } break; // Closing link tag // Closing link tag case 'link_close': case 'email_close': $arrCache[$strTag] = '</a>'; break; // Insert article // Insert article case 'insert_article': if (($strOutput = $this->getArticle($elements[1], false, true)) !== false) { $arrCache[$strTag] = ltrim($strOutput); } else { $arrCache[$strTag] = '<p class="error">' . sprintf($GLOBALS['TL_LANG']['MSC']['invalidPage'], $elements[1]) . '</p>'; } break; // Insert content element // Insert content element case 'insert_content': $arrCache[$strTag] = $this->getContentElement($elements[1]); break; // Insert module // Insert module case 'insert_module': $arrCache[$strTag] = $this->getFrontendModule($elements[1]); break; // Insert form // Insert form case 'insert_form': $arrCache[$strTag] = $this->getForm($elements[1]); break; // Article // Article case 'article': case 'article_open': case 'article_url': case 'article_title': if (($objArticle = \ArticleModel::findByIdOrAlias($elements[1])) === null || !($objPid = $objArticle->getRelated('pid')) instanceof PageModel) { break; } /** @var PageModel $objPid */ $strUrl = $objPid->getFrontendUrl('/articles/' . ($objArticle->alias ?: $objArticle->id)); // Replace the tag switch (strtolower($elements[0])) { case 'article': $arrCache[$strTag] = sprintf('<a href="%s" title="%s">%s</a>', $strUrl, \StringUtil::specialchars($objArticle->title), $objArticle->title); break; case 'article_open': $arrCache[$strTag] = sprintf('<a href="%s" title="%s">', $strUrl, \StringUtil::specialchars($objArticle->title)); break; case 'article_url': $arrCache[$strTag] = $strUrl; break; case 'article_title': $arrCache[$strTag] = \StringUtil::specialchars($objArticle->title); break; } break; // Article teaser // Article teaser case 'article_teaser': $objTeaser = \ArticleModel::findByIdOrAlias($elements[1]); if ($objTeaser !== null) { $arrCache[$strTag] = \StringUtil::toHtml5($objTeaser->teaser); } break; // Last update // Last update case 'last_update': $strQuery = "SELECT MAX(tstamp) AS tc"; $bundles = \System::getContainer()->getParameter('kernel.bundles'); if (isset($bundles['ContaoNewsBundle'])) { $strQuery .= ", (SELECT MAX(tstamp) FROM tl_news) AS tn"; } if (isset($bundles['ContaoCalendarBundle'])) { $strQuery .= ", (SELECT MAX(tstamp) FROM tl_calendar_events) AS te"; } $strQuery .= " FROM tl_content"; $objUpdate = \Database::getInstance()->query($strQuery); if ($objUpdate->numRows) { $arrCache[$strTag] = \Date::parse($elements[1] ?: \Config::get('datimFormat'), max($objUpdate->tc, $objUpdate->tn, $objUpdate->te)); } break; // Version // Version case 'version': $arrCache[$strTag] = VERSION . '.' . BUILD; break; // Request token // Request token case 'request_token': $arrCache[$strTag] = REQUEST_TOKEN; break; // POST data // POST data case 'post': $arrCache[$strTag] = \Input::post($elements[1]); break; // Mobile/desktop toggle (see #6469) // Mobile/desktop toggle (see #6469) case 'toggle_view': $strUrl = ampersand(\Environment::get('request')); $strGlue = strpos($strUrl, '?') === false ? '?' : '&'; if (\Input::cookie('TL_VIEW') == 'mobile' || \Environment::get('agent')->mobile && \Input::cookie('TL_VIEW') != 'desktop') { $arrCache[$strTag] = '<a href="' . $strUrl . $strGlue . 'toggle_view=desktop" class="toggle_desktop" title="' . \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['toggleDesktop'][1]) . '">' . $GLOBALS['TL_LANG']['MSC']['toggleDesktop'][0] . '</a>'; } else { $arrCache[$strTag] = '<a href="' . $strUrl . $strGlue . 'toggle_view=mobile" class="toggle_mobile" title="' . \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['toggleMobile'][1]) . '">' . $GLOBALS['TL_LANG']['MSC']['toggleMobile'][0] . '</a>'; } break; // Conditional tags (if) // Conditional tags (if) case 'iflng': if ($elements[1] != '' && $elements[1] != $objPage->language) { for (; $_rit < $_cnt; $_rit += 2) { if ($tags[$_rit + 1] == 'iflng' || $tags[$_rit + 1] == 'iflng::' . $objPage->language) { break; } } } unset($arrCache[$strTag]); break; // Conditional tags (if not) // Conditional tags (if not) case 'ifnlng': if ($elements[1] != '') { $langs = \StringUtil::trimsplit(',', $elements[1]); if (in_array($objPage->language, $langs)) { for (; $_rit < $_cnt; $_rit += 2) { if ($tags[$_rit + 1] == 'ifnlng') { break; } } } } unset($arrCache[$strTag]); break; // Environment // Environment case 'env': switch ($elements[1]) { case 'host': $arrCache[$strTag] = \Idna::decode(\Environment::get('host')); break; case 'http_host': $arrCache[$strTag] = \Idna::decode(\Environment::get('httpHost')); break; case 'url': $arrCache[$strTag] = \Idna::decode(\Environment::get('url')); break; case 'path': $arrCache[$strTag] = \Idna::decode(\Environment::get('base')); break; case 'request': $arrCache[$strTag] = \Environment::get('indexFreeRequest'); break; case 'ip': $arrCache[$strTag] = \Environment::get('ip'); break; case 'referer': $arrCache[$strTag] = $this->getReferer(true); break; case 'files_url': $arrCache[$strTag] = TL_FILES_URL; break; case 'assets_url': case 'plugins_url': case 'script_url': $arrCache[$strTag] = TL_ASSETS_URL; break; case 'base_url': $arrCache[$strTag] = \System::getContainer()->get('request_stack')->getCurrentRequest()->getBaseUrl(); break; } break; // Page // Page case 'page': if ($elements[1] == 'pageTitle' && $objPage->pageTitle == '') { $elements[1] = 'title'; } elseif ($elements[1] == 'parentPageTitle' && $objPage->parentPageTitle == '') { $elements[1] = 'parentTitle'; } elseif ($elements[1] == 'mainPageTitle' && $objPage->mainPageTitle == '') { $elements[1] = 'mainTitle'; } // Do not use \StringUtil::specialchars() here (see #4687) $arrCache[$strTag] = $objPage->{$elements[1]}; break; // User agent // User agent case 'ua': $ua = \Environment::get('agent'); if ($elements[1] != '') { $arrCache[$strTag] = $ua->{$elements[1]}; } else { $arrCache[$strTag] = ''; } break; // Abbreviations // Abbreviations case 'abbr': case 'acronym': if ($elements[1] != '') { $arrCache[$strTag] = '<abbr title="' . \StringUtil::specialchars($elements[1]) . '">'; } else { $arrCache[$strTag] = '</abbr>'; } break; // Images // Images case 'image': case 'picture': $width = null; $height = null; $alt = ''; $class = ''; $rel = ''; $strFile = $elements[1]; $mode = ''; $size = null; $strTemplate = 'picture_default'; // Take arguments if (strpos($elements[1], '?') !== false) { $arrChunks = explode('?', urldecode($elements[1]), 2); $strSource = \StringUtil::decodeEntities($arrChunks[1]); $strSource = str_replace('[&]', '&', $strSource); $arrParams = explode('&', $strSource); foreach ($arrParams as $strParam) { list($key, $value) = explode('=', $strParam); switch ($key) { case 'width': $width = $value; break; case 'height': $height = $value; break; case 'alt': $alt = $value; break; case 'class': $class = $value; break; case 'rel': $rel = $value; break; case 'mode': $mode = $value; break; case 'size': $size = (int) $value; break; case 'template': $strTemplate = preg_replace('/[^a-z0-9_]/i', '', $value); break; } } $strFile = $arrChunks[0]; } if (\Validator::isUuid($strFile)) { // Handle UUIDs $objFile = \FilesModel::findByUuid($strFile); if ($objFile === null) { $arrCache[$strTag] = ''; break; } $strFile = $objFile->path; } elseif (is_numeric($strFile)) { // Handle numeric IDs (see #4805) $objFile = \FilesModel::findByPk($strFile); if ($objFile === null) { $arrCache[$strTag] = ''; break; } $strFile = $objFile->path; } else { // Check the path if (\Validator::isInsecurePath($strFile)) { throw new \RuntimeException('Invalid path ' . $strFile); } } // Check the maximum image width if (\Config::get('maxImageWidth') > 0 && $width > \Config::get('maxImageWidth')) { $width = \Config::get('maxImageWidth'); $height = null; } // Generate the thumbnail image try { // Image if (strtolower($elements[0]) == 'image') { $dimensions = ''; $src = \System::getContainer()->get('contao.image.image_factory')->create(TL_ROOT . '/' . rawurldecode($strFile), array($width, $height, $mode))->getUrl(TL_ROOT); $objFile = new \File(rawurldecode($src)); // Add the image dimensions if (($imgSize = $objFile->imageSize) !== false) { $dimensions = ' width="' . \StringUtil::specialchars($imgSize[0]) . '" height="' . \StringUtil::specialchars($imgSize[1]) . '"'; } $arrCache[$strTag] = '<img src="' . TL_FILES_URL . $src . '" ' . $dimensions . ' alt="' . \StringUtil::specialchars($alt) . '"' . ($class != '' ? ' class="' . \StringUtil::specialchars($class) . '"' : '') . '>'; } else { $picture = \System::getContainer()->get('contao.image.picture_factory')->create(TL_ROOT . '/' . $strFile, $size); $picture = array('img' => $picture->getImg(TL_ROOT), 'sources' => $picture->getSources(TL_ROOT)); $picture['alt'] = $alt; $picture['class'] = $class; $pictureTemplate = new \FrontendTemplate($strTemplate); $pictureTemplate->setData($picture); $arrCache[$strTag] = $pictureTemplate->parse(); } // Add a lightbox link if ($rel != '') { if (strncmp($rel, 'lightbox', 8) !== 0) { $attribute = ' rel="' . \StringUtil::specialchars($rel) . '"'; } else { $attribute = ' data-lightbox="' . \StringUtil::specialchars(substr($rel, 8)) . '"'; } $arrCache[$strTag] = '<a href="' . TL_FILES_URL . $strFile . '"' . ($alt != '' ? ' title="' . \StringUtil::specialchars($alt) . '"' : '') . $attribute . '>' . $arrCache[$strTag] . '</a>'; } } catch (\Exception $e) { $arrCache[$strTag] = ''; } break; // Files (UUID or template path) // Files (UUID or template path) case 'file': if (\Validator::isUuid($elements[1])) { $objFile = \FilesModel::findByUuid($elements[1]); if ($objFile !== null) { $arrCache[$strTag] = $objFile->path; break; } } $arrGet = $_GET; \Input::resetCache(); $strFile = $elements[1]; // Take arguments and add them to the $_GET array if (strpos($elements[1], '?') !== false) { $arrChunks = explode('?', urldecode($elements[1])); $strSource = \StringUtil::decodeEntities($arrChunks[1]); $strSource = str_replace('[&]', '&', $strSource); $arrParams = explode('&', $strSource); foreach ($arrParams as $strParam) { $arrParam = explode('=', $strParam); $_GET[$arrParam[0]] = $arrParam[1]; } $strFile = $arrChunks[0]; } // Check the path if (\Validator::isInsecurePath($strFile)) { throw new \RuntimeException('Invalid path ' . $strFile); } // Include .php, .tpl, .xhtml and .html5 files if (preg_match('/\\.(php|tpl|xhtml|html5)$/', $strFile) && file_exists(TL_ROOT . '/templates/' . $strFile)) { ob_start(); include TL_ROOT . '/templates/' . $strFile; $arrCache[$strTag] = ob_get_clean(); } $_GET = $arrGet; \Input::resetCache(); break; // HOOK: pass unknown tags to callback functions // HOOK: pass unknown tags to callback functions default: if (isset($GLOBALS['TL_HOOKS']['replaceInsertTags']) && is_array($GLOBALS['TL_HOOKS']['replaceInsertTags'])) { foreach ($GLOBALS['TL_HOOKS']['replaceInsertTags'] as $callback) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($tag, $blnCache, $arrCache[$strTag], $flags, $tags, $arrCache, $_rit, $_cnt); // see #6672 // Replace the tag and stop the loop if ($varValue !== false) { $arrCache[$strTag] = $varValue; break; } } } \System::getContainer()->get('monolog.logger.contao')->log(LogLevel::INFO, 'Unknown insert tag: ' . $strTag); break; } // Handle the flags if (!empty($flags)) { foreach ($flags as $flag) { switch ($flag) { case 'addslashes': case 'standardize': case 'ampersand': case 'specialchars': case 'nl2br': case 'nl2br_pre': case 'strtolower': case 'utf8_strtolower': case 'strtoupper': case 'utf8_strtoupper': case 'ucfirst': case 'lcfirst': case 'ucwords': case 'trim': case 'rtrim': case 'ltrim': case 'utf8_romanize': case 'urlencode': case 'rawurlencode': $arrCache[$strTag] = $flag($arrCache[$strTag]); break; case 'encodeEmail': $arrCache[$strTag] = \StringUtil::$flag($arrCache[$strTag]); break; case 'number_format': $arrCache[$strTag] = \System::getFormattedNumber($arrCache[$strTag], 0); break; case 'currency_format': $arrCache[$strTag] = \System::getFormattedNumber($arrCache[$strTag], 2); break; case 'readable_size': $arrCache[$strTag] = \System::getReadableSize($arrCache[$strTag]); break; case 'flatten': if (!is_array($arrCache[$strTag])) { break; } $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($arrCache[$strTag])); $result = array(); foreach ($it as $leafValue) { $keys = array(); foreach (range(0, $it->getDepth()) as $depth) { $keys[] = $it->getSubIterator($depth)->key(); } $result[] = implode('.', $keys) . ': ' . $leafValue; } $arrCache[$strTag] = implode(', ', $result); break; // HOOK: pass unknown flags to callback functions // HOOK: pass unknown flags to callback functions default: if (isset($GLOBALS['TL_HOOKS']['insertTagFlags']) && is_array($GLOBALS['TL_HOOKS']['insertTagFlags'])) { foreach ($GLOBALS['TL_HOOKS']['insertTagFlags'] as $callback) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($flag, $tag, $arrCache[$strTag], $flags, $blnCache, $tags, $arrCache, $_rit, $_cnt); // see #5806 // Replace the tag and stop the loop if ($varValue !== false) { $arrCache[$strTag] = $varValue; break; } } } \System::getContainer()->get('monolog.logger.contao')->log(LogLevel::INFO, 'Unknown insert tag flag: ' . $flag); break; } } } $strBuffer .= $arrCache[$strTag]; } return \StringUtil::restoreBasicEntities($strBuffer); }
protected function addSubscriber() { $varInput = Idna::encodeEmail(Input::post('email', true)); // Validate the e-mail address if (!Validator::isEmail($varInput)) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['email']; $this->reload(); } $objCleverReach = new CleverReach(); foreach ($this->clr_groups as $strGroupId) { $objCleverReach->addReceiver($varInput, $strGroupId); } $objCleverReach->sendActivationMail($varInput, $this->clr_form); // Redirect to the jumpTo page if ($this->jumpTo && ($objTarget = $this->objModel->getRelated('jumpTo')) !== null) { $this->redirect($this->generateFrontendUrl($objTarget->row())); } $_SESSION['SUBSCRIBE_CONFIRM'] = $GLOBALS['TL_LANG']['MSC']['nl_confirm']; $this->reload(); }
/** * Create a new user and redirect * * @param MemberModel $objMember */ protected function sendPasswordLink($objMember) { $confirmationId = md5(uniqid(mt_rand(), true)); // Store the confirmation ID $objMember = \MemberModel::findByPk($objMember->id); $objMember->activation = $confirmationId; $objMember->save(); // Prepare the simple token data $arrData = $objMember->row(); $arrData['domain'] = \Idna::decode(\Environment::get('host')); $arrData['link'] = \Idna::decode(\Environment::get('base')) . \Environment::get('request') . (strpos(\Environment::get('request'), '?') !== false ? '&' : '?') . 'token=' . $confirmationId; // Send e-mail $objEmail = new \Email(); $objEmail->from = $GLOBALS['TL_ADMIN_EMAIL']; $objEmail->fromName = $GLOBALS['TL_ADMIN_NAME']; $objEmail->subject = sprintf($GLOBALS['TL_LANG']['MSC']['passwordSubject'], \Idna::decode(\Environment::get('host'))); $objEmail->text = \StringUtil::parseSimpleTokens($this->reg_password, $arrData); $objEmail->sendTo($objMember->email); $this->log('A new password has been requested for user ID ' . $objMember->id . ' (' . \Idna::decodeEmail($objMember->email) . ')', __METHOD__, TL_ACCESS); // Check whether there is a jumpTo page if (($objJumpTo = $this->objModel->getRelated('jumpTo')) instanceof PageModel) { $this->jumpToOrReload($objJumpTo->row()); } $this->reload(); }
/** * 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' && !empty($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 = \StringUtil::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; // Check whether the current value is a field name // Check whether the current value is a field name case 'fieldname': if (!\Validator::isFieldName($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidFieldName'], $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; }
/** * Return all non-excluded fields of a record as HTML table * * @return string */ public function show() { if (!strlen($this->intId)) { return ''; } $objRow = $this->Database->prepare("SELECT * FROM " . $this->strTable . " WHERE id=?")->limit(1)->execute($this->intId); if ($objRow->numRows < 1) { return ''; } $count = 1; $return = ''; $row = $objRow->row(); // Get the order fields $objDcaExtractor = \DcaExtractor::getInstance($this->strTable); $arrOrder = $objDcaExtractor->getOrderFields(); // Get all fields $fields = array_keys($row); $allowedFields = array('id', 'pid', 'sorting', 'tstamp'); if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'])) { $allowedFields = array_unique(array_merge($allowedFields, array_keys($GLOBALS['TL_DCA'][$this->strTable]['fields']))); } // Use the field order of the DCA file $fields = array_intersect($allowedFields, $fields); // Show all allowed fields foreach ($fields as $i) { if (!in_array($i, $allowedFields) || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'password' || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['doNotShow'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['hideInput']) { continue; } // Special treatment for table tl_undo if ($this->strTable == 'tl_undo' && $i == 'data') { continue; } $value = \StringUtil::deserialize($row[$i]); // Decrypt the value if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['encrypt']) { $value = \Encryption::decrypt($value); } $class = $count++ % 2 == 0 ? ' class="tl_bg"' : ''; // Get the field value if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey'])) { $temp = array(); $chunks = explode('.', $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['foreignKey'], 2); foreach ((array) $value as $v) { $objKey = $this->Database->prepare("SELECT " . $chunks[1] . " AS value FROM " . $chunks[0] . " WHERE id=?")->limit(1)->execute($v); if ($objKey->numRows) { $temp[] = $objKey->value; } } $row[$i] = implode(', ', $temp); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'fileTree' || in_array($i, $arrOrder)) { if (is_array($value)) { foreach ($value as $kk => $vv) { $value[$kk] = $vv ? \StringUtil::binToUuid($vv) : ''; } $row[$i] = implode(', ', $value); } else { $row[$i] = $value ? \StringUtil::binToUuid($value) : ''; } } elseif (is_array($value)) { foreach ($value as $kk => $vv) { if (is_array($vv)) { $vals = array_values($vv); $value[$kk] = $vals[0] . ' (' . $vals[1] . ')'; } } $row[$i] = implode(', ', $value); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'date') { $row[$i] = $value ? \Date::parse(\Config::get('dateFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'time') { $row[$i] = $value ? \Date::parse(\Config::get('timeFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'datim' || in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['flag'], array(5, 6, 7, 8, 9, 10)) || $i == 'tstamp') { $row[$i] = $value ? \Date::parse(\Config::get('datimFormat'), $value) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['multiple']) { $row[$i] = $value != '' ? $GLOBALS['TL_LANG']['MSC']['yes'] : $GLOBALS['TL_LANG']['MSC']['no']; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['rgxp'] == 'email') { $row[$i] = \Idna::decodeEmail($value); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['inputType'] == 'textarea' && ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['allowHtml'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['preserveTags'])) { $row[$i] = \StringUtil::specialchars($value); } elseif (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'])) { $row[$i] = isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) ? is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]]) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['reference'][$row[$i]] : $row[$i]; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options'])) { $row[$i] = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['options'][$row[$i]]; } else { $row[$i] = $value; } // Label if (isset($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'])) { $label = is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$i]['label']; } else { $label = is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i]; } if ($label == '') { $label = $i; } $return .= ' <tr> <td' . $class . '><span class="tl_label">' . $label . ': </span></td> <td' . $class . '>' . $row[$i] . '</td> </tr>'; } // Special treatment for tl_undo if ($this->strTable == 'tl_undo') { $arrData = \StringUtil::deserialize($objRow->data); foreach ($arrData as $strTable => $arrTableData) { \System::loadLanguageFile($strTable); $this->loadDataContainer($strTable); foreach ($arrTableData as $arrRow) { $count = 0; $return .= ' <tr> <td colspan="2" style="padding:0"><div style="margin-bottom:26px;line-height:24px;border-bottom:1px dotted #ccc"> </div></td> </tr>'; foreach ($arrRow as $i => $v) { if (is_array(\StringUtil::deserialize($v))) { continue; } $class = $count++ % 2 == 0 ? ' class="tl_bg"' : ''; // Get the field label if (isset($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'])) { $label = is_array($GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']) ? $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label'][0] : $GLOBALS['TL_DCA'][$strTable]['fields'][$i]['label']; } else { $label = is_array($GLOBALS['TL_LANG']['MSC'][$i]) ? $GLOBALS['TL_LANG']['MSC'][$i][0] : $GLOBALS['TL_LANG']['MSC'][$i]; } if (!strlen($label)) { $label = $i; } // Always encode special characters (thanks to Oliver Klee) $return .= ' <tr> <td' . $class . '><span class="tl_label">' . $label . ': </span></td> <td' . $class . '>' . \StringUtil::specialchars($v) . '</td> </tr>'; } } } } // Return table return ' <table class="tl_show">' . $return . ' </table>'; }