File indexing completed on 2024-05-12 06:03:14

0001 <?php
0002 /**
0003  * Zend Framework
0004  *
0005  * LICENSE
0006  *
0007  * This source file is subject to the new BSD license that is bundled
0008  * with this package in the file LICENSE.txt.
0009  * It is also available through the world-wide-web at this URL:
0010  * http://framework.zend.com/license/new-bsd
0011  * If you did not receive a copy of the license and are unable to
0012  * obtain it through the world-wide-web, please send an email
0013  * to license@zend.com so we can send you a copy immediately.
0014  *
0015  * @category   Zend
0016  * @package    Zend_Validate
0017  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0018  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0019  * @version    $Id$
0020  */
0021 
0022 /**
0023  * @see Zend_Validate_Abstract
0024  */
0025 // require_once 'Zend/Validate/Abstract.php';
0026 
0027 /**
0028  * @see Zend_Validate_Ip
0029  */
0030 // require_once 'Zend/Validate/Ip.php';
0031 
0032 /**
0033  * Please note there are two standalone test scripts for testing IDN characters due to problems
0034  * with file encoding.
0035  *
0036  * The first is tests/Zend/Validate/HostnameTestStandalone.php which is designed to be run on
0037  * the command line.
0038  *
0039  * The second is tests/Zend/Validate/HostnameTestForm.php which is designed to be run via HTML
0040  * to allow users to test entering UTF-8 characters in a form.
0041  *
0042  * @category   Zend
0043  * @package    Zend_Validate
0044  * @copyright  Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
0045  * @license    http://framework.zend.com/license/new-bsd     New BSD License
0046  */
0047 class Zend_Validate_Hostname extends Zend_Validate_Abstract
0048 {
0049     const CANNOT_DECODE_PUNYCODE  = 'hostnameCannotDecodePunycode';
0050     const INVALID                 = 'hostnameInvalid';
0051     const INVALID_DASH            = 'hostnameDashCharacter';
0052     const INVALID_HOSTNAME        = 'hostnameInvalidHostname';
0053     const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
0054     const INVALID_LOCAL_NAME      = 'hostnameInvalidLocalName';
0055     const INVALID_URI             = 'hostnameInvalidUri';
0056     const IP_ADDRESS_NOT_ALLOWED  = 'hostnameIpAddressNotAllowed';
0057     const LOCAL_NAME_NOT_ALLOWED  = 'hostnameLocalNameNotAllowed';
0058     const UNDECIPHERABLE_TLD      = 'hostnameUndecipherableTld';
0059     const UNKNOWN_TLD             = 'hostnameUnknownTld';
0060 
0061     /**
0062      * @var array
0063      */
0064     protected $_messageTemplates = array(
0065         self::CANNOT_DECODE_PUNYCODE  => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded",
0066         self::INVALID                 => "Invalid type given. String expected",
0067         self::INVALID_DASH            => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position",
0068         self::INVALID_HOSTNAME        => "'%value%' does not match the expected structure for a DNS hostname",
0069         self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
0070         self::INVALID_LOCAL_NAME      => "'%value%' does not appear to be a valid local network name",
0071         self::INVALID_URI             => "'%value%' does not appear to be a valid URI hostname",
0072         self::IP_ADDRESS_NOT_ALLOWED  => "'%value%' appears to be an IP address, but IP addresses are not allowed",
0073         self::LOCAL_NAME_NOT_ALLOWED  => "'%value%' appears to be a local network name but local network names are not allowed",
0074         self::UNDECIPHERABLE_TLD      => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
0075         self::UNKNOWN_TLD             => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
0076     );
0077 
0078     /**
0079      * @var array
0080      */
0081     protected $_messageVariables = array(
0082         'tld' => '_tld'
0083     );
0084 
0085     /**
0086      * Allows Internet domain names (e.g., example.com)
0087      */
0088     const ALLOW_DNS   = 1;
0089 
0090     /**
0091      * Allows IP addresses
0092      */
0093     const ALLOW_IP    = 2;
0094 
0095     /**
0096      * Allows local network names (e.g., localhost, www.localdomain)
0097      */
0098     const ALLOW_LOCAL = 4;
0099 
0100     /**
0101      * Allows all types of hostnames
0102      */
0103     const ALLOW_URI = 8;
0104 
0105     /**
0106      * Allows all types of hostnames
0107      */
0108     const ALLOW_ALL = 15;
0109 
0110     /**
0111      * Array of valid top-level-domains
0112      *
0113      * Version 2015091800, Last Updated Fri Sep 18 07:07:01 2015 UTC
0114      *
0115      * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt  List of all TLDs by domain
0116      * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
0117      * @var array
0118      */
0119     protected $_validTlds = array(
0120         'aaa',
0121         'abb',
0122         'abbott',
0123         'abogado',
0124         'ac',
0125         'academy',
0126         'accenture',
0127         'accountant',
0128         'accountants',
0129         'aco',
0130         'active',
0131         'actor',
0132         'ad',
0133         'ads',
0134         'adult',
0135         'ae',
0136         'aeg',
0137         'aero',
0138         'af',
0139         'afl',
0140         'ag',
0141         'agency',
0142         'ai',
0143         'aig',
0144         'airforce',
0145         'airtel',
0146         'al',
0147         'allfinanz',
0148         'alsace',
0149         'am',
0150         'amica',
0151         'amsterdam',
0152         'android',
0153         'ao',
0154         'apartments',
0155         'app',
0156         'aq',
0157         'aquarelle',
0158         'ar',
0159         'aramco',
0160         'archi',
0161         'army',
0162         'arpa',
0163         'arte',
0164         'as',
0165         'asia',
0166         'associates',
0167         'at',
0168         'attorney',
0169         'au',
0170         'auction',
0171         'audio',
0172         'auto',
0173         'autos',
0174         'aw',
0175         'ax',
0176         'axa',
0177         'az',
0178         'azure',
0179         'ba',
0180         'band',
0181         'bank',
0182         'bar',
0183         'barcelona',
0184         'barclaycard',
0185         'barclays',
0186         'bargains',
0187         'bauhaus',
0188         'bayern',
0189         'bb',
0190         'bbc',
0191         'bbva',
0192         'bcn',
0193         'bd',
0194         'be',
0195         'beer',
0196         'bentley',
0197         'berlin',
0198         'best',
0199         'bet',
0200         'bf',
0201         'bg',
0202         'bh',
0203         'bharti',
0204         'bi',
0205         'bible',
0206         'bid',
0207         'bike',
0208         'bing',
0209         'bingo',
0210         'bio',
0211         'biz',
0212         'bj',
0213         'black',
0214         'blackfriday',
0215         'bloomberg',
0216         'blue',
0217         'bm',
0218         'bms',
0219         'bmw',
0220         'bn',
0221         'bnl',
0222         'bnpparibas',
0223         'bo',
0224         'boats',
0225         'bom',
0226         'bond',
0227         'boo',
0228         'boots',
0229         'boutique',
0230         'br',
0231         'bradesco',
0232         'bridgestone',
0233         'broker',
0234         'brother',
0235         'brussels',
0236         'bs',
0237         'bt',
0238         'budapest',
0239         'build',
0240         'builders',
0241         'business',
0242         'buzz',
0243         'bv',
0244         'bw',
0245         'by',
0246         'bz',
0247         'bzh',
0248         'ca',
0249         'cab',
0250         'cafe',
0251         'cal',
0252         'camera',
0253         'camp',
0254         'cancerresearch',
0255         'canon',
0256         'capetown',
0257         'capital',
0258         'car',
0259         'caravan',
0260         'cards',
0261         'care',
0262         'career',
0263         'careers',
0264         'cars',
0265         'cartier',
0266         'casa',
0267         'cash',
0268         'casino',
0269         'cat',
0270         'catering',
0271         'cba',
0272         'cbn',
0273         'cc',
0274         'cd',
0275         'ceb',
0276         'center',
0277         'ceo',
0278         'cern',
0279         'cf',
0280         'cfa',
0281         'cfd',
0282         'cg',
0283         'ch',
0284         'chanel',
0285         'channel',
0286         'chat',
0287         'cheap',
0288         'chloe',
0289         'christmas',
0290         'chrome',
0291         'church',
0292         'ci',
0293         'cipriani',
0294         'cisco',
0295         'citic',
0296         'city',
0297         'ck',
0298         'cl',
0299         'claims',
0300         'cleaning',
0301         'click',
0302         'clinic',
0303         'clothing',
0304         'cloud',
0305         'club',
0306         'clubmed',
0307         'cm',
0308         'cn',
0309         'co',
0310         'coach',
0311         'codes',
0312         'coffee',
0313         'college',
0314         'cologne',
0315         'com',
0316         'commbank',
0317         'community',
0318         'company',
0319         'computer',
0320         'condos',
0321         'construction',
0322         'consulting',
0323         'contractors',
0324         'cooking',
0325         'cool',
0326         'coop',
0327         'corsica',
0328         'country',
0329         'coupons',
0330         'courses',
0331         'cr',
0332         'credit',
0333         'creditcard',
0334         'cricket',
0335         'crown',
0336         'crs',
0337         'cruises',
0338         'csc',
0339         'cu',
0340         'cuisinella',
0341         'cv',
0342         'cw',
0343         'cx',
0344         'cy',
0345         'cymru',
0346         'cyou',
0347         'cz',
0348         'dabur',
0349         'dad',
0350         'dance',
0351         'date',
0352         'dating',
0353         'datsun',
0354         'day',
0355         'dclk',
0356         'de',
0357         'deals',
0358         'degree',
0359         'delivery',
0360         'dell',
0361         'delta',
0362         'democrat',
0363         'dental',
0364         'dentist',
0365         'desi',
0366         'design',
0367         'dev',
0368         'diamonds',
0369         'diet',
0370         'digital',
0371         'direct',
0372         'directory',
0373         'discount',
0374         'dj',
0375         'dk',
0376         'dm',
0377         'dnp',
0378         'do',
0379         'docs',
0380         'dog',
0381         'doha',
0382         'domains',
0383         'doosan',
0384         'download',
0385         'drive',
0386         'durban',
0387         'dvag',
0388         'dz',
0389         'earth',
0390         'eat',
0391         'ec',
0392         'edu',
0393         'education',
0394         'ee',
0395         'eg',
0396         'email',
0397         'emerck',
0398         'energy',
0399         'engineer',
0400         'engineering',
0401         'enterprises',
0402         'epson',
0403         'equipment',
0404         'er',
0405         'erni',
0406         'es',
0407         'esq',
0408         'estate',
0409         'et',
0410         'eu',
0411         'eurovision',
0412         'eus',
0413         'events',
0414         'everbank',
0415         'exchange',
0416         'expert',
0417         'exposed',
0418         'express',
0419         'fage',
0420         'fail',
0421         'faith',
0422         'family',
0423         'fan',
0424         'fans',
0425         'farm',
0426         'fashion',
0427         'feedback',
0428         'fi',
0429         'film',
0430         'final',
0431         'finance',
0432         'financial',
0433         'firmdale',
0434         'fish',
0435         'fishing',
0436         'fit',
0437         'fitness',
0438         'fj',
0439         'fk',
0440         'flights',
0441         'florist',
0442         'flowers',
0443         'flsmidth',
0444         'fly',
0445         'fm',
0446         'fo',
0447         'foo',
0448         'football',
0449         'forex',
0450         'forsale',
0451         'forum',
0452         'foundation',
0453         'fr',
0454         'frl',
0455         'frogans',
0456         'fund',
0457         'furniture',
0458         'futbol',
0459         'fyi',
0460         'ga',
0461         'gal',
0462         'gallery',
0463         'game',
0464         'garden',
0465         'gb',
0466         'gbiz',
0467         'gd',
0468         'gdn',
0469         'ge',
0470         'gea',
0471         'gent',
0472         'genting',
0473         'gf',
0474         'gg',
0475         'ggee',
0476         'gh',
0477         'gi',
0478         'gift',
0479         'gifts',
0480         'gives',
0481         'giving',
0482         'gl',
0483         'glass',
0484         'gle',
0485         'global',
0486         'globo',
0487         'gm',
0488         'gmail',
0489         'gmo',
0490         'gmx',
0491         'gn',
0492         'gold',
0493         'goldpoint',
0494         'golf',
0495         'goo',
0496         'goog',
0497         'google',
0498         'gop',
0499         'gov',
0500         'gp',
0501         'gq',
0502         'gr',
0503         'graphics',
0504         'gratis',
0505         'green',
0506         'gripe',
0507         'group',
0508         'gs',
0509         'gt',
0510         'gu',
0511         'gucci',
0512         'guge',
0513         'guide',
0514         'guitars',
0515         'guru',
0516         'gw',
0517         'gy',
0518         'hamburg',
0519         'hangout',
0520         'haus',
0521         'healthcare',
0522         'help',
0523         'here',
0524         'hermes',
0525         'hiphop',
0526         'hitachi',
0527         'hiv',
0528         'hk',
0529         'hm',
0530         'hn',
0531         'hockey',
0532         'holdings',
0533         'holiday',
0534         'homedepot',
0535         'homes',
0536         'honda',
0537         'horse',
0538         'host',
0539         'hosting',
0540         'hoteles',
0541         'hotmail',
0542         'house',
0543         'how',
0544         'hr',
0545         'hsbc',
0546         'ht',
0547         'hu',
0548         'hyundai',
0549         'ibm',
0550         'icbc',
0551         'ice',
0552         'icu',
0553         'id',
0554         'ie',
0555         'ifm',
0556         'iinet',
0557         'il',
0558         'im',
0559         'immo',
0560         'immobilien',
0561         'in',
0562         'industries',
0563         'infiniti',
0564         'info',
0565         'ing',
0566         'ink',
0567         'institute',
0568         'insure',
0569         'int',
0570         'international',
0571         'investments',
0572         'io',
0573         'ipiranga',
0574         'iq',
0575         'ir',
0576         'irish',
0577         'is',
0578         'ist',
0579         'istanbul',
0580         'it',
0581         'itau',
0582         'iwc',
0583         'jaguar',
0584         'java',
0585         'jcb',
0586         'je',
0587         'jetzt',
0588         'jewelry',
0589         'jlc',
0590         'jll',
0591         'jm',
0592         'jo',
0593         'jobs',
0594         'joburg',
0595         'jp',
0596         'jprs',
0597         'juegos',
0598         'kaufen',
0599         'kddi',
0600         'ke',
0601         'kg',
0602         'kh',
0603         'ki',
0604         'kia',
0605         'kim',
0606         'kinder',
0607         'kitchen',
0608         'kiwi',
0609         'km',
0610         'kn',
0611         'koeln',
0612         'komatsu',
0613         'kp',
0614         'kr',
0615         'krd',
0616         'kred',
0617         'kw',
0618         'ky',
0619         'kyoto',
0620         'kz',
0621         'la',
0622         'lacaixa',
0623         'lancaster',
0624         'land',
0625         'landrover',
0626         'lasalle',
0627         'lat',
0628         'latrobe',
0629         'law',
0630         'lawyer',
0631         'lb',
0632         'lc',
0633         'lds',
0634         'lease',
0635         'leclerc',
0636         'legal',
0637         'lexus',
0638         'lgbt',
0639         'li',
0640         'liaison',
0641         'lidl',
0642         'life',
0643         'lighting',
0644         'limited',
0645         'limo',
0646         'linde',
0647         'link',
0648         'live',
0649         'lixil',
0650         'lk',
0651         'loan',
0652         'loans',
0653         'lol',
0654         'london',
0655         'lotte',
0656         'lotto',
0657         'love',
0658         'lr',
0659         'ls',
0660         'lt',
0661         'ltd',
0662         'ltda',
0663         'lu',
0664         'lupin',
0665         'luxe',
0666         'luxury',
0667         'lv',
0668         'ly',
0669         'ma',
0670         'madrid',
0671         'maif',
0672         'maison',
0673         'man',
0674         'management',
0675         'mango',
0676         'market',
0677         'marketing',
0678         'markets',
0679         'marriott',
0680         'mba',
0681         'mc',
0682         'md',
0683         'me',
0684         'media',
0685         'meet',
0686         'melbourne',
0687         'meme',
0688         'memorial',
0689         'men',
0690         'menu',
0691         'mg',
0692         'mh',
0693         'miami',
0694         'microsoft',
0695         'mil',
0696         'mini',
0697         'mk',
0698         'ml',
0699         'mm',
0700         'mma',
0701         'mn',
0702         'mo',
0703         'mobi',
0704         'moda',
0705         'moe',
0706         'moi',
0707         'mom',
0708         'monash',
0709         'money',
0710         'montblanc',
0711         'mormon',
0712         'mortgage',
0713         'moscow',
0714         'motorcycles',
0715         'mov',
0716         'movie',
0717         'movistar',
0718         'mp',
0719         'mq',
0720         'mr',
0721         'ms',
0722         'mt',
0723         'mtn',
0724         'mtpc',
0725         'mtr',
0726         'mu',
0727         'museum',
0728         'mutuelle',
0729         'mv',
0730         'mw',
0731         'mx',
0732         'my',
0733         'mz',
0734         'na',
0735         'nadex',
0736         'nagoya',
0737         'name',
0738         'navy',
0739         'nc',
0740         'ne',
0741         'nec',
0742         'net',
0743         'netbank',
0744         'network',
0745         'neustar',
0746         'new',
0747         'news',
0748         'nexus',
0749         'nf',
0750         'ng',
0751         'ngo',
0752         'nhk',
0753         'ni',
0754         'nico',
0755         'ninja',
0756         'nissan',
0757         'nl',
0758         'no',
0759         'nokia',
0760         'np',
0761         'nr',
0762         'nra',
0763         'nrw',
0764         'ntt',
0765         'nu',
0766         'nyc',
0767         'nz',
0768         'obi',
0769         'office',
0770         'okinawa',
0771         'om',
0772         'omega',
0773         'one',
0774         'ong',
0775         'onl',
0776         'online',
0777         'ooo',
0778         'oracle',
0779         'orange',
0780         'org',
0781         'organic',
0782         'osaka',
0783         'otsuka',
0784         'ovh',
0785         'pa',
0786         'page',
0787         'panerai',
0788         'paris',
0789         'partners',
0790         'parts',
0791         'party',
0792         'pe',
0793         'pet',
0794         'pf',
0795         'pg',
0796         'ph',
0797         'pharmacy',
0798         'philips',
0799         'photo',
0800         'photography',
0801         'photos',
0802         'physio',
0803         'piaget',
0804         'pics',
0805         'pictet',
0806         'pictures',
0807         'pink',
0808         'pizza',
0809         'pk',
0810         'pl',
0811         'place',
0812         'play',
0813         'plumbing',
0814         'plus',
0815         'pm',
0816         'pn',
0817         'pohl',
0818         'poker',
0819         'porn',
0820         'post',
0821         'pr',
0822         'praxi',
0823         'press',
0824         'pro',
0825         'prod',
0826         'productions',
0827         'prof',
0828         'properties',
0829         'property',
0830         'protection',
0831         'ps',
0832         'pt',
0833         'pub',
0834         'pw',
0835         'py',
0836         'qa',
0837         'qpon',
0838         'quebec',
0839         'racing',
0840         're',
0841         'realtor',
0842         'realty',
0843         'recipes',
0844         'red',
0845         'redstone',
0846         'rehab',
0847         'reise',
0848         'reisen',
0849         'reit',
0850         'ren',
0851         'rent',
0852         'rentals',
0853         'repair',
0854         'report',
0855         'republican',
0856         'rest',
0857         'restaurant',
0858         'review',
0859         'reviews',
0860         'rich',
0861         'ricoh',
0862         'rio',
0863         'rip',
0864         'ro',
0865         'rocks',
0866         'rodeo',
0867         'rs',
0868         'rsvp',
0869         'ru',
0870         'ruhr',
0871         'run',
0872         'rw',
0873         'rwe',
0874         'ryukyu',
0875         'sa',
0876         'saarland',
0877         'sakura',
0878         'sale',
0879         'samsung',
0880         'sandvik',
0881         'sandvikcoromant',
0882         'sanofi',
0883         'sap',
0884         'sarl',
0885         'saxo',
0886         'sb',
0887         'sc',
0888         'sca',
0889         'scb',
0890         'schmidt',
0891         'scholarships',
0892         'school',
0893         'schule',
0894         'schwarz',
0895         'science',
0896         'scor',
0897         'scot',
0898         'sd',
0899         'se',
0900         'seat',
0901         'security',
0902         'seek',
0903         'sener',
0904         'services',
0905         'seven',
0906         'sew',
0907         'sex',
0908         'sexy',
0909         'sg',
0910         'sh',
0911         'shiksha',
0912         'shoes',
0913         'show',
0914         'shriram',
0915         'si',
0916         'singles',
0917         'site',
0918         'sj',
0919         'sk',
0920         'ski',
0921         'sky',
0922         'skype',
0923         'sl',
0924         'sm',
0925         'sn',
0926         'sncf',
0927         'so',
0928         'soccer',
0929         'social',
0930         'software',
0931         'sohu',
0932         'solar',
0933         'solutions',
0934         'sony',
0935         'soy',
0936         'space',
0937         'spiegel',
0938         'spreadbetting',
0939         'sr',
0940         'srl',
0941         'st',
0942         'stada',
0943         'starhub',
0944         'statoil',
0945         'stc',
0946         'stcgroup',
0947         'stockholm',
0948         'studio',
0949         'study',
0950         'style',
0951         'su',
0952         'sucks',
0953         'supplies',
0954         'supply',
0955         'support',
0956         'surf',
0957         'surgery',
0958         'suzuki',
0959         'sv',
0960         'swatch',
0961         'swiss',
0962         'sx',
0963         'sy',
0964         'sydney',
0965         'systems',
0966         'sz',
0967         'taipei',
0968         'tatamotors',
0969         'tatar',
0970         'tattoo',
0971         'tax',
0972         'taxi',
0973         'tc',
0974         'td',
0975         'team',
0976         'tech',
0977         'technology',
0978         'tel',
0979         'telefonica',
0980         'temasek',
0981         'tennis',
0982         'tf',
0983         'tg',
0984         'th',
0985         'thd',
0986         'theater',
0987         'theatre',
0988         'tickets',
0989         'tienda',
0990         'tips',
0991         'tires',
0992         'tirol',
0993         'tj',
0994         'tk',
0995         'tl',
0996         'tm',
0997         'tn',
0998         'to',
0999         'today',
1000         'tokyo',
1001         'tools',
1002         'top',
1003         'toray',
1004         'toshiba',
1005         'tours',
1006         'town',
1007         'toyota',
1008         'toys',
1009         'tr',
1010         'trade',
1011         'trading',
1012         'training',
1013         'travel',
1014         'trust',
1015         'tt',
1016         'tui',
1017         'tv',
1018         'tw',
1019         'tz',
1020         'ua',
1021         'ubs',
1022         'ug',
1023         'uk',
1024         'university',
1025         'uno',
1026         'uol',
1027         'us',
1028         'uy',
1029         'uz',
1030         'va',
1031         'vacations',
1032         'vc',
1033         've',
1034         'vegas',
1035         'ventures',
1036         'versicherung',
1037         'vet',
1038         'vg',
1039         'vi',
1040         'viajes',
1041         'video',
1042         'villas',
1043         'vin',
1044         'virgin',
1045         'vision',
1046         'vista',
1047         'vistaprint',
1048         'viva',
1049         'vlaanderen',
1050         'vn',
1051         'vodka',
1052         'vote',
1053         'voting',
1054         'voto',
1055         'voyage',
1056         'vu',
1057         'wales',
1058         'walter',
1059         'wang',
1060         'watch',
1061         'webcam',
1062         'website',
1063         'wed',
1064         'wedding',
1065         'weir',
1066         'wf',
1067         'whoswho',
1068         'wien',
1069         'wiki',
1070         'williamhill',
1071         'win',
1072         'windows',
1073         'wine',
1074         'wme',
1075         'work',
1076         'works',
1077         'world',
1078         'ws',
1079         'wtc',
1080         'wtf',
1081         'xbox',
1082         'xerox',
1083         'xin',
1084         'xn--11b4c3d',
1085         'xn--1qqw23a',
1086         'xn--30rr7y',
1087         'xn--3bst00m',
1088         'xn--3ds443g',
1089         'xn--3e0b707e',
1090         'xn--3pxu8k',
1091         'xn--42c2d9a',
1092         'xn--45brj9c',
1093         'xn--45q11c',
1094         'xn--4gbrim',
1095         'xn--55qw42g',
1096         'xn--55qx5d',
1097         'xn--6frz82g',
1098         'xn--6qq986b3xl',
1099         'xn--80adxhks',
1100         'xn--80ao21a',
1101         'xn--80asehdb',
1102         'xn--80aswg',
1103         'xn--90a3ac',
1104         'xn--90ais',
1105         'xn--9dbq2a',
1106         'xn--9et52u',
1107         'xn--b4w605ferd',
1108         'xn--c1avg',
1109         'xn--c2br7g',
1110         'xn--cg4bki',
1111         'xn--clchc0ea0b2g2a9gcd',
1112         'xn--czr694b',
1113         'xn--czrs0t',
1114         'xn--czru2d',
1115         'xn--d1acj3b',
1116         'xn--d1alf',
1117         'xn--efvy88h',
1118         'xn--estv75g',
1119         'xn--fhbei',
1120         'xn--fiq228c5hs',
1121         'xn--fiq64b',
1122         'xn--fiqs8s',
1123         'xn--fiqz9s',
1124         'xn--fjq720a',
1125         'xn--flw351e',
1126         'xn--fpcrj9c3d',
1127         'xn--fzc2c9e2c',
1128         'xn--gecrj9c',
1129         'xn--h2brj9c',
1130         'xn--hxt814e',
1131         'xn--i1b6b1a6a2e',
1132         'xn--imr513n',
1133         'xn--io0a7i',
1134         'xn--j1aef',
1135         'xn--j1amh',
1136         'xn--j6w193g',
1137         'xn--kcrx77d1x4a',
1138         'xn--kprw13d',
1139         'xn--kpry57d',
1140         'xn--kput3i',
1141         'xn--l1acc',
1142         'xn--lgbbat1ad8j',
1143         'xn--mgb9awbf',
1144         'xn--mgba3a3ejt',
1145         'xn--mgba3a4f16a',
1146         'xn--mgbaam7a8h',
1147         'xn--mgbab2bd',
1148         'xn--mgbayh7gpa',
1149         'xn--mgbbh1a71e',
1150         'xn--mgbc0a9azcg',
1151         'xn--mgberp4a5d4ar',
1152         'xn--mgbpl2fh',
1153         'xn--mgbx4cd0ab',
1154         'xn--mk1bu44c',
1155         'xn--mxtq1m',
1156         'xn--ngbc5azd',
1157         'xn--node',
1158         'xn--nqv7f',
1159         'xn--nqv7fs00ema',
1160         'xn--nyqy26a',
1161         'xn--o3cw4h',
1162         'xn--ogbpf8fl',
1163         'xn--p1acf',
1164         'xn--p1ai',
1165         'xn--pgbs0dh',
1166         'xn--pssy2u',
1167         'xn--q9jyb4c',
1168         'xn--qcka1pmc',
1169         'xn--rhqv96g',
1170         'xn--s9brj9c',
1171         'xn--ses554g',
1172         'xn--t60b56a',
1173         'xn--tckwe',
1174         'xn--unup4y',
1175         'xn--vermgensberater-ctb',
1176         'xn--vermgensberatung-pwb',
1177         'xn--vhquv',
1178         'xn--vuq861b',
1179         'xn--wgbh1c',
1180         'xn--wgbl6a',
1181         'xn--xhq521b',
1182         'xn--xkc2al3hye2a',
1183         'xn--xkc2dl3a5ee0h',
1184         'xn--y9a3aq',
1185         'xn--yfro4i67o',
1186         'xn--ygbi2ammx',
1187         'xn--zfr164b',
1188         'xperia',
1189         'xxx',
1190         'xyz',
1191         'yachts',
1192         'yamaxun',
1193         'yandex',
1194         'ye',
1195         'yodobashi',
1196         'yoga',
1197         'yokohama',
1198         'youtube',
1199         'yt',
1200         'za',
1201         'zara',
1202         'zip',
1203         'zm',
1204         'zone',
1205         'zuerich',
1206         'zw',
1207         '测试',
1208         'परीक्षा',
1209         '佛山',
1210         '集团',
1211         '在线',
1212         '한국',
1213         'ভারত',
1214         '八卦',
1215         'موقع',
1216         'বাংলা',
1217         '公益',
1218         '公司',
1219         '移动',
1220         '我爱你',
1221         'москва',
1222         'испытание',
1223         'қаз',
1224         'онлайн',
1225         'сайт',
1226         'срб',
1227         'бел',
1228         '테스트',
1229         'орг',
1230         '삼성',
1231         'சிங்கப்பூர்',
1232         '商标',
1233         '商城',
1234         'дети',
1235         'мкд',
1236         'טעסט',
1237         '中文网',
1238         '中信',
1239         '中国',
1240         '中國',
1241         '谷歌',
1242         'భారత్',
1243         'ලංකා',
1244         '測試',
1245         'ભારત',
1246         'भारत',
1247         'آزمایشی',
1248         'பரிட்சை',
1249         'संगठन',
1250         '网络',
1251         'укр',
1252         '香港',
1253         'δοκιμή',
1254         'إختبار',
1255         '台湾',
1256         '台灣',
1257         '手机',
1258         'мон',
1259         'الجزائر',
1260         'عمان',
1261         'ایران',
1262         'امارات',
1263         'بازار',
1264         'پاکستان',
1265         'الاردن',
1266         'بھارت',
1267         'المغرب',
1268         'السعودية',
1269         'سودان',
1270         'عراق',
1271         'مليسيا',
1272         'شبكة',
1273         'გე',
1274         '机构',
1275         '组织机构',
1276         'ไทย',
1277         'سورية',
1278         'рус',
1279         'рф',
1280         'تونس',
1281         'みんな',
1282         'グーグル',
1283         '世界',
1284         'ਭਾਰਤ',
1285         '网址',
1286         '游戏',
1287         'vermögensberater',
1288         'vermögensberatung',
1289         '企业',
1290         'مصر',
1291         'قطر',
1292         '广东',
1293         'இலங்கை',
1294         'இந்தியா',
1295         'հայ',
1296         '新加坡',
1297         'فلسطين',
1298         'テスト',
1299         '政务',
1300     );
1301 
1302     /**
1303      * @var string
1304      */
1305     protected $_tld;
1306 
1307     /**
1308      * Array for valid Idns
1309      * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
1310      * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
1311      * (.AR) Argentinia http://www.nic.ar/faqidn.html
1312      * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
1313      * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
1314      * (.BIZ) International http://www.iana.org/domains/idn-tables/
1315      * (.BR) Brazil http://registro.br/faq/faq6.html
1316      * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
1317      * (.CA) Canada http://www.iana.org/domains/idn-tables/tables/ca_fr_1.0.html
1318      * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
1319      * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
1320      * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
1321      * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
1322      * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html
1323      * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
1324      * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
1325      * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
1326      * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
1327      * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
1328      * (.INFO) International http://www.nic.info/info/idn
1329      * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
1330      * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
1331      * (.IS) Iceland http://www.isnic.is/domain/rules.php
1332      * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
1333      * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
1334      * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
1335      * (.MD) Moldova http://www.register.md/
1336      * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
1337      * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
1338      * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
1339      * (.NU) Niue http://www.worldnames.net/
1340      * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
1341      * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
1342      * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
1343      * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
1344      * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
1345      * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
1346      * (.RS) Serbia http://www.iana.org/domains/idn-tables/tables/rs_sr-rs_1.0.pdf
1347      * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
1348      * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
1349      * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
1350      * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
1351      * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
1352      * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
1353      * (.TR) Turkey https://www.nic.tr/index.php
1354      * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html
1355      * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
1356      * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
1357      *
1358      * @var array
1359      */
1360     protected $_validIdns = array(
1361         'AC'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
1362         'AR'  => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'),
1363         'AS'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'),
1364         'AT'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'),
1365         'BIZ' => 'Hostname/Biz.php',
1366         'BR'  => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'),
1367         'BV'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
1368         'CA'  => array(1 => '/^[\x{002d}0-9a-zàâæçéèêëîïôœùûüÿ\x{00E0}\x{00E2}\x{00E7}\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{00EE}\x{00EF}\x{00F4}\x{00F9}\x{00FB}\x{00FC}\x{00E6}\x{0153}\x{00FF}]{1,63}$/iu'),
1369         'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'),
1370         'CH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
1371         'CL'  => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
1372         'CN'  => 'Hostname/Cn.php',
1373         'COM' => 'Hostname/Com.php',
1374         'DE'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťßţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
1375         'DK'  => array(1 => '/^[\x{002d}0-9a-zäéöüæøå]{1,63}$/iu'),
1376         'ES'  => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'),
1377         'EU'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
1378             2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
1379             3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu',
1380             4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu',
1381             5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu',
1382             6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ὼώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ῒΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'),
1383         'FI'  => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'),
1384         'GR'  => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'),
1385         'HK'  => 'Hostname/Cn.php',
1386         'HU'  => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'),
1387         'IL'  => array(1 => '/^[\x{002d}0-9\x{05D0}-\x{05EA}]{1,63}$/iu',
1388             2 => '/^[\x{002d}0-9a-z]{1,63}$/i'),
1389         'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
1390             2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
1391             3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
1392             4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
1393             5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
1394             6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
1395             7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
1396             8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
1397         'IO'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
1398         'IS'  => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'),
1399         'IT'  => array(1 => '/^[\x{002d}0-9a-zàâäèéêëìîïòôöùûüæœçÿß-]{1,63}$/iu'),
1400         'JP'  => 'Hostname/Jp.php',
1401         'KR'  => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
1402         'LI'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
1403         'LT'  => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'),
1404         'MD'  => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
1405         'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'),
1406         'NET' => 'Hostname/Com.php',
1407         'NO'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
1408         'NU'  => 'Hostname/Com.php',
1409         'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
1410             2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
1411             3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
1412             4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
1413             5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
1414             6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
1415             7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'),
1416         'PE'  => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'),
1417         'PL'  => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
1418             2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
1419             3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
1420             4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
1421             5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
1422             6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
1423             7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
1424             8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
1425             9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
1426             10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
1427             11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
1428             12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
1429             13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
1430             14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
1431             15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
1432             16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
1433             17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
1434             18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
1435             19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
1436             20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
1437             21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
1438             22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
1439             23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
1440             24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
1441             25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
1442             26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
1443             27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
1444             28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
1445             29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
1446             30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
1447             31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
1448             32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
1449             33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
1450         'PR'  => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'),
1451         'PT'  => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'),
1452         'RS'  => array(1 => '/^[\x{002D}\x{0030}-\x{0039}\x{0061}-\x{007A}\x{0107}\x{010D}\x{0111}\x{0161}\x{017E}]{1,63}$/iu)'),
1453         'RU'  => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
1454         'SA'  => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
1455         'SE'  => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'),
1456         'SH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
1457         'SI'  => array(
1458             1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
1459             2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
1460             3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'),
1461         'SJ'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
1462         'TH'  => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
1463         'TM'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
1464         'TW'  => 'Hostname/Cn.php',
1465         'TR'  => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'),
1466         'UA'  => array(1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu'),
1467         'VE'  => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'),
1468         'VN'  => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
1469         'мон' => array(1 => '/^[\x{002d}0-9\x{0430}-\x{044F}]{1,63}$/iu'),
1470         'срб' => array(1 => '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu'),
1471         'сайт' => array(1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'),
1472         'онлайн' => array(1 => '/^[\x{002d}0-9а-яёіїѝйўґг]{1,63}$/iu'),
1473         '中国' => 'Hostname/Cn.php',
1474         '中國' => 'Hostname/Cn.php',
1475         'ලංකා' => array(1 => '/^[\x{0d80}-\x{0dff}]{1,63}$/iu'),
1476         '香港' => 'Hostname/Cn.php',
1477         '台湾' => 'Hostname/Cn.php',
1478         '台灣' => 'Hostname/Cn.php',
1479         'امارات'   => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1480         'الاردن'    => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1481         'السعودية' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1482         'ไทย' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
1483         'рф' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
1484         'تونس' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1485         'مصر' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1486         'இலங்கை' => array(1 => '/^[\x{0b80}-\x{0bff}]{1,63}$/iu'),
1487         'فلسطين' => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1488         'شبكة'  => array(1 => '/^[\x{0621}-\x{0624}\x{0626}-\x{063A}\x{0641}\x{0642}\x{0644}-\x{0648}\x{067E}\x{0686}\x{0698}\x{06A9}\x{06AF}\x{06CC}\x{06F0}-\x{06F9}]{1,30}$/iu'),
1489     );
1490 
1491     protected $_idnLength = array(
1492         'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
1493         'CN'  => array(1 => 20),
1494         'COM' => array(3 => 17, 5 => 20),
1495         'HK'  => array(1 => 15),
1496         'INFO'=> array(4 => 17),
1497         'KR'  => array(1 => 17),
1498         'NET' => array(3 => 17, 5 => 20),
1499         'ORG' => array(6 => 17),
1500         'TW'  => array(1 => 20),
1501         'ایران' => array(1 => 30),
1502         '中国' => array(1 => 20),
1503         '公司' => array(1 => 20),
1504         '网络' => array(1 => 20),
1505     );
1506 
1507     protected $_options = array(
1508         'allow' => self::ALLOW_DNS,
1509         'idn'   => true,
1510         'tld'   => true,
1511         'ip'    => null
1512     );
1513 
1514     /**
1515      * Sets validator options
1516      *
1517      * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm  Technical Specifications for ccTLDs
1518      * @param array $options Validator options
1519      */
1520     public function __construct($options = array())
1521     {
1522         if ($options instanceof Zend_Config) {
1523             $options = $options->toArray();
1524         } else if (!is_array($options)) {
1525             $options = func_get_args();
1526             $temp['allow'] = array_shift($options);
1527             if (!empty($options)) {
1528                 $temp['idn'] = array_shift($options);
1529             }
1530 
1531             if (!empty($options)) {
1532                 $temp['tld'] = array_shift($options);
1533             }
1534 
1535             if (!empty($options)) {
1536                 $temp['ip'] = array_shift($options);
1537             }
1538 
1539             $options = $temp;
1540         }
1541 
1542         $options += $this->_options;
1543         $this->setOptions($options);
1544     }
1545 
1546     /**
1547      * Returns all set options
1548      *
1549      * @return array
1550      */
1551     public function getOptions()
1552     {
1553         return $this->_options;
1554     }
1555 
1556     /**
1557      * Sets the options for this validator
1558      *
1559      * @param array $options
1560      * @return Zend_Validate_Hostname
1561      */
1562     public function setOptions($options)
1563     {
1564         if (array_key_exists('allow', $options)) {
1565             $this->setAllow($options['allow']);
1566         }
1567 
1568         if (array_key_exists('idn', $options)) {
1569             $this->setValidateIdn($options['idn']);
1570         }
1571 
1572         if (array_key_exists('tld', $options)) {
1573             $this->setValidateTld($options['tld']);
1574         }
1575 
1576         if (array_key_exists('ip', $options)) {
1577             $this->setIpValidator($options['ip']);
1578         }
1579 
1580         return $this;
1581     }
1582 
1583     /**
1584      * Returns the set ip validator
1585      *
1586      * @return Zend_Validate_Ip
1587      */
1588     public function getIpValidator()
1589     {
1590         return $this->_options['ip'];
1591     }
1592 
1593     /**
1594      * @param Zend_Validate_Ip $ipValidator OPTIONAL
1595      * @return Zend_Validate_Hostname
1596      */
1597     public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
1598     {
1599         if ($ipValidator === null) {
1600             $ipValidator = new Zend_Validate_Ip();
1601         }
1602 
1603         $this->_options['ip'] = $ipValidator;
1604         return $this;
1605     }
1606 
1607     /**
1608      * Returns the allow option
1609      *
1610      * @return integer
1611      */
1612     public function getAllow()
1613     {
1614         return $this->_options['allow'];
1615     }
1616 
1617     /**
1618      * Sets the allow option
1619      *
1620      * @param  integer $allow
1621      * @return Zend_Validate_Hostname Provides a fluent interface
1622      */
1623     public function setAllow($allow)
1624     {
1625         $this->_options['allow'] = $allow;
1626         return $this;
1627     }
1628 
1629     /**
1630      * Returns the set idn option
1631      *
1632      * @return boolean
1633      */
1634     public function getValidateIdn()
1635     {
1636         return $this->_options['idn'];
1637     }
1638 
1639     /**
1640      * Set whether IDN domains are validated
1641      *
1642      * This only applies when DNS hostnames are validated
1643      *
1644      * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
1645      * @return $this
1646      */
1647     public function setValidateIdn ($allowed)
1648     {
1649         $this->_options['idn'] = (bool) $allowed;
1650         return $this;
1651     }
1652 
1653     /**
1654      * Returns the set tld option
1655      *
1656      * @return boolean
1657      */
1658     public function getValidateTld()
1659     {
1660         return $this->_options['tld'];
1661     }
1662 
1663     /**
1664      * Set whether the TLD element of a hostname is validated
1665      *
1666      * This only applies when DNS hostnames are validated
1667      *
1668      * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
1669      * @return $this
1670      */
1671     public function setValidateTld ($allowed)
1672     {
1673         $this->_options['tld'] = (bool) $allowed;
1674         return $this;
1675     }
1676 
1677     /**
1678      * Defined by Zend_Validate_Interface
1679      *
1680      * Returns true if and only if the $value is a valid hostname with respect to the current allow option
1681      *
1682      * @param  string $value
1683      * @throws Zend_Validate_Exception if a fatal error occurs for validation process
1684      * @return boolean
1685      */
1686     public function isValid($value)
1687     {
1688         if (!is_string($value)) {
1689             $this->_error(self::INVALID);
1690             return false;
1691         }
1692 
1693         $this->_setValue($value);
1694         // Check input against IP address schema
1695         if (preg_match('/^[0-9a-f:.]*$/i', $value) &&
1696             $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
1697             if (!($this->_options['allow'] & self::ALLOW_IP)) {
1698                 $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
1699                 return false;
1700             } else {
1701                 return true;
1702             }
1703         }
1704 
1705         // RFC3986 3.2.2 states:
1706         //
1707         //     The rightmost domain label of a fully qualified domain name
1708         //     in DNS may be followed by a single "." and should be if it is
1709         //     necessary to distinguish between the complete domain name and
1710         //     some local domain.
1711         //
1712         // (see ZF-6363)
1713 
1714         // Local hostnames are allowed to be partitial (ending '.')
1715         if ($this->_options['allow'] & self::ALLOW_LOCAL) {
1716             if (substr($value, -1) === '.') {
1717                 $value = substr($value, 0, -1);
1718                 if (substr($value, -1) === '.') {
1719                     // Empty hostnames (ending '..') are not allowed
1720                     $this->_error(self::INVALID_LOCAL_NAME);
1721                     return false;
1722                 }
1723             }
1724         }
1725 
1726         $domainParts = explode('.', $value);
1727 
1728         // Prevent partitial IP V4 adresses (ending '.')
1729         if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) &&
1730             $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
1731             $this->_error(self::INVALID_LOCAL_NAME);
1732         }
1733 
1734         // Check input against DNS hostname schema
1735         if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) {
1736             $status = false;
1737 
1738             $origenc = PHP_VERSION_ID < 50600
1739                         ? iconv_get_encoding('internal_encoding')
1740                         : ini_get('default_charset');
1741             if (PHP_VERSION_ID < 50600) {
1742                 iconv_set_encoding('internal_encoding', 'UTF-8');
1743             } else {
1744                 ini_set('default_charset', 'UTF-8');
1745             }
1746             do {
1747                 // First check TLD
1748                 $matches = array();
1749                 if (preg_match('/([^.]{2,63})$/iu', end($domainParts), $matches)
1750                     || (array_key_exists(end($domainParts), $this->_validIdns))) {
1751                     reset($domainParts);
1752 
1753                     // Hostname characters are: *(label dot)(label dot label); max 254 chars
1754                     // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
1755                     // id-prefix: alpha / digit
1756                     // ldh: alpha / digit / dash
1757 
1758                     // Match TLD against known list
1759                     $this->_tld = $matches[1];
1760                     if ($this->_options['tld']) {
1761                         if (!in_array(strtolower($this->_tld), $this->_validTlds)
1762                             && !in_array($this->_tld, $this->_validTlds)) {
1763                             $this->_error(self::UNKNOWN_TLD);
1764                             $status = false;
1765                             break;
1766                         }
1767                         // We have already validated that the TLD is fine. We don't want it to go through the below
1768                         // checks as new UTF-8 TLDs will incorrectly fail if there is no IDN regex for it.
1769                         array_pop($domainParts);
1770                     }
1771 
1772                     /**
1773                      * Match against IDN hostnames
1774                      * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
1775                      * @see Zend_Validate_Hostname_Interface
1776                      */
1777                     $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
1778                     if ($this->_options['idn'] &&  isset($this->_validIdns[strtoupper($this->_tld)])) {
1779                         if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
1780                             $regexChars += include($this->_validIdns[strtoupper($this->_tld)]);
1781                         } else {
1782                             $regexChars += $this->_validIdns[strtoupper($this->_tld)];
1783                         }
1784                     }
1785 
1786                     // Check each hostname part
1787                     $check = 0;
1788                     foreach ($domainParts as $domainPart) {
1789                         // If some domain part is empty (i.e. zend..com), it's invalid
1790                         if (empty($domainPart) && $domainPart !== '0') {
1791                             $this->_error(self::INVALID_HOSTNAME);
1792                             return false;
1793                         }
1794 
1795                         // Decode Punycode domainnames to IDN
1796                         if (strpos($domainPart, 'xn--') === 0) {
1797                             $domainPart = $this->decodePunycode(substr($domainPart, 4));
1798                             if ($domainPart === false) {
1799                                 return false;
1800                             }
1801                         }
1802 
1803                         // Check dash (-) does not start, end or appear in 3rd and 4th positions
1804                         if ((strpos($domainPart, '-') === 0)
1805                             || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
1806                             || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
1807                                 $this->_error(self::INVALID_DASH);
1808                             $status = false;
1809                             break 2;
1810                         }
1811 
1812                         // Check each domain part
1813                         $checked = false;
1814                         foreach($regexChars as $regexKey => $regexChar) {
1815                             $status = preg_match($regexChar, $domainPart);
1816                             if ($status > 0) {
1817                                 $length = 63;
1818                                 if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
1819                                     && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
1820                                     $length = $this->_idnLength[strtoupper($this->_tld)];
1821                                 }
1822 
1823                                 if (iconv_strlen($domainPart, 'UTF-8') > $length) {
1824                                     $this->_error(self::INVALID_HOSTNAME);
1825                                 } else {
1826                                     $checked = true;
1827                                     break;
1828                                 }
1829                             }
1830                         }
1831 
1832                         if ($checked) {
1833                             ++$check;
1834                         }
1835                     }
1836 
1837                     // If one of the labels doesn't match, the hostname is invalid
1838                     if ($check !== count($domainParts)) {
1839                         $this->_error(self::INVALID_HOSTNAME_SCHEMA);
1840                         $status = false;
1841                     }
1842                 } else {
1843                     // Hostname not long enough
1844                     $this->_error(self::UNDECIPHERABLE_TLD);
1845                     $status = false;
1846                 }
1847             } while (false);
1848 
1849             if (PHP_VERSION_ID < 50600) {
1850                 iconv_set_encoding('internal_encoding', $origenc);
1851             } else {
1852                 ini_set('default_charset', $origenc);
1853             }
1854             // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
1855             // passes validation
1856             if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) {
1857                 return true;
1858             }
1859         } else if ($this->_options['allow'] & self::ALLOW_DNS) {
1860             $this->_error(self::INVALID_HOSTNAME);
1861         }
1862 
1863         // Check for URI Syntax (RFC3986)
1864         if ($this->_options['allow'] & self::ALLOW_URI) {
1865             if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
1866                 return true;
1867             } else {
1868                 $this->_error(self::INVALID_URI);
1869             }
1870         }
1871 
1872         // Check input against local network name schema; last chance to pass validation
1873         $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/';
1874         $status = @preg_match($regexLocal, $value);
1875 
1876         // If the input passes as a local network name, and local network names are allowed, then the
1877         // hostname passes validation
1878         $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL;
1879         if ($status && $allowLocal) {
1880             return true;
1881         }
1882 
1883         // If the input does not pass as a local network name, add a message
1884         if (!$status) {
1885             $this->_error(self::INVALID_LOCAL_NAME);
1886         }
1887 
1888         // If local network names are not allowed, add a message
1889         if ($status && !$allowLocal) {
1890             $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
1891         }
1892 
1893         return false;
1894     }
1895 
1896     /**
1897      * Decodes a punycode encoded string to it's original utf8 string
1898      * In case of a decoding failure the original string is returned
1899      *
1900      * @param  string $encoded Punycode encoded string to decode
1901      * @return string
1902      */
1903     protected function decodePunycode($encoded)
1904     {
1905         if (!preg_match('/^[a-z0-9-]+$/i', $encoded)) {
1906             // no punycode encoded string
1907             $this->_error(self::CANNOT_DECODE_PUNYCODE);
1908             return false;
1909         }
1910 
1911         $decoded = array();
1912         $separator = strrpos($encoded, '-');
1913         if ($separator > 0) {
1914             for ($x = 0; $x < $separator; ++$x) {
1915                 // prepare decoding matrix
1916                 $decoded[] = ord($encoded[$x]);
1917             }
1918         }
1919 
1920         $lengthd = count($decoded);
1921         $lengthe = strlen($encoded);
1922 
1923         // decoding
1924         $init  = true;
1925         $base  = 72;
1926         $index = 0;
1927         $char  = 0x80;
1928 
1929         for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
1930             for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
1931                 $hex   = ord($encoded[$indexe++]);
1932                 $digit = ($hex - 48 < 10) ? $hex - 22
1933                        : (($hex - 65 < 26) ? $hex - 65
1934                        : (($hex - 97 < 26) ? $hex - 97
1935                        : 36));
1936 
1937                 $index += $digit * $pos;
1938                 $tag    = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
1939                 if ($digit < $tag) {
1940                     break;
1941                 }
1942 
1943                 $pos = (int) ($pos * (36 - $tag));
1944             }
1945 
1946             $delta   = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
1947             $delta  += intval($delta / ($lengthd + 1));
1948             for ($key = 0; $delta > 910 / 2; $key += 36) {
1949                 $delta = intval($delta / 35);
1950             }
1951 
1952             $base   = intval($key + 36 * $delta / ($delta + 38));
1953             $init   = false;
1954             $char  += (int) ($index / ($lengthd + 1));
1955             $index %= ($lengthd + 1);
1956             if ($lengthd > 0) {
1957                 for ($i = $lengthd; $i > $index; $i--) {
1958                     $decoded[$i] = $decoded[($i - 1)];
1959                 }
1960             }
1961 
1962             $decoded[$index++] = $char;
1963         }
1964 
1965         // convert decoded ucs4 to utf8 string
1966         foreach ($decoded as $key => $value) {
1967             if ($value < 128) {
1968                 $decoded[$key] = chr($value);
1969             } elseif ($value < (1 << 11)) {
1970                 $decoded[$key]  = chr(192 + ($value >> 6));
1971                 $decoded[$key] .= chr(128 + ($value & 63));
1972             } elseif ($value < (1 << 16)) {
1973                 $decoded[$key]  = chr(224 + ($value >> 12));
1974                 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1975                 $decoded[$key] .= chr(128 + ($value & 63));
1976             } elseif ($value < (1 << 21)) {
1977                 $decoded[$key]  = chr(240 + ($value >> 18));
1978                 $decoded[$key] .= chr(128 + (($value >> 12) & 63));
1979                 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1980                 $decoded[$key] .= chr(128 + ($value & 63));
1981             } else {
1982                 $this->_error(self::CANNOT_DECODE_PUNYCODE);
1983                 return false;
1984             }
1985         }
1986 
1987         return implode($decoded);
1988     }
1989 }