PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 1.3.1
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v1.3.1
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / libs / Zend / Validate / Hostname.php
matomo / app / libs / Zend / Validate Last commit date
File 6 years ago Hostname 6 years ago Abstract.php 6 years ago Alnum.php 6 years ago Alpha.php 6 years ago Between.php 6 years ago Callback.php 6 years ago Ccnum.php 6 years ago CreditCard.php 6 years ago Date.php 6 years ago Digits.php 6 years ago Exception.php 6 years ago Float.php 6 years ago GreaterThan.php 6 years ago Hex.php 6 years ago Hostname.php 6 years ago Iban.php 6 years ago Identical.php 6 years ago InArray.php 6 years ago Int.php 6 years ago Interface.php 6 years ago Ip.php 6 years ago Isbn.php 6 years ago LessThan.php 6 years ago NotEmpty.php 6 years ago PostCode.php 6 years ago Regex.php 6 years ago StringLength.php 6 years ago
Hostname.php
1052 lines
1 <?php
2 /**
3 * Zend Framework
4 *
5 * LICENSE
6 *
7 * This source file is subject to the new BSD license that is bundled
8 * with this package in the file LICENSE.txt.
9 * It is also available through the world-wide-web at this URL:
10 * http://framework.zend.com/license/new-bsd
11 * If you did not receive a copy of the license and are unable to
12 * obtain it through the world-wide-web, please send an email
13 * to license@zend.com so we can send you a copy immediately.
14 *
15 * @category Zend
16 * @package Zend_Validate
17 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
18 * @license http://framework.zend.com/license/new-bsd New BSD License
19 * @version $Id: Hostname.php 24307 2011-07-30 02:13:14Z adamlundrigan $
20 */
21
22 /**
23 * @see Zend_Validate_Abstract
24 */
25 // require_once 'Zend/Validate/Abstract.php';
26
27 /**
28 * @see Zend_Validate_Ip
29 */
30 // require_once 'Zend/Validate/Ip.php';
31
32 /**
33 * Please note there are two standalone test scripts for testing IDN characters due to problems
34 * with file encoding.
35 *
36 * The first is tests/Zend/Validate/HostnameTestStandalone.php which is designed to be run on
37 * the command line.
38 *
39 * The second is tests/Zend/Validate/HostnameTestForm.php which is designed to be run via HTML
40 * to allow users to test entering UTF-8 characters in a form.
41 *
42 * @category Zend
43 * @package Zend_Validate
44 * @copyright Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
45 * @license http://framework.zend.com/license/new-bsd New BSD License
46 */
47 class Zend_Validate_Hostname extends Zend_Validate_Abstract
48 {
49 const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode';
50 const INVALID = 'hostnameInvalid';
51 const INVALID_DASH = 'hostnameDashCharacter';
52 const INVALID_HOSTNAME = 'hostnameInvalidHostname';
53 const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
54 const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName';
55 const INVALID_URI = 'hostnameInvalidUri';
56 const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed';
57 const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed';
58 const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld';
59 const UNKNOWN_TLD = 'hostnameUnknownTld';
60 const VALID_UNICODE_DOMAIN = '/^[\p{L}\p{M}]{1,63}$/iu';
61
62 /**
63 * @var array
64 */
65 protected $_messageTemplates = array(
66 self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded",
67 self::INVALID => "Invalid type given. String expected",
68 self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position",
69 self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname",
70 self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
71 self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name",
72 self::INVALID_URI => "'%value%' does not appear to be a valid URI hostname",
73 self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed",
74 self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed",
75 self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
76 self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
77 );
78
79 /**
80 * @var array
81 */
82 protected $_messageVariables = array(
83 'tld' => '_tld'
84 );
85
86 /**
87 * Allows Internet domain names (e.g., example.com)
88 */
89 const ALLOW_DNS = 1;
90
91 /**
92 * Allows IP addresses
93 */
94 const ALLOW_IP = 2;
95
96 /**
97 * Allows local network names (e.g., localhost, www.localdomain)
98 */
99 const ALLOW_LOCAL = 4;
100
101 /**
102 * Allows all types of hostnames
103 */
104 const ALLOW_URI = 8;
105
106 /**
107 * Allows all types of hostnames
108 */
109 const ALLOW_ALL = 15;
110
111 /**
112 * Array of valid top-level-domains
113 *
114 * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain
115 * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
116 * @var array
117 */
118 protected $_validTlds = array(
119 'aaa', 'aarp', 'abb', 'abbott', 'abogado', 'ac', 'academy', 'accenture', 'accountant', 'accountants',
120 'aco', 'active', 'actor', 'ad', 'ads', 'adult', 'ae', 'aeg', 'aero', 'af', 'afl', 'ag', 'agency', 'ai',
121 'aig', 'airforce', 'airtel', 'al', 'allfinanz', 'alsace', 'am', 'amica', 'amsterdam', 'analytics',
122 'android', 'ao', 'apartments', 'app', 'apple', 'aq', 'aquarelle', 'ar', 'aramco', 'archi', 'army', 'arpa',
123 'arte', 'as', 'asia', 'associates', 'at', 'attorney', 'au', 'auction', 'audi', 'audio', 'author', 'auto',
124 'autos', 'aw', 'ax', 'axa', 'az', 'azure', 'ba', 'baidu', 'band', 'bank', 'bar', 'barcelona', 'barclaycard',
125 'barclays', 'bargains', 'bauhaus', 'bayern', 'bb', 'bbc', 'bbva', 'bcn', 'bd', 'be', 'beats', 'beer',
126 'bentley', 'berlin', 'best', 'bet', 'bf', 'bg', 'bh', 'bharti', 'bi', 'bible', 'bid', 'bike', 'bing',
127 'bingo', 'bio', 'biz', 'bj', 'black', 'blackfriday', 'bloomberg', 'blue', 'bm', 'bms', 'bmw', 'bn', 'bnl',
128 'bnpparibas', 'bo', 'boats', 'boehringer', 'bom', 'bond', 'boo', 'book', 'boots', 'bosch', 'bostik', 'bot',
129 'boutique', 'br', 'bradesco', 'bridgestone', 'broadway', 'broker', 'brother', 'brussels', 'bs', 'bt',
130 'budapest', 'bugatti', 'build', 'builders', 'business', 'buy', 'buzz', 'bv', 'bw', 'by', 'bz', 'bzh', 'ca',
131 'cab', 'cafe', 'cal', 'call', 'camera', 'camp', 'cancerresearch', 'canon', 'capetown', 'capital', 'car',
132 'caravan', 'cards', 'care', 'career', 'careers', 'cars', 'cartier', 'casa', 'cash', 'casino', 'cat',
133 'catering', 'cba', 'cbn', 'cc', 'cd', 'ceb', 'center', 'ceo', 'cern', 'cf', 'cfa', 'cfd', 'cg', 'ch',
134 'chanel', 'channel', 'chat', 'cheap', 'chloe', 'christmas', 'chrome', 'church', 'ci', 'cipriani',
135 'circle', 'cisco', 'citic', 'city', 'cityeats', 'ck', 'cl', 'claims', 'cleaning', 'click', 'clinic',
136 'clinique', 'clothing', 'cloud', 'club', 'clubmed', 'cm', 'cn', 'co', 'coach', 'codes', 'coffee',
137 'college', 'cologne', 'com', 'commbank', 'community', 'company', 'computer', 'comsec', 'condos',
138 'construction', 'consulting', 'contact', 'contractors', 'cooking', 'cool', 'coop', 'corsica', 'country',
139 'coupons', 'courses', 'cr', 'credit', 'creditcard', 'creditunion', 'cricket', 'crown', 'crs', 'cruises',
140 'csc', 'cu', 'cuisinella', 'cv', 'cw', 'cx', 'cy', 'cymru', 'cyou', 'cz', 'dabur', 'dad', 'dance', 'date',
141 'dating', 'datsun', 'day', 'dclk', 'de', 'dealer', 'deals', 'degree', 'delivery', 'dell', 'delta', 'democrat',
142 'dental', 'dentist', 'desi', 'design', 'dev', 'diamonds', 'diet', 'digital', 'direct', 'directory',
143 'discount', 'dj', 'dk', 'dm', 'dnp', 'do', 'docs', 'dog', 'doha', 'domains', 'doosan', 'download', 'drive',
144 'dubai', 'durban', 'dvag', 'dz', 'earth', 'eat', 'ec', 'edu', 'education', 'ee', 'eg', 'email', 'emerck',
145 'energy', 'engineer', 'engineering', 'enterprises', 'epson', 'equipment', 'er', 'erni', 'es', 'esq',
146 'estate', 'et', 'eu', 'eurovision', 'eus', 'events', 'everbank', 'exchange', 'expert', 'exposed', 'express',
147 'fage', 'fail', 'fairwinds', 'faith', 'family', 'fan', 'fans', 'farm', 'fashion', 'fast', 'feedback',
148 'ferrero', 'fi', 'film', 'final', 'finance', 'financial', 'firestone', 'firmdale', 'fish', 'fishing',
149 'fit', 'fitness', 'fj', 'fk', 'flights', 'florist', 'flowers', 'flsmidth', 'fly', 'fm', 'fo', 'foo',
150 'football', 'ford', 'forex', 'forsale', 'forum', 'foundation', 'fox', 'fr', 'frl', 'frogans', 'fund',
151 'furniture', 'futbol', 'fyi', 'ga', 'gal', 'gallery', 'game', 'garden', 'gb', 'gbiz', 'gd', 'gdn', 'ge',
152 'gea', 'gent', 'genting', 'gf', 'gg', 'ggee', 'gh', 'gi', 'gift', 'gifts', 'gives', 'giving', 'gl', 'glass',
153 'gle', 'global', 'globo', 'gm', 'gmail', 'gmo', 'gmx', 'gn', 'gold', 'goldpoint', 'golf', 'goo', 'goog',
154 'google', 'gop', 'got', 'gov', 'gp', 'gq', 'gr', 'grainger', 'graphics', 'gratis', 'green', 'gripe', 'group',
155 'gs', 'gt', 'gu', 'gucci', 'guge', 'guide', 'guitars', 'guru', 'gw', 'gy', 'hamburg', 'hangout', 'haus',
156 'healthcare', 'help', 'here', 'hermes', 'hiphop', 'hitachi', 'hiv', 'hk', 'hm', 'hn', 'hockey', 'holdings',
157 'holiday', 'homedepot', 'homes', 'honda', 'horse', 'host', 'hosting', 'hoteles', 'hotmail', 'house', 'how',
158 'hr', 'hsbc', 'ht', 'hu', 'hyundai', 'ibm', 'icbc', 'ice', 'icu', 'id', 'ie', 'ifm', 'iinet', 'il', 'im',
159 'immo', 'immobilien', 'in', 'industries', 'infiniti', 'info', 'ing', 'ink', 'institute', 'insurance', 'insure',
160 'int', 'international', 'investments', 'io', 'ipiranga', 'iq', 'ir', 'irish', 'is', 'ist', 'istanbul', 'it',
161 'itau', 'iwc', 'jaguar', 'java', 'jcb', 'je', 'jetzt', 'jewelry', 'jlc', 'jll', 'jm', 'jmp', 'jo', 'jobs',
162 'joburg', 'jot', 'joy', 'jp', 'jprs', 'juegos', 'kaufen', 'kddi', 'ke', 'kfh', 'kg', 'kh', 'ki', 'kia', 'kim',
163 'kinder', 'kitchen', 'kiwi', 'km', 'kn', 'koeln', 'komatsu', 'kp', 'kpn', 'kr', 'krd', 'kred', 'kw', 'ky',
164 'kyoto', 'kz', 'la', 'lacaixa', 'lamborghini', 'lamer', 'lancaster', 'land', 'landrover', 'lasalle', 'lat',
165 'latrobe', 'law', 'lawyer', 'lb', 'lc', 'lds', 'lease', 'leclerc', 'legal', 'lexus', 'lgbt', 'li', 'liaison',
166 'lidl', 'life', 'lifestyle', 'lighting', 'like', 'limited', 'limo', 'lincoln', 'linde', 'link', 'live',
167 'living', 'lixil', 'lk', 'loan', 'loans', 'lol', 'london', 'lotte', 'lotto', 'love', 'lr', 'ls', 'lt', 'ltd',
168 'ltda', 'lu', 'lupin', 'luxe', 'luxury', 'lv', 'ly', 'ma', 'madrid', 'maif', 'maison', 'man', 'management',
169 'mango', 'market', 'marketing', 'markets', 'marriott', 'mba', 'mc', 'md', 'me', 'med', 'media', 'meet',
170 'melbourne', 'meme', 'memorial', 'men', 'menu', 'meo', 'mg', 'mh', 'miami', 'microsoft', 'mil', 'mini', 'mk',
171 'ml', 'mm', 'mma', 'mn', 'mo', 'mobi', 'mobily', 'moda', 'moe', 'moi', 'mom', 'monash', 'money', 'montblanc',
172 'mormon', 'mortgage', 'moscow', 'motorcycles', 'mov', 'movie', 'movistar', 'mp', 'mq', 'mr', 'ms', 'mt',
173 'mtn', 'mtpc', 'mtr', 'mu', 'museum', 'mutuelle', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'nadex', 'nagoya',
174 'name', 'navy', 'nc', 'ne', 'nec', 'net', 'netbank', 'network', 'neustar', 'new', 'news', 'nexus', 'nf',
175 'ng', 'ngo', 'nhk', 'ni', 'nico', 'ninja', 'nissan', 'nl', 'no', 'nokia', 'norton', 'nowruz', 'np', 'nr',
176 'nra', 'nrw', 'ntt', 'nu', 'nyc', 'nz', 'obi', 'office', 'okinawa', 'om', 'omega', 'one', 'ong', 'onl',
177 'online', 'ooo', 'oracle', 'orange', 'org', 'organic', 'origins', 'osaka', 'otsuka', 'ovh', 'pa', 'page',
178 'panerai', 'paris', 'pars', 'partners', 'parts', 'party', 'pe', 'pet', 'pf', 'pg', 'ph', 'pharmacy',
179 'philips', 'photo', 'photography', 'photos', 'physio', 'piaget', 'pics', 'pictet', 'pictures', 'pid', 'pin',
180 'ping', 'pink', 'pizza', 'pk', 'pl', 'place', 'play', 'playstation', 'plumbing', 'plus', 'pm', 'pn', 'pohl',
181 'poker', 'porn', 'post', 'pr', 'praxi', 'press', 'pro', 'prod', 'productions', 'prof', 'promo', 'properties',
182 'property', 'protection', 'ps', 'pt', 'pub', 'pw', 'py', 'qa', 'qpon', 'quebec', 'racing', 're', 'read',
183 'realtor', 'realty', 'recipes', 'red', 'redstone', 'redumbrella', 'rehab', 'reise', 'reisen', 'reit', 'ren',
184 'rent', 'rentals', 'repair', 'report', 'republican', 'rest', 'restaurant', 'review', 'reviews', 'rexroth',
185 'rich', 'ricoh', 'rio', 'rip', 'ro', 'rocher', 'rocks', 'rodeo', 'room', 'rs', 'rsvp', 'ru', 'ruhr', 'run',
186 'rw', 'rwe', 'ryukyu', 'sa', 'saarland', 'safe', 'safety', 'sakura', 'sale', 'salon', 'samsung', 'sandvik',
187 'sandvikcoromant', 'sanofi', 'sap', 'sapo', 'sarl', 'sas', 'saxo', 'sb', 'sbs', 'sc', 'sca', 'scb',
188 'schaeffler', 'schmidt', 'scholarships', 'school', 'schule', 'schwarz', 'science', 'scor', 'scot', 'sd',
189 'se', 'seat', 'security', 'seek', 'sener', 'services', 'seven', 'sew', 'sex', 'sexy', 'sfr', 'sg', 'sh',
190 'sharp', 'shell', 'shia', 'shiksha', 'shoes', 'show', 'shriram', 'si', 'singles', 'site', 'sj', 'sk', 'ski',
191 'sky', 'skype', 'sl', 'sm', 'smile', 'sn', 'sncf', 'so', 'soccer', 'social', 'software', 'sohu', 'solar',
192 'solutions', 'sony', 'soy', 'space', 'spiegel', 'spreadbetting', 'sr', 'srl', 'st', 'stada', 'star', 'starhub',
193 'statefarm', 'statoil', 'stc', 'stcgroup', 'stockholm', 'storage', 'studio', 'study', 'style', 'su', 'sucks',
194 'supplies', 'supply', 'support', 'surf', 'surgery', 'suzuki', 'sv', 'swatch', 'swiss', 'sx', 'sy', 'sydney',
195 'symantec', 'systems', 'sz', 'tab', 'taipei', 'tatamotors', 'tatar', 'tattoo', 'tax', 'taxi', 'tc', 'tci',
196 'td', 'team', 'tech', 'technology', 'tel', 'telefonica', 'temasek', 'tennis', 'tf', 'tg', 'th', 'thd',
197 'theater', 'theatre', 'tickets', 'tienda', 'tips', 'tires', 'tirol', 'tj', 'tk', 'tl', 'tm', 'tn', 'to',
198 'today', 'tokyo', 'tools', 'top', 'toray', 'toshiba', 'tours', 'town', 'toyota', 'toys', 'tr', 'trade',
199 'trading', 'training', 'travel', 'travelers', 'travelersinsurance', 'trust', 'trv', 'tt', 'tui', 'tushu',
200 'tv', 'tw', 'tz', 'ua', 'ubs', 'ug', 'uk', 'university', 'uno', 'uol', 'us', 'uy', 'uz', 'va', 'vacations',
201 'vana', 'vc', 've', 'vegas', 'ventures', 'verisign', 'versicherung', 'vet', 'vg', 'vi', 'viajes', 'video',
202 'villas', 'vin', 'vip', 'virgin', 'vision', 'vista', 'vistaprint', 'viva', 'vlaanderen', 'vn', 'vodka', 'vote',
203 'voting', 'voto', 'voyage', 'vu', 'wales', 'walter', 'wang', 'wanggou', 'watch', 'watches', 'webcam', 'weber',
204 'website', 'wed', 'wedding', 'weir', 'wf', 'whoswho', 'wien', 'wiki', 'williamhill', 'win', 'windows', 'wine',
205 'wme', 'work', 'works', 'world', 'ws', 'wtc', 'wtf', 'xbox', 'xerox', 'xin', 'xperia', 'xxx', 'xyz', 'yachts', 'yamaxun', 'yandex', 'ye',
206 'yodobashi', 'yoga', 'yokohama', 'youtube', 'yt', 'za', 'zara', 'zero', 'zip', 'zm', 'zone', 'zuerich', 'zw'
207 );
208
209 /**
210 * @var string
211 */
212 protected $_tld;
213
214 /**
215 * Array for valid Idns
216 * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
217 * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
218 * (.AR) Argentinia http://www.nic.ar/faqidn.html
219 * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
220 * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
221 * (.BIZ) International http://www.iana.org/domains/idn-tables/
222 * (.BR) Brazil http://registro.br/faq/faq6.html
223 * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
224 * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
225 * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
226 * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
227 * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
228 * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html
229 * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
230 * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
231 * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
232 * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
233 * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
234 * (.INFO) International http://www.nic.info/info/idn
235 * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
236 * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
237 * (.IS) Iceland http://www.isnic.is/domain/rules.php
238 * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
239 * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
240 * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
241 * (.MD) Moldova http://www.register.md/
242 * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
243 * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
244 * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
245 * (.NU) Niue http://www.worldnames.net/
246 * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
247 * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
248 * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
249 * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
250 * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
251 * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
252 * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
253 * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
254 * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
255 * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
256 * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
257 * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
258 * (.TR) Turkey https://www.nic.tr/index.php
259 * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
260 * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
261 *
262 * @var array
263 */
264 protected $_validIdns = array(
265 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāă�
266 ćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
267 'AR' => array(1 => '/^[\x{002d}0-9a--ãç-êìíñ-õü]{1,63}$/iu'),
268 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāă�
269 ćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'),
270 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'),
271 'BIZ' => 'Hostname/Biz.php',
272 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'),
273 'BV' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
274 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'),
275 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
276 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
277 'CN' => 'Hostname/Cn.php',
278 'COM' => 'Hostname/Com.php',
279 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿă�
280 āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
281 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöü]{1,63}$/iu'),
282 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'),
283 'EU' => array(1 => '/^[\x{002d}0-9a--öø-ÿ]{1,63}$/iu',
284 2 => '/^[\x{002d}0-9a-zāă�
285 ćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
286 3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu',
287 4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστ�
288 φχψωϊϋόύώ]{1,63}$/iu',
289 5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуф�
290 цчшщъыьэюя]{1,63}$/iu',
291 6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-�
292 -ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'),
293 'FI' => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'),
294 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-�
295 Ὀ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'),
296 'HK' => 'Hostname/Cn.php',
297 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'),
298 'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
299 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
300 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
301 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
302 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
303 6 => '/^[\x{002d}0-9a-z�
304 čėęįšūųž]{1,63}$/iu',
305 7 => '/^[\x{002d}0-9a-zó�
306 ćęłńśźż]{1,63}$/iu',
307 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
308 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿă�
309 āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
310 'IS' => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'),
311 'JP' => 'Hostname/Jp.php',
312 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
313 'LI' => array(1 => '/^[\x{002d}0-9a--öø-ÿœ]{1,63}$/iu'),
314 'LT' => array(1 => '/^[\x{002d}0-9�
315 čęėįšųūž]{1,63}$/iu'),
316 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
317 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāă�
318 ćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃ�
319 ]{1,63}$/iu'),
320 'NET' => 'Hostname/Com.php',
321 'NO' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
322 'NU' => 'Hostname/Com.php',
323 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
324 2 => '/^[\x{002d}0-9a-zó�
325 ćęłńśźż]{1,63}$/iu',
326 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
327 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
328 5 => '/^[\x{002d}0-9a-z�
329 čėęįšūųž]{1,63}$/iu',
330 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
331 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'),
332 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'),
333 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
334 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
335 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
336 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
337 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
338 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
339 7 => '/^[\x{002d}0-9a-zó�
340 ćęłńśźż]{1,63}$/iu',
341 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
342 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
343 10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
344 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
345 12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
346 13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
347 14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
348 15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
349 16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
350 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
351 18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
352 19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
353 20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
354 21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
355 22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
356 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
357 24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
358 25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
359 26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
360 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
361 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
362 29=> '/^[\x{002d}0-9a-z�
363 čėęįšūųž]{1,63}$/iu',
364 30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
365 31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
366 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
367 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
368 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'),
369 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'),
370 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
371 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
372 'SE' => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'),
373 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿă�
374 āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
375 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
376 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
377 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāă�
378 ćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
379 'TW' => 'Hostname/Cn.php',
380 'TR' => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'),
381 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'),
382 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
383 'कॉम' => array(1 => self::VALID_UNICODE_DOMAIN),
384 'セール' => array(1 => self::VALID_UNICODE_DOMAIN),
385 '佛山' => array(1 => self::VALID_UNICODE_DOMAIN),
386 '�
387 �善' => array(1 => self::VALID_UNICODE_DOMAIN),
388 '集团' => array(1 => self::VALID_UNICODE_DOMAIN),
389 '在线' => array(1 => self::VALID_UNICODE_DOMAIN),
390 '한국' => array(1 => self::VALID_UNICODE_DOMAIN),
391 '点看' => array(1 => self::VALID_UNICODE_DOMAIN),
392 'คอม' => array(1 => self::VALID_UNICODE_DOMAIN),
393 'ভারত' => array(1 => self::VALID_UNICODE_DOMAIN),
394 '�
395 �卦' => array(1 => self::VALID_UNICODE_DOMAIN),
396 '�
397 وقع' => array(1 => self::VALID_UNICODE_DOMAIN),
398 '�
399 �益' => array(1 => self::VALID_UNICODE_DOMAIN),
400 '�
401 �司' => array(1 => self::VALID_UNICODE_DOMAIN),
402 '移动' => array(1 => self::VALID_UNICODE_DOMAIN),
403 '我爱你' => array(1 => self::VALID_UNICODE_DOMAIN),
404 'москва' => array(1 => self::VALID_UNICODE_DOMAIN),
405 'қаз' => array(1 => self::VALID_UNICODE_DOMAIN),
406 'онлайн' => array(1 => self::VALID_UNICODE_DOMAIN),
407 'сайт' => array(1 => self::VALID_UNICODE_DOMAIN),
408 '联通' => array(1 => self::VALID_UNICODE_DOMAIN),
409 'срб' => array(1 => self::VALID_UNICODE_DOMAIN),
410 'бел' => array(1 => self::VALID_UNICODE_DOMAIN),
411 'קום' => array(1 => self::VALID_UNICODE_DOMAIN),
412 '时尚' => array(1 => self::VALID_UNICODE_DOMAIN),
413 '淡马锡' => array(1 => self::VALID_UNICODE_DOMAIN),
414 'ファッション' => array(1 => self::VALID_UNICODE_DOMAIN),
415 'орг' => array(1 => self::VALID_UNICODE_DOMAIN),
416 'नेट' => array(1 => self::VALID_UNICODE_DOMAIN),
417 'ストア' => array(1 => self::VALID_UNICODE_DOMAIN),
418 '삼성' => array(1 => self::VALID_UNICODE_DOMAIN),
419 'சிங்கப்பூர்' => array(1 => self::VALID_UNICODE_DOMAIN),
420 '商标' => array(1 => self::VALID_UNICODE_DOMAIN),
421 '商店' => array(1 => self::VALID_UNICODE_DOMAIN),
422 '商城' => array(1 => self::VALID_UNICODE_DOMAIN),
423 'дети' => array(1 => self::VALID_UNICODE_DOMAIN),
424 'мкд' => array(1 => self::VALID_UNICODE_DOMAIN),
425 'ею' => array(1 => self::VALID_UNICODE_DOMAIN),
426 'ポイント' => array(1 => self::VALID_UNICODE_DOMAIN),
427 '新闻' => array(1 => self::VALID_UNICODE_DOMAIN),
428 '工行' => array(1 => self::VALID_UNICODE_DOMAIN),
429 'كو�
430 ' => array(1 => self::VALID_UNICODE_DOMAIN),
431 '中文网' => array(1 => self::VALID_UNICODE_DOMAIN),
432 '中信' => array(1 => self::VALID_UNICODE_DOMAIN),
433 '中国' => array(1 => self::VALID_UNICODE_DOMAIN),
434 '中國' => array(1 => self::VALID_UNICODE_DOMAIN),
435 '娱乐' => array(1 => self::VALID_UNICODE_DOMAIN),
436 '谷歌' => array(1 => self::VALID_UNICODE_DOMAIN),
437 'భారత్' => array(1 => self::VALID_UNICODE_DOMAIN),
438 'ලංකා' => array(1 => self::VALID_UNICODE_DOMAIN),
439 '购物' => array(1 => self::VALID_UNICODE_DOMAIN),
440 'クラウド' => array(1 => self::VALID_UNICODE_DOMAIN),
441 'ભારત' => array(1 => self::VALID_UNICODE_DOMAIN),
442 'भारत' => array(1 => self::VALID_UNICODE_DOMAIN),
443 '网店' => array(1 => self::VALID_UNICODE_DOMAIN),
444 'संगठन' => array(1 => self::VALID_UNICODE_DOMAIN),
445 '餐�
446 ' => array(1 => self::VALID_UNICODE_DOMAIN),
447 '网络' => array(1 => self::VALID_UNICODE_DOMAIN),
448 'ком' => array(1 => self::VALID_UNICODE_DOMAIN),
449 'укр' => array(1 => self::VALID_UNICODE_DOMAIN),
450 '香港' => array(1 => self::VALID_UNICODE_DOMAIN),
451 '诺基亚' => array(1 => self::VALID_UNICODE_DOMAIN),
452 '食品' => array(1 => self::VALID_UNICODE_DOMAIN),
453 '飞利浦' => array(1 => self::VALID_UNICODE_DOMAIN),
454 '台湾' => array(1 => self::VALID_UNICODE_DOMAIN),
455 '台灣' => array(1 => self::VALID_UNICODE_DOMAIN),
456 '手表' => array(1 => self::VALID_UNICODE_DOMAIN),
457 '手机' => array(1 => self::VALID_UNICODE_DOMAIN),
458 'мон' => array(1 => self::VALID_UNICODE_DOMAIN),
459 'الجزائر' => array(1 => self::VALID_UNICODE_DOMAIN),
460 'ع�
461 ان' => array(1 => self::VALID_UNICODE_DOMAIN),
462 'ارا�
463 كو' => array(1 => self::VALID_UNICODE_DOMAIN),
464 'ایران' => array(1 => self::VALID_UNICODE_DOMAIN),
465 'ا�
466 ارات' => array(1 => self::VALID_UNICODE_DOMAIN),
467 'بازار' => array(1 => self::VALID_UNICODE_DOMAIN),
468 'الاردن' => array(1 => self::VALID_UNICODE_DOMAIN),
469 '�
470 وبايلي' => array(1 => self::VALID_UNICODE_DOMAIN),
471 'بھارت' => array(1 => self::VALID_UNICODE_DOMAIN),
472 'ال�
473 غرب' => array(1 => self::VALID_UNICODE_DOMAIN),
474 'السعودية' => array(1 => self::VALID_UNICODE_DOMAIN),
475 'سودان' => array(1 => self::VALID_UNICODE_DOMAIN),
476 'ه�
477 راه' => array(1 => self::VALID_UNICODE_DOMAIN),
478 'عراق' => array(1 => self::VALID_UNICODE_DOMAIN),
479 '�
480 ليسيا' => array(1 => self::VALID_UNICODE_DOMAIN),
481 '澳門' => array(1 => self::VALID_UNICODE_DOMAIN),
482 '닷컴' => array(1 => self::VALID_UNICODE_DOMAIN),
483 '政府' => array(1 => self::VALID_UNICODE_DOMAIN),
484 'شبكة' => array(1 => self::VALID_UNICODE_DOMAIN),
485 'بيتك' => array(1 => self::VALID_UNICODE_DOMAIN),
486 'გე' => array(1 => self::VALID_UNICODE_DOMAIN),
487 '机构' => array(1 => self::VALID_UNICODE_DOMAIN),
488 '组织机构' => array(1 => self::VALID_UNICODE_DOMAIN),
489 '健康' => array(1 => self::VALID_UNICODE_DOMAIN),
490 'ไทย' => array(1 => self::VALID_UNICODE_DOMAIN),
491 'سورية' => array(1 => self::VALID_UNICODE_DOMAIN),
492 'рус' => array(1 => self::VALID_UNICODE_DOMAIN),
493 'рф' => array(1 => self::VALID_UNICODE_DOMAIN),
494 '珠宝' => array(1 => self::VALID_UNICODE_DOMAIN),
495 'تونس' => array(1 => self::VALID_UNICODE_DOMAIN),
496 '大拿' => array(1 => self::VALID_UNICODE_DOMAIN),
497 'みんな' => array(1 => self::VALID_UNICODE_DOMAIN),
498 'グーグル' => array(1 => self::VALID_UNICODE_DOMAIN),
499 'ελ' => array(1 => self::VALID_UNICODE_DOMAIN),
500 '世界' => array(1 => self::VALID_UNICODE_DOMAIN),
501 '書籍' => array(1 => self::VALID_UNICODE_DOMAIN),
502 'ਭਾਰਤ' => array(1 => self::VALID_UNICODE_DOMAIN),
503 '网址' => array(1 => self::VALID_UNICODE_DOMAIN),
504 '닷넷' => array(1 => self::VALID_UNICODE_DOMAIN),
505 'コム' => array(1 => self::VALID_UNICODE_DOMAIN),
506 '游戏' => array(1 => self::VALID_UNICODE_DOMAIN),
507 'VERMöGENSBERATER' => array(1 => self::VALID_UNICODE_DOMAIN),
508 'VERMöGENSBERATUNG' => array(1 => self::VALID_UNICODE_DOMAIN),
509 '企业' => array(1 => self::VALID_UNICODE_DOMAIN),
510 '信息' => array(1 => self::VALID_UNICODE_DOMAIN),
511 '嘉里大�
512 �店' => array(1 => self::VALID_UNICODE_DOMAIN),
513 '�
514 صر' => array(1 => self::VALID_UNICODE_DOMAIN),
515 'قطر' => array(1 => self::VALID_UNICODE_DOMAIN),
516 '广东' => array(1 => self::VALID_UNICODE_DOMAIN),
517 'இலங்கை' => array(1 => self::VALID_UNICODE_DOMAIN),
518 'இந்தியா' => array(1 => self::VALID_UNICODE_DOMAIN),
519 'հայ' => array(1 => self::VALID_UNICODE_DOMAIN),
520 '新加坡' => array(1 => self::VALID_UNICODE_DOMAIN),
521 'فلسطين' => array(1 => self::VALID_UNICODE_DOMAIN),
522 '政务' => array(1 => self::VALID_UNICODE_DOMAIN),
523 '家電' => array(1 => self::VALID_UNICODE_DOMAIN),
524 '微博' => array(1 => self::VALID_UNICODE_DOMAIN),
525 'ابوظبي' => array(1 => self::VALID_UNICODE_DOMAIN),
526 '网站' => array(1 => self::VALID_UNICODE_DOMAIN),
527 '大众汽车' => array(1 => self::VALID_UNICODE_DOMAIN),
528 '香格里拉' => array(1 => self::VALID_UNICODE_DOMAIN),
529 'бг' => array(1 => self::VALID_UNICODE_DOMAIN),
530 '電訊盈科' => array(1 => self::VALID_UNICODE_DOMAIN),
531 'العليان' => array(1 => self::VALID_UNICODE_DOMAIN),
532 '嘉里' => array(1 => self::VALID_UNICODE_DOMAIN),
533 'বাংলা' => array(1 => self::VALID_UNICODE_DOMAIN),
534 'католик' => array(1 => self::VALID_UNICODE_DOMAIN),
535 '通販' => array(1 => self::VALID_UNICODE_DOMAIN),
536 'پاکستان' => array(1 => self::VALID_UNICODE_DOMAIN),
537 'كاثوليك' => array(1 => self::VALID_UNICODE_DOMAIN),
538 '天主教' => array(1 => self::VALID_UNICODE_DOMAIN),
539 'ಭಾರತ' => array(1 => self::VALID_UNICODE_DOMAIN),
540 'ଭାରତ' => array(1 => self::VALID_UNICODE_DOMAIN),
541 'ভাৰত' => array(1 => self::VALID_UNICODE_DOMAIN),
542 'भारतम्' => array(1 => self::VALID_UNICODE_DOMAIN),
543 'भारोत' => array(1 => self::VALID_UNICODE_DOMAIN),
544 'اتصالات' => array(1 => self::VALID_UNICODE_DOMAIN),
545 'بارت' => array(1 => self::VALID_UNICODE_DOMAIN),
546 'ڀارت' => array(1 => self::VALID_UNICODE_DOMAIN),
547 'عرب' => array(1 => self::VALID_UNICODE_DOMAIN),
548 'ഭാരതം' => array(1 => self::VALID_UNICODE_DOMAIN),
549 );
550
551
552 protected $_idnLength = array(
553 'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
554 'CN' => array(1 => 20),
555 'COM' => array(3 => 17, 5 => 20),
556 'HK' => array(1 => 15),
557 'INFO'=> array(4 => 17),
558 'KR' => array(1 => 17),
559 'NET' => array(3 => 17, 5 => 20),
560 'ORG' => array(6 => 17),
561 'TW' => array(1 => 20),
562 'ایران' => array(1 => 30),
563 '中国' => array(1 => 20),
564 '�
565 �司' => array(1 => 20),
566 '网络' => array(1 => 20),
567 );
568
569 protected $_options = array(
570 'allow' => self::ALLOW_DNS,
571 'idn' => true,
572 'tld' => true,
573 'ip' => null
574 );
575
576 /**
577 * Sets validator options
578 *
579 * @param integer $allow OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
580 * @param boolean $validateIdn OPTIONAL Set whether IDN domains are validated (default true)
581 * @param boolean $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)
582 * @param Zend_Validate_Ip $ipValidator OPTIONAL
583 * @return void
584 * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs
585 */
586 public function __construct($options = array())
587 {
588 if ($options instanceof Zend_Config) {
589 $options = $options->toArray();
590 } else if (!is_array($options)) {
591 $options = func_get_args();
592 $temp['allow'] = array_shift($options);
593 if (!empty($options)) {
594 $temp['idn'] = array_shift($options);
595 }
596
597 if (!empty($options)) {
598 $temp['tld'] = array_shift($options);
599 }
600
601 if (!empty($options)) {
602 $temp['ip'] = array_shift($options);
603 }
604
605 $options = $temp;
606 }
607
608 $options += $this->_options;
609 $this->setOptions($options);
610 }
611
612 /**
613 * Returns all set options
614 *
615 * @return array
616 */
617 public function getOptions()
618 {
619 return $this->_options;
620 }
621
622 /**
623 * Sets the options for this validator
624 *
625 * @param array $options
626 * @return Zend_Validate_Hostname
627 */
628 public function setOptions($options)
629 {
630 if (array_key_exists('allow', $options)) {
631 $this->setAllow($options['allow']);
632 }
633
634 if (array_key_exists('idn', $options)) {
635 $this->setValidateIdn($options['idn']);
636 }
637
638 if (array_key_exists('tld', $options)) {
639 $this->setValidateTld($options['tld']);
640 }
641
642 if (array_key_exists('ip', $options)) {
643 $this->setIpValidator($options['ip']);
644 }
645
646 return $this;
647 }
648
649 /**
650 * Returns the set ip validator
651 *
652 * @return Zend_Validate_Ip
653 */
654 public function getIpValidator()
655 {
656 return $this->_options['ip'];
657 }
658
659 /**
660 * @param Zend_Validate_Ip $ipValidator OPTIONAL
661 * @return void;
662 */
663 public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
664 {
665 if ($ipValidator === null) {
666 $ipValidator = new Zend_Validate_Ip();
667 }
668
669 $this->_options['ip'] = $ipValidator;
670 return $this;
671 }
672
673 /**
674 * Returns the allow option
675 *
676 * @return integer
677 */
678 public function getAllow()
679 {
680 return $this->_options['allow'];
681 }
682
683 /**
684 * Sets the allow option
685 *
686 * @param integer $allow
687 * @return Zend_Validate_Hostname Provides a fluent interface
688 */
689 public function setAllow($allow)
690 {
691 $this->_options['allow'] = $allow;
692 return $this;
693 }
694
695 /**
696 * Returns the set idn option
697 *
698 * @return boolean
699 */
700 public function getValidateIdn()
701 {
702 return $this->_options['idn'];
703 }
704
705 /**
706 * Set whether IDN domains are validated
707 *
708 * This only applies when DNS hostnames are validated
709 *
710 * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
711 */
712 public function setValidateIdn ($allowed)
713 {
714 $this->_options['idn'] = (bool) $allowed;
715 return $this;
716 }
717
718 /**
719 * Returns the set tld option
720 *
721 * @return boolean
722 */
723 public function getValidateTld()
724 {
725 return $this->_options['tld'];
726 }
727
728 /**
729 * Set whether the TLD element of a hostname is validated
730 *
731 * This only applies when DNS hostnames are validated
732 *
733 * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
734 */
735 public function setValidateTld ($allowed)
736 {
737 $this->_options['tld'] = (bool) $allowed;
738 return $this;
739 }
740
741 /**
742 * Defined by Zend_Validate_Interface
743 *
744 * Returns true if and only if the $value is a valid hostname with respect to the current allow option
745 *
746 * @param string $value
747 * @throws Zend_Validate_Exception if a fatal error occurs for validation process
748 * @return boolean
749 */
750 public function isValid($value)
751 {
752 if (!is_string($value)) {
753 $this->_error(self::INVALID);
754 return false;
755 }
756
757 $this->_setValue($value);
758 // Check input against IP address schema
759 if (preg_match('/^[0-9a-f:.]*$/i', $value) &&
760 $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
761 if (!($this->_options['allow'] & self::ALLOW_IP)) {
762 $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
763 return false;
764 } else {
765 return true;
766 }
767 }
768
769 // RFC3986 3.2.2 states:
770 //
771 // The rightmost domain label of a fully qualified domain name
772 // in DNS may be followed by a single "." and should be if it is
773 // necessary to distinguish between the complete domain name and
774 // some local domain.
775 //
776 // (see ZF-6363)
777
778 // Local hostnames are allowed to be partitial (ending '.')
779 if ($this->_options['allow'] & self::ALLOW_LOCAL) {
780 if (substr($value, -1) === '.') {
781 $value = substr($value, 0, -1);
782 if (substr($value, -1) === '.') {
783 // Empty hostnames (ending '..') are not allowed
784 $this->_error(self::INVALID_LOCAL_NAME);
785 return false;
786 }
787 }
788 }
789
790 $domainParts = explode('.', $value);
791
792 // Prevent partitial IP V4 adresses (ending '.')
793 if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) &&
794 $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
795 $this->_error(self::INVALID_LOCAL_NAME);
796 }
797
798 // Check input against DNS hostname schema
799 if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) {
800 $status = false;
801
802 $origenc = PHP_VERSION_ID < 50600
803 ? iconv_get_encoding('internal_encoding')
804 : ini_get('default_charset');
805 if (PHP_VERSION_ID < 50600) {
806 iconv_set_encoding('internal_encoding', 'UTF-8');
807 } else {
808 @ini_set('default_charset', 'UTF-8');
809 }
810
811 do {
812 // First check TLD
813 $matches = array();
814 if (preg_match('/([^.]{2,63})$/i', end($domainParts), $matches) ||
815 (end($domainParts) == 'ایران') || (end($domainParts) == '中国') ||
816 (end($domainParts) == '�
817 �司') || (end($domainParts) == '网络')) {
818
819 reset($domainParts);
820
821 // Hostname characters are: *(label dot)(label dot label); max 254 chars
822 // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
823 // id-prefix: alpha / digit
824 // ldh: alpha / digit / dash
825
826 // Match TLD against known list
827 $this->_tld = strtolower($matches[1]);
828 if ($this->_options['tld']) {
829 if (!in_array($this->_tld, $this->_validTlds)) {
830 $this->_error(self::UNKNOWN_TLD);
831 $status = false;
832 break;
833 }
834 }
835
836 /**
837 * Match against IDN hostnames
838 * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
839 * @see Zend_Validate_Hostname_Interface
840 */
841 $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
842 if ($this->_options['idn'] && isset($this->_validIdns[strtoupper($this->_tld)])) {
843 if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
844 $regexChars += include(dirname(__FILE__) . DIRECTORY_SEPARATOR . $this->_validIdns[strtoupper($this->_tld)]);
845 } else {
846 $regexChars += $this->_validIdns[strtoupper($this->_tld)];
847 }
848 }
849
850 // Check each hostname part
851 $check = 0;
852 foreach ($domainParts as $domainPart) {
853 // Decode Punycode domainnames to IDN
854 if (strpos($domainPart, 'xn--') === 0) {
855 $domainPart = $this->decodePunycode(substr($domainPart, 4));
856 if ($domainPart === false) {
857 return false;
858 }
859 }
860
861 // Check dash (-) does not start, end or appear in 3rd and 4th positions
862 if ((strpos($domainPart, '-') === 0)
863 || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
864 || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
865 $this->_error(self::INVALID_DASH);
866 $status = false;
867 break 2;
868 }
869
870 // Check each domain part
871 $checked = false;
872 foreach($regexChars as $regexKey => $regexChar) {
873 $status = @preg_match($regexChar, $domainPart);
874 if ($status > 0) {
875 $length = 63;
876 if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
877 && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
878 $length = $this->_idnLength[strtoupper($this->_tld)];
879 }
880
881 if (iconv_strlen($domainPart, 'UTF-8') > $length) {
882 $this->_error(self::INVALID_HOSTNAME);
883 } else {
884 $checked = true;
885 break;
886 }
887 }
888 }
889
890 if ($checked) {
891 ++$check;
892 }
893 }
894
895 // If one of the labels doesn't match, the hostname is invalid
896 if ($check !== count($domainParts)) {
897 $this->_error(self::INVALID_HOSTNAME_SCHEMA);
898 $status = false;
899 }
900 } else {
901 // Hostname not long enough
902 $this->_error(self::UNDECIPHERABLE_TLD);
903 $status = false;
904 }
905 } while (false);
906
907 if (PHP_VERSION_ID < 50600) {
908 iconv_set_encoding('internal_encoding', $origenc);
909 } else {
910 @ini_set('default_charset', $origenc);
911 }
912
913 // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
914 // passes validation
915 if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) {
916 return true;
917 }
918 } else if ($this->_options['allow'] & self::ALLOW_DNS) {
919 $this->_error(self::INVALID_HOSTNAME);
920 }
921
922 // Check for URI Syntax (RFC3986)
923 if ($this->_options['allow'] & self::ALLOW_URI) {
924 if (preg_match("/^([a-zA-Z0-9-._~!$&'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
925 return true;
926 } else {
927 $this->_error(self::INVALID_URI);
928 }
929 }
930
931 // Check input against local network name schema; last chance to pass validation
932 $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/';
933 $status = @preg_match($regexLocal, $value);
934
935 // If the input passes as a local network name, and local network names are allowed, then the
936 // hostname passes validation
937 $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL;
938 if ($status && $allowLocal) {
939 return true;
940 }
941
942 // If the input does not pass as a local network name, add a message
943 if (!$status) {
944 $this->_error(self::INVALID_LOCAL_NAME);
945 }
946
947 // If local network names are not allowed, add a message
948 if ($status && !$allowLocal) {
949 $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
950 }
951
952 return false;
953 }
954
955 /**
956 * Decodes a punycode encoded string to it's original utf8 string
957 * In case of a decoding failure the original string is returned
958 *
959 * @param string $encoded Punycode encoded string to decode
960 * @return string
961 */
962 protected function decodePunycode($encoded)
963 {
964 $found = preg_match('/([^a-z0-9\x2d]{1,10})$/i', $encoded);
965 if (empty($encoded) || ($found > 0)) {
966 // no punycode encoded string, return as is
967 $this->_error(self::CANNOT_DECODE_PUNYCODE);
968 return false;
969 }
970
971 $separator = strrpos($encoded, '-');
972 if ($separator > 0) {
973 for ($x = 0; $x < $separator; ++$x) {
974 // prepare decoding matrix
975 $decoded[] = ord($encoded[$x]);
976 }
977 } else {
978 $this->_error(self::CANNOT_DECODE_PUNYCODE);
979 return false;
980 }
981
982 $lengthd = count($decoded);
983 $lengthe = strlen($encoded);
984
985 // decoding
986 $init = true;
987 $base = 72;
988 $index = 0;
989 $char = 0x80;
990
991 for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
992 for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
993 $hex = ord($encoded[$indexe++]);
994 $digit = ($hex - 48 < 10) ? $hex - 22
995 : (($hex - 65 < 26) ? $hex - 65
996 : (($hex - 97 < 26) ? $hex - 97
997 : 36));
998
999 $index += $digit * $pos;
1000 $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
1001 if ($digit < $tag) {
1002 break;
1003 }
1004
1005 $pos = (int) ($pos * (36 - $tag));
1006 }
1007
1008 $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
1009 $delta += intval($delta / ($lengthd + 1));
1010 for ($key = 0; $delta > 910 / 2; $key += 36) {
1011 $delta = intval($delta / 35);
1012 }
1013
1014 $base = intval($key + 36 * $delta / ($delta + 38));
1015 $init = false;
1016 $char += (int) ($index / ($lengthd + 1));
1017 $index %= ($lengthd + 1);
1018 if ($lengthd > 0) {
1019 for ($i = $lengthd; $i > $index; $i--) {
1020 $decoded[$i] = $decoded[($i - 1)];
1021 }
1022 }
1023
1024 $decoded[$index++] = $char;
1025 }
1026
1027 // convert decoded ucs4 to utf8 string
1028 foreach ($decoded as $key => $value) {
1029 if ($value < 128) {
1030 $decoded[$key] = chr($value);
1031 } elseif ($value < (1 << 11)) {
1032 $decoded[$key] = chr(192 + ($value >> 6));
1033 $decoded[$key] .= chr(128 + ($value & 63));
1034 } elseif ($value < (1 << 16)) {
1035 $decoded[$key] = chr(224 + ($value >> 12));
1036 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1037 $decoded[$key] .= chr(128 + ($value & 63));
1038 } elseif ($value < (1 << 21)) {
1039 $decoded[$key] = chr(240 + ($value >> 18));
1040 $decoded[$key] .= chr(128 + (($value >> 12) & 63));
1041 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1042 $decoded[$key] .= chr(128 + ($value & 63));
1043 } else {
1044 $this->_error(self::CANNOT_DECODE_PUNYCODE);
1045 return false;
1046 }
1047 }
1048
1049 return implode($decoded);
1050 }
1051 }
1052