Completed
Push — master ( 85e358...cf3219 )
by Rakesh
04:24 queued 10s
created

Zend_Validate_Hostname::isValid()   F

Complexity

Conditions 54
Paths 16336

Size

Total Lines 206
Code Lines 108

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 54
eloc 108
c 1
b 0
f 1
nc 16336
nop 1
dl 0
loc 206
rs 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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-2014 Zend Technologies USA Inc. (http://www.zend.com)
18
 * @license    http://framework.zend.com/license/new-bsd     New BSD License
19
 * @version    $Id$
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-2014 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
     * Version 2014071001, Last Updated Fri Jul 11 07:07:01 2014 UTC
114
     *
115
     * @see http://data.iana.org/TLD/tlds-alpha-by-domain.txt  List of all TLDs by domain
116
     * @see http://www.iana.org/domains/root/db/ Official list of supported TLDs
117
     * @var array
118
     */
119
    protected $_validTlds = array(
120
        'ac',
121
        'academy',
122
        'accountants',
123
        'active',
124
        'actor',
125
        'ad',
126
        'ae',
127
        'aero',
128
        'af',
129
        'ag',
130
        'agency',
131
        'ai',
132
        'airforce',
133
        'al',
134
        'am',
135
        'an',
136
        'ao',
137
        'aq',
138
        'ar',
139
        'archi',
140
        'army',
141
        'arpa',
142
        'as',
143
        'asia',
144
        'associates',
145
        'at',
146
        'attorney',
147
        'au',
148
        'audio',
149
        'autos',
150
        'aw',
151
        'ax',
152
        'axa',
153
        'az',
154
        'ba',
155
        'bar',
156
        'bargains',
157
        'bayern',
158
        'bb',
159
        'bd',
160
        'be',
161
        'beer',
162
        'berlin',
163
        'best',
164
        'bf',
165
        'bg',
166
        'bh',
167
        'bi',
168
        'bid',
169
        'bike',
170
        'bio',
171
        'biz',
172
        'bj',
173
        'black',
174
        'blackfriday',
175
        'blue',
176
        'bm',
177
        'bmw',
178
        'bn',
179
        'bo',
180
        'boutique',
181
        'br',
182
        'brussels',
183
        'bs',
184
        'bt',
185
        'build',
186
        'builders',
187
        'buzz',
188
        'bv',
189
        'bw',
190
        'by',
191
        'bz',
192
        'bzh',
193
        'ca',
194
        'cab',
195
        'camera',
196
        'camp',
197
        'cancerresearch',
198
        'capetown',
199
        'capital',
200
        'cards',
201
        'care',
202
        'career',
203
        'careers',
204
        'cash',
205
        'cat',
206
        'catering',
207
        'cc',
208
        'cd',
209
        'center',
210
        'ceo',
211
        'cf',
212
        'cg',
213
        'ch',
214
        'cheap',
215
        'christmas',
216
        'church',
217
        'ci',
218
        'citic',
219
        'city',
220
        'ck',
221
        'cl',
222
        'claims',
223
        'cleaning',
224
        'clinic',
225
        'clothing',
226
        'club',
227
        'cm',
228
        'cn',
229
        'co',
230
        'codes',
231
        'coffee',
232
        'college',
233
        'cologne',
234
        'com',
235
        'community',
236
        'company',
237
        'computer',
238
        'condos',
239
        'construction',
240
        'consulting',
241
        'contractors',
242
        'cooking',
243
        'cool',
244
        'coop',
245
        'country',
246
        'cr',
247
        'credit',
248
        'creditcard',
249
        'cruises',
250
        'cu',
251
        'cuisinella',
252
        'cv',
253
        'cw',
254
        'cx',
255
        'cy',
256
        'cz',
257
        'dance',
258
        'dating',
259
        'de',
260
        'deals',
261
        'degree',
262
        'democrat',
263
        'dental',
264
        'dentist',
265
        'desi',
266
        'diamonds',
267
        'digital',
268
        'direct',
269
        'directory',
270
        'discount',
271
        'dj',
272
        'dk',
273
        'dm',
274
        'dnp',
275
        'do',
276
        'domains',
277
        'durban',
278
        'dz',
279
        'ec',
280
        'edu',
281
        'education',
282
        'ee',
283
        'eg',
284
        'email',
285
        'engineer',
286
        'engineering',
287
        'enterprises',
288
        'equipment',
289
        'er',
290
        'es',
291
        'estate',
292
        'et',
293
        'eu',
294
        'eus',
295
        'events',
296
        'exchange',
297
        'expert',
298
        'exposed',
299
        'fail',
300
        'farm',
301
        'feedback',
302
        'fi',
303
        'finance',
304
        'financial',
305
        'fish',
306
        'fishing',
307
        'fitness',
308
        'fj',
309
        'fk',
310
        'flights',
311
        'florist',
312
        'fm',
313
        'fo',
314
        'foo',
315
        'foundation',
316
        'fr',
317
        'frogans',
318
        'fund',
319
        'furniture',
320
        'futbol',
321
        'ga',
322
        'gal',
323
        'gallery',
324
        'gb',
325
        'gd',
326
        'ge',
327
        'gf',
328
        'gg',
329
        'gh',
330
        'gi',
331
        'gift',
332
        'gives',
333
        'gl',
334
        'glass',
335
        'global',
336
        'globo',
337
        'gm',
338
        'gmo',
339
        'gn',
340
        'gop',
341
        'gov',
342
        'gp',
343
        'gq',
344
        'gr',
345
        'graphics',
346
        'gratis',
347
        'green',
348
        'gripe',
349
        'gs',
350
        'gt',
351
        'gu',
352
        'guide',
353
        'guitars',
354
        'guru',
355
        'gw',
356
        'gy',
357
        'hamburg',
358
        'haus',
359
        'hiphop',
360
        'hiv',
361
        'hk',
362
        'hm',
363
        'hn',
364
        'holdings',
365
        'holiday',
366
        'homes',
367
        'horse',
368
        'host',
369
        'house',
370
        'hr',
371
        'ht',
372
        'hu',
373
        'id',
374
        'ie',
375
        'il',
376
        'im',
377
        'immobilien',
378
        'in',
379
        'industries',
380
        'info',
381
        'ink',
382
        'institute',
383
        'insure',
384
        'int',
385
        'international',
386
        'investments',
387
        'io',
388
        'iq',
389
        'ir',
390
        'is',
391
        'it',
392
        'je',
393
        'jetzt',
394
        'jm',
395
        'jo',
396
        'jobs',
397
        'joburg',
398
        'jp',
399
        'juegos',
400
        'kaufen',
401
        'ke',
402
        'kg',
403
        'kh',
404
        'ki',
405
        'kim',
406
        'kitchen',
407
        'kiwi',
408
        'km',
409
        'kn',
410
        'koeln',
411
        'kp',
412
        'kr',
413
        'kred',
414
        'kw',
415
        'ky',
416
        'kz',
417
        'la',
418
        'land',
419
        'lawyer',
420
        'lb',
421
        'lc',
422
        'lease',
423
        'li',
424
        'life',
425
        'lighting',
426
        'limited',
427
        'limo',
428
        'link',
429
        'lk',
430
        'loans',
431
        'london',
432
        'lotto',
433
        'lr',
434
        'ls',
435
        'lt',
436
        'lu',
437
        'luxe',
438
        'luxury',
439
        'lv',
440
        'ly',
441
        'ma',
442
        'maison',
443
        'management',
444
        'mango',
445
        'market',
446
        'marketing',
447
        'mc',
448
        'md',
449
        'me',
450
        'media',
451
        'meet',
452
        'melbourne',
453
        'menu',
454
        'mg',
455
        'mh',
456
        'miami',
457
        'mil',
458
        'mini',
459
        'mk',
460
        'ml',
461
        'mm',
462
        'mn',
463
        'mo',
464
        'mobi',
465
        'moda',
466
        'moe',
467
        'monash',
468
        'mortgage',
469
        'moscow',
470
        'motorcycles',
471
        'mp',
472
        'mq',
473
        'mr',
474
        'ms',
475
        'mt',
476
        'mu',
477
        'museum',
478
        'mv',
479
        'mw',
480
        'mx',
481
        'my',
482
        'mz',
483
        'na',
484
        'nagoya',
485
        'name',
486
        'navy',
487
        'nc',
488
        'ne',
489
        'net',
490
        'neustar',
491
        'nf',
492
        'ng',
493
        'nhk',
494
        'ni',
495
        'ninja',
496
        'nl',
497
        'no',
498
        'np',
499
        'nr',
500
        'nu',
501
        'nyc',
502
        'nz',
503
        'okinawa',
504
        'om',
505
        'onl',
506
        'org',
507
        'organic',
508
        'ovh',
509
        'pa',
510
        'paris',
511
        'partners',
512
        'parts',
513
        'pe',
514
        'pf',
515
        'pg',
516
        'ph',
517
        'photo',
518
        'photography',
519
        'photos',
520
        'physio',
521
        'pics',
522
        'pictures',
523
        'pink',
524
        'pk',
525
        'pl',
526
        'place',
527
        'plumbing',
528
        'pm',
529
        'pn',
530
        'post',
531
        'pr',
532
        'press',
533
        'pro',
534
        'productions',
535
        'properties',
536
        'ps',
537
        'pt',
538
        'pub',
539
        'pw',
540
        'py',
541
        'qa',
542
        'qpon',
543
        'quebec',
544
        're',
545
        'recipes',
546
        'red',
547
        'rehab',
548
        'reise',
549
        'reisen',
550
        'ren',
551
        'rentals',
552
        'repair',
553
        'report',
554
        'republican',
555
        'rest',
556
        'reviews',
557
        'rich',
558
        'rio',
559
        'ro',
560
        'rocks',
561
        'rodeo',
562
        'rs',
563
        'ru',
564
        'ruhr',
565
        'rw',
566
        'ryukyu',
567
        'sa',
568
        'saarland',
569
        'sb',
570
        'sc',
571
        'schmidt',
572
        'schule',
573
        'scot',
574
        'sd',
575
        'se',
576
        'services',
577
        'sexy',
578
        'sg',
579
        'sh',
580
        'shiksha',
581
        'shoes',
582
        'si',
583
        'singles',
584
        'sj',
585
        'sk',
586
        'sl',
587
        'sm',
588
        'sn',
589
        'so',
590
        'social',
591
        'software',
592
        'sohu',
593
        'solar',
594
        'solutions',
595
        'soy',
596
        'space',
597
        'sr',
598
        'st',
599
        'su',
600
        'supplies',
601
        'supply',
602
        'support',
603
        'surf',
604
        'surgery',
605
        'suzuki',
606
        'sv',
607
        'sx',
608
        'sy',
609
        'systems',
610
        'sz',
611
        'tattoo',
612
        'tax',
613
        'tc',
614
        'td',
615
        'technology',
616
        'tel',
617
        'tf',
618
        'tg',
619
        'th',
620
        'tienda',
621
        'tips',
622
        'tirol',
623
        'tj',
624
        'tk',
625
        'tl',
626
        'tm',
627
        'tn',
628
        'to',
629
        'today',
630
        'tokyo',
631
        'tools',
632
        'town',
633
        'toys',
634
        'tp',
635
        'tr',
636
        'trade',
637
        'training',
638
        'travel',
639
        'tt',
640
        'tv',
641
        'tw',
642
        'tz',
643
        'ua',
644
        'ug',
645
        'uk',
646
        'university',
647
        'uno',
648
        'us',
649
        'uy',
650
        'uz',
651
        'va',
652
        'vacations',
653
        'vc',
654
        've',
655
        'vegas',
656
        'ventures',
657
        'versicherung',
658
        'vet',
659
        'vg',
660
        'vi',
661
        'viajes',
662
        'villas',
663
        'vision',
664
        'vlaanderen',
665
        'vn',
666
        'vodka',
667
        'vote',
668
        'voting',
669
        'voto',
670
        'voyage',
671
        'vu',
672
        'wang',
673
        'watch',
674
        'webcam',
675
        'website',
676
        'wed',
677
        'wf',
678
        'wien',
679
        'wiki',
680
        'works',
681
        'ws',
682
        'wtc',
683
        'wtf',
684
        'xn--3bst00m',
685
        'xn--3ds443g',
686
        'xn--3e0b707e',
687
        'xn--45brj9c',
688
        'xn--4gbrim',
689
        'xn--55qw42g',
690
        'xn--55qx5d',
691
        'xn--6frz82g',
692
        'xn--6qq986b3xl',
693
        'xn--80adxhks',
694
        'xn--80ao21a',
695
        'xn--80asehdb',
696
        'xn--80aswg',
697
        'xn--90a3ac',
698
        'xn--c1avg',
699
        'xn--cg4bki',
700
        'xn--clchc0ea0b2g2a9gcd',
701
        'xn--czr694b',
702
        'xn--czru2d',
703
        'xn--d1acj3b',
704
        'xn--fiq228c5hs',
705
        'xn--fiq64b',
706
        'xn--fiqs8s',
707
        'xn--fiqz9s',
708
        'xn--fpcrj9c3d',
709
        'xn--fzc2c9e2c',
710
        'xn--gecrj9c',
711
        'xn--h2brj9c',
712
        'xn--i1b6b1a6a2e',
713
        'xn--io0a7i',
714
        'xn--j1amh',
715
        'xn--j6w193g',
716
        'xn--kprw13d',
717
        'xn--kpry57d',
718
        'xn--kput3i',
719
        'xn--l1acc',
720
        'xn--lgbbat1ad8j',
721
        'xn--mgb9awbf',
722
        'xn--mgba3a4f16a',
723
        'xn--mgbaam7a8h',
724
        'xn--mgbab2bd',
725
        'xn--mgbayh7gpa',
726
        'xn--mgbbh1a71e',
727
        'xn--mgbc0a9azcg',
728
        'xn--mgberp4a5d4ar',
729
        'xn--mgbx4cd0ab',
730
        'xn--ngbc5azd',
731
        'xn--nqv7f',
732
        'xn--nqv7fs00ema',
733
        'xn--o3cw4h',
734
        'xn--ogbpf8fl',
735
        'xn--p1ai',
736
        'xn--pgbs0dh',
737
        'xn--q9jyb4c',
738
        'xn--rhqv96g',
739
        'xn--s9brj9c',
740
        'xn--ses554g',
741
        'xn--unup4y',
742
        'xn--wgbh1c',
743
        'xn--wgbl6a',
744
        'xn--xkc2al3hye2a',
745
        'xn--xkc2dl3a5ee0h',
746
        'xn--yfro4i67o',
747
        'xn--ygbi2ammx',
748
        'xn--zfr164b',
749
        'xxx',
750
        'xyz',
751
        'yachts',
752
        'ye',
753
        'yokohama',
754
        'yt',
755
        'za',
756
        'zm',
757
        'zone',
758
        'zw',
759
    );
760
761
    /**
762
     * @var string
763
     */
764
    protected $_tld;
765
766
    /**
767
     * Array for valid Idns
768
     * @see http://www.iana.org/domains/idn-tables/ Official list of supported IDN Chars
769
     * (.AC) Ascension Island http://www.nic.ac/pdf/AC-IDN-Policy.pdf
770
     * (.AR) Argentinia http://www.nic.ar/faqidn.html
771
     * (.AS) American Samoa http://www.nic.as/idn/chars.cfm
772
     * (.AT) Austria http://www.nic.at/en/service/technical_information/idn/charset_converter/
773
     * (.BIZ) International http://www.iana.org/domains/idn-tables/
774
     * (.BR) Brazil http://registro.br/faq/faq6.html
775
     * (.BV) Bouvett Island http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
776
     * (.CA) Canada http://www.iana.org/domains/idn-tables/tables/ca_fr_1.0.html
777
     * (.CAT) Catalan http://www.iana.org/domains/idn-tables/tables/cat_ca_1.0.html
778
     * (.CH) Switzerland https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
779
     * (.CL) Chile http://www.iana.org/domains/idn-tables/tables/cl_latn_1.0.html
780
     * (.COM) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
781
     * (.DE) Germany http://www.denic.de/en/domains/idns/liste.html
782
     * (.DK) Danmark http://www.dk-hostmaster.dk/index.php?id=151
783
     * (.ES) Spain https://www.nic.es/media/2008-05/1210147705287.pdf
784
     * (.FI) Finland http://www.ficora.fi/en/index/palvelut/fiverkkotunnukset/aakkostenkaytto.html
785
     * (.GR) Greece https://grweb.ics.forth.gr/CharacterTable1_en.jsp
786
     * (.HU) Hungary http://www.domain.hu/domain/English/szabalyzat/szabalyzat.html
787
     * (.INFO) International http://www.nic.info/info/idn
788
     * (.IO) British Indian Ocean Territory http://www.nic.io/IO-IDN-Policy.pdf
789
     * (.IR) Iran http://www.nic.ir/Allowable_Characters_dot-iran
790
     * (.IS) Iceland http://www.isnic.is/domain/rules.php
791
     * (.KR) Korea http://www.iana.org/domains/idn-tables/tables/kr_ko-kr_1.0.html
792
     * (.LI) Liechtenstein https://nic.switch.ch/reg/ocView.action?res=EF6GW2JBPVTG67DLNIQXU234MN6SC33JNQQGI7L6#anhang1
793
     * (.LT) Lithuania http://www.domreg.lt/static/doc/public/idn_symbols-en.pdf
794
     * (.MD) Moldova http://www.register.md/
795
     * (.MUSEUM) International http://www.iana.org/domains/idn-tables/tables/museum_latn_1.0.html
796
     * (.NET) International http://www.verisign.com/information-services/naming-services/internationalized-domain-names/index.html
797
     * (.NO) Norway http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
798
     * (.NU) Niue http://www.worldnames.net/
799
     * (.ORG) International http://www.pir.org/index.php?db=content/FAQs&tbl=FAQs_Registrant&id=2
800
     * (.PE) Peru https://www.nic.pe/nuevas_politicas_faq_2.php
801
     * (.PL) Poland http://www.dns.pl/IDN/allowed_character_sets.pdf
802
     * (.PR) Puerto Rico http://www.nic.pr/idn_rules.asp
803
     * (.PT) Portugal https://online.dns.pt/dns_2008/do?com=DS;8216320233;111;+PAGE(4000058)+K-CAT-CODIGO(C.125)+RCNT(100);
804
     * (.RU) Russia http://www.iana.org/domains/idn-tables/tables/ru_ru-ru_1.0.html
805
     * (.RS) Serbia http://www.iana.org/domains/idn-tables/tables/rs_sr-rs_1.0.pdf
806
     * (.SA) Saudi Arabia http://www.iana.org/domains/idn-tables/tables/sa_ar_1.0.html
807
     * (.SE) Sweden http://www.iis.se/english/IDN_campaignsite.shtml?lang=en
808
     * (.SH) Saint Helena http://www.nic.sh/SH-IDN-Policy.pdf
809
     * (.SJ) Svalbard and Jan Mayen http://www.norid.no/domeneregistrering/idn/idn_nyetegn.en.html
810
     * (.TH) Thailand http://www.iana.org/domains/idn-tables/tables/th_th-th_1.0.html
811
     * (.TM) Turkmenistan http://www.nic.tm/TM-IDN-Policy.pdf
812
     * (.TR) Turkey https://www.nic.tr/index.php
813
     * (.UA) Ukraine http://www.iana.org/domains/idn-tables/tables/ua_cyrl_1.2.html
814
     * (.VE) Venice http://www.iana.org/domains/idn-tables/tables/ve_es_1.0.html
815
     * (.VN) Vietnam http://www.vnnic.vn/english/5-6-300-2-2-04-20071115.htm#1.%20Introduction
816
     *
817
     * @var array
818
     */
819
    protected $_validIdns = array(
820
        'AC'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
821
        'AR'  => array(1 => '/^[\x{002d}0-9a-zà-ãç-êìíñ-õü]{1,63}$/iu'),
822
        'AS'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĸĺļľłńņňŋōŏőœŕŗřśŝşšţťŧũūŭůűųŵŷźż]{1,63}$/iu'),
823
        'AT'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœšž]{1,63}$/iu'),
