Skip to content

Commit 1262646

Browse files
committed
Improve decoupling resource retrieving and parsing
1 parent 9e3bb33 commit 1262646

14 files changed

+114
-134
lines changed

src/Domain.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ private function parseValue($domain): ?string
151151

152152
// if the domain name does not contains UTF-8 chars then it is malformed
153153
if (1 !== preg_match(self::REGEXP_IDN_PATTERN, $formattedDomain)) {
154-
throw SyntaxError::dueToInvalidLength($domain);
154+
throw SyntaxError::dueToMalformedValue($domain);
155155
}
156156

157157
return $this->domainToUnicode($this->domainToAscii($formattedDomain));

src/Rules.php

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,11 @@
99
use function array_pop;
1010
use function count;
1111
use function explode;
12-
use function fclose;
13-
use function fopen;
1412
use function gettype;
1513
use function is_object;
1614
use function is_string;
1715
use function method_exists;
1816
use function preg_match;
19-
use function stream_get_contents;
2017
use function strpos;
2118
use function substr;
2219

@@ -57,40 +54,20 @@ private function __construct(array $rules)
5754
*
5855
* @param null|resource $context
5956
*
60-
* @throws UnableToLoadPublicSuffixList If the rules can not be loaded from the path
57+
* @throws UnableToLoadResource If the rules can not be loaded from the path
58+
* @throws UnableToLoadPublicSuffixList If the rules contains in the resource are invalid
6159
*/
6260
public static function fromPath(string $path, $context = null): self
6361
{
64-
$resource = self::getResource($path, $context);
65-
if (false === $resource) {
66-
throw UnableToLoadPublicSuffixList::dueToInvalidPath($path);
67-
}
68-
69-
/** @var string $content */
70-
$content = stream_get_contents($resource);
71-
fclose($resource);
72-
73-
return self::fromString($content);
74-
}
75-
76-
/**
77-
* @param null|resource $context
78-
*
79-
* @return false|resource
80-
*/
81-
private static function getResource(string $path, $context = null)
82-
{
83-
if (null === $context) {
84-
return @fopen($path, 'r');
85-
}
86-
87-
return @fopen($path, 'r', false, $context);
62+
return self::fromString(Stream::getContentAsString($path, $context));
8863
}
8964

9065
/**
9166
* Returns a new instance from a string.
9267
*
9368
* @param object|string $content a string or an object which exposes the __toString method
69+
*
70+
* @throws UnableToLoadPublicSuffixList If the rules contains in the resource are invalid
9471
*/
9572
public static function fromString($content): self
9673
{

src/RulesTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public function testCreateFromPath(): void
4242

4343
public function testCreateFromPathThrowsException(): void
4444
{
45-
$this->expectException(UnableToLoadPublicSuffixList::class);
45+
$this->expectException(UnableToLoadResource::class);
4646

4747
Rules::fromPath('/foo/bar.dat');
4848
}

src/Storage/PublicSuffixListPsr18Client.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Pdp\PublicSuffixList;
88
use Pdp\Rules;
9-
use Pdp\UnableToLoadPublicSuffixList;
9+
use Pdp\UnableToLoadResource;
1010
use Psr\Http\Client\ClientExceptionInterface;
1111
use Psr\Http\Client\ClientInterface;
1212
use Psr\Http\Message\RequestFactoryInterface;
@@ -29,11 +29,11 @@ public function get(string $uri): PublicSuffixList
2929
try {
3030
$response = $this->client->sendRequest($request);
3131
} catch (ClientExceptionInterface $exception) {
32-
throw UnableToLoadPublicSuffixList::dueToUnavailableService($uri, $exception);
32+
throw UnableToLoadResource::dueToUnavailableService($uri, $exception);
3333
}
3434

3535
if (400 <= $response->getStatusCode()) {
36-
throw UnableToLoadPublicSuffixList::dueToUnexpectedContent($uri, $response->getStatusCode());
36+
throw UnableToLoadResource::dueToUnexpectedStatusCode($uri, $response->getStatusCode());
3737
}
3838

3939
return Rules::fromString($response->getBody());

src/Storage/PublicSuffixListPsr18ClientTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use GuzzleHttp\Psr7\Request;
99
use GuzzleHttp\Psr7\Response;
1010
use Pdp\Rules;
11-
use Pdp\UnableToLoadPublicSuffixList;
11+
use Pdp\UnableToLoadResource;
1212
use PHPUnit\Framework\TestCase;
1313
use Psr\Http\Client\ClientInterface;
1414
use Psr\Http\Message\RequestFactoryInterface;
@@ -62,8 +62,8 @@ public function createRequest(string $method, $uri): RequestInterface
6262
}
6363
};
6464

65-
$this->expectException(UnableToLoadPublicSuffixList::class);
66-
$this->expectExceptionMessage('Could not access the Public Suffix List URI: `http://www.example.com`.');
65+
$this->expectException(UnableToLoadResource::class);
66+
$this->expectExceptionMessage('Could not access the URI: `http://www.example.com`.');
6767

