00001 <?php
00025 require_once 'Zend/Validate/Abstract.php';
00026
00030 require_once 'Zend/Validate/Ip.php';
00031
00047 class Zend_Validate_Hostname extends Zend_Validate_Abstract
00048 {
00049 const INVALID = 'hostnameInvalid';
00050 const IP_ADDRESS_NOT_ALLOWED = 'hostnameIpAddressNotAllowed';
00051 const UNKNOWN_TLD = 'hostnameUnknownTld';
00052 const INVALID_DASH = 'hostnameDashCharacter';
00053 const INVALID_HOSTNAME_SCHEMA = 'hostnameInvalidHostnameSchema';
00054 const UNDECIPHERABLE_TLD = 'hostnameUndecipherableTld';
00055 const INVALID_HOSTNAME = 'hostnameInvalidHostname';
00056 const INVALID_LOCAL_NAME = 'hostnameInvalidLocalName';
00057 const LOCAL_NAME_NOT_ALLOWED = 'hostnameLocalNameNotAllowed';
00058 const CANNOT_DECODE_PUNYCODE = 'hostnameCannotDecodePunycode';
00059
00063 protected $_messageTemplates = array(
00064 self::INVALID => "Invalid type given, value should be a string",
00065 self::IP_ADDRESS_NOT_ALLOWED => "'%value%' appears to be an IP address, but IP addresses are not allowed",
00066 self::UNKNOWN_TLD => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
00067 self::INVALID_DASH => "'%value%' appears to be a DNS hostname but contains a dash (-) in an invalid position",
00068 self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
00069 self::UNDECIPHERABLE_TLD => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
00070 self::INVALID_HOSTNAME => "'%value%' does not match the expected structure for a DNS hostname",
00071 self::INVALID_LOCAL_NAME => "'%value%' does not appear to be a valid local network name",
00072 self::LOCAL_NAME_NOT_ALLOWED => "'%value%' appears to be a local network name but local network names are not allowed",
00073 self::CANNOT_DECODE_PUNYCODE => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded"
00074 );
00075
00079 protected $_messageVariables = array(
00080 'tld' => '_tld'
00081 );
00082
00086 const ALLOW_DNS = 1;
00087
00091 const ALLOW_IP = 2;
00092
00096 const ALLOW_LOCAL = 4;
00097
00101 const ALLOW_ALL = 7;
00102
00108 private $_validateIdn = true;
00109
00115 private $_validateTld = true;
00116
00122 protected $_allow;
00123
00131 protected $_validTlds = array(
00132 'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa',
00133 'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi',
00134 'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc',
00135 'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu',
00136 'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er',
00137 'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg',
00138 'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk',
00139 'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq',
00140 'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp',
00141 'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly',
00142 'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp',
00143 'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc',
00144 'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe',
00145 'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're',
00146 'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl',
00147 'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th',
00148 'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua',
00149 'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws',
00150 'ye', 'yt', 'yu', 'za', 'zm', 'zw'
00151 );
00152
00156 protected $_tld;
00157
00208 protected $_validIdns = array(
00209 'AC' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
00210 'AR' => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'),
00211 'AS' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'),
00212 'AT' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'),
00213 'BIZ' => 'Hostname/Biz.php',
00214 'BR' => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'),
00215 'BV' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
00216 'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'),
00217 'CH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
00218 'CL' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
00219 'CN' => 'Hostname/Cn.php',
00220 'COM' => 'Zend/Validate/Hostname/Com.php',
00221 'DE' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
00222 'DK' => array(1 => '/^[\x{002d}0-9a-zäéöü]{1,63}$/iu'),
00223 'ES' => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'),
00224 'FI' => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'),
00225 'GR' => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'),
00226 'HK' => 'Zend/Validate/Hostname/Cn.php',
00227 'HU' => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'),
00228 'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
00229 2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
00230 3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
00231 4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
00232 5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
00233 6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
00234 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
00235 8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
00236 'IO' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
00237 'IS' => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'),
00238 'JP' => 'Zend/Validate/Hostname/Jp.php',
00239 'KR' => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
00240 'LI' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
00241 'LT' => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'),
00242 'MD' => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
00243 'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'),
00244 'NET' => 'Zend/Validate/Hostname/Com.php',
00245 'NO' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
00246 'NU' => 'Zend/Validate/Hostname/Com.php',
00247 'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
00248 2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
00249 3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
00250 4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
00251 5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
00252 6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
00253 7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'),
00254 'PE' => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'),
00255 'PL' => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
00256 2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
00257 3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
00258 4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
00259 5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
00260 6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
00261 7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
00262 8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
00263 9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
00264 10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
00265 11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
00266 12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
00267 13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
00268 14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
00269 15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
00270 16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
00271 17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
00272 18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
00273 19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
00274 20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
00275 21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
00276 22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
00277 23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
00278 24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
00279 25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
00280 26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
00281 27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
00282 28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
00283 29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
00284 30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
00285 31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
00286 32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
00287 33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
00288 'PR' => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'),
00289 'PT' => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'),
00290 'RU' => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
00291 'SA' => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
00292 'SE' => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'),
00293 'SH' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
00294 'SJ' => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
00295 'TH' => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
00296 'TM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
00297 'TW' => 'Zend/Validate/Hostname/Cn.php',
00298 'TR' => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'),
00299 'VE' => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'),
00300 'VN' => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
00301 'ایران' => 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'),
00302 '中国' => 'Zend/Validate/Hostname/Cn.php',
00303 '公司' => 'Zend/Validate/Hostname/Cn.php',
00304 '网络' => 'Zend/Validate/Hostname/Cn.php'
00305 );
00306
00307 protected $_idnLength = array(
00308 'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
00309 'CN' => array(1 => 20),
00310 'COM' => array(3 => 17, 5 => 20),
00311 'HK' => array(1 => 15),
00312 'INFO'=> array(4 => 17),
00313 'KR' => array(1 => 17),
00314 'NET' => array(3 => 17, 5 => 20),
00315 'ORG' => array(6 => 17),
00316 'TW' => array(1 => 20),
00317 'ایران' => array(1 => 30),
00318 '中国' => array(1 => 20),
00319 '公司' => array(1 => 20),
00320 '网络' => array(1 => 20),
00321 );
00322
00333 public function __construct($allow = self::ALLOW_DNS, $validateIdn = true, $validateTld = true, Zend_Validate_Ip $ipValidator = null)
00334 {
00335
00336 $this->setAllow($allow);
00337
00338
00339 $this->_validateIdn = $validateIdn;
00340 $this->_validateTld = $validateTld;
00341
00342 $this->setIpValidator($ipValidator);
00343 }
00344
00349 public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
00350 {
00351 if ($ipValidator === null) {
00352 $ipValidator = new Zend_Validate_Ip();
00353 }
00354 $this->_ipValidator = $ipValidator;
00355 }
00356
00362 public function getAllow()
00363 {
00364 return $this->_allow;
00365 }
00366
00373 public function setAllow($allow)
00374 {
00375 $this->_allow = $allow;
00376 return $this;
00377 }
00378
00386 public function setValidateIdn ($allowed)
00387 {
00388 $this->_validateIdn = (bool) $allowed;
00389 }
00390
00398 public function setValidateTld ($allowed)
00399 {
00400 $this->_validateTld = (bool) $allowed;
00401 }
00402
00412 public function isValid($value)
00413 {
00414 if (!is_string($value)) {
00415 $this->_error(self::INVALID);
00416 return false;
00417 }
00418
00419 $this->_setValue($value);
00420
00421
00422 if (preg_match('/^[0-9.a-e:.]*$/i', $value) &&
00423 $this->_ipValidator->setTranslator($this->getTranslator())->isValid($value)) {
00424 if (!($this->_allow & self::ALLOW_IP)) {
00425 $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
00426 return false;
00427 } else {
00428 return true;
00429 }
00430 }
00431
00432
00433 $domainParts = explode('.', $value);
00434 if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) {
00435 $status = false;
00436
00437 $origenc = iconv_get_encoding('internal_encoding');
00438 iconv_set_encoding('internal_encoding', 'UTF-8');
00439 do {
00440
00441 $matches = array();
00442 if (preg_match('/([^.]{2,10})$/i', end($domainParts), $matches) ||
00443 (end($domainParts) == 'ایران') || (end($domainParts) == '中国') ||
00444 (end($domainParts) == '公司') || (end($domainParts) == '网络')) {
00445
00446 reset($domainParts);
00447
00448
00449
00450
00451
00452
00453
00454 $this->_tld = strtolower($matches[1]);
00455 if ($this->_validateTld) {
00456 if (!in_array($this->_tld, $this->_validTlds)) {
00457 $this->_error(self::UNKNOWN_TLD);
00458 $status = false;
00459 break;
00460 }
00461 }
00462
00468 $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
00469 if ($this->_validateIdn && isset($this->_validIdns[strtoupper($this->_tld)])) {
00470 if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
00471 $regexChars += include($this->_validIdns[strtoupper($this->_tld)]);
00472 } else {
00473 $regexChars += $this->_validIdns[strtoupper($this->_tld)];
00474 }
00475 }
00476
00477
00478 $valid = true;
00479 foreach ($domainParts as $domainPart) {
00480
00481
00482 if (strpos($domainPart, 'xn--') === 0) {
00483 $domainPart = $this->decodePunycode(substr($domainPart, 4));
00484 if ($domainPart === false) {
00485 return false;
00486 }
00487 }
00488
00489
00490 if ((strpos($domainPart, '-') === 0)
00491 || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
00492 || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
00493 $this->_error(self::INVALID_DASH);
00494 $status = false;
00495 break 2;
00496 }
00497
00498
00499 $check = false;
00500 foreach($regexChars as $regexKey => $regexChar) {
00501 $status = @preg_match($regexChar, $domainPart);
00502 if ($status === false) {
00503 iconv_set_encoding('internal_encoding', $origenc);
00504 require_once 'Zend/Validate/Exception.php';
00505 throw new Zend_Validate_Exception('Internal error: DNS validation failed');
00506 } elseif ($status !== 0) {
00507 $length = 63;
00508 if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
00509 && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
00510 $length = $this->_idnLength[strtoupper($this->_tld)];
00511 }
00512
00513 if (iconv_strlen($domainPart, 'UTF-8') > $length) {
00514 $this->_error(self::INVALID_HOSTNAME);
00515 } else {
00516 $check = true;
00517 break 2;
00518 }
00519 }
00520 }
00521
00522 if (!$check) {
00523 $valid = false;
00524 }
00525 }
00526
00527
00528 if (!$valid) {
00529 $this->_error(self::INVALID_HOSTNAME_SCHEMA);
00530 $status = false;
00531 }
00532
00533 } else {
00534
00535 $this->_error(self::UNDECIPHERABLE_TLD);
00536 $status = false;
00537 }
00538 } while (false);
00539
00540 iconv_set_encoding('internal_encoding', $origenc);
00541
00542
00543 if ($status && ($this->_allow & self::ALLOW_DNS)) {
00544 return true;
00545 }
00546 } else {
00547 $this->_error(self::INVALID_HOSTNAME);
00548 }
00549
00550
00551 $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}){1,254}$/';
00552 $status = @preg_match($regexLocal, $value);
00553 if (false === $status) {
00558 require_once 'Zend/Validate/Exception.php';
00559 throw new Zend_Validate_Exception('Internal error: local network name validation failed');
00560 }
00561
00562
00563
00564 $allowLocal = $this->_allow & self::ALLOW_LOCAL;
00565 if ($status && $allowLocal) {
00566 return true;
00567 }
00568
00569
00570 if (!$status) {
00571 $this->_error(self::INVALID_LOCAL_NAME);
00572 }
00573
00574
00575 if ($status && !$allowLocal) {
00576 $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
00577 }
00578
00579 return false;
00580 }
00581
00589 protected function decodePunycode($encoded)
00590 {
00591 $found = preg_match('/([^a-z0-9\x2d]{1,10})$/i', $encoded);
00592 if (empty($encoded) || ($found > 0)) {
00593
00594 $this->_error(self::CANNOT_DECODE_PUNYCODE);
00595 return false;
00596 }
00597
00598 $separator = strrpos($encoded, '-');
00599 if ($separator > 0) {
00600 for ($x = 0; $x < $separator; ++$x) {
00601
00602 $decoded[] = ord($encoded[$x]);
00603 }
00604 } else {
00605 $this->_error(self::CANNOT_DECODE_PUNYCODE);
00606 return false;
00607 }
00608
00609 $lengthd = count($decoded);
00610 $lengthe = strlen($encoded);
00611
00612
00613 $init = true;
00614 $base = 72;
00615 $index = 0;
00616 $char = 0x80;
00617
00618 for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
00619 for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
00620 $hex = ord($encoded[$indexe++]);
00621 $digit = ($hex - 48 < 10) ? $hex - 22
00622 : (($hex - 65 < 26) ? $hex - 65
00623 : (($hex - 97 < 26) ? $hex - 97
00624 : 36));
00625
00626 $index += $digit * $pos;
00627 $tag = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
00628 if ($digit < $tag) {
00629 break;
00630 }
00631
00632 $pos = (int) ($pos * (36 - $tag));
00633 }
00634
00635 $delta = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
00636 $delta += intval($delta / ($lengthd + 1));
00637 for ($key = 0; $delta > 910 / 2; $key += 36) {
00638 $delta = intval($delta / 35);
00639 }
00640
00641 $base = intval($key + 36 * $delta / ($delta + 38));
00642 $init = false;
00643 $char += (int) ($index / ($lengthd + 1));
00644 $index %= ($lengthd + 1);
00645 if ($lengthd > 0) {
00646 for ($i = $lengthd; $i > $index; $i--) {
00647 $decoded[$i] = $decoded[($i - 1)];
00648 }
00649 }
00650
00651 $decoded[$index++] = $char;
00652 }
00653
00654
00655 foreach ($decoded as $key => $value) {
00656 if ($value < 128) {
00657 $decoded[$key] = chr($value);
00658 } elseif ($value < (1 << 11)) {
00659 $decoded[$key] = chr(192 + ($value >> 6));
00660 $decoded[$key] .= chr(128 + ($value & 63));
00661 } elseif ($value < (1 << 16)) {
00662 $decoded[$key] = chr(224 + ($value >> 12));
00663 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
00664 $decoded[$key] .= chr(128 + ($value & 63));
00665 } elseif ($value < (1 << 21)) {
00666 $decoded[$key] = chr(240 + ($value >> 18));
00667 $decoded[$key] .= chr(128 + (($value >> 12) & 63));
00668 $decoded[$key] .= chr(128 + (($value >> 6) & 63));
00669 $decoded[$key] .= chr(128 + ($value & 63));
00670 } else {
00671 $this->_error(self::CANNOT_DECODE_PUNYCODE);
00672 return false;
00673 }
00674 }
00675
00676 return implode($decoded);
00677 }
00678 }