PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/libraries/joomla/utilities/string.php

https://bitbucket.org/pasamio/jhttprequest
PHP | 713 lines | 304 code | 41 blank | 368 comment | 99 complexity | 6f83fa440c3ee40f69d9f17274b7f8b6 MD5 | raw file
Possible License(s): BSD-3-Clause, GPL-2.0, LGPL-2.1
  1. <?php
  2. /**
  3. * @copyright Copyright (C) 2005 - 2011 Open Source Matters, Inc. All rights reserved.
  4. * @license GNU General Public License version 2 or later; see LICENSE
  5. * @package Joomla.Platform
  6. * @subpackage Utilities
  7. */
  8. defined('JPATH_PLATFORM') or die;
  9. /**
  10. * PHP mbstring and iconv local configuration
  11. */
  12. // check if mbstring extension is loaded and attempt to load it if not present except for windows
  13. if (extension_loaded('mbstring') || ((!strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && dl('mbstring.so')))) {
  14. //Make sure to surpress the output in case ini_set is disabled
  15. @ini_set('mbstring.internal_encoding', 'UTF-8');
  16. @ini_set('mbstring.http_input', 'UTF-8');
  17. @ini_set('mbstring.http_output', 'UTF-8');
  18. }
  19. // same for iconv
  20. if (function_exists('iconv') || ((!strtoupper(substr(PHP_OS, 0, 3)) === 'WIN' && dl('iconv.so')))) {
  21. // these are settings that can be set inside code
  22. iconv_set_encoding("internal_encoding", "UTF-8");
  23. iconv_set_encoding("input_encoding", "UTF-8");
  24. iconv_set_encoding("output_encoding", "UTF-8");
  25. }
  26. /**
  27. * Include the utf8 package
  28. */
  29. jimport('phputf8.utf8');
  30. jimport('phputf8.strcasecmp');
  31. /**
  32. * String handling class for utf-8 data
  33. * Wraps the phputf8 library
  34. * All functions assume the validity of utf-8 strings.
  35. *
  36. * @static
  37. * @package Joomla.Platform
  38. * @subpackage Utilities
  39. * @since 11.1
  40. */
  41. abstract class JString
  42. {
  43. /**
  44. * UTF-8 aware alternative to strpos
  45. * Find position of first occurrence of a string
  46. *
  47. * @static
  48. * @access public
  49. * @param $str - string String being examined
  50. * @param $search - string String being searced for
  51. * @param $offset - int Optional, specifies the position from which the search should be performed
  52. * @return mixed Number of characters before the first match or FALSE on failure
  53. * @see http://www.php.net/strpos
  54. */
  55. public static function strpos($str, $search, $offset = FALSE)
  56. {
  57. if ( $offset === FALSE ) {
  58. return utf8_strpos($str, $search);
  59. } else {
  60. return utf8_strpos($str, $search, $offset);
  61. }
  62. }
  63. /**
  64. * UTF-8 aware alternative to strrpos
  65. * Finds position of last occurrence of a string
  66. *
  67. * @static
  68. * @access public
  69. * @param $str - string String being examined
  70. * @param $search - string String being searced for
  71. * @return mixed Number of characters before the last match or FALSE on failure
  72. * @see http://www.php.net/strrpos
  73. */
  74. public static function strrpos($str, $search, $offset = false)
  75. {
  76. return utf8_strrpos($str, $search);
  77. }
  78. /**
  79. * UTF-8 aware alternative to substr
  80. * Return part of a string given character offset (and optionally length)
  81. *
  82. * @static
  83. * @access public
  84. * @param string
  85. * @param integer number of UTF-8 characters offset (from left)
  86. * @param integer (optional) length in UTF-8 characters from offset
  87. * @return mixed string or FALSE if failure
  88. * @see http://www.php.net/substr
  89. */
  90. public static function substr($str, $offset, $length = FALSE)
  91. {
  92. if ($length === FALSE) {
  93. return utf8_substr($str, $offset);
  94. } else {
  95. return utf8_substr($str, $offset, $length);
  96. }
  97. }
  98. /**
  99. * UTF-8 aware alternative to strtlower
  100. * Make a string lowercase
  101. * Note: The concept of a characters "case" only exists is some alphabets
  102. * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
  103. * not exist in the Chinese alphabet, for example. See Unicode Standard
  104. * Annex #21: Case Mappings
  105. *
  106. * @access public
  107. * @param string
  108. * @return mixed either string in lowercase or FALSE is UTF-8 invalid
  109. * @see http://www.php.net/strtolower
  110. */
  111. public static function strtolower($str){
  112. return utf8_strtolower($str);
  113. }
  114. /**
  115. * UTF-8 aware alternative to strtoupper
  116. * Make a string uppercase
  117. * Note: The concept of a characters "case" only exists is some alphabets
  118. * such as Latin, Greek, Cyrillic, Armenian and archaic Georgian - it does
  119. * not exist in the Chinese alphabet, for example. See Unicode Standard
  120. * Annex #21: Case Mappings
  121. *
  122. * @access public
  123. * @param string
  124. * @return mixed either string in uppercase or FALSE is UTF-8 invalid
  125. * @see http://www.php.net/strtoupper
  126. */
  127. public static function strtoupper($str){
  128. return utf8_strtoupper($str);
  129. }
  130. /**
  131. * UTF-8 aware alternative to strlen
  132. * Returns the number of characters in the string (NOT THE NUMBER OF BYTES),
  133. *
  134. * @access public
  135. * @param string UTF-8 string
  136. * @return int number of UTF-8 characters in string
  137. * @see http://www.php.net/strlen
  138. */
  139. public static function strlen($str){
  140. return utf8_strlen($str);
  141. }
  142. /**
  143. * UTF-8 aware alternative to str_ireplace
  144. * Case-insensitive version of str_replace
  145. *
  146. * @static
  147. * @access public
  148. * @param string string to search
  149. * @param string existing string to replace
  150. * @param string new string to replace with
  151. * @param int optional count value to be passed by referene
  152. * @see http://www.php.net/str_ireplace
  153. */
  154. public static function str_ireplace($search, $replace, $str, $count = NULL)
  155. {
  156. jimport('phputf8.str_ireplace');
  157. if ( $count === FALSE ) {
  158. return utf8_ireplace($search, $replace, $str);
  159. } else {
  160. return utf8_ireplace($search, $replace, $str, $count);
  161. }
  162. }
  163. /**
  164. * UTF-8 aware alternative to str_split
  165. * Convert a string to an array
  166. *
  167. * @static
  168. * @access public
  169. * @param string UTF-8 encoded
  170. * @param int number to characters to split string by
  171. * @return array
  172. * @see http://www.php.net/str_split
  173. */
  174. public static function str_split($str, $split_len = 1)
  175. {
  176. jimport('phputf8.str_split');
  177. return utf8_str_split($str, $split_len);
  178. }
  179. /**
  180. * UTF-8/LOCALE aware alternative to strcasecmp
  181. * A case insensivite string comparison
  182. *
  183. * @static
  184. * @access public
  185. * @param string string 1 to compare
  186. * @param string string 2 to compare
  187. * @param mixed The locale used by strcoll or false to use classical comparison
  188. * @return int < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
  189. * @see http://www.php.net/strcasecmp
  190. * @see http://www.php.net/strcoll
  191. * @see http://www.php.net/setlocale
  192. */
  193. public static function strcasecmp($str1, $str2, $locale = false)
  194. {
  195. if ($locale)
  196. {
  197. // get current locale
  198. $locale0 = setlocale(LC_COLLATE, 0);
  199. if (!$locale = setlocale(LC_COLLATE, $locale)) {
  200. $locale = $locale0;
  201. }
  202. // See if we have successfully set locale to UTF-8
  203. if(!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m)) {
  204. $encoding = 'CP' . $m[1];
  205. }
  206. else if(stristr($locale, 'UTF-8')){
  207. $encoding = 'UTF-8';
  208. }
  209. else {
  210. $encoding = 'nonrecodable';
  211. }
  212. // if we sucesfuly set encoding it to utf-8 or encoding is sth weird don't recode
  213. if ($encoding == 'UTF-8' || $encoding == 'nonrecodable') {
  214. return strcoll(utf8_strtolower($str1), utf8_strtolower($str2));
  215. } else {
  216. return strcoll(self::transcode(utf8_strtolower($str1),'UTF-8', $encoding), self::transcode(utf8_strtolower($str2),'UTF-8', $encoding));
  217. }
  218. }
  219. else
  220. {
  221. return utf8_strcasecmp($str1, $str2);
  222. }
  223. }
  224. /**
  225. * UTF-8/LOCALE aware alternative to strcmp
  226. * A case sensivite string comparison
  227. *
  228. * @static
  229. * @access public
  230. * @param string string 1 to compare
  231. * @param string string 2 to compare
  232. * @param mixed The locale used by strcoll or false to use classical comparison
  233. * @return int < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal.
  234. * @see http://www.php.net/strcmp
  235. * @see http://www.php.net/strcoll
  236. * @see http://www.php.net/setlocale
  237. */
  238. public static function strcmp($str1, $str2, $locale = false)
  239. {
  240. if ($locale)
  241. {
  242. // get current locale
  243. $locale0 = setlocale(LC_COLLATE, 0);
  244. if (!$locale = setlocale(LC_COLLATE, $locale)) {
  245. $locale = $locale0;
  246. }
  247. // See if we have successfully set locale to UTF-8
  248. if(!stristr($locale, 'UTF-8') && stristr($locale, '_') && preg_match('~\.(\d+)$~', $locale, $m)) {
  249. $encoding = 'CP' . $m[1];
  250. }
  251. else if(stristr($locale, 'UTF-8')){
  252. $encoding = 'UTF-8';
  253. }
  254. else {
  255. $encoding = 'nonrecodable';
  256. }
  257. // if we sucesfuly set encoding it to utf-8 or encoding is sth weird don't recode
  258. if ($encoding == 'UTF-8' || $encoding == 'nonrecodable') {
  259. return strcoll($str1, $str2);
  260. }
  261. else {
  262. return strcoll(self::transcode($str1,'UTF-8', $encoding), self::transcode($str2,'UTF-8', $encoding));
  263. }
  264. }
  265. else
  266. {
  267. return strcmp($str1, $str2);
  268. }
  269. }
  270. /**
  271. * UTF-8 aware alternative to strcspn
  272. * Find length of initial segment not matching mask
  273. *
  274. * @static
  275. * @access public
  276. * @param string
  277. * @param string the mask
  278. * @param int Optional starting character position (in characters)
  279. * @param int Optional length
  280. * @return int the length of the initial segment of str1 which does not contain any of the characters in str2
  281. * @see http://www.php.net/strcspn
  282. */
  283. public static function strcspn($str, $mask, $start = NULL, $length = NULL)
  284. {
  285. jimport('phputf8.strcspn');
  286. if ( $start === FALSE && $length === FALSE ) {
  287. return utf8_strcspn($str, $mask);
  288. } else if ( $length === FALSE ) {
  289. return utf8_strcspn($str, $mask, $start);
  290. } else {
  291. return utf8_strcspn($str, $mask, $start, $length);
  292. }
  293. }
  294. /**
  295. * UTF-8 aware alternative to stristr
  296. * Returns all of haystack from the first occurrence of needle to the end.
  297. * needle and haystack are examined in a case-insensitive manner
  298. * Find first occurrence of a string using case insensitive comparison
  299. *
  300. * @static
  301. * @access public
  302. * @param string the haystack
  303. * @param string the needle
  304. * @return string the sub string
  305. * @see http://www.php.net/stristr
  306. */
  307. public static function stristr($str, $search)
  308. {
  309. jimport('phputf8.stristr');
  310. return utf8_stristr($str, $search);
  311. }
  312. /**
  313. * UTF-8 aware alternative to strrev
  314. * Reverse a string
  315. *
  316. * @static
  317. * @access public
  318. * @param string String to be reversed
  319. * @return string The string in reverse character order
  320. * @see http://www.php.net/strrev
  321. */
  322. public static function strrev($str)
  323. {
  324. jimport('phputf8.strrev');
  325. return utf8_strrev($str);
  326. }
  327. /**
  328. * UTF-8 aware alternative to strspn
  329. * Find length of initial segment matching mask
  330. *
  331. * @static
  332. * @access public
  333. * @param string the haystack
  334. * @param string the mask
  335. * @param int start optional
  336. * @param int length optional
  337. * @see http://www.php.net/strspn
  338. */
  339. public static function strspn($str, $mask, $start = NULL, $length = NULL)
  340. {
  341. jimport('phputf8.strspn');
  342. if ( $start === NULL && $length === NULL ) {
  343. return utf8_strspn($str, $mask);
  344. } else if ( $length === NULL ) {
  345. return utf8_strspn($str, $mask, $start);
  346. } else {
  347. return utf8_strspn($str, $mask, $start, $length);
  348. }
  349. }
  350. /**
  351. * UTF-8 aware substr_replace
  352. * Replace text within a portion of a string
  353. *
  354. * @static
  355. * @access public
  356. * @param string the haystack
  357. * @param string the replacement string
  358. * @param int start
  359. * @param int length (optional)
  360. * @see http://www.php.net/substr_replace
  361. */
  362. public static function substr_replace($str, $repl, $start, $length = NULL)
  363. {
  364. // loaded by library loader
  365. if ( $length === FALSE ) {
  366. return utf8_substr_replace($str, $repl, $start);
  367. } else {
  368. return utf8_substr_replace($str, $repl, $start, $length);
  369. }
  370. }
  371. /**
  372. * UTF-8 aware replacement for ltrim()
  373. * Strip whitespace (or other characters) from the beginning of a string
  374. * Note: you only need to use this if you are supplying the charlist
  375. * optional arg and it contains UTF-8 characters. Otherwise ltrim will
  376. * work normally on a UTF-8 string
  377. *
  378. * @static
  379. * @access public
  380. * @param string the string to be trimmed
  381. * @param string the optional charlist of additional characters to trim
  382. * @return string the trimmed string
  383. * @see http://www.php.net/ltrim
  384. */
  385. public static function ltrim($str, $charlist = FALSE)
  386. {
  387. if (empty($charlist) && $charlist !== false) {
  388. return $str;
  389. }
  390. jimport('phputf8.trim');
  391. if ( $charlist === FALSE ) {
  392. return utf8_ltrim( $str );
  393. } else {
  394. return utf8_ltrim( $str, $charlist );
  395. }
  396. }
  397. /**
  398. * UTF-8 aware replacement for rtrim()
  399. * Strip whitespace (or other characters) from the end of a string
  400. * Note: you only need to use this if you are supplying the charlist
  401. * optional arg and it contains UTF-8 characters. Otherwise rtrim will
  402. * work normally on a UTF-8 string
  403. *
  404. * @static
  405. * @access public
  406. * @param string the string to be trimmed
  407. * @param string the optional charlist of additional characters to trim
  408. * @return string the trimmed string
  409. * @see http://www.php.net/rtrim
  410. */
  411. public static function rtrim($str, $charlist = FALSE)
  412. {
  413. if (empty($charlist) && $charlist !== false) {
  414. return $str;
  415. }
  416. jimport('phputf8.trim');
  417. if ( $charlist === FALSE ) {
  418. return utf8_rtrim($str);
  419. } else {
  420. return utf8_rtrim( $str, $charlist );
  421. }
  422. }
  423. /**
  424. * UTF-8 aware replacement for trim()
  425. * Strip whitespace (or other characters) from the beginning and end of a string
  426. * Note: you only need to use this if you are supplying the charlist
  427. * optional arg and it contains UTF-8 characters. Otherwise trim will
  428. * work normally on a UTF-8 string
  429. *
  430. * @static
  431. * @access public
  432. * @param string the string to be trimmed
  433. * @param string the optional charlist of additional characters to trim
  434. * @return string the trimmed string
  435. * @see http://www.php.net/trim
  436. */
  437. public static function trim($str, $charlist = FALSE)
  438. {
  439. if (empty($charlist) && $charlist !== false) {
  440. return $str;
  441. }
  442. jimport('phputf8.trim');
  443. if ( $charlist === FALSE ) {
  444. return utf8_trim( $str );
  445. } else {
  446. return utf8_trim( $str, $charlist );
  447. }
  448. }
  449. /**
  450. * UTF-8 aware alternative to ucfirst
  451. * Make a string's first character uppercase
  452. *
  453. * @static
  454. * @access public
  455. * @param string
  456. * @return string with first character as upper case (if applicable)
  457. * @see http://www.php.net/ucfirst
  458. */
  459. public static function ucfirst($str)
  460. {
  461. jimport('phputf8.ucfirst');
  462. return utf8_ucfirst($str);
  463. }
  464. /**
  465. * UTF-8 aware alternative to ucwords
  466. * Uppercase the first character of each word in a string
  467. *
  468. * @static
  469. * @access public
  470. * @param string
  471. * @return string with first char of each word uppercase
  472. * @see http://www.php.net/ucwords
  473. */
  474. public static function ucwords($str)
  475. {
  476. jimport('phputf8.ucwords');
  477. return utf8_ucwords($str);
  478. }
  479. /**
  480. * Transcode a string.
  481. *
  482. * @static
  483. * @param string $source The string to transcode.
  484. * @param string $from_encoding The source encoding.
  485. * @param string $to_encoding The target encoding.
  486. * @return string Transcoded string
  487. * @since 11.1
  488. */
  489. public static function transcode($source, $from_encoding, $to_encoding)
  490. {
  491. if (is_string($source)) {
  492. /*
  493. * "//TRANSLIT" is appendd to the $to_encoding to ensure that when iconv comes
  494. * across a character that cannot be represented in the target charset, it can
  495. * be approximated through one or several similarly looking characters.
  496. */
  497. return iconv($from_encoding, $to_encoding.'//TRANSLIT', $source);
  498. }
  499. }
  500. /**
  501. * Tests a string as to whether it's valid UTF-8 and supported by the
  502. * Unicode standard
  503. * Note: this function has been modified to simple return true or false
  504. * @author <hsivonen@iki.fi>
  505. * @param string UTF-8 encoded string
  506. * @return boolean true if valid
  507. * @since 1.6
  508. * @see http://hsivonen.iki.fi/php-utf8/
  509. * @see compliant
  510. */
  511. public static function valid($str)
  512. {
  513. $mState = 0; // cached expected number of octets after the current octet
  514. // until the beginning of the next UTF8 character sequence
  515. $mUcs4 = 0; // cached Unicode character
  516. $mBytes = 1; // cached expected number of octets in the current sequence
  517. $len = strlen($str);
  518. for ($i = 0; $i < $len; $i++)
  519. {
  520. $in = ord($str{$i});
  521. if ($mState == 0)
  522. {
  523. // When mState is zero we expect either a US-ASCII character or a
  524. // multi-octet sequence.
  525. if (0 == (0x80 & ($in))) {
  526. // US-ASCII, pass straight through.
  527. $mBytes = 1;
  528. } else if (0xC0 == (0xE0 & ($in))) {
  529. // First octet of 2 octet sequence
  530. $mUcs4 = ($in);
  531. $mUcs4 = ($mUcs4 & 0x1F) << 6;
  532. $mState = 1;
  533. $mBytes = 2;
  534. } else if (0xE0 == (0xF0 & ($in))) {
  535. // First octet of 3 octet sequence
  536. $mUcs4 = ($in);
  537. $mUcs4 = ($mUcs4 & 0x0F) << 12;
  538. $mState = 2;
  539. $mBytes = 3;
  540. } else if (0xF0 == (0xF8 & ($in))) {
  541. // First octet of 4 octet sequence
  542. $mUcs4 = ($in);
  543. $mUcs4 = ($mUcs4 & 0x07) << 18;
  544. $mState = 3;
  545. $mBytes = 4;
  546. } else if (0xF8 == (0xFC & ($in))) {
  547. /* First octet of 5 octet sequence.
  548. *
  549. * This is illegal because the encoded codepoint must be either
  550. * (a) not the shortest form or
  551. * (b) outside the Unicode range of 0-0x10FFFF.
  552. * Rather than trying to resynchronize, we will carry on until the end
  553. * of the sequence and let the later error handling code catch it.
  554. */
  555. $mUcs4 = ($in);
  556. $mUcs4 = ($mUcs4 & 0x03) << 24;
  557. $mState = 4;
  558. $mBytes = 5;
  559. } else if (0xFC == (0xFE & ($in))) {
  560. // First octet of 6 octet sequence, see comments for 5 octet sequence.
  561. $mUcs4 = ($in);
  562. $mUcs4 = ($mUcs4 & 1) << 30;
  563. $mState = 5;
  564. $mBytes = 6;
  565. } else {
  566. /* Current octet is neither in the US-ASCII range nor a legal first
  567. * octet of a multi-octet sequence.
  568. */
  569. return FALSE;
  570. }
  571. }
  572. else
  573. {
  574. // When mState is non-zero, we expect a continuation of the multi-octet
  575. // sequence
  576. if (0x80 == (0xC0 & ($in)))
  577. {
  578. // Legal continuation.
  579. $shift = ($mState - 1) * 6;
  580. $tmp = $in;
  581. $tmp = ($tmp & 0x0000003F) << $shift;
  582. $mUcs4 |= $tmp;
  583. /**
  584. * End of the multi-octet sequence. mUcs4 now contains the final
  585. * Unicode codepoint to be output
  586. */
  587. if (0 == --$mState)
  588. {
  589. /*
  590. * Check for illegal sequences and codepoints.
  591. */
  592. // From Unicode 3.1, non-shortest form is illegal
  593. if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
  594. ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
  595. ((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
  596. (4 < $mBytes) ||
  597. // From Unicode 3.2, surrogate characters are illegal
  598. (($mUcs4 & 0xFFFFF800) == 0xD800) ||
  599. // Codepoints outside the Unicode range are illegal
  600. ($mUcs4 > 0x10FFFF)) {
  601. return FALSE;
  602. }
  603. // Initialize UTF8 cache.
  604. $mState = 0;
  605. $mUcs4 = 0;
  606. $mBytes = 1;
  607. }
  608. }
  609. else
  610. {
  611. /**
  612. *((0xC0 & (*in) != 0x80) && (mState != 0))
  613. * Incomplete multi-octet sequence.
  614. */
  615. return FALSE;
  616. }
  617. }
  618. }
  619. return TRUE;
  620. }
  621. /**
  622. * Tests whether a string complies as UTF-8. This will be much
  623. * faster than utf8_is_valid but will pass five and six octet
  624. * UTF-8 sequences, which are not supported by Unicode and
  625. * so cannot be displayed correctly in a browser. In other words
  626. * it is not as strict as utf8_is_valid but it's faster. If you use
  627. * is to validate user input, you place yourself at the risk that
  628. * attackers will be able to inject 5 and 6 byte sequences (which
  629. * may or may not be a significant risk, depending on what you are
  630. * are doing)
  631. * @see valid
  632. * @see http://www.php.net/manual/en/reference.pcre.pattern.modifiers.php#54805
  633. * @param string UTF-8 string to check
  634. * @return boolean TRUE if string is valid UTF-8
  635. * @since 1.6
  636. */
  637. public static function compliant($str)
  638. {
  639. if (strlen($str) == 0) {
  640. return TRUE;
  641. }
  642. // If even just the first character can be matched, when the /u
  643. // modifier is used, then it's valid UTF-8. If the UTF-8 is somehow
  644. // invalid, nothing at all will match, even if the string contains
  645. // some valid sequences
  646. return (preg_match('/^.{1}/us',$str,$ar) == 1);
  647. }
  648. /**
  649. * Does a UTF-8 safe version of PHP parse_url function
  650. * @see http://us3.php.net/manual/en/function.parse-url.php
  651. *
  652. * @param string URL to parse
  653. * @return associative array or false if badly formed URL.
  654. * @since 1.6
  655. */
  656. public static function parse_url($url) {
  657. $result = array();
  658. // Build arrays of values we need to decode before parsing
  659. $entities = array('%21', '%2A', '%27', '%28', '%29', '%3B', '%3A', '%40', '%26', '%3D', '%24', '%2C', '%2F', '%3F', '%25', '%23', '%5B', '%5D');
  660. $replacements = array('!', '*', "'", "(", ")", ";", ":", "@", "&", "=", "$", ",", "/", "?", "%", "#", "[", "]");
  661. // Create encoded URL with special URL characters decoded so it can be parsed
  662. // All other charcters will be encoded
  663. $encodedURL = str_replace($entities, $replacements, urlencode($url));
  664. // Parse the encoded URL
  665. $encodedParts = parse_url($encodedURL);
  666. // Now, decode each value of the resulting array
  667. foreach ($encodedParts as $key => $value) {
  668. $result[$key] = urldecode($value);
  669. }
  670. return $result;
  671. }
  672. }