Minor dependency updates
[yaffs-website] / vendor / easyrdf / easyrdf / lib / EasyRdf / ParsedUri.php
1 <?php
2
3 /**
4  * EasyRdf
5  *
6  * LICENSE
7  *
8  * Copyright (c) 2009-2013 Nicholas J Humfrey.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright notice,
15  *    this list of conditions and the following disclaimer in the documentation
16  *    and/or other materials provided with the distribution.
17  * 3. The name of the author 'Nicholas J Humfrey" may be used to endorse or
18  *    promote products derived from this software without specific prior
19  *    written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  * @package    EasyRdf
34  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
35  * @license    http://www.opensource.org/licenses/bsd-license.php
36  */
37
38
39 /**
40  * A RFC3986 compliant URI parser
41  *
42  * @package    EasyRdf
43  * @copyright  Copyright (c) 2009-2013 Nicholas J Humfrey
44  * @license    http://www.opensource.org/licenses/bsd-license.php
45  * @link       http://www.ietf.org/rfc/rfc3986.txt
46  */
47 class EasyRdf_ParsedUri
48 {
49     // For all URIs:
50     private $scheme = null;
51     private $fragment = null;
52
53     // For hierarchical URIs:
54     private $authority = null;
55     private $path = null;
56     private $query = null;
57
58     const URI_REGEX = "|^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?|";
59
60     /** Constructor for creating a new parsed URI
61      *
62      * The $uri parameter can either be a string or an
63      * associative array with the following keys:
64      * scheme, authority, path, query, fragment
65      *
66      * @param  mixed $uri  The URI as a string or an array
67      * @return object EasyRdf_ParsedUri
68      */
69     public function __construct($uri = null)
70     {
71         if (is_string($uri)) {
72             if (preg_match(self::URI_REGEX, $uri, $matches)) {
73                 if (!empty($matches[1])) {
74                     $this->scheme = isset($matches[2]) ? $matches[2] : '';
75                 }
76                 if (!empty($matches[3])) {
77                     $this->authority = isset($matches[4]) ? $matches[4] : '';
78                 }
79                 $this->path = isset($matches[5]) ? $matches[5] : '';
80                 if (!empty($matches[6])) {
81                     $this->query = isset($matches[7]) ? $matches[7] : '';
82                 }
83                 if (!empty($matches[8])) {
84                     $this->fragment = isset($matches[9]) ? $matches[9] : '';
85                 }
86             }
87         } elseif (is_array($uri)) {
88             $this->scheme = isset($uri['scheme']) ? $uri['scheme'] : null;
89             $this->authority = isset($uri['authority']) ? $uri['authority'] : null;
90             $this->path = isset($uri['path']) ? $uri['path'] : null;
91             $this->query = isset($uri['query']) ? $uri['query'] : null;
92             $this->fragment = isset($uri['fragment']) ? $uri['fragment'] : null;
93         }
94     }
95
96
97     /** Returns true if this is an absolute (complete) URI
98      * @return boolean
99      */
100     public function isAbsolute()
101     {
102         return $this->scheme !== null;
103     }
104
105     /** Returns true if this is an relative (partial) URI
106      * @return boolean
107      */
108     public function isRelative()
109     {
110         return $this->scheme === null;
111     }
112
113     /** Returns the scheme of the URI (e.g. http)
114      * @return string
115      */
116     public function getScheme()
117     {
118         return $this->scheme;
119     }
120
121     /** Sets the scheme of the URI (e.g. http)
122      * @param string $scheme The new value for the scheme of the URI
123      */
124     public function setScheme($scheme)
125     {
126         $this->scheme = $scheme;
127     }
128
129     /** Returns the authority of the URI (e.g. www.example.com:8080)
130      * @return string
131      */
132     public function getAuthority()
133     {
134         return $this->authority;
135     }
136
137     /** Sets the authority of the URI (e.g. www.example.com:8080)
138      * @param string $authority The new value for the authority component of the URI
139      */
140     public function setAuthority($authority)
141     {
142         $this->authority = $authority;
143     }
144
145     /** Returns the path of the URI (e.g. /foo/bar)
146      * @return string
147      */
148     public function getPath()
149     {
150         return $this->path;
151     }
152
153     /** Set the path of the URI (e.g. /foo/bar)
154      * @param string $path The new value for the path component of the URI
155      */
156     public function setPath($path)
157     {
158         $this->path = $path;
159     }
160
161     /** Returns the query string part of the URI (e.g. foo=bar)
162      * @return string
163      */
164     public function getQuery()
165     {
166         return $this->query;
167     }
168
169     /** Set the query string of the URI (e.g. foo=bar)
170      * @param string $query The new value for the query string component of the URI
171      */
172     public function setQuery($query)
173     {
174         $this->query = $query;
175     }
176
177     /** Returns the fragment part of the URI (i.e. after the #)
178      * @return string
179      */
180     public function getFragment()
181     {
182         return $this->fragment;
183     }
184
185     /** Set the fragment of the URI (i.e. after the #)
186      * @param string $fragment The new value for the fragment component of the URI
187      */
188     public function setFragment($fragment)
189     {
190         $this->fragment = $fragment;
191     }
192
193
194     /**
195      * Normalises the path of this URI if it has one. Normalising a path means
196      * that any unnecessary '.' and '..' segments are removed. For example, the
197      * URI http://example.com/a/b/../c/./d would be normalised to
198      * http://example.com/a/c/d
199      *
200      * @return object EasyRdf_ParsedUri
201      */
202     public function normalise()
203     {
204         if (empty($this->path)) {
205             return $this;
206         }
207
208         // Remove ./ from the start
209         if (substr($this->path, 0, 2) == './') {
210             // Remove both characters
211             $this->path = substr($this->path, 2);
212         }
213
214         // Remove /. from the end
215         if (substr($this->path, -2) == '/.') {
216             // Remove only the last dot, not the slash!
217             $this->path = substr($this->path, 0, -1);
218         }
219
220         if (substr($this->path, -3) == '/..') {
221             $this->path .= '/';
222         }
223
224         // Split the path into its segments
225         $segments = explode('/', $this->path);
226         $newSegments = array();
227
228         // Remove all unnecessary '.' and '..' segments
229         foreach ($segments as $segment) {
230             if ($segment == '..') {
231                 // Remove the previous part of the path
232                 $count = count($newSegments);
233                 if ($count > 0 && $newSegments[$count-1]) {
234                     array_pop($newSegments);
235                 }
236             } elseif ($segment == '.') {
237                 // Ignore
238                 continue;
239             } else {
240                 array_push($newSegments, $segment);
241             }
242         }
243
244         // Construct the new normalised path
245         $this->path = implode($newSegments, '/');
246
247         // Allow easy chaining of methods
248         return $this;
249     }
250
251     /**
252      * Resolves a relative URI using this URI as the base URI.
253      */
254     public function resolve($relUri)
255     {
256         // If it is a string, then convert it to a parsed object
257         if (is_string($relUri)) {
258             $relUri = new EasyRdf_ParsedUri($relUri);
259         }
260
261         // This code is based on the pseudocode in section 5.2.2 of RFC3986
262         $target = new EasyRdf_ParsedUri();
263         if ($relUri->scheme) {
264             $target->scheme = $relUri->scheme;
265             $target->authority = $relUri->authority;
266             $target->path = $relUri->path;
267             $target->query = $relUri->query;
268         } else {
269             if ($relUri->authority) {
270                 $target->authority = $relUri->authority;
271                 $target->path = $relUri->path;
272                 $target->query = $relUri->query;
273             } else {
274                 if (empty($relUri->path)) {
275                     $target->path = $this->path;
276                     if ($relUri->query) {
277                         $target->query = $relUri->query;
278                     } else {
279                         $target->query = $this->query;
280                     }
281                 } else {
282                     if (substr($relUri->path, 0, 1) == '/') {
283                         $target->path = $relUri->path;
284                     } else {
285                         $path = $this->path;
286                         $lastSlash = strrpos($path, '/');
287                         if ($lastSlash !== false) {
288                             $path = substr($path, 0, $lastSlash + 1);
289                         } else {
290                             $path = '/';
291                         }
292
293                         $target->path .= $path . $relUri->path;
294                     }
295                     $target->query = $relUri->query;
296                 }
297                 $target->authority = $this->authority;
298             }
299             $target->scheme = $this->scheme;
300         }
301
302         $target->fragment = $relUri->fragment;
303
304         $target->normalise();
305
306         return $target;
307     }
308
309     /** Convert the parsed URI back into a string
310      *
311      * @return string The URI as a string
312      */
313     public function toString()
314     {
315         $str = '';
316         if ($this->scheme !== null) {
317             $str .= $this->scheme . ':';
318         }
319         if ($this->authority !== null) {
320             $str .= '//' . $this->authority;
321         }
322         $str .= $this->path;
323         if ($this->query !== null) {
324             $str .= '?' . $this->query;
325         }
326         if ($this->fragment !== null) {
327             $str .= '#' . $this->fragment;
328         }
329         return $str;
330     }
331
332     /** Magic method to convert the URI, when casted, back to a string
333      *
334      * @return string The URI as a string
335      */
336     public function __toString()
337     {
338         return $this->toString();
339     }
340 }