PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-includes/compat.php

https://gitlab.com/juanito.abelo/nlmobile
PHP | 580 lines | 259 code | 77 blank | 244 comment | 56 complexity | f50f625bd3d102fc84ef026c63d11d60 MD5 | raw file
  1. <?php
  2. /**
  3. * WordPress implementation for PHP functions either missing from older PHP versions or not included by default.
  4. *
  5. * @package PHP
  6. * @access private
  7. */
  8. // If gettext isn't available
  9. if ( !function_exists('_') ) {
  10. function _($string) {
  11. return $string;
  12. }
  13. }
  14. /**
  15. * Returns whether PCRE/u (PCRE_UTF8 modifier) is available for use.
  16. *
  17. * @ignore
  18. * @since 4.2.2
  19. * @access private
  20. *
  21. * @staticvar string $utf8_pcre
  22. *
  23. * @param bool $set - Used for testing only
  24. * null : default - get PCRE/u capability
  25. * false : Used for testing - return false for future calls to this function
  26. * 'reset': Used for testing - restore default behavior of this function
  27. */
  28. function _wp_can_use_pcre_u( $set = null ) {
  29. static $utf8_pcre = 'reset';
  30. if ( null !== $set ) {
  31. $utf8_pcre = $set;
  32. }
  33. if ( 'reset' === $utf8_pcre ) {
  34. $utf8_pcre = @preg_match( '/^./u', 'a' );
  35. }
  36. return $utf8_pcre;
  37. }
  38. if ( ! function_exists( 'mb_substr' ) ) :
  39. /**
  40. * Compat function to mimic mb_substr().
  41. *
  42. * @ignore
  43. * @since 3.2.0
  44. *
  45. * @see _mb_substr()
  46. *
  47. * @param string $str The string to extract the substring from.
  48. * @param int $start Position to being extraction from in `$str`.
  49. * @param int|null $length Optional. Maximum number of characters to extract from `$str`.
  50. * Default null.
  51. * @param string|null $encoding Optional. Character encoding to use. Default null.
  52. * @return string Extracted substring.
  53. */
  54. function mb_substr( $str, $start, $length = null, $encoding = null ) {
  55. return _mb_substr( $str, $start, $length, $encoding );
  56. }
  57. endif;
  58. /**
  59. * Internal compat function to mimic mb_substr().
  60. *
  61. * Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
  62. * For $encoding === UTF-8, the $str input is expected to be a valid UTF-8 byte sequence.
  63. * The behavior of this function for invalid inputs is undefined.
  64. *
  65. * @ignore
  66. * @since 3.2.0
  67. *
  68. * @param string $str The string to extract the substring from.
  69. * @param int $start Position to being extraction from in `$str`.
  70. * @param int|null $length Optional. Maximum number of characters to extract from `$str`.
  71. * Default null.
  72. * @param string|null $encoding Optional. Character encoding to use. Default null.
  73. * @return string Extracted substring.
  74. */
  75. function _mb_substr( $str, $start, $length = null, $encoding = null ) {
  76. if ( null === $encoding ) {
  77. $encoding = get_option( 'blog_charset' );
  78. }
  79. /*
  80. * The solution below works only for UTF-8, so in case of a different
  81. * charset just use built-in substr().
  82. */
  83. if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
  84. return is_null( $length ) ? substr( $str, $start ) : substr( $str, $start, $length );
  85. }
  86. if ( _wp_can_use_pcre_u() ) {
  87. // Use the regex unicode support to separate the UTF-8 characters into an array.
  88. preg_match_all( '/./us', $str, $match );
  89. $chars = is_null( $length ) ? array_slice( $match[0], $start ) : array_slice( $match[0], $start, $length );
  90. return implode( '', $chars );
  91. }
  92. $regex = '/(
  93. [\x00-\x7F] # single-byte sequences 0xxxxxxx
  94. | [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
  95. | \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
  96. | [\xE1-\xEC][\x80-\xBF]{2}
  97. | \xED[\x80-\x9F][\x80-\xBF]
  98. | [\xEE-\xEF][\x80-\xBF]{2}
  99. | \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
  100. | [\xF1-\xF3][\x80-\xBF]{3}
  101. | \xF4[\x80-\x8F][\x80-\xBF]{2}
  102. )/x';
  103. // Start with 1 element instead of 0 since the first thing we do is pop.
  104. $chars = array( '' );
  105. do {
  106. // We had some string left over from the last round, but we counted it in that last round.
  107. array_pop( $chars );
  108. /*
  109. * Split by UTF-8 character, limit to 1000 characters (last array element will contain
  110. * the rest of the string).
  111. */
  112. $pieces = preg_split( $regex, $str, 1000, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY );
  113. $chars = array_merge( $chars, $pieces );
  114. // If there's anything left over, repeat the loop.
  115. } while ( count( $pieces ) > 1 && $str = array_pop( $pieces ) );
  116. return join( '', array_slice( $chars, $start, $length ) );
  117. }
  118. if ( ! function_exists( 'mb_strlen' ) ) :
  119. /**
  120. * Compat function to mimic mb_strlen().
  121. *
  122. * @ignore
  123. * @since 4.2.0
  124. *
  125. * @see _mb_strlen()
  126. *
  127. * @param string $str The string to retrieve the character length from.
  128. * @param string|null $encoding Optional. Character encoding to use. Default null.
  129. * @return int String length of `$str`.
  130. */
  131. function mb_strlen( $str, $encoding = null ) {
  132. return _mb_strlen( $str, $encoding );
  133. }
  134. endif;
  135. /**
  136. * Internal compat function to mimic mb_strlen().
  137. *
  138. * Only understands UTF-8 and 8bit. All other character sets will be treated as 8bit.
  139. * For $encoding === UTF-8, the `$str` input is expected to be a valid UTF-8 byte
  140. * sequence. The behavior of this function for invalid inputs is undefined.
  141. *
  142. * @ignore
  143. * @since 4.2.0
  144. *
  145. * @param string $str The string to retrieve the character length from.
  146. * @param string|null $encoding Optional. Character encoding to use. Default null.
  147. * @return int String length of `$str`.
  148. */
  149. function _mb_strlen( $str, $encoding = null ) {
  150. if ( null === $encoding ) {
  151. $encoding = get_option( 'blog_charset' );
  152. }
  153. /*
  154. * The solution below works only for UTF-8, so in case of a different charset
  155. * just use built-in strlen().
  156. */
  157. if ( ! in_array( $encoding, array( 'utf8', 'utf-8', 'UTF8', 'UTF-8' ) ) ) {
  158. return strlen( $str );
  159. }
  160. if ( _wp_can_use_pcre_u() ) {
  161. // Use the regex unicode support to separate the UTF-8 characters into an array.
  162. preg_match_all( '/./us', $str, $match );
  163. return count( $match[0] );
  164. }
  165. $regex = '/(?:
  166. [\x00-\x7F] # single-byte sequences 0xxxxxxx
  167. | [\xC2-\xDF][\x80-\xBF] # double-byte sequences 110xxxxx 10xxxxxx
  168. | \xE0[\xA0-\xBF][\x80-\xBF] # triple-byte sequences 1110xxxx 10xxxxxx * 2
  169. | [\xE1-\xEC][\x80-\xBF]{2}
  170. | \xED[\x80-\x9F][\x80-\xBF]
  171. | [\xEE-\xEF][\x80-\xBF]{2}
  172. | \xF0[\x90-\xBF][\x80-\xBF]{2} # four-byte sequences 11110xxx 10xxxxxx * 3
  173. | [\xF1-\xF3][\x80-\xBF]{3}
  174. | \xF4[\x80-\x8F][\x80-\xBF]{2}
  175. )/x';
  176. // Start at 1 instead of 0 since the first thing we do is decrement.
  177. $count = 1;
  178. do {
  179. // We had some string left over from the last round, but we counted it in that last round.
  180. $count--;
  181. /*
  182. * Split by UTF-8 character, limit to 1000 characters (last array element will contain
  183. * the rest of the string).
  184. */
  185. $pieces = preg_split( $regex, $str, 1000 );
  186. // Increment.
  187. $count += count( $pieces );
  188. // If there's anything left over, repeat the loop.
  189. } while ( $str = array_pop( $pieces ) );
  190. // Fencepost: preg_split() always returns one extra item in the array.
  191. return --$count;
  192. }
  193. if ( !function_exists('hash_hmac') ):
  194. /**
  195. * Compat function to mimic hash_hmac().
  196. *
  197. * @ignore
  198. * @since 3.2.0
  199. *
  200. * @see _hash_hmac()
  201. *
  202. * @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
  203. * @param string $data Data to be hashed.
  204. * @param string $key Secret key to use for generating the hash.
  205. * @param bool $raw_output Optional. Whether to output raw binary data (true),
  206. * or lowercase hexits (false). Default false.
  207. * @return string|false The hash in output determined by `$raw_output`. False if `$algo`
  208. * is unknown or invalid.
  209. */
  210. function hash_hmac($algo, $data, $key, $raw_output = false) {
  211. return _hash_hmac($algo, $data, $key, $raw_output);
  212. }
  213. endif;
  214. /**
  215. * Internal compat function to mimic hash_hmac().
  216. *
  217. * @ignore
  218. * @since 3.2.0
  219. *
  220. * @param string $algo Hash algorithm. Accepts 'md5' or 'sha1'.
  221. * @param string $data Data to be hashed.
  222. * @param string $key Secret key to use for generating the hash.
  223. * @param bool $raw_output Optional. Whether to output raw binary data (true),
  224. * or lowercase hexits (false). Default false.
  225. * @return string|false The hash in output determined by `$raw_output`. False if `$algo`
  226. * is unknown or invalid.
  227. */
  228. function _hash_hmac($algo, $data, $key, $raw_output = false) {
  229. $packs = array('md5' => 'H32', 'sha1' => 'H40');
  230. if ( !isset($packs[$algo]) )
  231. return false;
  232. $pack = $packs[$algo];
  233. if (strlen($key) > 64)
  234. $key = pack($pack, $algo($key));
  235. $key = str_pad($key, 64, chr(0));
  236. $ipad = (substr($key, 0, 64) ^ str_repeat(chr(0x36), 64));
  237. $opad = (substr($key, 0, 64) ^ str_repeat(chr(0x5C), 64));
  238. $hmac = $algo($opad . pack($pack, $algo($ipad . $data)));
  239. if ( $raw_output )
  240. return pack( $pack, $hmac );
  241. return $hmac;
  242. }
  243. if ( !function_exists('json_encode') ) {
  244. function json_encode( $string ) {
  245. global $wp_json;
  246. if ( ! ( $wp_json instanceof Services_JSON ) ) {
  247. require_once( ABSPATH . WPINC . '/class-json.php' );
  248. $wp_json = new Services_JSON();
  249. }
  250. return $wp_json->encodeUnsafe( $string );
  251. }
  252. }
  253. if ( !function_exists('json_decode') ) {
  254. /**
  255. * @global Services_JSON $wp_json
  256. * @param string $string
  257. * @param bool $assoc_array
  258. * @return object|array
  259. */
  260. function json_decode( $string, $assoc_array = false ) {
  261. global $wp_json;
  262. if ( ! ($wp_json instanceof Services_JSON ) ) {
  263. require_once( ABSPATH . WPINC . '/class-json.php' );
  264. $wp_json = new Services_JSON();
  265. }
  266. $res = $wp_json->decode( $string );
  267. if ( $assoc_array )
  268. $res = _json_decode_object_helper( $res );
  269. return $res;
  270. }
  271. /**
  272. * @param object $data
  273. * @return array
  274. */
  275. function _json_decode_object_helper($data) {
  276. if ( is_object($data) )
  277. $data = get_object_vars($data);
  278. return is_array($data) ? array_map(__FUNCTION__, $data) : $data;
  279. }
  280. }
  281. if ( ! function_exists( 'hash_equals' ) ) :
  282. /**
  283. * Timing attack safe string comparison
  284. *
  285. * Compares two strings using the same time whether they're equal or not.
  286. *
  287. * This function was added in PHP 5.6.
  288. *
  289. * Note: It can leak the length of a string when arguments of differing length are supplied.
  290. *
  291. * @since 3.9.2
  292. *
  293. * @param string $a Expected string.
  294. * @param string $b Actual, user supplied, string.
  295. * @return bool Whether strings are equal.
  296. */
  297. function hash_equals( $a, $b ) {
  298. $a_length = strlen( $a );
  299. if ( $a_length !== strlen( $b ) ) {
  300. return false;
  301. }
  302. $result = 0;
  303. // Do not attempt to "optimize" this.
  304. for ( $i = 0; $i < $a_length; $i++ ) {
  305. $result |= ord( $a[ $i ] ) ^ ord( $b[ $i ] );
  306. }
  307. return $result === 0;
  308. }
  309. endif;
  310. // JSON_PRETTY_PRINT was introduced in PHP 5.4
  311. // Defined here to prevent a notice when using it with wp_json_encode()
  312. if ( ! defined( 'JSON_PRETTY_PRINT' ) ) {
  313. define( 'JSON_PRETTY_PRINT', 128 );
  314. }
  315. if ( ! function_exists( 'json_last_error_msg' ) ) :
  316. /**
  317. * Retrieves the error string of the last json_encode() or json_decode() call.
  318. *
  319. * @since 4.4.0
  320. *
  321. * @internal This is a compatibility function for PHP <5.5
  322. *
  323. * @return bool|string Returns the error message on success, "No Error" if no error has occurred,
  324. * or false on failure.
  325. */
  326. function json_last_error_msg() {
  327. // See https://core.trac.wordpress.org/ticket/27799.
  328. if ( ! function_exists( 'json_last_error' ) ) {
  329. return false;
  330. }
  331. $last_error_code = json_last_error();
  332. // Just in case JSON_ERROR_NONE is not defined.
  333. $error_code_none = defined( 'JSON_ERROR_NONE' ) ? JSON_ERROR_NONE : 0;
  334. switch ( true ) {
  335. case $last_error_code === $error_code_none:
  336. return 'No error';
  337. case defined( 'JSON_ERROR_DEPTH' ) && JSON_ERROR_DEPTH === $last_error_code:
  338. return 'Maximum stack depth exceeded';
  339. case defined( 'JSON_ERROR_STATE_MISMATCH' ) && JSON_ERROR_STATE_MISMATCH === $last_error_code:
  340. return 'State mismatch (invalid or malformed JSON)';
  341. case defined( 'JSON_ERROR_CTRL_CHAR' ) && JSON_ERROR_CTRL_CHAR === $last_error_code:
  342. return 'Control character error, possibly incorrectly encoded';
  343. case defined( 'JSON_ERROR_SYNTAX' ) && JSON_ERROR_SYNTAX === $last_error_code:
  344. return 'Syntax error';
  345. case defined( 'JSON_ERROR_UTF8' ) && JSON_ERROR_UTF8 === $last_error_code:
  346. return 'Malformed UTF-8 characters, possibly incorrectly encoded';
  347. case defined( 'JSON_ERROR_RECURSION' ) && JSON_ERROR_RECURSION === $last_error_code:
  348. return 'Recursion detected';
  349. case defined( 'JSON_ERROR_INF_OR_NAN' ) && JSON_ERROR_INF_OR_NAN === $last_error_code:
  350. return 'Inf and NaN cannot be JSON encoded';
  351. case defined( 'JSON_ERROR_UNSUPPORTED_TYPE' ) && JSON_ERROR_UNSUPPORTED_TYPE === $last_error_code:
  352. return 'Type is not supported';
  353. default:
  354. return 'An unknown error occurred';
  355. }
  356. }
  357. endif;
  358. if ( ! interface_exists( 'JsonSerializable' ) ) {
  359. define( 'WP_JSON_SERIALIZE_COMPATIBLE', true );
  360. /**
  361. * JsonSerializable interface.
  362. *
  363. * Compatibility shim for PHP <5.4
  364. *
  365. * @link https://secure.php.net/jsonserializable
  366. *
  367. * @since 4.4.0
  368. */
  369. interface JsonSerializable {
  370. public function jsonSerialize();
  371. }
  372. }
  373. // random_int was introduced in PHP 7.0
  374. if ( ! function_exists( 'random_int' ) ) {
  375. require ABSPATH . WPINC . '/random_compat/random.php';
  376. }
  377. if ( ! function_exists( 'array_replace_recursive' ) ) :
  378. /**
  379. * PHP-agnostic version of {@link array_replace_recursive()}.
  380. *
  381. * The array_replace_recursive() function is a PHP 5.3 function. WordPress
  382. * currently supports down to PHP 5.2, so this method is a workaround
  383. * for PHP 5.2.
  384. *
  385. * Note: array_replace_recursive() supports infinite arguments, but for our use-
  386. * case, we only need to support two arguments.
  387. *
  388. * Subject to removal once WordPress makes PHP 5.3.0 the minimum requirement.
  389. *
  390. * @since 4.5.3
  391. *
  392. * @see http://php.net/manual/en/function.array-replace-recursive.php#109390
  393. *
  394. * @param array $base Array with keys needing to be replaced.
  395. * @param array $replacements Array with the replaced keys.
  396. *
  397. * @return array
  398. */
  399. function array_replace_recursive( $base = array(), $replacements = array() ) {
  400. foreach ( array_slice( func_get_args(), 1 ) as $replacements ) {
  401. $bref_stack = array( &$base );
  402. $head_stack = array( $replacements );
  403. do {
  404. end( $bref_stack );
  405. $bref = &$bref_stack[ key( $bref_stack ) ];
  406. $head = array_pop( $head_stack );
  407. unset( $bref_stack[ key( $bref_stack ) ] );
  408. foreach ( array_keys( $head ) as $key ) {
  409. if ( isset( $key, $bref ) &&
  410. isset( $bref[ $key ] ) && is_array( $bref[ $key ] ) &&
  411. isset( $head[ $key ] ) && is_array( $head[ $key ] )
  412. ) {
  413. $bref_stack[] = &$bref[ $key ];
  414. $head_stack[] = $head[ $key ];
  415. } else {
  416. $bref[ $key ] = $head[ $key ];
  417. }
  418. }
  419. } while ( count( $head_stack ) );
  420. }
  421. return $base;
  422. }
  423. endif;
  424. // SPL can be disabled on PHP 5.2
  425. if ( ! function_exists( 'spl_autoload_register' ) ):
  426. $_wp_spl_autoloaders = array();
  427. /**
  428. * Autoloader compatibility callback.
  429. *
  430. * @since 4.6.0
  431. *
  432. * @param string $classname Class to attempt autoloading.
  433. */
  434. function __autoload( $classname ) {
  435. global $_wp_spl_autoloaders;
  436. foreach ( $_wp_spl_autoloaders as $autoloader ) {
  437. if ( ! is_callable( $autoloader ) ) {
  438. // Avoid the extra warning if the autoloader isn't callable.
  439. continue;
  440. }
  441. call_user_func( $autoloader, $classname );
  442. // If it has been autoloaded, stop processing.
  443. if ( class_exists( $classname, false ) ) {
  444. return;
  445. }
  446. }
  447. }
  448. /**
  449. * Registers a function to be autoloaded.
  450. *
  451. * @since 4.6.0
  452. *
  453. * @param callable $autoload_function The function to register.
  454. * @param bool $throw Optional. Whether the function should throw an exception
  455. * if the function isn't callable. Default true.
  456. * @param bool $prepend Whether the function should be prepended to the stack.
  457. * Default false.
  458. */
  459. function spl_autoload_register( $autoload_function, $throw = true, $prepend = false ) {
  460. if ( $throw && ! is_callable( $autoload_function ) ) {
  461. // String not translated to match PHP core.
  462. throw new Exception( 'Function not callable' );
  463. }
  464. global $_wp_spl_autoloaders;
  465. // Don't allow multiple registration.
  466. if ( in_array( $autoload_function, $_wp_spl_autoloaders ) ) {
  467. return;
  468. }
  469. if ( $prepend ) {
  470. array_unshift( $_wp_spl_autoloaders, $autoload_function );
  471. } else {
  472. $_wp_spl_autoloaders[] = $autoload_function;
  473. }
  474. }
  475. /**
  476. * Unregisters an autoloader function.
  477. *
  478. * @since 4.6.0
  479. *
  480. * @param callable $function The function to unregister.
  481. * @return bool True if the function was unregistered, false if it could not be.
  482. */
  483. function spl_autoload_unregister( $function ) {
  484. global $_wp_spl_autoloaders;
  485. foreach ( $_wp_spl_autoloaders as &$autoloader ) {
  486. if ( $autoloader === $function ) {
  487. unset( $autoloader );
  488. return true;
  489. }
  490. }
  491. return false;
  492. }
  493. /**
  494. * Retrieves the registered autoloader functions.
  495. *
  496. * @since 4.6.0
  497. *
  498. * @return array List of autoloader functions.
  499. */
  500. function spl_autoload_functions() {
  501. return $GLOBALS['_wp_spl_autoloaders'];
  502. }
  503. endif;