6868
$storage = new PublicSuffixListPsr18Client($client, $requestFactory);
6969
$storage->get('http://www.example.com');
@@ -85,8 +85,8 @@ public function createRequest(string $method, $uri): RequestInterface
8585
}
8686
};
8787

88-
$this->expectException(UnableToLoadPublicSuffixList::class);
89-
$this->expectExceptionMessage('Invalid response from Public Suffix List URI: `http://www.example.com`.');
88+
$this->expectException(UnableToLoadResource::class);
89+
$this->expectExceptionMessage('Invalid response from URI: `http://www.example.com`.');
9090
$this->expectExceptionCode(404);
9191

9292
$storage = new PublicSuffixListPsr18Client($client, $requestFactory);

src/Storage/TopLevelDomainListPsr18Client.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
use Pdp\TopLevelDomainList;
88
use Pdp\TopLevelDomains;
9-
use Pdp\UnableToLoadTopLevelDomainList;
9+
use Pdp\UnableToLoadResource;
1010
use Psr\Http\Client\ClientExceptionInterface;
1111
use Psr\Http\Client\ClientInterface;
1212
use Psr\Http\Message\RequestFactoryInterface;
@@ -29,11 +29,11 @@ public function get(string $uri): TopLevelDomainList
2929
try {
3030
$response = $this->client->sendRequest($request);
3131
} catch (ClientExceptionInterface $exception) {
32-
throw UnableToLoadTopLevelDomainList::dueToUnavailableService($uri, $exception);
32+
throw UnableToLoadResource::dueToUnavailableService($uri, $exception);
3333
}
3434

3535
if (400 <= $response->getStatusCode()) {
36-
throw UnableToLoadTopLevelDomainList::dueToUnexpectedContent($uri, $response->getStatusCode());
36+
throw UnableToLoadResource::dueToUnexpectedStatusCode($uri, $response->getStatusCode());
3737
}
3838

3939
return TopLevelDomains::fromString($response->getBody());

src/Storage/TopLevelDomainListPsr18ClientTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use GuzzleHttp\Psr7\Request;
99
use GuzzleHttp\Psr7\Response;
1010
use Pdp\TopLevelDomains;
11-
use Pdp\UnableToLoadTopLevelDomainList;
11+
use Pdp\UnableToLoadResource;
1212
use PHPUnit\Framework\TestCase;
1313
use Psr\Http\Client\ClientInterface;
1414
use Psr\Http\Message\RequestFactoryInterface;
@@ -63,8 +63,8 @@ public function createRequest(string $method, $uri): RequestInterface
6363
}
6464
};
6565

66-
$this->expectException(UnableToLoadTopLevelDomainList::class);
67-
$this->expectExceptionMessage('Could not access the Top Level Domain List URI: `http://www.example.com`.');
66+
$this->expectException(UnableToLoadResource::class);
67+
$this->expectExceptionMessage('Could not access the URI: `http://www.example.com`.');
6868

6969
$storage = new TopLevelDomainListPsr18Client($client, $requestFactory);
7070
$storage->get('http://www.example.com');
@@ -86,8 +86,8 @@ public function createRequest(string $method, $uri): RequestInterface
8686
}
8787
};
8888

89-
$this->expectException(UnableToLoadTopLevelDomainList::class);
90-
$this->expectExceptionMessage('Invalid response from Top Level Domain List URI: `http://www.example.com`.');
89+
$this->expectException(UnableToLoadResource::class);
90+
$this->expectExceptionMessage('Invalid response from URI: `http://www.example.com`.');
9191
$this->expectExceptionCode(404);
9292

9393
$storage = new TopLevelDomainListPsr18Client($client, $requestFactory);

src/Stream.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Pdp;
6+
7+
use function fclose;
8+
use function fopen;
9+
use function stream_get_contents;
10+
11+
/**
12+
* @internal
13+
*/
14+
final class Stream
15+
{
16+
/**
17+
* Returns the content as string from a path.
18+
*
19+
* @param null|resource $context
20+
*
21+
* @throws UnableToLoadPublicSuffixList If the rules can not be loaded from the path
22+
*/
23+
public static function getContentAsString(string $path, $context = null): string
24+
{
25+
$resource = self::getResource($path, $context);
26+
if (false === $resource) {
27+
throw UnableToLoadResource::dueToInvalidUri($path);
28+
}
29+
30+
/** @var string $content */
31+
$content = stream_get_contents($resource);
32+
fclose($resource);
33+
34+
return $content;
35+
}
36+
37+
/**
38+
* @param null|resource $context
39+
*
40+
* @return false|resource
41+
*/
42+
private static function getResource(string $path, $context = null)
43+
{
44+
if (null === $context) {
45+
return @fopen($path, 'r');
46+
}
47+
48+
return @fopen($path, 'r', false, $context);
49+
}
50+
}

