как проверить интернационализированные доменные имена

Я хочу проверить URL-адрес домена в php, который может быть в формате интернационализированного доменного имени, например, в греческом доменном имени = http: //παράδειγμα.δοκιμή. Есть ли у них какой-либо способ проверить его с помощью регулярного выражения?

Это idn- домены, я бы сначала конвертировал их в версию штрафного кода и затем проверял домены.

Но если вам действительно нравится проверять регулярное выражение

 <?php $domain = 'παράδειγμα.gr'; $regex = '#^([\w-]+://?|www[\.])?([^\-\s\,\;\:\+\/\\\?\^\`\=\&\%\"\'\*\#\<\>]*)\.[az]{2,7}$#'; if (preg_match($regex, $domain)) { echo "VALID"; } 

Но это позволяет вам запускать ложные возможности, потому что очень сложно проверить домен idn, который я пытался проверить, что недопустимые символы не включены, но список НЕ завершен.

Лучше конвертировать bevore в punny code

 $regex = '#^([\w-]+://?|www[\.])?[a-z0-9]+[a-z0-9\-\.]*[a-z0-9]+\.[az]{2,7}$#'; if (preg_match($regex, idn_to_ascii($domain))) { echo "VALID"; } 

И если вы хотите проверить, может ли домен быть разрешен, попробуйте:

 $regex = '#^([\w-]+://?|www[\.])?[a-z0-9]+[a-z0-9\-\.]*[a-z0-9]+\.[az]{2,7}$#'; $punny_domain = idn_to_ascii($domain); if (preg_match($regex, $punny_domain)) { if (gethostbyname($punny_domain) != $punny_domain) { echo "VALID"; } } 

Если вы хотите создать свой собственный либрарий, вам нужно использовать таблицу разрешенных кодовых точек ( IANA – репозиторий методов IDN , руководство по проверке символов IDN , параметры IDNA ) и таблицу свойств сценария Unicode ( UNIDATA / Scripts.txt ).

Gmail принимает спецификацию Unicode Consortium « Hlyly Restricted » ( защита Gmail в глобальном мире ). Разрешены следующие дополнения Unicode Scripts.

  • Один скрипт
  • Латин + Хан + Хирагана + Катакана
  • Латин + Хан + Бопомофо
  • Латинский + Хан + Хангул

Возможно, вам придется оплачивать специальные значения свойств скрипта (Common, Inherited, Unknown), поскольку некоторые из символов имеют несколько свойств или неправильных свойств.

Например, U + 3099 (COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK) имеет две возможности («Katakana» и «Hiragana»), а функция PCRE классифицирует ее как «Inherited». Другим примером является U + x2A708. Althogh правильное свойство скрипта U + 2A708 (компиляция U + 30C8 KATAKANA LETTER TO и U + 30E2 KATAKANA LETTER MO) – это «Катакана», спецификация Юникода неправильно классифицирует его как «Хан».

Возможно, вам придется рассмотреть атаку гомографа IDN . Политика IDN Google Chrome принимает черные списки .

Моя рекомендация – использовать Zend \ Validator \ Hostname. В этой библиотеке используется таблица разрешенных кодовых точек для японского и китайского языков .

Если вы используете Symfony, подумайте о том, чтобы обновить приложение версии до версии 2.5, которое использует egulias / email-validatornd ( Manual ). Вам нужна дополнительная проверка того, является ли строка хорошо сформированной последовательностью байтов. См. Мой отчет a> для подробной информации.

Не забывайте, что XSS и SQL-инъекция. Следующий адрес действителен на основе RFC5322 на основе адресов электронной почты.

 // From Japanese tutorial // http://blog.tokumaru.org/2013/11/xsssqlrfc5322.html "><script>alert('or/**/1=1#')</script>"@example.jp 

Я думаю, что сомнительно использовать idn_to_ascii для проверки, так как idn_to_ascii передает почти все символы.

 for ($i = 0; $i < 0x110000; ++$i) { $c = utf8_chr($i); if ($c !== '' && false !== idn_to_ascii($c)) { $number = strtoupper(dechex($i)); $length = strlen($number); if ($i < 0x10000) { $number = str_repeat('0', 4 - $length).$number; } $idn = $c.'example.com'; echo 'U+'.$number.' '; echo ' '.$idn.' '. idn_to_ascii($idn); echo PHP_EOL; } } function utf8_chr($code_point) { if ($code_point < 0 || 0x10FFFF < $code_point || (0xD800 <= $code_point && $code_point <= 0xDFFF)) { return ''; } if ($code_point < 0x80) { $hex[0] = $code_point; $ret = chr($hex[0]); } else if ($code_point < 0x800) { $hex[0] = 0x1C0 | $code_point >> 6; $hex[1] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]); } else if ($code_point < 0x10000) { $hex[0] = 0xE0 | $code_point >> 12; $hex[1] = 0x80 | $code_point >> 6 & 0x3F; $hex[2] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]); } else { $hex[0] = 0xF0 | $code_point >> 18; $hex[1] = 0x80 | $code_point >> 12 & 0x3F; $hex[2] = 0x80 | $code_point >> 6 & 0x3F; $hex[3] = 0x80 | $code_point & 0x3F; $ret = chr($hex[0]).chr($hex[1]).chr($hex[2]).chr($hex[3]); } return $ret; } 