824
        'BIZ' => 'Hostname/Biz.php',
825
        'BR'  => array(1 => '/^[\x{002d}0-9a-zà-ãçéíó-õúü]{1,63}$/iu'),
826
        'BV'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
827
        'CA'  => array(1 => '/^[\x{002d}0-9a-zàâæçéèêëîïôœùûüÿ\x{00E0}\x{00E2}\x{00E7}\x{00E8}\x{00E9}\x{00EA}\x{00EB}\x{00EE}\x{00EF}\x{00F4}\x{00F9}\x{00FB}\x{00FC}\x{00E6}\x{0153}\x{00FF}]{1,63}$/iu'),
828
        'CAT' => array(1 => '/^[\x{002d}0-9a-z·àç-éíïòóúü]{1,63}$/iu'),
829
        'CH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
830
        'CL'  => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
831
        'CN'  => 'Hostname/Cn.php',
832
        'COM' => 'Zend/Validate/Hostname/Com.php',
833
        'DE'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
834
        'DK'  => array(1 => '/^[\x{002d}0-9a-zäéöüæøå]{1,63}$/iu'),
835
        'ES'  => array(1 => '/^[\x{002d}0-9a-zàáçèéíïñòóúü·]{1,63}$/iu'),
836
        'EU'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
837
            2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
