public function test_encodeEmail() { $strEmailPrefix = 'user@'; foreach ($this->arrIdnaTests as $strDefaultDomain => $strEncodedDomain) { $this->assertEquals(Idna::encodeEmail($strEmailPrefix . $strDefaultDomain), $strEmailPrefix . $strEncodedDomain); } }
public function test_isEmail() { $arrEmails = array('*****@*****.**' => true, 'test@test.c' => false, 'test@test.' => false, 'test@test' => false, 'test@' => false, 'test' => false, Idna::encodeEmail('test@tèst.ch') => true); foreach ($arrEmails as $strAddress => $blnValidity) { $this->assertEquals(Validator::isEmail($strAddress), $blnValidity); } }
private function addRecipient($email, $arrChannels, $strMailText, $intJumpTo) { $varInput = \Idna::encodeEmail($email); // Get the existing active subscriptions $arrSubscriptions = array(); if (($objSubscription = \NewsletterRecipientsModel::findBy(array("email=? AND active=1"), $varInput)) !== null) { $arrSubscriptions = $objSubscription->fetchEach('pid'); } $arrNew = array_diff($arrChannels, $arrSubscriptions); // Return if there are no new subscriptions if (!is_array($arrNew) || empty($arrNew)) { return; } // Remove old subscriptions that have not been activated yet if (($objOld = \NewsletterRecipientsModel::findBy(array("email=? AND active=''"), $varInput)) !== 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 = $varInput; $objRecipient->active = ''; $objRecipient->addedOn = $time; $objRecipient->ip = $this->anonymizeIp(\Environment::get('ip')); $objRecipient->token = $strToken; $objRecipient->confirmed = ''; $objRecipient->save(); } // Get the channels $objChannel = \NewsletterChannelModel::findByIds($arrChannels); // Prepare the e-mail text $strText = str_replace('##token##', $strToken, $strMailText); $strText = str_replace('##domain##', \Environment::get('host'), $strText); //$strText = str_replace('##link##', \Environment::get('base') . \Environment::get('request') . (($GLOBALS['TL_CONFIG']['disableAlias'] || strpos(\Environment::get('request'), '?') !== false) ? '&' : '?') . 'token=' . $strToken, $strText); $objPageConfirm = \PageModel::findByPk($intJumpTo); if ($objPageConfirm === null) { $this->log('Newsletter confirmation page not found, id: ' . $intJumpTo, __CLASS__ . ":" . __METHOD__, TL_NEWSLETTER); } $strText = str_replace('##link##', rtrim(\Environment::get('base'), '/') . '/' . $this->generateFrontendUrl($objPageConfirm->row()) . '?token=' . $strToken, $strText); $strText = str_replace(array('##channel##', '##channels##'), implode("\n", $objChannel->fetchEach('title')), $strText); // 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'], \Environment::get('host')); $objEmail->text = $strText; $objEmail->sendTo($varInput); }
/** * Trim the values * * @param mixed $varInput The user input * * @return mixed The validated user input */ protected function validator($varInput) { if (is_array($varInput)) { return parent::validator($varInput); } // Convert to Punycode format (see #5571) if ($this->rgxp == 'url') { $varInput = \Idna::encodeUrl($varInput); } elseif ($this->rgxp == 'email' || $this->rgxp == 'friendly') { $varInput = \Idna::encodeEmail($varInput); } return parent::validator($varInput); }
/** * Add a new recipient */ protected function addRecipient() { if (!\Environment::get('isAjaxRequest')) { return parent::addRecipient(); } $arrChannels = \Input::post('channels'); if (!is_array($arrChannels)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; return false; } $arrChannels = array_intersect($arrChannels, $this->nl_channels); // see #3240 // Check the selection if (!is_array($arrChannels) || empty($arrChannels)) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; return false; } $varInput = \Idna::encodeEmail(\Input::post('email', true)); // Validate the e-mail address if (!\Validator::isEmail($varInput)) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['email']; return false; } $arrSubscriptions = array(); // Get the existing active subscriptions if (($objSubscription = \NewsletterRecipientsModel::findBy(array("email=? AND active=1"), $varInput)) !== null) { $arrSubscriptions = $objSubscription->fetchEach('pid'); } $arrNew = array_diff($arrChannels, $arrSubscriptions); // Return if there are no new subscriptions if (!is_array($arrNew) || empty($arrNew)) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['subscribed']; return false; } // Remove old subscriptions that have not been activated yet if (($objOld = \NewsletterRecipientsModel::findBy(array("email=? AND active=''"), $varInput)) !== 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 = $varInput; $objRecipient->active = ''; $objRecipient->addedOn = $time; $objRecipient->ip = $this->anonymizeIp(\Environment::get('ip')); $objRecipient->token = $strToken; $objRecipient->confirmed = ''; $objRecipient->save(); } // Get the channels $objChannel = \NewsletterChannelModel::findByIds($arrChannels); // Prepare the e-mail text $strText = str_replace('##token##', $strToken, $this->nl_subscribe); $strText = str_replace('##domain##', \Idna::decode(\Environment::get('host')), $strText); $strText = str_replace('##link##', \Idna::decode(\Environment::get('base')) . \Environment::get('request') . (\Config::get('disableAlias') || strpos(\Environment::get('request'), '?') !== false ? '&' : '?') . 'token=' . $strToken, $strText); $strText = str_replace(array('##channel##', '##channels##'), implode("\n", $objChannel->fetchEach('title')), $strText); // 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 = $strText; $objEmail->sendTo($varInput); // 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']; return true; }
/** * Encode the domain in an e-mail address * * @param string $strEmail The e-mail address * * @return string The encoded e-mail address * * @deprecated Use Idna::encodeEmail() instead */ protected function idnaEncodeEmail($strEmail) { return \Idna::encodeEmail($strEmail); }
/** * Extract the e-mail addresses from the func_get_args() arguments * * @param array $arrRecipients The recipients array * * @return array An array of e-mail addresses */ protected function compileRecipients($arrRecipients) { $arrReturn = array(); foreach ($arrRecipients as $varRecipients) { if (!is_array($varRecipients)) { $varRecipients = \String::splitCsv($varRecipients); } // Support friendly name addresses and internationalized domain names foreach ($varRecipients as $v) { list($strName, $strEmail) = \String::splitFriendlyEmail($v); $strName = trim($strName, ' "'); $strEmail = \Idna::encodeEmail($strEmail); if ($strName != '') { $arrReturn[$strEmail] = $strName; } else { $arrReturn[] = $strEmail; } } } return $arrReturn; }
/** * Valid e-mail address * * @param mixed $varValue The value to be validated * * @return boolean True if the value is a valid e-mail address */ public static function isEmail($varValue) { /* * The regex below is based on a regex by Michael Rushton adjusted by * Rasmus Lerdorf to to only consider routeable addresses as valid. We * have also added Unicode support for the local part. * * Michael's regex carries this copyright: * * Copyright © Michael Rushton 2009-10 * http://squiloople.com/ * Feel free to use and redistribute this code. But please keep this copyright notice. * * @see https://github.com/php/php-src/blob/master/ext/filter/logical_filters.c#L601 */ return preg_match('/^(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){255,})(?!(?:(?:\\x22?\\x5C[\\x00-\\x7E]\\x22?)|(?:\\x22?[^\\x5C\\x22]\\x22?)){65,}@)(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E\\pL\\pN]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F\\pL\\pN]|(?:\\x5C[\\x00-\\x7F]))*\\x22))(?:\\.(?:(?:[\\x21\\x23-\\x27\\x2A\\x2B\\x2D\\x2F-\\x39\\x3D\\x3F\\x5E-\\x7E\\pL\\pN]+)|(?:\\x22(?:[\\x01-\\x08\\x0B\\x0C\\x0E-\\x1F\\x21\\x23-\\x5B\\x5D-\\x7F\\pL\\pN]|(?:\\x5C[\\x00-\\x7F]))*\\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-+[a-z0-9]+)*\\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-+[a-z0-9]+)*)|(?:\\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\\]))$/iDu', \Idna::encodeEmail($varValue)); }
/** * Valid e-mail address * * @param mixed $varValue The value to be validated * * @return boolean True if the value is a valid e-mail address */ public static function isEmail($varValue) { return preg_match('/^(\\w+[!#\\$%&\'\\*\\+\\-\\/=\\?^_`\\.\\{\\|\\}~]*)+(?<!\\.)@\\w+([_\\.-]*\\w+)*\\.[A-Za-z]{2,6}$/', \Idna::encodeEmail($varValue)); }
/** * 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) = \String::splitFriendlyEmail($varInput); // no break; // Check whether the current value is a valid e-mail address // no break; // Check whether the current value is a valid e-mail address case 'email': if (!\Validator::isEmail($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['email'], $this->strLabel)); } if ($this->rgxp == 'friendly' && $strName != '') { $varInput = $strName . ' [' . $varInput . ']'; } break; // Check whether the current value is list of valid e-mail addresses // Check whether the current value is list of valid e-mail addresses case 'emails': $arrEmails = trimsplit(',', $varInput); foreach ($arrEmails as $strEmail) { $strEmail = \Idna::encodeEmail($strEmail); if (!\Validator::isEmail($strEmail)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['emails'], $this->strLabel)); break; } } break; // Check whether the current value is a valid URL // Check whether the current value is a valid URL case 'url': if (!\Validator::isUrl($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['url'], $this->strLabel)); } break; // Check whether the current value is a valid alias // Check whether the current value is a valid alias case 'alias': if (!\Validator::isAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['alias'], $this->strLabel)); } break; // Check whether the current value is a valid folder URL alias // Check whether the current value is a valid folder URL alias case 'folderalias': if (!\Validator::isFolderAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['folderalias'], $this->strLabel)); } break; // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) case 'phone': if (!\Validator::isPhone(html_entity_decode($varInput))) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['phone'], $this->strLabel)); } break; // Check whether the current value is a percent value // Check whether the current value is a percent value case 'prcnt': if (!\Validator::isPercent($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['prcnt'], $this->strLabel)); } break; // Check whether the current value is a locale // Check whether the current value is a locale case 'locale': if (!\Validator::isLocale($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['locale'], $this->strLabel)); } break; // Check whether the current value is a language code // Check whether the current value is a language code case 'language': if (!\Validator::isLanguage($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['language'], $this->strLabel)); } break; // Check whether the current value is a Google+ ID or vanity name // Check whether the current value is a Google+ ID or vanity name case 'google+': if (!\Validator::isGooglePlusId($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['invalidGoogleId'], $this->strLabel)); } break; // HOOK: pass unknown tags to callback functions // HOOK: pass unknown tags to callback functions default: if (isset($GLOBALS['TL_HOOKS']['addCustomRegexp']) && is_array($GLOBALS['TL_HOOKS']['addCustomRegexp'])) { foreach ($GLOBALS['TL_HOOKS']['addCustomRegexp'] as $callback) { $this->import($callback[0]); $break = $this->{$callback}[0]->{$callback}[1]($this->rgxp, $varInput, $this); // Stop the loop if a callback returned true if ($break === true) { break; } } } break; } } if ($this->isHexColor && $varInput != '' && strncmp($varInput, '$', 1) !== 0) { $varInput = preg_replace('/[^a-f0-9]+/i', '', $varInput); } if ($this->nospace && preg_match('/[\\t ]+/', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['noSpace'], $this->strLabel)); } if ($this->spaceToUnderscore) { $varInput = preg_replace('/\\s+/', '_', trim($varInput)); } if (is_bool($this->trailingSlash) && $varInput != '') { $varInput = preg_replace('/\\/+$/', '', $varInput) . ($this->trailingSlash ? '/' : ''); } return $varInput; }
/** * Remove the recipient */ protected function removeRecipient() { $arrChannels = \Input::post('channels'); $arrChannels = array_intersect($arrChannels, $this->nl_channels); // see #3240 // Check the selection if (!is_array($arrChannels) || empty($arrChannels)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; $this->reload(); } $varInput = \Idna::encodeEmail(\Input::post('email', true)); // Validate e-mail address if (!\Validator::isEmail($varInput)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['email']; $this->reload(); } $arrSubscriptions = array(); // Get the existing active subscriptions if (($objSubscription = \NewsletterRecipientsModel::findBy(array("email=? AND active=1"), $varInput)) !== null) { $arrSubscriptions = $objSubscription->fetchEach('pid'); } $arrRemove = array_intersect($arrChannels, $arrSubscriptions); // Return if there are no subscriptions to remove if (!is_array($arrRemove) || empty($arrRemove)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['unsubscribed']; $this->reload(); } // Remove the subscriptions if (($objRemove = \NewsletterRecipientsModel::findByEmailAndPids($varInput, $arrRemove)) !== null) { while ($objRemove->next()) { $objRemove->delete(); } } // Get the channels $objChannels = \NewsletterChannelModel::findByIds($arrRemove); $arrChannels = $objChannels->fetchEach('title'); // Log activity $this->log($varInput . ' unsubscribed from ' . implode(', ', $arrChannels), 'ModuleUnsubscribe removeRecipient()', TL_NEWSLETTER); // 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]($varInput, $arrRemove); } } // Prepare the e-mail text $strText = str_replace('##domain##', \Environment::get('host'), $this->nl_unsubscribe); $strText = str_replace(array('##channel##', '##channels##'), implode("\n", $arrChannels), $strText); // 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'], \Environment::get('host')); $objEmail->text = $strText; $objEmail->sendTo($varInput); // Redirect to the jumpTo page if ($this->jumpTo && ($objTarget = $this->objModel->getRelated('jumpTo')) !== null) { $this->redirect($this->generateFrontendUrl($objTarget->row())); } $_SESSION['UNSUBSCRIBE_CONFIRM'] = $GLOBALS['TL_LANG']['MSC']['nl_removed']; $this->reload(); }
/** * Valid e-mail address * * @param mixed $varValue The value to be validated * * @return boolean True if the value is a valid e-mail address */ public static function isEmail($varValue) { $email = \Idna::encodeEmail($varValue); return filter_var($email, FILTER_VALIDATE_EMAIL) === $email; }
/** * Add a new recipient */ protected function removeRecipient() { $arrChannels = $this->Input->post('channels'); $arrChannels = array_intersect($arrChannels, $this->nl_channels); // see #3240 // Check the selection if (!is_array($arrChannels) || count($arrChannels) < 1) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; $this->reload(); } $arrSubscriptions = array(); $email = \Idna::encodeEmail($this->Input->post('email', true)); $subscriber = new Subscriber($email); // Get active subscriptions $objSubscription = $this->Database->prepare("SELECT pid FROM tl_newsletter_recipients WHERE email=? AND active=1")->execute($email); if ($objSubscription->numRows) { $arrSubscriptions = $objSubscription->fetchEach('pid'); } $arrRemove = array_intersect($arrChannels, $arrSubscriptions); // Return if there are no subscriptions to remove if (!is_array($arrRemove) || count($arrRemove) < 1) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['unsubscribed']; $this->reload(); } // check for cleverreach support $objChannel = $this->Database->execute("SELECT id FROM tl_newsletter_channel WHERE cleverreach_active = 1 AND id IN(" . implode(',', array_map('intval', $arrRemove)) . ")"); // TODO: multiple channel unsubscription $subscriber->getByChannel($arrRemove[0]); // Remove subscriptions $subscriber->remove($arrRemove); // optional Cleverreach Deletion if ($objChannel->numRows > 0) { $subscriber->removeFromCR($objChannel->fetchEach('id')); } // Get channels $objChannels = $this->Database->execute("SELECT title FROM tl_newsletter_channel WHERE id IN(" . implode(',', array_map('intval', $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]($varInput, $arrRemove); } } global $objPage; // Redirect to jumpTo page if (strlen($this->jumpTo) && $this->jumpTo != $objPage->id) { $objNextPage = $this->Database->prepare("SELECT id, alias FROM tl_page WHERE id=?")->limit(1)->execute($this->jumpTo); if ($objNextPage->numRows) { $this->redirect($this->generateFrontendUrl($objNextPage->fetchAssoc())); } } if ($subscriber->sendUnSubscribeMail($arrRemove)) { $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; } $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->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 [.] minus [-] and space [ ]) // DO NOT ADD A break; STATEMENT HERE // Numeric characters (including full stop [.] minus [-] and space [ ]) case 'digit': if (!\Validator::isNumeric($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['digit'], $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': $objDate = new \Date(); if (!preg_match('~^' . $objDate->getRegexp($GLOBALS['TL_CONFIG']['dateFormat']) . '$~i', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['date'], $objDate->getInputFormat($GLOBALS['TL_CONFIG']['dateFormat']))); } break; // Check whether the current value is a valid time format // Check whether the current value is a valid time format case 'time': $objDate = new \Date(); if (!preg_match('~^' . $objDate->getRegexp($GLOBALS['TL_CONFIG']['timeFormat']) . '$~i', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['time'], $objDate->getInputFormat($GLOBALS['TL_CONFIG']['timeFormat']))); } 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': $objDate = new \Date(); if (!preg_match('~^' . $objDate->getRegexp($GLOBALS['TL_CONFIG']['datimFormat']) . '$~i', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['dateTime'], $objDate->getInputFormat($GLOBALS['TL_CONFIG']['datimFormat']))); } 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) = $this->splitFriendlyName($varInput); // no break; // Check whether the current value is a valid e-mail address // no break; // Check whether the current value is a valid e-mail address case 'email': if (!\Validator::isEmail($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['email'], $this->strLabel)); } if ($this->rgxp == 'friendly' && $strName != '') { $varInput = $strName . ' [' . $varInput . ']'; } break; // Check whether the current value is list of valid e-mail addresses // Check whether the current value is list of valid e-mail addresses case 'emails': $arrEmails = trimsplit(',', $varInput); foreach ($arrEmails as $strEmail) { $strEmail = \Idna::encodeEmail($strEmail); if (!\Validator::isEmail($strEmail)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['emails'], $this->strLabel)); break; } } break; // Check whether the current value is a valid URL // Check whether the current value is a valid URL case 'url': if (!\Validator::isUrl($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['url'], $this->strLabel)); } break; // Check whether the current value is a valid alias // Check whether the current value is a valid alias case 'alias': if (!\Validator::isAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['alias'], $this->strLabel)); } break; // Check whether the current value is a valid folder URL alias // Check whether the current value is a valid folder URL alias case 'folderalias': if (!\Validator::isFolderAlias($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['folderalias'], $this->strLabel)); } break; // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) // Phone numbers (numeric characters, space [ ], plus [+], minus [-], parentheses [()] and slash [/]) case 'phone': if (!\Validator::isPhone(html_entity_decode($varInput))) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['phone'], $this->strLabel)); } break; // Check whether the current value is a percent value // Check whether the current value is a percent value case 'prcnt': if (!\Validator::isPercent($varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['prcnt'], $this->strLabel)); } break; // 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 ]+/i', $varInput)) { $this->addError(sprintf($GLOBALS['TL_LANG']['ERR']['noSpace'], $this->strLabel)); } if ($this->spaceToUnderscore) { $varInput = preg_replace('/\\s+/i', '_', trim($varInput)); } if (is_bool($this->trailingSlash) && $varInput != '') { $varInput = preg_replace('/\\/+$/i', '', $varInput) . ($this->trailingSlash ? '/' : ''); } return $varInput; }
/** * Remove the recipient */ protected function removeRecipient() { $arrChannels = \Input::post('channels'); if (!is_array($arrChannels)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; $this->reload(); } $arrChannels = array_intersect($arrChannels, $this->nl_channels); // see #3240 // Check the selection if (!is_array($arrChannels) || empty($arrChannels)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; $this->reload(); } $varInput = \Idna::encodeEmail(\Input::post('email', true)); // Validate e-mail address if (!\Validator::isEmail($varInput)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['email']; $this->reload(); } $arrSubscriptions = array(); // Get the existing active subscriptions if (($objSubscription = \NewsletterRecipientsModel::findBy(array("email=? AND active=1"), $varInput)) !== null) { $arrSubscriptions = $objSubscription->fetchEach('pid'); } $arrRemove = array_intersect($arrChannels, $arrSubscriptions); // Return if there are no subscriptions to remove if (!is_array($arrRemove) || empty($arrRemove)) { $_SESSION['UNSUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['unsubscribed']; $this->reload(); } // Remove the subscriptions if (($objRemove = \NewsletterRecipientsModel::findByEmailAndPids($varInput, $arrRemove)) !== null) { while ($objRemove->next()) { $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]}($varInput, $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($varInput); // Redirect to the jumpTo page if ($this->jumpTo && ($objTarget = $this->objModel->getRelated('jumpTo')) !== null) { /** @var \PageModel $objTarget */ $this->redirect($objTarget->getFrontendUrl()); } $_SESSION['UNSUBSCRIBE_CONFIRM'] = $GLOBALS['TL_LANG']['MSC']['nl_removed']; $this->reload(); }
/** * Add a new recipient */ protected function addRecipient() { global $objPage; $arrChannels = $this->Input->post('channels'); $arrChannels = array_intersect($arrChannels, $this->nl_channels); // see #3240 // Check the selection if (!is_array($arrChannels) || count($arrChannels) < 1) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['noChannels']; $this->reload(); } $email = \Idna::encodeEmail($this->Input->post('email', true)); $subscriber = new Subscriber($email); $arrSub = $subscriber->getActiveSubscriptionIds(); // Get new subscriptions $arrNew = array_diff($arrChannels, $arrSub); // Return if there are no new subscriptions if (!is_array($arrNew) || count($arrNew) < 1) { $_SESSION['SUBSCRIBE_ERROR'] = $GLOBALS['TL_LANG']['ERR']['subscribed']; $this->redirect($this->generateFrontendUrl($objPage->row()) . '#' . $this->strFormId); } // Remove old subscriptions that have not been activated yet $subscriber->dropInactiveSubscriptions(); $time = time(); $strToken = md5(uniqid(mt_rand(), true)); // check if additional input fields are required for this channel $objChannel = $this->Database->execute("SELECT * FROM tl_newsletter_channel WHERE id IN(" . implode(',', array_map('intval', $arrNew)) . ")"); $addPlusFields = false; $channelInfo = array(); while ($objChannel->next()) { $check = deserialize($objChannel->subscribeplus_inputs); if (is_array($check) && count($check) > 0) { $addPlusFields = true; } $channelInfo[$objChannel->id] = $objChannel->row(); } foreach ($arrNew as $cid) { $subscriber->tstamp = $time; $subscriber->pid = $cid; $subscriber->addedOn = $time; $subscriber->ip = $this->anonymizeIp($this->Environment->ip); $subscriber->token = $strToken; $subscriber->active = ''; $subscriber->registered = $time; if ($addPlusFields) { foreach ($GLOBALS['TL_DCA']['tl_subscribe_plus']['fields'] as $name => $form) { $subscriber->{$name} = $this->Input->post($name) ? $this->Input->post($name) : ''; } } // Add new subscriptions $subscriber->add(); if (array_key_exists($cid, $channelInfo)) { if ($channelInfo[$cid]['cleverreach_active'] == 1) { $subscriber->addToCR(); } } } // Redirect to jumpTo page if (strlen($this->jumpTo) && $this->jumpTo != $objPage->id) { $objNextPage = $this->Database->prepare("SELECT id, alias FROM tl_page WHERE id=?")->limit(1)->execute($this->jumpTo); if ($objNextPage->numRows) { $this->redirect($this->generateFrontendUrl($objNextPage->fetchAssoc())); } } // Activation e-mail if ($subscriber->sendActivationMail($objChannel->fetchEach('id'))) { $this->redirect($this->generateFrontendUrl($objPage->row()) . '#' . $this->strFormId); } }