diff options
author | Nicolas LÅ“uillet <nicolas.loeuillet@gmail.com> | 2013-08-25 12:12:53 -0700 |
---|---|---|
committer | Nicolas LÅ“uillet <nicolas.loeuillet@gmail.com> | 2013-08-25 12:12:53 -0700 |
commit | c51be6b697da573cdcf0788eb8617130ce5517a4 (patch) | |
tree | 642eaf70afb134dee5f274c84bf15b8aab00c117 /inc/3rdparty/simplepie/SimplePie/IRI.php | |
parent | 7ba37bd91a43321196e6d867caf9e298e82c6d6c (diff) | |
parent | 063fc1a7baaf6f7e1fb08eced058962a6140a471 (diff) | |
download | wallabag-c51be6b697da573cdcf0788eb8617130ce5517a4.tar.gz wallabag-c51be6b697da573cdcf0788eb8617130ce5517a4.tar.zst wallabag-c51be6b697da573cdcf0788eb8617130ce5517a4.zip |
Merge pull request #181 from inthepoche/dev
beta4
Diffstat (limited to 'inc/3rdparty/simplepie/SimplePie/IRI.php')
-rw-r--r-- | inc/3rdparty/simplepie/SimplePie/IRI.php | 997 |
1 files changed, 997 insertions, 0 deletions
diff --git a/inc/3rdparty/simplepie/SimplePie/IRI.php b/inc/3rdparty/simplepie/SimplePie/IRI.php new file mode 100644 index 00000000..0fead324 --- /dev/null +++ b/inc/3rdparty/simplepie/SimplePie/IRI.php | |||
@@ -0,0 +1,997 @@ | |||
1 | <?php | ||
2 | /** | ||
3 | * SimplePie | ||
4 | * | ||
5 | * A PHP-Based RSS and Atom Feed Framework. | ||
6 | * Takes the hard work out of managing a complete RSS/Atom solution. | ||
7 | * | ||
8 | * Copyright (c) 2004-2009, Ryan Parman, Geoffrey Sneddon, Ryan McCue, and contributors | ||
9 | * All rights reserved. | ||
10 | * | ||
11 | * Redistribution and use in source and binary forms, with or without modification, are | ||
12 | * permitted provided that the following conditions are met: | ||
13 | * | ||
14 | * * Redistributions of source code must retain the above copyright notice, this list of | ||
15 | * conditions and the following disclaimer. | ||
16 | * | ||
17 | * * Redistributions in binary form must reproduce the above copyright notice, this list | ||
18 | * of conditions and the following disclaimer in the documentation and/or other materials | ||
19 | * provided with the distribution. | ||
20 | * | ||
21 | * * Neither the name of the SimplePie Team nor the names of its contributors may be used | ||
22 | * to endorse or promote products derived from this software without specific prior | ||
23 | * written permission. | ||
24 | * | ||
25 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS | ||
26 | * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | ||
27 | * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS | ||
28 | * AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
29 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
30 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
31 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | ||
32 | * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
33 | * POSSIBILITY OF SUCH DAMAGE. | ||
34 | * | ||
35 | * @package SimplePie | ||
36 | * @version 1.3-dev | ||
37 | * @copyright 2004-2010 Ryan Parman, Geoffrey Sneddon, Ryan McCue | ||
38 | * @author Ryan Parman | ||
39 | * @author Geoffrey Sneddon | ||
40 | * @author Ryan McCue | ||
41 | * @link http://simplepie.org/ SimplePie | ||
42 | * @license http://www.opensource.org/licenses/bsd-license.php BSD License | ||
43 | * @todo phpDoc comments | ||
44 | */ | ||
45 | |||
46 | /** | ||
47 | * IRI parser/serialiser | ||
48 | * | ||
49 | * @package SimplePie | ||
50 | */ | ||
51 | class SimplePie_IRI | ||
52 | { | ||
53 | /** | ||
54 | * Scheme | ||
55 | * | ||
56 | * @access private | ||
57 | * @var string | ||
58 | */ | ||
59 | var $scheme; | ||
60 | |||
61 | /** | ||
62 | * User Information | ||
63 | * | ||
64 | * @access private | ||
65 | * @var string | ||
66 | */ | ||
67 | var $userinfo; | ||
68 | |||
69 | /** | ||
70 | * Host | ||
71 | * | ||
72 | * @access private | ||
73 | * @var string | ||
74 | */ | ||
75 | var $host; | ||
76 | |||
77 | /** | ||
78 | * Port | ||
79 | * | ||
80 | * @access private | ||
81 | * @var string | ||
82 | */ | ||
83 | var $port; | ||
84 | |||
85 | /** | ||
86 | * Path | ||
87 | * | ||
88 | * @access private | ||
89 | * @var string | ||
90 | */ | ||
91 | var $path; | ||
92 | |||
93 | /** | ||
94 | * Query | ||
95 | * | ||
96 | * @access private | ||
97 | * @var string | ||
98 | */ | ||
99 | var $query; | ||
100 | |||
101 | /** | ||
102 | * Fragment | ||
103 | * | ||
104 | * @access private | ||
105 | * @var string | ||
106 | */ | ||
107 | var $fragment; | ||
108 | |||
109 | /** | ||
110 | * Whether the object represents a valid IRI | ||
111 | * | ||
112 | * @access private | ||
113 | * @var array | ||
114 | */ | ||
115 | var $valid = array(); | ||
116 | |||
117 | /** | ||
118 | * Return the entire IRI when you try and read the object as a string | ||
119 | * | ||
120 | * @access public | ||
121 | * @return string | ||
122 | */ | ||
123 | public function __toString() | ||
124 | { | ||
125 | return $this->get_iri(); | ||
126 | } | ||
127 | |||
128 | /** | ||
129 | * Create a new IRI object, from a specified string | ||
130 | * | ||
131 | * @access public | ||
132 | * @param string $iri | ||
133 | * @return SimplePie_IRI | ||
134 | */ | ||
135 | public function __construct($iri) | ||
136 | { | ||
137 | $iri = (string) $iri; | ||
138 | if ($iri !== '') | ||
139 | { | ||
140 | $parsed = $this->parse_iri($iri); | ||
141 | $this->set_scheme($parsed['scheme']); | ||
142 | $this->set_authority($parsed['authority']); | ||
143 | $this->set_path($parsed['path']); | ||
144 | $this->set_query($parsed['query']); | ||
145 | $this->set_fragment($parsed['fragment']); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * Create a new IRI object by resolving a relative IRI | ||
151 | * | ||
152 | * @static | ||
153 | * @access public | ||
154 | * @param SimplePie_IRI $base Base IRI | ||
155 | * @param string $relative Relative IRI | ||
156 | * @return SimplePie_IRI | ||
157 | */ | ||
158 | public static function absolutize($base, $relative) | ||
159 | { | ||
160 | $relative = (string) $relative; | ||
161 | if ($relative !== '') | ||
162 | { | ||
163 | $relative = new SimplePie_IRI($relative); | ||
164 | if ($relative->get_scheme() !== null) | ||
165 | { | ||
166 | $target = $relative; | ||
167 | } | ||
168 | elseif ($base->get_iri() !== null) | ||
169 | { | ||
170 | if ($relative->get_authority() !== null) | ||
171 | { | ||
172 | $target = $relative; | ||
173 | $target->set_scheme($base->get_scheme()); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | $target = new SimplePie_IRI(''); | ||
178 | $target->set_scheme($base->get_scheme()); | ||
179 | $target->set_userinfo($base->get_userinfo()); | ||
180 | $target->set_host($base->get_host()); | ||
181 | $target->set_port($base->get_port()); | ||
182 | if ($relative->get_path() !== null) | ||
183 | { | ||
184 | if (strpos($relative->get_path(), '/') === 0) | ||
185 | { | ||
186 | $target->set_path($relative->get_path()); | ||
187 | } | ||
188 | elseif (($base->get_userinfo() !== null || $base->get_host() !== null || $base->get_port() !== null) && $base->get_path() === null) | ||
189 | { | ||
190 | $target->set_path('/' . $relative->get_path()); | ||
191 | } | ||
192 | elseif (($last_segment = strrpos($base->get_path(), '/')) !== false) | ||
193 | { | ||
194 | $target->set_path(substr($base->get_path(), 0, $last_segment + 1) . $relative->get_path()); | ||
195 | } | ||
196 | else | ||
197 | { | ||
198 | $target->set_path($relative->get_path()); | ||
199 | } | ||
200 | $target->set_query($relative->get_query()); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | $target->set_path($base->get_path()); | ||
205 | if ($relative->get_query() !== null) | ||
206 | { | ||
207 | $target->set_query($relative->get_query()); | ||
208 | } | ||
209 | elseif ($base->get_query() !== null) | ||
210 | { | ||
211 | $target->set_query($base->get_query()); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | $target->set_fragment($relative->get_fragment()); | ||
216 | } | ||
217 | else | ||
218 | { | ||
219 | // No base URL, just return the relative URL | ||
220 | $target = $relative; | ||
221 | } | ||
222 | } | ||
223 | else | ||
224 | { | ||
225 | $target = $base; | ||
226 | } | ||
227 | return $target; | ||
228 | } | ||
229 | |||
230 | /** | ||
231 | * Parse an IRI into scheme/authority/path/query/fragment segments | ||
232 | * | ||
233 | * @access private | ||
234 | * @param string $iri | ||
235 | * @return array | ||
236 | */ | ||
237 | public function parse_iri($iri) | ||
238 | { | ||
239 | preg_match('/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/', $iri, $match); | ||
240 | for ($i = count($match); $i <= 9; $i++) | ||
241 | { | ||
242 | $match[$i] = ''; | ||
243 | } | ||
244 | return array('scheme' => $match[2], 'authority' => $match[4], 'path' => $match[5], 'query' => $match[7], 'fragment' => $match[9]); | ||
245 | } | ||
246 | |||
247 | /** | ||
248 | * Remove dot segments from a path | ||
249 | * | ||
250 | * @access private | ||
251 | * @param string $input | ||
252 | * @return string | ||
253 | */ | ||
254 | public function remove_dot_segments($input) | ||
255 | { | ||
256 | $output = ''; | ||
257 | while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') | ||
258 | { | ||
259 | // A: If the input buffer begins with a prefix of "../" or "./", then remove that prefix from the input buffer; otherwise, | ||
260 | if (strpos($input, '../') === 0) | ||
261 | { | ||
262 | $input = substr($input, 3); | ||
263 | } | ||
264 | elseif (strpos($input, './') === 0) | ||
265 | { | ||
266 | $input = substr($input, 2); | ||
267 | } | ||
268 | // B: if the input buffer begins with a prefix of "/./" or "/.", where "." is a complete path segment, then replace that prefix with "/" in the input buffer; otherwise, | ||
269 | elseif (strpos($input, '/./') === 0) | ||
270 | { | ||
271 | $input = substr_replace($input, '/', 0, 3); | ||
272 | } | ||
273 | elseif ($input === '/.') | ||
274 | { | ||
275 | $input = '/'; | ||
276 | } | ||
277 | // C: if the input buffer begins with a prefix of "/../" or "/..", where ".." is a complete path segment, then replace that prefix with "/" in the input buffer and remove the last segment and its preceding "/" (if any) from the output buffer; otherwise, | ||
278 | elseif (strpos($input, '/../') === 0) | ||
279 | { | ||
280 | $input = substr_replace($input, '/', 0, 4); | ||
281 | $output = substr_replace($output, '', strrpos($output, '/')); | ||
282 | } | ||
283 | elseif ($input === '/..') | ||
284 | { | ||
285 | $input = '/'; | ||
286 | $output = substr_replace($output, '', strrpos($output, '/')); | ||
287 | } | ||
288 | // D: if the input buffer consists only of "." or "..", then remove that from the input buffer; otherwise, | ||
289 | elseif ($input === '.' || $input === '..') | ||
290 | { | ||
291 | $input = ''; | ||
292 | } | ||
293 | // E: move the first path segment in the input buffer to the end of the output buffer, including the initial "/" character (if any) and any subsequent characters up to, but not including, the next "/" character or the end of the input buffer | ||
294 | elseif (($pos = strpos($input, '/', 1)) !== false) | ||
295 | { | ||
296 | $output .= substr($input, 0, $pos); | ||
297 | $input = substr_replace($input, '', 0, $pos); | ||
298 | } | ||
299 | else | ||
300 | { | ||
301 | $output .= $input; | ||
302 | $input = ''; | ||
303 | } | ||
304 | } | ||
305 | return $output . $input; | ||
306 | } | ||
307 | |||
308 | /** | ||
309 | * Replace invalid character with percent encoding | ||
310 | * | ||
311 | * @param string $string Input string | ||
312 | * @param string $valid_chars Valid characters not in iunreserved or iprivate (this is ASCII-only) | ||
313 | * @param int $case Normalise case | ||
314 | * @param bool $iprivate Allow iprivate | ||
315 | * @return string | ||
316 | */ | ||
317 | protected function replace_invalid_with_pct_encoding($string, $valid_chars, $case = SIMPLEPIE_SAME_CASE, $iprivate = false) | ||
318 | { | ||
319 | // Normalize as many pct-encoded sections as possible | ||
320 | $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string); | ||
321 | |||
322 | // Replace invalid percent characters | ||
323 | $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); | ||
324 | |||
325 | // Add unreserved and % to $valid_chars (the latter is safe because all | ||
326 | // pct-encoded sections are now valid). | ||
327 | $valid_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; | ||
328 | |||
329 | // Now replace any bytes that aren't allowed with their pct-encoded versions | ||
330 | $position = 0; | ||
331 | $strlen = strlen($string); | ||
332 | while (($position += strspn($string, $valid_chars, $position)) < $strlen) | ||
333 | { | ||
334 | $value = ord($string[$position]); | ||
335 | |||
336 | // Start position | ||
337 | $start = $position; | ||
338 | |||
339 | // By default we are valid | ||
340 | $valid = true; | ||
341 | |||
342 | // No one byte sequences are valid due to the while. | ||
343 | // Two byte sequence: | ||
344 | if (($value & 0xE0) === 0xC0) | ||
345 | { | ||
346 | $character = ($value & 0x1F) << 6; | ||
347 | $length = 2; | ||
348 | $remaining = 1; | ||
349 | } | ||
350 | // Three byte sequence: | ||
351 | elseif (($value & 0xF0) === 0xE0) | ||
352 | { | ||
353 | $character = ($value & 0x0F) << 12; | ||
354 | $length = 3; | ||
355 | $remaining = 2; | ||
356 | } | ||
357 | // Four byte sequence: | ||
358 | elseif (($value & 0xF8) === 0xF0) | ||
359 | { | ||
360 | $character = ($value & 0x07) << 18; | ||
361 | $length = 4; | ||
362 | $remaining = 3; | ||
363 | } | ||
364 | // Invalid byte: | ||
365 | else | ||
366 | { | ||
367 | $valid = false; | ||
368 | $length = 1; | ||
369 | $remaining = 0; | ||
370 | } | ||
371 | |||
372 | if ($remaining) | ||
373 | { | ||
374 | if ($position + $length <= $strlen) | ||
375 | { | ||
376 | for ($position++; $remaining; $position++) | ||
377 | { | ||
378 | $value = ord($string[$position]); | ||
379 | |||
380 | // Check that the byte is valid, then add it to the character: | ||
381 | if (($value & 0xC0) === 0x80) | ||
382 | { | ||
383 | $character |= ($value & 0x3F) << (--$remaining * 6); | ||
384 | } | ||
385 | // If it is invalid, count the sequence as invalid and reprocess the current byte: | ||
386 | else | ||
387 | { | ||
388 | $valid = false; | ||
389 | $position--; | ||
390 | break; | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | $position = $strlen - 1; | ||
397 | $valid = false; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | // Percent encode anything invalid or not in ucschar | ||
402 | if ( | ||
403 | // Invalid sequences | ||
404 | !$valid | ||
405 | // Non-shortest form sequences are invalid | ||
406 | || $length > 1 && $character <= 0x7F | ||
407 | || $length > 2 && $character <= 0x7FF | ||
408 | || $length > 3 && $character <= 0xFFFF | ||
409 | // Outside of range of ucschar codepoints | ||
410 | // Noncharacters | ||
411 | || ($character & 0xFFFE) === 0xFFFE | ||
412 | || $character >= 0xFDD0 && $character <= 0xFDEF | ||
413 | || ( | ||
414 | // Everything else not in ucschar | ||
415 | $character > 0xD7FF && $character < 0xF900 | ||
416 | || $character < 0xA0 | ||
417 | || $character > 0xEFFFD | ||
418 | ) | ||
419 | && ( | ||
420 | // Everything not in iprivate, if it applies | ||
421 | !$iprivate | ||
422 | || $character < 0xE000 | ||
423 | || $character > 0x10FFFD | ||
424 | ) | ||
425 | ) | ||
426 | { | ||
427 | // If we were a character, pretend we weren't, but rather an error. | ||
428 | if ($valid) | ||
429 | $position--; | ||
430 | |||
431 | for ($j = $start; $j <= $position; $j++) | ||
432 | { | ||
433 | $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); | ||
434 | $j += 2; | ||
435 | $position += 2; | ||
436 | $strlen += 2; | ||
437 | } | ||
438 | } | ||
439 | } | ||
440 | |||
441 | // Normalise case | ||
442 | if ($case & SIMPLEPIE_LOWERCASE) | ||
443 | { | ||
444 | $string = strtolower($string); | ||
445 | } | ||
446 | elseif ($case & SIMPLEPIE_UPPERCASE) | ||
447 | { | ||
448 | $string = strtoupper($string); | ||
449 | } | ||
450 | |||
451 | return $string; | ||
452 | } | ||
453 | |||
454 | /** | ||
455 | * Callback function for preg_replace_callback. | ||
456 | * | ||
457 | * Removes sequences of percent encoded bytes that represent UTF-8 | ||
458 | * encoded characters in iunreserved | ||
459 | * | ||
460 | * @param array $match PCRE match | ||
461 | * @return string Replacement | ||
462 | */ | ||
463 | protected function remove_iunreserved_percent_encoded($match) | ||
464 | { | ||
465 | // As we just have valid percent encoded sequences we can just explode | ||
466 | // and ignore the first member of the returned array (an empty string). | ||
467 | $bytes = explode('%', $match[0]); | ||
468 | |||
469 | // Initialize the new string (this is what will be returned) and that | ||
470 | // there are no bytes remaining in the current sequence (unsurprising | ||
471 | // at the first byte!). | ||
472 | $string = ''; | ||
473 | $remaining = 0; | ||
474 | |||
475 | // Loop over each and every byte, and set $value to its value | ||
476 | for ($i = 1, $len = count($bytes); $i < $len; $i++) | ||
477 | { | ||
478 | $value = hexdec($bytes[$i]); | ||
479 | |||
480 | // If we're the first byte of sequence: | ||
481 | if (!$remaining) | ||
482 | { | ||
483 | // Start position | ||
484 | $start = $i; | ||
485 | |||
486 | // By default we are valid | ||
487 | $valid = true; | ||
488 | |||
489 | // One byte sequence: | ||
490 | if ($value <= 0x7F) | ||
491 | { | ||
492 | $character = $value; | ||
493 | $length = 1; | ||
494 | } | ||
495 | // Two byte sequence: | ||
496 | elseif (($value & 0xE0) === 0xC0) | ||
497 | { | ||
498 | $character = ($value & 0x1F) << 6; | ||
499 | $length = 2; | ||
500 | $remaining = 1; | ||
501 | } | ||
502 | // Three byte sequence: | ||
503 | elseif (($value & 0xF0) === 0xE0) | ||
504 | { | ||
505 | $character = ($value & 0x0F) << 12; | ||
506 | $length = 3; | ||
507 | $remaining = 2; | ||
508 | } | ||
509 | // Four byte sequence: | ||
510 | elseif (($value & 0xF8) === 0xF0) | ||
511 | { | ||
512 | $character = ($value & 0x07) << 18; | ||
513 | $length = 4; | ||
514 | $remaining = 3; | ||
515 | } | ||
516 | // Invalid byte: | ||
517 | else | ||
518 | { | ||
519 | $valid = false; | ||
520 | $remaining = 0; | ||
521 | } | ||
522 | } | ||
523 | // Continuation byte: | ||
524 | else | ||
525 | { | ||
526 | // Check that the byte is valid, then add it to the character: | ||
527 | if (($value & 0xC0) === 0x80) | ||
528 | { | ||
529 | $remaining--; | ||
530 | $character |= ($value & 0x3F) << ($remaining * 6); | ||
531 | } | ||
532 | // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: | ||
533 | else | ||
534 | { | ||
535 | $valid = false; | ||
536 | $remaining = 0; | ||
537 | $i--; | ||
538 | } | ||
539 | } | ||
540 | |||
541 | // If we've reached the end of the current byte sequence, append it to Unicode::$data | ||
542 | if (!$remaining) | ||
543 | { | ||
544 | // Percent encode anything invalid or not in iunreserved | ||
545 | if ( | ||
546 | // Invalid sequences | ||
547 | !$valid | ||
548 | // Non-shortest form sequences are invalid | ||
549 | || $length > 1 && $character <= 0x7F | ||
550 | || $length > 2 && $character <= 0x7FF | ||
551 | || $length > 3 && $character <= 0xFFFF | ||
552 | // Outside of range of iunreserved codepoints | ||
553 | || $character < 0x2D | ||
554 | || $character > 0xEFFFD | ||
555 | // Noncharacters | ||
556 | || ($character & 0xFFFE) === 0xFFFE | ||
557 | || $character >= 0xFDD0 && $character <= 0xFDEF | ||
558 | // Everything else not in iunreserved (this is all BMP) | ||
559 | || $character === 0x2F | ||
560 | || $character > 0x39 && $character < 0x41 | ||
561 | || $character > 0x5A && $character < 0x61 | ||
562 | || $character > 0x7A && $character < 0x7E | ||
563 | || $character > 0x7E && $character < 0xA0 | ||
564 | || $character > 0xD7FF && $character < 0xF900 | ||
565 | ) | ||
566 | { | ||
567 | for ($j = $start; $j <= $i; $j++) | ||
568 | { | ||
569 | $string .= '%' . strtoupper($bytes[$j]); | ||
570 | } | ||
571 | } | ||
572 | else | ||
573 | { | ||
574 | for ($j = $start; $j <= $i; $j++) | ||
575 | { | ||
576 | $string .= chr(hexdec($bytes[$j])); | ||
577 | } | ||
578 | } | ||
579 | } | ||
580 | } | ||
581 | |||
582 | // If we have any bytes left over they are invalid (i.e., we are | ||
583 | // mid-way through a multi-byte sequence) | ||
584 | if ($remaining) | ||
585 | { | ||
586 | for ($j = $start; $j < $len; $j++) | ||
587 | { | ||
588 | $string .= '%' . strtoupper($bytes[$j]); | ||
589 | } | ||
590 | } | ||
591 | |||
592 | return $string; | ||
593 | } | ||
594 | |||
595 | /** | ||
596 | * Check if the object represents a valid IRI | ||
597 | * | ||
598 | * @access public | ||
599 | * @return bool | ||
600 | */ | ||
601 | public function is_valid() | ||
602 | { | ||
603 | return array_sum($this->valid) === count($this->valid); | ||
604 | } | ||
605 | |||
606 | /** | ||
607 | * Set the scheme. Returns true on success, false on failure (if there are | ||
608 | * any invalid characters). | ||
609 | * | ||
610 | * @access public | ||
611 | * @param string $scheme | ||
612 | * @return bool | ||
613 | */ | ||
614 | public function set_scheme($scheme) | ||
615 | { | ||
616 | if ($scheme === null || $scheme === '') | ||
617 | { | ||
618 | $this->scheme = null; | ||
619 | } | ||
620 | else | ||
621 | { | ||
622 | $len = strlen($scheme); | ||
623 | switch (true) | ||
624 | { | ||
625 | case $len > 1: | ||
626 | if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-.', 1)) | ||
627 | { | ||
628 | $this->scheme = null; | ||
629 | $this->valid[__FUNCTION__] = false; | ||
630 | return false; | ||
631 | } | ||
632 | |||
633 | case $len > 0: | ||
634 | if (!strspn($scheme, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 0, 1)) | ||
635 | { | ||
636 | $this->scheme = null; | ||
637 | $this->valid[__FUNCTION__] = false; | ||
638 | return false; | ||
639 | } | ||
640 | } | ||
641 | $this->scheme = strtolower($scheme); | ||
642 | } | ||
643 | $this->valid[__FUNCTION__] = true; | ||
644 | return true; | ||
645 | } | ||
646 | |||
647 | /** | ||
648 | * Set the authority. Returns true on success, false on failure (if there are | ||
649 | * any invalid characters). | ||
650 | * | ||
651 | * @access public | ||
652 | * @param string $authority | ||
653 | * @return bool | ||
654 | */ | ||
655 | public function set_authority($authority) | ||
656 | { | ||
657 | if (($userinfo_end = strrpos($authority, '@')) !== false) | ||
658 | { | ||
659 | $userinfo = substr($authority, 0, $userinfo_end); | ||
660 | $authority = substr($authority, $userinfo_end + 1); | ||
661 | } | ||
662 | else | ||
663 | { | ||
664 | $userinfo = null; | ||
665 | } | ||
666 | |||
667 | if (($port_start = strpos($authority, ':')) !== false) | ||
668 | { | ||
669 | $port = substr($authority, $port_start + 1); | ||
670 | if ($port === false) | ||
671 | { | ||
672 | $port = null; | ||
673 | } | ||
674 | $authority = substr($authority, 0, $port_start); | ||
675 | } | ||
676 | else | ||
677 | { | ||
678 | $port = null; | ||
679 | } | ||
680 | |||
681 | return $this->set_userinfo($userinfo) && $this->set_host($authority) && $this->set_port($port); | ||
682 | } | ||
683 | |||
684 | /** | ||
685 | * Set the userinfo. | ||
686 | * | ||
687 | * @access public | ||
688 | * @param string $userinfo | ||
689 | * @return bool | ||
690 | */ | ||
691 | public function set_userinfo($userinfo) | ||
692 | { | ||
693 | if ($userinfo === null || $userinfo === '') | ||
694 | { | ||
695 | $this->userinfo = null; | ||
696 | } | ||
697 | else | ||
698 | { | ||
699 | $this->userinfo = $this->replace_invalid_with_pct_encoding($userinfo, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:'); | ||
700 | } | ||
701 | $this->valid[__FUNCTION__] = true; | ||
702 | return true; | ||
703 | } | ||
704 | |||
705 | /** | ||
706 | * Set the host. Returns true on success, false on failure (if there are | ||
707 | * any invalid characters). | ||
708 | * | ||
709 | * @access public | ||
710 | * @param string $host | ||
711 | * @return bool | ||
712 | */ | ||
713 | public function set_host($host) | ||
714 | { | ||
715 | if ($host === null || $host === '') | ||
716 | { | ||
717 | $this->host = null; | ||
718 | $this->valid[__FUNCTION__] = true; | ||
719 | return true; | ||
720 | } | ||
721 | elseif ($host[0] === '[' && substr($host, -1) === ']') | ||
722 | { | ||
723 | if (SimplePie_Net_IPv6::checkIPv6(substr($host, 1, -1))) | ||
724 | { | ||
725 | $this->host = $host; | ||
726 | $this->valid[__FUNCTION__] = true; | ||
727 | return true; | ||
728 | } | ||
729 | else | ||
730 | { | ||
731 | $this->host = null; | ||
732 | $this->valid[__FUNCTION__] = false; | ||
733 | return false; | ||
734 | } | ||
735 | } | ||
736 | else | ||
737 | { | ||
738 | $this->host = $this->replace_invalid_with_pct_encoding($host, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=', SIMPLEPIE_LOWERCASE); | ||
739 | $this->valid[__FUNCTION__] = true; | ||
740 | return true; | ||
741 | } | ||
742 | } | ||
743 | |||
744 | /** | ||
745 | * Set the port. Returns true on success, false on failure (if there are | ||
746 | * any invalid characters). | ||
747 | * | ||
748 | * @access public | ||
749 | * @param string $port | ||
750 | * @return bool | ||
751 | */ | ||
752 | public function set_port($port) | ||
753 | { | ||
754 | if ($port === null || $port === '') | ||
755 | { | ||
756 | $this->port = null; | ||
757 | $this->valid[__FUNCTION__] = true; | ||
758 | return true; | ||
759 | } | ||
760 | elseif (strspn($port, '0123456789') === strlen($port)) | ||
761 | { | ||
762 | $this->port = (int) $port; | ||
763 | $this->valid[__FUNCTION__] = true; | ||
764 | return true; | ||
765 | } | ||
766 | else | ||
767 | { | ||
768 | $this->port = null; | ||
769 | $this->valid[__FUNCTION__] = false; | ||
770 | return false; | ||
771 | } | ||
772 | } | ||
773 | |||
774 | /** | ||
775 | * Set the path. | ||
776 | * | ||
777 | * @access public | ||
778 | * @param string $path | ||
779 | * @return bool | ||
780 | */ | ||
781 | public function set_path($path) | ||
782 | { | ||
783 | if ($path === null || $path === '') | ||
784 | { | ||
785 | $this->path = null; | ||
786 | $this->valid[__FUNCTION__] = true; | ||
787 | return true; | ||
788 | } | ||
789 | elseif (substr($path, 0, 2) === '//' && $this->userinfo === null && $this->host === null && $this->port === null) | ||
790 | { | ||
791 | $this->path = null; | ||
792 | $this->valid[__FUNCTION__] = false; | ||
793 | return false; | ||
794 | } | ||
795 | else | ||
796 | { | ||
797 | $this->path = $this->replace_invalid_with_pct_encoding($path, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=@/'); | ||
798 | if ($this->scheme !== null) | ||
799 | { | ||
800 | $this->path = $this->remove_dot_segments($this->path); | ||
801 | } | ||
802 | $this->valid[__FUNCTION__] = true; | ||
803 | return true; | ||
804 | } | ||
805 | } | ||
806 | |||
807 | /** | ||
808 | * Set the query. | ||
809 | * | ||
810 | * @access public | ||
811 | * @param string $query | ||
812 | * @return bool | ||
813 | */ | ||
814 | public function set_query($query) | ||
815 | { | ||
816 | if ($query === null || $query === '') | ||
817 | { | ||
818 | $this->query = null; | ||
819 | } | ||
820 | else | ||
821 | { | ||
822 | $this->query = $this->replace_invalid_with_pct_encoding($query, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$\'()*+,;:@/?&='); | ||
823 | } | ||
824 | $this->valid[__FUNCTION__] = true; | ||
825 | return true; | ||
826 | } | ||
827 | |||
828 | /** | ||
829 | * Set the fragment. | ||
830 | * | ||
831 | * @access public | ||
832 | * @param string $fragment | ||
833 | * @return bool | ||
834 | */ | ||
835 | public function set_fragment($fragment) | ||
836 | { | ||
837 | if ($fragment === null || $fragment === '') | ||
838 | { | ||
839 | $this->fragment = null; | ||
840 | } | ||
841 | else | ||
842 | { | ||
843 | $this->fragment = $this->replace_invalid_with_pct_encoding($fragment, 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!$&\'()*+,;=:@/?'); | ||
844 | } | ||
845 | $this->valid[__FUNCTION__] = true; | ||
846 | return true; | ||
847 | } | ||
848 | |||
849 | /** | ||
850 | * Get the complete IRI | ||
851 | * | ||
852 | * @access public | ||
853 | * @return string | ||
854 | */ | ||
855 | public function get_iri() | ||
856 | { | ||
857 | $iri = ''; | ||
858 | if ($this->scheme !== null) | ||
859 | { | ||
860 | $iri .= $this->scheme . ':'; | ||
861 | } | ||
862 | if (($authority = $this->get_authority()) !== null) | ||
863 | { | ||
864 | $iri .= '//' . $authority; | ||
865 | } | ||
866 | if ($this->path !== null) | ||
867 | { | ||
868 | $iri .= $this->path; | ||
869 | } | ||
870 | if ($this->query !== null) | ||
871 | { | ||
872 | $iri .= '?' . $this->query; | ||
873 | } | ||
874 | if ($this->fragment !== null) | ||
875 | { | ||
876 | $iri .= '#' . $this->fragment; | ||
877 | } | ||
878 | |||
879 | if ($iri !== '') | ||
880 | { | ||
881 | return $iri; | ||
882 | } | ||
883 | else | ||
884 | { | ||
885 | return null; | ||
886 | } | ||
887 | } | ||
888 | |||
889 | /** | ||
890 | * Get the scheme | ||
891 | * | ||
892 | * @access public | ||
893 | * @return string | ||
894 | */ | ||
895 | public function get_scheme() | ||
896 | { | ||
897 | return $this->scheme; | ||
898 | } | ||
899 | |||
900 | /** | ||
901 | * Get the complete authority | ||
902 | * | ||
903 | * @access public | ||
904 | * @return string | ||
905 | */ | ||
906 | public function get_authority() | ||
907 | { | ||
908 | $authority = ''; | ||
909 | if ($this->userinfo !== null) | ||
910 | { | ||
911 | $authority .= $this->userinfo . '@'; | ||
912 | } | ||
913 | if ($this->host !== null) | ||
914 | { | ||
915 | $authority .= $this->host; | ||
916 | } | ||
917 | if ($this->port !== null) | ||
918 | { | ||
919 | $authority .= ':' . $this->port; | ||
920 | } | ||
921 | |||
922 | if ($authority !== '') | ||
923 | { | ||
924 | return $authority; | ||
925 | } | ||
926 | else | ||
927 | { | ||
928 | return null; | ||
929 | } | ||
930 | } | ||
931 | |||
932 | /** | ||
933 | * Get the user information | ||
934 | * | ||
935 | * @access public | ||
936 | * @return string | ||
937 | */ | ||
938 | public function get_userinfo() | ||
939 | { | ||
940 | return $this->userinfo; | ||
941 | } | ||
942 | |||
943 | /** | ||
944 | * Get the host | ||
945 | * | ||
946 | * @access public | ||
947 | * @return string | ||
948 | */ | ||
949 | public function get_host() | ||
950 | { | ||
951 | return $this->host; | ||
952 | } | ||
953 | |||
954 | /** | ||
955 | * Get the port | ||
956 | * | ||
957 | * @access public | ||
958 | * @return string | ||
959 | */ | ||
960 | public function get_port() | ||
961 | { | ||
962 | return $this->port; | ||
963 | } | ||
964 | |||
965 | /** | ||
966 | * Get the path | ||
967 | * | ||
968 | * @access public | ||
969 | * @return string | ||
970 | */ | ||
971 | public function get_path() | ||
972 | { | ||
973 | return $this->path; | ||
974 | } | ||
975 | |||
976 | /** | ||
977 | * Get the query | ||
978 | * | ||
979 | * @access public | ||
980 | * @return string | ||
981 | */ | ||
982 | public function get_query() | ||
983 | { | ||
984 | return $this->query; | ||
985 | } | ||
986 | |||
987 | /** | ||
988 | * Get the fragment | ||
989 | * | ||
990 | * @access public | ||
991 | * @return string | ||
992 | */ | ||
993 | public function get_fragment() | ||
994 | { | ||
995 | return $this->fragment; | ||
996 | } | ||
997 | } | ||