/** * 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'; }
/** * Run the controller and parse the password template * * @return Response */ public function run() { /** @var BackendTemplate|object $objTemplate */ $objTemplate = new \BackendTemplate('be_password'); if (\Input::post('FORM_SUBMIT') == 'tl_password') { $pw = \Input::postUnsafeRaw('password'); $cnf = \Input::postUnsafeRaw('confirm'); // The passwords do not match if ($pw != $cnf) { \Message::addError($GLOBALS['TL_LANG']['ERR']['passwordMatch']); } elseif (Utf8::strlen($pw) < \Config::get('minPasswordLength')) { \Message::addError(sprintf($GLOBALS['TL_LANG']['ERR']['passwordLength'], \Config::get('minPasswordLength'))); } elseif ($pw == $this->User->username) { \Message::addError($GLOBALS['TL_LANG']['ERR']['passwordName']); } else { // Make sure the password has been changed if (\Encryption::verify($pw, $this->User->password)) { \Message::addError($GLOBALS['TL_LANG']['MSC']['pw_change']); } else { $this->loadDataContainer('tl_user'); // Trigger the save_callback if (is_array($GLOBALS['TL_DCA']['tl_user']['fields']['password']['save_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_user']['fields']['password']['save_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $pw = $this->{$callback[0]}->{$callback[1]}($pw); } elseif (is_callable($callback)) { $pw = $callback($pw); } } } $objUser = \UserModel::findByPk($this->User->id); $objUser->pwChange = ''; $objUser->password = \Encryption::hash($pw); $objUser->save(); \Message::addConfirmation($GLOBALS['TL_LANG']['MSC']['pw_changed']); $this->redirect('contao/main.php'); } } $this->reload(); } $objTemplate->theme = \Backend::getTheme(); $objTemplate->messages = \Message::generate(); $objTemplate->base = \Environment::get('base'); $objTemplate->language = $GLOBALS['TL_LANGUAGE']; $objTemplate->title = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['pw_new']); $objTemplate->charset = \Config::get('characterSet'); $objTemplate->action = ampersand(\Environment::get('request')); $objTemplate->headline = $GLOBALS['TL_LANG']['MSC']['pw_change']; $objTemplate->submitButton = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['continue']); $objTemplate->password = $GLOBALS['TL_LANG']['MSC']['password'][0]; $objTemplate->confirm = $GLOBALS['TL_LANG']['MSC']['confirm'][0]; return $objTemplate->getResponse(); }
/** * Check if user authentication succeeds on phpbb site and if so update contao member * * @param $username * @param $password * @param User $user * @return bool */ public function onCheckCredentials($username, $password, User $user) { // Only try to login if it's frontend user if ($user instanceof FrontendUser) { $loginResult = System::getContainer()->get('phpbb_bridge.connector')->validateLogin($username, $password); // Login was successful on phpbb side. Maybe user changed his password. So do we for contao then if ($loginResult === true) { $user->password = Encryption::hash($password); $user->save(); return true; } } return false; }
/** * Compare versions */ public function compare() { $strBuffer = ''; $arrVersions = array(); $intTo = 0; $intFrom = 0; $objVersions = $this->Database->prepare("SELECT * FROM tl_version WHERE pid=? AND fromTable=? ORDER BY version DESC")->execute($this->intPid, $this->strTable); if ($objVersions->numRows < 2) { $strBuffer = '<p>There are no versions of ' . $this->strTable . '.id=' . $this->intPid . '</p>'; } else { $intIndex = 0; $from = array(); // Store the versions and mark the active one while ($objVersions->next()) { if ($objVersions->active) { $intIndex = $objVersions->version; } $arrVersions[$objVersions->version] = $objVersions->row(); $arrVersions[$objVersions->version]['info'] = $GLOBALS['TL_LANG']['MSC']['version'] . ' ' . $objVersions->version . ' (' . \Date::parse(\Config::get('datimFormat'), $objVersions->tstamp) . ') ' . $objVersions->username; } // To if (\Input::post('to') && isset($arrVersions[\Input::post('to')])) { $intTo = \Input::post('to'); $to = \StringUtil::deserialize($arrVersions[\Input::post('to')]['data']); } elseif (\Input::get('to') && isset($arrVersions[\Input::get('to')])) { $intTo = \Input::get('to'); $to = \StringUtil::deserialize($arrVersions[\Input::get('to')]['data']); } else { $intTo = $intIndex; $to = \StringUtil::deserialize($arrVersions[$intTo]['data']); } // From if (\Input::post('from') && isset($arrVersions[\Input::post('from')])) { $intFrom = \Input::post('from'); $from = \StringUtil::deserialize($arrVersions[\Input::post('from')]['data']); } elseif (\Input::get('from') && isset($arrVersions[\Input::get('from')])) { $intFrom = \Input::get('from'); $from = \StringUtil::deserialize($arrVersions[\Input::get('from')]['data']); } elseif ($intIndex > 1) { $intFrom = $intIndex - 1; $from = \StringUtil::deserialize($arrVersions[$intFrom]['data']); } // Only continue if both version numbers are set if ($intTo > 0 && $intFrom > 0) { \System::loadLanguageFile($this->strTable); $this->loadDataContainer($this->strTable); // Get the order fields $objDcaExtractor = \DcaExtractor::getInstance($this->strTable); $arrOrder = $objDcaExtractor->getOrderFields(); // Find the changed fields and highlight the changes foreach ($to as $k => $v) { if ($from[$k] != $to[$k]) { if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['doNotShow'] || $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['hideInput']) { continue; } $blnIsBinary = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['inputType'] == 'fileTree' || in_array($k, $arrOrder); // Decrypt the values if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['encrypt']) { $to[$k] = \Encryption::decrypt($to[$k]); $from[$k] = \Encryption::decrypt($from[$k]); } // Convert serialized arrays into strings if (is_array($tmp = \StringUtil::deserialize($to[$k])) && !is_array($to[$k])) { $to[$k] = $this->implodeRecursive($tmp, $blnIsBinary); } if (is_array($tmp = \StringUtil::deserialize($from[$k])) && !is_array($from[$k])) { $from[$k] = $this->implodeRecursive($tmp, $blnIsBinary); } unset($tmp); // Convert binary UUIDs to their hex equivalents (see #6365) if ($blnIsBinary && \Validator::isBinaryUuid($to[$k])) { $to[$k] = \StringUtil::binToUuid($to[$k]); } if ($blnIsBinary && \Validator::isBinaryUuid($from[$k])) { $to[$k] = \StringUtil::binToUuid($from[$k]); } // Convert date fields if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'date') { $to[$k] = \Date::parse(\Config::get('dateFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('dateFormat'), $from[$k] ?: ''); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'time') { $to[$k] = \Date::parse(\Config::get('timeFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('timeFormat'), $from[$k] ?: ''); } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['eval']['rgxp'] == 'datim' || $k == 'tstamp') { $to[$k] = \Date::parse(\Config::get('datimFormat'), $to[$k] ?: ''); $from[$k] = \Date::parse(\Config::get('datimFormat'), $from[$k] ?: ''); } // Convert strings into arrays if (!is_array($to[$k])) { $to[$k] = explode("\n", $to[$k]); } if (!is_array($from[$k])) { $from[$k] = explode("\n", $from[$k]); } $objDiff = new \Diff($from[$k], $to[$k]); $strBuffer .= $objDiff->render(new DiffRenderer(array('field' => $GLOBALS['TL_DCA'][$this->strTable]['fields'][$k]['label'][0] ?: (isset($GLOBALS['TL_LANG']['MSC'][$k]) ? is_array($GLOBALS['TL_LANG']['MSC'][$k]) ? $GLOBALS['TL_LANG']['MSC'][$k][0] : $GLOBALS['TL_LANG']['MSC'][$k] : $k)))); } } } } // Identical versions if ($strBuffer == '') { $strBuffer = '<p>' . $GLOBALS['TL_LANG']['MSC']['identicalVersions'] . '</p>'; } /** @var BackendTemplate|object $objTemplate */ $objTemplate = new \BackendTemplate('be_diff'); // Template variables $objTemplate->content = $strBuffer; $objTemplate->versions = $arrVersions; $objTemplate->to = $intTo; $objTemplate->from = $intFrom; $objTemplate->showLabel = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['showDifferences']); $objTemplate->theme = \Backend::getTheme(); $objTemplate->base = \Environment::get('base'); $objTemplate->language = $GLOBALS['TL_LANGUAGE']; $objTemplate->title = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['showDifferences']); $objTemplate->charset = \Config::get('characterSet'); $objTemplate->action = ampersand(\Environment::get('request')); throw new ResponseException($objTemplate->getResponse()); }
/** * @param $row * @param $label * @param DataContainer $dc * @param $args * @return mixed */ public function labelCallback($row, $label, DataContainer $dc, $args) { // Set image $image = 'protect'; if (Encryption::decrypt($row['protect']) == '1') { $image .= '_'; } $args[0] = sprintf('<div class="list_icon_new" style="background-image:url(\'%s%s/images/%s.gif\')"> </div>', TL_SCRIPT_URL, SECURE_ACCESSDATA_PATH, $image); // Set User if (is_numeric($args[3])) { $objUser = UserModel::findByPk($args[3]); if ($objUser !== null) { $args[3] = $objUser->name; } } switch ($row['type']) { case 'weblogin': $args[4] = sprintf('%s<br>%s', Encryption::decrypt($row['weblogin_name']), Encryption::decrypt($row['weblogin_pwd'])); break; case 'contao_login': $args[4] = sprintf('%s<br>%s', Encryption::decrypt($row['contao_user']), Encryption::decrypt($row['contao_pwd'])); break; case 'encryption_key': $strEncryptionKey = Encryption::decrypt($row['encryption_key']); if (strlen($strEncryptionKey) <= 32) { $args[4] = $strEncryptionKey; } else { $args[4] = substr($strEncryptionKey, 0, 29) . '...'; } break; case 'mail': $args[4] = sprintf('%s<br>%s<br>%s', Encryption::decrypt($row['mail_email']), Encryption::decrypt($row['mail_loginname']), Encryption::decrypt($row['mail_pwd'])); break; case 'project': break; case 'online_project': break; } return $args; }
/** * Generate the module */ protected function compile() { /** @var PageModel $objPage */ global $objPage; $this->import('FrontendUser', 'User'); $GLOBALS['TL_LANGUAGE'] = $objPage->language; \System::loadLanguageFile('tl_member'); $this->loadDataContainer('tl_member'); // Old password widget $arrFields['oldPassword'] = array('name' => 'oldpassword', 'label' => &$GLOBALS['TL_LANG']['MSC']['oldPassword'], 'inputType' => 'text', 'eval' => array('mandatory' => true, 'preserveTags' => true, 'hideInput' => true)); // New password widget $arrFields['newPassword'] = $GLOBALS['TL_DCA']['tl_member']['fields']['password']; $arrFields['newPassword']['name'] = 'password'; $arrFields['newPassword']['label'] =& $GLOBALS['TL_LANG']['MSC']['newPassword']; $row = 0; $strFields = ''; $doNotSubmit = false; $objMember = \MemberModel::findByPk($this->User->id); $strFormId = 'tl_change_password_' . $this->id; $flashBag = \System::getContainer()->get('session')->getFlashBag(); $strTable = $objMember->getTable(); // Initialize the versioning (see #8301) $objVersions = new \Versions($strTable, $objMember->id); $objVersions->setUsername($objMember->username); $objVersions->setUserId(0); $objVersions->setEditUrl('contao/main.php?do=member&act=edit&id=%s&rt=1'); $objVersions->initialize(); /** @var FormTextField $objOldPassword */ $objOldPassword = null; /** @var FormPassword $objNewPassword */ $objNewPassword = null; // Initialize the widgets foreach ($arrFields as $strKey => $arrField) { /** @var Widget $strClass */ $strClass = $GLOBALS['TL_FFL'][$arrField['inputType']]; // Continue if the class is not defined if (!class_exists($strClass)) { continue; } $arrField['eval']['required'] = $arrField['eval']['mandatory']; /** @var Widget $objWidget */ $objWidget = new $strClass($strClass::getAttributesFromDca($arrField, $arrField['name'])); $objWidget->storeValues = true; $objWidget->rowClass = 'row_' . $row . ($row == 0 ? ' row_first' : '') . ($row % 2 == 0 ? ' even' : ' odd'); // Increase the row count if it is a password field if ($objWidget instanceof FormPassword) { $objWidget->rowClassConfirm = 'row_' . ++$row . ($row % 2 == 0 ? ' even' : ' odd'); } ++$row; // Store the widget objects $strVar = 'obj' . ucfirst($strKey); ${$strVar} = $objWidget; // Validate the widget if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); // Validate the old password if ($strKey == 'oldPassword') { if (\Encryption::test($objMember->password)) { $blnAuthenticated = \Encryption::verify($objWidget->value, $objMember->password); } else { list($strPassword, $strSalt) = explode(':', $objMember->password); $blnAuthenticated = $strSalt == '' ? $strPassword === sha1($objWidget->value) : $strPassword === sha1($strSalt . $objWidget->value); } if (!$blnAuthenticated) { $objWidget->value = ''; $objWidget->addError($GLOBALS['TL_LANG']['MSC']['oldPasswordWrong']); sleep(2); // Wait 2 seconds while brute forcing :) } } if ($objWidget->hasErrors()) { $doNotSubmit = true; } } $strFields .= $objWidget->parse(); } $this->Template->fields = $strFields; $this->Template->hasError = $doNotSubmit; // Store the new password if (\Input::post('FORM_SUBMIT') == $strFormId && !$doNotSubmit) { $objMember->tstamp = time(); $objMember->password = $objNewPassword->value; $objMember->save(); // Create a new version if ($GLOBALS['TL_DCA'][$strTable]['config']['enableVersioning']) { $objVersions->create(); } // HOOK: set new password callback if (isset($GLOBALS['TL_HOOKS']['setNewPassword']) && is_array($GLOBALS['TL_HOOKS']['setNewPassword'])) { foreach ($GLOBALS['TL_HOOKS']['setNewPassword'] as $callback) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($objMember, $objNewPassword->value, $this); } } // Check whether there is a jumpTo page if (($objJumpTo = $this->objModel->getRelated('jumpTo')) instanceof PageModel) { $this->jumpToOrReload($objJumpTo->row()); } $flashBag->set('mod_change_password_confirm', $GLOBALS['TL_LANG']['MSC']['newPasswordSet']); $this->reload(); } // Confirmation message if ($flashBag->has('mod_change_password_confirm')) { $arrMessages = $flashBag->get('mod_change_password_confirm'); $this->Template->message = $arrMessages[0]; } $this->Template->formId = $strFormId; $this->Template->action = \Environment::get('indexFreeRequest'); $this->Template->slabel = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['changePassword']); $this->Template->rowLast = 'row_' . $row . ' row_last' . ($row % 2 == 0 ? ' even' : ' odd'); }
/** * Renders a form to log in. * * @return Response|RedirectResponse The response object */ private function login() { $request = $this->container->get('request_stack')->getCurrentRequest(); if ('tl_login' !== $request->request->get('FORM_SUBMIT')) { return $this->render('login.html.twig'); } $installTool = $this->container->get('contao.install_tool'); $verified = Encryption::verify($request->request->get('password'), $installTool->getConfig('installPassword')); if (!$verified) { $installTool->increaseLoginCount(); return $this->render('login.html.twig', ['error' => $this->trans('invalid_password')]); } $installTool->resetLoginCount(); $this->container->get('contao.install_tool_user')->setAuthenticated(true); return $this->getRedirectResponse(); }
/** * List all records of the current table and return them as HTML string * * @return string */ protected function listView() { $return = ''; $table = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 6 ? $this->ptable : $this->strTable; $orderBy = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields']; $firstOrderBy = preg_replace('/\\s+.*$/', '', $orderBy[0]); if (is_array($this->orderBy) && $this->orderBy[0] != '') { $orderBy = $this->orderBy; $firstOrderBy = $this->firstOrderBy; } $query = "SELECT * FROM " . $this->strTable; if (!empty($this->procedure)) { $query .= " WHERE " . implode(' AND ', $this->procedure); } if (!empty($this->root) && is_array($this->root)) { $query .= (!empty($this->procedure) ? " AND " : " WHERE ") . "id IN(" . implode(',', array_map('intval', $this->root)) . ")"; } if (is_array($orderBy) && $orderBy[0] != '') { foreach ($orderBy as $k => $v) { list($key, $direction) = explode(' ', $v, 2); if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['eval']['findInSet']) { if (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'])) { $strClass = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'][0]; $strMethod = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'][1]; $this->import($strClass); $keys = $this->{$strClass}->{$strMethod}($this); } elseif (is_callable($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback'])) { $keys = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options_callback']($this); } else { $keys = $GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['options']; } if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['eval']['isAssociative'] || array_is_assoc($keys)) { $keys = array_keys($keys); } $orderBy[$k] = $this->Database->findInSet($v, $keys); } elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$key]['flag'], array(5, 6, 7, 8, 9, 10))) { $orderBy[$k] = "CAST({$key} AS SIGNED)" . ($direction ? " {$direction}" : ""); // see #5503 } } if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 3) { $firstOrderBy = 'pid'; $showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields']; $query .= " ORDER BY (SELECT " . $showFields[0] . " FROM " . $this->ptable . " WHERE " . $this->ptable . ".id=" . $this->strTable . ".pid), " . implode(', ', $orderBy); // Set the foreignKey so that the label is translated if ($GLOBALS['TL_DCA'][$table]['fields']['pid']['foreignKey'] == '') { $GLOBALS['TL_DCA'][$table]['fields']['pid']['foreignKey'] = $this->ptable . '.' . $showFields[0]; } // Remove the parent field from label fields array_shift($showFields); $GLOBALS['TL_DCA'][$table]['list']['label']['fields'] = $showFields; } else { $query .= " ORDER BY " . implode(', ', $orderBy); } } if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] == 1 && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] % 2 == 0) { $query .= " DESC"; } $objRowStmt = $this->Database->prepare($query); if ($this->limit != '') { $arrLimit = explode(',', $this->limit); $objRowStmt->limit($arrLimit[1], $arrLimit[0]); } $objRow = $objRowStmt->execute($this->values); $this->bid = $return != '' ? $this->bid : 'tl_buttons'; // Display buttos if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] || !empty($GLOBALS['TL_DCA'][$this->strTable]['list']['global_operations'])) { $return .= ' <div id="' . $this->bid . '">' . (\Input::get('act') == 'select' || $this->ptable ? ' <a href="' . $this->getReferer(true, $this->ptable) . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> ' : (isset($GLOBALS['TL_DCA'][$this->strTable]['config']['backlink']) ? ' <a href="contao/main.php?' . $GLOBALS['TL_DCA'][$this->strTable]['config']['backlink'] . '" class="header_back" title="' . specialchars($GLOBALS['TL_LANG']['MSC']['backBTTitle']) . '" accesskey="b" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG']['MSC']['backBT'] . '</a> ' : '')) . (\Input::get('act') != 'select' && !$GLOBALS['TL_DCA'][$this->strTable]['config']['closed'] && !$GLOBALS['TL_DCA'][$this->strTable]['config']['notCreatable'] ? ' <a href="' . ($this->ptable != '' ? $this->addToUrl('act=create' . ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] < 4 ? '&mode=2' : '') . '&pid=' . $this->intId) : $this->addToUrl('act=create')) . '" class="header_new" title="' . specialchars($GLOBALS['TL_LANG'][$this->strTable]['new'][1]) . '" accesskey="n" onclick="Backend.getScrollOffset()">' . $GLOBALS['TL_LANG'][$this->strTable]['new'][0] . '</a> ' : '') . $this->generateGlobalButtons() . ' </div>' . \Message::generate(true); } // Return "no records found" message if ($objRow->numRows < 1) { $return .= ' <p class="tl_empty">' . $GLOBALS['TL_LANG']['MSC']['noResult'] . '</p>'; } else { $result = $objRow->fetchAllAssoc(); $return .= (\Input::get('act') == 'select' ? ' <form action="' . ampersand(\Environment::get('request'), true) . '" id="tl_select" class="tl_form' . (\Input::get('act') == 'select' ? ' unselectable' : '') . '" method="post" novalidate> <div class="tl_formbody"> <input type="hidden" name="FORM_SUBMIT" value="tl_select"> <input type="hidden" name="REQUEST_TOKEN" value="' . REQUEST_TOKEN . '">' : '') . ' <div class="tl_listing_container list_view">' . (\Input::get('act') == 'select' ? ' <div class="tl_select_trigger"> <label for="tl_select_trigger" class="tl_select_label">' . $GLOBALS['TL_LANG']['MSC']['selectAll'] . '</label> <input type="checkbox" id="tl_select_trigger" onclick="Backend.toggleCheckboxes(this)" class="tl_tree_checkbox"> </div>' : '') . ' <table class="tl_listing' . ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns'] ? ' showColumns' : '') . '">'; // Automatically add the "order by" field as last column if we do not have group headers if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) { $blnFound = false; // Extract the real key and compare it to $firstOrderBy foreach ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'] as $f) { if (strpos($f, ':') !== false) { list($f) = explode(':', $f, 2); } if ($firstOrderBy == $f) { $blnFound = true; break; } } if (!$blnFound) { $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][] = $firstOrderBy; } } // Generate the table header if the "show columns" option is active if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) { $return .= ' <tr>'; foreach ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'] as $f) { if (strpos($f, ':') !== false) { list($f) = explode(':', $f, 2); } $return .= ' <th class="tl_folder_tlist col_' . $f . ($f == $firstOrderBy ? ' ordered_by' : '') . '">' . (is_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label']) ? $GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label'][0] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$f]['label']) . '</th>'; } $return .= ' <th class="tl_folder_tlist tl_right_nowrap"> </th> </tr>'; } // Process result and add label and buttons $remoteCur = false; $groupclass = 'tl_folder_tlist'; $eoCount = -1; foreach ($result as $row) { $args = array(); $this->current[] = $row['id']; $showFields = $GLOBALS['TL_DCA'][$table]['list']['label']['fields']; // Label foreach ($showFields as $k => $v) { // Decrypt the value if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['encrypt']) { $row[$v] = \Encryption::decrypt(deserialize($row[$v])); } if (strpos($v, ':') !== false) { list($strKey, $strTable) = explode(':', $v); list($strTable, $strField) = explode('.', $strTable); $objRef = $this->Database->prepare("SELECT " . $strField . " FROM " . $strTable . " WHERE id=?")->limit(1)->execute($row[$strKey]); $args[$k] = $objRef->numRows ? $objRef->{$strField} : ''; } elseif (in_array($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['flag'], array(5, 6, 7, 8, 9, 10))) { if ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['rgxp'] == 'date') { $args[$k] = $row[$v] ? \Date::parse(\Config::get('dateFormat'), $row[$v]) : '-'; } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['rgxp'] == 'time') { $args[$k] = $row[$v] ? \Date::parse(\Config::get('timeFormat'), $row[$v]) : '-'; } else { $args[$k] = $row[$v] ? \Date::parse(\Config::get('datimFormat'), $row[$v]) : '-'; } } elseif ($GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['inputType'] == 'checkbox' && !$GLOBALS['TL_DCA'][$this->strTable]['fields'][$v]['eval']['multiple']) { $args[$k] = $row[$v] != '' ? $GLOBALS['TL_DCA'][$table]['fields'][$v]['label'][0] : ''; } else { $row_v = deserialize($row[$v]); if (is_array($row_v)) { $args_k = array(); foreach ($row_v as $option) { $args_k[] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$option] ?: $option; } $args[$k] = implode(', ', $args_k); } elseif (isset($GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]])) { $args[$k] = is_array($GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]]) ? $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]][0] : $GLOBALS['TL_DCA'][$table]['fields'][$v]['reference'][$row[$v]]; } elseif (($GLOBALS['TL_DCA'][$table]['fields'][$v]['eval']['isAssociative'] || array_is_assoc($GLOBALS['TL_DCA'][$table]['fields'][$v]['options'])) && isset($GLOBALS['TL_DCA'][$table]['fields'][$v]['options'][$row[$v]])) { $args[$k] = $GLOBALS['TL_DCA'][$table]['fields'][$v]['options'][$row[$v]]; } else { $args[$k] = $row[$v]; } } } // Shorten the label it if it is too long $label = vsprintf($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['format'] ?: '%s', $args); if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'] > 0 && $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'] < strlen(strip_tags($label))) { $label = trim(\StringUtil::substrHtml($label, $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['maxCharacters'])) . ' …'; } // Remove empty brackets (), [], {}, <> and empty tags from the label $label = preg_replace('/\\( *\\) ?|\\[ *\\] ?|\\{ *\\} ?|< *> ?/', '', $label); $label = preg_replace('/<[^>]+>\\s*<\\/[^>]+>/', '', $label); // Build the sorting groups if ($GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['mode'] > 0) { $current = $row[$firstOrderBy]; $orderBy = $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['fields']; $sortingMode = count($orderBy) == 1 && $firstOrderBy == $orderBy[0] && $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] != '' && $GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['flag'] == '' ? $GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['flag'] : $GLOBALS['TL_DCA'][$this->strTable]['fields'][$firstOrderBy]['flag']; $remoteNew = $this->formatCurrentValue($firstOrderBy, $current, $sortingMode); // Add the group header if (!$GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns'] && !$GLOBALS['TL_DCA'][$this->strTable]['list']['sorting']['disableGrouping'] && ($remoteNew != $remoteCur || $remoteCur === false)) { $eoCount = -1; $group = $this->formatGroupHeader($firstOrderBy, $remoteNew, $sortingMode, $row); $remoteCur = $remoteNew; $return .= ' <tr> <td colspan="2" class="' . $groupclass . '">' . $group . '</td> </tr>'; $groupclass = 'tl_folder_list'; } } $return .= ' <tr class="' . (++$eoCount % 2 == 0 ? 'even' : 'odd') . ' click2edit toggle_select hover-row"> '; $colspan = 1; // Call the label_callback ($row, $label, $this) if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback']) || is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) { if (is_array($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) { $strClass = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'][0]; $strMethod = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'][1]; $this->import($strClass); $args = $this->{$strClass}->{$strMethod}($row, $label, $this, $args); } elseif (is_callable($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback'])) { $args = $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['label_callback']($row, $label, $this, $args); } // Handle strings and arrays if (!$GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) { $label = is_array($args) ? implode(' ', $args) : $args; } elseif (!is_array($args)) { $args = array($args); $colspan = count($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields']); } } // Show columns if ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['showColumns']) { foreach ($args as $j => $arg) { $return .= '<td colspan="' . $colspan . '" class="tl_file_list col_' . $GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][$j] . ($GLOBALS['TL_DCA'][$this->strTable]['list']['label']['fields'][$j] == $firstOrderBy ? ' ordered_by' : '') . '">' . ($arg ?: '-') . '</td>'; } } else { $return .= '<td class="tl_file_list">' . $label . '</td>'; } // Buttons ($row, $table, $root, $blnCircularReference, $childs, $previous, $next) $return .= (\Input::get('act') == 'select' ? ' <td class="tl_file_list tl_right_nowrap"><input type="checkbox" name="IDS[]" id="ids_' . $row['id'] . '" class="tl_tree_checkbox" value="' . $row['id'] . '"></td>' : ' <td class="tl_file_list tl_right_nowrap">' . $this->generateButtons($row, $this->strTable, $this->root) . '</td>') . ' </tr>'; } // Close the table $return .= ' </table> </div>'; // Close the form if (\Input::get('act') == 'select') { // Submit buttons $arrButtons = array(); if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notDeletable']) { $arrButtons['delete'] = '<button type="submit" name="delete" id="delete" class="tl_submit" accesskey="d" onclick="return confirm(\'' . $GLOBALS['TL_LANG']['MSC']['delAllConfirm'] . '\')">' . $GLOBALS['TL_LANG']['MSC']['deleteSelected'] . '</button>'; } if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notCopyable']) { $arrButtons['copy'] = '<button type="submit" name="copy" id="copy" class="tl_submit" accesskey="c">' . $GLOBALS['TL_LANG']['MSC']['copySelected'] . '</button>'; } if (!$GLOBALS['TL_DCA'][$this->strTable]['config']['notEditable']) { $arrButtons['override'] = '<button type="submit" name="override" id="override" class="tl_submit" accesskey="v">' . $GLOBALS['TL_LANG']['MSC']['overrideSelected'] . '</button>'; $arrButtons['edit'] = '<button type="submit" name="edit" id="edit" class="tl_submit" accesskey="s">' . $GLOBALS['TL_LANG']['MSC']['editSelected'] . '</button>'; } // Call the buttons_callback (see #4691) if (is_array($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'])) { foreach ($GLOBALS['TL_DCA'][$this->strTable]['select']['buttons_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $arrButtons = $this->{$callback[0]}->{$callback[1]}($arrButtons, $this); } elseif (is_callable($callback)) { $arrButtons = $callback($arrButtons, $this); } } } $return .= ' <div class="tl_formbody_submit" style="text-align:right"> <div class="tl_submit_container"> ' . implode(' ', $arrButtons) . ' </div> </div> </div> </form>'; } } return $return; }
/** * Persists the admin user. * * @param string $username The username * @param string $name The name * @param string $email The e-mail address * @param string $password The plain text password * @param string $language The language */ public function persistAdminUser($username, $name, $email, $password, $language) { $statement = $this->connection->prepare("\n INSERT INTO tl_user(\n tstamp,\n name,\n email,\n username,\n password,\n language,\n backendTheme,\n admin,\n showHelp,\n useRTE,\n useCE,\n thumbnails,\n dateAdded\n ) VALUES (\n :time,\n :name,\n :email,\n :username,\n :password,\n :language,\n 'flexible',\n 1,\n 1,\n 1,\n 1,\n 1,\n :time\n )\n "); $replace = ['#' => '#', '<' => '<', '>' => '>', '(' => '(', ')' => ')', '\\' => '\', '=' => '=']; $statement->execute([':time' => time(), ':name' => strtr($name, $replace), ':email' => $email, ':username' => strtr($username, $replace), ':password' => Encryption::hash($password), ':language' => $language]); }
/** * 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; }
/** * Generate the module */ protected function compile() { /** @var PageModel $objPage */ global $objPage; $this->import('FrontendUser', 'User'); $GLOBALS['TL_LANGUAGE'] = $objPage->language; \System::loadLanguageFile('tl_member'); $this->loadDataContainer('tl_member'); // Call onload_callback (e.g. to check permissions) if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}(); } elseif (is_callable($callback)) { $callback(); } } } $this->Template->fields = ''; $arrFields = array(); $doNotSubmit = false; $hasUpload = false; $row = 0; // Predefine the group order (other groups will be appended automatically) $arrGroups = array('personal' => array(), 'address' => array(), 'contact' => array(), 'login' => array(), 'profile' => array()); $blnModified = false; $objMember = \MemberModel::findByPk($this->User->id); $strTable = $objMember->getTable(); $strFormId = 'tl_member_' . $this->id; $flashBag = \System::getContainer()->get('session')->getFlashBag(); // Initialize the versioning (see #7415) $objVersions = new \Versions($strTable, $objMember->id); $objVersions->setUsername($objMember->username); $objVersions->setUserId(0); $objVersions->setEditUrl('contao/main.php?do=member&act=edit&id=%s&rt=1'); $objVersions->initialize(); // Build the form foreach ($this->editable as $field) { $arrData =& $GLOBALS['TL_DCA']['tl_member']['fields'][$field]; // Map checkboxWizards to regular checkbox widgets if ($arrData['inputType'] == 'checkboxWizard') { $arrData['inputType'] = 'checkbox'; } // Map fileTrees to upload widgets (see #8091) if ($arrData['inputType'] == 'fileTree') { $arrData['inputType'] = 'upload'; } /** @var Widget $strClass */ $strClass = $GLOBALS['TL_FFL'][$arrData['inputType']]; // Continue if the class does not exist if (!$arrData['eval']['feEditable'] || !class_exists($strClass)) { continue; } $strGroup = $arrData['eval']['feGroup']; $arrData['eval']['required'] = false; // Use strlen() here (see #3277) if ($arrData['eval']['mandatory']) { if (is_array($this->User->{$field})) { if (empty($this->User->{$field})) { $arrData['eval']['required'] = true; } } else { if (!strlen($this->User->{$field})) { $arrData['eval']['required'] = true; } } } $varValue = $this->User->{$field}; // Call the load_callback if (isset($arrData['load_callback']) && is_array($arrData['load_callback'])) { foreach ($arrData['load_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, $this->User, $this); } elseif (is_callable($callback)) { $varValue = $callback($varValue, $this->User, $this); } } } /** @var Widget $objWidget */ $objWidget = new $strClass($strClass::getAttributesFromDca($arrData, $field, $varValue, '', '', $this)); $objWidget->storeValues = true; $objWidget->rowClass = 'row_' . $row . ($row == 0 ? ' row_first' : '') . ($row % 2 == 0 ? ' even' : ' odd'); // Increase the row count if it is a password field if ($objWidget instanceof FormPassword) { if ($objMember->password != '') { $objWidget->mandatory = false; } $objWidget->rowClassConfirm = 'row_' . ++$row . ($row % 2 == 0 ? ' even' : ' odd'); } // Validate the form data if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); $varValue = $objWidget->value; $rgxp = $arrData['eval']['rgxp']; // Convert date formats into timestamps (check the eval setting first -> #3063) if ($varValue != '' && in_array($rgxp, array('date', 'time', 'datim'))) { try { $objDate = new \Date($varValue, \Date::getFormatFromRgxp($rgxp)); $varValue = $objDate->tstamp; } catch (\OutOfBoundsException $e) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varValue)); } } // Make sure that unique fields are unique (check the eval setting first -> #3063) if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue('tl_member', $field, $varValue, $this->User->id)) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $field)); } // Trigger the save_callback (see #5247) if ($objWidget->submitInput() && !$objWidget->hasErrors() && is_array($arrData['save_callback'])) { foreach ($arrData['save_callback'] as $callback) { try { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, $this->User, $this); } elseif (is_callable($callback)) { $varValue = $callback($varValue, $this->User, $this); } } catch (\Exception $e) { $objWidget->class = 'error'; $objWidget->addError($e->getMessage()); } } } // Do not submit the field if there are errors if ($objWidget->hasErrors()) { $doNotSubmit = true; } elseif ($objWidget->submitInput()) { // Store the form data $_SESSION['FORM_DATA'][$field] = $varValue; // Set the correct empty value (see #6284, #6373) if ($varValue === '') { $varValue = $objWidget->getEmptyValue(); } // Encrypt the value (see #7815) if ($arrData['eval']['encrypt']) { $varValue = \Encryption::encrypt($varValue); } // Set the new value if ($varValue !== $this->User->{$field}) { $this->User->{$field} = $varValue; // Set the new field in the member model $blnModified = true; $objMember->{$field} = $varValue; } } } if ($objWidget instanceof \uploadable) { $hasUpload = true; } $temp = $objWidget->parse(); $this->Template->fields .= $temp; $arrFields[$strGroup][$field] .= $temp; ++$row; } // Save the model if ($blnModified) { $objMember->tstamp = time(); $objMember->save(); // Create a new version if ($GLOBALS['TL_DCA'][$strTable]['config']['enableVersioning']) { $objVersions->create(); $this->log('A new version of record "' . $strTable . '.id=' . $objMember->id . '" has been created' . $this->getParentEntries($strTable, $objMember->id), __METHOD__, TL_GENERAL); } } $this->Template->hasError = $doNotSubmit; // Redirect or reload if there was no error if (\Input::post('FORM_SUBMIT') == $strFormId && !$doNotSubmit) { // HOOK: updated personal data if (isset($GLOBALS['TL_HOOKS']['updatePersonalData']) && is_array($GLOBALS['TL_HOOKS']['updatePersonalData'])) { foreach ($GLOBALS['TL_HOOKS']['updatePersonalData'] as $callback) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($this->User, $_SESSION['FORM_DATA'], $this); } } // Call the onsubmit_callback if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onsubmit_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}($this->User, $this); } elseif (is_callable($callback)) { $callback($this->User, $this); } } } // Check whether there is a jumpTo page if (($objJumpTo = $this->objModel->getRelated('jumpTo')) !== null) { $this->jumpToOrReload($objJumpTo->row()); } $flashBag->set('mod_personal_data_confirm', $GLOBALS['TL_LANG']['MSC']['savedData']); $this->reload(); } $this->Template->loginDetails = $GLOBALS['TL_LANG']['tl_member']['loginDetails']; $this->Template->addressDetails = $GLOBALS['TL_LANG']['tl_member']['addressDetails']; $this->Template->contactDetails = $GLOBALS['TL_LANG']['tl_member']['contactDetails']; $this->Template->personalData = $GLOBALS['TL_LANG']['tl_member']['personalData']; // Add the groups foreach ($arrFields as $k => $v) { // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->{$k} = $v; $key = $k . ($k == 'personal' ? 'Data' : 'Details'); $arrGroups[$GLOBALS['TL_LANG']['tl_member'][$key]] = $v; } // Confirmation message if ($flashBag->has('mod_personal_data_confirm')) { $arrMessages = $flashBag->get('mod_personal_data_confirm'); $this->Template->message = $arrMessages[0]; } $this->Template->categories = $arrGroups; $this->Template->formId = $strFormId; $this->Template->slabel = specialchars($GLOBALS['TL_LANG']['MSC']['saveData']); $this->Template->action = \Environment::get('indexFreeRequest'); $this->Template->enctype = $hasUpload ? 'multipart/form-data' : 'application/x-www-form-urlencoded'; $this->Template->rowLast = 'row_' . $row . ($row % 2 == 0 ? ' even' : ' odd'); }
/** * 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); }
/** * Validate input and set value * * @param mixed $varInput The user input * * @return mixed The validated user input */ protected function validator($varInput) { $this->blnSubmitInput = false; if (!strlen($varInput) && (strlen($this->varValue) || !$this->mandatory)) { return ''; } if (Utf8::strlen($varInput) < \Config::get('minPasswordLength')) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['passwordLength'], \Config::get('minPasswordLength'))); } if ($varInput != $this->getPost($this->strName . '_confirm')) { $this->addError($GLOBALS['TL_LANG']['ERR']['passwordMatch']); } $varInput = parent::validator($varInput); if (!$this->hasErrors()) { $this->blnSubmitInput = true; return \Encryption::hash($varInput); } return ''; }
/** * Validate input and set value * * @param mixed $varInput * * @return string */ protected function validator($varInput) { $this->blnSubmitInput = false; if (($varInput == '' || $varInput == '*****') && $this->varValue != '') { return '*****'; } if (Utf8::strlen($varInput) < \Config::get('minPasswordLength')) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['passwordLength'], \Config::get('minPasswordLength'))); } if ($varInput != $this->getPost($this->strName . '_confirm')) { $this->addError($GLOBALS['TL_LANG']['ERR']['passwordMatch']); } if ($varInput == $GLOBALS['TL_USERNAME']) { $this->addError($GLOBALS['TL_LANG']['ERR']['passwordName']); } $varInput = parent::validator($varInput); if (!$this->hasErrors()) { $this->blnSubmitInput = true; \Message::addConfirmation($GLOBALS['TL_LANG']['MSC']['pw_changed']); return \Encryption::hash($varInput); } return ''; }
/** * @param null $dc * @throws \Exception */ public function setAutoPassword($dc = null) { // Front end call if (!$dc instanceof DataContainer) { return; } if ($this->isDisabledAccountmail($dc)) { return; } $intId = $dc->id; if (Input::get('act') == 'overrideAll' && Input::get('fields') && $intId === null) { // Define indicator for given or not given password on overrideAll mode if (!isset($GLOBALS['ACCOUNTMAIL']['AUTO_PASSWORD'])) { $strPassword = $this->getPostPassword(); $GLOBALS['ACCOUNTMAIL']['AUTO_PASSWORD'] = $strPassword == '' || $strPassword == '*****' ? true : false; if ($GLOBALS['ACCOUNTMAIL']['AUTO_PASSWORD'] === true) { // Set password, that no error occurs with "password not set" $strNewPassword = substr(str_shuffle('abcdefghkmnpqrstuvwxyzABCDEFGHKMNOPQRSTUVWXYZ0123456789'), 0, 8); $this->setPostPassword($strNewPassword); } Message::addConfirmation($GLOBALS['TL_LANG']['MSC']['pw_changed']); } return; } $strPassword = $this->getPostPassword($intId); if ($strPassword !== null && $strPassword == '') { $strModel = Model::getClassFromTable($dc->table); $objAccount = $strModel::findByPk($intId); if ($objAccount !== null) { $strNewPassword = substr(str_shuffle('abcdefghkmnpqrstuvwxyzABCDEFGHKMNOPQRSTUVWXYZ0123456789'), 0, 8); $this->setPostPassword($strNewPassword, $intId); Message::addConfirmation($GLOBALS['TL_LANG']['MSC']['pw_changed']); $objAccount->password = Encryption::hash($strNewPassword); $objAccount->save(); } } }
/** * Return an object property * * @param string $strKey The property name * * @return string The property value */ public function __get($strKey) { switch ($strKey) { case 'id': return $this->strId; break; case 'name': return $this->strName; break; case 'label': return $this->strLabel; break; case 'value': // Encrypt the value if ($this->arrConfiguration['encrypt']) { return \Encryption::encrypt($this->varValue); } elseif ($this->varValue == '') { return $this->getEmptyStringOrNull(); } return $this->varValue; break; case 'class': return $this->strClass; break; case 'prefix': return $this->strPrefix; break; case 'template': return $this->strTemplate; break; case 'wizard': return $this->strWizard; break; case 'required': return $this->arrConfiguration[$strKey]; break; case 'forAttribute': return $this->blnForAttribute; break; case 'dataContainer': return $this->objDca; break; case 'activeRecord': return $this->objDca->activeRecord; break; default: if (isset($this->arrAttributes[$strKey])) { return $this->arrAttributes[$strKey]; } elseif (isset($this->arrConfiguration[$strKey])) { return $this->arrConfiguration[$strKey]; } break; } return parent::__get($strKey); }
/** * Imports a user from phpbb to contao * * @param $username * @param $password * @return bool * @throws \Exception */ public function importUser($username, $password) { if ($this->debug) { System::log("phpbb_bridge: " . __METHOD__, __METHOD__, TL_ACCESS); } // Find User in forum $user = $this->getUser($username); if ($user) { System::log('Importing User ' . $username, __METHOD__, TL_ACCESS); // Try to find user by real username if he entered username_clean // he may not be imported yet with it's clean username $contaoUser = MemberModel::findByUsername($user->username); if (null == $contaoUser) { $contaoUser = new MemberModel(); } $contaoUser->username = $user->username; $contaoUser->username_clean = $user->username_clean; $contaoUser->email = $user->user_email; $contaoUser->firstname = 'Vorname'; $contaoUser->lastname = 'Nachname'; $contaoUser->password = Encryption::hash($password); $contaoUser->login = 1; $contaoUser->tstamp = $contaoUser->dateAdded = time(); $contaoUser->groups = $this->getForumMemberGroupIds(true); // @todo add try catch, make it more safe, logout phpbb user on fail? $contaoUser->save(); System::log('User imported: ' . $contaoUser->username, __METHOD__, TL_ACCESS); // username_clean used for login if ($username != $contaoUser->username) { Input::setPost('username', $contaoUser->username); } return true; } else { System::log($username . ' could not be found in phpbb db', __METHOD__, TL_ACCESS); return false; } }
/** * Generate the module */ protected function compile() { /** @var PageModel $objPage */ global $objPage; $GLOBALS['TL_LANGUAGE'] = $objPage->language; \System::loadLanguageFile('tl_member'); $this->loadDataContainer('tl_member'); // Call onload_callback (e.g. to check permissions) if (is_array($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'])) { foreach ($GLOBALS['TL_DCA']['tl_member']['config']['onload_callback'] as $callback) { if (is_array($callback)) { $this->import($callback[0]); $this->{$callback[0]}->{$callback[1]}(); } elseif (is_callable($callback)) { $callback(); } } } // Activate account if (\Input::get('token') != '') { $this->activateAcount(); return; } if ($this->memberTpl != '') { /** @var FrontendTemplate|object $objTemplate */ $objTemplate = new \FrontendTemplate($this->memberTpl); $this->Template = $objTemplate; $this->Template->setData($this->arrData); } $this->Template->fields = ''; $objCaptcha = null; $doNotSubmit = false; $strFormId = 'tl_registration_' . $this->id; // Predefine the group order (other groups will be appended automatically) $arrGroups = array('personal' => array(), 'address' => array(), 'contact' => array(), 'login' => array(), 'profile' => array()); // Captcha if (!$this->disableCaptcha) { $arrCaptcha = array('id' => 'registration', 'label' => $GLOBALS['TL_LANG']['MSC']['securityQuestion'], 'type' => 'captcha', 'mandatory' => true, 'required' => true); /** @var FormCaptcha $strClass */ $strClass = $GLOBALS['TL_FFL']['captcha']; // Fallback to default if the class is not defined if (!class_exists($strClass)) { $strClass = 'FormCaptcha'; } /** @var FormCaptcha $objCaptcha */ $objCaptcha = new $strClass($arrCaptcha); if (\Input::post('FORM_SUBMIT') == $strFormId) { $objCaptcha->validate(); if ($objCaptcha->hasErrors()) { $doNotSubmit = true; } } } $objMember = null; // Check for a follow-up registration (see #7992) if (\Input::post('email', true) != '' && ($objMember = \MemberModel::findUnactivatedByEmail(\Input::post('email', true))) !== null) { $this->resendActivationMail($objMember); return; } $arrUser = array(); $arrFields = array(); $hasUpload = false; $i = 0; // Build form foreach ($this->editable as $field) { $arrData = $GLOBALS['TL_DCA']['tl_member']['fields'][$field]; // Map checkboxWizards to regular checkbox widgets if ($arrData['inputType'] == 'checkboxWizard') { $arrData['inputType'] = 'checkbox'; } // Map fileTrees to upload widgets (see #8091) if ($arrData['inputType'] == 'fileTree') { $arrData['inputType'] = 'upload'; } /** @var Widget $strClass */ $strClass = $GLOBALS['TL_FFL'][$arrData['inputType']]; // Continue if the class is not defined if (!class_exists($strClass)) { continue; } $arrData['eval']['required'] = $arrData['eval']['mandatory']; // Unset the unique field check upon follow-up registrations if ($objMember !== null && $arrData['eval']['unique'] && \Input::post($field) == $objMember->{$field}) { $arrData['eval']['unique'] = false; } $objWidget = new $strClass($strClass::getAttributesFromDca($arrData, $field, $arrData['default'], '', '', $this)); $objWidget->storeValues = true; $objWidget->rowClass = 'row_' . $i . ($i == 0 ? ' row_first' : '') . ($i % 2 == 0 ? ' even' : ' odd'); // Increase the row count if its a password field if ($objWidget instanceof FormPassword) { $objWidget->rowClassConfirm = 'row_' . ++$i . ($i % 2 == 0 ? ' even' : ' odd'); } // Validate input if (\Input::post('FORM_SUBMIT') == $strFormId) { $objWidget->validate(); $varValue = $objWidget->value; // Check whether the password matches the username if ($objWidget instanceof FormPassword && \Encryption::verify(\Input::post('username'), $varValue)) { $objWidget->addError($GLOBALS['TL_LANG']['ERR']['passwordName']); } $rgxp = $arrData['eval']['rgxp']; // Convert date formats into timestamps (check the eval setting first -> #3063) if ($varValue != '' && in_array($rgxp, array('date', 'time', 'datim'))) { try { $objDate = new \Date($varValue, \Date::getFormatFromRgxp($rgxp)); $varValue = $objDate->tstamp; } catch (\OutOfBoundsException $e) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidDate'], $varValue)); } } // Make sure that unique fields are unique (check the eval setting first -> #3063) if ($arrData['eval']['unique'] && $varValue != '' && !$this->Database->isUniqueValue('tl_member', $field, $varValue)) { $objWidget->addError(sprintf($GLOBALS['TL_LANG']['ERR']['unique'], $arrData['label'][0] ?: $field)); } // Save callback if ($objWidget->submitInput() && !$objWidget->hasErrors() && is_array($arrData['save_callback'])) { foreach ($arrData['save_callback'] as $callback) { try { if (is_array($callback)) { $this->import($callback[0]); $varValue = $this->{$callback[0]}->{$callback[1]}($varValue, null); } elseif (is_callable($callback)) { $varValue = $callback($varValue, null); } } catch (\Exception $e) { $objWidget->class = 'error'; $objWidget->addError($e->getMessage()); } } } // Store the current value if ($objWidget->hasErrors()) { $doNotSubmit = true; } elseif ($objWidget->submitInput()) { // Set the correct empty value (see #6284, #6373) if ($varValue === '') { $varValue = $objWidget->getEmptyValue(); } // Encrypt the value (see #7815) if ($arrData['eval']['encrypt']) { $varValue = \Encryption::encrypt($varValue); } // Set the new value $arrUser[$field] = $varValue; } } if ($objWidget instanceof \uploadable) { $hasUpload = true; } $temp = $objWidget->parse(); $this->Template->fields .= $temp; $arrFields[$arrData['eval']['feGroup']][$field] .= $temp; ++$i; } // Captcha if (!$this->disableCaptcha) { $objCaptcha->rowClass = 'row_' . $i . ($i == 0 ? ' row_first' : '') . ($i % 2 == 0 ? ' even' : ' odd'); $strCaptcha = $objCaptcha->parse(); $this->Template->fields .= $strCaptcha; $arrFields['captcha']['captcha'] .= $strCaptcha; } $this->Template->rowLast = 'row_' . ++$i . ($i % 2 == 0 ? ' even' : ' odd'); $this->Template->enctype = $hasUpload ? 'multipart/form-data' : 'application/x-www-form-urlencoded'; $this->Template->hasError = $doNotSubmit; // Create new user if there are no errors if (\Input::post('FORM_SUBMIT') == $strFormId && !$doNotSubmit) { $this->createNewUser($arrUser); } $this->Template->loginDetails = $GLOBALS['TL_LANG']['tl_member']['loginDetails']; $this->Template->addressDetails = $GLOBALS['TL_LANG']['tl_member']['addressDetails']; $this->Template->contactDetails = $GLOBALS['TL_LANG']['tl_member']['contactDetails']; $this->Template->personalData = $GLOBALS['TL_LANG']['tl_member']['personalData']; $this->Template->captchaDetails = $GLOBALS['TL_LANG']['MSC']['securityQuestion']; // Add the groups foreach ($arrFields as $k => $v) { // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->{$k} = $v; $key = $k . ($k == 'personal' ? 'Data' : 'Details'); $arrGroups[$GLOBALS['TL_LANG']['tl_member'][$key]] = $v; } $this->Template->categories = $arrGroups; $this->Template->formId = $strFormId; $this->Template->slabel = \StringUtil::specialchars($GLOBALS['TL_LANG']['MSC']['register']); $this->Template->action = \Environment::get('indexFreeRequest'); // Deprecated since Contao 4.0, to be removed in Contao 5.0 $this->Template->captcha = $arrFields['captcha']['captcha']; }
/** * Create an admin user */ protected function createAdminUser() { try { $objAdmin = $this->Database->execute("SELECT COUNT(*) AS count FROM tl_user WHERE admin=1"); if ($objAdmin->count > 0) { $this->Template->adminCreated = true; } elseif (\Input::post('FORM_SUBMIT') == 'tl_admin') { // Do not allow special characters in usernames if (preg_match('/[#\\(\\)\\/<=>]/', \Input::post('username', true))) { $this->Template->usernameError = $GLOBALS['TL_LANG']['ERR']['extnd']; } elseif (strpos(\Input::post('username', true), ' ') !== false) { $this->Template->usernameError = sprintf($GLOBALS['TL_LANG']['ERR']['noSpace'], $GLOBALS['TL_LANG']['MSC']['username']); } elseif (!\Validator::isEmail(\Input::post('email', true))) { $this->Template->emailError = $GLOBALS['TL_LANG']['ERR']['email']; } elseif (\Input::post('pass', true) != \Input::post('confirm_pass', true)) { $this->Template->passwordError = $GLOBALS['TL_LANG']['ERR']['passwordMatch']; } elseif (utf8_strlen(\Input::post('pass', true)) < \Config::get('minPasswordLength')) { $this->Template->passwordError = sprintf($GLOBALS['TL_LANG']['ERR']['passwordLength'], \Config::get('minPasswordLength')); } elseif (\Input::post('pass', true) == \Input::post('username', true)) { $this->Template->passwordError = $GLOBALS['TL_LANG']['ERR']['passwordName']; } elseif (\Input::post('name') != '' && \Input::post('email', true) != '' && \Input::post('username', true) != '') { $time = time(); $strPassword = \Encryption::hash(\Input::post('pass', true)); $this->Database->prepare("INSERT INTO tl_user (tstamp, name, email, username, password, language, backendTheme, admin, showHelp, useRTE, useCE, thumbnails, dateAdded) VALUES ({$time}, ?, ?, ?, ?, ?, ?, 1, 1, 1, 1, 1, {$time})")->execute(\Input::post('name'), \Input::post('email', true), \Input::post('username', true), $strPassword, str_replace('-', '_', $GLOBALS['TL_LANGUAGE']), \Config::get('backendTheme')); \Config::persist('adminEmail', \Input::post('email', true)); // Scan the upload folder (see #6134) if ($this->Database->tableExists('tl_files') && $this->Database->query("SELECT COUNT(*) AS count FROM tl_files")->count < 1) { $this->import('Database\\Updater', 'Updater'); $this->Updater->scanUploadFolder(); } $this->reload(); } $this->Template->adminName = \Input::post('name'); $this->Template->adminEmail = \Input::post('email', true); $this->Template->adminUser = \Input::post('username', true); } } catch (ResponseException $e) { throw $e; // see #267 } catch (\Exception $e) { $this->Template->adminCreated = false; } }