20
20
use Pdp \Exception \CouldNotResolveSubDomain ;
21
21
use Pdp \Exception \InvalidLabel ;
22
22
use Pdp \Exception \InvalidLabelKey ;
23
+ use Throwable ;
23
24
use TypeError ;
24
25
use function array_count_values ;
25
26
use function array_keys ;
@@ -82,32 +83,62 @@ final class Domain implements DomainInterface, JsonSerializable
82
83
* @var string|null
83
84
*/
84
85
private $ subDomain ;
85
-
86
+
87
+ /**
88
+ * @var int
89
+ */
90
+ private $ asciiIDNAOption = IDNA_DEFAULT ;
91
+
92
+ /**
93
+ * @var int
94
+ */
95
+ private $ unicodeIDNAOption = IDNA_DEFAULT ;
96
+
97
+ /**
98
+ * @var bool
99
+ */
100
+ private $ isTransitionalDifferent ;
101
+
86
102
/**
87
103
* {@inheritdoc}
88
104
*/
89
105
public static function __set_state (array $ properties ): self
90
106
{
91
- return new self ($ properties ['domain ' ], $ properties ['publicSuffix ' ]);
107
+ return new self (
108
+ $ properties ['domain ' ],
109
+ $ properties ['publicSuffix ' ],
110
+ $ properties ['asciiIDNAOption ' ] ?? IDNA_DEFAULT ,
111
+ $ properties ['unicodeIDNAOption ' ] ?? IDNA_DEFAULT
112
+ );
92
113
}
93
-
114
+
94
115
/**
95
116
* New instance.
96
- *
97
117
* @param null|mixed $domain
98
118
* @param null|PublicSuffix $publicSuffix
99
- */
100
- public function __construct ($ domain = null , PublicSuffix $ publicSuffix = null )
101
- {
102
- $ this ->labels = $ this ->setLabels ($ domain );
119
+ * @param int $asciiIDNAOption
120
+ * @param int $unicodeIDNAOption
121
+ */
122
+ public function __construct (
123
+ $ domain = null ,
124
+ PublicSuffix $ publicSuffix = null ,
125
+ int $ asciiIDNAOption = IDNA_DEFAULT ,
126
+ int $ unicodeIDNAOption = IDNA_DEFAULT
127
+ ) {
128
+ $ this ->asciiIDNAOption = $ asciiIDNAOption ;
129
+ $ this ->unicodeIDNAOption = $ unicodeIDNAOption ;
130
+ $ this ->labels = $ this ->setLabels ($ domain , $ asciiIDNAOption , $ unicodeIDNAOption );
131
+ $ this ->isTransitionalDifferent = $ this ->hasTransitionalDifference ($ domain );
103
132
if ([] !== $ this ->labels ) {
104
133
$ this ->domain = implode ('. ' , array_reverse ($ this ->labels ));
105
134
}
106
- $ this ->publicSuffix = $ this ->setPublicSuffix ($ publicSuffix ?? new PublicSuffix ());
135
+ $ this ->publicSuffix = $ this ->setPublicSuffix (
136
+ $ publicSuffix ?? new PublicSuffix (null , '' , $ asciiIDNAOption , $ unicodeIDNAOption )
137
+ );
107
138
$ this ->registrableDomain = $ this ->setRegistrableDomain ();
108
139
$ this ->subDomain = $ this ->setSubDomain ();
109
140
}
110
-
141
+
111
142
/**
112
143
* Sets the public suffix domain part.
113
144
*
@@ -224,7 +255,7 @@ public function jsonSerialize()
224
255
*/
225
256
public function __debugInfo ()
226
257
{
227
- return [
258
+ return [
228
259
'domain ' => $ this ->domain ,
229
260
'registrableDomain ' => $ this ->registrableDomain ,
230
261
'subDomain ' => $ this ->subDomain ,
@@ -388,12 +419,12 @@ public function toAscii()
388
419
return $ this ;
389
420
}
390
421
391
- $ domain = $ this ->idnToAscii ($ this ->domain );
422
+ $ domain = $ this ->idnToAscii ($ this ->domain , $ this -> asciiIDNAOption );
392
423
if ($ domain === $ this ->domain ) {
393
424
return $ this ;
394
425
}
395
426
396
- return new self ($ domain , $ this ->publicSuffix );
427
+ return new self ($ domain , $ this ->publicSuffix , $ this -> getAsciiIDNAOption (), $ this -> getUnicodeIDNAOption () );
397
428
}
398
429
399
430
/**
@@ -405,7 +436,12 @@ public function toUnicode()
405
436
return $ this ;
406
437
}
407
438
408
- return new self ($ this ->idnToUnicode ($ this ->domain ), $ this ->publicSuffix );
439
+ return new self (
440
+ $ this ->idnToUnicode ($ this ->domain , $ this ->unicodeIDNAOption ),
441
+ $ this ->publicSuffix ,
442
+ $ this ->getAsciiIDNAOption (),
443
+ $ this ->getUnicodeIDNAOption ()
444
+ );
409
445
}
410
446
411
447
/**
@@ -426,15 +462,20 @@ public function toUnicode()
426
462
public function resolve ($ publicSuffix ): self
427
463
{
428
464
if (!$ publicSuffix instanceof PublicSuffix) {
429
- $ publicSuffix = new PublicSuffix ($ publicSuffix );
465
+ $ publicSuffix = new PublicSuffix (
466
+ $ publicSuffix ,
467
+ '' ,
468
+ $ this ->getAsciiIDNAOption (),
469
+ $ this ->getUnicodeIDNAOption ()
470
+ );
430
471
}
431
472
432
473
$ publicSuffix = $ this ->normalize ($ publicSuffix );
433
474
if ($ this ->publicSuffix == $ publicSuffix ) {
434
475
return $ this ;
435
476
}
436
477
437
- return new self ($ this ->domain , $ publicSuffix );
478
+ return new self ($ this ->domain , $ publicSuffix, $ this -> getAsciiIDNAOption (), $ this -> getUnicodeIDNAOption () );
438
479
}
439
480
440
481
/**
@@ -453,7 +494,12 @@ public function resolve($publicSuffix): self
453
494
public function withPublicSuffix ($ publicSuffix ): self
454
495
{
455
496
if (!$ publicSuffix instanceof PublicSuffix) {
456
- $ publicSuffix = new PublicSuffix ($ publicSuffix );
497
+ $ publicSuffix = new PublicSuffix (
498
+ $ publicSuffix ,
499
+ '' ,
500
+ $ this ->getAsciiIDNAOption (),
501
+ $ this ->getUnicodeIDNAOption ()
502
+ );
457
503
}
458
504
459
505
$ publicSuffix = $ this ->normalize ($ publicSuffix );
@@ -463,10 +509,15 @@ public function withPublicSuffix($publicSuffix): self
463
509
464
510
$ domain = implode ('. ' , array_reverse (array_slice ($ this ->labels , count ($ this ->publicSuffix ))));
465
511
if (null === $ publicSuffix ->getContent ()) {
466
- return new self ($ domain );
512
+ return new self ($ domain, null , $ this -> getAsciiIDNAOption (), $ this -> getUnicodeIDNAOption () );
467
513
}
468
514
469
- return new self ($ domain .'. ' .$ publicSuffix ->getContent (), $ publicSuffix );
515
+ return new self (
516
+ $ domain .'. ' .$ publicSuffix ->getContent (),
517
+ $ publicSuffix ,
518
+ $ this ->getAsciiIDNAOption (),
519
+ $ this ->getUnicodeIDNAOption ()
520
+ );
470
521
}
471
522
472
523
@@ -494,10 +545,20 @@ public function withSubDomain($subDomain): self
494
545
}
495
546
496
547
if (null === $ subDomain ) {
497
- return new self ($ this ->registrableDomain , $ this ->publicSuffix );
548
+ return new self (
549
+ $ this ->registrableDomain ,
550
+ $ this ->publicSuffix ,
551
+ $ this ->getAsciiIDNAOption (),
552
+ $ this ->getUnicodeIDNAOption ()
553
+ );
498
554
}
499
555
500
- return new self ($ subDomain .'. ' .$ this ->registrableDomain , $ this ->publicSuffix );
556
+ return new self (
557
+ $ subDomain .'. ' .$ this ->registrableDomain ,
558
+ $ this ->publicSuffix ,
559
+ $ this ->getAsciiIDNAOption (),
560
+ $ this ->getUnicodeIDNAOption ()
561
+ );
501
562
}
502
563
503
564
/**
@@ -529,10 +590,10 @@ private function normalizeContent($domain)
529
590
}
530
591
531
592
if (preg_match (self ::REGEXP_IDN_PATTERN , $ this ->domain )) {
532
- return $ this ->idnToUnicode ($ domain );
593
+ return $ this ->idnToUnicode ($ domain, $ this -> unicodeIDNAOption );
533
594
}
534
595
535
- return $ this ->idnToAscii ($ domain );
596
+ return $ this ->idnToAscii ($ domain, $ this -> asciiIDNAOption );
536
597
}
537
598
538
599
/**
@@ -605,10 +666,20 @@ public function withLabel(int $key, $label): self
605
666
ksort ($ labels );
606
667
607
668
if (null !== $ this ->publicSuffix ->getLabel ($ key )) {
608
- return new self (implode ('. ' , array_reverse ($ labels )));
669
+ return new self (
670
+ implode ('. ' , array_reverse ($ labels )),
671
+ null ,
672
+ $ this ->getAsciiIDNAOption (),
673
+ $ this ->getUnicodeIDNAOption ()
674
+ );
609
675
}
610
676
611
- return new self (implode ('. ' , array_reverse ($ labels )), $ this ->publicSuffix );
677
+ return new self (
678
+ implode ('. ' , array_reverse ($ labels )),
679
+ $ this ->publicSuffix ,
680
+ $ this ->getAsciiIDNAOption (),
681
+ $ this ->getUnicodeIDNAOption ()
682
+ );
612
683
}
613
684
614
685
/**
@@ -651,15 +722,47 @@ public function withoutLabel(int $key, int ...$keys): self
651
722
}
652
723
653
724
if ([] === $ labels ) {
654
- return new self ();
725
+ return new self (null , null , $ this -> getAsciiIDNAOption (), $ this -> getUnicodeIDNAOption () );
655
726
}
656
727
657
728
$ domain = implode ('. ' , array_reverse ($ labels ));
658
729
$ psContent = $ this ->publicSuffix ->getContent ();
659
730
if (null === $ psContent || '. ' .$ psContent !== substr ($ domain , - strlen ($ psContent ) - 1 )) {
660
- return new self ($ domain );
731
+ return new self ($ domain, null , $ this -> getAsciiIDNAOption (), $ this -> getUnicodeIDNAOption () );
661
732
}
662
733
663
- return new self ($ domain , $ this ->publicSuffix );
734
+ return new self ($ domain , $ this ->publicSuffix , $ this ->getAsciiIDNAOption (), $ this ->getUnicodeIDNAOption ());
735
+ }
736
+
737
+
738
+ public function getAsciiIDNAOption (): int
739
+ {
740
+ return $ this ->asciiIDNAOption ;
741
+ }
742
+
743
+ public function getUnicodeIDNAOption (): int
744
+ {
745
+ return $ this ->unicodeIDNAOption ;
746
+ }
747
+ /**
748
+ * Set IDNA_* options for functions idn_to_ascii, idn_to_utf.
749
+ * @see https://www.php.net/manual/en/intl.constants.php
750
+ * @param int $forAscii
751
+ * @param int $forUnicode
752
+ * @return $this
753
+ */
754
+ public function withIDNAOptions (int $ forAscii , int $ forUnicode )
755
+ {
756
+ return new self ($ this ->domain , $ this ->publicSuffix , $ forAscii , $ forUnicode );
757
+ }
758
+
759
+ /**
760
+ * return true if domain contains deviation characters.
761
+ * @see http://unicode.org/reports/tr46/#Transition_Considerations
762
+ * @return bool
763
+ **/
764
+ public function isTransitionalDifferent (): bool
765
+ {
766
+ return $ this ->isTransitionalDifferent ;
664
767
}
665
768
}
0 commit comments