PageRenderTime 49ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/libraries/joomla/utilities/string.php

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