*/ public static function domainProvider(): array { return [ 'muellerde' => ['müller.de', 'xn--mller-kva.de'], 'buecherde' => ['bücher.de', 'xn--bcher-kva.de'], 'muenchende' => ['münchen.de', 'xn--mnchen-3ya.de'], 'nur ein Label' => ['münchen', 'xn--mnchen-3ya'], 'mehrere Umlaute' => ['grüße.example.com', 'xn--gre-6ka8l.example.com'], 'Subdomain umlautfrei' => ['www.müller.de', 'www.xn--mller-kva.de'], ]; } /** * @dataProvider domainProvider */ public function testEncodeDomain(string $unicode, string $expected): void { self::assertSame($expected, Punycode::encodeDomain($unicode)); } /** * Die eigene Implementierung muss dasselbe Ergebnis liefern wie die * Referenz aus ext-intl. Ohne intl entfaellt die Gegenprobe. */ public function testStimmtMitIntlUeberein(): void { if (!function_exists('idn_to_ascii')) { self::markTestSkipped('ext-intl ist nicht verfuegbar.'); } $domains = [ 'müller.de', 'bücher.de', 'münchen.de', 'grüße.example.com', 'www.müller.de', 'österreich.at', 'köln.de', 'schöne-grüße.de', '日本語.jp', 'мосва.рф', 'ελλάδα.gr', ]; foreach ($domains as $domain) { $reference = idn_to_ascii($domain, IDNA_DEFAULT, INTL_IDNA_VARIANT_UTS46); self::assertIsString($reference, $domain); // Die eigene Implementierung direkt aufrufen, nicht den // intl-Weg innerhalb von encodeDomain(). self::assertSame($reference, self::encodeWithoutIntl($domain), $domain); } } /** * Ruft den Rueckfallweg ueber Reflection auf, damit die Gegenprobe * nicht wieder bei idn_to_ascii landet. */ private static function encodeWithoutIntl(string $host): string { // Kein setAccessible(): seit PHP 8.1 wirkungslos, seit 8.5 veraltet. $method = new \ReflectionMethod(Punycode::class, 'encodeLabel'); $labels = array_map( static fn (string $label): string => (string) $method->invoke(null, $label), explode('.', $host), ); return implode('.', $labels); } }