838
            3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu',
839
            4 => '/^[\x{002d}0-9a-zΐάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ]{1,63}$/iu',
840
            5 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюя]{1,63}$/iu',
841
            6 => '/^[\x{002d}0-9a-zἀ-ἇἐ-ἕἠ-ἧἰ-ἷὀ-ὅὐ-ὗὠ-ὧὰ-ώᾀ-ᾇᾐ-ᾗᾠ-ᾧᾰ-ᾴᾶᾷῂῃῄῆῇῐ-ΐῖῗῠ-ῧῲῳῴῶῷ]{1,63}$/iu'),
842
        'FI'  => array(1 => '/^[\x{002d}0-9a-zäåö]{1,63}$/iu'),
843
        'GR'  => array(1 => '/^[\x{002d}0-9a-zΆΈΉΊΌΎ-ΡΣ-ώἀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼῂῃῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲῳῴῶ-ῼ]{1,63}$/iu'),
844
        'HK'  => 'Zend/Validate/Hostname/Cn.php',
845
        'HU'  => array(1 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu'),
846
        'INFO'=> array(1 => '/^[\x{002d}0-9a-zäåæéöøü]{1,63}$/iu',
847
            2 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
848
            3 => '/^[\x{002d}0-9a-záæéíðóöúýþ]{1,63}$/iu',
849
            4 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
850
            5 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
851
            6 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
852
            7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
853
            8 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu'),
854
        'IO'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
855
        'IS'  => array(1 => '/^[\x{002d}0-9a-záéýúíóþæöð]{1,63}$/iu'),
856
        'JP'  => 'Zend/Validate/Hostname/Jp.php',
857
        'KR'  => array(1 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu'),
858
        'LI'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿœ]{1,63}$/iu'),
859
        'LT'  => array(1 => '/^[\x{002d}0-9ąčęėįšųūž]{1,63}$/iu'),
860
        'MD'  => array(1 => '/^[\x{002d}0-9ăâîşţ]{1,63}$/iu'),
861
        'MUSEUM' => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćċčďđēėęěğġģħīįıķĺļľłńņňŋōőœŕŗřśşšţťŧūůűųŵŷźżžǎǐǒǔ\x{01E5}\x{01E7}\x{01E9}\x{01EF}ə\x{0292}ẁẃẅỳ]{1,63}$/iu'),
862
        'NET' => 'Zend/Validate/Hostname/Com.php',
863
        'NO'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
864
        'NU'  => 'Zend/Validate/Hostname/Com.php',
865
        'ORG' => array(1 => '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
866
            2 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
867
            3 => '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
868
            4 => '/^[\x{002d}0-9a-záéíóöúüőű]{1,63}$/iu',
869
            5 => '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
870
            6 => '/^[\x{AC00}-\x{D7A3}]{1,17}$/iu',
871
            7 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu'),
872
        'PE'  => array(1 => '/^[\x{002d}0-9a-zñáéíóúü]{1,63}$/iu'),
873
        'PL'  => array(1 => '/^[\x{002d}0-9a-zāčēģīķļņōŗšūž]{1,63}$/iu',
874
            2 => '/^[\x{002d}а-ик-ш\x{0450}ѓѕјљњќџ]{1,63}$/iu',
875
            3 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
876
            4 => '/^[\x{002d}0-9а-яё\x{04C2}]{1,63}$/iu',
877
            5 => '/^[\x{002d}0-9a-zàáâèéêìíîòóôùúûċġħż]{1,63}$/iu',
878
            6 => '/^[\x{002d}0-9a-zàäåæéêòóôöøü]{1,63}$/iu',
879
            7 => '/^[\x{002d}0-9a-zóąćęłńśźż]{1,63}$/iu',
880
            8 => '/^[\x{002d}0-9a-zàáâãçéêíòóôõúü]{1,63}$/iu',
881
            9 => '/^[\x{002d}0-9a-zâîăşţ]{1,63}$/iu',
882
            10=> '/^[\x{002d}0-9a-záäéíóôúýčďĺľňŕšťž]{1,63}$/iu',
883
            11=> '/^[\x{002d}0-9a-zçë]{1,63}$/iu',
884
            12=> '/^[\x{002d}0-9а-ик-шђјљњћџ]{1,63}$/iu',
885
            13=> '/^[\x{002d}0-9a-zćčđšž]{1,63}$/iu',
886
            14=> '/^[\x{002d}0-9a-zâçöûüğış]{1,63}$/iu',
887
            15=> '/^[\x{002d}0-9a-záéíñóúü]{1,63}$/iu',
888
            16=> '/^[\x{002d}0-9a-zäõöüšž]{1,63}$/iu',
889
            17=> '/^[\x{002d}0-9a-zĉĝĥĵŝŭ]{1,63}$/iu',
890
            18=> '/^[\x{002d}0-9a-zâäéëîô]{1,63}$/iu',
891
            19=> '/^[\x{002d}0-9a-zàáâäåæçèéêëìíîïðñòôöøùúûüýćčłńřśš]{1,63}$/iu',
892
            20=> '/^[\x{002d}0-9a-zäåæõöøüšž]{1,63}$/iu',
893
            21=> '/^[\x{002d}0-9a-zàáçèéìíòóùú]{1,63}$/iu',
894
            22=> '/^[\x{002d}0-9a-zàáéíóöúüőű]{1,63}$/iu',
895
            23=> '/^[\x{002d}0-9ΐά-ώ]{1,63}$/iu',
896
            24=> '/^[\x{002d}0-9a-zàáâåæçèéêëðóôöøüþœ]{1,63}$/iu',
897
            25=> '/^[\x{002d}0-9a-záäéíóöúüýčďěňřšťůž]{1,63}$/iu',
898
            26=> '/^[\x{002d}0-9a-z·àçèéíïòóúü]{1,63}$/iu',
899
            27=> '/^[\x{002d}0-9а-ъьюя\x{0450}\x{045D}]{1,63}$/iu',
900
            28=> '/^[\x{002d}0-9а-яёіў]{1,63}$/iu',
901
            29=> '/^[\x{002d}0-9a-ząčėęįšūųž]{1,63}$/iu',
902
            30=> '/^[\x{002d}0-9a-záäåæéëíðóöøúüýþ]{1,63}$/iu',
903
            31=> '/^[\x{002d}0-9a-zàâæçèéêëîïñôùûüÿœ]{1,63}$/iu',
904
            32=> '/^[\x{002d}0-9а-щъыьэюяёєіїґ]{1,63}$/iu',
905
            33=> '/^[\x{002d}0-9א-ת]{1,63}$/iu'),
906
        'PR'  => array(1 => '/^[\x{002d}0-9a-záéíóúñäëïüöâêîôûàèùæçœãõ]{1,63}$/iu'),
907
        'PT'  => array(1 => '/^[\x{002d}0-9a-záàâãçéêíóôõú]{1,63}$/iu'),
908
        'RS'  => array(1 => '/^[\x{002D}\x{0030}-\x{0039}\x{0061}-\x{007A}\x{0107}\x{010D}\x{0111}\x{0161}\x{017E}]{1,63}$/iu)'),
909
        'RU'  => array(1 => '/^[\x{002d}0-9а-яё]{1,63}$/iu'),
910
        'SA'  => array(1 => '/^[\x{002d}.0-9\x{0621}-\x{063A}\x{0641}-\x{064A}\x{0660}-\x{0669}]{1,63}$/iu'),
911
        'SE'  => array(1 => '/^[\x{002d}0-9a-zäåéöü]{1,63}$/iu'),
912
        'SH'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿăąāćĉčċďđĕěėęēğĝġģĥħĭĩįīıĵķĺľļłńňņŋŏőōœĸŕřŗśŝšşťţŧŭůűũųūŵŷźžż]{1,63}$/iu'),
913
        'SI'  => array(
914
            1 => '/^[\x{002d}0-9a-zà-öø-ÿ]{1,63}$/iu',
915
            2 => '/^[\x{002d}0-9a-zāăąćĉċčďđēĕėęěĝğġģĥħĩīĭįıĵķĺļľŀłńņňʼnŋōŏőœŕŗřśŝšťŧũūŭůűųŵŷźżž]{1,63}$/iu',
916
            3 => '/^[\x{002d}0-9a-zșț]{1,63}$/iu'),
917
        'SJ'  => array(1 => '/^[\x{002d}0-9a-zàáä-éêñ-ôöøüčđńŋšŧž]{1,63}$/iu'),
918
        'TH'  => array(1 => '/^[\x{002d}0-9a-z\x{0E01}-\x{0E3A}\x{0E40}-\x{0E4D}\x{0E50}-\x{0E59}]{1,63}$/iu'),
919
        'TM'  => array(1 => '/^[\x{002d}0-9a-zà-öø-ÿāăąćĉċčďđēėęěĝġģĥħīįĵķĺļľŀłńņňŋőœŕŗřśŝşšţťŧūŭůűųŵŷźżž]{1,63}$/iu'),
920
        'TW'  => 'Zend/Validate/Hostname/Cn.php',
921
        'TR'  => array(1 => '/^[\x{002d}0-9a-zğıüşöç]{1,63}$/iu'),
922
        'UA'  => array(1 => '/^[\x{002d}0-9a-zабвгдежзийклмнопрстуфхцчшщъыьэюяѐёђѓєѕіїјљњћќѝўџґӂʼ]{1,63}$/iu'),
923
        'VE'  => array(1 => '/^[\x{002d}0-9a-záéíóúüñ]{1,63}$/iu'),
924
        'VN'  => array(1 => '/^[ÀÁÂÃÈÉÊÌÍÒÓÔÕÙÚÝàáâãèéêìíòóôõùúýĂăĐđĨĩŨũƠơƯư\x{1EA0}-\x{1EF9}]{1,63}$/iu'),
925
        'ایران' => 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'),
926
        '中国' => 'Zend/Validate/Hostname/Cn.php',
927
        '公司' => 'Zend/Validate/Hostname/Cn.php',
928
        '网络' => 'Zend/Validate/Hostname/Cn.php'
929
    );
