Skip to content

Commit 1fa861e

Browse files
committed
add idna-options
1 parent bab1a99 commit 1fa861e

File tree

8 files changed

+194
-104
lines changed

8 files changed

+194
-104
lines changed

src/Manager.php

Lines changed: 36 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -82,16 +82,19 @@ public function __construct(CacheInterface $cache, HttpClient $http, $ttl = null
8282

8383
/**
8484
* Gets the Public Suffix List Rules.
85-
*
8685
* @param string $url the Public Suffix List URL
8786
* @param null|mixed $ttl the cache TTL
88-
*
89-
* @throws CouldNotLoadRules If the PSL rules can not be loaded
90-
*
87+
* @param int $asciiIDNAOption
88+
* @param int $unicodeIDNAOption
9189
* @return Rules
90+
* @throws \Psr\SimpleCache\InvalidArgumentException
9291
*/
93-
public function getRules(string $url = self::PSL_URL, $ttl = null): Rules
94-
{
92+
public function getRules(
93+
string $url = self::PSL_URL,
94+
$ttl = null,
95+
int $asciiIDNAOption = IDNA_DEFAULT,
96+
int $unicodeIDNAOption = IDNA_DEFAULT
97+
):Rules {
9598
$key = $this->getCacheKey('PSL', $url);
9699
$data = $this->cache->get($key);
97100

@@ -101,7 +104,7 @@ public function getRules(string $url = self::PSL_URL, $ttl = null): Rules
101104

102105
$data = json_decode($data ?? $this->cache->get($key), true);
103106
if (JSON_ERROR_NONE === json_last_error()) {
104-
return new Rules($data);
107+
return new Rules($data, $asciiIDNAOption, $unicodeIDNAOption);
105108
}
106109

107110
throw new CouldNotLoadRules(sprintf('The public suffix list cache is corrupted: %s', json_last_error_msg()), json_last_error());
@@ -131,57 +134,66 @@ public function refreshRules(string $url = self::PSL_URL, $ttl = null): bool
131134

132135
/**
133136
* Gets the Public Suffix List Rules.
134-
*
135137
* @param string $url the IANA Root Zone Database URL
136138
* @param null|mixed $ttl the cache TTL
137-
*
138-
* @throws Exception If the Top Level Domains can not be returned
139-
*
139+
* @param int $asciiIDNAOption
140+
* @param int $unicodeIDNAOption
140141
* @return TopLevelDomains
142+
* @throws \Psr\SimpleCache\InvalidArgumentException
141143
*/
142-
public function getTLDs(string $url = self::RZD_URL, $ttl = null): TopLevelDomains
143-
{
144+
public function getTLDs(
145+
string $url = self::RZD_URL,
146+
$ttl = null,
147+
int $asciiIDNAOption = IDNA_DEFAULT,
148+
int $unicodeIDNAOption = IDNA_DEFAULT
149+
):TopLevelDomains {
144150
$key = $this->getCacheKey('RZD', $url);
145151
$data = $this->cache->get($key);
146152

147153
if (null === $data && !$this->refreshTLDs($url, $ttl)) {
148154
throw new CouldNotLoadTLDs(sprintf('Unable to load the root zone database from %s', $url));
149155
}
150-
156+
151157
$data = json_decode($data ?? $this->cache->get($key), true);
152158
if (JSON_ERROR_NONE !== json_last_error()) {
153-
throw new CouldNotLoadTLDs(sprintf('The root zone database cache is corrupted: %s', json_last_error_msg()), json_last_error());
159+
throw new CouldNotLoadTLDs(sprintf('The root zone database cache is corrupted: %s', json_last_error_msg()),
160+
json_last_error());
154161
}
155-
162+
156163
if (!isset($data['records'], $data['version'], $data['modifiedDate'])) {
157164
throw new CouldNotLoadTLDs('The root zone database cache content is corrupted');
158165
}
159166

160167
return new TopLevelDomains(
161168
$data['records'],
162169
$data['version'],
163-
DateTimeImmutable::createFromFormat(DATE_ATOM, $data['modifiedDate'])
170+
DateTimeImmutable::createFromFormat(DATE_ATOM, $data['modifiedDate']),
171+
$asciiIDNAOption,
172+
$unicodeIDNAOption
164173
);
165174
}
166175

167176
/**
168177
* Downloads, converts and cache the IANA Root Zone TLD.
169-
*
170178
* If a local cache already exists, it will be overwritten.
171-
*
172179
* Returns true if the refresh was successful
173-
*
174180
* @param string $url the IANA Root Zone Database URL
175181
* @param null|mixed $ttl the cache TTL
176-
*
182+
* @param int $asciiIDNAOption
183+
* @param int $unicodeIDNAOption
177184
* @return bool
185+
* @throws \Psr\SimpleCache\InvalidArgumentException
178186
*/
179-
public function refreshTLDs(string $url = self::RZD_URL, $ttl = null): bool
180-
{
187+
public function refreshTLDs(
188+
string $url = self::RZD_URL,
189+
$ttl = null,
190+
int $asciiIDNAOption = IDNA_DEFAULT,
191+
int $unicodeIDNAOption = IDNA_DEFAULT
192+
): bool {
181193
static $converter;
182194

183195
$converter = $converter ?? new TLDConverter();
184-
$data = json_encode($converter->convert($this->http->getContent($url)));
196+
$data = json_encode($converter->convert($this->http->getContent($url), $asciiIDNAOption, $unicodeIDNAOption));
185197

186198
return $this->cache->set($this->getCacheKey('RZD', $url), $data, $this->filterTtl($ttl) ?? $this->ttl);
187199
}

src/PublicSuffix.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
use JsonSerializable;
1919
use Pdp\Exception\CouldNotResolvePublicSuffix;
2020
use Pdp\Exception\InvalidDomain;
21-
use Throwable;
2221
use function array_keys;
2322
use function array_reverse;
2423
use function count;
@@ -87,8 +86,8 @@ public static function __set_state(array $properties): self
8786
return new self(
8887
$properties['publicSuffix'],
8988
$properties['section'],
90-
$properties['asciiIDNAOption'],
91-
$properties['unicodeIDNAOption']
89+
$properties['asciiIDNAOption'] ?? IDNA_DEFAULT,
90+
$properties['unicodeIDNAOption'] ?? IDNA_DEFAULT
9291
);
9392
}
9493

src/Rules.php

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,31 @@ final class Rules implements PublicSuffixListSection
5050
* @var array
5151
*/
5252
private $rules;
53-
53+
54+
/**
55+
* @var int
56+
*/
57+
private $asciiIDNAOption;
58+
59+
/**
60+
* @var int
61+
*/
62+
private $unicodeIDNAOption;
63+
5464
/**
5565
* Returns a new instance from a file path.
56-
*
5766
* @param string $path
5867
* @param null|resource $context
59-
*
60-
* @throws CouldNotLoadRules If the rules can not be loaded from the path
61-
*
68+
* @param int $asciiIDNAOption
69+
* @param int $unicodeIDNAOption
6270
* @return self
6371
*/
64-
public static function createFromPath(string $path, $context = null): self
65-
{
72+
public static function createFromPath(
73+
string $path,
74+
$context = null,
75+
int $asciiIDNAOption = IDNA_DEFAULT,
76+
int $unicodeIDNAOption = IDNA_DEFAULT
77+
): self {
6678
$args = [$path, 'r', false];
6779
if (null !== $context) {
6880
$args[] = $context;
@@ -75,41 +87,54 @@ public static function createFromPath(string $path, $context = null): self
7587
$content = stream_get_contents($resource);
7688
fclose($resource);
7789

78-
return self::createFromString($content);
90+
return self::createFromString($content, $asciiIDNAOption, $unicodeIDNAOption);
7991
}
8092

8193
/**
8294
* Returns a new instance from a string.
83-
*
8495
* @param string $content
85-
*
96+
* @param int $asciiIDNAOption
97+
* @param int $unicodeIDNAOption
8698
* @return self
8799
*/
88-
public static function createFromString(string $content): self
89-
{
100+
public static function createFromString(
101+
string $content,
102+
int $asciiIDNAOption = IDNA_DEFAULT,
103+
int $unicodeIDNAOption = IDNA_DEFAULT
104+
): self {
90105
static $converter;
91106

92107
$converter = $converter ?? new Converter();
93108

94-
return new self($converter->convert($content));
109+
return new self($converter->convert($content), $asciiIDNAOption, $unicodeIDNAOption);
95110
}
96111

97112
/**
98113
* {@inheritdoc}
99114
*/
100115
public static function __set_state(array $properties): self
101116
{
102-
return new self($properties['rules']);
117+
return new self(
118+
$properties['rules'],
119+
$properties['asciiIDNAOption'] ?? IDNA_DEFAULT,
120+
$properties['unicodeIDNAOption'] ?? IDNA_DEFAULT
121+
);
103122
}
104123

105124
/**
106125
* New instance.
107-
*
108126
* @param array $rules
127+
* @param int $asciiIDNAOption
128+
* @param int $unicodeIDNAOption
109129
*/
110-
public function __construct(array $rules)
111-
{
130+
public function __construct(
131+
array $rules,
132+
int $asciiIDNAOption = IDNA_DEFAULT,
133+
int $unicodeIDNAOption = IDNA_DEFAULT
134+
){
112135
$this->rules = $rules;
136+
$this->asciiIDNAOption = $asciiIDNAOption;
137+
$this->unicodeIDNAOption = $unicodeIDNAOption;
113138
}
114139

115140
/**
@@ -125,7 +150,9 @@ public function __construct(array $rules)
125150
public function getPublicSuffix($domain, string $section = self::ALL_DOMAINS): PublicSuffix
126151
{
127152
$section = $this->validateSection($section);
128-
$domain = $domain instanceof Domain ? $domain : new Domain($domain);
153+
$domain = $domain instanceof Domain
154+
? $domain
155+
: new Domain($domain, null, $this->asciiIDNAOption, $this->unicodeIDNAOption);
129156
if (!$domain->isResolvable()) {
130157
throw new CouldNotResolvePublicSuffix(sprintf('The domain `%s` can not contain a public suffix', $domain->getContent()));
131158
}
@@ -137,28 +164,21 @@ public function getPublicSuffix($domain, string $section = self::ALL_DOMAINS): P
137164
* Returns PSL info for a given domain.
138165
* @param mixed $domain
139166
* @param string $section
140-
* @param int $asciiIDNAOption
141-
* @param int $unicodeIDNAOption
142167
* @return Domain
143168
*/
144-
public function resolve(
145-
$domain,
146-
string $section = self::ALL_DOMAINS,
147-
int $asciiIDNAOption = IDNA_DEFAULT,
148-
int $unicodeIDNAOption = IDNA_DEFAULT
149-
): Domain {
169+
public function resolve($domain, string $section = self::ALL_DOMAINS): Domain {
150170
$section = $this->validateSection($section);
151171
try {
152172
$domain = $domain instanceof Domain
153173
? $domain
154-
: new Domain($domain, null, $asciiIDNAOption, $unicodeIDNAOption);
174+
: new Domain($domain, null, $this->asciiIDNAOption, $this->unicodeIDNAOption);
155175
if (!$domain->isResolvable()) {
156176
return $domain;
157177
}
158178

159179
return $domain->resolve($this->findPublicSuffix($domain, $section));
160180
} catch (Exception $e) {
161-
return new Domain();
181+
return new Domain(null, null, $this->asciiIDNAOption, $this->unicodeIDNAOption);
162182
}
163183
}
164184

@@ -206,7 +226,7 @@ private function findPublicSuffix(DomainInterface $domain, string $section): Pub
206226
}
207227

208228
if (self::PRIVATE_DOMAINS === $section) {
209-
return new PublicSuffix($domain->getLabel(0));
229+
return new PublicSuffix($domain->getLabel(0), '', $this->asciiIDNAOption, $this->unicodeIDNAOption);
210230
}
211231

212232
return $icann;
@@ -246,9 +266,14 @@ private function findPublicSuffixFromSection(DomainInterface $domain, string $se
246266
}
247267

248268
if ([] === $matches) {
249-
return new PublicSuffix($domain->getLabel(0));
269+
return new PublicSuffix($domain->getLabel(0), '', $this->asciiIDNAOption, $this->unicodeIDNAOption);
250270
}
251271

252-
return new PublicSuffix(implode('.', array_reverse($matches)), $section);
272+
return new PublicSuffix(
273+
implode('.', array_reverse($matches)),
274+
$section,
275+
$this->asciiIDNAOption,
276+
$this->unicodeIDNAOption
277+
);
253278
}
254279
}

src/TLDConverter.php

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use DateTimeImmutable;
1919
use Pdp\Exception\CouldNotLoadTLDs;
2020
use SplTempFileObject;
21+
use function compact;
2122
use function preg_match;
2223
use function sprintf;
2324
use function strpos;
@@ -37,26 +38,27 @@ final class TLDConverter
3738
* @internal
3839
*/
3940
const IANA_DATE_FORMAT = 'D M d H:i:s Y e';
40-
41+
4142
/**
4243
* Converts the IANA Root Zone Database into a TopLevelDomains associative array.
43-
*
4444
* @param string $content
45-
*
46-
* @throws CouldNotLoadTLDs if the content is invalid or can not be correctly parsed and converted
47-
*
45+
* @param int $asciiIDNAOption
46+
* @param int $unicodeIDNAOption
4847
* @return array
4948
*/
50-
public function convert(string $content): array
51-
{
49+
public function convert(
50+
string $content,
51+
int $asciiIDNAOption = IDNA_DEFAULT,
52+
int $unicodeIDNAOption = IDNA_DEFAULT
53+
): array {
5254
$data = [];
5355
$file = new SplTempFileObject();
5456
$file->fwrite($content);
5557
$file->setFlags(SplTempFileObject::DROP_NEW_LINE | SplTempFileObject::READ_AHEAD | SplTempFileObject::SKIP_EMPTY);
5658
foreach ($file as $line) {
5759
$line = trim($line);
5860
if ([] === $data) {
59-
$data = $this->extractHeader($line);
61+
$data = array_merge($this->extractHeader($line), compact('asciiIDNAOption', 'unicodeIDNAOption'));
6062
continue;
6163
}
6264

@@ -70,7 +72,7 @@ public function convert(string $content): array
7072
}
7173

7274
if (isset($data['version'], $data['modifiedDate'], $data['records'])) {
73-
return $data;
75+
return array_merge($data, compact('asciiIDNAOption', 'unicodeIDNAOption'));
7476
}
7577

7678
throw new CouldNotLoadTLDs(sprintf('Invalid content: TLD conversion failed'));

0 commit comments

Comments
 (0)