11
11
12
12
namespace Pdp ;
13
13
14
- use Countable ;
15
14
use JsonSerializable ;
16
15
17
16
/**
28
27
* @author Jeremy Kendall <[email protected] >
29
28
* @author Ignace Nyamagana Butera <[email protected] >
30
29
*/
31
- final class Domain implements Countable , JsonSerializable
30
+ final class Domain implements DomainInterface , JsonSerializable
32
31
{
33
32
use IDNAConverterTrait;
34
33
@@ -37,6 +36,11 @@ final class Domain implements Countable, JsonSerializable
37
36
*/
38
37
private $ domain ;
39
38
39
+ /**
40
+ * @var string[]
41
+ */
42
+ private $ labels ;
43
+
40
44
/**
41
45
* @var PublicSuffix
42
46
*/
@@ -66,59 +70,51 @@ public static function __set_state(array $properties): self
66
70
* @param string|null $domain
67
71
* @param PublicSuffix $publicSuffix
68
72
*/
69
- public function __construct ($ domain = null , PublicSuffix $ publicSuffix = null )
73
+ public function __construct (string $ domain = null , PublicSuffix $ publicSuffix = null )
70
74
{
71
- $ this ->domain = $ this ->setDomain ($ domain );
75
+ list ( $ this ->domain , $ this -> labels ) = $ this ->setDomain ($ domain );
72
76
$ this ->publicSuffix = $ this ->setPublicSuffix ($ publicSuffix );
77
+ $ this ->assertValidState ();
73
78
$ this ->registrableDomain = $ this ->setRegistrableDomain ();
74
79
$ this ->subDomain = $ this ->setSubDomain ();
75
80
}
76
81
77
82
/**
78
- * Normalize the given domain.
83
+ * Sets the public suffix domain part .
79
84
*
80
- * @param string |null $domain
85
+ * @param PublicSuffix |null $publicSuffix
81
86
*
82
- * @return string|null
87
+ * @return PublicSuffix
83
88
*/
84
- private function setDomain ( string $ domain = null )
89
+ private function setPublicSuffix ( PublicSuffix $ publicSuffix = null ): PublicSuffix
85
90
{
86
- if (null === $ domain ) {
87
- return null ;
88
- }
89
-
90
- if ( false !== strpos ( $ domain , ' % ' ) ) {
91
- $ domain = rawurldecode ( $ domain );
91
+ if (null === $ publicSuffix
92
+ || null === $ this -> domain
93
+ || false === strpos ( $ this -> domain , ' . ' )
94
+ || count ( $ this -> labels ) === count ( $ publicSuffix )
95
+ ) {
96
+ return new PublicSuffix ( );
92
97
}
93
98
94
- return strtolower ( $ domain ) ;
99
+ return $ publicSuffix ;
95
100
}
96
101
97
102
/**
98
- * Sets the public suffix domain part.
99
- *
100
- * @param PublicSuffix|null $publicSuffix
103
+ * assert the domain internal state is valid
101
104
*
102
- * @return PublicSuffix
105
+ * @throws Exception if the public suffix does not match the domain
103
106
*/
104
- private function setPublicSuffix ( PublicSuffix $ publicSuffix = null ): PublicSuffix
107
+ protected function assertValidState ()
105
108
{
106
- $ publicSuffix = $ publicSuffix ?? new PublicSuffix ();
107
- if (null === $ publicSuffix ->getContent ()) {
108
- return $ publicSuffix ;
109
- }
110
-
111
- if (null === $ this ->domain || false === strpos ($ this ->domain , '. ' )) {
112
- return new PublicSuffix ();
109
+ foreach ($ this ->publicSuffix as $ offset => $ label ) {
110
+ if ($ label !== $ this ->labels [$ offset ]) {
111
+ throw new Exception (sprintf ('The submitted public suffix `%s` is invalid for the given domain `%s` ' , $ this ->publicSuffix ->getContent (), $ this ->domain ));
112
+ }
113
113
}
114
-
115
- return $ publicSuffix ;
116
114
}
117
115
118
116
/**
119
117
* Computes the registrable domain part.
120
- *
121
- * @return string|null
122
118
*/
123
119
private function setRegistrableDomain ()
124
120
{
@@ -129,9 +125,6 @@ private function setRegistrableDomain()
129
125
$ labels = explode ('. ' , $ this ->domain );
130
126
$ countLabels = count ($ labels );
131
127
$ countPublicSuffixLabels = count ($ this ->publicSuffix );
132
- if ($ countLabels === $ countPublicSuffixLabels ) {
133
- return null ;
134
- }
135
128
136
129
return implode ('. ' , array_slice ($ labels , $ countLabels - $ countPublicSuffixLabels - 1 ));
137
130
}
@@ -157,16 +150,30 @@ private function setSubDomain()
157
150
return implode ('. ' , array_slice ($ labels , 0 , $ countLabels - $ countLabelsToRemove ));
158
151
}
159
152
153
+ /**
154
+ * {@inheritdoc}
155
+ */
156
+ public function getIterator ()
157
+ {
158
+ foreach ($ this ->labels as $ offset => $ label ) {
159
+ yield $ label ;
160
+ }
161
+ }
162
+
160
163
/**
161
164
* {@inheritdoc}
162
165
*/
163
166
public function jsonSerialize ()
164
167
{
165
- return array_merge ( [
168
+ return [
166
169
'domain ' => $ this ->domain ,
167
170
'registrableDomain ' => $ this ->registrableDomain ,
168
171
'subDomain ' => $ this ->subDomain ,
169
- ], $ this ->publicSuffix ->jsonSerialize ());
172
+ 'publicSuffix ' => $ this ->publicSuffix ->getContent (),
173
+ 'isKnown ' => $ this ->isKnown (),
174
+ 'isICANN ' => $ this ->isICANN (),
175
+ 'isPrivate ' => $ this ->isPrivate (),
176
+ ];
170
177
}
171
178
172
179
/**
@@ -182,19 +189,11 @@ public function __debugInfo()
182
189
*/
183
190
public function count ()
184
191
{
185
- if (null === $ this ->domain ) {
186
- return 0 ;
187
- }
188
-
189
- return count (explode ('. ' , $ this ->domain ));
192
+ return count ($ this ->labels );
190
193
}
191
194
192
195
/**
193
- * Returns the domain content.
194
- *
195
- * This method should return null on seriously malformed domain name
196
- *
197
- * @return string|null
196
+ * {@inheritdoc}
198
197
*/
199
198
public function getContent ()
200
199
{
@@ -206,7 +205,7 @@ public function getContent()
206
205
*
207
206
* DEPRECATION WARNING! This method will be removed in the next major point release
208
207
*
209
- * @deprecated deprecated since version 5.3
208
+ * @deprecated 5.3 deprecated
210
209
* @see Domain::getContent
211
210
*
212
211
* This method should return null on seriously malformed domain name
@@ -218,6 +217,26 @@ public function getDomain()
218
217
return $ this ->getContent ();
219
218
}
220
219
220
+ /**
221
+ * {@inheritdoc}
222
+ */
223
+ public function getLabel (int $ offset )
224
+ {
225
+ if ($ offset < 0 ) {
226
+ $ offset += count ($ this ->labels );
227
+ }
228
+
229
+ return $ this ->labels [$ offset ] ?? null ;
230
+ }
231
+
232
+ /**
233
+ * {@inheritdoc}
234
+ */
235
+ public function keys (string $ label ): array
236
+ {
237
+ return array_keys ($ this ->labels , $ label , true );
238
+ }
239
+
221
240
/**
222
241
* Returns the registrable domain.
223
242
*
@@ -258,7 +277,7 @@ public function getPublicSuffix()
258
277
}
259
278
260
279
/**
261
- * Tells whether the public suffix has been matching rule in a Public Suffix List.
280
+ * Tells whether the public suffix has a matching rule in a Public Suffix List.
262
281
*
263
282
* @return bool
264
283
*/
@@ -288,45 +307,41 @@ public function isPrivate(): bool
288
307
}
289
308
290
309
/**
291
- * Converts the domain to its IDNA ASCII form.
292
- *
293
- * This method MUST retain the state of the current instance, and return
294
- * an instance with is content converted to its IDNA ASCII form
295
- *
296
- * @throws Exception if the domain can not be converted to ASCII using IDN UTS46 algorithm
297
- *
298
- * @return self
310
+ * {@inheritdoc}
299
311
*/
300
- public function toAscii (): self
312
+ public function toAscii ()
301
313
{
302
- if (null === $ this ->domain || false !== strpos ($ this ->domain , 'xn-- ' )) {
314
+ static $ pattern = '/[^\x20-\x7f]/ ' ;
315
+ if (null === $ this ->domain || !preg_match ($ pattern , $ this ->domain )) {
303
316
return $ this ;
304
317
}
305
318
306
- $ newDomain = $ this ->idnToAscii ($ this ->domain );
307
- if ($ newDomain === $ this ->domain ) {
308
- return $ this ;
309
- }
319
+ $ clone = clone $ this ;
320
+ $ clone ->domain = $ this ->idnToAscii ($ this ->domain );
321
+ $ clone ->labels = array_reverse (explode ('. ' , $ clone ->domain ));
322
+ $ clone ->publicSuffix = $ this ->publicSuffix ->toAscii ();
323
+ $ clone ->registrableDomain = $ clone ->setRegistrableDomain ();
324
+ $ clone ->subDomain = $ clone ->setSubDomain ();
310
325
311
- return new self ( $ newDomain , $ this -> publicSuffix -> toAscii ()) ;
326
+ return $ clone ;
312
327
}
313
328
314
329
/**
315
- * Converts the domain to its IDNA UTF8 form.
316
- *
317
- * This method MUST retain the state of the current instance, and return
318
- * an instance with is content converted to its IDNA UTF8 form
319
- *
320
- * @throws Exception if the domain can not be converted to Unicode using IDN UTS46 algorithm
321
- *
322
- * @return self
330
+ * {@inheritdoc}
323
331
*/
324
- public function toUnicode (): self
332
+ public function toUnicode ()
325
333
{
326
334
if (null === $ this ->domain || false === strpos ($ this ->domain , 'xn-- ' )) {
327
335
return $ this ;
328
336
}
329
337
330
- return new self ($ this ->idnToUnicode ($ this ->domain ), $ this ->publicSuffix ->toUnicode ());
338
+ $ clone = clone $ this ;
339
+ $ clone ->domain = $ this ->idnToUnicode ($ this ->domain );
340
+ $ clone ->labels = array_reverse (explode ('. ' , $ clone ->domain ));
341
+ $ clone ->publicSuffix = $ this ->publicSuffix ->toUnicode ();
342
+ $ clone ->registrableDomain = $ clone ->setRegistrableDomain ();
343
+ $ clone ->subDomain = $ clone ->setSubDomain ();
344
+
345
+ return $ clone ;
331
346
}
332
347
}
0 commit comments