930
931
    protected $_idnLength = array(
932
        'BIZ' => array(5 => 17, 11 => 15, 12 => 20),
933
        'CN'  => array(1 => 20),
934
        'COM' => array(3 => 17, 5 => 20),
935
        'HK'  => array(1 => 15),
936
        'INFO'=> array(4 => 17),
937
        'KR'  => array(1 => 17),
938
        'NET' => array(3 => 17, 5 => 20),
939
        'ORG' => array(6 => 17),
940
        'TW'  => array(1 => 20),
941
        'ایران' => array(1 => 30),
942
        '中国' => array(1 => 20),
943
        '公司' => array(1 => 20),
944
        '网络' => array(1 => 20),
945
    );
946
947
    protected $_options = array(
948
        'allow' => self::ALLOW_DNS,
949
        'idn'   => true,
950
        'tld'   => true,
951
        'ip'    => null
952
    );
953
954
    /**
955
     * Sets validator options
956
     *
957
     * @param integer          $allow       OPTIONAL Set what types of hostname to allow (default ALLOW_DNS)
958
     * @param boolean          $validateIdn OPTIONAL Set whether IDN domains are validated (default true)
959
     * @param boolean          $validateTld OPTIONAL Set whether the TLD element of a hostname is validated (default true)
960
     * @param Zend_Validate_Ip $ipValidator OPTIONAL
961
     * @return void
962
     * @see http://www.iana.org/cctld/specifications-policies-cctlds-01apr02.htm  Technical Specifications for ccTLDs
963
     */
