2013-01-14 38 views
7

Tôi muốn xác thực url miền trong php có thể ở định dạng tên miền quốc tế như trong tên của Hy Lạp = http: //παράδειγμα.δοκιμή Có cách nào để xác thực nó bằng cách sử dụng thường xuyên không biểu hiện?cách xác thực tên miền quốc tế

+1

"Xác thực" như "kiểm tra xem nó có được chấp nhận cho DNS" hay không (hoặc là "kiểm tra xem nó có tồn tại trong DNS" hay không). – tripleee

+0

Điều gì là hợp lệ? Có phải chỉ là 'http: //' được theo sau bởi một số ký tự, sau đó là '.' theo sau là một số ký tự? –

+0

Tôi chỉ muốn kiểm tra xem DNS có hợp lệ hay không. Có regex nào có thể giúp tôi ở đây không. URL có thể có các ký tự từ các ngôn ngữ khác như tiếng Đức. ví dụ. yÄhoo.com. Tôi đang sử dụng regex này nhưng nó sẽ không làm việc cho chỉ ký tự chữ và số./^ [a-z \ d] [a-z \ d -] {0,62} $/i. Làm thế nào tôi có thể hình thành regex mà cũng đánh chặn các nhân vật từ các ngôn ngữ khác, – user1969981

Trả lời

2

Đây là idn tên miền, trước tiên tôi sẽ chuyển đổi tên miền thành phiên bản puny codevalidate các miền sau đó.

Nhưng nếu bạn thực sự muốn xác nhận một bằng regex

<?php 

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

Nhưng bạn này cho phép bạn chạy ở possitives sai sự thật, bởi vì nó là thực sự phức tạp để xác nhận một miền IDN i tryed để xác nhận rằng không có ký tự không hợp lệ là bên trong, nhưng danh sách KHÔNG hoàn thành.

Better chuyển đổi bevore mã punny

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

Và nếu bạn thêm muốn kiểm tra xem tên miền có thể được giải quyết thử:

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

Đây là một cái gọi là IDN domain. Khách hàng hỗ trợ các miền IDN chuẩn hóa nó bằng cách sử dụng tiêu chuẩn IDNA2008 như được chỉ định trong RFC 5890, sau đó thay thế các ký tự unicode còn lại bằng cách sử dụng mã hóa Punycode như được định nghĩa trong RFC 3492 trước khi gửi để giải quyết DNS.

Theo đặc điểm, nghĩa là mọi ký tự trong bộ ký tự UTF-8 hợp lệ để sử dụng trong miền IDN, nhưng mọi cơ quan cấp cao nhất đều có thể xác định các ký tự hợp lệ trong bộ mã Unicode để nó khó có thể là create and maintain a real regex.

Nếu bạn muốn chấp nhận tên miền IDN trong ứng dụng của bạn, bạn nên làm việc nội bộ với phiên bản được mã hóa. PHP extension intl mang hai chức năng để en- và giải mã tên miền IDN

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

xn--tst-qla.de

Sau khi mã hóa, tên miền, sẽ vượt qua bất kỳ traditional regex check

Simple xác thực:

$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.'; 
} 

EDIT:

Nếu bạn muốn có một DNS thực verfification bạn có thể sử dụng dns_get_record (PHP 5) hoặc gethostbyaddr

ví dụ

$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"; 
} 

Kết quả:

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 
    ) 
) 
+2

Tôi * nghĩ * Tôi tìm thấy một lỗi * quan trọng * trong câu trả lời của bạn. Bạn nói: 'Theo đặc điểm kỹ thuật, nghĩa là mọi ký tự trong bộ ký tự UTF-8 là hợp lệ để sử dụng trong một miền IDN' (trong khi bạn nói về IDNA2008 và RFC5890). * HOWEVER * (theo hiểu biết của tôi), IDNA2008 bây giờ không cho phép khoảng tám nghìn ký tự được sử dụng hợp lệ, bao gồm tất cả các ký tự chữ hoa, biến thể toàn bộ/nửa chiều rộng, ký hiệu và dấu chấm câu (trước đây được cho phép trong IDNA2003 và tại thời điểm này) làm việc trong hầu hết các triển khai). Xem http://www.unicode.org/faq/idn.html & http://tools.ietf.org/html/rfc5892. Hay tôi đã đọc sai? – GitaarLAB

+1

@Gitaar cảm ơn, bạn đã đúng. Điều này là mới đối với tôi nhưng hoàn toàn có ý nghĩa, vì tên miền không phân biệt chữ hoa chữ thường và các ký tự dấu chấm câu có thể được đặt trước (ví dụ: dấu phân tách miền 'dấu chấm', dấu phân cách chuỗi truy vấn, v.v. –

2

Nếu bạn muốn tạo libirary riêng bạn, bạn cần phải sử dụng bảng codepoints phép (IANA — Repository of IDN Practices, IDN Character Validation Guidance, IDNA Parameters) và bảng tính Unicode Script (UNIDATA/Scripts.txt).

Gmail áp dụng đặc điểm kỹ thuật "H ighly Restricted" của Unicode Consortium (Protecting Gmail in a global world). Cho phép các comibinations mã Unicode sau đây.

  • kịch bản đơn
  • Latinh + Han + Hiragana + Katakana
  • Latinh + Han + Bopomofo
  • Latinh + Han + Hangul

Bạn có thể cần phải trả tiền Chú ý nào để sở hữu kịch bản đặc biệt giá trị (Chung, Thừa kế, Không xác định) vì một số ký tự có nhiều thuộc tính hoặc thuộc tính sai.

Ví dụ: U + 3099 (KẾT NỐI KẾT NỐI KATAKANA-HIRAGANA SOUND) có hai mệnh đề ("Katakana" và "Hiragana") và chức năng PCRE phân loại nó là "Kế thừa". Một ví dụ khác là U + x2A708. Althogh thuộc tính kịch bản bên phải của U + 2A708 (comibination của U + 30C8 KATAKANA LETTER TO và U + 30E2 KATAKANA THƯ MO) là "Katakana", Đặc tả Unicode phân loại sai nó là "Han".

Bạn có thể cần xem xét IDN homograph attack. Google232 IDN policy thông qua the blacklist chars.

Đề xuất của tôi là sử dụng Zend \ Validator \ Hostname. Thư viện này sử dụng the table of permitted code points cho tiếng Nhật và tiếng Trung.

Nếu bạn sử dụng Symfony, hãy cân nhắc nâng cấp ứng dụng phiên bản lên 2.5, thông qua egulias/email-validatornd (Manual). Bạn cần xác thực thêm cho dù chuỗi là chuỗi byte được hình thành tốt. Xem report a> để biết chi tiết.

Đừng quên XSS và SQL injection. Địa chỉ sau là địa chỉ email hợp lệ dựa trên RFC5322.

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

Tôi nghĩ rằng việc sử dụng idn_to_ascii để xác thực là đáng ngờ vì idn_to_ascii vượt qua hầu hết các ký tự.

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; 
} 

Nếu bạn muốn xác thực miền bằng thuộc tính Unicode Script, hãy sử dụng các chức năng PCRE.

Mã sau đây cho biết cách lấy tên tne thuộc tính tập lệnh Unicode. Nếu bạn muốn che giấu tính hiệu quả của JavaScript Script trong JavaScript, hãy sử dụng 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 ''; 
} 
Các vấn đề liên quan