src/SyntaxError.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ public static function dueToInvalidCharacters(string $domain): self
2121
return new self('The host `'.$domain.'` is invalid: it contains invalid characters.');
2222
}
2323

24-
public static function dueToInvalidLength(string $domain): self
24+
public static function dueToMalformedValue(string $domain): self
2525
{
26-
return new self('The host `'.$domain.'` is invalid: its length is longer than 255 bytes in its storage form.');
26+
return new self('The host `'.$domain.'` is malformed; Verify its length and/or characters.');
2727
}
2828

2929
public static function dueToIDNAError(string $domain, IdnaInfo $idnaInfo): self

src/TopLevelDomains.php

Lines changed: 11 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,13 @@
99
use Iterator;
1010
use SplTempFileObject;
1111
use TypeError;
12-
use function array_flip;
1312
use function count;
14-
use function fclose;
15-
use function fopen;
1613
use function gettype;
1714
use function in_array;
1815
use function is_object;
1916
use function is_string;
2017
use function method_exists;
2118
use function preg_match;
22-
use function stream_get_contents;
2319
use function strpos;
2420
use function trim;
2521

@@ -53,40 +49,20 @@ private function __construct(array $records, string $version, DateTimeImmutable
5349
*
5450
* @param null|resource $context
5551
*
56-
* @throws UnableToLoadTopLevelDomainList If the rules can not be loaded from the path
52+
* @throws UnableToLoadResource If the rules can not be loaded from the path
53+
* @throws UnableToLoadTopLevelDomainList If the content is invalid or can not be correctly parsed and converted
5754
*/
5855
public static function fromPath(string $path, $context = null): self
5956
{
60-
$resource = self::getResource($path, $context);
61-
if (false === $resource) {
62-
throw UnableToLoadTopLevelDomainList::dueToInvalidPath($path);
63-
}
64-
65-
/** @var string $content */
66-
$content = stream_get_contents($resource);
67-
fclose($resource);
68-
69-
return self::fromString($content);
70-
}
71-
72-
/**
73-
* @param null|resource $context
74-
*
75-
* @return false|resource
76-
*/
77-
private static function getResource(string $path, $context = null)
78-
{
79-
if (null === $context) {
80-
return @fopen($path, 'r');
81-
}
82-
83-
return @fopen($path, 'r', false, $context);
57+
return self::fromString(Stream::getContentAsString($path, $context));
8458
}
8559

8660
/**
8761
* Returns a new instance from a string.
8862
*
8963
* @param object|string $content a string or an object which exposes the __toString method
64+
*
65+
* @throws UnableToLoadTopLevelDomainList if the content is invalid or can not be correctly parsed and converted
9066
*/
9167
public static function fromString($content): self
9268
{
@@ -103,15 +79,15 @@ public static function fromString($content): self
10379
/** @var DateTimeImmutable $lastUpdated */
10480
$lastUpdated = DateTimeImmutable::createFromFormat(DateTimeInterface::ATOM, $data['lastUpdated']);
10581

106-
return new self(array_flip($data['records']), $data['version'], $lastUpdated);
82+
return new self($data['records'], $data['version'], $lastUpdated);
10783
}
10884

10985
/**
11086
* Converts the IANA Top Level Domain List into a TopLevelDomains associative array.
11187
*
112-
*@throws UnableToLoadTopLevelDomainList if the content is invalid or can not be correctly parsed and converted
88+
* @throws UnableToLoadTopLevelDomainList if the content is invalid or can not be correctly parsed and converted
11389
*
114-
* @return array{version:string, lastUpdated:string, records:array<string>}
90+
* @return array{version:string, lastUpdated:string, records:array<string,int>}
11591
*/
11692
public static function parse(string $content): array
11793
{
@@ -129,7 +105,7 @@ public static function parse(string $content): array
129105

130106
if (false === strpos($line, '#')) {
131107
$data['records'] = $data['records'] ?? [];
132-
$data['records'][] = self::extractRootZone($line);
108+
$data['records'][self::extractRootZone($line)] = 1;
133109
continue;
134110
}
135111

@@ -168,7 +144,7 @@ private static function extractHeader(string $content): array
168144
/**
169145
* Extract IANA Root Zone.
170146
*
171-
* @throws UnableToLoadTopLevelDomainList If the Root Zone is invalid
147+
* @throws UnableToLoadTopLevelDomainList If the Top Level Domain is invalid
172148
*/
173149
private static function extractRootZone(string $content): string
174150
{
@@ -178,7 +154,7 @@ private static function extractRootZone(string $content): string
178154
throw UnableToLoadTopLevelDomainList::dueToInvalidTopLevelDomain($content, $exception);
179155
}
180156

181-
return $tld->toString();
157+
return $tld->toAscii()->toString();
182158
}
183159

184160
/**

0 commit comments

Comments
 (0)