964
    public function __construct($options = array())
965
    {
966
        if ($options instanceof Zend_Config) {
0 ignored issues
show
Bug introduced by
The type Zend_Config was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
967
            $options = $options->toArray();
968
        } else if (!is_array($options)) {
969
			$temp = array();
970
971
            $options = func_get_args();
972
            $temp['allow'] = array_shift($options);
973
            if (!empty($options)) {
974
                $temp['idn'] = array_shift($options);
975
            }
976
977
            if (!empty($options)) {
978
                $temp['tld'] = array_shift($options);
979
            }
980
981
            if (!empty($options)) {
982
                $temp['ip'] = array_shift($options);
983
            }
984
985
            $options = $temp;
986
        }
987
988
        $options += $this->_options;
989
        $this->setOptions($options);
990
    }
991
992
    /**
993
     * Returns all set options
994
     *
995
     * @return array
996
     */
997
    public function getOptions()
998
    {
999
        return $this->_options;
1000
    }
1001
1002
    /**
1003
     * Sets the options for this validator
1004
     *
1005
     * @param array $options
1006
     * @return Zend_Validate_Hostname
1007
     */
1008
    public function setOptions($options)
1009
    {
1010
        if (array_key_exists('allow', $options)) {
1011
            $this->setAllow($options['allow']);
1012
        }
1013
1014
        if (array_key_exists('idn', $options)) {
1015
            $this->setValidateIdn($options['idn']);
1016
        }
1017
1018
        if (array_key_exists('tld', $options)) {
1019
            $this->setValidateTld($options['tld']);
1020
        }
1021
1022
        if (array_key_exists('ip', $options)) {
1023
            $this->setIpValidator($options['ip']);
1024
        }
1025
1026
        return $this;
1027
    }
