Skip to content

Commit 7db81b1

Browse files
committed
simplify withPublicSuffix usage
1 parent f54d639 commit 7db81b1

19 files changed

+799
-880
lines changed

.php_cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ return PhpCsFixer\Config::create()
2424
'phpdoc_order' => true,
2525
'phpdoc_scalar' => true,
2626
'phpdoc_to_comment' => true,
27+
'phpdoc_summary' => true,
2728
'psr0' => true,
2829
'psr4' => true,
2930
'return_type_declaration' => ['space_before' => 'none'],

CHANGELOG.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ All Notable changes to `PHP Domain Parser` **5.x** series will be documented in
66

77
### Added
88

9+
- `Pdp\SectionInterface` interface implemented by `Pdp\Rules` and `Pdp\PublicSuffix`
910
- `Pdp\DomainInterface` interface implemented by `Pdp\Domain` and `Pdp\PublicSuffix`
10-
- `Pdp\Domain::getContent` returns the Domain name value replaces `Pdp\Domain::getDomain`
1111
- `Pdp\Domain` implements the `Countable` interface.
12-
- `Pdp\Domain::withPublicSuffix` returns a new Domain object with a different Public Suffix
12+
- `Pdp\Domain::getContent` returns the Domain name value replaces `Pdp\Domain::getDomain`
13+
- `Pdp\Domain::withPublicSuffix` updates the `Pdp\Domain` public suffix part.
14+
- `Pdp\Domain::withSubDomain` updates the `Pdp\Domain` sub domain part.
15+
- `Pdp\Domain::withLabel` adds a new label to the `Pdp\Domain`.
16+
- `Pdp\Domain::withoutLabel` removes a label from the `Pdp\Domain`.
1317
- `Pdp\PublicSuffix::createFromDomain` returns a new `Pdp\PublicSuffix` object from a `Pdp\Domain`object
14-
- `Pdp\append` append a host to a domain name
15-
- `Pdp\prepend` prepend a host to a domain name
16-
- `Pdp\replace` replace a label from the domain name
17-
- `Pdp\public_suffix_replace` replace the domain name public suffix
1818

1919
### Fixed
2020

README.md

Lines changed: 101 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -42,79 +42,129 @@ Installation
4242
$ composer require jeremykendall/php-domain-parser
4343
~~~
4444

45-
Documentation
45+
Usage
4646
--------
4747

48-
### Domain name resolution
49-
50-
The `Pdp\Rules` object is responsible for public suffix resolution for a given domain.
48+
### Parsing a domain name.
5149

5250
~~~php
5351
<?php
5452

55-
namespace Pdp;
53+
use Pdp\Cache;
54+
use Pdp\CurlHttpClient;
55+
use Pdp\Manager;
5656

57-
final class Rules
58-
{
59-
const ALL_DOMAINS = 'ALL_DOMAINS';
60-
const ICANN_DOMAINS = 'ICANN_DOMAINS';
61-
const PRIVATE_DOMAINS = 'PRIVATE_DOMAINS';
62-
63-
public static function createFromPath(string $path, $context = null): self
64-
public static function createFromString(string $content): self
65-
public function __construct(array $rules)
66-
public function getPublicSuffix($domain = null, string $section = self::ALL_DOMAINS): PublicSuffix
67-
public function resolve($domain = null, string $section = self::ALL_DOMAINS): Domain
68-
}
57+
$manager = new Manager(new Cache(), new CurlHttpClient());
58+
$rules = $manager->getRules(); //$rules is a Pdp\Rules object
59+
60+
$domain = $rules->resolve('www.ulb.ac.be');
61+
echo json_encode($domain, JSON_PRETTY_PRINT);
62+
// returns
63+
// {
64+
// "domain": "www.ulb.ac.be",
65+
// "registrableDomain": "ulb.ac.be",
66+
// "subDomain": "www",
67+
// "publicSuffix": "ac.be",
68+
// "isKnown": true,
69+
// "isICANN": true,
70+
// "isPrivate": false
71+
// }
72+
73+
$publicSuffix = $rules->getPublicSuffix('www.ulb.ac.be');
74+
echo json_encode($publicSuffix, JSON_PRETTY_PRINT);
75+
// returns
76+
// {
77+
// "publicSuffix": "ac.be",
78+
// "isKnown": true,
79+
// "isICANN": true,
80+
// "isPrivate": false
81+
// }
6982
~~~
7083

