Requests_IRI

IRI parser/serialiser/normaliser.

Defined (1)

The class is defined in the following location(s).

/wp-includes/Requests/IRI.php  
  1. class Requests_IRI { 
  2. /** 
  3. * Scheme 
  4. * @var string 
  5. */ 
  6. protected $scheme = null; 
  7.  
  8. /** 
  9. * User Information 
  10. * @var string 
  11. */ 
  12. protected $iuserinfo = null; 
  13.  
  14. /** 
  15. * ihost 
  16. * @var string 
  17. */ 
  18. protected $ihost = null; 
  19.  
  20. /** 
  21. * Port 
  22. * @var string 
  23. */ 
  24. protected $port = null; 
  25.  
  26. /** 
  27. * ipath 
  28. * @var string 
  29. */ 
  30. protected $ipath = ''; 
  31.  
  32. /** 
  33. * iquery 
  34. * @var string 
  35. */ 
  36. protected $iquery = null; 
  37.  
  38. /** 
  39. * ifragment 
  40. * @var string 
  41. */ 
  42. protected $ifragment = null; 
  43.  
  44. /** 
  45. * Normalization database 
  46. * Each key is the scheme, each value is an array with each key as the IRI 
  47. * part and value as the default value for that part. 
  48. */ 
  49. protected $normalization = array( 
  50. 'acap' => array( 
  51. 'port' => 674 
  52. ),  
  53. 'dict' => array( 
  54. 'port' => 2628 
  55. ),  
  56. 'file' => array( 
  57. 'ihost' => 'localhost' 
  58. ),  
  59. 'http' => array( 
  60. 'port' => 80,  
  61. ),  
  62. 'https' => array( 
  63. 'port' => 443,  
  64. ),  
  65. ); 
  66.  
  67. /** 
  68. * Return the entire IRI when you try and read the object as a string 
  69. * @return string 
  70. */ 
  71. public function __toString() { 
  72. return $this->get_iri(); 
  73.  
  74. /** 
  75. * Overload __set() to provide access via properties 
  76. * @param string $name Property name 
  77. * @param mixed $value Property value 
  78. */ 
  79. public function __set($name, $value) { 
  80. if (method_exists($this, 'set_' . $name)) { 
  81. call_user_func(array($this, 'set_' . $name), $value); 
  82. elseif ( 
  83. $name === 'iauthority' 
  84. || $name === 'iuserinfo' 
  85. || $name === 'ihost' 
  86. || $name === 'ipath' 
  87. || $name === 'iquery' 
  88. || $name === 'ifragment' 
  89. ) { 
  90. call_user_func(array($this, 'set_' . substr($name, 1)), $value); 
  91.  
  92. /** 
  93. * Overload __get() to provide access via properties 
  94. * @param string $name Property name 
  95. * @return mixed 
  96. */ 
  97. public function __get($name) { 
  98. // isset() returns false for null, we don't want to do that 
  99. // Also why we use array_key_exists below instead of isset() 
  100. $props = get_object_vars($this); 
  101.  
  102. if ( 
  103. $name === 'iri' || 
  104. $name === 'uri' || 
  105. $name === 'iauthority' || 
  106. $name === 'authority' 
  107. ) { 
  108. $method = 'get_' . $name; 
  109. $return = $this->$method(); 
  110. elseif (array_key_exists($name, $props)) { 
  111. $return = $this->$name; 
  112. // host -> ihost 
  113. elseif (($prop = 'i' . $name) && array_key_exists($prop, $props)) { 
  114. $name = $prop; 
  115. $return = $this->$prop; 
  116. // ischeme -> scheme 
  117. elseif (($prop = substr($name, 1)) && array_key_exists($prop, $props)) { 
  118. $name = $prop; 
  119. $return = $this->$prop; 
  120. else { 
  121. trigger_error('Undefined property: ' . get_class($this) . '::' . $name, E_USER_NOTICE); 
  122. $return = null; 
  123.  
  124. if ($return === null && isset($this->normalization[$this->scheme][$name])) { 
  125. return $this->normalization[$this->scheme][$name]; 
  126. else { 
  127. return $return; 
  128.  
  129. /** 
  130. * Overload __isset() to provide access via properties 
  131. * @param string $name Property name 
  132. * @return bool 
  133. */ 
  134. public function __isset($name) { 
  135. return (method_exists($this, 'get_' . $name) || isset($this->$name)); 
  136.  
  137. /** 
  138. * Overload __unset() to provide access via properties 
  139. * @param string $name Property name 
  140. */ 
  141. public function __unset($name) { 
  142. if (method_exists($this, 'set_' . $name)) { 
  143. call_user_func(array($this, 'set_' . $name), ''); 
  144.  
  145. /** 
  146. * Create a new IRI object, from a specified string 
  147. * @param string|null $iri 
  148. */ 
  149. public function __construct($iri = null) { 
  150. $this->set_iri($iri); 
  151.  
  152. /** 
  153. * Create a new IRI object by resolving a relative IRI 
  154. * Returns false if $base is not absolute, otherwise an IRI. 
  155. * @param IRI|string $base (Absolute) Base IRI 
  156. * @param IRI|string $relative Relative IRI 
  157. * @return IRI|false 
  158. */ 
  159. public static function absolutize($base, $relative) { 
  160. if (!($relative instanceof Requests_IRI)) { 
  161. $relative = new Requests_IRI($relative); 
  162. if (!$relative->is_valid()) { 
  163. return false; 
  164. elseif ($relative->scheme !== null) { 
  165. return clone $relative; 
  166.  
  167. if (!($base instanceof Requests_IRI)) { 
  168. $base = new Requests_IRI($base); 
  169. if ($base->scheme === null || !$base->is_valid()) { 
  170. return false; 
  171.  
  172. if ($relative->get_iri() !== '') { 
  173. if ($relative->iuserinfo !== null || $relative->ihost !== null || $relative->port !== null) { 
  174. $target = clone $relative; 
  175. $target->scheme = $base->scheme; 
  176. else { 
  177. $target = new Requests_IRI; 
  178. $target->scheme = $base->scheme; 
  179. $target->iuserinfo = $base->iuserinfo; 
  180. $target->ihost = $base->ihost; 
  181. $target->port = $base->port; 
  182. if ($relative->ipath !== '') { 
  183. if ($relative->ipath[0] === '/') { 
  184. $target->ipath = $relative->ipath; 
  185. elseif (($base->iuserinfo !== null || $base->ihost !== null || $base->port !== null) && $base->ipath === '') { 
  186. $target->ipath = '/' . $relative->ipath; 
  187. elseif (($last_segment = strrpos($base->ipath, '/')) !== false) { 
  188. $target->ipath = substr($base->ipath, 0, $last_segment + 1) . $relative->ipath; 
  189. else { 
  190. $target->ipath = $relative->ipath; 
  191. $target->ipath = $target->remove_dot_segments($target->ipath); 
  192. $target->iquery = $relative->iquery; 
  193. else { 
  194. $target->ipath = $base->ipath; 
  195. if ($relative->iquery !== null) { 
  196. $target->iquery = $relative->iquery; 
  197. elseif ($base->iquery !== null) { 
  198. $target->iquery = $base->iquery; 
  199. $target->ifragment = $relative->ifragment; 
  200. else { 
  201. $target = clone $base; 
  202. $target->ifragment = null; 
  203. $target->scheme_normalization(); 
  204. return $target; 
  205.  
  206. /** 
  207. * Parse an IRI into scheme/authority/path/query/fragment segments 
  208. * @param string $iri 
  209. * @return array 
  210. */ 
  211. protected function parse_iri($iri) { 
  212. $iri = trim($iri, "\x20\x09\x0A\x0C\x0D"); 
  213. $has_match = preg_match('/^((?P<scheme>[^:\/?#]+):)?(\/\/(?P<authority>[^\/?#]*))?(?P<path>[^?#]*)(\?(?P<query>[^#]*))?(#(?P<fragment>.*))?$/', $iri, $match); 
  214. if (!$has_match) { 
  215. throw new Requests_Exception('Cannot parse supplied IRI', 'iri.cannot_parse', $iri); 
  216.  
  217. if ($match[1] === '') { 
  218. $match['scheme'] = null; 
  219. if (!isset($match[3]) || $match[3] === '') { 
  220. $match['authority'] = null; 
  221. if (!isset($match[5])) { 
  222. $match['path'] = ''; 
  223. if (!isset($match[6]) || $match[6] === '') { 
  224. $match['query'] = null; 
  225. if (!isset($match[8]) || $match[8] === '') { 
  226. $match['fragment'] = null; 
  227. return $match; 
  228.  
  229. /** 
  230. * Remove dot segments from a path 
  231. * @param string $input 
  232. * @return string 
  233. */ 
  234. protected function remove_dot_segments($input) { 
  235. $output = ''; 
  236. while (strpos($input, './') !== false || strpos($input, '/.') !== false || $input === '.' || $input === '..') { 
  237. // A: If the input buffer begins with a prefix of "../" or "./",  
  238. // then remove that prefix from the input buffer; otherwise,  
  239. if (strpos($input, '../') === 0) { 
  240. $input = substr($input, 3); 
  241. elseif (strpos($input, './') === 0) { 
  242. $input = substr($input, 2); 
  243. // B: if the input buffer begins with a prefix of "/./" or "/.",  
  244. // where "." is a complete path segment, then replace that prefix 
  245. // with "/" in the input buffer; otherwise,  
  246. elseif (strpos($input, '/./') === 0) { 
  247. $input = substr($input, 2); 
  248. elseif ($input === '/.') { 
  249. $input = '/'; 
  250. // C: if the input buffer begins with a prefix of "/../" or "/..",  
  251. // where ".." is a complete path segment, then replace that prefix 
  252. // with "/" in the input buffer and remove the last segment and its 
  253. // preceding "/" (if any) from the output buffer; otherwise,  
  254. elseif (strpos($input, '/../') === 0) { 
  255. $input = substr($input, 3); 
  256. $output = substr_replace($output, '', strrpos($output, '/')); 
  257. elseif ($input === '/..') { 
  258. $input = '/'; 
  259. $output = substr_replace($output, '', strrpos($output, '/')); 
  260. // D: if the input buffer consists only of "." or "..", then remove 
  261. // that from the input buffer; otherwise,  
  262. elseif ($input === '.' || $input === '..') { 
  263. $input = ''; 
  264. // E: move the first path segment in the input buffer to the end of 
  265. // the output buffer, including the initial "/" character (if any) 
  266. // and any subsequent characters up to, but not including, the next 
  267. // "/" character or the end of the input buffer 
  268. elseif (($pos = strpos($input, '/', 1)) !== false) { 
  269. $output .= substr($input, 0, $pos); 
  270. $input = substr_replace($input, '', 0, $pos); 
  271. else { 
  272. $output .= $input; 
  273. $input = ''; 
  274. return $output . $input; 
  275.  
  276. /** 
  277. * Replace invalid character with percent encoding 
  278. * @param string $string Input string 
  279. * @param string $extra_chars Valid characters not in iunreserved or 
  280. * iprivate (this is ASCII-only) 
  281. * @param bool $iprivate Allow iprivate 
  282. * @return string 
  283. */ 
  284. protected function replace_invalid_with_pct_encoding($string, $extra_chars, $iprivate = false) { 
  285. // Normalize as many pct-encoded sections as possible 
  286. $string = preg_replace_callback('/(?:%[A-Fa-f0-9]{2})+/', array(&$this, 'remove_iunreserved_percent_encoded'), $string); 
  287.  
  288. // Replace invalid percent characters 
  289. $string = preg_replace('/%(?![A-Fa-f0-9]{2})/', '%25', $string); 
  290.  
  291. // Add unreserved and % to $extra_chars (the latter is safe because all 
  292. // pct-encoded sections are now valid). 
  293. $extra_chars .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~%'; 
  294.  
  295. // Now replace any bytes that aren't allowed with their pct-encoded versions 
  296. $position = 0; 
  297. $strlen = strlen($string); 
  298. while (($position += strspn($string, $extra_chars, $position)) < $strlen) { 
  299. $value = ord($string[$position]); 
  300.  
  301. // Start position 
  302. $start = $position; 
  303.  
  304. // By default we are valid 
  305. $valid = true; 
  306.  
  307. // No one byte sequences are valid due to the while. 
  308. // Two byte sequence: 
  309. if (($value & 0xE0) === 0xC0) { 
  310. $character = ($value & 0x1F) << 6; 
  311. $length = 2; 
  312. $remaining = 1; 
  313. // Three byte sequence: 
  314. elseif (($value & 0xF0) === 0xE0) { 
  315. $character = ($value & 0x0F) << 12; 
  316. $length = 3; 
  317. $remaining = 2; 
  318. // Four byte sequence: 
  319. elseif (($value & 0xF8) === 0xF0) { 
  320. $character = ($value & 0x07) << 18; 
  321. $length = 4; 
  322. $remaining = 3; 
  323. // Invalid byte: 
  324. else { 
  325. $valid = false; 
  326. $length = 1; 
  327. $remaining = 0; 
  328.  
  329. if ($remaining) { 
  330. if ($position + $length <= $strlen) { 
  331. for ($position++; $remaining; $position++) { 
  332. $value = ord($string[$position]); 
  333.  
  334. // Check that the byte is valid, then add it to the character: 
  335. if (($value & 0xC0) === 0x80) { 
  336. $character |= ($value & 0x3F) << (--$remaining * 6); 
  337. // If it is invalid, count the sequence as invalid and reprocess the current byte: 
  338. else { 
  339. $valid = false; 
  340. $position--; 
  341. break; 
  342. else { 
  343. $position = $strlen - 1; 
  344. $valid = false; 
  345.  
  346. // Percent encode anything invalid or not in ucschar 
  347. if ( 
  348. // Invalid sequences 
  349. !$valid 
  350. // Non-shortest form sequences are invalid 
  351. || $length > 1 && $character <= 0x7F 
  352. || $length > 2 && $character <= 0x7FF 
  353. || $length > 3 && $character <= 0xFFFF 
  354. // Outside of range of ucschar codepoints 
  355. // Noncharacters 
  356. || ($character & 0xFFFE) === 0xFFFE 
  357. || $character >= 0xFDD0 && $character <= 0xFDEF 
  358. || ( 
  359. // Everything else not in ucschar 
  360. $character > 0xD7FF && $character < 0xF900 
  361. || $character < 0xA0 
  362. || $character > 0xEFFFD 
  363. && ( 
  364. // Everything not in iprivate, if it applies 
  365. !$iprivate 
  366. || $character < 0xE000 
  367. || $character > 0x10FFFD 
  368. ) { 
  369. // If we were a character, pretend we weren't, but rather an error. 
  370. if ($valid) { 
  371. $position--; 
  372.  
  373. for ($j = $start; $j <= $position; $j++) { 
  374. $string = substr_replace($string, sprintf('%%%02X', ord($string[$j])), $j, 1); 
  375. $j += 2; 
  376. $position += 2; 
  377. $strlen += 2; 
  378.  
  379. return $string; 
  380.  
  381. /** 
  382. * Callback function for preg_replace_callback. 
  383. * Removes sequences of percent encoded bytes that represent UTF-8 
  384. * encoded characters in iunreserved 
  385. * @param array $match PCRE match 
  386. * @return string Replacement 
  387. */ 
  388. protected function remove_iunreserved_percent_encoded($match) { 
  389. // As we just have valid percent encoded sequences we can just explode 
  390. // and ignore the first member of the returned array (an empty string). 
  391. $bytes = explode('%', $match[0]); 
  392.  
  393. // Initialize the new string (this is what will be returned) and that 
  394. // there are no bytes remaining in the current sequence (unsurprising 
  395. // at the first byte!). 
  396. $string = ''; 
  397. $remaining = 0; 
  398.  
  399. // Loop over each and every byte, and set $value to its value 
  400. for ($i = 1, $len = count($bytes); $i < $len; $i++) { 
  401. $value = hexdec($bytes[$i]); 
  402.  
  403. // If we're the first byte of sequence: 
  404. if (!$remaining) { 
  405. // Start position 
  406. $start = $i; 
  407.  
  408. // By default we are valid 
  409. $valid = true; 
  410.  
  411. // One byte sequence: 
  412. if ($value <= 0x7F) { 
  413. $character = $value; 
  414. $length = 1; 
  415. // Two byte sequence: 
  416. elseif (($value & 0xE0) === 0xC0) { 
  417. $character = ($value & 0x1F) << 6; 
  418. $length = 2; 
  419. $remaining = 1; 
  420. // Three byte sequence: 
  421. elseif (($value & 0xF0) === 0xE0) { 
  422. $character = ($value & 0x0F) << 12; 
  423. $length = 3; 
  424. $remaining = 2; 
  425. // Four byte sequence: 
  426. elseif (($value & 0xF8) === 0xF0) { 
  427. $character = ($value & 0x07) << 18; 
  428. $length = 4; 
  429. $remaining = 3; 
  430. // Invalid byte: 
  431. else { 
  432. $valid = false; 
  433. $remaining = 0; 
  434. // Continuation byte: 
  435. else { 
  436. // Check that the byte is valid, then add it to the character: 
  437. if (($value & 0xC0) === 0x80) { 
  438. $remaining--; 
  439. $character |= ($value & 0x3F) << ($remaining * 6); 
  440. // If it is invalid, count the sequence as invalid and reprocess the current byte as the start of a sequence: 
  441. else { 
  442. $valid = false; 
  443. $remaining = 0; 
  444. $i--; 
  445.  
  446. // If we've reached the end of the current byte sequence, append it to Unicode::$data 
  447. if (!$remaining) { 
  448. // Percent encode anything invalid or not in iunreserved 
  449. if ( 
  450. // Invalid sequences 
  451. !$valid 
  452. // Non-shortest form sequences are invalid 
  453. || $length > 1 && $character <= 0x7F 
  454. || $length > 2 && $character <= 0x7FF 
  455. || $length > 3 && $character <= 0xFFFF 
  456. // Outside of range of iunreserved codepoints 
  457. || $character < 0x2D 
  458. || $character > 0xEFFFD 
  459. // Noncharacters 
  460. || ($character & 0xFFFE) === 0xFFFE 
  461. || $character >= 0xFDD0 && $character <= 0xFDEF 
  462. // Everything else not in iunreserved (this is all BMP) 
  463. || $character === 0x2F 
  464. || $character > 0x39 && $character < 0x41 
  465. || $character > 0x5A && $character < 0x61 
  466. || $character > 0x7A && $character < 0x7E 
  467. || $character > 0x7E && $character < 0xA0 
  468. || $character > 0xD7FF && $character < 0xF900 
  469. ) { 
  470. for ($j = $start; $j <= $i; $j++) { 
  471. $string .= '%' . strtoupper($bytes[$j]); 
  472. else { 
  473. for ($j = $start; $j <= $i; $j++) { 
  474. $string .= chr(hexdec($bytes[$j])); 
  475.  
  476. // If we have any bytes left over they are invalid (i.e., we are 
  477. // mid-way through a multi-byte sequence) 
  478. if ($remaining) { 
  479. for ($j = $start; $j < $len; $j++) { 
  480. $string .= '%' . strtoupper($bytes[$j]); 
  481.  
  482. return $string; 
  483.  
  484. protected function scheme_normalization() { 
  485. if (isset($this->normalization[$this->scheme]['iuserinfo']) && $this->iuserinfo === $this->normalization[$this->scheme]['iuserinfo']) { 
  486. $this->iuserinfo = null; 
  487. if (isset($this->normalization[$this->scheme]['ihost']) && $this->ihost === $this->normalization[$this->scheme]['ihost']) { 
  488. $this->ihost = null; 
  489. if (isset($this->normalization[$this->scheme]['port']) && $this->port === $this->normalization[$this->scheme]['port']) { 
  490. $this->port = null; 
  491. if (isset($this->normalization[$this->scheme]['ipath']) && $this->ipath === $this->normalization[$this->scheme]['ipath']) { 
  492. $this->ipath = ''; 
  493. if (isset($this->ihost) && empty($this->ipath)) { 
  494. $this->ipath = '/'; 
  495. if (isset($this->normalization[$this->scheme]['iquery']) && $this->iquery === $this->normalization[$this->scheme]['iquery']) { 
  496. $this->iquery = null; 
  497. if (isset($this->normalization[$this->scheme]['ifragment']) && $this->ifragment === $this->normalization[$this->scheme]['ifragment']) { 
  498. $this->ifragment = null; 
  499.  
  500. /** 
  501. * Check if the object represents a valid IRI. This needs to be done on each 
  502. * call as some things change depending on another part of the IRI. 
  503. * @return bool 
  504. */ 
  505. public function is_valid() { 
  506. $isauthority = $this->iuserinfo !== null || $this->ihost !== null || $this->port !== null; 
  507. if ($this->ipath !== '' && 
  508. $isauthority && ( 
  509. $this->ipath[0] !== '/' || 
  510. substr($this->ipath, 0, 2) === '//' 
  511. ) || 
  512. $this->scheme === null && 
  513. !$isauthority && 
  514. strpos($this->ipath, ':') !== false && 
  515. (strpos($this->ipath, '/') === false ? true : strpos($this->ipath, ':') < strpos($this->ipath, '/')) 
  516. ) { 
  517. return false; 
  518.  
  519. return true; 
  520.  
  521. /** 
  522. * Set the entire IRI. Returns true on success, false on failure (if there 
  523. * are any invalid characters). 
  524. * @param string $iri 
  525. * @return bool 
  526. */ 
  527. protected function set_iri($iri) { 
  528. static $cache; 
  529. if (!$cache) { 
  530. $cache = array(); 
  531.  
  532. if ($iri === null) { 
  533. return true; 
  534. if (isset($cache[$iri])) { 
  535. list($this->scheme,  
  536. $this->iuserinfo,  
  537. $this->ihost,  
  538. $this->port,  
  539. $this->ipath,  
  540. $this->iquery,  
  541. $this->ifragment,  
  542. $return) = $cache[$iri]; 
  543. return $return; 
  544.  
  545. $parsed = $this->parse_iri((string) $iri); 
  546.  
  547. $return = $this->set_scheme($parsed['scheme']) 
  548. && $this->set_authority($parsed['authority']) 
  549. && $this->set_path($parsed['path']) 
  550. && $this->set_query($parsed['query']) 
  551. && $this->set_fragment($parsed['fragment']); 
  552.  
  553. $cache[$iri] = array($this->scheme,  
  554. $this->iuserinfo,  
  555. $this->ihost,  
  556. $this->port,  
  557. $this->ipath,  
  558. $this->iquery,  
  559. $this->ifragment,  
  560. $return); 
  561. return $return; 
  562.  
  563. /** 
  564. * Set the scheme. Returns true on success, false on failure (if there are 
  565. * any invalid characters). 
  566. * @param string $scheme 
  567. * @return bool 
  568. */ 
  569. protected function set_scheme($scheme) { 
  570. if ($scheme === null) { 
  571. $this->scheme = null; 
  572. elseif (!preg_match('/^[A-Za-z][0-9A-Za-z+\-.]*$/', $scheme)) { 
  573. $this->scheme = null; 
  574. return false; 
  575. else { 
  576. $this->scheme = strtolower($scheme); 
  577. return true; 
  578.  
  579. /** 
  580. * Set the authority. Returns true on success, false on failure (if there are 
  581. * any invalid characters). 
  582. * @param string $authority 
  583. * @return bool 
  584. */ 
  585. protected function set_authority($authority) { 
  586. static $cache; 
  587. if (!$cache) { 
  588. $cache = array(); 
  589.  
  590. if ($authority === null) { 
  591. $this->iuserinfo = null; 
  592. $this->ihost = null; 
  593. $this->port = null; 
  594. return true; 
  595. if (isset($cache[$authority])) { 
  596. list($this->iuserinfo,  
  597. $this->ihost,  
  598. $this->port,  
  599. $return) = $cache[$authority]; 
  600.  
  601. return $return; 
  602.  
  603. $remaining = $authority; 
  604. if (($iuserinfo_end = strrpos($remaining, '@')) !== false) { 
  605. $iuserinfo = substr($remaining, 0, $iuserinfo_end); 
  606. $remaining = substr($remaining, $iuserinfo_end + 1); 
  607. else { 
  608. $iuserinfo = null; 
  609. if (($port_start = strpos($remaining, ':', strpos($remaining, ']'))) !== false) { 
  610. $port = substr($remaining, $port_start + 1); 
  611. if ($port === false || $port === '') { 
  612. $port = null; 
  613. $remaining = substr($remaining, 0, $port_start); 
  614. else { 
  615. $port = null; 
  616.  
  617. $return = $this->set_userinfo($iuserinfo) && 
  618. $this->set_host($remaining) && 
  619. $this->set_port($port); 
  620.  
  621. $cache[$authority] = array($this->iuserinfo,  
  622. $this->ihost,  
  623. $this->port,  
  624. $return); 
  625.  
  626. return $return; 
  627.  
  628. /** 
  629. * Set the iuserinfo. 
  630. * @param string $iuserinfo 
  631. * @return bool 
  632. */ 
  633. protected function set_userinfo($iuserinfo) { 
  634. if ($iuserinfo === null) { 
  635. $this->iuserinfo = null; 
  636. else { 
  637. $this->iuserinfo = $this->replace_invalid_with_pct_encoding($iuserinfo, '!$&\'()*+, ;=:'); 
  638. $this->scheme_normalization(); 
  639.  
  640. return true; 
  641.  
  642. /** 
  643. * Set the ihost. Returns true on success, false on failure (if there are 
  644. * any invalid characters). 
  645. * @param string $ihost 
  646. * @return bool 
  647. */ 
  648. protected function set_host($ihost) { 
  649. if ($ihost === null) { 
  650. $this->ihost = null; 
  651. return true; 
  652. if (substr($ihost, 0, 1) === '[' && substr($ihost, -1) === ']') { 
  653. if (Requests_IPv6::check_ipv6(substr($ihost, 1, -1))) { 
  654. $this->ihost = '[' . Requests_IPv6::compress(substr($ihost, 1, -1)) . ']'; 
  655. else { 
  656. $this->ihost = null; 
  657. return false; 
  658. else { 
  659. $ihost = $this->replace_invalid_with_pct_encoding($ihost, '!$&\'()*+, ;='); 
  660.  
  661. // Lowercase, but ignore pct-encoded sections (as they should 
  662. // remain uppercase). This must be done after the previous step 
  663. // as that can add unescaped characters. 
  664. $position = 0; 
  665. $strlen = strlen($ihost); 
  666. while (($position += strcspn($ihost, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ%', $position)) < $strlen) { 
  667. if ($ihost[$position] === '%') { 
  668. $position += 3; 
  669. else { 
  670. $ihost[$position] = strtolower($ihost[$position]); 
  671. $position++; 
  672.  
  673. $this->ihost = $ihost; 
  674.  
  675. $this->scheme_normalization(); 
  676.  
  677. return true; 
  678.  
  679. /** 
  680. * Set the port. Returns true on success, false on failure (if there are 
  681. * any invalid characters). 
  682. * @param string $port 
  683. * @return bool 
  684. */ 
  685. protected function set_port($port) { 
  686. if ($port === null) { 
  687. $this->port = null; 
  688. return true; 
  689.  
  690. if (strspn($port, '0123456789') === strlen($port)) { 
  691. $this->port = (int) $port; 
  692. $this->scheme_normalization(); 
  693. return true; 
  694.  
  695. $this->port = null; 
  696. return false; 
  697.  
  698. /** 
  699. * Set the ipath. 
  700. * @param string $ipath 
  701. * @return bool 
  702. */ 
  703. protected function set_path($ipath) { 
  704. static $cache; 
  705. if (!$cache) { 
  706. $cache = array(); 
  707.  
  708. $ipath = (string) $ipath; 
  709.  
  710. if (isset($cache[$ipath])) { 
  711. $this->ipath = $cache[$ipath][(int) ($this->scheme !== null)]; 
  712. else { 
  713. $valid = $this->replace_invalid_with_pct_encoding($ipath, '!$&\'()*+, ;=@:/'); 
  714. $removed = $this->remove_dot_segments($valid); 
  715.  
  716. $cache[$ipath] = array($valid, $removed); 
  717. $this->ipath = ($this->scheme !== null) ? $removed : $valid; 
  718. $this->scheme_normalization(); 
  719. return true; 
  720.  
  721. /** 
  722. * Set the iquery. 
  723. * @param string $iquery 
  724. * @return bool 
  725. */ 
  726. protected function set_query($iquery) { 
  727. if ($iquery === null) { 
  728. $this->iquery = null; 
  729. else { 
  730. $this->iquery = $this->replace_invalid_with_pct_encoding($iquery, '!$&\'()*+, ;=:@/?', true); 
  731. $this->scheme_normalization(); 
  732. return true; 
  733.  
  734. /** 
  735. * Set the ifragment. 
  736. * @param string $ifragment 
  737. * @return bool 
  738. */ 
  739. protected function set_fragment($ifragment) { 
  740. if ($ifragment === null) { 
  741. $this->ifragment = null; 
  742. else { 
  743. $this->ifragment = $this->replace_invalid_with_pct_encoding($ifragment, '!$&\'()*+, ;=:@/?'); 
  744. $this->scheme_normalization(); 
  745. return true; 
  746.  
  747. /** 
  748. * Convert an IRI to a URI (or parts thereof) 
  749. * @param string|bool IRI to convert (or false from {@see get_iri}) 
  750. * @return string|false URI if IRI is valid, false otherwise. 
  751. */ 
  752. protected function to_uri($string) { 
  753. if (!is_string($string)) { 
  754. return false; 
  755.  
  756. static $non_ascii; 
  757. if (!$non_ascii) { 
  758. $non_ascii = implode('', range("\x80", "\xFF")); 
  759.  
  760. $position = 0; 
  761. $strlen = strlen($string); 
  762. while (($position += strcspn($string, $non_ascii, $position)) < $strlen) { 
  763. $string = substr_replace($string, sprintf('%%%02X', ord($string[$position])), $position, 1); 
  764. $position += 3; 
  765. $strlen += 2; 
  766.  
  767. return $string; 
  768.  
  769. /** 
  770. * Get the complete IRI 
  771. * @return string 
  772. */ 
  773. protected function get_iri() { 
  774. if (!$this->is_valid()) { 
  775. return false; 
  776.  
  777. $iri = ''; 
  778. if ($this->scheme !== null) { 
  779. $iri .= $this->scheme . ':'; 
  780. if (($iauthority = $this->get_iauthority()) !== null) { 
  781. $iri .= '//' . $iauthority; 
  782. $iri .= $this->ipath; 
  783. if ($this->iquery !== null) { 
  784. $iri .= '?' . $this->iquery; 
  785. if ($this->ifragment !== null) { 
  786. $iri .= '#' . $this->ifragment; 
  787.  
  788. return $iri; 
  789.  
  790. /** 
  791. * Get the complete URI 
  792. * @return string 
  793. */ 
  794. protected function get_uri() { 
  795. return $this->to_uri($this->get_iri()); 
  796.  
  797. /** 
  798. * Get the complete iauthority 
  799. * @return string 
  800. */ 
  801. protected function get_iauthority() { 
  802. if ($this->iuserinfo === null && $this->ihost === null && $this->port === null) { 
  803. return null; 
  804.  
  805. $iauthority = ''; 
  806. if ($this->iuserinfo !== null) { 
  807. $iauthority .= $this->iuserinfo . '@'; 
  808. if ($this->ihost !== null) { 
  809. $iauthority .= $this->ihost; 
  810. if ($this->port !== null) { 
  811. $iauthority .= ':' . $this->port; 
  812. return $iauthority; 
  813.  
  814. /** 
  815. * Get the complete authority 
  816. * @return string 
  817. */ 
  818. protected function get_authority() { 
  819. $iauthority = $this->get_iauthority(); 
  820. if (is_string($iauthority)) { 
  821. return $this->to_uri($iauthority); 
  822. else { 
  823. return $iauthority;