1028
1029
    /**
1030
     * Returns the set ip validator
1031
     *
1032
     * @return Zend_Validate_Ip
1033
     */
1034
    public function getIpValidator()
1035
    {
1036
        return $this->_options['ip'];
1037
    }
1038
1039
    /**
1040
     * @param Zend_Validate_Ip $ipValidator OPTIONAL
1041
     * @return void;
1042
     */
1043
    public function setIpValidator(Zend_Validate_Ip $ipValidator = null)
1044
    {
1045
        if ($ipValidator === null) {
1046
            $ipValidator = new Zend_Validate_Ip();
1047
        }
1048
1049
        $this->_options['ip'] = $ipValidator;
1050
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Zend_Validate_Hostname which is incompatible with the documented return type void.
Loading history...
1051
    }
1052
1053
    /**
1054
     * Returns the allow option
1055
     *
1056
     * @return integer
1057
     */
1058
    public function getAllow()
1059
    {
1060
        return $this->_options['allow'];
1061
    }
1062
1063
    /**
1064
     * Sets the allow option
1065
     *
1066
     * @param  integer $allow
1067
     * @return Zend_Validate_Hostname Provides a fluent interface
1068
     */
1069
    public function setAllow($allow)
1070
    {
1071
        $this->_options['allow'] = $allow;
1072
        return $this;
1073
    }
1074
1075
    /**
1076
     * Returns the set idn option
1077
     *
1078
     * @return boolean
1079
     */
1080
    public function getValidateIdn()
1081
    {
1082
        return $this->_options['idn'];
1083
    }
1084
1085
    /**
1086
     * Set whether IDN domains are validated
1087
     *
1088
     * This only applies when DNS hostnames are validated
1089
     *
1090
     * @param boolean $allowed Set allowed to true to validate IDNs, and false to not validate them
1091
     */
1092
    public function setValidateIdn ($allowed)
1093
    {
1094
        $this->_options['idn'] = (bool) $allowed;
1095
        return $this;
1096
    }
1097
1098
    /**
1099
     * Returns the set tld option
1100
     *
1101
     * @return boolean
1102
     */
1103
    public function getValidateTld()
1104
    {
1105
        return $this->_options['tld'];
1106
    }
1107
1108
    /**
1109
     * Set whether the TLD element of a hostname is validated
1110
     *
1111
     * This only applies when DNS hostnames are validated
1112
     *
1113
     * @param boolean $allowed Set allowed to true to validate TLDs, and false to not validate them
1114
     */
1115
    public function setValidateTld ($allowed)
1116
    {
1117
        $this->_options['tld'] = (bool) $allowed;
1118
        return $this;
1119
    }
1120
1121
    /**
1122
     * Defined by Zend_Validate_Interface
1123
     *
1124
     * Returns true if and only if the $value is a valid hostname with respect to the current allow option
1125
     *
1126
     * @param  string $value
1127
     * @throws Zend_Validate_Exception if a fatal error occurs for validation process
1128
     * @return boolean
1129
     */
1130
    public function isValid($value)
