Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions src/config/GeneralConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -3212,6 +3212,31 @@ class GeneralConfig extends BaseConfig
*/
public bool $useEmailAsUsername = false;

/**
* @var bool Whether [nontransitional processing](https://www.php.net/manual/en/intl.constants.php#constant.idna-nontransitional-to-unicode) should be used when using [idn_to_utf8()](https://www.php.net/manual/en/function.idn-to-utf8.php).
*
* When your system supports IDNA ASCII strings, the domain name is converted from IDNA ASCII to Unicode using INTL_IDNA_VARIANT_UTS46 by default.
* INTL_IDNA_VARIANT_UTS46 uses UTS 46 algorithm which is consistent with the requirements of the IDNA2008 protocol and mostly compatible with IDNA2003 (which was deprecated in php 7.2.0).
*
* There are a handful of characters which result in different resolution of IDNs between IDNA2008 and IDNA2003, unless explicit action is taken.
* Those characters are: German eszett, Greek final sigma, joiner characters (ZWJ and ZWNJ). [More info](https://unicode.org/reports/tr46/#Deviations))
*
* For example, by default, `ß` will be translated to `ss` by the `idn_to_utf8` method. If you'd like to preseve it as `ß`, you need to set the `useIdnaNontransitionalToUnicode` to `true`.
*
* ::: code
* ```php Static Config
* ->useIdnaNontransitionalToUnicode(true)
* ```
* ```shell Environment Override
* CRAFT_USE_IDNA_NONTRANSITIONAL_TO_UNICODE=true
* ```
* :::
*
* @group System
* @since 5.9.0
*/
public bool $useIdnaNontransitionalToUnicode = false;

/**
* @var bool Whether [iFrame Resizer options](http://davidjbradshaw.github.io/iframe-resizer/#options) should be used for Live Preview.
*
Expand Down Expand Up @@ -6962,6 +6987,33 @@ public function useEmailAsUsername(bool $value = true): self
return $this;
}

/**
* Whether [nontransitional processing](https://www.php.net/manual/en/intl.constants.php#constant.idna-nontransitional-to-unicode) should be used when using [idn_to_utf8()](https://www.php.net/manual/en/function.idn-to-utf8.php).
*
* When your system supports IDNA ASCII strings, the domain name is converted from IDNA ASCII to Unicode using INTL_IDNA_VARIANT_UTS46 by default.
* INTL_IDNA_VARIANT_UTS46 uses UTS 46 algorithm which is consistent with the requirements of the IDNA2008 protocol and mostly compatible with IDNA2003 (which was deprecated in php 7.2.0).
*
* There are a handful of characters which result in different resolution of IDNs between IDNA2008 and IDNA2003, unless explicit action is taken.
* Those characters are: German eszett, Greek final sigma, joiner characters (ZWJ and ZWNJ). [More info](https://unicode.org/reports/tr46/#Deviations))
*
* For example, by default, `ß` will be translated to `ss` by the `idn_to_utf8` method. If you'd like to preseve it as `ß`, you need to set the `useIdnaNontransitionalToUnicode` to `true`.
*
* ```php
* ->useIdnaNontransitionalToUnicode(true)
* ```
*
* @group System
* @param bool $value
* @return self
* @see $useIdnaNontransitionalToUnicode
* @since 5.9.0
*/
public function useIdnaNontransitionalToUnicode(bool $value = false): self
{
$this->useIdnaNontransitionalToUnicode = $value;
return $this;
}

/**
* Whether [iFrame Resizer options](http://davidjbradshaw.github.io/iframe-resizer/#options) should be used for Live Preview.
*
Expand Down
2 changes: 1 addition & 1 deletion src/elements/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -993,7 +993,7 @@ protected function defineRules(): array
$rules[] = [['lastLoginDate', 'lastInvalidLoginDate', 'lockoutDate', 'lastPasswordChangeDate', 'verificationCodeIssuedDate'], DateTimeValidator::class];
$rules[] = [['invalidLoginCount', 'photoId', 'affiliatedSiteId'], 'number', 'integerOnly' => true];
$rules[] = [['username', 'email', 'unverifiedEmail', 'fullName', 'firstName', 'lastName'], 'trim', 'skipOnEmpty' => true];
$rules[] = [['email', 'unverifiedEmail'], 'email', 'enableIDN' => App::supportsIdn(), 'enableLocalIDN' => false];
$rules[] = [['email', 'unverifiedEmail'], 'email', 'enableIDN' => App::supportsIdn(), 'enableLocalIDN' => App::supportsIdn()];
$rules[] = [['email', 'username', 'fullName', 'firstName', 'lastName', 'password', 'unverifiedEmail'], 'string', 'max' => 255];
$rules[] = [['verificationCode'], 'string', 'max' => 100];
$rules[] = [['email'], 'required', 'when' => fn() => !$this->getIsDraft()];
Expand Down
2 changes: 1 addition & 1 deletion src/fields/Email.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public function getElementValidationRules(): array
{
return [
['trim'],
['email', 'enableIDN' => App::supportsIdn(), 'enableLocalIDN' => false],
['email', 'enableIDN' => App::supportsIdn(), 'enableLocalIDN' => App::supportsIdn()],
];
}

Expand Down
7 changes: 6 additions & 1 deletion src/helpers/StringHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -1949,9 +1949,14 @@ public static function idnToUtf8Email(string $email): string
return $email;
}

if (Craft::$app->getConfig()->getGeneral()->useIdnaNontransitionalToUnicode && defined('IDNA_NONTRANSITIONAL_TO_UNICODE')) {
$variant = IDNA_NONTRANSITIONAL_TO_UNICODE;
} else {
$variant = INTL_IDNA_VARIANT_UTS46;
}
$parts = explode('@', $email, 2);
foreach ($parts as &$part) {
if (($part = idn_to_utf8($part, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46)) === false) {
if (($part = idn_to_utf8($part, IDNA_DEFAULT, $variant)) === false) {
return $email;
}
}
Expand Down
Loading