-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUri.php
175 lines (159 loc) · 4.7 KB
/
Uri.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
<?php
namespace JsonRef;
/**
* Encapsulates a valid URI. Suprised PHP has no such class.
* Note parse_url() parses URLs not URIs but it ~works. Only works with absolute file paths though.
* @todo Not really a URI. This is a stub for an eventual higher quality implementation.
*/
class Uri
{
private $parts = [];
/**
* Init. The simplest valid Uri is "#" ("" is not valid).
*/
public function __construct(string $uri) {
$parse = preg_replace("/#$/", "# ", urldecode($uri)); // Ensure empty frag parses to not null.
$parse = parse_url($parse);
if(isset($parse['fragment']) && $parse['fragment'] == " ") {
$parse['fragment'] = "";
}
if(!$parse) {
throw new UriException("Could not parse URI '$uri'");
}
foreach($parse as $part => $value) {
$this->set($part, $value);
}
}
/**
* Get part.
*/
public function get($part) {
return isset($this->parts[$part]) ? $this->parts[$part] : null;
}
/**
* Set part.
* @todo Ensure the URI remains valid.
*/
public function set($part, $value) {
$allow = ['scheme', 'host', 'user', 'pass', 'path', 'port', 'query', 'fragment'];
if(!in_array($part, $allow)) {
throw new UriException("Can't set $part.");
}
switch($part) {
case 'path': {
$this->parts['path'] = preg_replace("#\/+#", "/", $value);
break;
}
default: {
$this->parts[$part] = $value;
}
}
}
/**
* Allow certain parts to be unset.
* @todo Ensure the URI remains valid.
*/
public function clear($part) {
$allow = ['user', 'pass', 'path', 'query', 'fragment'];
if(!in_array($part, $allow)) {
throw new UriException("Can't unset $part.");
}
if($part == 'path') {
unset($this->parts['query']);
unset($this->parts['fragment']);
}
unset($this->parts[$part]);
}
public function __get($part) {
return $this->get($part);
}
public function __set($part, $value) {
return $this->set($part, $value);
}
public function __unset($part) {
return $this->clear($part);
}
/**
* Returns true iff this URI is an absolute URI.
* According to RFC3986 only the scheme need be defined for a URI to be absolute.
*/
public function isAbsoluteUri() {
return isset($this->parts['scheme']);
}
/**
* Returns true iff this URI is a relative URI.
*/
public function isRelativeUri() {
return !$this->isAbsoluteUri();
}
/**
* Return a URI that is this URI rebased against $base, an absolute Base URI.
* If this URI is an absolute URI a copy of this URI is returned.
* Notes: Always use the reference's fragment. Replace the base's query only if path is non empty.
* @see https://tools.ietf.org/html/rfc3986#section-5.2.
*/
public function baseOn(Uri $base) {
$uri = null;
if($base->isRelativeUri()) {
throw new UriException("Can't base $this against $base. Invalid base URI");
}
if($this->isAbsoluteUri()) {
$uri = clone $this;
}
else {
$uri = clone $base;
$path = $this->get('path');
$query = $this->get('query');
if(empty($path)) {
if(isset($query)) {
$uri->set('query', $query);
}
}
else if(strpos($path, '/') === 0) {
$uri->set('path', $path);
$uri->set('query', $query);
}
else {
$basePath = preg_replace('#/[^/]*$#', "", $uri->get('path'));
$uri->set('path', $basePath . "/" . $path);
$uri->set('query', $query);
}
$uri->set('fragment', $this->get('fragment'));
}
return $uri;
}
/**
* Same as baseOn() but the other way around.
*/
public function resolveRelativeUriOn(Uri $uri) {
return $uri->baseOn($this);
}
/**
* To a string!
*/
public function __toString() {
return self::unparse_url($this->parts);
}
/**
* To an array!
*/
public function toArray() {
return $this->parts;
}
/**
* To string method for parse_url() output. C&P from http://php.net/.
*/
public static function unparse_url(array $parts) {
$scheme = isset($parts['scheme']) ? $parts['scheme'] . '://' : '';
$host = isset($parts['host']) ? $parts['host'] : '';
$port = isset($parts['port']) ? ':' . $parts['port'] : '';
$user = isset($parts['user']) ? $parts['user'] : '';
$pass = isset($parts['pass']) ? ':' . $parts['pass'] : '';
$pass = ($user || $pass) ? "$pass@" : '';
$path = isset($parts['path']) ? $parts['path'] : '';
$query = isset($parts['query']) ? '?' . $parts['query'] : '';
$fragment = isset($parts['fragment']) ? '#' . $parts['fragment'] : '';
return "$scheme$user$pass$host$port$path$query$fragment";
}
}
class UriException extends \Exception {}