1131
    {
1132
        if (!is_string($value)) {
0 ignored issues
show
introduced by
The condition is_string($value) is always true.
Loading history...
1133
            $this->_error(self::INVALID);
1134
            return false;
1135
        }
1136
1137
        $this->_setValue($value);
1138
        // Check input against IP address schema
1139
        if (preg_match('/^[0-9a-f:.]*$/i', $value) &&
1140
            $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
1141
            if (!($this->_options['allow'] & self::ALLOW_IP)) {
1142
                $this->_error(self::IP_ADDRESS_NOT_ALLOWED);
1143
                return false;
1144
            } else {
1145
                return true;
1146
            }
1147
        }
1148
1149
        // RFC3986 3.2.2 states:
1150
        //
1151
        //     The rightmost domain label of a fully qualified domain name
1152
        //     in DNS may be followed by a single "." and should be if it is
1153
        //     necessary to distinguish between the complete domain name and
1154
        //     some local domain.
1155
        //
1156
        // (see ZF-6363)
1157
1158
        // Local hostnames are allowed to be partitial (ending '.')
1159
        if ($this->_options['allow'] & self::ALLOW_LOCAL) {
1160
            if (substr($value, -1) === '.') {
1161
                $value = substr($value, 0, -1);
1162
                if (substr($value, -1) === '.') {
1163
                    // Empty hostnames (ending '..') are not allowed
1164
                    $this->_error(self::INVALID_LOCAL_NAME);
1165
                    return false;
1166
                }
1167
            }
1168
        }
1169
1170
        $domainParts = explode('.', $value);
1171
1172
        // Prevent partitial IP V4 adresses (ending '.')
1173
        if ((count($domainParts) == 4) && preg_match('/^[0-9.a-e:.]*$/i', $value) &&
1174
            $this->_options['ip']->setTranslator($this->getTranslator())->isValid($value)) {
1175
            $this->_error(self::INVALID_LOCAL_NAME);
1176
        }
1177
1178
        // Check input against DNS hostname schema
1179
        if ((count($domainParts) > 1) && (strlen($value) >= 4) && (strlen($value) <= 254)) {
1180
            $status = false;
1181
1182
            $origenc = PHP_VERSION_ID < 50600
1183
                        ? iconv_get_encoding('internal_encoding')
1184
                        : ini_get('default_charset');
1185
            if (PHP_VERSION_ID < 50600) {
1186
                iconv_set_encoding('internal_encoding', 'UTF-8');
1187
            } else {
1188
                ini_set('default_charset', 'UTF-8');
1189
            }
1190
            do {
1191
                // First check TLD
1192
                $matches = array();
1193
                if (preg_match('/([^.]{2,63})$/i', end($domainParts), $matches) ||
1194
                    (end($domainParts) == 'ایران') || (end($domainParts) == '中国') ||
1195
                    (end($domainParts) == '公司') || (end($domainParts) == '网络')) {
1196
1197
                    reset($domainParts);
1198
1199
                    // Hostname characters are: *(label dot)(label dot label); max 254 chars
1200
                    // label: id-prefix [*ldh{61} id-prefix]; max 63 chars
1201
                    // id-prefix: alpha / digit
1202
                    // ldh: alpha / digit / dash
1203
1204
                    // Match TLD against known list
1205
                    $this->_tld = strtolower($matches[1]);
1206
                    if ($this->_options['tld']) {
1207
                        if (!in_array($this->_tld, $this->_validTlds)) {
1208
                            $this->_error(self::UNKNOWN_TLD);
1209
                            $status = false;
1210
                            break;
1211
                        }
1212
                    }
1213
1214
                    /**
1215
                     * Match against IDN hostnames
1216
                     * Note: Keep label regex short to avoid issues with long patterns when matching IDN hostnames
1217
                     * @see Zend_Validate_Hostname_Interface
1218
                     */
1219
                    $regexChars = array(0 => '/^[a-z0-9\x2d]{1,63}$/i');
1220
                    if ($this->_options['idn'] &&  isset($this->_validIdns[strtoupper($this->_tld)])) {
1221
                        if (is_string($this->_validIdns[strtoupper($this->_tld)])) {
1222
                            $regexChars += include($this->_validIdns[strtoupper($this->_tld)]);
1223
                        } else {
1224
                            $regexChars += $this->_validIdns[strtoupper($this->_tld)];
1225
                        }
1226
                    }
1227
1228
                    // Check each hostname part
1229
                    $check = 0;
1230
                    foreach ($domainParts as $domainPart) {
1231
                        // If some domain part is empty (i.e. zend..com), it's invalid
1232
                        if (empty($domainPart)) {
1233
                            $this->_error(self::INVALID_HOSTNAME);
1234
                            return false;
1235
                        }
1236
1237
                        // Decode Punycode domainnames to IDN
1238
                        if (strpos($domainPart, 'xn--') === 0) {
1239
                            $domainPart = $this->decodePunycode(substr($domainPart, 4));
1240
                            if ($domainPart === false) {
1241
                                return false;
1242
                            }
1243
                        }
1244
1245
                        // Check dash (-) does not start, end or appear in 3rd and 4th positions
1246
                        if ((strpos($domainPart, '-') === 0)
1247
                            || ((strlen($domainPart) > 2) && (strpos($domainPart, '-', 2) == 2) && (strpos($domainPart, '-', 3) == 3))
1248
                            || (strpos($domainPart, '-') === (strlen($domainPart) - 1))) {
1249
                                $this->_error(self::INVALID_DASH);
1250
                            $status = false;
1251
                            break 2;
1252
                        }
1253
1254
                        // Check each domain part
1255
                        $checked = false;
1256
                        foreach($regexChars as $regexKey => $regexChar) {
1257
                            $status = @preg_match($regexChar, $domainPart);
1258
                            if ($status > 0) {
1259
                                $length = 63;
1260
                                if (array_key_exists(strtoupper($this->_tld), $this->_idnLength)
1261
                                    && (array_key_exists($regexKey, $this->_idnLength[strtoupper($this->_tld)]))) {
1262
                                    $length = $this->_idnLength[strtoupper($this->_tld)];
1263
                                }
1264
1265
                                if (iconv_strlen($domainPart, 'UTF-8') > $length) {
1266
                                    $this->_error(self::INVALID_HOSTNAME);
1267
                                } else {
1268
                                    $checked = true;
1269
                                    break;
1270
                                }
1271
                            }
1272
                        }
1273
1274
                        if ($checked) {
1275
                            ++$check;
1276
                        }
1277
                    }
1278
1279
                    // If one of the labels doesn't match, the hostname is invalid
1280
                    if ($check !== count($domainParts)) {
1281
                        $this->_error(self::INVALID_HOSTNAME_SCHEMA);
1282
                        $status = false;
1283
                    }
1284
                } else {
1285
                    // Hostname not long enough
1286
                    $this->_error(self::UNDECIPHERABLE_TLD);
1287
                    $status = false;
1288
                }
1289
            } while (false);
1290
1291
            if (PHP_VERSION_ID < 50600) {
1292
                iconv_set_encoding('internal_encoding', $origenc);
1293
            } else {
1294
                ini_set('default_charset', $origenc);
1295
            }
1296
            // If the input passes as an Internet domain name, and domain names are allowed, then the hostname
1297
            // passes validation
1298
            if ($status && ($this->_options['allow'] & self::ALLOW_DNS)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $status of type false|integer is loosely compared to true; this is ambiguous if the integer can be 0. You might want to explicitly use !== false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
1299
                return true;
1300
            }
1301
        } else if ($this->_options['allow'] & self::ALLOW_DNS) {
1302
            $this->_error(self::INVALID_HOSTNAME);
1303
        }
1304
1305
        // Check for URI Syntax (RFC3986)
1306
        if ($this->_options['allow'] & self::ALLOW_URI) {
1307
            if (preg_match("/^([a-zA-Z0-9-._~!$&\'()*+,;=]|%[[:xdigit:]]{2}){1,254}$/i", $value)) {
1308
                return true;
1309
            } else {
1310
                $this->_error(self::INVALID_URI);
1311
            }
1312
        }
1313
1314
        // Check input against local network name schema; last chance to pass validation
1315
        $regexLocal = '/^(([a-zA-Z0-9\x2d]{1,63}\x2e)*[a-zA-Z0-9\x2d]{1,63}[\x2e]{0,1}){1,254}$/';
1316
        $status = @preg_match($regexLocal, $value);
1317
1318
        // If the input passes as a local network name, and local network names are allowed, then the
1319
        // hostname passes validation
1320
        $allowLocal = $this->_options['allow'] & self::ALLOW_LOCAL;
1321
        if ($status && $allowLocal) {
1322
            return true;
1323
        }
1324
1325
        // If the input does not pass as a local network name, add a message
1326
        if (!$status) {
1327
            $this->_error(self::INVALID_LOCAL_NAME);
1328
        }
1329
1330
        // If local network names are not allowed, add a message
1331
        if ($status && !$allowLocal) {
1332
            $this->_error(self::LOCAL_NAME_NOT_ALLOWED);
1333
        }
1334
1335
        return false;
1336
    }
