1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Spatie\Crawler; |
4
|
|
|
|
5
|
|
|
class Url |
6
|
|
|
{ |
7
|
|
|
/** @var null|string */ |
8
|
|
|
public $scheme; |
9
|
|
|
|
10
|
|
|
/** @var null|string */ |
11
|
|
|
public $host; |
12
|
|
|
|
13
|
|
|
/** @var int */ |
14
|
|
|
public $port = 80; |
15
|
|
|
|
16
|
|
|
/** @var null|string */ |
17
|
|
|
public $path; |
18
|
|
|
|
19
|
|
|
/** @var null|string */ |
20
|
|
|
public $query; |
21
|
|
|
|
22
|
|
|
/** @var null|string */ |
23
|
|
|
protected $toString; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @param string $url |
27
|
|
|
* |
28
|
|
|
* @return static |
29
|
|
|
*/ |
30
|
|
|
public static function create(string $url) |
31
|
|
|
{ |
32
|
|
|
return new static($url); |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
public function __construct(string $url) |
36
|
|
|
{ |
37
|
|
|
$urlProperties = parse_url($url); |
38
|
|
|
|
39
|
|
|
foreach (['scheme', 'host', 'path', 'port', 'query'] as $property) { |
40
|
|
|
if (isset($urlProperties[$property])) { |
41
|
|
|
$this->$property = $urlProperties[$property]; |
42
|
|
|
} |
43
|
|
|
} |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
public function isRelative(): bool |
47
|
|
|
{ |
48
|
|
|
return is_null($this->host); |
49
|
|
|
} |
50
|
|
|
|
51
|
|
|
public function isProtocolIndependent(): bool |
52
|
|
|
{ |
53
|
|
|
return is_null($this->scheme); |
54
|
|
|
} |
55
|
|
|
|
56
|
|
|
public function hasCrawlableScheme(): bool |
57
|
|
|
{ |
58
|
|
|
return in_array($this->scheme, [null, 'http', 'https']); |
59
|
|
|
} |
60
|
|
|
|
61
|
|
|
/** |
62
|
|
|
* @param string $scheme |
63
|
|
|
* |
64
|
|
|
* @return $this |
65
|
|
|
*/ |
66
|
|
|
public function setScheme(string $scheme) |
67
|
|
|
{ |
68
|
|
|
$this->scheme = $scheme; |
69
|
|
|
$this->toString = null; |
70
|
|
|
|
71
|
|
|
return $this; |
72
|
|
|
} |
73
|
|
|
|
74
|
|
|
/** |
75
|
|
|
* @param string $host |
76
|
|
|
* |
77
|
|
|
* @return $this |
78
|
|
|
*/ |
79
|
|
|
public function setHost(string $host) |
80
|
|
|
{ |
81
|
|
|
$this->host = $host; |
82
|
|
|
$this->toString = null; |
83
|
|
|
|
84
|
|
|
return $this; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* @param $port |
89
|
|
|
* |
90
|
|
|
* @return $this |
91
|
|
|
*/ |
92
|
|
|
public function setPort(int $port) |
93
|
|
|
{ |
94
|
|
|
$this->port = $port; |
95
|
|
|
$this->toString = null; |
96
|
|
|
|
97
|
|
|
return $this; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* @return $this |
102
|
|
|
*/ |
103
|
|
|
public function removeFragment() |
104
|
|
|
{ |
105
|
|
|
$this->path = explode('#', $this->path)[0]; |
106
|
|
|
$this->toString = null; |
107
|
|
|
|
108
|
|
|
return $this; |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* @param $path |
113
|
|
|
* |
114
|
|
|
* @return $this |
115
|
|
|
*/ |
116
|
|
|
public function setPath(string $path) |
117
|
|
|
{ |
118
|
|
|
$this->path = $path; |
119
|
|
|
$this->toString = null; |
120
|
|
|
|
121
|
|
|
return $this; |
122
|
|
|
} |
123
|
|
|
|
124
|
|
|
/** |
125
|
|
|
* @return null|string |
126
|
|
|
*/ |
127
|
|
|
public function path() |
128
|
|
|
{ |
129
|
|
|
return $this->path; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
/** |
133
|
|
|
* @deprecated This function is not being used internally anymore and will be removed in the next major version. |
134
|
|
|
* |
135
|
|
|
* @return null|string |
136
|
|
|
*/ |
137
|
|
|
public function directory() |
138
|
|
|
{ |
139
|
|
|
$segments = $this->segments(); |
|
|
|
|
140
|
|
|
array_pop($segments); |
141
|
|
|
|
142
|
|
|
return implode('/', $segments).'/'; |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
/** |
146
|
|
|
* @deprecated This function is not being used internally anymore and will be removed in the next major version. |
147
|
|
|
* |
148
|
|
|
* @param int|null $index |
149
|
|
|
* |
150
|
|
|
* @return array|null|string |
151
|
|
|
*/ |
152
|
|
|
public function segments(int $index = null) |
153
|
|
|
{ |
154
|
|
|
$segments = collect(explode('/', $this->path())) |
155
|
|
|
->filter(function ($value) { |
156
|
|
|
return $value !== ''; |
157
|
|
|
}) |
158
|
|
|
->values() |
159
|
|
|
->toArray(); |
160
|
|
|
|
161
|
|
|
if (! is_null($index)) { |
162
|
|
|
return $this->segment($index); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
return $segments; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
/** |
169
|
|
|
* @param int $index |
170
|
|
|
* |
171
|
|
|
* @return string|null |
172
|
|
|
*/ |
173
|
|
|
public function segment(int $index) |
174
|
|
|
{ |
175
|
|
|
if (! isset($this->segments()[$index - 1])) { |
|
|
|
|
176
|
|
|
return; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
return $this->segments()[$index - 1]; |
|
|
|
|
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
public function isEqual(Url $otherUrl): bool |
183
|
|
|
{ |
184
|
|
|
return (string) $this === (string) $otherUrl; |
185
|
|
|
} |
186
|
|
|
|
187
|
|
|
/** |
188
|
|
|
* @return string |
189
|
|
|
*/ |
190
|
|
|
public function __toString() |
191
|
|
|
{ |
192
|
|
|
if ($this->toString === null) { |
193
|
|
|
$path = $this->startsWith($this->path, '/') ? substr($this->path, 1) : $this->path; |
194
|
|
|
|
195
|
|
|
$port = ($this->port === 80 ? '' : ":{$this->port}"); |
196
|
|
|
|
197
|
|
|
$queryString = (is_null($this->query) ? '' : "?{$this->query}"); |
198
|
|
|
|
199
|
|
|
$this->toString = "{$this->scheme}://{$this->host}{$port}/{$path}{$queryString}"; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
return $this->toString; |
203
|
|
|
} |
204
|
|
|
|
205
|
|
|
/** |
206
|
|
|
* @param string|null $haystack |
207
|
|
|
* @param string|array $needles |
208
|
|
|
* |
209
|
|
|
* @return bool |
210
|
|
|
*/ |
211
|
|
|
public function startsWith($haystack, $needles): bool |
212
|
|
|
{ |
213
|
|
|
foreach ((array) $needles as $needle) { |
214
|
|
|
if ($needle != '' && substr($haystack, 0, strlen($needle)) === (string) $needle) { |
215
|
|
|
return true; |
216
|
|
|
} |
217
|
|
|
} |
218
|
|
|
|
219
|
|
|
return false; |
220
|
|
|
} |
221
|
|
|
} |
222
|
|
|
|
This method has been deprecated. The supplier of the class has supplied an explanatory message.
The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.