Skip to content

Commit 3f9a48c

Browse files
committed
Create Uri.php
1 parent 8fbea47 commit 3f9a48c

File tree

1 file changed

+358
-0
lines changed

1 file changed

+358
-0
lines changed

src/Uri.php

Lines changed: 358 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,358 @@
1+
<?php
2+
/**
3+
* Класс uri.
4+
* @package evas-php\evas-http
5+
* @author Egor Vasyakin <[email protected]>
6+
*/
7+
namespace Evas\Http;
8+
9+
use Evas\Http\Interfaces\UriInterface;
10+
11+
class Uri implements UriInterface
12+
{
13+
const HTTP_DEFAULT_HOST = 'localhost';
14+
15+
private static $defaultPorts = [
16+
'http' => 80,
17+
'https' => 443,
18+
'ftp' => 21,
19+
'gopher' => 70,
20+
'nntp' => 119,
21+
'news' => 119,
22+
'telnet' => 23,
23+
'tn3270' => 23,
24+
'imap' => 143,
25+
'pop' => 110,
26+
'ldap' => 389,
27+
];
28+
29+
/** @var string Uri scheme */
30+
private $scheme;
31+
32+
/** @var string|null Uri user info */
33+
private $userInfo;
34+
35+
/** @var string Uri host */
36+
private $host;
37+
38+
/** @var int|null Uri port */
39+
private $port;
40+
41+
/** @var string Uri path */
42+
private $path = '';
43+
44+
/** @var string|null Uri query string */
45+
private $query;
46+
47+
/** @var string|null Uri fragment */
48+
private $fragment;
49+
50+
/**
51+
* Конструктор.
52+
* @param string|null uri для парсинга
53+
*/
54+
public function __construct(string $uri = null)
55+
{
56+
if (!empty($uri)) {
57+
$parts = parse_url($uri);
58+
if (false === $parts) {
59+
throw new \InvalidArgumentException("Unable to parse URI: $uri");
60+
}
61+
$this->applyParts($parts);
62+
}
63+
}
64+
65+
public function __toString()
66+
{
67+
return self::composeComponents(
68+
$this->scheme,
69+
$this->getAuthority(),
70+
$this->path,
71+
$this->query,
72+
$this->fragment
73+
);
74+
}
75+
76+
public static function composeComponents(string $scheme = null, string $authority = null, string $path = null, string $query = null, string $fragment = null)
77+
{
78+
$uri = '';
79+
if (!empty($scheme)) $uri .= $scheme . ':';
80+
if (!empty($authority) || $scheme === 'file') $uri .= '//' . $authority;
81+
if ((!empty($authority) || 'file' === $scheme)
82+
&& !empty($path) && '/' !== $path[0]) {
83+
$path = '/' . $path;
84+
}
85+
$uri .= $path;
86+
if (!empty($query)) $uri .= '?' . $query;
87+
if (!empty($fragment)) $uri .= '#' . $fragment;
88+
return $uri;
89+
}
90+
91+
/**
92+
* Создание URI из частей uri разобранных с помощью parse_uri.
93+
* @param array части uri
94+
* @return static
95+
*/
96+
public static function createFromUriParts(array $parts): UriInterface
97+
{
98+
return (new self())->applyParts($parts);
99+
}
100+
101+
/**
102+
* Проверка является ли порт URI портом по умолчанию.
103+
* @return bool
104+
*/
105+
public function isDefaultPort(): bool
106+
{
107+
return $this->getPort() === null
108+
|| (isset(self::$defaultPorts[$this->getScheme()])
109+
&& $this->getPort() === self::$defaultPorts[$this->getScheme()]);
110+
}
111+
112+
/**
113+
* Проверка на сетевой uri.
114+
* @return bool
115+
*/
116+
public function isNetwork(): bool
117+
{
118+
return !empty($this->getScheme()) && !empty($this->getAuthority());
119+
}
120+
121+
/**
122+
* Проверка uri на абсолютный.
123+
* @return bool
124+
*/
125+
public function isAbsolute(): bool
126+
{
127+
return empty($this->getScheme())
128+
&& empty($this->getAuthority())
129+
&& !empty($this->getPath()) && '/' === $this->getPath()[0];
130+
}
131+
132+
/**
133+
* Проверка uri на относительный.
134+
* @return bool
135+
*/
136+
public function isRelative(): bool
137+
{
138+
return empty($this->getScheme())
139+
&& empty($this->getAuthority())
140+
&& (empty($this->getPath()) || '/' !== $this->getPath()[0]);
141+
}
142+
143+
144+
145+
/**
146+
* Получение схемы uri.
147+
* @return string|null uri scheme
148+
*/
149+
public function getScheme(): ?string
150+
{
151+
return $this->scheme;
152+
}
153+
154+
/**
155+
* Получение authority компонента uri.
156+
* Формат: "[user-info@]host[:port]"
157+
* @return string|null uri authority
158+
*/
159+
public function getAuthority(): ?string
160+
{
161+
$a = $this->host;
162+
if (!empty($this->userInfo)) $a = $this->userInfo . '@' . $a;
163+
if (!empty($this->port)) $a .= ':' . $this->port;
164+
return $a;
165+
}
166+
167+
/**
168+
* Получение компонента пользовательской информации uri.
169+
* Формат: "username[:password]"
170+
* @return string|null uri userinfo
171+
*/
172+
public function getUserInfo(): ?string
173+
{
174+
return $this->userInfo;
175+
}
176+
177+
/**
178+
* Получение хоста uri.
179+
* @return string|null uri host
180+
*/
181+
public function getHost(): ?string
182+
{
183+
return $this->host;
184+
}
185+
186+
/**
187+
* Получение порта uri.
188+
* @return int|null uri port
189+
*/
190+
public function getPort(): ?int
191+
{
192+
return $this->port;
193+
}
194+
195+
/**
196+
* Получение пути uri.
197+
* @return string|null uri path
198+
*/
199+
public function getPath(): ?string
200+
{
201+
return $this->path;
202+
}
203+
204+
/**
205+
* Получение query строки uri.
206+
* @return string|null uri query string
207+
*/
208+
public function getQuery(): ?string
209+
{
210+
return $this->query;
211+
}
212+
213+
/**
214+
* Получение fragment компонента uri
215+
* @return string|null uri fragment
216+
*/
217+
public function getFragment(): ?string
218+
{
219+
return $this->fragment;
220+
}
221+
222+
223+
/**
224+
* Установка схемы uri.
225+
* @param string схема uri
226+
* @return self
227+
*/
228+
public function withScheme(string $scheme): UriInterface
229+
{
230+
$this->scheme = strtolower($scheme);
231+
$this->removeDefaultPort();
232+
if (empty($this->host) && in_array($this->scheme, ['http', 'https'])) {
233+
$this->withHost(self::HTTP_DEFAULT_HOST);
234+
}
235+
return $this;
236+
}
237+
238+
/**
239+
* Установка информации пользователя uri.
240+
* @param string имя пользователя
241+
* @param null|string пароль
242+
* @return self
243+
*/
244+
public function withUserInfo(string $user, string $password = null): UriInterface
245+
{
246+
$this->userInfo = $user;
247+
if (!empty($password)) {
248+
$this->userInfo .= ':' . $password;
249+
}
250+
return $this;
251+
}
252+
253+
/**
254+
* Установка хоста uri.
255+
* @param string хост
256+
* @return self
257+
*/
258+
public function withHost(string $host): UriInterface
259+
{
260+
$this->host = strtolower($host);
261+
return $this;
262+
}
263+
264+
/**
265+
* Установка порта uri.
266+
* @param null|int порт или null для сброса на порт по умолчанию
267+
* @return self
268+
*/
269+
public function withPort(int $port = null): UriInterface
270+
{
271+
if (is_int($port) && (0 > $port || 0xffff < $port)) {
272+
throw new \InvalidArgumentException('Invalid port: $port. Must be between 0 and 65535');
273+
}
274+
$this->port = $port;
275+
$this->removeDefaultPort();
276+
return $this;
277+
}
278+
279+
/**
280+
* Установка пути uri.
281+
* @param string|null путь
282+
* @return self
283+
*/
284+
public function withPath(string $path = null): UriInterface
285+
{
286+
$this->path = $path;
287+
return $this;
288+
}
289+
290+
/**
291+
* Установка query строки uri.
292+
* @param string|null query строка
293+
* @return self
294+
*/
295+
public function withQuery(string $query = null): UriInterface
296+
{
297+
$this->query = $query;
298+
return $this;
299+
}
300+
301+
/**
302+
* Установка query строки uri из маппинга.
303+
* @param array|null маппинг свойств query
304+
* @return self
305+
*/
306+
public function withQueryParams(array $params = null): UriInterface
307+
{
308+
foreach ($params as $name => $value) {
309+
$parts[] = urlencode($name) .'='. urlencode($value);
310+
}
311+
if (!empty($parts)) {
312+
return $this->withQuery(implode('&', $parts));
313+
}
314+
return $this;
315+
}
316+
317+
/**
318+
* Установка фрагмента uri.
319+
* @param string|null фрагмент uri
320+
* @return self
321+
*/
322+
public function withFragment(string $fragment = null): UriInterface
323+
{
324+
$this->fragment = $fragment;
325+
return $this;
326+
}
327+
328+
329+
/**
330+
* Применение частей uri разобранных с помощью parse_url.
331+
* @param array части uri
332+
* @return self
333+
*/
334+
private function applyParts(array $parts): UriInterface
335+
{
336+
$this->withScheme($parts['scheme'] ?? '');
337+
if (!empty($parts['user'])) {
338+
$this->withUserInfo($parts['user'], $parts['pass'] ?? null);
339+
}
340+
$this->withHost($parts['host'] ?? '');
341+
$this->withPort($parts['port'] ?? null);
342+
$this->withPath($parts['path'] ?? null);
343+
$this->withQuery($parts['query'] ?? null);
344+
$this->withFragment($parts['fragment'] ?? null);
345+
$this->removeDefaultPort();
346+
return $this;
347+
}
348+
349+
/**
350+
* Сброс порта по умолчанию.
351+
*/
352+
private function removeDefaultPort()
353+
{
354+
if ($this->port !== null && $this->isDefaultPort()) {
355+
$this->port = null;
356+
}
357+
}
358+
}

0 commit comments

Comments
 (0)