71-
#### Usage
84+
Using the above code you can parse and get public suffix informations about any valid domain name.
7285

73-
Public suffix resolution is done using the `Pdp\Rules::resolve` method which expects at most two parameters:
86+
### Manipulating the domain name
7487

75-
- `$domain` a domain name as a string
76-
- `$section` a string which specifies which section of the PSL you want to validate the given domain against. The possible values are:
77-
- `Rules::ALL_DOMAINS`, to validate against the full PSL.
78-
- `Rules::ICANN_DOMAINS`, to validate against the PSL ICANN DOMAINS section only.
79-
- `Rules::PRIVATE_DOMAINS`, to validate against the PSL PRIVATE DOMAINS section only.
88+
The `Pdp\Domain` returned by the `Pdp\Rules::resolve` method is an immutable value object representing a valid domain name. This object let's you access all the domain name properties as well as the public suffix informations attached to it using the following methods.
8089

81-
By default, the `$section` argument is equal to `Rules::ALL_DOMAINS`. If an unsupported section is submitted a `Pdp\Exception` exception will be thrown.
90+
~~~php
91+
public function Domain::getLabel(int $key): ?string
92+
public function Domain::keys(?string $label): int[]
93+
public function Domain::getContent(): ?string
94+
public function Domain::getPublicSuffix(): ?string
95+
public function Domain::getRegistrableDomain(): ?string
96+
public function Domain::getSubDomain(); ?string
97+
public function Domain::isKnown(): bool;
98+
public function Domain::isICANN(): bool;
99+
public function Domain::isPrivate(): bool;
100+
~~~
82101

83-
The `Pdp\Rules::resolve` returns a `Pdp\Domain` object.
102+
*The getter methods returns normalized and lowercased domain labels or `null` if no value was found for a particular domain part.*
84103

85-
The `Pdp\Domain` implements the `Pdp\DomainInterface`
104+
The `Pdp\Domain` object also implements PHP's `Countable` and `IteratorAggregate` interfaces to ease counting and iterating over the domain labels as well as PHP's `JsonSerializable` interfaces to output a JSON array with all the useful informations regarding the domain name.
86105

87-
~~~php
88-
<?php
106+
Once you have a `Pdp\Domain` object can also modify its content using the following methods:
89107

90-
interface DomainInterface extends Countable, IteratorAggregate
91-
{
92-
public function getContent(): ?string
93-
public function getLabel(int $key): ?string
94-
public function keys(string $label): int[]
95-
public function toUnicode(): static;
96-
public function toAscii(): static;
97-
}
108+
~~~php
109+
public function Domain::toAscii(): self
110+
public function Domain::toUnicode(): self
111+
public function Domain::withPublicSuffix($publicSuffix): self
112+
public function Domain::withSubDomain($subDomain): self
113+
public function Domain::withLabel(int $key, $label): self
114+
public function Domain::withoutLabel(int $key): self
115+
public function Domain::resolve($publicSuffix): self
98116
~~~
99117

100-
But also enable returns informations about the domain parts and its public suffix status.
118+
Because the `Pdp\Domain` object is immutable:
119+
120+
- If the method change any of the current object property, a new object is returned.
121+
- If a modification is not possible a `Pdp\Exception` exception is thrown.
101122

102123
~~~php
103-
<?php
124+
$manager = new Manager(new Cache(), new CurlHttpClient());
125+
$rules = $manager->getRules();
126+
$domain = $rules->resolve('www.bbc.co.uk');
127+
$newDomain = $domain
128+
->withPublicSuffix('com')
129+
->withSubDomain('shop')
130+
->withLabel(-2, 'example')
131+
;
132+
$newDomain->getContent(); //returns shop.example.com;
133+
$newDomain->isKnown(); //return false;
134+
~~~
104135

