[ Index ]

PHP Cross Reference of vtigercrm-6.1.0

title

Body

[close]

/include/Zend/Validate/ -> Hostname.php (source)

   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 [email protected] so we can send you a copy immediately.
  14   *
  15   * @category   Zend
  16   * @package    Zend_Validate
  17   * @copyright  Copyright (c) 2005-2012 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 24631 2012-02-24 17:43:08Z 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-2012 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  
  61      /**
  62       * @var array
  63       */
  64      protected $_messageTemplates = array(
  65          self::CANNOT_DECODE_PUNYCODE  => "'%value%' appears to be a DNS hostname but the given punycode notation cannot be decoded",
  66          self::INVALID                 => "Invalid type given. String expected",
  67          self::INVALID_DASH            => "'%value%' appears to be a DNS hostname but contains a dash in an invalid position",
  68          self::INVALID_HOSTNAME        => "'%value%' does not match the expected structure for a DNS hostname",
  69          self::INVALID_HOSTNAME_SCHEMA => "'%value%' appears to be a DNS hostname but cannot match against hostname schema for TLD '%tld%'",
  70          self::INVALID_LOCAL_NAME      => "'%value%' does not appear to be a valid local network name",
  71          self::INVALID_URI             => "'%value%' does not appear to be a valid URI hostname",
  72          self::IP_ADDRESS_NOT_ALLOWED  => "'%value%' appears to be an IP address, but IP addresses are not allowed",
  73          self::LOCAL_NAME_NOT_ALLOWED  => "'%value%' appears to be a local network name but local network names are not allowed",
  74          self::UNDECIPHERABLE_TLD      => "'%value%' appears to be a DNS hostname but cannot extract TLD part",
  75          self::UNKNOWN_TLD             => "'%value%' appears to be a DNS hostname but cannot match TLD against known list",
  76      );
  77  
  78      /**
  79       * @var array
  80       */
  81      protected $_messageVariables = array(
  82          'tld' => '_tld'
  83      );
  84  
  85      /**
  86       * Allows Internet domain names (e.g., example.com)
  87       */
  88      const ALLOW_DNS   = 1;
  89  
  90      /**
  91       * Allows IP addresses
  92       */
  93      const ALLOW_IP    = 2;
  94  
  95      /**
  96       * Allows local network names (e.g., localhost, www.localdomain)
  97       */
  98      const ALLOW_LOCAL = 4;
  99  
 100      /**
 101       * Allows all types of hostnames
 102       */
 103      const ALLOW_URI = 8;
 104  
 105      /**
 106       * Allows all types of hostnames
 107       */
 108      const ALLOW_ALL = 15;
 109  
 110      /**
 111       * Array of valid top-level-domains
 112       *
 113       * @see ftp://data.iana.org/TLD/tlds-alpha-by-domain.txt  List of all TLDs by domain
 114       * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
 115       * @var array
 116       */
 117      protected $_validTlds = array(
 118          'ac', 'ad', 'ae', 'aero', 'af', 'ag', 'ai', 'al', 'am', 'an', 'ao', 'aq', 'ar', 'arpa',
 119          'as', 'asia', 'at', 'au', 'aw', 'ax', 'az', 'ba', 'bb', 'bd', 'be', 'bf', 'bg', 'bh', 'bi',
 120          'biz', 'bj', 'bm', 'bn', 'bo', 'br', 'bs', 'bt', 'bv', 'bw', 'by', 'bz', 'ca', 'cat', 'cc',
 121          'cd', 'cf', 'cg', 'ch', 'ci', 'ck', 'cl', 'cm', 'cn', 'co', 'com', 'coop', 'cr', 'cu',
 122          'cv', 'cx', 'cy', 'cz', 'de', 'dj', 'dk', 'dm', 'do', 'dz', 'ec', 'edu', 'ee', 'eg', 'er',
 123          'es', 'et', 'eu', 'fi', 'fj', 'fk', 'fm', 'fo', 'fr', 'ga', 'gb', 'gd', 'ge', 'gf', 'gg',
 124          'gh', 'gi', 'gl', 'gm', 'gn', 'gov', 'gp', 'gq', 'gr', 'gs', 'gt', 'gu', 'gw', 'gy', 'hk',
 125          'hm', 'hn', 'hr', 'ht', 'hu', 'id', 'ie', 'il', 'im', 'in', 'info', 'int', 'io', 'iq',
 126          'ir', 'is', 'it', 'je', 'jm', 'jo', 'jobs', 'jp', 'ke', 'kg', 'kh', 'ki', 'km', 'kn', 'kp',
 127          'kr', 'kw', 'ky', 'kz', 'la', 'lb', 'lc', 'li', 'lk', 'lr', 'ls', 'lt', 'lu', 'lv', 'ly',
 128          'ma', 'mc', 'md', 'me', 'mg', 'mh', 'mil', 'mk', 'ml', 'mm', 'mn', 'mo', 'mobi', 'mp',
 129          'mq', 'mr', 'ms', 'mt', 'mu', 'museum', 'mv', 'mw', 'mx', 'my', 'mz', 'na', 'name', 'nc',
 130          'ne', 'net', 'nf', 'ng', 'ni', 'nl', 'no', 'np', 'nr', 'nu', 'nz', 'om', 'org', 'pa', 'pe',
 131          'pf', 'pg', 'ph', 'pk', 'pl', 'pm', 'pn', 'pr', 'pro', 'ps', 'pt', 'pw', 'py', 'qa', 're',
 132          'ro', 'rs', 'ru', 'rw', 'sa', 'sb', 'sc', 'sd', 'se', 'sg', 'sh', 'si', 'sj', 'sk', 'sl',
 133          'sm', 'sn', 'so', 'sr', 'st', 'su', 'sv', 'sy', 'sz', 'tc', 'td', 'tel', 'tf', 'tg', 'th',
 134          'tj', 'tk', 'tl', 'tm', 'tn', 'to', 'tp', 'tr', 'travel', 'tt', 'tv', 'tw', 'tz', 'ua',
 135          'ug', 'uk', 'um', 'us', 'uy', 'uz', 'va', 'vc', 've', 'vg', 'vi', 'vn', 'vu', 'wf', 'ws',
 136          'xxx', 'ye', 'yt', 'yu', 'za', 'zm', 'zw'
 137      );
 138  
 139      /**
 140       * @var string
 141       */
 142      protected $_tld;
 143  
 144      /**
 145       * Array for valid Idns
 146       * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
 147       * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
 148       * (.AR) Argentinia http://www.nic.ar/faqidn.html
 149       * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
 150       * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
 151       * (.BIZ) International http://www.iana.org/domains/idn-tables/
 152       * (.BR) Brazil http://registro.br/faq/faq6.html
 153       * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
 154       * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
 155       * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
 156       * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
 157       * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
 158       * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html
 159       * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
 160       * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
 161       * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
 162       * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
 163       * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
 164       * (.INFO) International http://www.nic.info/info/idn
 165       * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
 166       * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
 167       * (.IS) Iceland http://www.isnic.is/domain/rules.php
 168       * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
 169       * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
 170       * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
 171       * (.MD) Moldova http://www.register.md/
 172       * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
 173       * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
 174       * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
 175       * (.NU) Niue http://www.worldnames.net/
 176       * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
 177       * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
 178       * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
 179       * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
 180       * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
 181       * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
 182       * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
 183       * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
 184       * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
 185       * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
 186       * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
 187       * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
 188       * (.TR) Turkey https://www.nic.tr/index.php
 189       * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
 190       * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
 191       *
 192       * @var array
 193       */
 194      protected $_validIdns = array(
 195          'AC'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
 196          'AR'  => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'),
 197          'AS'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'),
 198          'AT'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'),
 199          'BIZ' => 'Hostname/Biz.php',
 200          'BR'  => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'),
 201          'BV'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
 202          'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'),
 203          'CH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
 204          'CL'  => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
 205          'CN'  => 'Hostname/Cn.php',
 206          'COM' => 'Zend/Validate/Hostname/Com.php',
 207          'DE'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
 208          'DK'  => array(1 => '/^[\x{002d}0-9a-zäéöü]{1,63}$/iu'),
 209          'ES'  => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'),
 210          'EU'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
 211              2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
 212              3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu',
 213              4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu',
 214              5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu',
 215              6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'),
 216          'FI'  => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'),
 217          'GR'  => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'),
 218          'HK'  => 'Zend/Validate/Hostname/Cn.php',
 219          'HU'  => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'),
 220          'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
 221              2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
 222              3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
 223              4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
 224              5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
 225              6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
 226              7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
 227              8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
 228          'IO'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
 229          'IS'  => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'),
 230          'JP'  => 'Zend/Validate/Hostname/Jp.php',
 231          'KR'  => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
 232          'LI'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
 233          'LT'  => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'),
 234          'MD'  => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
 235          'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'),
 236          'NET' => 'Zend/Validate/Hostname/Com.php',
 237          'NO'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
 238          'NU'  => 'Zend/Validate/Hostname/Com.php',
 239          'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
 240              2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
 241              3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
 242              4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
 243              5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
 244              6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
 245              7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'),
 246          'PE'  => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'),
 247          'PL'  => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
 248              2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
 249              3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
 250              4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
 251              5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
 252              6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
 253              7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
 254              8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
 255              9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
 256              10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
 257              11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
 258              12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
 259              13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
 260              14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
 261              15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
 262              16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
 263              17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
 264              18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
 265              19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
 266              20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
 267              21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
 268              22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
 269              23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
 270              24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
 271              25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
 272              26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
 273              27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
 274              28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
 275              29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
 276              30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
 277              31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
 278              32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
 279              33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
 280          'PR'  => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'),
 281          'PT'  => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'),
 282          'RU'  => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
 283          'SA'  => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
 284          'SE'  => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'),
 285          'SH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
 286          'SI'  => array(
 287              1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
 288              2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
 289              3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'),
 290          'SJ'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
 291          'TH'  => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
 292          'TM'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
 293          'TW'  => 'Zend/Validate/Hostname/Cn.php',
 294          'TR'  => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'),
 295          'VE'  => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'),
 296          'VN'  => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
 297          'ایران' => 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'),
 298          '中国' => 'Zend/Validate/Hostname/Cn.php',
 299          '公司' => 'Zend/Validate/Hostname/Cn.php',
 300          '网络' => 'Zend/Validate/Hostname/Cn.php'
 301      );
 302  
 303      protected $_idnLength = array(
 304          'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
 305          'CN'  => array(1 => 20),
 306          'COM' => array(3 => 17, 5 => 20),
 307          'HK'  => array(1 => 15),
 308          'INFO'=> array(4 => 17),
 309          'KR'  => array(1 => 17),
 310          'NET' => array(3 => 17, 5 => 20),
 311          'ORG' => array(6 => 17),
 312          'TW'  => array(1 => 20),
 313          'ایران' => array(1 => 30),
 314          '中国' => array(1 => 20),
 315          '公司' => array(1 => 20),
 316          '网络' => array(1 => 20),
 317      );
 318  
 319      protected $_options = array(
 320          'allow' => self::ALLOW_DNS,
 321          'idn'   => true,
 322          'tld'   => true,
 323          'ip'    => null
 324      );
 325  
 326      /**
 327       * Sets validator options
 328       *
 329       * @param integer          $allow       OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
 330       * @param boolean          $validateIdn OPTIONAL Set whether IDN domains are validated (default true)
 331       * @param boolean          $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)
 332       * @param Zend_Validate_Ip $ipValidator OPTIONAL
 333       * @return void
 334       * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm  Technical Specifications for ccTLDs
 335       */
 336      public function __construct($options = array())
 337      {
 338          if ($options instanceof Zend_Config) {
 339              $options = $options->toArray();
 340          } else if (!is_array($options)) {
 341              $options = func_get_args();
 342              $temp['allow'] = array_shift($options);
 343              if (!empty($options)) {
 344                  $temp['idn'] = array_shift($options);
 345              }
 346  
 347              if (!empty($options)) {
 348                  $temp['tld'] = array_shift($options);
 349              }
 350  
 351              if (!empty($options)) {
 352                  $temp['ip'] = array_shift($options);
 353              }
 354  
 355              $options = $temp;
 356          }
 357  
 358          $options += $this->_options;
 359          $this->setOptions($options);
 360      }
 361  
 362      /**
 363       * Returns all set options
 364       *
 365       * @return array
 366       */
 367      public function getOptions()
 368      {
 369          return $this->_options;
 370      }
 371  
 372      /**
 373       * Sets the options for this validator
 374       *
 375       * @param array $options
 376       * @return Zend_Validate_Hostname
 377       */
 378      public function setOptions($options)
 379      {
 380          if (array_key_exists('allow', $options)) {
 381              $this->setAllow($options['allow']);
 382          }
 383  
 384          if (array_key_exists('idn', $options)) {
 385              $this->setValidateIdn($options['idn']);
 386          }
 387  
 388          if (array_key_exists('tld', $options)) {
 389              $this->setValidateTld($options['tld']);
 390          }
 391  
 392          if (array_key_exists('ip', $options)) {
 393              $this->setIpValidator($options['ip']);
 394          }
 395  
 396          return $this;
 397      }
 398  
 399      /**
 400       * Returns the set ip validator
 401       *
 402       * @return Zend_Validate_Ip
 403       */
 404      public function getIpValidator()
 405      {
 406          return $this->_options['ip'];
 407      }
 408  
 409      /**
 410       * @param Zend_Validate_Ip $ipValidator OPTIONAL
 411       * @return void;
 412       */
 413      public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
 414      {
 415          if ($ipValidator === null) {
 416              $ipValidator = new Zend_Validate_Ip();
 417          }
 418  
 419          $this->_options['ip'] = $ipValidator;
 420          return $this;
 421      }
 422  
 423      /**
 424       * Returns the allow option
 425       *
 426       * @return integer
 427       */
 428      public function getAllow()
 429      {
 430          return $this->_options['allow'];
 431      }
 432  
 433      /**
 434       * Sets the allow option
 435       *
 436       * @param  integer $allow
 437       * @return Zend_Validate_Hostname Provides a fluent interface
 438       */
 439      public function setAllow($allow)
 440      {
 441          $this->_options['allow'] = $allow;
 442          return $this;
 443      }
 444  
 445      /**
 446       * Returns the set idn option
 447       *
 448       * @return boolean
 449       */
 450      public function getValidateIdn()
 451      {
 452          return $this->_options['idn'];
 453      }
 454  
 455      /**
 456       * Set whether IDN domains are validated
 457       *
 458       * This only applies when DNS hostnames are validated
 459       *
 460       * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
 461       */
 462      public function setValidateIdn ($allowed)
 463      {
 464          $this->_options['idn'] = (bool) $allowed;
 465          return $this;
 466      }
 467  
 468      /**
 469       * Returns the set tld option
 470       *
 471       * @return boolean
 472       */
 473      public function getValidateTld()
 474      {
 475          return $this->_options['tld'];
 476      }
 477  
 478      /**
 479       * Set whether the TLD element of a hostname is validated
 480       *
 481       * This only applies when DNS hostnames are validated
 482       *
 483       * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
 484       */
 485      public function setValidateTld ($allowed)
 486      {
 487          $this->_options['tld'] = (bool) $allowed;
 488          return $this;
 489      }
 490  
 491      /**
 492       * Defined by Zend_Validate_Interface
 493       *
 494       * Returns true if and only if the $value is a valid hostname with respect to the current allow option
 495       *
 496       * @param  string $value
 497       * @throws Zend_Validate_Exception if a fatal error occurs for validation process
 498       * @return boolean
 499       */
 500      public function isValid($value)
 501      {
 502          if (!is_string($value)) {
 503              $this->_error(self::INVALID);
 504              return false;
 505          }
 506  
 507          $this->_setValue($value);
 508          // Check input against IP address schema
 509          if (preg_match('/^[0-9a-f:.]*$/i', $value) &&
 510              $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
 511              if (!($this->_options['allow'] & self::ALLOW_IP)) {
 512                  $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
 513                  return false;
 514              } else {
 515                  return true;
 516              }
 517          }
 518  
 519          // RFC3986 3.2.2 states:
 520          // 
 521          //     The rightmost domain label of a fully qualified domain name
 522          //     in DNS may be followed by a single "." and should be if it is 
 523          //     necessary to distinguish between the complete domain name and
 524          //     some local domain.
 525          //     
 526          // (see ZF-6363)
 527          
 528          // Local hostnames are allowed to be partitial (ending '.')
 529          if ($this->_options['allow'] & self::ALLOW_LOCAL) {
 530              if (substr($value, -1) === '.') {
 531                  $value = substr($value, 0, -1);
 532                  if (substr($value, -1) === '.') {
 533                      // Empty hostnames (ending '..') are not allowed
 534                      $this->_error(self::INVALID_LOCAL_NAME);
 535                      return false;
 536                  }
 537              }
 538          }
 539  
 540          $domainParts = explode('.', $value);
 541  
 542          // Prevent partitial IP V4 adresses (ending '.')
 543          if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) &&
 544              $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
 545              $this->_error(self::INVALID_LOCAL_NAME);
 546          }
 547  
 548          // Check input against DNS hostname schema
 549          if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) {
 550              $status = false;
 551  
 552              $origenc = iconv_get_encoding('internal_encoding');
 553              iconv_set_encoding('internal_encoding', 'UTF-8');
 554              do {
 555                  // First check TLD
 556                  $matches = array();
 557                  if (preg_match('/([^.]{2,10})$/i', end($domainParts), $matches) ||
 558                      (end($domainParts) == 'ایران') || (end($domainParts) == '中国') ||
 559                      (end($domainParts) == '公司') || (end($domainParts) == '网络')) {
 560  
 561                      reset($domainParts);
 562  
 563                      // Hostname characters are: *(label dot)(label dot label); max 254 chars
 564                      // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
 565                      // id-prefix: alpha / digit
 566                      // ldh: alpha / digit / dash
 567  
 568                      // Match TLD against known list
 569                      $this->_tld = strtolower($matches[1]);
 570                      if ($this->_options['tld']) {
 571                          if (!in_array($this->_tld, $this->_validTlds)) {
 572                              $this->_error(self::UNKNOWN_TLD);
 573                              $status = false;
 574                              break;
 575                          }
 576                      }
 577  
 578                      /**
 579                       * Match against IDN hostnames
 580                       * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
 581                       * @see Zend_Validate_Hostname_Interface
 582                       */
 583                      $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
 584                      if ($this->_options['idn'] &&  isset($this->_validIdns[strtoupper($this->_tld)])) {
 585                          if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
 586                              $regexChars += include($this->_validIdns[strtoupper($this->_tld)]);
 587                          } else {
 588                              $regexChars += $this->_validIdns[strtoupper($this->_tld)];
 589                          }
 590                      }
 591  
 592                      // Check each hostname part
 593                      $check = 0;
 594                      foreach ($domainParts as $domainPart) {
 595                          // Decode Punycode domainnames to IDN
 596                          if (strpos($domainPart, 'xn--') === 0) {
 597                              $domainPart = $this->decodePunycode(substr($domainPart, 4));
 598                              if ($domainPart === false) {
 599                                  return false;
 600                              }
 601                          }
 602  
 603                          // Check dash (-) does not start, end or appear in 3rd and 4th positions
 604                          if ((strpos($domainPart, '-') === 0)
 605                              || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
 606                              || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
 607                                  $this->_error(self::INVALID_DASH);
 608                              $status = false;
 609                              break 2;
 610                          }
 611  
 612                          // Check each domain part
 613                          $checked = false;
 614                          foreach($regexChars as $regexKey => $regexChar) {
 615                              $status = @preg_match($regexChar, $domainPart);
 616                              if ($status > 0) {
 617                                  $length = 63;
 618                                  if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
 619                                      && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
 620                                      $length = $this->_idnLength[strtoupper($this->_tld)];
 621                                  }
 622  
 623                                  if (iconv_strlen($domainPart, 'UTF-8') > $length) {
 624                                      $this->_error(self::INVALID_HOSTNAME);
 625                                  } else {
 626                                      $checked = true;
 627                                      break;
 628                                  }
 629                              }
 630                          }
 631  
 632                          if ($checked) {
 633                              ++$check;
 634                          }
 635                      }
 636  
 637                      // If one of the labels doesn't match, the hostname is invalid
 638                      if ($check !== count($domainParts)) {
 639                          $this->_error(self::INVALID_HOSTNAME_SCHEMA);
 640                          $status = false;
 641                      }
 642                  } else {
 643                      // Hostname not long enough
 644                      $this->_error(self::UNDECIPHERABLE_TLD);
 645                      $status = false;
 646                  }
 647              } while (false);
 648  
 649              iconv_set_encoding('internal_encoding', $origenc);
 650              // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
 651              // passes validation
 652              if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) {
 653                  return true;
 654              }
 655          } else if ($this->_options['allow'] & self::ALLOW_DNS) {
 656              $this->_error(self::INVALID_HOSTNAME);
 657          }
 658  
 659          // Check for URI Syntax (RFC3986)
 660          if ($this->_options['allow'] & self::ALLOW_URI) {
 661              if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
 662                  return true;
 663              } else {
 664                  $this->_error(self::INVALID_URI);
 665              }
 666          }
 667  
 668          // Check input against local network name schema; last chance to pass validation
 669          $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/';
 670          $status = @preg_match($regexLocal, $value);
 671  
 672          // If the input passes as a local network name, and local network names are allowed, then the
 673          // hostname passes validation
 674          $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL;
 675          if ($status && $allowLocal) {
 676              return true;
 677          }
 678  
 679          // If the input does not pass as a local network name, add a message
 680          if (!$status) {
 681              $this->_error(self::INVALID_LOCAL_NAME);
 682          }
 683  
 684          // If local network names are not allowed, add a message
 685          if ($status && !$allowLocal) {
 686              $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
 687          }
 688  
 689          return false;
 690      }
 691  
 692      /**
 693       * Decodes a punycode encoded string to it's original utf8 string
 694       * In case of a decoding failure the original string is returned
 695       *
 696       * @param  string $encoded Punycode encoded string to decode
 697       * @return string
 698       */
 699      protected function decodePunycode($encoded)
 700      {
 701          $found = preg_match('/([^a-z0-9\x2d]{1,10})$/i', $encoded);
 702          if (empty($encoded) || ($found > 0)) {
 703              // no punycode encoded string, return as is
 704              $this->_error(self::CANNOT_DECODE_PUNYCODE);
 705              return false;
 706          }
 707  
 708          $separator = strrpos($encoded, '-');
 709          if ($separator > 0) {
 710              for ($x = 0; $x < $separator; ++$x) {
 711                  // prepare decoding matrix
 712                  $decoded[] = ord($encoded[$x]);
 713              }
 714          } else {
 715              $this->_error(self::CANNOT_DECODE_PUNYCODE);
 716              return false;
 717          }
 718  
 719          $lengthd = count($decoded);
 720          $lengthe = strlen($encoded);
 721  
 722          // decoding
 723          $init  = true;
 724          $base  = 72;
 725          $index = 0;
 726          $char  = 0x80;
 727  
 728          for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
 729              for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
 730                  $hex   = ord($encoded[$indexe++]);
 731                  $digit = ($hex - 48 < 10) ? $hex - 22
 732                         : (($hex - 65 < 26) ? $hex - 65
 733                         : (($hex - 97 < 26) ? $hex - 97
 734                         : 36));
 735  
 736                  $index += $digit * $pos;
 737                  $tag    = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
 738                  if ($digit < $tag) {
 739                      break;
 740                  }
 741  
 742                  $pos = (int) ($pos * (36 - $tag));
 743              }
 744  
 745              $delta   = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
 746              $delta  += intval($delta / ($lengthd + 1));
 747              for ($key = 0; $delta > 910 / 2; $key += 36) {
 748                  $delta = intval($delta / 35);
 749              }
 750  
 751              $base   = intval($key + 36 * $delta / ($delta + 38));
 752              $init   = false;
 753              $char  += (int) ($index / ($lengthd + 1));
 754              $index %= ($lengthd + 1);
 755              if ($lengthd > 0) {
 756                  for ($i = $lengthd; $i > $index; $i--) {
 757                      $decoded[$i] = $decoded[($i - 1)];
 758                  }
 759              }
 760  
 761              $decoded[$index++] = $char;
 762          }
 763  
 764          // convert decoded ucs4 to utf8 string
 765          foreach ($decoded as $key => $value) {
 766              if ($value < 128) {
 767                  $decoded[$key] = chr($value);
 768              } elseif ($value < (1 << 11)) {
 769                  $decoded[$key]  = chr(192 + ($value >> 6));
 770                  $decoded[$key] .= chr(128 + ($value & 63));
 771              } elseif ($value < (1 << 16)) {
 772                  $decoded[$key]  = chr(224 + ($value >> 12));
 773                  $decoded[$key] .= chr(128 + (($value >> 6) & 63));
 774                  $decoded[$key] .= chr(128 + ($value & 63));
 775              } elseif ($value < (1 << 21)) {
 776                  $decoded[$key]  = chr(240 + ($value >> 18));
 777                  $decoded[$key] .= chr(128 + (($value >> 12) & 63));
 778                  $decoded[$key] .= chr(128 + (($value >> 6) & 63));
 779                  $decoded[$key] .= chr(128 + ($value & 63));
 780              } else {
 781                  $this->_error(self::CANNOT_DECODE_PUNYCODE);
 782                  return false;
 783              }
 784          }
 785  
 786          return implode($decoded);
 787      }
 788  }


Generated: Fri Nov 28 20:08:37 2014 Cross-referenced by PHPXref 0.7.1