Если вы хотите проверить домен по свойствам Unicode Script, используйте функции PCRE.

Следующий код показывает, как получить имя свойства скрипта Unicode. Если вы хотите, чтобы U-скрипты Unicode выполнялись в JavaScript, используйте mathiasbynens / unicode-data .

 function get_unicode_script_name($c) { // http://php.net/manual/regexp.reference.unicode.php $names = [ 'Arabic', 'Armenian', 'Avestan', 'Balinese', 'Bamum', 'Batak', 'Bengali', 'Bopomofo', 'Brahmi', 'Braille', 'Buginese', 'Buhid', 'Canadian_Aboriginal', 'Carian', 'Chakma', 'Cham', 'Cherokee', 'Common', 'Coptic', 'Cuneiform', 'Cypriot', 'Cyrillic', 'Deseret', 'Devanagari', 'Egyptian_Hieroglyphs', 'Ethiopic', 'Georgian', 'Glagolitic', 'Gothic', 'Greek', 'Gujarati', 'Gurmukhi', 'Han', 'Hangul', 'Hanunoo', 'Hebrew', 'Hiragana', 'Imperial_Aramaic', 'Inherited', 'Inscriptional_Pahlavi', 'Inscriptional_Parthian', 'Javanese', 'Kaithi', 'Kannada', 'Katakana', 'Kayah_Li', 'Kharoshthi', 'Khmer', 'Lao', 'Latin', 'Lepcha', 'Limbu', 'Linear_B', 'Lisu', 'Lycian', 'Lydian', 'Malayalam', 'Mandaic', 'Meetei_Mayek', 'Meroitic_Cursive', 'Meroitic_Hieroglyphs', 'Miao', 'Mongolian', 'Myanmar', 'New_Tai_Lue', 'Nko', 'Ogham', 'Old_Italic', 'Old_Persian', 'Old_South_Arabian', 'Old_Turkic', 'Ol_Chiki', 'Oriya', 'Osmanya', 'Phags_Pa', 'Phoenician', 'Rejang', 'Runic', 'Samaritan', 'Saurashtra', 'Sharada', 'Shavian', 'Sinhala', 'Sora_Sompeng', 'Sundanese', 'Syloti_Nagri', 'Syriac', 'Tagalog', 'Tagbanwa', 'Tai_Le', 'Tai_Tham', 'Tai_Viet', 'Takri', 'Tamil', 'Telugu', 'Thaana', 'Thai', 'Tibetan', 'Tifinagh', 'Ugaritic', 'Vai', 'Yi' ]; $ret = []; foreach ($names as $name) { $pattern = '/\p{'.$name.'}/u'; if (preg_match($pattern, $c)) { return $name; } } return ''; } 

Это так называемый домен IDN . Клиенты, поддерживающие домены IDN, нормализуют его с использованием стандарта IDNA2008, как указано в RFC 5890 , а затем заменяют оставшиеся символы Юникода, используя кодировку Punycode, как определено в RFC 3492, перед отправкой для разрешения DNS.

По спецификации буквально каждый символ в наборе символов UTF-8 действителен для использования в домене IDN, но каждый авторитет домена верхнего уровня может определять допустимые символы в кодировке Unicode, поэтому будет сложно создать и поддерживать реальное регулярное выражение .

Если вы хотите принимать домены IDN в своем приложении, вы должны внутренне работать с кодированной версией. PHP extension intl предоставляет две функции для en- и декодирования имен доменов IDN

 echo idn_to_ascii('täst.de'); 

xn--tst-qla.de

После кодирования в домене будет проходить обычная регулярная проверка

Простая проверка:

 $url = "http://example.com/"; if (preg_match('/^(http|https|ftp):\/\/([A-Z0-9][A-Z0-9_-]*(?:\.[A-Z0-9][A-Z0-9_-]*)+):?(\d+)?\/?/i', $url)) { echo 'OK'; } else { echo 'Invalid URL.'; } 

РЕДАКТИРОВАТЬ:

Если вы хотите настоящую DNS-проверку, вы можете использовать dns_get_record (PHP 5) или gethostbyaddr

например

 $domain = 'ελληνικά.idn.icann.org'; $idnDomain = idn_to_ascii( $domain ); if ( $dnsResult = dns_get_record( $idnDomain, DNS_ANY ) ) { echo $idnDomain , "\n"; print_r( $dnsResult ); } else { echo "failed to lookup domain\n"; } 

Результат:

 xn--hxargifdar.idn.icann.org Array ( [0] => Array ( [host] => xn--hxargifdar.idn.icann.org [class] => IN [ttl] => 21456 [type] => A [ip] => 199.7.85.10 ) [1] => Array ( [host] => xn--hxargifdar.idn.icann.org [class] => IN [ttl] => 21600 [type] => AAAA [ipv6] => 2620::2830:230:0:0:0:10 ) )