105-
final class Domain implements DomainInterface, JsonSerializable
106-
{
107-
public function __construct($domain = null, PublicSuffix $publicSuffix = null)
108-
public function getPublicSuffix(): ?string
109-
public function getRegistrableDomain(): ?string
110-
public function getSubDomain(); ?string
111-
public function isKnown(): bool;
112-
public function isICANN(): bool;
113-
public function isPrivate(): bool;
114-
public function withPublicSuffix(PublicSuffix $publicSuffix): self;
115-
}
136+
**WARNING: in the example above the PSL info are lost because the newly attached public suffix had none.**
137+
138+
To avoid this data loss you should use an already resolved public suffix.
139+
140+
~~~php
141+
$manager = new Manager(new Cache(), new CurlHttpClient());
142+
$rules = $manager->getRules();
143+
$domain = $rules->resolve('www.bbc.co.uk');
144+
$newPublicSuffix = $rules->getPublicSuffix('example.com');
145+
$newDomain = $domain
146+
->withPublicSuffix($newPublicSuffix)
147+
->withSubDomain('shop')
148+
->withLabel(-2, 'example')
149+
;
150+
$newDomain->getContent(); //returns shop.example.com;
151+
$newDomain->isKnown(); //return true;
116152
~~~
117153

154+
### Getting the domain public suffix information.
155+
156+
The `Pdp\Rules` object is responsible for public suffix resolution for a given domain. Public suffix resolution is done using the `Pdp\Rules::resolve` or `Pdp\Rules::getPublicSuffix` methods which expects at most two parameters:
157+
158+
- `$domain` a domain name as a string
159+
- `$section` a string which specifies which section of the PSL you want to validate the given domain against. The possible values are:
160+
- `Rules::ALL_DOMAINS`, to validate against the full PSL.
161+
- `Rules::ICANN_DOMAINS`, to validate against the PSL ICANN DOMAINS section only.
162+
- `Rules::PRIVATE_DOMAINS`, to validate against the PSL PRIVATE DOMAINS section only.
163+
164+
By default, the `$section` argument is equal to `Rules::ALL_DOMAINS`. If an unsupported section is submitted a `Pdp\Exception` exception will be thrown.
165+
166+
While the `Pdp\Rules::resolve` returns a `Pdp\Domain` object, the `Pdp\Rules::getPublicSuffix` returns a `Pdp\PublicSuffix` object.
167+
118168
**THIS EXAMPLE ILLUSTRATES HOW THE OBJECT WORK BUT SHOULD BE AVOIDED IN PRODUCTON**
119169

120170
~~~php
@@ -127,25 +177,6 @@ $pdp_url = 'https://raw.githubusercontent.com/publicsuffix/list/master/public_su
127177
$rules = Rules::createFromPath($pdp_url);
128178

129179
$domain = $rules->resolve('www.Ulb.AC.be'); //using Rules::ALL_DOMAINS
130-
$domain->getContent(); //returns 'www.ulb.ac.be'
131-
$domain->getPublicSuffix(); //returns 'ac.be'
132-
$domain->getRegistrableDomain(); //returns 'ulb.ac.be'
133-
$domain->getSubDomain(); //returns 'www'
134-
$domain->getLabel(0) //returns 'be'
135-
$domain->getLabel(-1) //returns 'www'
136-
$domain->keys('ulb') //returns [2]
137-
$domain->isKnown(); //returns true
138-
$domain->isICANN(); //returns true
139-
$domain->isPrivate(); //returns false
140-
echo json_encode(iterator_to_array($domain), JSON_PRETTY_PRINT);
141-
// returns
142-
// [
143-
// 'be',
144-
// 'ac',
145-
// 'ulb',
146-
// 'www'
147-
// ]
148-
149180
echo json_encode($domain, JSON_PRETTY_PRINT);
150181
// returns
151182
// {
@@ -174,34 +205,12 @@ echo json_encode($domain, JSON_PRETTY_PRINT);
174205
// }
175206
~~~
176207

177-
- All `Pdp\Domain` getter methods returns normalized and lowercased domain labels or `null` if no value was found for a particular domain part.
178-
179208
**The domain public suffix status depends on the PSL section used to resolve it:**
180209

181210
- `Pdp\Domain::isKnown` returns `true` if the public suffix is found in the selected PSL;
182211
- `Pdp\Domain::isICANN` returns `true` if the public suffix is found using a PSL which includes the ICANN DOMAINS section;
183212
- `Pdp\Domain::isPrivate` returns `true` if the public suffix is found using a PSL which includes the PRIVATE DOMAINS section;
184213

