Skip to content

Commit f977096

Browse files
committed
Improve Package
- add Pdp\Domain::append - add Pdp\Domain::prepend Improve Domain and PublicSuffix validation methods
1 parent 219b379 commit f977096

File tree

7 files changed

+206
-83
lines changed

7 files changed

+206
-83
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@ All Notable changes to `PHP Domain Parser` **5.x** series will be documented in
99
- `Pdp\PublicSuffixListSection` interface implemented by `Pdp\Rules` and `Pdp\PublicSuffix`
1010
- `Pdp\DomainInterface` interface implemented by `Pdp\Domain` and `Pdp\PublicSuffix`
1111
- `Pdp\Domain::getContent` replaces `Pdp\Domain::getDomain`
12+
- `Pdp\Domain::withLabel` adds a new label to the `Pdp\Domain`.
13+
- `Pdp\Domain::withoutLabel` removes labels from the `Pdp\Domain`.
1214
- `Pdp\Domain::withPublicSuffix` updates the `Pdp\Domain` public suffix part.
1315
- `Pdp\Domain::withSubDomain` updates the `Pdp\Domain` sub domain part.
14-
- `Pdp\Domain::withLabel` adds a new label to the `Pdp\Domain`.
15-
- `Pdp\Domain::withoutLabels` removes labels from the `Pdp\Domain`.
16+
- `Pdp\Domain::append` appends a label to `Pdp\Domain`.
17+
- `Pdp\Domain::prepend` prepends a label to `Pdp\Domain`.
1618
- `Pdp\Domain::resolve` attach a public suffix to the `Pdp\Domain`.
1719
- `Pdp\Domain::isResolvable` tells whether the current `Pdp\Domain` can have a public suffix attached to it or not.
1820
- `Pdp\PublicSuffix::createFromDomain` returns a new `Pdp\PublicSuffix` object from a `Pdp\Domain`object

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public function Domain::toUnicode(): self
113113
public function Domain::withPublicSuffix($publicSuffix): self
114114
public function Domain::withSubDomain($subDomain): self
115115
public function Domain::withLabel(int $key, $label): self
116-
public function Domain::withoutLabels(int $key, int ...$keys): self
116+
public function Domain::withoutLabel(int $key, int ...$keys): self
117117
public function Domain::resolve($publicSuffix): self
118118
~~~
119119

data/pdp-PSL_FULL_5a3cc7f81795bb2e48e848af42d287b4.cache

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

src/Domain.php

Lines changed: 111 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -105,13 +105,13 @@ private function setPublicSuffix(PublicSuffix $publicSuffix): PublicSuffix
105105
}
106106

