symfony/polyfill-intl-idn
Provides polyfills for the Intl IDN functions idn_to_ascii() and idn_to_utf8(), enabling Internationalized Domain Name conversion on PHP installations without the intl extension. Part of Symfony’s Polyfill suite, MIT licensed.
Installation:
composer require symfony/polyfill-intl-idn:^1.38.1
No additional configuration is required—Laravel’s autoloader handles the polyfill automatically.
First Use Case:
Use the polyfill to handle IDN (Internationalized Domain Names) in Laravel applications where the Intl extension is unavailable. Example:
use Symfony\Component\Polyfill\Intl\Idn\IdnToAscii;
use Symfony\Component\Polyfill\Intl\Idn\IdnToUtf8;
// Convert IDN to ASCII (e.g., for DNS lookups or storage)
$idnToAscii = new IdnToAscii();
$asciiDomain = $idnToAscii->encode('例子.测试'); // Returns 'xn--fsq.xn--0zwm56d'
// Convert ASCII back to UTF-8 (e.g., for display)
$idnToUtf8 = new IdnToUtf8();
$utf8Domain = $idnToUtf8->decode('xn--fsq.xn--0zwm56d'); // Returns '例子.测试'
Where to Look First:
Str::of() or URL::to() for domain handling. Extend these helpers to use the polyfill internally.use Illuminate\Validation\Rule;
use Symfony\Component\Polyfill\Intl\Idn\IdnToAscii;
Rule::define('idn_domain', function ($attribute, $value, $parameters, $validator) {
$idnToAscii = new IdnToAscii();
return $idnToAscii->encode($value) !== false;
});
$this->app->singleton(IdnToAscii::class, function () {
return new IdnToAscii();
});
Domain Handling in URLs: Normalize IDNs in URLs before processing or storage:
use Symfony\Component\Polyfill\Intl\Idn\IdnToAscii;
$idnToAscii = new IdnToAscii();
$url = 'https://例子.测试';
$normalizedUrl = str_replace(
parse_url($url, PHP_URL_HOST),
$idnToAscii->encode(parse_url($url, PHP_URL_HOST)),
$url
);
Email Validation: Validate internationalized email domains:
use Symfony\Component\Polyfill\Intl\Idn\IdnToAscii;
$idnToAscii = new IdnToAscii();
$email = 'user@例子.测试';
$domain = explode('@', $email)[1];
$asciiDomain = $idnToAscii->encode($domain);
if ($asciiDomain === false) {
return false; // Invalid IDN
}
DNS or API Requests: Ensure DNS lookups or API calls use ASCII-encoded domains:
use Symfony\Component\Polyfill\Intl\Idn\IdnToAscii;
$idnToAscii = new IdnToAscii();
$domain = '例子.测试';
$asciiDomain = $idnToAscii->encode($domain);
if ($asciiDomain !== false) {
// Use $asciiDomain for DNS resolution or API calls
$result = dns_get_record($asciiDomain);
}
Laravel Helpers:
Extend Laravel’s Str or URL helpers to support IDN:
// In AppServiceProvider's boot method
Str::macro('toAsciiDomain', function ($domain) {
$idnToAscii = new IdnToAscii();
return $idnToAscii->encode($domain);
});
// Usage
$asciiDomain = Str::toAsciiDomain('例子.测试');
User Input Handling:
Internationalized Email Systems:
Localization Features:
laravel-localization) to handle IDNs in multilingual applications.Testing:
Intl extension:
$this->app->instance(IdnToAscii::class, Mockery::mock(IdnToAscii::class));
Check for Intl Extension:
Dynamically switch between native functions and the polyfill:
function idnToAscii($domain) {
if (extension_loaded('intl')) {
return idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46);
}
$idnToAscii = new IdnToAscii();
return $idnToAscii->encode($domain);
}
Error Handling:
Handle cases where the polyfill returns false (invalid input):
$asciiDomain = $idnToAscii->encode($domain);
if ($asciiDomain === false) {
throw new \InvalidArgumentException("Invalid IDN domain: {$domain}");
}
Performance Optimization: Cache converted domains to avoid repeated conversions:
$cache = new \Symfony\Component\Cache\Simple\FilesystemCache();
$key = 'idn_ascii_' . md5($domain);
if (!$cache->has($key)) {
$asciiDomain = $idnToAscii->encode($domain);
$cache->set($key, $asciiDomain, 3600); // Cache for 1 hour
} else {
$asciiDomain = $cache->get($key);
}
Laravel Events:
Use Laravel’s events to normalize IDNs during specific lifecycle hooks (e.g., Illuminate\Auth\Events\Registered):
Event::listen('registered', function ($user) {
if (Str::contains($user->email, '@')) {
$domain = explode('@', $user->email)[1];
$user->email = str_replace(
$domain,
app(IdnToAscii::class)->encode($domain),
$user->email
);
$user->save();
}
});
False Positives in Validation:
The polyfill may return false for valid but unusual IDNs. Always test with a diverse set of domains (e.g., CJK, Arabic, Cyrillic scripts).
Case Sensitivity: IDN conversion is case-insensitive, but ensure your application handles this consistently (e.g., normalize domains to lowercase before conversion).
Unicode Normalization:
The polyfill follows Unicode normalization rules, but edge cases (e.g., combining characters) may behave differently than the native Intl extension. Test thoroughly.
Performance Overhead:
The polyfill is slower than native Intl functions. Benchmark in high-traffic applications and consider caching.
Dependency Conflicts:
If another package redefines idn_to_ascii or idn_to_utf8, the polyfill may not work as expected. Use composer why symfony/polyfill-intl-idn to debug conflicts.
Security Update (v1.38.1):
Rejection of Invalid Punycode Payloads: This release introduces a security fix to reject xn-- labels whose Punycode payload decodes to ASCII-only strings (CVE-2026-46644). This may cause previously accepted domains like xn--example-ascii.xn--com to fail validation. Update your validation logic to handle this change:
$asciiDomain = $idnToAscii->encode('xn--example-ascii.xn--com');
if ($asciiDomain === false) {
// Handle rejection (e.g., log or throw an exception)
Log::warning("Invalid Punycode payload detected in domain: xn--example-ascii.xn--com");
}
How can I help you explore Laravel packages today?