1337
1338
    /**
1339
     * Decodes a punycode encoded string to it's original utf8 string
1340
     * In case of a decoding failure the original string is returned
1341
     *
1342
     * @param  string $encoded Punycode encoded string to decode
1343
     * @return string
1344
     */
1345
    protected function decodePunycode($encoded)
1346
    {
1347
        if (!preg_match('/^[a-z0-9-]+$/i', $encoded)) {
1348
            // no punycode encoded string
1349
            $this->_error(self::CANNOT_DECODE_PUNYCODE);
1350
            return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1351
        }
1352
1353
        $decoded = array();
1354
        $separator = strrpos($encoded, '-');
1355
        if ($separator > 0) {
1356
            for ($x = 0; $x < $separator; ++$x) {
1357
                // prepare decoding matrix
1358
                $decoded[] = ord($encoded[$x]);
1359
            }
1360
        }
1361
1362
        $lengthd = count($decoded);
1363
        $lengthe = strlen($encoded);
1364
1365
        // decoding
1366
        $init  = true;
1367
        $base  = 72;
1368
        $index = 0;
1369
        $char  = 0x80;
1370
1371
        for ($indexe = ($separator) ? ($separator + 1) : 0; $indexe < $lengthe; ++$lengthd) {
1372
            for ($old_index = $index, $pos = 1, $key = 36; 1 ; $key += 36) {
1373
                $hex   = ord($encoded[$indexe++]);
1374
                $digit = ($hex - 48 < 10) ? $hex - 22
1375
                       : (($hex - 65 < 26) ? $hex - 65
1376
                       : (($hex - 97 < 26) ? $hex - 97
1377
                       : 36));
1378
1379
                $index += $digit * $pos;
1380
                $tag    = ($key <= $base) ? 1 : (($key >= $base + 26) ? 26 : ($key - $base));
1381
                if ($digit < $tag) {
1382
                    break;
1383
                }
1384
1385
                $pos = (int) ($pos * (36 - $tag));
1386
            }
1387
1388
            $delta   = intval($init ? (($index - $old_index) / 700) : (($index - $old_index) / 2));
1389
            $delta  += intval($delta / ($lengthd + 1));
1390
            for ($key = 0; $delta > 910 / 2; $key += 36) {
1391
                $delta = intval($delta / 35);
1392
            }
1393
1394
            $base   = intval($key + 36 * $delta / ($delta + 38));
1395
            $init   = false;
1396
            $char  += (int) ($index / ($lengthd + 1));
1397
            $index %= ($lengthd + 1);
1398
            if ($lengthd > 0) {
1399
                for ($i = $lengthd; $i > $index; $i--) {
1400
                    $decoded[$i] = $decoded[($i - 1)];
1401
                }
1402
            }
1403
1404
            $decoded[$index++] = $char;
1405
        }
1406
1407
        // convert decoded ucs4 to utf8 string
1408
        foreach ($decoded as $key => $value) {
1409
            if ($value < 128) {
1410
                $decoded[$key] = chr($value);
1411
            } elseif ($value < (1 << 11)) {
1412
                $decoded[$key]  = chr(192 + ($value >> 6));
1413
                $decoded[$key] .= chr(128 + ($value & 63));
1414
            } elseif ($value < (1 << 16)) {
1415
                $decoded[$key]  = chr(224 + ($value >> 12));
1416
                $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1417
                $decoded[$key] .= chr(128 + ($value & 63));
1418
            } elseif ($value < (1 << 21)) {
1419
                $decoded[$key]  = chr(240 + ($value >> 18));
1420
                $decoded[$key] .= chr(128 + (($value >> 12) & 63));
1421
                $decoded[$key] .= chr(128 + (($value >> 6) & 63));
1422
                $decoded[$key] .= chr(128 + ($value & 63));
1423
            } else {
1424
                $this->_error(self::CANNOT_DECODE_PUNYCODE);
1425
                return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type string.
Loading history...
1426
            }
1427
        }
1428
1429
        return implode($decoded);
1430
    }
1431
}
1432