]>
Commit | Line | Data |
---|---|---|
ec397236 NL |
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 | } |