PageRenderTime 77ms CodeModel.GetById 36ms RepoModel.GetById 0ms app.codeStats 2ms

/wp-includes/functions.php

https://github.com/markjaquith/WordPress
PHP | 8373 lines | 4871 code | 714 blank | 2788 comment | 653 complexity | f866d284c4d9204f45a98bdff8f35f6e MD5 | raw file
Possible License(s): GPL-2.0, AGPL-1.0, LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. /**
  3. * Main WordPress API
  4. *
  5. * @package WordPress
  6. */
  7. require ABSPATH . WPINC . '/option.php';
  8. /**
  9. * Convert given MySQL date string into a different format.
  10. *
  11. * - `$format` should be a PHP date format string.
  12. * - 'U' and 'G' formats will return an integer sum of timestamp with timezone offset.
  13. * - `$date` is expected to be local time in MySQL format (`Y-m-d H:i:s`).
  14. *
  15. * Historically UTC time could be passed to the function to produce Unix timestamp.
  16. *
  17. * If `$translate` is true then the given date and format string will
  18. * be passed to `wp_date()` for translation.
  19. *
  20. * @since 0.71
  21. *
  22. * @param string $format Format of the date to return.
  23. * @param string $date Date string to convert.
  24. * @param bool $translate Whether the return date should be translated. Default true.
  25. * @return string|int|false Integer if `$format` is 'U' or 'G', string otherwise.
  26. * False on failure.
  27. */
  28. function mysql2date( $format, $date, $translate = true ) {
  29. if ( empty( $date ) ) {
  30. return false;
  31. }
  32. $datetime = date_create( $date, wp_timezone() );
  33. if ( false === $datetime ) {
  34. return false;
  35. }
  36. // Returns a sum of timestamp with timezone offset. Ideally should never be used.
  37. if ( 'G' === $format || 'U' === $format ) {
  38. return $datetime->getTimestamp() + $datetime->getOffset();
  39. }
  40. if ( $translate ) {
  41. return wp_date( $format, $datetime->getTimestamp() );
  42. }
  43. return $datetime->format( $format );
  44. }
  45. /**
  46. * Retrieves the current time based on specified type.
  47. *
  48. * - The 'mysql' type will return the time in the format for MySQL DATETIME field.
  49. * - The 'timestamp' or 'U' types will return the current timestamp or a sum of timestamp
  50. * and timezone offset, depending on `$gmt`.
  51. * - Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
  52. *
  53. * If `$gmt` is a truthy value then both types will use GMT time, otherwise the
  54. * output is adjusted with the GMT offset for the site.
  55. *
  56. * @since 1.0.0
  57. * @since 5.3.0 Now returns an integer if `$type` is 'U'. Previously a string was returned.
  58. *
  59. * @param string $type Type of time to retrieve. Accepts 'mysql', 'timestamp', 'U',
  60. * or PHP date format string (e.g. 'Y-m-d').
  61. * @param int|bool $gmt Optional. Whether to use GMT timezone. Default false.
  62. * @return int|string Integer if `$type` is 'timestamp' or 'U', string otherwise.
  63. */
  64. function current_time( $type, $gmt = 0 ) {
  65. // Don't use non-GMT timestamp, unless you know the difference and really need to.
  66. if ( 'timestamp' === $type || 'U' === $type ) {
  67. return $gmt ? time() : time() + (int) ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  68. }
  69. if ( 'mysql' === $type ) {
  70. $type = 'Y-m-d H:i:s';
  71. }
  72. $timezone = $gmt ? new DateTimeZone( 'UTC' ) : wp_timezone();
  73. $datetime = new DateTime( 'now', $timezone );
  74. return $datetime->format( $type );
  75. }
  76. /**
  77. * Retrieves the current time as an object using the site's timezone.
  78. *
  79. * @since 5.3.0
  80. *
  81. * @return DateTimeImmutable Date and time object.
  82. */
  83. function current_datetime() {
  84. return new DateTimeImmutable( 'now', wp_timezone() );
  85. }
  86. /**
  87. * Retrieves the timezone of the site as a string.
  88. *
  89. * Uses the `timezone_string` option to get a proper timezone name if available,
  90. * otherwise falls back to a manual UTC ± offset.
  91. *
  92. * Example return values:
  93. *
  94. * - 'Europe/Rome'
  95. * - 'America/North_Dakota/New_Salem'
  96. * - 'UTC'
  97. * - '-06:30'
  98. * - '+00:00'
  99. * - '+08:45'
  100. *
  101. * @since 5.3.0
  102. *
  103. * @return string PHP timezone name or a ±HH:MM offset.
  104. */
  105. function wp_timezone_string() {
  106. $timezone_string = get_option( 'timezone_string' );
  107. if ( $timezone_string ) {
  108. return $timezone_string;
  109. }
  110. $offset = (float) get_option( 'gmt_offset' );
  111. $hours = (int) $offset;
  112. $minutes = ( $offset - $hours );
  113. $sign = ( $offset < 0 ) ? '-' : '+';
  114. $abs_hour = abs( $hours );
  115. $abs_mins = abs( $minutes * 60 );
  116. $tz_offset = sprintf( '%s%02d:%02d', $sign, $abs_hour, $abs_mins );
  117. return $tz_offset;
  118. }
  119. /**
  120. * Retrieves the timezone of the site as a `DateTimeZone` object.
  121. *
  122. * Timezone can be based on a PHP timezone string or a ±HH:MM offset.
  123. *
  124. * @since 5.3.0
  125. *
  126. * @return DateTimeZone Timezone object.
  127. */
  128. function wp_timezone() {
  129. return new DateTimeZone( wp_timezone_string() );
  130. }
  131. /**
  132. * Retrieves the date in localized format, based on a sum of Unix timestamp and
  133. * timezone offset in seconds.
  134. *
  135. * If the locale specifies the locale month and weekday, then the locale will
  136. * take over the format for the date. If it isn't, then the date format string
  137. * will be used instead.
  138. *
  139. * Note that due to the way WP typically generates a sum of timestamp and offset
  140. * with `strtotime()`, it implies offset added at a _current_ time, not at the time
  141. * the timestamp represents. Storing such timestamps or calculating them differently
  142. * will lead to invalid output.
  143. *
  144. * @since 0.71
  145. * @since 5.3.0 Converted into a wrapper for wp_date().
  146. *
  147. * @global WP_Locale $wp_locale WordPress date and time locale object.
  148. *
  149. * @param string $format Format to display the date.
  150. * @param int|bool $timestamp_with_offset Optional. A sum of Unix timestamp and timezone offset
  151. * in seconds. Default false.
  152. * @param bool $gmt Optional. Whether to use GMT timezone. Only applies
  153. * if timestamp is not provided. Default false.
  154. * @return string The date, translated if locale specifies it.
  155. */
  156. function date_i18n( $format, $timestamp_with_offset = false, $gmt = false ) {
  157. $timestamp = $timestamp_with_offset;
  158. // If timestamp is omitted it should be current time (summed with offset, unless `$gmt` is true).
  159. if ( ! is_numeric( $timestamp ) ) {
  160. // phpcs:ignore WordPress.DateTime.CurrentTimeTimestamp.Requested
  161. $timestamp = current_time( 'timestamp', $gmt );
  162. }
  163. /*
  164. * This is a legacy implementation quirk that the returned timestamp is also with offset.
  165. * Ideally this function should never be used to produce a timestamp.
  166. */
  167. if ( 'U' === $format ) {
  168. $date = $timestamp;
  169. } elseif ( $gmt && false === $timestamp_with_offset ) { // Current time in UTC.
  170. $date = wp_date( $format, null, new DateTimeZone( 'UTC' ) );
  171. } elseif ( false === $timestamp_with_offset ) { // Current time in site's timezone.
  172. $date = wp_date( $format );
  173. } else {
  174. /*
  175. * Timestamp with offset is typically produced by a UTC `strtotime()` call on an input without timezone.
  176. * This is the best attempt to reverse that operation into a local time to use.
  177. */
  178. $local_time = gmdate( 'Y-m-d H:i:s', $timestamp );
  179. $timezone = wp_timezone();
  180. $datetime = date_create( $local_time, $timezone );
  181. $date = wp_date( $format, $datetime->getTimestamp(), $timezone );
  182. }
  183. /**
  184. * Filters the date formatted based on the locale.
  185. *
  186. * @since 2.8.0
  187. *
  188. * @param string $date Formatted date string.
  189. * @param string $format Format to display the date.
  190. * @param int $timestamp A sum of Unix timestamp and timezone offset in seconds.
  191. * Might be without offset if input omitted timestamp but requested GMT.
  192. * @param bool $gmt Whether to use GMT timezone. Only applies if timestamp was not provided.
  193. * Default false.
  194. */
  195. $date = apply_filters( 'date_i18n', $date, $format, $timestamp, $gmt );
  196. return $date;
  197. }
  198. /**
  199. * Retrieves the date, in localized format.
  200. *
  201. * This is a newer function, intended to replace `date_i18n()` without legacy quirks in it.
  202. *
  203. * Note that, unlike `date_i18n()`, this function accepts a true Unix timestamp, not summed
  204. * with timezone offset.
  205. *
  206. * @since 5.3.0
  207. *
  208. * @global WP_Locale $wp_locale WordPress date and time locale object.
  209. *
  210. * @param string $format PHP date format.
  211. * @param int $timestamp Optional. Unix timestamp. Defaults to current time.
  212. * @param DateTimeZone $timezone Optional. Timezone to output result in. Defaults to timezone
  213. * from site settings.
  214. * @return string|false The date, translated if locale specifies it. False on invalid timestamp input.
  215. */
  216. function wp_date( $format, $timestamp = null, $timezone = null ) {
  217. global $wp_locale;
  218. if ( null === $timestamp ) {
  219. $timestamp = time();
  220. } elseif ( ! is_numeric( $timestamp ) ) {
  221. return false;
  222. }
  223. if ( ! $timezone ) {
  224. $timezone = wp_timezone();
  225. }
  226. $datetime = date_create( '@' . $timestamp );
  227. $datetime->setTimezone( $timezone );
  228. if ( empty( $wp_locale->month ) || empty( $wp_locale->weekday ) ) {
  229. $date = $datetime->format( $format );
  230. } else {
  231. // We need to unpack shorthand `r` format because it has parts that might be localized.
  232. $format = preg_replace( '/(?<!\\\\)r/', DATE_RFC2822, $format );
  233. $new_format = '';
  234. $format_length = strlen( $format );
  235. $month = $wp_locale->get_month( $datetime->format( 'm' ) );
  236. $weekday = $wp_locale->get_weekday( $datetime->format( 'w' ) );
  237. for ( $i = 0; $i < $format_length; $i ++ ) {
  238. switch ( $format[ $i ] ) {
  239. case 'D':
  240. $new_format .= addcslashes( $wp_locale->get_weekday_abbrev( $weekday ), '\\A..Za..z' );
  241. break;
  242. case 'F':
  243. $new_format .= addcslashes( $month, '\\A..Za..z' );
  244. break;
  245. case 'l':
  246. $new_format .= addcslashes( $weekday, '\\A..Za..z' );
  247. break;
  248. case 'M':
  249. $new_format .= addcslashes( $wp_locale->get_month_abbrev( $month ), '\\A..Za..z' );
  250. break;
  251. case 'a':
  252. $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'a' ) ), '\\A..Za..z' );
  253. break;
  254. case 'A':
  255. $new_format .= addcslashes( $wp_locale->get_meridiem( $datetime->format( 'A' ) ), '\\A..Za..z' );
  256. break;
  257. case '\\':
  258. $new_format .= $format[ $i ];
  259. // If character follows a slash, we add it without translating.
  260. if ( $i < $format_length ) {
  261. $new_format .= $format[ ++$i ];
  262. }
  263. break;
  264. default:
  265. $new_format .= $format[ $i ];
  266. break;
  267. }
  268. }
  269. $date = $datetime->format( $new_format );
  270. $date = wp_maybe_decline_date( $date, $format );
  271. }
  272. /**
  273. * Filters the date formatted based on the locale.
  274. *
  275. * @since 5.3.0
  276. *
  277. * @param string $date Formatted date string.
  278. * @param string $format Format to display the date.
  279. * @param int $timestamp Unix timestamp.
  280. * @param DateTimeZone $timezone Timezone.
  281. */
  282. $date = apply_filters( 'wp_date', $date, $format, $timestamp, $timezone );
  283. return $date;
  284. }
  285. /**
  286. * Determines if the date should be declined.
  287. *
  288. * If the locale specifies that month names require a genitive case in certain
  289. * formats (like 'j F Y'), the month name will be replaced with a correct form.
  290. *
  291. * @since 4.4.0
  292. * @since 5.4.0 The `$format` parameter was added.
  293. *
  294. * @global WP_Locale $wp_locale WordPress date and time locale object.
  295. *
  296. * @param string $date Formatted date string.
  297. * @param string $format Optional. Date format to check. Default empty string.
  298. * @return string The date, declined if locale specifies it.
  299. */
  300. function wp_maybe_decline_date( $date, $format = '' ) {
  301. global $wp_locale;
  302. // i18n functions are not available in SHORTINIT mode.
  303. if ( ! function_exists( '_x' ) ) {
  304. return $date;
  305. }
  306. /*
  307. * translators: If months in your language require a genitive case,
  308. * translate this to 'on'. Do not translate into your own language.
  309. */
  310. if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
  311. $months = $wp_locale->month;
  312. $months_genitive = $wp_locale->month_genitive;
  313. /*
  314. * Match a format like 'j F Y' or 'j. F' (day of the month, followed by month name)
  315. * and decline the month.
  316. */
  317. if ( $format ) {
  318. $decline = preg_match( '#[dj]\.? F#', $format );
  319. } else {
  320. // If the format is not passed, try to guess it from the date string.
  321. $decline = preg_match( '#\b\d{1,2}\.? [^\d ]+\b#u', $date );
  322. }
  323. if ( $decline ) {
  324. foreach ( $months as $key => $month ) {
  325. $months[ $key ] = '# ' . preg_quote( $month, '#' ) . '\b#u';
  326. }
  327. foreach ( $months_genitive as $key => $month ) {
  328. $months_genitive[ $key ] = ' ' . $month;
  329. }
  330. $date = preg_replace( $months, $months_genitive, $date );
  331. }
  332. /*
  333. * Match a format like 'F jS' or 'F j' (month name, followed by day with an optional ordinal suffix)
  334. * and change it to declined 'j F'.
  335. */
  336. if ( $format ) {
  337. $decline = preg_match( '#F [dj]#', $format );
  338. } else {
  339. // If the format is not passed, try to guess it from the date string.
  340. $decline = preg_match( '#\b[^\d ]+ \d{1,2}(st|nd|rd|th)?\b#u', trim( $date ) );
  341. }
  342. if ( $decline ) {
  343. foreach ( $months as $key => $month ) {
  344. $months[ $key ] = '#\b' . preg_quote( $month, '#' ) . ' (\d{1,2})(st|nd|rd|th)?([-–]\d{1,2})?(st|nd|rd|th)?\b#u';
  345. }
  346. foreach ( $months_genitive as $key => $month ) {
  347. $months_genitive[ $key ] = '$1$3 ' . $month;
  348. }
  349. $date = preg_replace( $months, $months_genitive, $date );
  350. }
  351. }
  352. // Used for locale-specific rules.
  353. $locale = get_locale();
  354. if ( 'ca' === $locale ) {
  355. // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
  356. $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
  357. }
  358. return $date;
  359. }
  360. /**
  361. * Convert float number to format based on the locale.
  362. *
  363. * @since 2.3.0
  364. *
  365. * @global WP_Locale $wp_locale WordPress date and time locale object.
  366. *
  367. * @param float $number The number to convert based on locale.
  368. * @param int $decimals Optional. Precision of the number of decimal places. Default 0.
  369. * @return string Converted number in string format.
  370. */
  371. function number_format_i18n( $number, $decimals = 0 ) {
  372. global $wp_locale;
  373. if ( isset( $wp_locale ) ) {
  374. $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
  375. } else {
  376. $formatted = number_format( $number, absint( $decimals ) );
  377. }
  378. /**
  379. * Filters the number formatted based on the locale.
  380. *
  381. * @since 2.8.0
  382. * @since 4.9.0 The `$number` and `$decimals` parameters were added.
  383. *
  384. * @param string $formatted Converted number in string format.
  385. * @param float $number The number to convert based on locale.
  386. * @param int $decimals Precision of the number of decimal places.
  387. */
  388. return apply_filters( 'number_format_i18n', $formatted, $number, $decimals );
  389. }
  390. /**
  391. * Convert number of bytes largest unit bytes will fit into.
  392. *
  393. * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
  394. * number of bytes to human readable number by taking the number of that unit
  395. * that the bytes will go into it. Supports TB value.
  396. *
  397. * Please note that integers in PHP are limited to 32 bits, unless they are on
  398. * 64 bit architecture, then they have 64 bit size. If you need to place the
  399. * larger size then what PHP integer type will hold, then use a string. It will
  400. * be converted to a double, which should always have 64 bit length.
  401. *
  402. * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
  403. *
  404. * @since 2.3.0
  405. *
  406. * @param int|string $bytes Number of bytes. Note max integer size for integers.
  407. * @param int $decimals Optional. Precision of number of decimal places. Default 0.
  408. * @return string|false Number string on success, false on failure.
  409. */
  410. function size_format( $bytes, $decimals = 0 ) {
  411. $quant = array(
  412. /* translators: Unit symbol for terabyte. */
  413. _x( 'TB', 'unit symbol' ) => TB_IN_BYTES,
  414. /* translators: Unit symbol for gigabyte. */
  415. _x( 'GB', 'unit symbol' ) => GB_IN_BYTES,
  416. /* translators: Unit symbol for megabyte. */
  417. _x( 'MB', 'unit symbol' ) => MB_IN_BYTES,
  418. /* translators: Unit symbol for kilobyte. */
  419. _x( 'KB', 'unit symbol' ) => KB_IN_BYTES,
  420. /* translators: Unit symbol for byte. */
  421. _x( 'B', 'unit symbol' ) => 1,
  422. );
  423. if ( 0 === $bytes ) {
  424. /* translators: Unit symbol for byte. */
  425. return number_format_i18n( 0, $decimals ) . ' ' . _x( 'B', 'unit symbol' );
  426. }
  427. foreach ( $quant as $unit => $mag ) {
  428. if ( (float) $bytes >= $mag ) {
  429. return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
  430. }
  431. }
  432. return false;
  433. }
  434. /**
  435. * Convert a duration to human readable format.
  436. *
  437. * @since 5.1.0
  438. *
  439. * @param string $duration Duration will be in string format (HH:ii:ss) OR (ii:ss),
  440. * with a possible prepended negative sign (-).
  441. * @return string|false A human readable duration string, false on failure.
  442. */
  443. function human_readable_duration( $duration = '' ) {
  444. if ( ( empty( $duration ) || ! is_string( $duration ) ) ) {
  445. return false;
  446. }
  447. $duration = trim( $duration );
  448. // Remove prepended negative sign.
  449. if ( '-' === substr( $duration, 0, 1 ) ) {
  450. $duration = substr( $duration, 1 );
  451. }
  452. // Extract duration parts.
  453. $duration_parts = array_reverse( explode( ':', $duration ) );
  454. $duration_count = count( $duration_parts );
  455. $hour = null;
  456. $minute = null;
  457. $second = null;
  458. if ( 3 === $duration_count ) {
  459. // Validate HH:ii:ss duration format.
  460. if ( ! ( (bool) preg_match( '/^([0-9]+):([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
  461. return false;
  462. }
  463. // Three parts: hours, minutes & seconds.
  464. list( $second, $minute, $hour ) = $duration_parts;
  465. } elseif ( 2 === $duration_count ) {
  466. // Validate ii:ss duration format.
  467. if ( ! ( (bool) preg_match( '/^([0-5]?[0-9]):([0-5]?[0-9])$/', $duration ) ) ) {
  468. return false;
  469. }
  470. // Two parts: minutes & seconds.
  471. list( $second, $minute ) = $duration_parts;
  472. } else {
  473. return false;
  474. }
  475. $human_readable_duration = array();
  476. // Add the hour part to the string.
  477. if ( is_numeric( $hour ) ) {
  478. /* translators: %s: Time duration in hour or hours. */
  479. $human_readable_duration[] = sprintf( _n( '%s hour', '%s hours', $hour ), (int) $hour );
  480. }
  481. // Add the minute part to the string.
  482. if ( is_numeric( $minute ) ) {
  483. /* translators: %s: Time duration in minute or minutes. */
  484. $human_readable_duration[] = sprintf( _n( '%s minute', '%s minutes', $minute ), (int) $minute );
  485. }
  486. // Add the second part to the string.
  487. if ( is_numeric( $second ) ) {
  488. /* translators: %s: Time duration in second or seconds. */
  489. $human_readable_duration[] = sprintf( _n( '%s second', '%s seconds', $second ), (int) $second );
  490. }
  491. return implode( ', ', $human_readable_duration );
  492. }
  493. /**
  494. * Get the week start and end from the datetime or date string from MySQL.
  495. *
  496. * @since 0.71
  497. *
  498. * @param string $mysqlstring Date or datetime field type from MySQL.
  499. * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
  500. * @return int[] {
  501. * Week start and end dates as Unix timestamps.
  502. *
  503. * @type int $start The week start date as a Unix timestamp.
  504. * @type int $end The week end date as a Unix timestamp.
  505. * }
  506. */
  507. function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
  508. // MySQL string year.
  509. $my = substr( $mysqlstring, 0, 4 );
  510. // MySQL string month.
  511. $mm = substr( $mysqlstring, 8, 2 );
  512. // MySQL string day.
  513. $md = substr( $mysqlstring, 5, 2 );
  514. // The timestamp for MySQL string day.
  515. $day = mktime( 0, 0, 0, $md, $mm, $my );
  516. // The day of the week from the timestamp.
  517. $weekday = gmdate( 'w', $day );
  518. if ( ! is_numeric( $start_of_week ) ) {
  519. $start_of_week = get_option( 'start_of_week' );
  520. }
  521. if ( $weekday < $start_of_week ) {
  522. $weekday += 7;
  523. }
  524. // The most recent week start day on or before $day.
  525. $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
  526. // $start + 1 week - 1 second.
  527. $end = $start + WEEK_IN_SECONDS - 1;
  528. return compact( 'start', 'end' );
  529. }
  530. /**
  531. * Serialize data, if needed.
  532. *
  533. * @since 2.0.5
  534. *
  535. * @param string|array|object $data Data that might be serialized.
  536. * @return mixed A scalar data.
  537. */
  538. function maybe_serialize( $data ) {
  539. if ( is_array( $data ) || is_object( $data ) ) {
  540. return serialize( $data );
  541. }
  542. /*
  543. * Double serialization is required for backward compatibility.
  544. * See https://core.trac.wordpress.org/ticket/12930
  545. * Also the world will end. See WP 3.6.1.
  546. */
  547. if ( is_serialized( $data, false ) ) {
  548. return serialize( $data );
  549. }
  550. return $data;
  551. }
  552. /**
  553. * Unserialize data only if it was serialized.
  554. *
  555. * @since 2.0.0
  556. *
  557. * @param string $data Data that might be unserialized.
  558. * @return mixed Unserialized data can be any type.
  559. */
  560. function maybe_unserialize( $data ) {
  561. if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
  562. return @unserialize( trim( $data ) );
  563. }
  564. return $data;
  565. }
  566. /**
  567. * Check value to find if it was serialized.
  568. *
  569. * If $data is not an string, then returned value will always be false.
  570. * Serialized data is always a string.
  571. *
  572. * @since 2.0.5
  573. *
  574. * @param string $data Value to check to see if was serialized.
  575. * @param bool $strict Optional. Whether to be strict about the end of the string. Default true.
  576. * @return bool False if not serialized and true if it was.
  577. */
  578. function is_serialized( $data, $strict = true ) {
  579. // If it isn't a string, it isn't serialized.
  580. if ( ! is_string( $data ) ) {
  581. return false;
  582. }
  583. $data = trim( $data );
  584. if ( 'N;' === $data ) {
  585. return true;
  586. }
  587. if ( strlen( $data ) < 4 ) {
  588. return false;
  589. }
  590. if ( ':' !== $data[1] ) {
  591. return false;
  592. }
  593. if ( $strict ) {
  594. $lastc = substr( $data, -1 );
  595. if ( ';' !== $lastc && '}' !== $lastc ) {
  596. return false;
  597. }
  598. } else {
  599. $semicolon = strpos( $data, ';' );
  600. $brace = strpos( $data, '}' );
  601. // Either ; or } must exist.
  602. if ( false === $semicolon && false === $brace ) {
  603. return false;
  604. }
  605. // But neither must be in the first X characters.
  606. if ( false !== $semicolon && $semicolon < 3 ) {
  607. return false;
  608. }
  609. if ( false !== $brace && $brace < 4 ) {
  610. return false;
  611. }
  612. }
  613. $token = $data[0];
  614. switch ( $token ) {
  615. case 's':
  616. if ( $strict ) {
  617. if ( '"' !== substr( $data, -2, 1 ) ) {
  618. return false;
  619. }
  620. } elseif ( false === strpos( $data, '"' ) ) {
  621. return false;
  622. }
  623. // Or else fall through.
  624. case 'a':
  625. case 'O':
  626. return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
  627. case 'b':
  628. case 'i':
  629. case 'd':
  630. $end = $strict ? '$' : '';
  631. return (bool) preg_match( "/^{$token}:[0-9.E+-]+;$end/", $data );
  632. }
  633. return false;
  634. }
  635. /**
  636. * Check whether serialized data is of string type.
  637. *
  638. * @since 2.0.5
  639. *
  640. * @param string $data Serialized data.
  641. * @return bool False if not a serialized string, true if it is.
  642. */
  643. function is_serialized_string( $data ) {
  644. // if it isn't a string, it isn't a serialized string.
  645. if ( ! is_string( $data ) ) {
  646. return false;
  647. }
  648. $data = trim( $data );
  649. if ( strlen( $data ) < 4 ) {
  650. return false;
  651. } elseif ( ':' !== $data[1] ) {
  652. return false;
  653. } elseif ( ';' !== substr( $data, -1 ) ) {
  654. return false;
  655. } elseif ( 's' !== $data[0] ) {
  656. return false;
  657. } elseif ( '"' !== substr( $data, -2, 1 ) ) {
  658. return false;
  659. } else {
  660. return true;
  661. }
  662. }
  663. /**
  664. * Retrieve post title from XMLRPC XML.
  665. *
  666. * If the title element is not part of the XML, then the default post title from
  667. * the $post_default_title will be used instead.
  668. *
  669. * @since 0.71
  670. *
  671. * @global string $post_default_title Default XML-RPC post title.
  672. *
  673. * @param string $content XMLRPC XML Request content
  674. * @return string Post title
  675. */
  676. function xmlrpc_getposttitle( $content ) {
  677. global $post_default_title;
  678. if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
  679. $post_title = $matchtitle[1];
  680. } else {
  681. $post_title = $post_default_title;
  682. }
  683. return $post_title;
  684. }
  685. /**
  686. * Retrieve the post category or categories from XMLRPC XML.
  687. *
  688. * If the category element is not found, then the default post category will be
  689. * used. The return type then would be what $post_default_category. If the
  690. * category is found, then it will always be an array.
  691. *
  692. * @since 0.71
  693. *
  694. * @global string $post_default_category Default XML-RPC post category.
  695. *
  696. * @param string $content XMLRPC XML Request content
  697. * @return string|array List of categories or category name.
  698. */
  699. function xmlrpc_getpostcategory( $content ) {
  700. global $post_default_category;
  701. if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
  702. $post_category = trim( $matchcat[1], ',' );
  703. $post_category = explode( ',', $post_category );
  704. } else {
  705. $post_category = $post_default_category;
  706. }
  707. return $post_category;
  708. }
  709. /**
  710. * XMLRPC XML content without title and category elements.
  711. *
  712. * @since 0.71
  713. *
  714. * @param string $content XML-RPC XML Request content.
  715. * @return string XMLRPC XML Request content without title and category elements.
  716. */
  717. function xmlrpc_removepostdata( $content ) {
  718. $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
  719. $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
  720. $content = trim( $content );
  721. return $content;
  722. }
  723. /**
  724. * Use RegEx to extract URLs from arbitrary content.
  725. *
  726. * @since 3.7.0
  727. *
  728. * @param string $content Content to extract URLs from.
  729. * @return string[] Array of URLs found in passed string.
  730. */
  731. function wp_extract_urls( $content ) {
  732. preg_match_all(
  733. "#([\"']?)("
  734. . '(?:([\w-]+:)?//?)'
  735. . '[^\s()<>]+'
  736. . '[.]'
  737. . '(?:'
  738. . '\([\w\d]+\)|'
  739. . '(?:'
  740. . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
  741. . '(?:[:]\d+)?/?'
  742. . ')+'
  743. . ')'
  744. . ")\\1#",
  745. $content,
  746. $post_links
  747. );
  748. $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
  749. return array_values( $post_links );
  750. }
  751. /**
  752. * Check content for video and audio links to add as enclosures.
  753. *
  754. * Will not add enclosures that have already been added and will
  755. * remove enclosures that are no longer in the post. This is called as
  756. * pingbacks and trackbacks.
  757. *
  758. * @since 1.5.0
  759. * @since 5.3.0 The `$content` parameter was made optional, and the `$post` parameter was
  760. * updated to accept a post ID or a WP_Post object.
  761. * @since 5.6.0 The `$content` parameter is no longer optional, but passing `null` to skip it
  762. * is still supported.
  763. *
  764. * @global wpdb $wpdb WordPress database abstraction object.
  765. *
  766. * @param string|null $content Post content. If `null`, the `post_content` field from `$post` is used.
  767. * @param int|WP_Post $post Post ID or post object.
  768. * @return void|false Void on success, false if the post is not found.
  769. */
  770. function do_enclose( $content, $post ) {
  771. global $wpdb;
  772. // @todo Tidy this code and make the debug code optional.
  773. include_once ABSPATH . WPINC . '/class-IXR.php';
  774. $post = get_post( $post );
  775. if ( ! $post ) {
  776. return false;
  777. }
  778. if ( null === $content ) {
  779. $content = $post->post_content;
  780. }
  781. $post_links = array();
  782. $pung = get_enclosed( $post->ID );
  783. $post_links_temp = wp_extract_urls( $content );
  784. foreach ( $pung as $link_test ) {
  785. // Link is no longer in post.
  786. if ( ! in_array( $link_test, $post_links_temp, true ) ) {
  787. $mids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $link_test ) . '%' ) );
  788. foreach ( $mids as $mid ) {
  789. delete_metadata_by_mid( 'post', $mid );
  790. }
  791. }
  792. }
  793. foreach ( (array) $post_links_temp as $link_test ) {
  794. // If we haven't pung it already.
  795. if ( ! in_array( $link_test, $pung, true ) ) {
  796. $test = parse_url( $link_test );
  797. if ( false === $test ) {
  798. continue;
  799. }
  800. if ( isset( $test['query'] ) ) {
  801. $post_links[] = $link_test;
  802. } elseif ( isset( $test['path'] ) && ( '/' !== $test['path'] ) && ( '' !== $test['path'] ) ) {
  803. $post_links[] = $link_test;
  804. }
  805. }
  806. }
  807. /**
  808. * Filters the list of enclosure links before querying the database.
  809. *
  810. * Allows for the addition and/or removal of potential enclosures to save
  811. * to postmeta before checking the database for existing enclosures.
  812. *
  813. * @since 4.4.0
  814. *
  815. * @param string[] $post_links An array of enclosure links.
  816. * @param int $post_ID Post ID.
  817. */
  818. $post_links = apply_filters( 'enclosure_links', $post_links, $post->ID );
  819. foreach ( (array) $post_links as $url ) {
  820. $url = strip_fragment_from_url( $url );
  821. if ( '' !== $url && ! $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE post_id = %d AND meta_key = 'enclosure' AND meta_value LIKE %s", $post->ID, $wpdb->esc_like( $url ) . '%' ) ) ) {
  822. $headers = wp_get_http_headers( $url );
  823. if ( $headers ) {
  824. $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
  825. $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
  826. $allowed_types = array( 'video', 'audio' );
  827. // Check to see if we can figure out the mime type from the extension.
  828. $url_parts = parse_url( $url );
  829. if ( false !== $url_parts && ! empty( $url_parts['path'] ) ) {
  830. $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
  831. if ( ! empty( $extension ) ) {
  832. foreach ( wp_get_mime_types() as $exts => $mime ) {
  833. if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
  834. $type = $mime;
  835. break;
  836. }
  837. }
  838. }
  839. }
  840. if ( in_array( substr( $type, 0, strpos( $type, '/' ) ), $allowed_types, true ) ) {
  841. add_post_meta( $post->ID, 'enclosure', "$url\n$len\n$mime\n" );
  842. }
  843. }
  844. }
  845. }
  846. }
  847. /**
  848. * Retrieve HTTP Headers from URL.
  849. *
  850. * @since 1.5.1
  851. *
  852. * @param string $url URL to retrieve HTTP headers from.
  853. * @param bool $deprecated Not Used.
  854. * @return string|false Headers on success, false on failure.
  855. */
  856. function wp_get_http_headers( $url, $deprecated = false ) {
  857. if ( ! empty( $deprecated ) ) {
  858. _deprecated_argument( __FUNCTION__, '2.7.0' );
  859. }
  860. $response = wp_safe_remote_head( $url );
  861. if ( is_wp_error( $response ) ) {
  862. return false;
  863. }
  864. return wp_remote_retrieve_headers( $response );
  865. }
  866. /**
  867. * Determines whether the publish date of the current post in the loop is different
  868. * from the publish date of the previous post in the loop.
  869. *
  870. * For more information on this and similar theme functions, check out
  871. * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  872. * Conditional Tags} article in the Theme Developer Handbook.
  873. *
  874. * @since 0.71
  875. *
  876. * @global string $currentday The day of the current post in the loop.
  877. * @global string $previousday The day of the previous post in the loop.
  878. *
  879. * @return int 1 when new day, 0 if not a new day.
  880. */
  881. function is_new_day() {
  882. global $currentday, $previousday;
  883. if ( $currentday !== $previousday ) {
  884. return 1;
  885. } else {
  886. return 0;
  887. }
  888. }
  889. /**
  890. * Build URL query based on an associative and, or indexed array.
  891. *
  892. * This is a convenient function for easily building url queries. It sets the
  893. * separator to '&' and uses _http_build_query() function.
  894. *
  895. * @since 2.3.0
  896. *
  897. * @see _http_build_query() Used to build the query
  898. * @link https://www.php.net/manual/en/function.http-build-query.php for more on what
  899. * http_build_query() does.
  900. *
  901. * @param array $data URL-encode key/value pairs.
  902. * @return string URL-encoded string.
  903. */
  904. function build_query( $data ) {
  905. return _http_build_query( $data, null, '&', '', false );
  906. }
  907. /**
  908. * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
  909. *
  910. * @since 3.2.0
  911. * @access private
  912. *
  913. * @see https://www.php.net/manual/en/function.http-build-query.php
  914. *
  915. * @param array|object $data An array or object of data. Converted to array.
  916. * @param string $prefix Optional. Numeric index. If set, start parameter numbering with it.
  917. * Default null.
  918. * @param string $sep Optional. Argument separator; defaults to 'arg_separator.output'.
  919. * Default null.
  920. * @param string $key Optional. Used to prefix key name. Default empty.
  921. * @param bool $urlencode Optional. Whether to use urlencode() in the result. Default true.
  922. * @return string The query string.
  923. */
  924. function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
  925. $ret = array();
  926. foreach ( (array) $data as $k => $v ) {
  927. if ( $urlencode ) {
  928. $k = urlencode( $k );
  929. }
  930. if ( is_int( $k ) && null != $prefix ) {
  931. $k = $prefix . $k;
  932. }
  933. if ( ! empty( $key ) ) {
  934. $k = $key . '%5B' . $k . '%5D';
  935. }
  936. if ( null === $v ) {
  937. continue;
  938. } elseif ( false === $v ) {
  939. $v = '0';
  940. }
  941. if ( is_array( $v ) || is_object( $v ) ) {
  942. array_push( $ret, _http_build_query( $v, '', $sep, $k, $urlencode ) );
  943. } elseif ( $urlencode ) {
  944. array_push( $ret, $k . '=' . urlencode( $v ) );
  945. } else {
  946. array_push( $ret, $k . '=' . $v );
  947. }
  948. }
  949. if ( null === $sep ) {
  950. $sep = ini_get( 'arg_separator.output' );
  951. }
  952. return implode( $sep, $ret );
  953. }
  954. /**
  955. * Retrieves a modified URL query string.
  956. *
  957. * You can rebuild the URL and append query variables to the URL query by using this function.
  958. * There are two ways to use this function; either a single key and value, or an associative array.
  959. *
  960. * Using a single key and value:
  961. *
  962. * add_query_arg( 'key', 'value', 'http://example.com' );
  963. *
  964. * Using an associative array:
  965. *
  966. * add_query_arg( array(
  967. * 'key1' => 'value1',
  968. * 'key2' => 'value2',
  969. * ), 'http://example.com' );
  970. *
  971. * Omitting the URL from either use results in the current URL being used
  972. * (the value of `$_SERVER['REQUEST_URI']`).
  973. *
  974. * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
  975. *
  976. * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
  977. *
  978. * Important: The return value of add_query_arg() is not escaped by default. Output should be
  979. * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
  980. * (XSS) attacks.
  981. *
  982. * @since 1.5.0
  983. * @since 5.3.0 Formalized the existing and already documented parameters
  984. * by adding `...$args` to the function signature.
  985. *
  986. * @param string|array $key Either a query variable key, or an associative array of query variables.
  987. * @param string $value Optional. Either a query variable value, or a URL to act upon.
  988. * @param string $url Optional. A URL to act upon.
  989. * @return string New URL query string (unescaped).
  990. */
  991. function add_query_arg( ...$args ) {
  992. if ( is_array( $args[0] ) ) {
  993. if ( count( $args ) < 2 || false === $args[1] ) {
  994. $uri = $_SERVER['REQUEST_URI'];
  995. } else {
  996. $uri = $args[1];
  997. }
  998. } else {
  999. if ( count( $args ) < 3 || false === $args[2] ) {
  1000. $uri = $_SERVER['REQUEST_URI'];
  1001. } else {
  1002. $uri = $args[2];
  1003. }
  1004. }
  1005. $frag = strstr( $uri, '#' );
  1006. if ( $frag ) {
  1007. $uri = substr( $uri, 0, -strlen( $frag ) );
  1008. } else {
  1009. $frag = '';
  1010. }
  1011. if ( 0 === stripos( $uri, 'http://' ) ) {
  1012. $protocol = 'http://';
  1013. $uri = substr( $uri, 7 );
  1014. } elseif ( 0 === stripos( $uri, 'https://' ) ) {
  1015. $protocol = 'https://';
  1016. $uri = substr( $uri, 8 );
  1017. } else {
  1018. $protocol = '';
  1019. }
  1020. if ( strpos( $uri, '?' ) !== false ) {
  1021. list( $base, $query ) = explode( '?', $uri, 2 );
  1022. $base .= '?';
  1023. } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
  1024. $base = $uri . '?';
  1025. $query = '';
  1026. } else {
  1027. $base = '';
  1028. $query = $uri;
  1029. }
  1030. wp_parse_str( $query, $qs );
  1031. $qs = urlencode_deep( $qs ); // This re-URL-encodes things that were already in the query string.
  1032. if ( is_array( $args[0] ) ) {
  1033. foreach ( $args[0] as $k => $v ) {
  1034. $qs[ $k ] = $v;
  1035. }
  1036. } else {
  1037. $qs[ $args[0] ] = $args[1];
  1038. }
  1039. foreach ( $qs as $k => $v ) {
  1040. if ( false === $v ) {
  1041. unset( $qs[ $k ] );
  1042. }
  1043. }
  1044. $ret = build_query( $qs );
  1045. $ret = trim( $ret, '?' );
  1046. $ret = preg_replace( '#=(&|$)#', '$1', $ret );
  1047. $ret = $protocol . $base . $ret . $frag;
  1048. $ret = rtrim( $ret, '?' );
  1049. $ret = str_replace( '?#', '#', $ret );
  1050. return $ret;
  1051. }
  1052. /**
  1053. * Removes an item or items from a query string.
  1054. *
  1055. * @since 1.5.0
  1056. *
  1057. * @param string|string[] $key Query key or keys to remove.
  1058. * @param false|string $query Optional. When false uses the current URL. Default false.
  1059. * @return string New URL query string.
  1060. */
  1061. function remove_query_arg( $key, $query = false ) {
  1062. if ( is_array( $key ) ) { // Removing multiple keys.
  1063. foreach ( $key as $k ) {
  1064. $query = add_query_arg( $k, false, $query );
  1065. }
  1066. return $query;
  1067. }
  1068. return add_query_arg( $key, false, $query );
  1069. }
  1070. /**
  1071. * Returns an array of single-use query variable names that can be removed from a URL.
  1072. *
  1073. * @since 4.4.0
  1074. *
  1075. * @return string[] An array of query variable names to remove from the URL.
  1076. */
  1077. function wp_removable_query_args() {
  1078. $removable_query_args = array(
  1079. 'activate',
  1080. 'activated',
  1081. 'admin_email_remind_later',
  1082. 'approved',
  1083. 'core-major-auto-updates-saved',
  1084. 'deactivate',
  1085. 'delete_count',
  1086. 'deleted',
  1087. 'disabled',
  1088. 'doing_wp_cron',
  1089. 'enabled',
  1090. 'error',
  1091. 'hotkeys_highlight_first',
  1092. 'hotkeys_highlight_last',
  1093. 'ids',
  1094. 'locked',
  1095. 'message',
  1096. 'same',
  1097. 'saved',
  1098. 'settings-updated',
  1099. 'skipped',
  1100. 'spammed',
  1101. 'trashed',
  1102. 'unspammed',
  1103. 'untrashed',
  1104. 'update',
  1105. 'updated',
  1106. 'wp-post-new-reload',
  1107. );
  1108. /**
  1109. * Filters the list of query variable names to remove.
  1110. *
  1111. * @since 4.2.0
  1112. *
  1113. * @param string[] $removable_query_args An array of query variable names to remove from a URL.
  1114. */
  1115. return apply_filters( 'removable_query_args', $removable_query_args );
  1116. }
  1117. /**
  1118. * Walks the array while sanitizing the contents.
  1119. *
  1120. * @since 0.71
  1121. * @since 5.5.0 Non-string values are left untouched.
  1122. *
  1123. * @param array $array Array to walk while sanitizing contents.
  1124. * @return array Sanitized $array.
  1125. */
  1126. function add_magic_quotes( $array ) {
  1127. foreach ( (array) $array as $k => $v ) {
  1128. if ( is_array( $v ) ) {
  1129. $array[ $k ] = add_magic_quotes( $v );
  1130. } elseif ( is_string( $v ) ) {
  1131. $array[ $k ] = addslashes( $v );
  1132. } else {
  1133. continue;
  1134. }
  1135. }
  1136. return $array;
  1137. }
  1138. /**
  1139. * HTTP request for URI to retrieve content.
  1140. *
  1141. * @since 1.5.1
  1142. *
  1143. * @see wp_safe_remote_get()
  1144. *
  1145. * @param string $uri URI/URL of web page to retrieve.
  1146. * @return string|false HTTP content. False on failure.
  1147. */
  1148. function wp_remote_fopen( $uri ) {
  1149. $parsed_url = parse_url( $uri );
  1150. if ( ! $parsed_url || ! is_array( $parsed_url ) ) {
  1151. return false;
  1152. }
  1153. $options = array();
  1154. $options['timeout'] = 10;
  1155. $response = wp_safe_remote_get( $uri, $options );
  1156. if ( is_wp_error( $response ) ) {
  1157. return false;
  1158. }
  1159. return wp_remote_retrieve_body( $response );
  1160. }
  1161. /**
  1162. * Set up the WordPress query.
  1163. *
  1164. * @since 2.0.0
  1165. *
  1166. * @global WP $wp Current WordPress environment instance.
  1167. * @global WP_Query $wp_query WordPress Query object.
  1168. * @global WP_Query $wp_the_query Copy of the WordPress Query object.
  1169. *
  1170. * @param string|array $query_vars Default WP_Query arguments.
  1171. */
  1172. function wp( $query_vars = '' ) {
  1173. global $wp, $wp_query, $wp_the_query;
  1174. $wp->main( $query_vars );
  1175. if ( ! isset( $wp_the_query ) ) {
  1176. $wp_the_query = $wp_query;
  1177. }
  1178. }
  1179. /**
  1180. * Retrieve the description for the HTTP status.
  1181. *
  1182. * @since 2.3.0
  1183. * @since 3.9.0 Added status codes 418, 428, 429, 431, and 511.
  1184. * @since 4.5.0 Added status codes 308, 421, and 451.
  1185. * @since 5.1.0 Added status code 103.
  1186. *
  1187. * @global array $wp_header_to_desc
  1188. *
  1189. * @param int $code HTTP status code.
  1190. * @return string Status description if found, an empty string otherwise.
  1191. */
  1192. function get_status_header_desc( $code ) {
  1193. global $wp_header_to_desc;
  1194. $code = absint( $code );
  1195. if ( ! isset( $wp_header_to_desc ) ) {
  1196. $wp_header_to_desc = array(
  1197. 100 => 'Continue',
  1198. 101 => 'Switching Protocols',
  1199. 102 => 'Processing',
  1200. 103 => 'Early Hints',
  1201. 200 => 'OK',
  1202. 201 => 'Created',
  1203. 202 => 'Accepted',
  1204. 203 => 'Non-Authoritative Information',
  1205. 204 => 'No Content',
  1206. 205 => 'Reset Content',
  1207. 206 => 'Partial Content',
  1208. 207 => 'Multi-Status',
  1209. 226 => 'IM Used',
  1210. 300 => 'Multiple Choices',
  1211. 301 => 'Moved Permanently',
  1212. 302 => 'Found',
  1213. 303 => 'See Other',
  1214. 304 => 'Not Modified',
  1215. 305 => 'Use Proxy',
  1216. 306 => 'Reserved',
  1217. 307 => 'Temporary Redirect',
  1218. 308 => 'Permanent Redirect',
  1219. 400 => 'Bad Request',
  1220. 401 => 'Unauthorized',
  1221. 402 => 'Payment Required',
  1222. 403 => 'Forbidden',
  1223. 404 => 'Not Found',
  1224. 405 => 'Method Not Allowed',
  1225. 406 => 'Not Acceptable',
  1226. 407 => 'Proxy Authentication Required',
  1227. 408 => 'Request Timeout',
  1228. 409 => 'Conflict',
  1229. 410 => 'Gone',
  1230. 411 => 'Length Required',
  1231. 412 => 'Precondition Failed',
  1232. 413 => 'Request Entity Too Large',
  1233. 414 => 'Request-URI Too Long',
  1234. 415 => 'Unsupported Media Type',
  1235. 416 => 'Requested Range Not Satisfiable',
  1236. 417 => 'Expectation Failed',
  1237. 418 => 'I\'m a teapot',
  1238. 421 => 'Misdirected Request',
  1239. 422 => 'Unprocessable Entity',
  1240. 423 => 'Locked',
  1241. 424 => 'Failed Dependency',
  1242. 426 => 'Upgrade Required',
  1243. 428 => 'Precondition Required',
  1244. 429 => 'Too Many Requests',
  1245. 431 => 'Request Header Fields Too Large',
  1246. 451 => 'Unavailable For Legal Reasons',
  1247. 500 => 'Internal Server Error',
  1248. 501 => 'Not Implemented',
  1249. 502 => 'Bad Gateway',
  1250. 503 => 'Service Unavailable',
  1251. 504 => 'Gateway Timeout',
  1252. 505 => 'HTTP Version Not Supported',
  1253. 506 => 'Variant Also Negotiates',
  1254. 507 => 'Insufficient Storage',
  1255. 510 => 'Not Extended',
  1256. 511 => 'Network Authentication Required',
  1257. );
  1258. }
  1259. if ( isset( $wp_header_to_desc[ $code ] ) ) {
  1260. return $wp_header_to_desc[ $code ];
  1261. } else {
  1262. return '';
  1263. }
  1264. }
  1265. /**
  1266. * Set HTTP status header.
  1267. *
  1268. * @since 2.0.0
  1269. * @since 4.4.0 Added the `$description` parameter.
  1270. *
  1271. * @see get_status_header_desc()
  1272. *
  1273. * @param int $code HTTP status code.
  1274. * @param string $description Optional. A custom description for the HTTP status.
  1275. */
  1276. function status_header( $code, $description = '' ) {
  1277. if ( ! $description ) {
  1278. $description = get_status_header_desc( $code );
  1279. }
  1280. if ( empty( $description ) ) {
  1281. return;
  1282. }
  1283. $protocol = wp_get_server_protocol();
  1284. $status_header = "$protocol $code $description";
  1285. if ( function_exists( 'apply_filters' ) ) {
  1286. /**
  1287. * Filters an HTTP status header.
  1288. *
  1289. * @since 2.2.0
  1290. *
  1291. * @param string $status_header HTTP status header.
  1292. * @param int $code HTTP status code.
  1293. * @param string $description Description for the status code.
  1294. * @param string $protocol Server protocol.
  1295. */
  1296. $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
  1297. }
  1298. if ( ! headers_sent() ) {
  1299. header( $status_header, true, $code );
  1300. }
  1301. }
  1302. /**
  1303. * Get the header information to prevent caching.
  1304. *
  1305. * The several different headers cover the different ways cache prevention
  1306. * is handled by different browsers
  1307. *
  1308. * @since 2.8.0
  1309. *
  1310. * @return array The associative array of header names and field values.
  1311. */
  1312. function wp_get_nocache_headers() {
  1313. $headers = array(
  1314. 'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
  1315. 'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
  1316. );
  1317. if ( function_exists( 'apply_filters' ) ) {
  1318. /**
  1319. * Filters the cache-controlling headers.
  1320. *
  1321. * @since 2.8.0
  1322. *
  1323. * @see wp_get_nocache_headers()
  1324. *
  1325. * @param array $headers {
  1326. * Header names and field values.
  1327. *
  1328. * @type string $Expires Expires header.
  1329. * @type string $Cache-Control Cache-Control header.
  1330. * }
  1331. */
  1332. $headers = (array) apply_filters( 'nocache_headers', $headers );
  1333. }
  1334. $headers['Last-Modified'] = false;
  1335. return $headers;
  1336. }
  1337. /**
  1338. * Set the headers to prevent caching for the different browsers.
  1339. *
  1340. * Different browsers support different nocache headers, so several
  1341. * headers must be sent so that all of them get the point that no
  1342. * caching should occur.
  1343. *
  1344. * @since 2.0.0
  1345. *
  1346. * @see wp_get_nocache_headers()
  1347. */
  1348. function nocache_headers() {
  1349. if ( headers_sent() ) {
  1350. return;
  1351. }
  1352. $headers = wp_get_nocache_headers();
  1353. unset( $headers['Last-Modified'] );
  1354. header_remove( 'Last-Modified' );
  1355. foreach ( $headers as $name => $field_value ) {
  1356. header( "{$name}: {$field_value}" );
  1357. }
  1358. }
  1359. /**
  1360. * Set the headers for caching for 10 days with JavaScript content type.
  1361. *
  1362. * @since 2.1.0
  1363. */
  1364. function cache_javascript_headers() {
  1365. $expiresOffset = 10 * DAY_IN_SECONDS;
  1366. header( 'Content-Type: text/javascript; charset=' . get_bloginfo( 'charset' ) );
  1367. header( 'Vary: Accept-Encoding' ); // Handle proxies.
  1368. header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + $expiresOffset ) . ' GMT' );
  1369. }
  1370. /**
  1371. * Retrieve the number of database queries during the WordPress execution.
  1372. *
  1373. * @since 2.0.0
  1374. *
  1375. * @global wpdb $wpdb WordPress database abstraction object.
  1376. *
  1377. * @return int Number of database queries.
  1378. */
  1379. function get_num_queries() {
  1380. global $wpdb;
  1381. return $wpdb->num_queries;
  1382. }
  1383. /**
  1384. * Whether input is yes or no.
  1385. *
  1386. * Must be 'y' to be true.
  1387. *
  1388. * @since 1.0.0
  1389. *
  1390. * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
  1391. * @return bool True if 'y', false on anything else.
  1392. */
  1393. function bool_from_yn( $yn ) {
  1394. return ( 'y' === strtolower( $yn ) );
  1395. }
  1396. /**
  1397. * Load the feed template from the use of an action hook.
  1398. *
  1399. * If the feed action does not have a hook, then the function will die with a
  1400. * message telling the visitor that the feed is not valid.
  1401. *
  1402. * It is better to only have one hook for each feed.
  1403. *
  1404. * @since 2.1.0
  1405. *
  1406. * @global WP_Query $wp_query WordPress Query object.
  1407. */
  1408. function do_feed() {
  1409. global $wp_query;
  1410. $feed = get_query_var( 'feed' );
  1411. // Remove the pad, if present.
  1412. $feed = preg_replace( '/^_+/', '', $feed );
  1413. if ( '' === $feed || 'feed' === $feed ) {
  1414. $feed = get_default_feed();
  1415. }
  1416. if ( ! has_action( "do_feed_{$feed}" ) ) {
  1417. wp_die( __( 'Error: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
  1418. }
  1419. /**
  1420. * Fires once the given feed is loaded.
  1421. *
  1422. * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
  1423. *
  1424. * Possible hook names include:
  1425. *
  1426. * - `do_feed_atom`
  1427. * - `do_feed_rdf`
  1428. * - `do_feed_rss`
  1429. * - `do_feed_rss2`
  1430. *
  1431. * @since 2.1.0
  1432. * @since 4.4.0 The `$feed` parameter was added.
  1433. *
  1434. * @param bool $is_comment_feed Whether the feed is a comment feed.
  1435. * @param string $feed The feed name.
  1436. */
  1437. do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
  1438. }
  1439. /**
  1440. * Load the RDF RSS 0.91 Feed template.
  1441. *
  1442. * @since 2.1.0
  1443. *
  1444. * @see load_template()
  1445. */
  1446. function do_feed_rdf() {
  1447. load_template( ABSPATH . WPINC . '/feed-rdf.php' );
  1448. }
  1449. /**
  1450. * Load the RSS 1.0 Feed Template.
  1451. *
  1452. * @since 2.1.0
  1453. *
  1454. * @see load_template()
  1455. */
  1456. function do_feed_rss() {
  1457. load_template( ABSPATH . WPINC . '/feed-rss.php' );
  1458. }
  1459. /**
  1460. * Load either the RSS2 comment feed or the RSS2 posts feed.
  1461. *
  1462. * @since 2.1.0
  1463. *
  1464. * @see load_template()
  1465. *
  1466. * @param bool $for_comments True for the comment feed, false for normal feed.
  1467. */
  1468. function do_feed_rss2( $for_comments ) {
  1469. if ( $for_comments ) {
  1470. load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
  1471. } else {
  1472. load_template( ABSPATH . WPINC . '/feed-rss2.php' );
  1473. }
  1474. }
  1475. /**
  1476. * Load either Atom comment feed or Atom posts feed.
  1477. *
  1478. * @since 2.1.0
  1479. *
  1480. * @see load_template()
  1481. *
  1482. * @param bool $for_comments True for the comment feed, false for normal feed.
  1483. */
  1484. function do_feed_atom( $for_comments ) {
  1485. if ( $for_comments ) {
  1486. load_template( ABSPATH . WPINC . '/feed-atom-comments.php' );
  1487. } else {
  1488. load_template( ABSPATH . WPINC . '/feed-atom.php' );
  1489. }
  1490. }
  1491. /**
  1492. * Displays the default robots.txt file content.
  1493. *
  1494. * @since 2.1.0
  1495. * @since 5.3.0 Remove the "Disallow: /" output if search engine visiblity is
  1496. * discouraged in favor of robots meta HTML tag via wp_robots_no_robots()
  1497. * filter callback.
  1498. */
  1499. function do_robots() {
  1500. header( 'Content-Type: text/plain; charset=utf-8' );
  1501. /**
  1502. * Fires when displaying the robots.txt file.
  1503. *
  1504. * @since 2.1.0
  1505. */
  1506. do_action( 'do_robotstxt' );
  1507. $output = "User-agent: *\n";
  1508. $public = get_option( 'blog_public' );
  1509. $site_url = parse_url( site_url() );
  1510. $path = ( ! empty( $site_url['path'] ) ) ? $site_url['path'] : '';
  1511. $output .= "Disallow: $path/wp-admin/\n";
  1512. $output .= "Allow: $path/wp-admin/admin-ajax.php\n";
  1513. /**
  1514. * Filters the robots.txt output.
  1515. *
  1516. * @since 3.0.0
  1517. *
  1518. * @param string $output The robots.txt output.
  1519. * @param bool $public Whether the site is considered "public".
  1520. */
  1521. echo apply_filters( 'robots_txt', $output, $public );
  1522. }
  1523. /**
  1524. * Display the favicon.ico file content.
  1525. *
  1526. * @since 5.4.0
  1527. */
  1528. function do_favicon() {
  1529. /**
  1530. * Fires when serving the favicon.ico file.
  1531. *
  1532. * @since 5.4.0
  1533. */
  1534. do_action( 'do_faviconico' );
  1535. wp_redirect( get_site_icon_url( 32, includes_url( 'images/w-logo-blue-white-bg.png' ) ) );
  1536. exit;
  1537. }
  1538. /**
  1539. * Determines whether WordPress is already installed.
  1540. *
  1541. * The cache will be checked first. If you have a cache plugin, which saves
  1542. * the cache values, then this will work. If you use the default WordPress
  1543. * cache, and the database goes away, then you might have problems.
  1544. *
  1545. * Checks for the 'siteurl' option for whether WordPress is installed.
  1546. *
  1547. * For more information on this and similar theme functions, check out
  1548. * the {@link https://developer.wordpress.org/themes/basics/conditional-tags/
  1549. * Conditional Tags} article in the Theme Developer Handbook.
  1550. *
  1551. * @since 2.1.0
  1552. *
  1553. * @global wpdb $wpdb WordPress database abstraction object.
  1554. *
  1555. * @return bool Whether the site is already installed.
  1556. */
  1557. function is_blog_installed() {
  1558. global $wpdb;
  1559. /*
  1560. * Check cache first. If options table goes away and we have true
  1561. * cached, oh well.
  1562. */
  1563. if ( wp_cache_get( 'is_blog_installed' ) ) {
  1564. return true;
  1565. }
  1566. $suppress = $wpdb->suppress_errors();
  1567. if ( ! wp_installing() ) {
  1568. $alloptions = wp_load_alloptions();
  1569. }
  1570. // If siteurl is not set to autoload, check it specifically.
  1571. if ( ! isset( $alloptions['siteurl'] ) ) {
  1572. $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
  1573. } else {
  1574. $installed = $alloptions['siteurl'];
  1575. }
  1576. $wpdb->suppress_errors( $suppress );
  1577. $installed = ! empty( $installed );
  1578. wp_cache_set( 'is_blog_installed', $installed );
  1579. if ( $installed ) {
  1580. return true;
  1581. }
  1582. // If visiting repair.php, return true and let it take over.
  1583. if ( defined( 'WP_REPAIRING' ) ) {
  1584. return true;
  1585. }
  1586. $suppress = $wpdb->suppress_errors();
  1587. /*
  1588. * Loop…

Large files files are truncated, but you can click here to view the full file