185-
The `Rules::getPublicSuffix` method expects the same arguments as `Rules::resolve` but returns a `Pdp\PublicSuffix` object instead.
186-
187-
~~~php
188-
<?php
189-
190-
final class PublicSuffix implements DomainInterface, JsonSerializable
191-
{
192-
public function __construct($publicSuffix = null)
193-
public function isKnown(): bool;
194-
public function isICANN(): bool;
195-
public function isPrivate(): bool;
196-
}
197-
~~~
198-
199-
While `Rules::resolve` will only throws an exception if the section value is invalid, the `Rules::getPublicSuffix` is more restrictive and will additionnally throw if:
200-
201-
- The domain name is invalid or seriously malformed
202-
- No public suffix can be match against the submitted domain.
203-
- The public suffix can not be normalized using the domain encoding.
204-
205214
**WARNING:**
206215

207216
**You should never use the library this way in production, without, at least, a caching mechanism to reduce PSL downloads.**
@@ -287,7 +296,7 @@ $retval = $manager->refreshRules('https://publicsuffix.org/list/public_suffix_li
287296
if ($retval) {
288297
//the local cache has been updated
289298
} else {
290-
//the local cache has not been updated
299+
//the local cache was not updated
291300
}
292301
~~~
293302

@@ -358,7 +367,6 @@ You can also add a composer script in your `composer.json` file to update the PS
358367
}
359368
~~~
360369

361-
362370
If you prefer using your own implementations you should:
363371

364372
1. Copy the `Pdp\Installer` class

composer.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@
5555
"autoload": {
5656
"psr-4": {
5757
"Pdp\\": "src/"
58-
},
59-
"files": ["src/functions_include.php"]
58+
}
6059
},
6160
"autoload-dev": {
6261
"psr-4": {

src/Converter.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,21 @@
2121
* @author Jeremy Kendall <[email protected]>
2222
* @author Ignace Nyamagana Butera <[email protected]>
2323
*/
24-
final class Converter
24+
final class Converter implements SectionInterface
2525
{
2626
use IDNAConverterTrait;
2727

2828
/**
2929
* Convert the Public Suffix List into
30-
* an associative, multidimensional array
30+
* an associative, multidimensional array.
3131
*
3232
* @param string $content
3333
*
3434
* @return array
3535
*/
3636
public function convert(string $content): array
3737
{
38-
$rules = [Rules::ICANN_DOMAINS => [], Rules::PRIVATE_DOMAINS => []];
38+
$rules = [self::ICANN_DOMAINS => [], self::PRIVATE_DOMAINS => []];
3939
$section = '';
4040
$file = new SplTempFileObject();
4141
$file->fwrite($content);
@@ -61,8 +61,8 @@ public function convert(string $content): array
6161
private function getSection(string $section, string $line): string
6262
{
6363
static $section_list = [
64-
'ICANN' => ['BEGIN' => Rules::ICANN_DOMAINS, 'END' => ''],
65-
'PRIVATE' => ['BEGIN' => Rules::PRIVATE_DOMAINS, 'END' => ''],
64+
'ICANN' => ['BEGIN' => self::ICANN_DOMAINS, 'END' => ''],
65+
'PRIVATE' => ['BEGIN' => self::PRIVATE_DOMAINS, 'END' => ''],
6666
];
6767
static $pattern = ',^// ===(?<point>BEGIN|END) (?<type>ICANN|PRIVATE) DOMAINS===,';
6868
if (preg_match($pattern, $line, $matches)) {

src/CurlHttpClient.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Pdp;
1313

1414
/**
15-
* Simple cURL Http client
15+
* Simple cURL Http client.
1616
*
1717
* Lifted pretty much completely from William Durand's excellent Geocoder
1818
* project
@@ -26,14 +26,14 @@
2626
final class CurlHttpClient implements HttpClient
2727
{
2828
/**
29-
* Additionnal cURL options
29+
* Additionnal cURL options.
3030
*
3131
* @var array
3232
*/
3333
private $options;
3434

3535
/**
36-
* new instance
36+
* new instance.
3737
*
3838
* @param array $options additional cURL options
3939
*/

0 commit comments

Comments
 (0)