107107
$publicSuffix = $this->normalize($publicSuffix);
108-
$publicSuffixContent = $publicSuffix->getContent();
109-
if ($this->domain === $publicSuffixContent) {
110-
throw new Exception(sprintf('The public suffix `%s` can not be equal to the domain name `%s`', $publicSuffixContent, $this->domain));
108+
$psContent = $publicSuffix->getContent();
109+
if ($this->domain === $psContent) {
110+
throw new Exception(sprintf('The public suffix `%s` can not be equal to the domain name `%s`', $psContent, $this->domain));
111111
}
112112

113-
if ('.'.$publicSuffixContent !== substr($this->domain, - strlen($publicSuffixContent) - 1)) {
114-
throw new Exception(sprintf('The public suffix `%s` can not be assign to the domain name `%s`', $publicSuffixContent, $this->domain));
113+
if ('.'.$psContent !== substr($this->domain, - strlen($psContent) - 1)) {
114+
throw new Exception(sprintf('The public suffix `%s` can not be assign to the domain name `%s`', $psContent, $this->domain));
115115
}
116116

117117
return $publicSuffix;
@@ -193,6 +193,14 @@ public function getIterator()
193193
* {@inheritdoc}
194194
*/
195195
public function jsonSerialize()
196+
{
197+
return $this->__debugInfo();
198+
}
199+
200+
/**
201+
* {@inheritdoc}
202+
*/
203+
public function __debugInfo()
196204
{
197205
return [
198206
'domain' => $this->domain,
@@ -205,14 +213,6 @@ public function jsonSerialize()
205213
];
206214
}
207215

208-
/**
209-
* {@inheritdoc}
210-
*/
211-
public function __debugInfo()
212-
{
213-
return $this->jsonSerialize();
214-
}
215-
216216
/**
217217
* {@inheritdoc}
218218
*/
@@ -433,18 +433,52 @@ public function withSubDomain($subDomain): self
433433
throw new Exception('A subdomain can not be added to a domain without a public suffix part.');
434434
}
435435

436-
if (!$subDomain instanceof PublicSuffix) {
437-
$subDomain = new PublicSuffix($subDomain);
436+
$subDomain = $this->filterSubDomain($subDomain);
437+
$subLabels = [];
438+
if (null !== $subDomain) {
439+
static $pattern = '/[^\x20-\x7f]/';
440+
$method = !preg_match($pattern, $this->domain) ? 'idnToAscii' : 'idnToUnicode';
441+
442+
$subDomain = $this->$method($subDomain);
443+
$subLabels = array_reverse(explode('.', $subDomain));
438444
}
439445

440-
$subDomain = $this->normalize($subDomain);
441-
if ($this->subDomain === $subDomain->getContent()) {
446+
if ($this->subDomain === $subDomain) {
442447
return $this;
443448
}
444449

445-
$labels = array_merge(array_slice($this->labels, 0, count($this->publicSuffix) + 1), iterator_to_array($subDomain));
450+
$labels = array_merge(
451+
array_slice($this->labels, 0, count($this->publicSuffix) + 1),
452+
$subLabels
453+
);
454+
455+
return new self(implode('.', array_reverse($labels)), $this->publicSuffix);
456+
}
457+
458+
/**
459+
* Filter a subdomain to update the domain part.
460+
*
461+
* @param mixed $subDomain
462+
*
463+
* @throws TypeError if the sub domain can not be converted
464+
*
465+
* @return string|null
466+
*/
467+
private function filterSubDomain($subDomain)
468+
{
469+
if ($subDomain instanceof DomainInterface) {
470+
return $subDomain->getContent();
471+
}
472+
473+
if (null === $subDomain) {
474+
return $subDomain;
475+
}
476+
477+
if (is_scalar($subDomain) || method_exists($subDomain, '__toString')) {
478+
return (string) $subDomain;
479+
}
446480

447-
return new self(implode('.', array_reverse(array_values($labels))), $this->publicSuffix);
481+
throw new TypeError(sprintf('The label must be a scalar, a stringable object or NULL, `%s` given', gettype($subDomain)));
448482
}
449483

450484
/**
@@ -461,22 +495,53 @@ public function withSubDomain($subDomain): self
461495
*/
462496
public function withPublicSuffix($publicSuffix): self
463497
{
464-
if (!$publicSuffix instanceof PublicSuffix) {
465-
$publicSuffix = new PublicSuffix($publicSuffix);
466-
}
467-
468498
if (null === $this->publicSuffix->getContent()) {
469499
throw new Exception('A public suffix can not be added to a domain without a public suffix part.');
470500
}
471501

502+
if (!$publicSuffix instanceof PublicSuffix) {
503+
$publicSuffix = new PublicSuffix($publicSuffix);
504+
}
505+
472506
$publicSuffix = $this->normalize($publicSuffix);
473507
if ($this->publicSuffix == $publicSuffix) {
474508
return $this;
475509
}
476510

477-
$labels = array_merge(iterator_to_array($publicSuffix), array_slice($this->labels, count($this->publicSuffix)));
511+
$labels = array_merge(
512+
iterator_to_array($publicSuffix),
513+
array_slice($this->labels, count($this->publicSuffix))
514+
);
478515

479-
return new self(implode('.', array_reverse(array_values($labels))), $publicSuffix);
516+
return new self(implode('.', array_reverse($labels)), $publicSuffix);
517+
}
518+
519+
/**
520+
* Appends a label to the domain.
521+
*
522+
* @see ::withLabel
523+
*
524+
* @param mixed $label
525+
*
526+
* @return self
527+
*/
528+
public function prepend($label): self
529+
{
530+
return $this->withLabel(count($this->labels), $label);
531+
}
532+
533+
/**
534+
* Prepends a label to the domain.
535+
*
536+
* @see ::withLabel
537+
*
538+
* @param mixed $label
539+
*
540+
* @return self
541+
*/
542+
public function append($label): self
543+
{
544+
return $this->withLabel(- count($this->labels) - 1, $label);
480545
}
481546

482547
/**
@@ -498,40 +563,33 @@ public function withPublicSuffix($publicSuffix): self
498563
*/
499564
public function withLabel(int $key, $label): self
500565
{
501-
if (null === $label) {
502-
throw new TypeError('The label must be a scalar or a stringable object `NULL` given');
503-
}
504-
505-
if (!$label instanceof Domain) {
506-
$label = new Domain($label);
507-
}
508-
509566
$nb_labels = count($this->labels);
510-
$offset = filter_var($key, FILTER_VALIDATE_INT, ['options' => ['min_range' => - $nb_labels - 1, 'max_range' => $nb_labels]]);
511-
if (false === $offset) {
567+
if ($key < - $nb_labels - 1 || $key > $nb_labels) {
512568
throw new Exception(sprintf('the given key `%s` is invalid', $key));
513569
}
514570

515-
if (0 > $offset) {
516-
$offset = $nb_labels + $offset;
571+
if (0 > $key) {
572+
$key = $nb_labels + $key;
517573
}
518574

519-
if (($this->labels[$offset] ?? null) === (string) $label) {
520-
return $this;
575+
if (!is_scalar($label) && !method_exists($label, '__toString')) {
576+
throw new TypeError(sprintf('The label must be a scalar or a stringable object `%s` given', gettype($label)));
521577
}
522578

523-
if (null !== $this->domain) {
524-
static $pattern = '/[^\x20-\x7f]/';
525-
$label = !preg_match($pattern, $this->domain) ? $label->toAscii() : $label->toUnicode();
579+
static $pattern = '/[^\x20-\x7f]/';
580+
$method = !preg_match($pattern, $this->domain) ? 'idnToAscii' : 'idnToUnicode';
581+
$label = $this->$method((string) $label);
582+
if (($this->labels[$key] ?? null) === $label) {
583+
return $this;
526584
}
527585

528586
$labels = $this->labels;
529-
$labels[$offset] = (string) $label;
587+
$labels[$key] = $label;
530588
ksort($labels);
531589

532590
return new self(
533-
implode('.', array_reverse(array_values($labels))),
534-
null === $this->publicSuffix->getLabel($offset) ? $this->publicSuffix : null
591+
implode('.', array_reverse($labels)),
592+
null === $this->publicSuffix->getLabel($key) ? $this->publicSuffix : null
535593
);
536594
}
537595

@@ -551,25 +609,23 @@ public function withLabel(int $key, $label): self
551609
*
552610
* @return self
553611
*/
554-
public function withoutLabels(int $key, int ...$keys): self
612+
public function withoutLabel(int $key, int ...$keys): self
555613
{
556614
array_unshift($keys, $key);
557615
$nb_labels = count($this->labels);
558-
$options = ['options' => ['min_range' => - $nb_labels, 'max_range' => $nb_labels - 1]];
559-
$mapper = function (int $key) use ($options, $nb_labels): int {
560-
if (false === ($offset = filter_var($key, FILTER_VALIDATE_INT, $options))) {
616+
$mapper = function (int $key) use ($nb_labels): int {
617+
if (- $nb_labels > $key || $nb_labels - 1 < $key) {
561618
throw new Exception(sprintf('the key `%s` is invalid', $key));
562619
}
563620

564-
if (0 > $offset) {
565-
return $nb_labels + $offset;
621+
if (0 > $key) {
622+
return $nb_labels + $key;
566623
}
567624

568-
return $offset;
625+
return $key;
569626
};
570627

571628
$deleted_keys = array_keys(array_count_values(array_map($mapper, $keys)));
572-
573629
$filter = function ($key) use ($deleted_keys): bool {
574630
return !in_array($key, $deleted_keys, true);
575631
};
@@ -580,11 +636,8 @@ public function withoutLabels(int $key, int ...$keys): self
580636
}
581637

582638
$domain = implode('.', array_reverse(array_values($labels)));
583-
$publicSuffixContent = $this->publicSuffix->getContent();
584-
585-
if (null === $publicSuffixContent ||
586-
'.'.$publicSuffixContent !== substr($domain, - strlen($publicSuffixContent) - 1)
587-
) {
639+
$psContent = $this->publicSuffix->getContent();
640+
if (null === $psContent || '.'.$psContent !== substr($domain, - strlen($psContent) - 1)) {
588641
return new self($domain);
589642
}
590643

src/PublicSuffix.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,20 @@ public function getIterator()
148148
*/
149149
public function jsonSerialize()
150150
{
151-
return [
152-
'publicSuffix' => $this->publicSuffix,
153-
'isKnown' => $this->isKnown(),
154-
'isICANN' => $this->isICANN(),
155-
'isPrivate' => $this->isPrivate(),
156-
];
151+
return $this->__debugInfo();
157152
}
158153

159154
/**
160155
* {@inheritdoc}
161156
*/
162157
public function __debugInfo()
163158
{
164-
return $this->jsonSerialize();
159+
return [
160+
'publicSuffix' => $this->publicSuffix,
161+
'isKnown' => $this->isKnown(),
162+
'isICANN' => $this->isICANN(),
163+
'isPrivate' => $this->isPrivate(),
164+
];
165165
}
166166

167167
/**

0 commit comments

Comments
 (0)