source: trunk/www.guidonia.net/wp/wp-content/plugins/webtv/Drivers/Zend/Validate/Hostname.php@ 44

Last change on this file since 44 was 44, checked in by luciano, 14 years ago
File size: 31.2 KB
Line 
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-2008 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 14556 2009-03-31 10:35:42Z thomas $
20 */
21
22/**
23 * @see Zend_Validate_Abstract
24 */
25require_once 'Zend/Validate/Abstract.php';
26
27/**
28 * @see Zend_Loader
29 */
30require_once 'Zend/Loader.php';
31
32/**
33 * @see Zend_Validate_Ip
34 */
35require_once 'Zend/Validate/Ip.php';
36
37/**
38 * Please note there are two standalone test scripts for testing IDN characters due to problems
39 * with file encoding.
40 *
41 * The first is tests/Zend/Validate/HostnameTestStandalone.php which is designed to be run on
42 * the command line.
43 *
44 * The second is tests/Zend/Validate/HostnameTestForm.php which is designed to be run via HTML
45 * to allow users to test entering UTF-8 characters in a form.
46 *
47 * @category Zend
48 * @package Zend_Validate
49 * @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
50 * @license http://framework.zend.com/license/new-bsd New BSD License
51 */
52class Zend_Validate_Hostname extends Zend_Validate_Abstract
53{
54 const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed';
55 const UNKNOWN_TLD = 'hostnameUnknownTld';
56 const INVALID_DASH = 'hostnameDashCharacter';
57 const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
58 const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld';
59 const INVALID_HOSTNAME = 'hostnameInvalidHostname';
60 const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName';
61 const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed';
62 const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode';
63
64 /**
65 * @var array
66 */
67 protected $_messageTemplates = array(
68 self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed",
69 self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
70 self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash (-) in an invalid position",
71 self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
72 self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
73 self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname",
74 self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name",
75 self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed",
76 self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded"
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_ALL = 7;
105
106 /**
107 * Whether IDN domains are validated
108 *
109 * @var boolean
110 */
111 private $_validateIdn = true;
112
113 /**
114 * Whether TLDs are validated against a known list
115 *
116 * @var boolean
117 */
118 private $_validateTld = true;
119
120 /**
121 * Bit field of ALLOW constants; determines which types of hostnames are allowed
122 *
123 * @var integer
124 */
125 protected $_allow;
126
127 /**
128 * Array of valid top-level-domains
129 *
130 * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt List of all TLDs by domain
131 * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
132 * @var array
133 */
134 protected $_validTlds = array(
135 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa',
136 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi',
137 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc',
138 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu',
139 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er',
140 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg',
141 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk',
142 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq',
143 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp',
144 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly',
145 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp',
146 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc',
147 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe',
148 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're',
149 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl',
150 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th',
151 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua',
152 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws',
153 'ye', 'yt', 'yu', 'za', 'zm', 'zw'
154 );
155
156 /**
157 * @var string
158 */
159 protected $_tld;
160
161 /**
162 * Array for valid Idns
163 * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
164 * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
165 * (.AR) Argentinia http://www.nic.ar/faqidn.html
166 * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
167 * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
168 * (.BIZ) International http://www.iana.org/domains/idn-tables/
169 * (.BR) Brazil http://registro.br/faq/faq6.html
170 * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
171 * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
172 * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
173 * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
174 * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
175 * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html
176 * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
177 * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
178 * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
179 * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
180 * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
181 * (.INFO) International http://www.nic.info/info/idn
182 * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
183 * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
184 * (.IS) Iceland http://www.isnic.is/domain/rules.php
185 * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
186 * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
187 * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
188 * (.MD) Moldova http://www.register.md/
189 * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
190 * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
191 * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
192 * (.NU) Niue http://www.worldnames.net/
193 * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
194 * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
195 * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
196 * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
197 * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
198 * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
199 * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
200 * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
201 * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
202 * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
203 * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
204 * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
205 * (.TR) Turkey https://www.nic.tr/index.php
206 * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
207 * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
208 *
209 * @var array
210 */
211 protected $_validIdns = array(
212 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿāăą
213ćĉċčďđēėęěĝġģĥħīįĵķĺČğŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźŌş]{1,63}$/iu'),
214 'AR' => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õÌ]{1,63}$/iu'),
215 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿāăą
216ćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĞĺČğłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźŌ]{1,63}$/iu'),
217 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿœšş]{1,63}$/iu'),
218 'BIZ' => 'Hostname/Biz.php',
219 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúÌ]{1,63}$/iu'),
220 'BV' => array(1 => '/^[\x{002d}0-9a-zàáÀ-éêñ-ÎöÞÌčđńŋšŧş]{1,63}$/iu'),
221 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúÌ]{1,63}$/iu'),
222 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿœ]{1,63}$/iu'),
223 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúÌ]{1,63}$/iu'),
224 'CN' => 'Hostname/Cn.php',
225 'COM' => 'Zend/Validate/Hostname/Com.php',
226 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿăą
227āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺğČłńňņŋŏőōœĞŕřŗśŝšşťţŧŭůűũųūŵŷźşŌ]{1,63}$/iu'),
228 'DK' => array(1 => '/^[\x{002d}0-9a-zÀéöÌ]{1,63}$/iu'),
229 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçÚéíïñòóúÌ·]{1,63}$/iu'),
230 'FI' => array(1 => '/^[\x{002d}0-9a-zÀåö]{1,63}$/iu'),
231 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώጀ-ጕጘ-ጝጠ-ᜅ
232ᜈ-ᜍᜐ-᜗᜙᜛᜝ᜟ-᜜ៀ-៎៶-៌ῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳ῎ῶ-á¿Œ]{1,63}$/iu'),
233 'HK' => 'Zend/Validate/Hostname/Cn.php',
234 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúÌőű]{1,63}$/iu'),
235 'INFO'=> array(1 => '/^[\x{002d}0-9a-zÀåÊéöÞÌ]{1,63}$/iu',
236 2 => '/^[\x{002d}0-9a-záéíóöúÌőű]{1,63}$/iu',
237 3 => '/^[\x{002d}0-9a-záÊéíðóöúÜß]{1,63}$/iu',
238 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
239 5 => '/^[\x{002d}0-9a-zāčēģīķČņōŗšūş]{1,63}$/iu',
240 6 => '/^[\x{002d}0-9a-zą
241čėęįšūųş]{1,63}$/iu',
242 7 => '/^[\x{002d}0-9a-zóą
243ćęłńśźŌ]{1,63}$/iu',
244 8 => '/^[\x{002d}0-9a-záéíñóúÌ]{1,63}$/iu'),
245 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿăą
246āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺğČłńňņŋŏőōœĞŕřŗśŝšşťţŧŭůűũųūŵŷźşŌ]{1,63}$/iu'),
247 'IS' => array(1 => '/^[\x{002d}0-9a-záéÜúíóßÊöð]{1,63}$/iu'),
248 'JP' => 'Zend/Validate/Hostname/Jp.php',
249 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
250 'LI' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿœ]{1,63}$/iu'),
251 'LT' => array(1 => '/^[\x{002d}0-9ą
252čęėįšųūş]{1,63}$/iu'),
253 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
254 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿāăą
255ćċčďđēėęěğġģħīįıķĺČğłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźŌşǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅ
256ỳ]{1,63}$/iu'),
257 'NET' => 'Zend/Validate/Hostname/Com.php',
258 'NO' => array(1 => '/^[\x{002d}0-9a-zàáÀ-éêñ-ÎöÞÌčđńŋšŧş]{1,63}$/iu'),
259 'NU' => 'Zend/Validate/Hostname/Com.php',
260 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúÌ]{1,63}$/iu',
261 2 => '/^[\x{002d}0-9a-zóą
262ćęłńśźŌ]{1,63}$/iu',
263 3 => '/^[\x{002d}0-9a-záÀåÊéëíðóöÞúÌÜß]{1,63}$/iu',
264 4 => '/^[\x{002d}0-9a-záéíóöúÌőű]{1,63}$/iu',
265 5 => '/^[\x{002d}0-9a-zą
266čėęįšūųş]{1,63}$/iu',
267 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
268 7 => '/^[\x{002d}0-9a-zāčēģīķČņōŗšūş]{1,63}$/iu'),
269 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúÌ]{1,63}$/iu'),
270 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķČņōŗšūş]{1,63}$/iu',
271 2 => '/^[\x{002d}а-Ок-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
272 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
273 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
274 5 => '/^[\x{002d}0-9a-zàáâÚéêìíîòóÎùúûċġħŌ]{1,63}$/iu',
275 6 => '/^[\x{002d}0-9a-zàÀåÊéêòóÎöÞÌ]{1,63}$/iu',
276 7 => '/^[\x{002d}0-9a-zóą
277ćęłńśźŌ]{1,63}$/iu',
278 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóÎõúÌ]{1,63}$/iu',
279 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
280 10=> '/^[\x{002d}0-9a-záÀéíóÎúÜčďĺğňŕšťş]{1,63}$/iu',
281 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
282 12=> '/^[\x{002d}0-9а-Ок-шђјљњћџ]{1,63}$/iu',
283 13=> '/^[\x{002d}0-9a-zćčđšş]{1,63}$/iu',
284 14=> '/^[\x{002d}0-9a-zâçöûÌğış]{1,63}$/iu',
285 15=> '/^[\x{002d}0-9a-záéíñóúÌ]{1,63}$/iu',
286 16=> '/^[\x{002d}0-9a-zÀõöÌšş]{1,63}$/iu',
287 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
288 18=> '/^[\x{002d}0-9a-zâÀéëîÎ]{1,63}$/iu',
289 19=> '/^[\x{002d}0-9a-zàáâÀåÊçÚéêëìíîïðñòÎöÞùúûÌÜćčłńřśš]{1,63}$/iu',
290 20=> '/^[\x{002d}0-9a-zÀåÊõöÞÌšş]{1,63}$/iu',
291 21=> '/^[\x{002d}0-9a-zàáçÚéìíòóùú]{1,63}$/iu',
292 22=> '/^[\x{002d}0-9a-zàáéíóöúÌőű]{1,63}$/iu',
293 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
294 24=> '/^[\x{002d}0-9a-zàáâåÊçÚéêëðóÎöÞÌßœ]{1,63}$/iu',
295 25=> '/^[\x{002d}0-9a-záÀéíóöúÌÜčďěňřšťůş]{1,63}$/iu',
296 26=> '/^[\x{002d}0-9a-z·àçÚéíïòóúÌ]{1,63}$/iu',
297 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
298 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
299 29=> '/^[\x{002d}0-9a-zą
300čėęįšūųş]{1,63}$/iu',
301 30=> '/^[\x{002d}0-9a-záÀåÊéëíðóöÞúÌÜß]{1,63}$/iu',
302 31=> '/^[\x{002d}0-9a-zàâÊçÚéêëîïñÎùûÌÿœ]{1,63}$/iu',
303 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
304 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
305 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñÀëïÌöâêîÎûàÚùÊçœãõ]{1,63}$/iu'),
306 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóÎõú]{1,63}$/iu'),
307 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
308 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
309 'SE' => array(1 => '/^[\x{002d}0-9a-zÀåéöÌ]{1,63}$/iu'),
310 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿăą
311āćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺğČłńňņŋŏőōœĞŕřŗśŝšşťţŧŭůűũųūŵŷźşŌ]{1,63}$/iu'),
312 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáÀ-éêñ-ÎöÞÌčđńŋšŧş]{1,63}$/iu'),
313 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
314 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öÞ-ÿāăą
315ćĉċčďđēėęěĝġģĥħīįĵķĺČğŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźŌş]{1,63}$/iu'),
316 'TW' => 'Zend/Validate/Hostname/Cn.php',
317 'TR' => array(1 => '/^[\x{002d}0-9a-zğıÌşöç]{1,63}$/iu'),
318 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúÌñ]{1,63}$/iu'),
319 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãÚéêìíòóÎõùúÜĂăĐđĚĩŚũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
320 'ایران' => 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'),
321 '䞭囜' => 'Zend/Validate/Hostname/Cn.php',
322 'å…
323¬åž' => 'Zend/Validate/Hostname/Cn.php',
324 '眑络' => 'Zend/Validate/Hostname/Cn.php'
325 );
326
327 protected $_idnLength = array(
328 'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
329 'CN' => array(1 => 20),
330 'COM' => array(3 => 17, 5 => 20),
331 'HK' => array(1 => 15),
332 'INFO'=> array(4 => 17),
333 'KR' => array(1 => 17),
334 'NET' => array(3 => 17, 5 => 20),
335 'ORG' => array(6 => 17),
336 'TW' => array(1 => 20),
337 'ایران' => array(1 => 30),
338 '䞭囜' => array(1 => 20),
339 'å…
340¬åž' => array(1 => 20),
341 '眑络' => array(1 => 20),
342 );
343
344 /**
345 * Sets validator options
346 *
347 * @param integer $allow OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
348 * @param boolean $validateIdn OPTIONAL Set whether IDN domains are validated (default true)
349 * @param boolean $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)
350 * @param Zend_Validate_Ip $ipValidator OPTIONAL
351 * @return void
352 * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm Technical Specifications for ccTLDs
353 */
354 public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null)
355 {
356 // Set allow options
357 $this->setAllow($allow);
358
359 // Set validation options
360 $this->_validateIdn = $validateIdn;
361 $this->_validateTld = $validateTld;
362
363 $this->setIpValidator($ipValidator);
364 }
365
366 /**
367 * @param Zend_Validate_Ip $ipValidator OPTIONAL
368 * @return void;
369 */
370 public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
371 {
372 if ($ipValidator === null) {
373 $ipValidator = new Zend_Validate_Ip();
374 }
375 $this->_ipValidator = $ipValidator;
376 }
377
378 /**
379 * Returns the allow option
380 *
381 * @return integer
382 */
383 public function getAllow()
384 {
385 return $this->_allow;
386 }
387
388 /**
389 * Sets the allow option
390 *
391 * @param integer $allow
392 * @return Zend_Validate_Hostname Provides a fluent interface
393 */
394 public function setAllow($allow)
395 {
396 $this->_allow = $allow;
397 return $this;
398 }
399
400 /**
401 * Set whether IDN domains are validated
402 *
403 * This only applies when DNS hostnames are validated
404 *
405 * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
406 */
407 public function setValidateIdn ($allowed)
408 {
409 $this->_validateIdn = (bool) $allowed;
410 }
411
412 /**
413 * Set whether the TLD element of a hostname is validated
414 *
415 * This only applies when DNS hostnames are validated
416 *
417 * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
418 */
419 public function setValidateTld ($allowed)
420 {
421 $this->_validateTld = (bool) $allowed;
422 }
423
424 /**
425 * Defined by Zend_Validate_Interface
426 *
427 * Returns true if and only if the $value is a valid hostname with respect to the current allow option
428 *
429 * @param string $value
430 * @throws Zend_Validate_Exception if a fatal error occurs for validation process
431 * @return boolean
432 */
433 public function isValid($value)
434 {
435 $valueString = (string) $value;
436
437 $this->_setValue($valueString);
438
439 // Check input against IP address schema
440 if ($this->_ipValidator->setTranslator($this->getTranslator())->isValid($valueString)) {
441 if (!($this->_allow & self::ALLOW_IP)) {
442 $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
443 return false;
444 } else{
445 return true;
446 }
447 }
448
449 // Check input against DNS hostname schema
450 $domainParts = explode('.', $valueString);
451 if ((count($domainParts) > 1) && (strlen($valueString) >= 4) && (strlen($valueString) <= 254)) {
452 $status = false;
453
454 do {
455 // First check TLD
456 if (preg_match('/([^.]{2,10})$/i', end($domainParts), $matches) ||
457 (end($domainParts) == 'ایران') || (end($domainParts) == '䞭囜') ||
458 (end($domainParts) == 'å…
459¬åž') || (end($domainParts) == '眑络')) {
460
461 reset($domainParts);
462
463 // Hostname characters are: *(label dot)(label dot label); max 254 chars
464 // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
465 // id-prefix: alpha / digit
466 // ldh: alpha / digit / dash
467
468 // Match TLD against known list
469 $this->_tld = strtolower($matches[1]);
470 if ($this->_validateTld) {
471 if (!in_array($this->_tld, $this->_validTlds)) {
472 $this->_error(self::UNKNOWN_TLD);
473 $status = false;
474 break;
475 }
476 }
477
478 /**
479 * Match against IDN hostnames
480 * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
481 * @see Zend_Validate_Hostname_Interface
482 */
483 $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
484 if ($this->_validateIdn && isset($this->_validIdns[strtoupper($this->_tld)])) {
485 if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
486 $regexChars += include($this->_validIdns[strtoupper($this->_tld)]);
487 } else {
488 $regexChars += $this->_validIdns[strtoupper($this->_tld)];
489 }
490 }
491
492 // Check each hostname part
493 $valid = true;
494 foreach ($domainParts as $domainPart) {
495
496 // Decode Punycode domainnames to IDN
497 if (strpos($domainPart, 'xn--') === 0) {
498 $domainPart = $this->decodePunycode(substr($domainPart, 4));
499 if ($domainPart === false) {
500 return false;
501 }
502 }
503
504 // Check dash (-) does not start, end or appear in 3rd and 4th positions
505 if ((strpos($domainPart, '-') === 0)
506 || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
507 || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
508 $this->_error(self::INVALID_DASH);
509 $status = false;
510 break 2;
511 }
512
513 // Check each domain part
514 $check = false;
515 foreach($regexChars as $regexKey => $regexChar) {
516 $status = @preg_match($regexChar, $domainPart);
517 if ($status === false) {
518 require_once 'Zend/Validate/Exception.php';
519 throw new Zend_Validate_Exception('Internal error: DNS validation failed');
520 } elseif ($status !== 0) {
521 $length = 63;
522 if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
523 && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
524 $length = $this->_idnLength[strtoupper($this->_tld)];
525 }
526
527 if (iconv_strlen($domainPart) > $length) {
528 $this->_error(self::INVALID_HOSTNAME);
529 } else {
530 $check = true;
531 break 2;
532 }
533 }
534 }
535
536 if (!$check) {
537 $valid = false;
538 }
539 }
540
541 // If all labels didn't match, the hostname is invalid
542 if (!$valid) {
543 $this->_error(self::INVALID_HOSTNAME_SCHEMA);
544 $status = false;
545 }
546
547 } else {
548 // Hostname not long enough
549 $this->_error(self::UNDECIPHERABLE_TLD);
550 $status = false;
551 }
552 } while (false);
553
554 // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
555 // passes validation
556 if ($status && ($this->_allow & self::ALLOW_DNS)) {
557 return true;
558 }
559 } else {
560 $this->_error(self::INVALID_HOSTNAME);
561 }
562
563 // Check input against local network name schema; last chance to pass validation
564 $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}){1,254}$/';
565 $status = @preg_match($regexLocal, $valueString);
566 if (false === $status) {
567 /**
568 * Regex error
569 * @see Zend_Validate_Exception
570 */
571 require_once 'Zend/Validate/Exception.php';
572 throw new Zend_Validate_Exception('Internal error: local network name validation failed');
573 }
574
575 // If the input passes as a local network name, and local network names are allowed, then the
576 // hostname passes validation
577 $allowLocal = $this->_allow & self::ALLOW_LOCAL;
578 if ($status && $allowLocal) {
579 return true;
580 }
581
582 // If the input does not pass as a local network name, add a message
583 if (!$status) {
584 $this->_error(self::INVALID_LOCAL_NAME);
585 }
586
587 // If local network names are not allowed, add a message
588 if ($status && !$allowLocal) {
589 $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
590 }
591
592 return false;
593 }
594
595 /**
596 * Decodes a punycode encoded string to it's original utf8 string
597 * In case of a decoding failure the original string is returned
598 *
599 * @param string $encoded Punycode encoded string to decode
600 * @return string
601 */
602 protected function decodePunycode($encoded)
603 {
604 $matches = array();
605 $found = preg_match('/([^a-z0-9\x2d]{1,10})$/i', $encoded);
606 if (empty($encoded) || (count($matches) > 0)) {
607 // no punycode encoded string, return as is
608 $this->_error(self::CANNOT_DECODE_PUNYCODE);
609 return false;
610 }
611
612 $separator = strrpos($encoded, '-');
613 if ($separator > 0) {
614 for ($x = 0; $x < $separator; ++$x) {
615 // prepare decoding matrix
616 $decoded[] = ord($encoded[$x]);
617 }
618 } else {
619 $this->_error(self::CANNOT_DECODE_PUNYCODE);
620 return false;
621 }
622
623 $lengthd = count($decoded);
624 $lengthe = strlen($encoded);
625
626 // decoding
627 $init = true;
628 $base = 72;
629 $index = 0;
630 $char = 0x80;
631
632 for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
633 for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
634 $hex = ord($encoded[$indexe++]);
635 $digit = ($hex - 48 < 10) ? $hex - 22
636 : (($hex - 65 < 26) ? $hex - 65
637 : (($hex - 97 < 26) ? $hex - 97
638 : 36));
639
640 $index += $digit * $pos;
641 $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
642 if ($digit < $tag) {
643 break;
644 }
645
646 $pos = (int) ($pos * (36 - $tag));
647 }
648
649 $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
650 $delta += intval($delta / ($lengthd + 1));
651 for ($key = 0; $delta > 910 / 2; $key += 36) {
652 $delta = intval($delta / 35);
653 }
654
655 $base = intval($key + 36 * $delta / ($delta + 38));
656 $init = false;
657 $char += (int) ($index / ($lengthd + 1));
658 $index %= ($lengthd + 1);
659 if ($lengthd > 0) {
660 for ($i = $lengthd; $i > $index; $i--) {
661 $decoded[$i] = $decoded[($i - 1)];
662 }
663 }
664
665 $decoded[$index++] = $char;
666 }
667
668 // convert decoded ucs4 to utf8 string
669 foreach ($decoded as $key => $value) {
670 if ($value < 128) {
671 $decoded[$key] = chr($value);
672 } elseif ($value < (1 << 11)) {
673 $decoded[$key] = chr(192 + ($value >> 6));
674 $decoded[$key] .= chr(128 + ($value & 63));
675 } elseif ($value < (1 << 16)) {
676 $decoded[$key] = chr(224 + ($value >> 12));
677 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
678 $decoded[$key] .= chr(128 + ($value & 63));
679 } elseif ($value < (1 << 21)) {
680 $decoded[$key] = chr(240 + ($value >> 18));
681 $decoded[$key] .= chr(128 + (($value >> 12) & 63));
682 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
683 $decoded[$key] .= chr(128 + ($value & 63));
684 } else {
685 $this->_error(self::CANNOT_DECODE_PUNYCODE);
686 return false;
687 }
688 }
689
690 return implode($decoded);
691 }
692}
Note: See TracBrowser for help on using the repository browser.