Skip to content

Commit e510d8f

Browse files
authored
Merge pull request #236 from Insolita/idna_options
Idna options
2 parents eaf6017 + e99bc5e commit e510d8f

11 files changed

+714
-155
lines changed

src/Domain.php

Lines changed: 130 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -82,32 +82,62 @@ final class Domain implements DomainInterface, JsonSerializable
8282
* @var string|null
8383
*/
8484
private $subDomain;
85-
85+
86+
/**
87+
* @var int
88+
*/
89+
private $asciiIDNAOption = IDNA_DEFAULT;
90+
91+
/**
92+
* @var int
93+
*/
94+
private $unicodeIDNAOption = IDNA_DEFAULT;
95+
96+
/**
97+
* @var bool
98+
*/
99+
private $isTransitionalDifferent;
100+
86101
/**
87102
* {@inheritdoc}
88103
*/
89104
public static function __set_state(array $properties): self
90105
{
91-
return new self($properties['domain'], $properties['publicSuffix']);
106+
return new self(
107+
$properties['domain'],
108+
$properties['publicSuffix'],
109+
$properties['asciiIDNAOption'] ?? IDNA_DEFAULT,
110+
$properties['unicodeIDNAOption'] ?? IDNA_DEFAULT
111+
);
92112
}
93-
113+
94114
/**
95115
* New instance.
96-
*
97116
* @param null|mixed $domain
98117
* @param null|PublicSuffix $publicSuffix
99-
*/
100-
public function __construct($domain = null, PublicSuffix $publicSuffix = null)
101-
{
102-
$this->labels = $this->setLabels($domain);
118+
* @param int $asciiIDNAOption
119+
* @param int $unicodeIDNAOption
120+
*/
121+
public function __construct(
122+
$domain = null,
123+
PublicSuffix $publicSuffix = null,
124+
int $asciiIDNAOption = IDNA_DEFAULT,
125+
int $unicodeIDNAOption = IDNA_DEFAULT
126+
) {
127+
$this->asciiIDNAOption = $asciiIDNAOption;
128+
$this->unicodeIDNAOption = $unicodeIDNAOption;
129+
$this->labels = $this->setLabels($domain, $asciiIDNAOption, $unicodeIDNAOption);
130+
$this->isTransitionalDifferent = $this->hasTransitionalDifference($domain);
103131
if ([] !== $this->labels) {
104132
$this->domain = implode('.', array_reverse($this->labels));
105133
}
106-
$this->publicSuffix = $this->setPublicSuffix($publicSuffix ?? new PublicSuffix());
134+
$this->publicSuffix = $this->setPublicSuffix(
135+
$publicSuffix ?? new PublicSuffix(null, '', $asciiIDNAOption, $unicodeIDNAOption)
136+
);
107137
$this->registrableDomain = $this->setRegistrableDomain();
108138
$this->subDomain = $this->setSubDomain();
109139
}
110-
140+
111141
/**
112142
* Sets the public suffix domain part.
113143
*
@@ -224,7 +254,7 @@ public function jsonSerialize()
224254
*/
225255
public function __debugInfo()
226256
{
227-
return [
257+
return [
228258
'domain' => $this->domain,
229259
'registrableDomain' => $this->registrableDomain,
230260
'subDomain' => $this->subDomain,
@@ -388,12 +418,12 @@ public function toAscii()
388418
return $this;
389419
}
390420

391-
$domain = $this->idnToAscii($this->domain);
421+
$domain = $this->idnToAscii($this->domain, $this->asciiIDNAOption);
392422
if ($domain === $this->domain) {
393423
return $this;
394424
}
395425

396-
return new self($domain, $this->publicSuffix);
426+
return new self($domain, $this->publicSuffix, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
397427
}
398428

399429
/**
@@ -405,7 +435,12 @@ public function toUnicode()
405435
return $this;
406436
}
407437

408-
return new self($this->idnToUnicode($this->domain), $this->publicSuffix);
438+
return new self(
439+
$this->idnToUnicode($this->domain, $this->unicodeIDNAOption),
440+
$this->publicSuffix,
441+
$this->getAsciiIDNAOption(),
442+
$this->getUnicodeIDNAOption()
443+
);
409444
}
410445

411446
/**
@@ -426,15 +461,20 @@ public function toUnicode()
426461
public function resolve($publicSuffix): self
427462
{
428463
if (!$publicSuffix instanceof PublicSuffix) {
429-
$publicSuffix = new PublicSuffix($publicSuffix);
464+
$publicSuffix = new PublicSuffix(
465+
$publicSuffix,
466+
'',
467+
$this->getAsciiIDNAOption(),
468+
$this->getUnicodeIDNAOption()
469+
);
430470
}
431471

432472
$publicSuffix = $this->normalize($publicSuffix);
433473
if ($this->publicSuffix == $publicSuffix) {
434474
return $this;
435475
}
436476

437-
return new self($this->domain, $publicSuffix);
477+
return new self($this->domain, $publicSuffix, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
438478
}
439479

440480
/**
@@ -453,7 +493,12 @@ public function resolve($publicSuffix): self
453493
public function withPublicSuffix($publicSuffix): self
454494
{
455495
if (!$publicSuffix instanceof PublicSuffix) {
456-
$publicSuffix = new PublicSuffix($publicSuffix);
496+
$publicSuffix = new PublicSuffix(
497+
$publicSuffix,
498+
'',
499+
$this->getAsciiIDNAOption(),
500+
$this->getUnicodeIDNAOption()
501+
);
457502
}
458503

459504
$publicSuffix = $this->normalize($publicSuffix);
@@ -463,10 +508,15 @@ public function withPublicSuffix($publicSuffix): self
463508

464509
$domain = implode('.', array_reverse(array_slice($this->labels, count($this->publicSuffix))));
465510
if (null === $publicSuffix->getContent()) {
466-
return new self($domain);
511+
return new self($domain, null, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
467512
}
468513

469-
return new self($domain.'.'.$publicSuffix->getContent(), $publicSuffix);
514+
return new self(
515+
$domain.'.'.$publicSuffix->getContent(),
516+
$publicSuffix,
517+
$this->getAsciiIDNAOption(),
518+
$this->getUnicodeIDNAOption()
519+
);
470520
}
471521

472522

@@ -494,10 +544,20 @@ public function withSubDomain($subDomain): self
494544
}
495545

496546
if (null === $subDomain) {
497-
return new self($this->registrableDomain, $this->publicSuffix);
547+
return new self(
548+
$this->registrableDomain,
549+
$this->publicSuffix,
550+
$this->getAsciiIDNAOption(),
551+
$this->getUnicodeIDNAOption()
552+
);
498553
}
499554

500-
return new self($subDomain.'.'.$this->registrableDomain, $this->publicSuffix);
555+
return new self(
556+
$subDomain.'.'.$this->registrableDomain,
557+
$this->publicSuffix,
558+
$this->getAsciiIDNAOption(),
559+
$this->getUnicodeIDNAOption()
560+
);
501561
}
502562

503563
/**
@@ -529,10 +589,10 @@ private function normalizeContent($domain)
529589
}
530590

531591
if (preg_match(self::REGEXP_IDN_PATTERN, $this->domain)) {
532-
return $this->idnToUnicode($domain);
592+
return $this->idnToUnicode($domain, $this->unicodeIDNAOption);
533593
}
534594

535-
return $this->idnToAscii($domain);
595+
return $this->idnToAscii($domain, $this->asciiIDNAOption);
536596
}
537597

538598
/**
@@ -605,10 +665,20 @@ public function withLabel(int $key, $label): self
605665
ksort($labels);
606666

607667
if (null !== $this->publicSuffix->getLabel($key)) {
608-
return new self(implode('.', array_reverse($labels)));
668+
return new self(
669+
implode('.', array_reverse($labels)),
670+
null,
671+
$this->getAsciiIDNAOption(),
672+
$this->getUnicodeIDNAOption()
673+
);
609674
}
610675

611-
return new self(implode('.', array_reverse($labels)), $this->publicSuffix);
676+
return new self(
677+
implode('.', array_reverse($labels)),
678+
$this->publicSuffix,
679+
$this->getAsciiIDNAOption(),
680+
$this->getUnicodeIDNAOption()
681+
);
612682
}
613683

614684
/**
@@ -651,15 +721,47 @@ public function withoutLabel(int $key, int ...$keys): self
651721
}
652722

653723
if ([] === $labels) {
654-
return new self();
724+
return new self(null, null, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
655725
}
656726

657727
$domain = implode('.', array_reverse($labels));
658728
$psContent = $this->publicSuffix->getContent();
659729
if (null === $psContent || '.'.$psContent !== substr($domain, - strlen($psContent) - 1)) {
660-
return new self($domain);
730+
return new self($domain, null, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
661731
}
662732

663-
return new self($domain, $this->publicSuffix);
733+
return new self($domain, $this->publicSuffix, $this->getAsciiIDNAOption(), $this->getUnicodeIDNAOption());
734+
}
735+
736+
737+
public function getAsciiIDNAOption(): int
738+
{
739+
return $this->asciiIDNAOption;
740+
}
741+
742+
public function getUnicodeIDNAOption(): int
743+
{
744+
return $this->unicodeIDNAOption;
745+
}
746+
/**
747+
* Set IDNA_* options for functions idn_to_ascii, idn_to_utf.
748+
* @see https://www.php.net/manual/en/intl.constants.php
749+
* @param int $forAscii
750+
* @param int $forUnicode
751+
* @return $this
752+
*/
753+
public function withIDNAOptions(int $forAscii, int $forUnicode)
754+
{
755+
return new self($this->domain, $this->publicSuffix, $forAscii, $forUnicode);
756+
}
757+
758+
/**
759+
* return true if domain contains deviation characters.
760+
* @see http://unicode.org/reports/tr46/#Transition_Considerations
761+
* @return bool
762+
**/
763+
public function isTransitionalDifferent(): bool
764+
{
765+
return $this->isTransitionalDifferent;
664766
}
665767
}

0 commit comments

Comments
 (0)