[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

title

Body

[close]

/wp-includes/ -> functions.php (source)

   1  <?php
   2  /**
   3   * Main WordPress API
   4   *
   5   * @package WordPress
   6   */
   7  
   8  require ( ABSPATH . WPINC . '/option.php' );
   9  
  10  /**
  11   * Convert given date string into a different format.
  12   *
  13   * $format should be either a PHP date format string, e.g. 'U' for a Unix
  14   * timestamp, or 'G' for a Unix timestamp assuming that $date is GMT.
  15   *
  16   * If $translate is true then the given date and format string will
  17   * be passed to date_i18n() for translation.
  18   *
  19   * @since 0.71
  20   *
  21   * @param string $format    Format of the date to return.
  22   * @param string $date      Date string to convert.
  23   * @param bool   $translate Whether the return date should be translated. Default true.
  24   * @return string|int|bool Formatted date string or Unix timestamp. False if $date is empty.
  25   */
  26  function mysql2date( $format, $date, $translate = true ) {
  27      if ( empty( $date ) )
  28          return false;
  29  
  30      if ( 'G' == $format )
  31          return strtotime( $date . ' +0000' );
  32  
  33      $i = strtotime( $date );
  34  
  35      if ( 'U' == $format )
  36          return $i;
  37  
  38      if ( $translate )
  39          return date_i18n( $format, $i );
  40      else
  41          return date( $format, $i );
  42  }
  43  
  44  /**
  45   * Retrieve the current time based on specified type.
  46   *
  47   * The 'mysql' type will return the time in the format for MySQL DATETIME field.
  48   * The 'timestamp' type will return the current timestamp.
  49   * Other strings will be interpreted as PHP date formats (e.g. 'Y-m-d').
  50   *
  51   * If $gmt is set to either '1' or 'true', then both types will use GMT time.
  52   * if $gmt is false, the output is adjusted with the GMT offset in the WordPress option.
  53   *
  54   * @since 1.0.0
  55   *
  56   * @param string   $type Type of time to retrieve. Accepts 'mysql', 'timestamp', or PHP date
  57   *                       format string (e.g. 'Y-m-d').
  58   * @param int|bool $gmt  Optional. Whether to use GMT timezone. Default false.
  59   * @return int|string Integer if $type is 'timestamp', string otherwise.
  60   */
  61  function current_time( $type, $gmt = 0 ) {
  62      switch ( $type ) {
  63          case 'mysql':
  64              return ( $gmt ) ? gmdate( 'Y-m-d H:i:s' ) : gmdate( 'Y-m-d H:i:s', ( time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) ) );
  65          case 'timestamp':
  66              return ( $gmt ) ? time() : time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS );
  67          default:
  68              return ( $gmt ) ? date( $type ) : date( $type, time() + ( get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ) );
  69      }
  70  }
  71  
  72  /**
  73   * Retrieve the date in localized format, based on timestamp.
  74   *
  75   * If the locale specifies the locale month and weekday, then the locale will
  76   * take over the format for the date. If it isn't, then the date format string
  77   * will be used instead.
  78   *
  79   * @since 0.71
  80   *
  81   * @global WP_Locale $wp_locale
  82   *
  83   * @param string   $dateformatstring Format to display the date.
  84   * @param bool|int $unixtimestamp    Optional. Unix timestamp. Default false.
  85   * @param bool     $gmt              Optional. Whether to use GMT timezone. Default false.
  86   *
  87   * @return string The date, translated if locale specifies it.
  88   */
  89  function date_i18n( $dateformatstring, $unixtimestamp = false, $gmt = false ) {
  90      global $wp_locale;
  91      $i = $unixtimestamp;
  92  
  93      if ( false === $i ) {
  94          $i = current_time( 'timestamp', $gmt );
  95      }
  96  
  97      /*
  98       * Store original value for language with untypical grammars.
  99       * See https://core.trac.wordpress.org/ticket/9396
 100       */
 101      $req_format = $dateformatstring;
 102  
 103      if ( ( !empty( $wp_locale->month ) ) && ( !empty( $wp_locale->weekday ) ) ) {
 104          $datemonth = $wp_locale->get_month( date( 'm', $i ) );
 105          $datemonth_abbrev = $wp_locale->get_month_abbrev( $datemonth );
 106          $dateweekday = $wp_locale->get_weekday( date( 'w', $i ) );
 107          $dateweekday_abbrev = $wp_locale->get_weekday_abbrev( $dateweekday );
 108          $datemeridiem = $wp_locale->get_meridiem( date( 'a', $i ) );
 109          $datemeridiem_capital = $wp_locale->get_meridiem( date( 'A', $i ) );
 110          $dateformatstring = ' '.$dateformatstring;
 111          $dateformatstring = preg_replace( "/([^\\\])D/", "\\1" . backslashit( $dateweekday_abbrev ), $dateformatstring );
 112          $dateformatstring = preg_replace( "/([^\\\])F/", "\\1" . backslashit( $datemonth ), $dateformatstring );
 113          $dateformatstring = preg_replace( "/([^\\\])l/", "\\1" . backslashit( $dateweekday ), $dateformatstring );
 114          $dateformatstring = preg_replace( "/([^\\\])M/", "\\1" . backslashit( $datemonth_abbrev ), $dateformatstring );
 115          $dateformatstring = preg_replace( "/([^\\\])a/", "\\1" . backslashit( $datemeridiem ), $dateformatstring );
 116          $dateformatstring = preg_replace( "/([^\\\])A/", "\\1" . backslashit( $datemeridiem_capital ), $dateformatstring );
 117  
 118          $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
 119      }
 120      $timezone_formats = array( 'P', 'I', 'O', 'T', 'Z', 'e' );
 121      $timezone_formats_re = implode( '|', $timezone_formats );
 122      if ( preg_match( "/$timezone_formats_re/", $dateformatstring ) ) {
 123          $timezone_string = get_option( 'timezone_string' );
 124          if ( $timezone_string ) {
 125              $timezone_object = timezone_open( $timezone_string );
 126              $date_object = date_create( null, $timezone_object );
 127              foreach ( $timezone_formats as $timezone_format ) {
 128                  if ( false !== strpos( $dateformatstring, $timezone_format ) ) {
 129                      $formatted = date_format( $date_object, $timezone_format );
 130                      $dateformatstring = ' '.$dateformatstring;
 131                      $dateformatstring = preg_replace( "/([^\\\])$timezone_format/", "\\1" . backslashit( $formatted ), $dateformatstring );
 132                      $dateformatstring = substr( $dateformatstring, 1, strlen( $dateformatstring ) -1 );
 133                  }
 134              }
 135          }
 136      }
 137      $j = @date( $dateformatstring, $i );
 138  
 139      /**
 140       * Filters the date formatted based on the locale.
 141       *
 142       * @since 2.8.0
 143       *
 144       * @param string $j          Formatted date string.
 145       * @param string $req_format Format to display the date.
 146       * @param int    $i          Unix timestamp.
 147       * @param bool   $gmt        Whether to convert to GMT for time. Default false.
 148       */
 149      $j = apply_filters( 'date_i18n', $j, $req_format, $i, $gmt );
 150      return $j;
 151  }
 152  
 153  /**
 154   * Determines if the date should be declined.
 155   *
 156   * If the locale specifies that month names require a genitive case in certain
 157   * formats (like 'j F Y'), the month name will be replaced with a correct form.
 158   *
 159   * @since 4.4.0
 160   *
 161   * @global WP_Locale $wp_locale
 162   *
 163   * @param string $date Formatted date string.
 164   * @return string The date, declined if locale specifies it.
 165   */
 166  function wp_maybe_decline_date( $date ) {
 167      global $wp_locale;
 168  
 169      // i18n functions are not available in SHORTINIT mode
 170      if ( ! function_exists( '_x' ) ) {
 171          return $date;
 172      }
 173  
 174      /* translators: If months in your language require a genitive case,
 175       * translate this to 'on'. Do not translate into your own language.
 176       */
 177      if ( 'on' === _x( 'off', 'decline months names: on or off' ) ) {
 178          // Match a format like 'j F Y' or 'j. F'
 179          if ( @preg_match( '#^\d{1,2}\.? [^\d ]+#u', $date ) ) {
 180              $months          = $wp_locale->month;
 181              $months_genitive = $wp_locale->month_genitive;
 182  
 183              foreach ( $months as $key => $month ) {
 184                  $months[ $key ] = '# ' . $month . '( |$)#u';
 185              }
 186  
 187              foreach ( $months_genitive as $key => $month ) {
 188                  $months_genitive[ $key ] = ' ' . $month . '$1';
 189              }
 190  
 191              $date = preg_replace( $months, $months_genitive, $date );
 192          }
 193      }
 194  
 195      // Used for locale-specific rules
 196      $locale = get_locale();
 197  
 198      if ( 'ca' === $locale ) {
 199          // " de abril| de agost| de octubre..." -> " d'abril| d'agost| d'octubre..."
 200          $date = preg_replace( '# de ([ao])#i', " d'\\1", $date );
 201      }
 202  
 203      return $date;
 204  }
 205  
 206  /**
 207   * Convert float number to format based on the locale.
 208   *
 209   * @since 2.3.0
 210   *
 211   * @global WP_Locale $wp_locale
 212   *
 213   * @param float $number   The number to convert based on locale.
 214   * @param int   $decimals Optional. Precision of the number of decimal places. Default 0.
 215   * @return string Converted number in string format.
 216   */
 217  function number_format_i18n( $number, $decimals = 0 ) {
 218      global $wp_locale;
 219  
 220      if ( isset( $wp_locale ) ) {
 221          $formatted = number_format( $number, absint( $decimals ), $wp_locale->number_format['decimal_point'], $wp_locale->number_format['thousands_sep'] );
 222      } else {
 223          $formatted = number_format( $number, absint( $decimals ) );
 224      }
 225  
 226      /**
 227       * Filters the number formatted based on the locale.
 228       *
 229       * @since  2.8.0
 230       *
 231       * @param string $formatted Converted number in string format.
 232       */
 233      return apply_filters( 'number_format_i18n', $formatted );
 234  }
 235  
 236  /**
 237   * Convert number of bytes largest unit bytes will fit into.
 238   *
 239   * It is easier to read 1 KB than 1024 bytes and 1 MB than 1048576 bytes. Converts
 240   * number of bytes to human readable number by taking the number of that unit
 241   * that the bytes will go into it. Supports TB value.
 242   *
 243   * Please note that integers in PHP are limited to 32 bits, unless they are on
 244   * 64 bit architecture, then they have 64 bit size. If you need to place the
 245   * larger size then what PHP integer type will hold, then use a string. It will
 246   * be converted to a double, which should always have 64 bit length.
 247   *
 248   * Technically the correct unit names for powers of 1024 are KiB, MiB etc.
 249   *
 250   * @since 2.3.0
 251   *
 252   * @param int|string $bytes    Number of bytes. Note max integer size for integers.
 253   * @param int        $decimals Optional. Precision of number of decimal places. Default 0.
 254   * @return string|false False on failure. Number string on success.
 255   */
 256  function size_format( $bytes, $decimals = 0 ) {
 257      $quant = array(
 258          'TB' => TB_IN_BYTES,
 259          'GB' => GB_IN_BYTES,
 260          'MB' => MB_IN_BYTES,
 261          'KB' => KB_IN_BYTES,
 262          'B'  => 1,
 263      );
 264  
 265      if ( 0 === $bytes ) {
 266          return number_format_i18n( 0, $decimals ) . ' B';
 267      }
 268  
 269      foreach ( $quant as $unit => $mag ) {
 270          if ( doubleval( $bytes ) >= $mag ) {
 271              return number_format_i18n( $bytes / $mag, $decimals ) . ' ' . $unit;
 272          }
 273      }
 274  
 275      return false;
 276  }
 277  
 278  /**
 279   * Get the week start and end from the datetime or date string from MySQL.
 280   *
 281   * @since 0.71
 282   *
 283   * @param string     $mysqlstring   Date or datetime field type from MySQL.
 284   * @param int|string $start_of_week Optional. Start of the week as an integer. Default empty string.
 285   * @return array Keys are 'start' and 'end'.
 286   */
 287  function get_weekstartend( $mysqlstring, $start_of_week = '' ) {
 288      // MySQL string year.
 289      $my = substr( $mysqlstring, 0, 4 );
 290  
 291      // MySQL string month.
 292      $mm = substr( $mysqlstring, 8, 2 );
 293  
 294      // MySQL string day.
 295      $md = substr( $mysqlstring, 5, 2 );
 296  
 297      // The timestamp for MySQL string day.
 298      $day = mktime( 0, 0, 0, $md, $mm, $my );
 299  
 300      // The day of the week from the timestamp.
 301      $weekday = date( 'w', $day );
 302  
 303      if ( !is_numeric($start_of_week) )
 304          $start_of_week = get_option( 'start_of_week' );
 305  
 306      if ( $weekday < $start_of_week )
 307          $weekday += 7;
 308  
 309      // The most recent week start day on or before $day.
 310      $start = $day - DAY_IN_SECONDS * ( $weekday - $start_of_week );
 311  
 312      // $start + 1 week - 1 second.
 313      $end = $start + WEEK_IN_SECONDS - 1;
 314      return compact( 'start', 'end' );
 315  }
 316  
 317  /**
 318   * Unserialize value only if it was serialized.
 319   *
 320   * @since 2.0.0
 321   *
 322   * @param string $original Maybe unserialized original, if is needed.
 323   * @return mixed Unserialized data can be any type.
 324   */
 325  function maybe_unserialize( $original ) {
 326      if ( is_serialized( $original ) ) // don't attempt to unserialize data that wasn't serialized going in
 327          return @unserialize( $original );
 328      return $original;
 329  }
 330  
 331  /**
 332   * Check value to find if it was serialized.
 333   *
 334   * If $data is not an string, then returned value will always be false.
 335   * Serialized data is always a string.
 336   *
 337   * @since 2.0.5
 338   *
 339   * @param string $data   Value to check to see if was serialized.
 340   * @param bool   $strict Optional. Whether to be strict about the end of the string. Default true.
 341   * @return bool False if not serialized and true if it was.
 342   */
 343  function is_serialized( $data, $strict = true ) {
 344      // if it isn't a string, it isn't serialized.
 345      if ( ! is_string( $data ) ) {
 346          return false;
 347      }
 348      $data = trim( $data );
 349       if ( 'N;' == $data ) {
 350          return true;
 351      }
 352      if ( strlen( $data ) < 4 ) {
 353          return false;
 354      }
 355      if ( ':' !== $data[1] ) {
 356          return false;
 357      }
 358      if ( $strict ) {
 359          $lastc = substr( $data, -1 );
 360          if ( ';' !== $lastc && '}' !== $lastc ) {
 361              return false;
 362          }
 363      } else {
 364          $semicolon = strpos( $data, ';' );
 365          $brace     = strpos( $data, '}' );
 366          // Either ; or } must exist.
 367          if ( false === $semicolon && false === $brace )
 368              return false;
 369          // But neither must be in the first X characters.
 370          if ( false !== $semicolon && $semicolon < 3 )
 371              return false;
 372          if ( false !== $brace && $brace < 4 )
 373              return false;
 374      }
 375      $token = $data[0];
 376      switch ( $token ) {
 377          case 's' :
 378              if ( $strict ) {
 379                  if ( '"' !== substr( $data, -2, 1 ) ) {
 380                      return false;
 381                  }
 382              } elseif ( false === strpos( $data, '"' ) ) {
 383                  return false;
 384              }
 385              // or else fall through
 386          case 'a' :
 387          case 'O' :
 388              return (bool) preg_match( "/^{$token}:[0-9]+:/s", $data );
 389          case 'b' :
 390          case 'i' :
 391          case 'd' :
 392              $end = $strict ? '$' : '';
 393              return (bool) preg_match( "/^{$token}:[0-9.E-]+;$end/", $data );
 394      }
 395      return false;
 396  }
 397  
 398  /**
 399   * Check whether serialized data is of string type.
 400   *
 401   * @since 2.0.5
 402   *
 403   * @param string $data Serialized data.
 404   * @return bool False if not a serialized string, true if it is.
 405   */
 406  function is_serialized_string( $data ) {
 407      // if it isn't a string, it isn't a serialized string.
 408      if ( ! is_string( $data ) ) {
 409          return false;
 410      }
 411      $data = trim( $data );
 412      if ( strlen( $data ) < 4 ) {
 413          return false;
 414      } elseif ( ':' !== $data[1] ) {
 415          return false;
 416      } elseif ( ';' !== substr( $data, -1 ) ) {
 417          return false;
 418      } elseif ( $data[0] !== 's' ) {
 419          return false;
 420      } elseif ( '"' !== substr( $data, -2, 1 ) ) {
 421          return false;
 422      } else {
 423          return true;
 424      }
 425  }
 426  
 427  /**
 428   * Serialize data, if needed.
 429   *
 430   * @since 2.0.5
 431   *
 432   * @param string|array|object $data Data that might be serialized.
 433   * @return mixed A scalar data
 434   */
 435  function maybe_serialize( $data ) {
 436      if ( is_array( $data ) || is_object( $data ) )
 437          return serialize( $data );
 438  
 439      // Double serialization is required for backward compatibility.
 440      // See https://core.trac.wordpress.org/ticket/12930
 441      // Also the world will end. See WP 3.6.1.
 442      if ( is_serialized( $data, false ) )
 443          return serialize( $data );
 444  
 445      return $data;
 446  }
 447  
 448  /**
 449   * Retrieve post title from XMLRPC XML.
 450   *
 451   * If the title element is not part of the XML, then the default post title from
 452   * the $post_default_title will be used instead.
 453   *
 454   * @since 0.71
 455   *
 456   * @global string $post_default_title Default XML-RPC post title.
 457   *
 458   * @param string $content XMLRPC XML Request content
 459   * @return string Post title
 460   */
 461  function xmlrpc_getposttitle( $content ) {
 462      global $post_default_title;
 463      if ( preg_match( '/<title>(.+?)<\/title>/is', $content, $matchtitle ) ) {
 464          $post_title = $matchtitle[1];
 465      } else {
 466          $post_title = $post_default_title;
 467      }
 468      return $post_title;
 469  }
 470  
 471  /**
 472   * Retrieve the post category or categories from XMLRPC XML.
 473   *
 474   * If the category element is not found, then the default post category will be
 475   * used. The return type then would be what $post_default_category. If the
 476   * category is found, then it will always be an array.
 477   *
 478   * @since 0.71
 479   *
 480   * @global string $post_default_category Default XML-RPC post category.
 481   *
 482   * @param string $content XMLRPC XML Request content
 483   * @return string|array List of categories or category name.
 484   */
 485  function xmlrpc_getpostcategory( $content ) {
 486      global $post_default_category;
 487      if ( preg_match( '/<category>(.+?)<\/category>/is', $content, $matchcat ) ) {
 488          $post_category = trim( $matchcat[1], ',' );
 489          $post_category = explode( ',', $post_category );
 490      } else {
 491          $post_category = $post_default_category;
 492      }
 493      return $post_category;
 494  }
 495  
 496  /**
 497   * XMLRPC XML content without title and category elements.
 498   *
 499   * @since 0.71
 500   *
 501   * @param string $content XML-RPC XML Request content.
 502   * @return string XMLRPC XML Request content without title and category elements.
 503   */
 504  function xmlrpc_removepostdata( $content ) {
 505      $content = preg_replace( '/<title>(.+?)<\/title>/si', '', $content );
 506      $content = preg_replace( '/<category>(.+?)<\/category>/si', '', $content );
 507      $content = trim( $content );
 508      return $content;
 509  }
 510  
 511  /**
 512   * Use RegEx to extract URLs from arbitrary content.
 513   *
 514   * @since 3.7.0
 515   *
 516   * @param string $content Content to extract URLs from.
 517   * @return array URLs found in passed string.
 518   */
 519  function wp_extract_urls( $content ) {
 520      preg_match_all(
 521          "#([\"']?)("
 522              . "(?:([\w-]+:)?//?)"
 523              . "[^\s()<>]+"
 524              . "[.]"
 525              . "(?:"
 526                  . "\([\w\d]+\)|"
 527                  . "(?:"
 528                      . "[^`!()\[\]{};:'\".,<>«»“”‘’\s]|"
 529                      . "(?:[:]\d+)?/?"
 530                  . ")+"
 531              . ")"
 532          . ")\\1#",
 533          $content,
 534          $post_links
 535      );
 536  
 537      $post_links = array_unique( array_map( 'html_entity_decode', $post_links[2] ) );
 538  
 539      return array_values( $post_links );
 540  }
 541  
 542  /**
 543   * Check content for video and audio links to add as enclosures.
 544   *
 545   * Will not add enclosures that have already been added and will
 546   * remove enclosures that are no longer in the post. This is called as
 547   * pingbacks and trackbacks.
 548   *
 549   * @since 1.5.0
 550   *
 551   * @global wpdb $wpdb WordPress database abstraction object.
 552   *
 553   * @param string $content Post Content.
 554   * @param int    $post_ID Post ID.
 555   */
 556  function do_enclose( $content, $post_ID ) {
 557      global $wpdb;
 558  
 559      //TODO: Tidy this ghetto code up and make the debug code optional
 560      include_once ( ABSPATH . WPINC . '/class-IXR.php' );
 561  
 562      $post_links = array();
 563  
 564      $pung = get_enclosed( $post_ID );
 565  
 566      $post_links_temp = wp_extract_urls( $content );
 567  
 568      foreach ( $pung as $link_test ) {
 569          if ( ! in_array( $link_test, $post_links_temp ) ) { // link no longer in post
 570              $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 ) . '%') );
 571              foreach ( $mids as $mid )
 572                  delete_metadata_by_mid( 'post', $mid );
 573          }
 574      }
 575  
 576      foreach ( (array) $post_links_temp as $link_test ) {
 577          if ( !in_array( $link_test, $pung ) ) { // If we haven't pung it already
 578              $test = @parse_url( $link_test );
 579              if ( false === $test )
 580                  continue;
 581              if ( isset( $test['query'] ) )
 582                  $post_links[] = $link_test;
 583              elseif ( isset($test['path']) && ( $test['path'] != '/' ) &&  ($test['path'] != '' ) )
 584                  $post_links[] = $link_test;
 585          }
 586      }
 587  
 588      /**
 589       * Filters the list of enclosure links before querying the database.
 590       *
 591       * Allows for the addition and/or removal of potential enclosures to save
 592       * to postmeta before checking the database for existing enclosures.
 593       *
 594       * @since 4.4.0
 595       *
 596       * @param array $post_links An array of enclosure links.
 597       * @param int   $post_ID    Post ID.
 598       */
 599      $post_links = apply_filters( 'enclosure_links', $post_links, $post_ID );
 600  
 601      foreach ( (array) $post_links as $url ) {
 602          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 ) . '%' ) ) ) {
 603  
 604              if ( $headers = wp_get_http_headers( $url) ) {
 605                  $len = isset( $headers['content-length'] ) ? (int) $headers['content-length'] : 0;
 606                  $type = isset( $headers['content-type'] ) ? $headers['content-type'] : '';
 607                  $allowed_types = array( 'video', 'audio' );
 608  
 609                  // Check to see if we can figure out the mime type from
 610                  // the extension
 611                  $url_parts = @parse_url( $url );
 612                  if ( false !== $url_parts ) {
 613                      $extension = pathinfo( $url_parts['path'], PATHINFO_EXTENSION );
 614                      if ( !empty( $extension ) ) {
 615                          foreach ( wp_get_mime_types() as $exts => $mime ) {
 616                              if ( preg_match( '!^(' . $exts . ')$!i', $extension ) ) {
 617                                  $type = $mime;
 618                                  break;
 619                              }
 620                          }
 621                      }
 622                  }
 623  
 624                  if ( in_array( substr( $type, 0, strpos( $type, "/" ) ), $allowed_types ) ) {
 625                      add_post_meta( $post_ID, 'enclosure', "$url\n$len\n$mime\n" );
 626                  }
 627              }
 628          }
 629      }
 630  }
 631  
 632  /**
 633   * Retrieve HTTP Headers from URL.
 634   *
 635   * @since 1.5.1
 636   *
 637   * @param string $url        URL to retrieve HTTP headers from.
 638   * @param bool   $deprecated Not Used.
 639   * @return bool|string False on failure, headers on success.
 640   */
 641  function wp_get_http_headers( $url, $deprecated = false ) {
 642      if ( !empty( $deprecated ) )
 643          _deprecated_argument( __FUNCTION__, '2.7.0' );
 644  
 645      $response = wp_safe_remote_head( $url );
 646  
 647      if ( is_wp_error( $response ) )
 648          return false;
 649  
 650      return wp_remote_retrieve_headers( $response );
 651  }
 652  
 653  /**
 654   * Whether the publish date of the current post in the loop is different from the
 655   * publish date of the previous post in the loop.
 656   *
 657   * @since 0.71
 658   *
 659   * @global string $currentday  The day of the current post in the loop.
 660   * @global string $previousday The day of the previous post in the loop.
 661   *
 662   * @return int 1 when new day, 0 if not a new day.
 663   */
 664  function is_new_day() {
 665      global $currentday, $previousday;
 666      if ( $currentday != $previousday )
 667          return 1;
 668      else
 669          return 0;
 670  }
 671  
 672  /**
 673   * Build URL query based on an associative and, or indexed array.
 674   *
 675   * This is a convenient function for easily building url queries. It sets the
 676   * separator to '&' and uses _http_build_query() function.
 677   *
 678   * @since 2.3.0
 679   *
 680   * @see _http_build_query() Used to build the query
 681   * @link https://secure.php.net/manual/en/function.http-build-query.php for more on what
 682   *         http_build_query() does.
 683   *
 684   * @param array $data URL-encode key/value pairs.
 685   * @return string URL-encoded string.
 686   */
 687  function build_query( $data ) {
 688      return _http_build_query( $data, null, '&', '', false );
 689  }
 690  
 691  /**
 692   * From php.net (modified by Mark Jaquith to behave like the native PHP5 function).
 693   *
 694   * @since 3.2.0
 695   * @access private
 696   *
 697   * @see https://secure.php.net/manual/en/function.http-build-query.php
 698   *
 699   * @param array|object  $data       An array or object of data. Converted to array.
 700   * @param string        $prefix     Optional. Numeric index. If set, start parameter numbering with it.
 701   *                                  Default null.
 702   * @param string        $sep        Optional. Argument separator; defaults to 'arg_separator.output'.
 703   *                                  Default null.
 704   * @param string        $key        Optional. Used to prefix key name. Default empty.
 705   * @param bool          $urlencode  Optional. Whether to use urlencode() in the result. Default true.
 706   *
 707   * @return string The query string.
 708   */
 709  function _http_build_query( $data, $prefix = null, $sep = null, $key = '', $urlencode = true ) {
 710      $ret = array();
 711  
 712      foreach ( (array) $data as $k => $v ) {
 713          if ( $urlencode)
 714              $k = urlencode($k);
 715          if ( is_int($k) && $prefix != null )
 716              $k = $prefix.$k;
 717          if ( !empty($key) )
 718              $k = $key . '%5B' . $k . '%5D';
 719          if ( $v === null )
 720              continue;
 721          elseif ( $v === false )
 722              $v = '0';
 723  
 724          if ( is_array($v) || is_object($v) )
 725              array_push($ret,_http_build_query($v, '', $sep, $k, $urlencode));
 726          elseif ( $urlencode )
 727              array_push($ret, $k.'='.urlencode($v));
 728          else
 729              array_push($ret, $k.'='.$v);
 730      }
 731  
 732      if ( null === $sep )
 733          $sep = ini_get('arg_separator.output');
 734  
 735      return implode($sep, $ret);
 736  }
 737  
 738  /**
 739   * Retrieves a modified URL query string.
 740   *
 741   * You can rebuild the URL and append query variables to the URL query by using this function.
 742   * There are two ways to use this function; either a single key and value, or an associative array.
 743   *
 744   * Using a single key and value:
 745   *
 746   *     add_query_arg( 'key', 'value', 'http://example.com' );
 747   *
 748   * Using an associative array:
 749   *
 750   *     add_query_arg( array(
 751   *         'key1' => 'value1',
 752   *         'key2' => 'value2',
 753   *     ), 'http://example.com' );
 754   *
 755   * Omitting the URL from either use results in the current URL being used
 756   * (the value of `$_SERVER['REQUEST_URI']`).
 757   *
 758   * Values are expected to be encoded appropriately with urlencode() or rawurlencode().
 759   *
 760   * Setting any query variable's value to boolean false removes the key (see remove_query_arg()).
 761   *
 762   * Important: The return value of add_query_arg() is not escaped by default. Output should be
 763   * late-escaped with esc_url() or similar to help prevent vulnerability to cross-site scripting
 764   * (XSS) attacks.
 765   *
 766   * @since 1.5.0
 767   *
 768   * @param string|array $key   Either a query variable key, or an associative array of query variables.
 769   * @param string       $value Optional. Either a query variable value, or a URL to act upon.
 770   * @param string       $url   Optional. A URL to act upon.
 771   * @return string New URL query string (unescaped).
 772   */
 773  function add_query_arg() {
 774      $args = func_get_args();
 775      if ( is_array( $args[0] ) ) {
 776          if ( count( $args ) < 2 || false === $args[1] )
 777              $uri = $_SERVER['REQUEST_URI'];
 778          else
 779              $uri = $args[1];
 780      } else {
 781          if ( count( $args ) < 3 || false === $args[2] )
 782              $uri = $_SERVER['REQUEST_URI'];
 783          else
 784              $uri = $args[2];
 785      }
 786  
 787      if ( $frag = strstr( $uri, '#' ) )
 788          $uri = substr( $uri, 0, -strlen( $frag ) );
 789      else
 790          $frag = '';
 791  
 792      if ( 0 === stripos( $uri, 'http://' ) ) {
 793          $protocol = 'http://';
 794          $uri = substr( $uri, 7 );
 795      } elseif ( 0 === stripos( $uri, 'https://' ) ) {
 796          $protocol = 'https://';
 797          $uri = substr( $uri, 8 );
 798      } else {
 799          $protocol = '';
 800      }
 801  
 802      if ( strpos( $uri, '?' ) !== false ) {
 803          list( $base, $query ) = explode( '?', $uri, 2 );
 804          $base .= '?';
 805      } elseif ( $protocol || strpos( $uri, '=' ) === false ) {
 806          $base = $uri . '?';
 807          $query = '';
 808      } else {
 809          $base = '';
 810          $query = $uri;
 811      }
 812  
 813      wp_parse_str( $query, $qs );
 814      $qs = urlencode_deep( $qs ); // this re-URL-encodes things that were already in the query string
 815      if ( is_array( $args[0] ) ) {
 816          foreach ( $args[0] as $k => $v ) {
 817              $qs[ $k ] = $v;
 818          }
 819      } else {
 820          $qs[ $args[0] ] = $args[1];
 821      }
 822  
 823      foreach ( $qs as $k => $v ) {
 824          if ( $v === false )
 825              unset( $qs[$k] );
 826      }
 827  
 828      $ret = build_query( $qs );
 829      $ret = trim( $ret, '?' );
 830      $ret = preg_replace( '#=(&|$)#', '$1', $ret );
 831      $ret = $protocol . $base . $ret . $frag;
 832      $ret = rtrim( $ret, '?' );
 833      return $ret;
 834  }
 835  
 836  /**
 837   * Removes an item or items from a query string.
 838   *
 839   * @since 1.5.0
 840   *
 841   * @param string|array $key   Query key or keys to remove.
 842   * @param bool|string  $query Optional. When false uses the current URL. Default false.
 843   * @return string New URL query string.
 844   */
 845  function remove_query_arg( $key, $query = false ) {
 846      if ( is_array( $key ) ) { // removing multiple keys
 847          foreach ( $key as $k )
 848              $query = add_query_arg( $k, false, $query );
 849          return $query;
 850      }
 851      return add_query_arg( $key, false, $query );
 852  }
 853  
 854  /**
 855   * Returns an array of single-use query variable names that can be removed from a URL.
 856   *
 857   * @since 4.4.0
 858   *
 859   * @return array An array of parameters to remove from the URL.
 860   */
 861  function wp_removable_query_args() {
 862      $removable_query_args = array(
 863          'activate',
 864          'activated',
 865          'approved',
 866          'deactivate',
 867          'deleted',
 868          'disabled',
 869          'enabled',
 870          'error',
 871          'hotkeys_highlight_first',
 872          'hotkeys_highlight_last',
 873          'locked',
 874          'message',
 875          'same',
 876          'saved',
 877          'settings-updated',
 878          'skipped',
 879          'spammed',
 880          'trashed',
 881          'unspammed',
 882          'untrashed',
 883          'update',
 884          'updated',
 885          'wp-post-new-reload',
 886      );
 887  
 888      /**
 889       * Filters the list of query variables to remove.
 890       *
 891       * @since 4.2.0
 892       *
 893       * @param array $removable_query_args An array of query variables to remove from a URL.
 894       */
 895      return apply_filters( 'removable_query_args', $removable_query_args );
 896  }
 897  
 898  /**
 899   * Walks the array while sanitizing the contents.
 900   *
 901   * @since 0.71
 902   *
 903   * @param array $array Array to walk while sanitizing contents.
 904   * @return array Sanitized $array.
 905   */
 906  function add_magic_quotes( $array ) {
 907      foreach ( (array) $array as $k => $v ) {
 908          if ( is_array( $v ) ) {
 909              $array[$k] = add_magic_quotes( $v );
 910          } else {
 911              $array[$k] = addslashes( $v );
 912          }
 913      }
 914      return $array;
 915  }
 916  
 917  /**
 918   * HTTP request for URI to retrieve content.
 919   *
 920   * @since 1.5.1
 921   *
 922   * @see wp_safe_remote_get()
 923   *
 924   * @param string $uri URI/URL of web page to retrieve.
 925   * @return false|string HTTP content. False on failure.
 926   */
 927  function wp_remote_fopen( $uri ) {
 928      $parsed_url = @parse_url( $uri );
 929  
 930      if ( !$parsed_url || !is_array( $parsed_url ) )
 931          return false;
 932  
 933      $options = array();
 934      $options['timeout'] = 10;
 935  
 936      $response = wp_safe_remote_get( $uri, $options );
 937  
 938      if ( is_wp_error( $response ) )
 939          return false;
 940  
 941      return wp_remote_retrieve_body( $response );
 942  }
 943  
 944  /**
 945   * Set up the WordPress query.
 946   *
 947   * @since 2.0.0
 948   *
 949   * @global WP       $wp_locale
 950   * @global WP_Query $wp_query
 951   * @global WP_Query $wp_the_query
 952   *
 953   * @param string|array $query_vars Default WP_Query arguments.
 954   */
 955  function wp( $query_vars = '' ) {
 956      global $wp, $wp_query, $wp_the_query;
 957      $wp->main( $query_vars );
 958  
 959      if ( !isset($wp_the_query) )
 960          $wp_the_query = $wp_query;
 961  }
 962  
 963  /**
 964   * Retrieve the description for the HTTP status.
 965   *
 966   * @since 2.3.0
 967   *
 968   * @global array $wp_header_to_desc
 969   *
 970   * @param int $code HTTP status code.
 971   * @return string Empty string if not found, or description if found.
 972   */
 973  function get_status_header_desc( $code ) {
 974      global $wp_header_to_desc;
 975  
 976      $code = absint( $code );
 977  
 978      if ( !isset( $wp_header_to_desc ) ) {
 979          $wp_header_to_desc = array(
 980              100 => 'Continue',
 981              101 => 'Switching Protocols',
 982              102 => 'Processing',
 983  
 984              200 => 'OK',
 985              201 => 'Created',
 986              202 => 'Accepted',
 987              203 => 'Non-Authoritative Information',
 988              204 => 'No Content',
 989              205 => 'Reset Content',
 990              206 => 'Partial Content',
 991              207 => 'Multi-Status',
 992              226 => 'IM Used',
 993  
 994              300 => 'Multiple Choices',
 995              301 => 'Moved Permanently',
 996              302 => 'Found',
 997              303 => 'See Other',
 998              304 => 'Not Modified',
 999              305 => 'Use Proxy',
1000              306 => 'Reserved',
1001              307 => 'Temporary Redirect',
1002              308 => 'Permanent Redirect',
1003  
1004              400 => 'Bad Request',
1005              401 => 'Unauthorized',
1006              402 => 'Payment Required',
1007              403 => 'Forbidden',
1008              404 => 'Not Found',
1009              405 => 'Method Not Allowed',
1010              406 => 'Not Acceptable',
1011              407 => 'Proxy Authentication Required',
1012              408 => 'Request Timeout',
1013              409 => 'Conflict',
1014              410 => 'Gone',
1015              411 => 'Length Required',
1016              412 => 'Precondition Failed',
1017              413 => 'Request Entity Too Large',
1018              414 => 'Request-URI Too Long',
1019              415 => 'Unsupported Media Type',
1020              416 => 'Requested Range Not Satisfiable',
1021              417 => 'Expectation Failed',
1022              418 => 'I\'m a teapot',
1023              421 => 'Misdirected Request',
1024              422 => 'Unprocessable Entity',
1025              423 => 'Locked',
1026              424 => 'Failed Dependency',
1027              426 => 'Upgrade Required',
1028              428 => 'Precondition Required',
1029              429 => 'Too Many Requests',
1030              431 => 'Request Header Fields Too Large',
1031              451 => 'Unavailable For Legal Reasons',
1032  
1033              500 => 'Internal Server Error',
1034              501 => 'Not Implemented',
1035              502 => 'Bad Gateway',
1036              503 => 'Service Unavailable',
1037              504 => 'Gateway Timeout',
1038              505 => 'HTTP Version Not Supported',
1039              506 => 'Variant Also Negotiates',
1040              507 => 'Insufficient Storage',
1041              510 => 'Not Extended',
1042              511 => 'Network Authentication Required',
1043          );
1044      }
1045  
1046      if ( isset( $wp_header_to_desc[$code] ) )
1047          return $wp_header_to_desc[$code];
1048      else
1049          return '';
1050  }
1051  
1052  /**
1053   * Set HTTP status header.
1054   *
1055   * @since 2.0.0
1056   * @since 4.4.0 Added the `$description` parameter.
1057   *
1058   * @see get_status_header_desc()
1059   *
1060   * @param int    $code        HTTP status code.
1061   * @param string $description Optional. A custom description for the HTTP status.
1062   */
1063  function status_header( $code, $description = '' ) {
1064      if ( ! $description ) {
1065          $description = get_status_header_desc( $code );
1066      }
1067  
1068      if ( empty( $description ) ) {
1069          return;
1070      }
1071  
1072      $protocol = wp_get_server_protocol();
1073      $status_header = "$protocol $code $description";
1074      if ( function_exists( 'apply_filters' ) )
1075  
1076          /**
1077           * Filters an HTTP status header.
1078           *
1079           * @since 2.2.0
1080           *
1081           * @param string $status_header HTTP status header.
1082           * @param int    $code          HTTP status code.
1083           * @param string $description   Description for the status code.
1084           * @param string $protocol      Server protocol.
1085           */
1086          $status_header = apply_filters( 'status_header', $status_header, $code, $description, $protocol );
1087  
1088      @header( $status_header, true, $code );
1089  }
1090  
1091  /**
1092   * Get the header information to prevent caching.
1093   *
1094   * The several different headers cover the different ways cache prevention
1095   * is handled by different browsers
1096   *
1097   * @since 2.8.0
1098   *
1099   * @return array The associative array of header names and field values.
1100   */
1101  function wp_get_nocache_headers() {
1102      $headers = array(
1103          'Expires' => 'Wed, 11 Jan 1984 05:00:00 GMT',
1104          'Cache-Control' => 'no-cache, must-revalidate, max-age=0',
1105      );
1106  
1107      if ( function_exists('apply_filters') ) {
1108          /**
1109           * Filters the cache-controlling headers.
1110           *
1111           * @since 2.8.0
1112           *
1113           * @see wp_get_nocache_headers()
1114           *
1115           * @param array $headers {
1116           *     Header names and field values.
1117           *
1118           *     @type string $Expires       Expires header.
1119           *     @type string $Cache-Control Cache-Control header.
1120           * }
1121           */
1122          $headers = (array) apply_filters( 'nocache_headers', $headers );
1123      }
1124      $headers['Last-Modified'] = false;
1125      return $headers;
1126  }
1127  
1128  /**
1129   * Set the headers to prevent caching for the different browsers.
1130   *
1131   * Different browsers support different nocache headers, so several
1132   * headers must be sent so that all of them get the point that no
1133   * caching should occur.
1134   *
1135   * @since 2.0.0
1136   *
1137   * @see wp_get_nocache_headers()
1138   */
1139  function nocache_headers() {
1140      $headers = wp_get_nocache_headers();
1141  
1142      unset( $headers['Last-Modified'] );
1143  
1144      // In PHP 5.3+, make sure we are not sending a Last-Modified header.
1145      if ( function_exists( 'header_remove' ) ) {
1146          @header_remove( 'Last-Modified' );
1147      } else {
1148          // In PHP 5.2, send an empty Last-Modified header, but only as a
1149          // last resort to override a header already sent. #WP23021
1150          foreach ( headers_list() as $header ) {
1151              if ( 0 === stripos( $header, 'Last-Modified' ) ) {
1152                  $headers['Last-Modified'] = '';
1153                  break;
1154              }
1155          }
1156      }
1157  
1158      foreach ( $headers as $name => $field_value )
1159          @header("{$name}: {$field_value}");
1160  }
1161  
1162  /**
1163   * Set the headers for caching for 10 days with JavaScript content type.
1164   *
1165   * @since 2.1.0
1166   */
1167  function cache_javascript_headers() {
1168      $expiresOffset = 10 * DAY_IN_SECONDS;
1169  
1170      header( "Content-Type: text/javascript; charset=" . get_bloginfo( 'charset' ) );
1171      header( "Vary: Accept-Encoding" ); // Handle proxies
1172      header( "Expires: " . gmdate( "D, d M Y H:i:s", time() + $expiresOffset ) . " GMT" );
1173  }
1174  
1175  /**
1176   * Retrieve the number of database queries during the WordPress execution.
1177   *
1178   * @since 2.0.0
1179   *
1180   * @global wpdb $wpdb WordPress database abstraction object.
1181   *
1182   * @return int Number of database queries.
1183   */
1184  function get_num_queries() {
1185      global $wpdb;
1186      return $wpdb->num_queries;
1187  }
1188  
1189  /**
1190   * Whether input is yes or no.
1191   *
1192   * Must be 'y' to be true.
1193   *
1194   * @since 1.0.0
1195   *
1196   * @param string $yn Character string containing either 'y' (yes) or 'n' (no).
1197   * @return bool True if yes, false on anything else.
1198   */
1199  function bool_from_yn( $yn ) {
1200      return ( strtolower( $yn ) == 'y' );
1201  }
1202  
1203  /**
1204   * Load the feed template from the use of an action hook.
1205   *
1206   * If the feed action does not have a hook, then the function will die with a
1207   * message telling the visitor that the feed is not valid.
1208   *
1209   * It is better to only have one hook for each feed.
1210   *
1211   * @since 2.1.0
1212   *
1213   * @global WP_Query $wp_query Used to tell if the use a comment feed.
1214   */
1215  function do_feed() {
1216      global $wp_query;
1217  
1218      $feed = get_query_var( 'feed' );
1219  
1220      // Remove the pad, if present.
1221      $feed = preg_replace( '/^_+/', '', $feed );
1222  
1223      if ( $feed == '' || $feed == 'feed' )
1224          $feed = get_default_feed();
1225  
1226      if ( ! has_action( "do_feed_{$feed}" ) ) {
1227          wp_die( __( 'ERROR: This is not a valid feed template.' ), '', array( 'response' => 404 ) );
1228      }
1229  
1230      /**
1231       * Fires once the given feed is loaded.
1232       *
1233       * The dynamic portion of the hook name, `$feed`, refers to the feed template name.
1234       * Possible values include: 'rdf', 'rss', 'rss2', and 'atom'.
1235       *
1236       * @since 2.1.0
1237       * @since 4.4.0 The `$feed` parameter was added.
1238       *
1239       * @param bool   $is_comment_feed Whether the feed is a comment feed.
1240       * @param string $feed            The feed name.
1241       */
1242      do_action( "do_feed_{$feed}", $wp_query->is_comment_feed, $feed );
1243  }
1244  
1245  /**
1246   * Load the RDF RSS 0.91 Feed template.
1247   *
1248   * @since 2.1.0
1249   *
1250   * @see load_template()
1251   */
1252  function do_feed_rdf() {
1253      load_template( ABSPATH . WPINC . '/feed-rdf.php' );
1254  }
1255  
1256  /**
1257   * Load the RSS 1.0 Feed Template.
1258   *
1259   * @since 2.1.0
1260   *
1261   * @see load_template()
1262   */
1263  function do_feed_rss() {
1264      load_template( ABSPATH . WPINC . '/feed-rss.php' );
1265  }
1266  
1267  /**
1268   * Load either the RSS2 comment feed or the RSS2 posts feed.
1269   *
1270   * @since 2.1.0
1271   *
1272   * @see load_template()
1273   *
1274   * @param bool $for_comments True for the comment feed, false for normal feed.
1275   */
1276  function do_feed_rss2( $for_comments ) {
1277      if ( $for_comments )
1278          load_template( ABSPATH . WPINC . '/feed-rss2-comments.php' );
1279      else
1280          load_template( ABSPATH . WPINC . '/feed-rss2.php' );
1281  }
1282  
1283  /**
1284   * Load either Atom comment feed or Atom posts feed.
1285   *
1286   * @since 2.1.0
1287   *
1288   * @see load_template()
1289   *
1290   * @param bool $for_comments True for the comment feed, false for normal feed.
1291   */
1292  function do_feed_atom( $for_comments ) {
1293      if ($for_comments)
1294          load_template( ABSPATH . WPINC . '/feed-atom-comments.php');
1295      else
1296          load_template( ABSPATH . WPINC . '/feed-atom.php' );
1297  }
1298  
1299  /**
1300   * Display the robots.txt file content.
1301   *
1302   * The echo content should be with usage of the permalinks or for creating the
1303   * robots.txt file.
1304   *
1305   * @since 2.1.0
1306   */
1307  function do_robots() {
1308      header( 'Content-Type: text/plain; charset=utf-8' );
1309  
1310      /**
1311       * Fires when displaying the robots.txt file.
1312       *
1313       * @since 2.1.0
1314       */
1315      do_action( 'do_robotstxt' );
1316  
1317      $output = "User-agent: *\n";
1318      $public = get_option( 'blog_public' );
1319      if ( '0' == $public ) {
1320          $output .= "Disallow: /\n";
1321      } else {
1322          $site_url = parse_url( site_url() );
1323          $path = ( !empty( $site_url['path'] ) ) ? $site_url['path'] : '';
1324          $output .= "Disallow: $path/wp-admin/\n";
1325          $output .= "Allow: $path/wp-admin/admin-ajax.php\n";
1326      }
1327  
1328      /**
1329       * Filters the robots.txt output.
1330       *
1331       * @since 3.0.0
1332       *
1333       * @param string $output Robots.txt output.
1334       * @param bool   $public Whether the site is considered "public".
1335       */
1336      echo apply_filters( 'robots_txt', $output, $public );
1337  }
1338  
1339  /**
1340   * Test whether WordPress is already installed.
1341   *
1342   * The cache will be checked first. If you have a cache plugin, which saves
1343   * the cache values, then this will work. If you use the default WordPress
1344   * cache, and the database goes away, then you might have problems.
1345   *
1346   * Checks for the 'siteurl' option for whether WordPress is installed.
1347   *
1348   * @since 2.1.0
1349   *
1350   * @global wpdb $wpdb WordPress database abstraction object.
1351   *
1352   * @return bool Whether the site is already installed.
1353   */
1354  function is_blog_installed() {
1355      global $wpdb;
1356  
1357      /*
1358       * Check cache first. If options table goes away and we have true
1359       * cached, oh well.
1360       */
1361      if ( wp_cache_get( 'is_blog_installed' ) )
1362          return true;
1363  
1364      $suppress = $wpdb->suppress_errors();
1365      if ( ! wp_installing() ) {
1366          $alloptions = wp_load_alloptions();
1367      }
1368      // If siteurl is not set to autoload, check it specifically
1369      if ( !isset( $alloptions['siteurl'] ) )
1370          $installed = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'siteurl'" );
1371      else
1372          $installed = $alloptions['siteurl'];
1373      $wpdb->suppress_errors( $suppress );
1374  
1375      $installed = !empty( $installed );
1376      wp_cache_set( 'is_blog_installed', $installed );
1377  
1378      if ( $installed )
1379          return true;
1380  
1381      // If visiting repair.php, return true and let it take over.
1382      if ( defined( 'WP_REPAIRING' ) )
1383          return true;
1384  
1385      $suppress = $wpdb->suppress_errors();
1386  
1387      /*
1388       * Loop over the WP tables. If none exist, then scratch install is allowed.
1389       * If one or more exist, suggest table repair since we got here because the
1390       * options table could not be accessed.
1391       */
1392      $wp_tables = $wpdb->tables();
1393      foreach ( $wp_tables as $table ) {
1394          // The existence of custom user tables shouldn't suggest an insane state or prevent a clean install.
1395          if ( defined( 'CUSTOM_USER_TABLE' ) && CUSTOM_USER_TABLE == $table )
1396              continue;
1397          if ( defined( 'CUSTOM_USER_META_TABLE' ) && CUSTOM_USER_META_TABLE == $table )
1398              continue;
1399  
1400          if ( ! $wpdb->get_results( "DESCRIBE $table;" ) )
1401              continue;
1402  
1403          // One or more tables exist. We are insane.
1404  
1405          wp_load_translations_early();
1406  
1407          // Die with a DB error.
1408          $wpdb->error = sprintf(
1409              /* translators: %s: database repair URL */
1410              __( 'One or more database tables are unavailable. The database may need to be <a href="%s">repaired</a>.' ),
1411              'maint/repair.php?referrer=is_blog_installed'
1412          );
1413  
1414          dead_db();
1415      }
1416  
1417      $wpdb->suppress_errors( $suppress );
1418  
1419      wp_cache_set( 'is_blog_installed', false );
1420  
1421      return false;
1422  }
1423  
1424  /**
1425   * Retrieve URL with nonce added to URL query.
1426   *
1427   * @since 2.0.4
1428   *
1429   * @param string     $actionurl URL to add nonce action.
1430   * @param int|string $action    Optional. Nonce action name. Default -1.
1431   * @param string     $name      Optional. Nonce name. Default '_wpnonce'.
1432   * @return string Escaped URL with nonce action added.
1433   */
1434  function wp_nonce_url( $actionurl, $action = -1, $name = '_wpnonce' ) {
1435      $actionurl = str_replace( '&amp;', '&', $actionurl );
1436      return esc_html( add_query_arg( $name, wp_create_nonce( $action ), $actionurl ) );
1437  }
1438  
1439  /**
1440   * Retrieve or display nonce hidden field for forms.
1441   *
1442   * The nonce field is used to validate that the contents of the form came from
1443   * the location on the current site and not somewhere else. The nonce does not
1444   * offer absolute protection, but should protect against most cases. It is very
1445   * important to use nonce field in forms.
1446   *
1447   * The $action and $name are optional, but if you want to have better security,
1448   * it is strongly suggested to set those two parameters. It is easier to just
1449   * call the function without any parameters, because validation of the nonce
1450   * doesn't require any parameters, but since crackers know what the default is
1451   * it won't be difficult for them to find a way around your nonce and cause
1452   * damage.
1453   *
1454   * The input name will be whatever $name value you gave. The input value will be
1455   * the nonce creation value.
1456   *
1457   * @since 2.0.4
1458   *
1459   * @param int|string $action  Optional. Action name. Default -1.
1460   * @param string     $name    Optional. Nonce name. Default '_wpnonce'.
1461   * @param bool       $referer Optional. Whether to set the referer field for validation. Default true.
1462   * @param bool       $echo    Optional. Whether to display or return hidden form field. Default true.
1463   * @return string Nonce field HTML markup.
1464   */
1465  function wp_nonce_field( $action = -1, $name = "_wpnonce", $referer = true , $echo = true ) {
1466      $name = esc_attr( $name );
1467      $nonce_field = '<input type="hidden" id="' . $name . '" name="' . $name . '" value="' . wp_create_nonce( $action ) . '" />';
1468  
1469      if ( $referer )
1470          $nonce_field .= wp_referer_field( false );
1471  
1472      if ( $echo )
1473          echo $nonce_field;
1474  
1475      return $nonce_field;
1476  }
1477  
1478  /**
1479   * Retrieve or display referer hidden field for forms.
1480   *
1481   * The referer link is the current Request URI from the server super global. The
1482   * input name is '_wp_http_referer', in case you wanted to check manually.
1483   *
1484   * @since 2.0.4
1485   *
1486   * @param bool $echo Optional. Whether to echo or return the referer field. Default true.
1487   * @return string Referer field HTML markup.
1488   */
1489  function wp_referer_field( $echo = true ) {
1490      $referer_field = '<input type="hidden" name="_wp_http_referer" value="'. esc_attr( wp_unslash( $_SERVER['REQUEST_URI'] ) ) . '" />';
1491  
1492      if ( $echo )
1493          echo $referer_field;
1494      return $referer_field;
1495  }
1496  
1497  /**
1498   * Retrieve or display original referer hidden field for forms.
1499   *
1500   * The input name is '_wp_original_http_referer' and will be either the same
1501   * value of wp_referer_field(), if that was posted already or it will be the
1502   * current page, if it doesn't exist.
1503   *
1504   * @since 2.0.4
1505   *
1506   * @param bool   $echo         Optional. Whether to echo the original http referer. Default true.
1507   * @param string $jump_back_to Optional. Can be 'previous' or page you want to jump back to.
1508   *                             Default 'current'.
1509   * @return string Original referer field.
1510   */
1511  function wp_original_referer_field( $echo = true, $jump_back_to = 'current' ) {
1512      if ( ! $ref = wp_get_original_referer() ) {
1513          $ref = 'previous' == $jump_back_to ? wp_get_referer() : wp_unslash( $_SERVER['REQUEST_URI'] );
1514      }
1515      $orig_referer_field = '<input type="hidden" name="_wp_original_http_referer" value="' . esc_attr( $ref ) . '" />';
1516      if ( $echo )
1517          echo $orig_referer_field;
1518      return $orig_referer_field;
1519  }
1520  
1521  /**
1522   * Retrieve referer from '_wp_http_referer' or HTTP referer.
1523   *
1524   * If it's the same as the current request URL, will return false.
1525   *
1526   * @since 2.0.4
1527   *
1528   * @return false|string False on failure. Referer URL on success.
1529   */
1530  function wp_get_referer() {
1531      if ( ! function_exists( 'wp_validate_redirect' ) ) {
1532          return false;
1533      }
1534  
1535      $ref = wp_get_raw_referer();
1536  
1537      if ( $ref && $ref !== wp_unslash( $_SERVER['REQUEST_URI'] ) && $ref !== home_url() . wp_unslash( $_SERVER['REQUEST_URI'] ) ) {
1538          return wp_validate_redirect( $ref, false );
1539      }
1540  
1541      return false;
1542  }
1543  
1544  /**
1545   * Retrieves unvalidated referer from '_wp_http_referer' or HTTP referer.
1546   *
1547   * Do not use for redirects, use wp_get_referer() instead.
1548   *
1549   * @since 4.5.0
1550   *
1551   * @return string|false Referer URL on success, false on failure.
1552   */
1553  function wp_get_raw_referer() {
1554      if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
1555          return wp_unslash( $_REQUEST['_wp_http_referer'] );
1556      } else if ( ! empty( $_SERVER['HTTP_REFERER'] ) ) {
1557          return wp_unslash( $_SERVER['HTTP_REFERER'] );
1558      }
1559  
1560      return false;
1561  }
1562  
1563  /**
1564   * Retrieve original referer that was posted, if it exists.
1565   *
1566   * @since 2.0.4
1567   *
1568   * @return string|false False if no original referer or original referer if set.
1569   */
1570  function wp_get_original_referer() {
1571      if ( ! empty( $_REQUEST['_wp_original_http_referer'] ) && function_exists( 'wp_validate_redirect' ) )
1572          return wp_validate_redirect( wp_unslash( $_REQUEST['_wp_original_http_referer'] ), false );
1573      return false;
1574  }
1575  
1576  /**
1577   * Recursive directory creation based on full path.
1578   *
1579   * Will attempt to set permissions on folders.
1580   *
1581   * @since 2.0.1
1582   *
1583   * @param string $target Full path to attempt to create.
1584   * @return bool Whether the path was created. True if path already exists.
1585   */
1586  function wp_mkdir_p( $target ) {
1587      $wrapper = null;
1588  
1589      // Strip the protocol.
1590      if ( wp_is_stream( $target ) ) {
1591          list( $wrapper, $target ) = explode( '://', $target, 2 );
1592      }
1593  
1594      // From php.net/mkdir user contributed notes.
1595      $target = str_replace( '//', '/', $target );
1596  
1597      // Put the wrapper back on the target.
1598      if ( $wrapper !== null ) {
1599          $target = $wrapper . '://' . $target;
1600      }
1601  
1602      /*
1603       * Safe mode fails with a trailing slash under certain PHP versions.
1604       * Use rtrim() instead of untrailingslashit to avoid formatting.php dependency.
1605       */
1606      $target = rtrim($target, '/');
1607      if ( empty($target) )
1608          $target = '/';
1609  
1610      if ( file_exists( $target ) )
1611          return @is_dir( $target );
1612  
1613      // We need to find the permissions of the parent folder that exists and inherit that.
1614      $target_parent = dirname( $target );
1615      while ( '.' != $target_parent && ! is_dir( $target_parent ) ) {
1616          $target_parent = dirname( $target_parent );
1617      }
1618  
1619      // Get the permission bits.
1620      if ( $stat = @stat( $target_parent ) ) {
1621          $dir_perms = $stat['mode'] & 0007777;
1622      } else {
1623          $dir_perms = 0777;
1624      }
1625  
1626      if ( @mkdir( $target, $dir_perms, true ) ) {
1627  
1628          /*
1629           * If a umask is set that modifies $dir_perms, we'll have to re-set
1630           * the $dir_perms correctly with chmod()
1631           */
1632          if ( $dir_perms != ( $dir_perms & ~umask() ) ) {
1633              $folder_parts = explode( '/', substr( $target, strlen( $target_parent ) + 1 ) );
1634              for ( $i = 1, $c = count( $folder_parts ); $i <= $c; $i++ ) {
1635                  @chmod( $target_parent . '/' . implode( '/', array_slice( $folder_parts, 0, $i ) ), $dir_perms );
1636              }
1637          }
1638  
1639          return true;
1640      }
1641  
1642      return false;
1643  }
1644  
1645  /**
1646   * Test if a give filesystem path is absolute.
1647   *
1648   * For example, '/foo/bar', or 'c:\windows'.
1649   *
1650   * @since 2.5.0
1651   *
1652   * @param string $path File path.
1653   * @return bool True if path is absolute, false is not absolute.
1654   */
1655  function path_is_absolute( $path ) {
1656      /*
1657       * This is definitive if true but fails if $path does not exist or contains
1658       * a symbolic link.
1659       */
1660      if ( realpath($path) == $path )
1661          return true;
1662  
1663      if ( strlen($path) == 0 || $path[0] == '.' )
1664          return false;
1665  
1666      // Windows allows absolute paths like this.
1667      if ( preg_match('#^[a-zA-Z]:\\\\#', $path) )
1668          return true;
1669  
1670      // A path starting with / or \ is absolute; anything else is relative.
1671      return ( $path[0] == '/' || $path[0] == '\\' );
1672  }
1673  
1674  /**
1675   * Join two filesystem paths together.
1676   *
1677   * For example, 'give me $path relative to $base'. If the $path is absolute,
1678   * then it the full path is returned.
1679   *
1680   * @since 2.5.0
1681   *
1682   * @param string $base Base path.
1683   * @param string $path Path relative to $base.
1684   * @return string The path with the base or absolute path.
1685   */
1686  function path_join( $base, $path ) {
1687      if ( path_is_absolute($path) )
1688          return $path;
1689  
1690      return rtrim($base, '/') . '/' . ltrim($path, '/');
1691  }
1692  
1693  /**
1694   * Normalize a filesystem path.
1695   *
1696   * On windows systems, replaces backslashes with forward slashes
1697   * and forces upper-case drive letters.
1698   * Allows for two leading slashes for Windows network shares, but
1699   * ensures that all other duplicate slashes are reduced to a single.
1700   *
1701   * @since 3.9.0
1702   * @since 4.4.0 Ensures upper-case drive letters on Windows systems.
1703   * @since 4.5.0 Allows for Windows network shares.
1704   *
1705   * @param string $path Path to normalize.
1706   * @return string Normalized path.
1707   */
1708  function wp_normalize_path( $path ) {
1709      $path = str_replace( '\\', '/', $path );
1710      $path = preg_replace( '|(?<=.)/+|', '/', $path );
1711      if ( ':' === substr( $path, 1, 1 ) ) {
1712          $path = ucfirst( $path );
1713      }
1714      return $path;
1715  }
1716  
1717  /**
1718   * Determine a writable directory for temporary files.
1719   *
1720   * Function's preference is the return value of sys_get_temp_dir(),
1721   * followed by your PHP temporary upload directory, followed by WP_CONTENT_DIR,
1722   * before finally defaulting to /tmp/
1723   *
1724   * In the event that this function does not find a writable location,
1725   * It may be overridden by the WP_TEMP_DIR constant in your wp-config.php file.
1726   *
1727   * @since 2.5.0
1728   *
1729   * @staticvar string $temp
1730   *
1731   * @return string Writable temporary directory.
1732   */
1733  function get_temp_dir() {
1734      static $temp = '';
1735      if ( defined('WP_TEMP_DIR') )
1736          return trailingslashit(WP_TEMP_DIR);
1737  
1738      if ( $temp )
1739          return trailingslashit( $temp );
1740  
1741      if ( function_exists('sys_get_temp_dir') ) {
1742          $temp = sys_get_temp_dir();
1743          if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1744              return trailingslashit( $temp );
1745      }
1746  
1747      $temp = ini_get('upload_tmp_dir');
1748      if ( @is_dir( $temp ) && wp_is_writable( $temp ) )
1749          return trailingslashit( $temp );
1750  
1751      $temp = WP_CONTENT_DIR . '/';
1752      if ( is_dir( $temp ) && wp_is_writable( $temp ) )
1753          return $temp;
1754  
1755      return '/tmp/';
1756  }
1757  
1758  /**
1759   * Determine if a directory is writable.
1760   *
1761   * This function is used to work around certain ACL issues in PHP primarily
1762   * affecting Windows Servers.
1763   *
1764   * @since 3.6.0
1765   *
1766   * @see win_is_writable()
1767   *
1768   * @param string $path Path to check for write-ability.
1769   * @return bool Whether the path is writable.
1770   */
1771  function wp_is_writable( $path ) {
1772      if ( 'WIN' === strtoupper( substr( PHP_OS, 0, 3 ) ) )
1773          return win_is_writable( $path );
1774      else
1775          return @is_writable( $path );
1776  }
1777  
1778  /**
1779   * Workaround for Windows bug in is_writable() function
1780   *
1781   * PHP has issues with Windows ACL's for determine if a
1782   * directory is writable or not, this works around them by
1783   * checking the ability to open files rather than relying
1784   * upon PHP to interprate the OS ACL.
1785   *
1786   * @since 2.8.0
1787   *
1788   * @see https://bugs.php.net/bug.php?id=27609
1789   * @see https://bugs.php.net/bug.php?id=30931
1790   *
1791   * @param string $path Windows path to check for write-ability.
1792   * @return bool Whether the path is writable.
1793   */
1794  function win_is_writable( $path ) {
1795  
1796      if ( $path[strlen( $path ) - 1] == '/' ) { // if it looks like a directory, check a random file within the directory
1797          return win_is_writable( $path . uniqid( mt_rand() ) . '.tmp');
1798      } elseif ( is_dir( $path ) ) { // If it's a directory (and not a file) check a random file within the directory
1799          return win_is_writable( $path . '/' . uniqid( mt_rand() ) . '.tmp' );
1800      }
1801      // check tmp file for read/write capabilities
1802      $should_delete_tmp_file = !file_exists( $path );
1803      $f = @fopen( $path, 'a' );
1804      if ( $f === false )
1805          return false;
1806      fclose( $f );
1807      if ( $should_delete_tmp_file )
1808          unlink( $path );
1809      return true;
1810  }
1811  
1812  /**
1813   * Retrieves uploads directory information.
1814   *
1815   * Same as wp_upload_dir() but "light weight" as it doesn't attempt to create the uploads directory.
1816   * Intended for use in themes, when only 'basedir' and 'baseurl' are needed, generally in all cases
1817   * when not uploading files.
1818   *
1819   * @since 4.5.0
1820   *
1821   * @see wp_upload_dir()
1822   *
1823   * @return array See wp_upload_dir() for description.
1824   */
1825  function wp_get_upload_dir() {
1826      return wp_upload_dir( null, false );
1827  }
1828  
1829  /**
1830   * Get an array containing the current upload directory's path and url.
1831   *
1832   * Checks the 'upload_path' option, which should be from the web root folder,
1833   * and if it isn't empty it will be used. If it is empty, then the path will be
1834   * 'WP_CONTENT_DIR/uploads'. If the 'UPLOADS' constant is defined, then it will
1835   * override the 'upload_path' option and 'WP_CONTENT_DIR/uploads' path.
1836   *
1837   * The upload URL path is set either by the 'upload_url_path' option or by using
1838   * the 'WP_CONTENT_URL' constant and appending '/uploads' to the path.
1839   *
1840   * If the 'uploads_use_yearmonth_folders' is set to true (checkbox if checked in
1841   * the administration settings panel), then the time will be used. The format
1842   * will be year first and then month.
1843   *
1844   * If the path couldn't be created, then an error will be returned with the key
1845   * 'error' containing the error message. The error suggests that the parent
1846   * directory is not writable by the server.
1847   *
1848   * On success, the returned array will have many indices:
1849   * 'path' - base directory and sub directory or full path to upload directory.
1850   * 'url' - base url and sub directory or absolute URL to upload directory.
1851   * 'subdir' - sub directory if uploads use year/month folders option is on.
1852   * 'basedir' - path without subdir.
1853   * 'baseurl' - URL path without subdir.
1854   * 'error' - false or error message.
1855   *
1856   * @since 2.0.0
1857   * @uses _wp_upload_dir()
1858   *
1859   * @staticvar array $cache
1860   * @staticvar array $tested_paths
1861   *
1862   * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1863   * @param bool   $create_dir Optional. Whether to check and create the uploads directory.
1864   *                           Default true for backward compatibility.
1865   * @param bool   $refresh_cache Optional. Whether to refresh the cache. Default false.
1866   * @return array See above for description.
1867   */
1868  function wp_upload_dir( $time = null, $create_dir = true, $refresh_cache = false ) {
1869      static $cache = array(), $tested_paths = array();
1870  
1871      $key = sprintf( '%d-%s', get_current_blog_id(), (string) $time );
1872  
1873      if ( $refresh_cache || empty( $cache[ $key ] ) ) {
1874          $cache[ $key ] = _wp_upload_dir( $time );
1875      }
1876  
1877      /**
1878       * Filters the uploads directory data.
1879       *
1880       * @since 2.0.0
1881       *
1882       * @param array $uploads Array of upload directory data with keys of 'path',
1883       *                       'url', 'subdir, 'basedir', and 'error'.
1884       */
1885      $uploads = apply_filters( 'upload_dir', $cache[ $key ] );
1886  
1887      if ( $create_dir ) {
1888          $path = $uploads['path'];
1889  
1890          if ( array_key_exists( $path, $tested_paths ) ) {
1891              $uploads['error'] = $tested_paths[ $path ];
1892          } else {
1893              if ( ! wp_mkdir_p( $path ) ) {
1894                  if ( 0 === strpos( $uploads['basedir'], ABSPATH ) ) {
1895                      $error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
1896                  } else {
1897                      $error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
1898                  }
1899  
1900                  $uploads['error'] = sprintf(
1901                      /* translators: %s: directory path */
1902                      __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
1903                      esc_html( $error_path )
1904                  );
1905              }
1906  
1907              $tested_paths[ $path ] = $uploads['error'];
1908          }
1909      }
1910  
1911      return $uploads;
1912  }
1913  
1914  /**
1915   * A non-filtered, non-cached version of wp_upload_dir() that doesn't check the path.
1916   *
1917   * @since 4.5.0
1918   * @access private
1919   *
1920   * @param string $time Optional. Time formatted in 'yyyy/mm'. Default null.
1921   * @return array See wp_upload_dir()
1922   */
1923  function _wp_upload_dir( $time = null ) {
1924      $siteurl = get_option( 'siteurl' );
1925      $upload_path = trim( get_option( 'upload_path' ) );
1926  
1927      if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
1928          $dir = WP_CONTENT_DIR . '/uploads';
1929      } elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
1930          // $dir is absolute, $upload_path is (maybe) relative to ABSPATH
1931          $dir = path_join( ABSPATH, $upload_path );
1932      } else {
1933          $dir = $upload_path;
1934      }
1935  
1936      if ( !$url = get_option( 'upload_url_path' ) ) {
1937          if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
1938              $url = WP_CONTENT_URL . '/uploads';
1939          else
1940              $url = trailingslashit( $siteurl ) . $upload_path;
1941      }
1942  
1943      /*
1944       * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
1945       * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
1946       */
1947      if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
1948          $dir = ABSPATH . UPLOADS;
1949          $url = trailingslashit( $siteurl ) . UPLOADS;
1950      }
1951  
1952      // If multisite (and if not the main site in a post-MU network)
1953      if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
1954  
1955          if ( ! get_site_option( 'ms_files_rewriting' ) ) {
1956              /*
1957               * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
1958               * straightforward: Append sites/%d if we're not on the main site (for post-MU
1959               * networks). (The extra directory prevents a four-digit ID from conflicting with
1960               * a year-based directory for the main site. But if a MU-era network has disabled
1961               * ms-files rewriting manually, they don't need the extra directory, as they never
1962               * had wp-content/uploads for the main site.)
1963               */
1964  
1965              if ( defined( 'MULTISITE' ) )
1966                  $ms_dir = '/sites/' . get_current_blog_id();
1967              else
1968                  $ms_dir = '/' . get_current_blog_id();
1969  
1970              $dir .= $ms_dir;
1971              $url .= $ms_dir;
1972  
1973          } elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
1974              /*
1975               * Handle the old-form ms-files.php rewriting if the network still has that enabled.
1976               * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
1977               * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
1978               *    there, and
1979               * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
1980               *    the original blog ID.
1981               *
1982               * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
1983               * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
1984               * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
1985               * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
1986               */
1987  
1988              if ( defined( 'BLOGUPLOADDIR' ) )
1989                  $dir = untrailingslashit( BLOGUPLOADDIR );
1990              else
1991                  $dir = ABSPATH . UPLOADS;
1992              $url = trailingslashit( $siteurl ) . 'files';
1993          }
1994      }
1995  
1996      $basedir = $dir;
1997      $baseurl = $url;
1998  
1999      $subdir = '';
2000      if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
2001          // Generate the yearly and monthly dirs
2002          if ( !$time )
2003              $time = current_time( 'mysql' );
2004          $y = substr( $time, 0, 4 );
2005          $m = substr( $time, 5, 2 );
2006          $subdir = "/$y/$m";
2007      }
2008  
2009      $dir .= $subdir;
2010      $url .= $subdir;
2011  
2012      return array(
2013          'path'    => $dir,
2014          'url'     => $url,
2015          'subdir'  => $subdir,
2016          'basedir' => $basedir,
2017          'baseurl' => $baseurl,
2018          'error'   => false,
2019      );
2020  }
2021  
2022  /**
2023   * Get a filename that is sanitized and unique for the given directory.
2024   *
2025   * If the filename is not unique, then a number will be added to the filename
2026   * before the extension, and will continue adding numbers until the filename is
2027   * unique.
2028   *
2029   * The callback is passed three parameters, the first one is the directory, the
2030   * second is the filename, and the third is the extension.
2031   *
2032   * @since 2.5.0
2033   *
2034   * @param string   $dir                      Directory.
2035   * @param string   $filename                 File name.
2036   * @param callable $unique_filename_callback Callback. Default null.
2037   * @return string New filename, if given wasn't unique.
2038   */
2039  function wp_unique_filename( $dir, $filename, $unique_filename_callback = null ) {
2040      // Sanitize the file name before we begin processing.
2041      $filename = sanitize_file_name($filename);
2042  
2043      // Separate the filename into a name and extension.
2044      $ext = pathinfo( $filename, PATHINFO_EXTENSION );
2045      $name = pathinfo( $filename, PATHINFO_BASENAME );
2046      if ( $ext ) {
2047          $ext = '.' . $ext;
2048      }
2049  
2050      // Edge case: if file is named '.ext', treat as an empty name.
2051      if ( $name === $ext ) {
2052          $name = '';
2053      }
2054  
2055      /*
2056       * Increment the file number until we have a unique file to save in $dir.
2057       * Use callback if supplied.
2058       */
2059      if ( $unique_filename_callback && is_callable( $unique_filename_callback ) ) {
2060          $filename = call_user_func( $unique_filename_callback, $dir, $name, $ext );
2061      } else {
2062          $number = '';
2063  
2064          // Change '.ext' to lower case.
2065          if ( $ext && strtolower($ext) != $ext ) {
2066              $ext2 = strtolower($ext);
2067              $filename2 = preg_replace( '|' . preg_quote($ext) . '$|', $ext2, $filename );
2068  
2069              // Check for both lower and upper case extension or image sub-sizes may be overwritten.
2070              while ( file_exists($dir . "/$filename") || file_exists($dir . "/$filename2") ) {
2071                  $new_number = (int) $number + 1;
2072                  $filename = str_replace( array( "-$number$ext", "$number$ext" ), "-$new_number$ext", $filename );
2073                  $filename2 = str_replace( array( "-$number$ext2", "$number$ext2" ), "-$new_number$ext2", $filename2 );
2074                  $number = $new_number;
2075              }
2076  
2077              /**
2078               * Filters the result when generating a unique file name.
2079               *
2080               * @since 4.5.0
2081               *
2082               * @param string        $filename                 Unique file name.
2083               * @param string        $ext                      File extension, eg. ".png".
2084               * @param string        $dir                      Directory path.
2085               * @param callable|null $unique_filename_callback Callback function that generates the unique file name.
2086               */
2087              return apply_filters( 'wp_unique_filename', $filename2, $ext, $dir, $unique_filename_callback );
2088          }
2089  
2090          while ( file_exists( $dir . "/$filename" ) ) {
2091              $new_number = (int) $number + 1;
2092              if ( '' == "$number$ext" ) {
2093                  $filename = "$filename-" . $new_number;
2094              } else {
2095                  $filename = str_replace( array( "-$number$ext", "$number$ext" ), "-" . $new_number . $ext, $filename );
2096              }
2097              $number = $new_number;
2098          }
2099      }
2100  
2101      /** This filter is documented in wp-includes/functions.php */
2102      return apply_filters( 'wp_unique_filename', $filename, $ext, $dir, $unique_filename_callback );
2103  }
2104  
2105  /**
2106   * Create a file in the upload folder with given content.
2107   *
2108   * If there is an error, then the key 'error' will exist with the error message.
2109   * If success, then the key 'file' will have the unique file path, the 'url' key
2110   * will have the link to the new file. and the 'error' key will be set to false.
2111   *
2112   * This function will not move an uploaded file to the upload folder. It will
2113   * create a new file with the content in $bits parameter. If you move the upload
2114   * file, read the content of the uploaded file, and then you can give the
2115   * filename and content to this function, which will add it to the upload
2116   * folder.
2117   *
2118   * The permissions will be set on the new file automatically by this function.
2119   *
2120   * @since 2.0.0
2121   *
2122   * @param string       $name       Filename.
2123   * @param null|string  $deprecated Never used. Set to null.
2124   * @param mixed        $bits       File content
2125   * @param string       $time       Optional. Time formatted in 'yyyy/mm'. Default null.
2126   * @return array
2127   */
2128  function wp_upload_bits( $name, $deprecated, $bits, $time = null ) {
2129      if ( !empty( $deprecated ) )
2130          _deprecated_argument( __FUNCTION__, '2.0.0' );
2131  
2132      if ( empty( $name ) )
2133          return array( 'error' => __( 'Empty filename' ) );
2134  
2135      $wp_filetype = wp_check_filetype( $name );
2136      if ( ! $wp_filetype['ext'] && ! current_user_can( 'unfiltered_upload' ) )
2137          return array( 'error' => __( 'Sorry, this file type is not permitted for security reasons.' ) );
2138  
2139      $upload = wp_upload_dir( $time );
2140  
2141      if ( $upload['error'] !== false )
2142          return $upload;
2143  
2144      /**
2145       * Filters whether to treat the upload bits as an error.
2146       *
2147       * Passing a non-array to the filter will effectively short-circuit preparing
2148       * the upload bits, returning that value instead.
2149       *
2150       * @since 3.0.0
2151       *
2152       * @param mixed $upload_bits_error An array of upload bits data, or a non-array error to return.
2153       */
2154      $upload_bits_error = apply_filters( 'wp_upload_bits', array( 'name' => $name, 'bits' => $bits, 'time' => $time ) );
2155      if ( !is_array( $upload_bits_error ) ) {
2156          $upload[ 'error' ] = $upload_bits_error;
2157          return $upload;
2158      }
2159  
2160      $filename = wp_unique_filename( $upload['path'], $name );
2161  
2162      $new_file = $upload['path'] . "/$filename";
2163      if ( ! wp_mkdir_p( dirname( $new_file ) ) ) {
2164          if ( 0 === strpos( $upload['basedir'], ABSPATH ) )
2165              $error_path = str_replace( ABSPATH, '', $upload['basedir'] ) . $upload['subdir'];
2166          else
2167              $error_path = basename( $upload['basedir'] ) . $upload['subdir'];
2168  
2169          $message = sprintf(
2170              /* translators: %s: directory path */
2171              __( 'Unable to create directory %s. Is its parent directory writable by the server?' ),
2172              $error_path
2173          );
2174          return array( 'error' => $message );
2175      }
2176  
2177      $ifp = @ fopen( $new_file, 'wb' );
2178      if ( ! $ifp )
2179          return array( 'error' => sprintf( __( 'Could not write file %s' ), $new_file ) );
2180  
2181      @fwrite( $ifp, $bits );
2182      fclose( $ifp );
2183      clearstatcache();
2184  
2185      // Set correct file permissions
2186      $stat = @ stat( dirname( $new_file ) );
2187      $perms = $stat['mode'] & 0007777;
2188      $perms = $perms & 0000666;
2189      @ chmod( $new_file, $perms );
2190      clearstatcache();
2191  
2192      // Compute the URL
2193      $url = $upload['url'] . "/$filename";
2194  
2195      /** This filter is documented in wp-admin/includes/file.php */
2196      return apply_filters( 'wp_handle_upload', array( 'file' => $new_file, 'url' => $url, 'type' => $wp_filetype['type'], 'error' => false ), 'sideload' );
2197  }
2198  
2199  /**
2200   * Retrieve the file type based on the extension name.
2201   *
2202   * @since 2.5.0
2203   *
2204   * @param string $ext The extension to search.
2205   * @return string|void The file type, example: audio, video, document, spreadsheet, etc.
2206   */
2207  function wp_ext2type( $ext ) {
2208      $ext = strtolower( $ext );
2209  
2210      $ext2type = wp_get_ext_types();
2211      foreach ( $ext2type as $type => $exts )
2212          if ( in_array( $ext, $exts ) )
2213              return $type;
2214  }
2215  
2216  /**
2217   * Retrieve the file type from the file name.
2218   *
2219   * You can optionally define the mime array, if needed.
2220   *
2221   * @since 2.0.4
2222   *
2223   * @param string $filename File name or path.
2224   * @param array  $mimes    Optional. Key is the file extension with value as the mime type.
2225   * @return array Values with extension first and mime type.
2226   */
2227  function wp_check_filetype( $filename, $mimes = null ) {
2228      if ( empty($mimes) )
2229          $mimes = get_allowed_mime_types();
2230      $type = false;
2231      $ext = false;
2232  
2233      foreach ( $mimes as $ext_preg => $mime_match ) {
2234          $ext_preg = '!\.(' . $ext_preg . ')$!i';
2235          if ( preg_match( $ext_preg, $filename, $ext_matches ) ) {
2236              $type = $mime_match;
2237              $ext = $ext_matches[1];
2238              break;
2239          }
2240      }
2241  
2242      return compact( 'ext', 'type' );
2243  }
2244  
2245  /**
2246   * Attempt to determine the real file type of a file.
2247   *
2248   * If unable to, the file name extension will be used to determine type.
2249   *
2250   * If it's determined that the extension does not match the file's real type,
2251   * then the "proper_filename" value will be set with a proper filename and extension.
2252   *
2253   * Currently this function only supports renaming images validated via wp_get_image_mime().
2254   *
2255   * @since 3.0.0
2256   *
2257   * @param string $file     Full path to the file.
2258   * @param string $filename The name of the file (may differ from $file due to $file being
2259   *                         in a tmp directory).
2260   * @param array   $mimes   Optional. Key is the file extension with value as the mime type.
2261   * @return array Values for the extension, MIME, and either a corrected filename or false
2262   *               if original $filename is valid.
2263   */
2264  function wp_check_filetype_and_ext( $file, $filename, $mimes = null ) {
2265      $proper_filename = false;
2266  
2267      // Do basic extension validation and MIME mapping
2268      $wp_filetype = wp_check_filetype( $filename, $mimes );
2269      $ext = $wp_filetype['ext'];
2270      $type = $wp_filetype['type'];
2271  
2272      // We can't do any further validation without a file to work with
2273      if ( ! file_exists( $file ) ) {
2274          return compact( 'ext', 'type', 'proper_filename' );
2275      }
2276  
2277      $real_mime = false;
2278  
2279      // Validate image types.
2280      if ( $type && 0 === strpos( $type, 'image/' ) ) {
2281  
2282          // Attempt to figure out what type of image it actually is
2283          $real_mime = wp_get_image_mime( $file );
2284  
2285          if ( $real_mime && $real_mime != $type ) {
2286              /**
2287               * Filters the list mapping image mime types to their respective extensions.
2288               *
2289               * @since 3.0.0
2290               *
2291               * @param  array $mime_to_ext Array of image mime types and their matching extensions.
2292               */
2293              $mime_to_ext = apply_filters( 'getimagesize_mimes_to_exts', array(
2294                  'image/jpeg' => 'jpg',
2295                  'image/png'  => 'png',
2296                  'image/gif'  => 'gif',
2297                  'image/bmp'  => 'bmp',
2298                  'image/tiff' => 'tif',
2299              ) );
2300  
2301              // Replace whatever is after the last period in the filename with the correct extension
2302              if ( ! empty( $mime_to_ext[ $real_mime ] ) ) {
2303                  $filename_parts = explode( '.', $filename );
2304                  array_pop( $filename_parts );
2305                  $filename_parts[] = $mime_to_ext[ $real_mime ];
2306                  $new_filename = implode( '.', $filename_parts );
2307  
2308                  if ( $new_filename != $filename ) {
2309                      $proper_filename = $new_filename; // Mark that it changed
2310                  }
2311                  // Redefine the extension / MIME
2312                  $wp_filetype = wp_check_filetype( $new_filename, $mimes );
2313                  $ext = $wp_filetype['ext'];
2314                  $type = $wp_filetype['type'];
2315              } else {
2316                  // Reset $real_mime and try validating again.
2317                  $real_mime = false;
2318              }
2319          }
2320      }
2321  
2322      // Validate files that didn't get validated during previous checks.
2323      if ( $type && ! $real_mime && extension_loaded( 'fileinfo' ) ) {
2324          $finfo = finfo_open( FILEINFO_MIME_TYPE );
2325          $real_mime = finfo_file( $finfo, $file );
2326          finfo_close( $finfo );
2327  
2328          /*
2329           * If $real_mime doesn't match what we're expecting, we need to do some extra
2330           * vetting of application mime types to make sure this type of file is allowed.
2331           * Other mime types are assumed to be safe, but should be considered unverified.
2332           */
2333          if ( $real_mime && ( $real_mime !== $type ) && ( 0 === strpos( $real_mime, 'application' ) ) ) {
2334              $allowed = get_allowed_mime_types();
2335  
2336              if ( ! in_array( $real_mime, $allowed ) ) {
2337                  $type = $ext = false;
2338              }
2339          }
2340      }
2341  
2342      /**
2343       * Filters the "real" file type of the given file.
2344       *
2345       * @since 3.0.0
2346       *
2347       * @param array  $wp_check_filetype_and_ext File data array containing 'ext', 'type', and
2348       *                                          'proper_filename' keys.
2349       * @param string $file                      Full path to the file.
2350       * @param string $filename                  The name of the file (may differ from $file due to
2351       *                                          $file being in a tmp directory).
2352       * @param array  $mimes                     Key is the file extension with value as the mime type.
2353       */
2354      return apply_filters( 'wp_check_filetype_and_ext', compact( 'ext', 'type', 'proper_filename' ), $file, $filename, $mimes );
2355  }
2356  
2357  /**
2358   * Returns the real mime type of an image file.
2359   *
2360   * This depends on exif_imagetype() or getimagesize() to determine real mime types.
2361   *
2362   * @since 4.7.1
2363   *
2364   * @param string $file Full path to the file.
2365   * @return string|false The actual mime type or false if the type cannot be determined.
2366   */
2367  function wp_get_image_mime( $file ) {
2368      /*
2369       * Use exif_imagetype() to check the mimetype if available or fall back to
2370       * getimagesize() if exif isn't avaialbe. If either function throws an Exception
2371       * we assume the file could not be validated.
2372       */
2373      try {
2374          if ( is_callable( 'exif_imagetype' ) ) {
2375              $imagetype = exif_imagetype( $file );
2376              $mime = ( $imagetype ) ? image_type_to_mime_type( $imagetype ) : false;
2377          } elseif ( function_exists( 'getimagesize' ) ) {
2378              $imagesize = getimagesize( $file );
2379              $mime = ( isset( $imagesize['mime'] ) ) ? $imagesize['mime'] : false;
2380          } else {
2381              $mime = false;
2382          }
2383      } catch ( Exception $e ) {
2384          $mime = false;
2385      }
2386  
2387      return $mime;
2388  }
2389  
2390  /**
2391   * Retrieve list of mime types and file extensions.
2392   *
2393   * @since 3.5.0
2394   * @since 4.2.0 Support was added for GIMP (xcf) files.
2395   *
2396   * @return array Array of mime types keyed by the file extension regex corresponding to those types.
2397   */
2398  function wp_get_mime_types() {
2399      /**
2400       * Filters the list of mime types and file extensions.
2401       *
2402       * This filter should be used to add, not remove, mime types. To remove
2403       * mime types, use the {@see 'upload_mimes'} filter.
2404       *
2405       * @since 3.5.0
2406       *
2407       * @param array $wp_get_mime_types Mime types keyed by the file extension regex
2408       *                                 corresponding to those types.
2409       */
2410      return apply_filters( 'mime_types', array(
2411      // Image formats.
2412      'jpg|jpeg|jpe' => 'image/jpeg',
2413      'gif' => 'image/gif',
2414      'png' => 'image/png',
2415      'bmp' => 'image/bmp',
2416      'tiff|tif' => 'image/tiff',
2417      'ico' => 'image/x-icon',
2418      // Video formats.
2419      'asf|asx' => 'video/x-ms-asf',
2420      'wmv' => 'video/x-ms-wmv',
2421      'wmx' => 'video/x-ms-wmx',
2422      'wm' => 'video/x-ms-wm',
2423      'avi' => 'video/avi',
2424      'divx' => 'video/divx',
2425      'flv' => 'video/x-flv',
2426      'mov|qt' => 'video/quicktime',
2427      'mpeg|mpg|mpe' => 'video/mpeg',
2428      'mp4|m4v' => 'video/mp4',
2429      'ogv' => 'video/ogg',
2430      'webm' => 'video/webm',
2431      'mkv' => 'video/x-matroska',
2432      '3gp|3gpp' => 'video/3gpp', // Can also be audio
2433      '3g2|3gp2' => 'video/3gpp2', // Can also be audio
2434      // Text formats.
2435      'txt|asc|c|cc|h|srt' => 'text/plain',
2436      'csv' => 'text/csv',
2437      'tsv' => 'text/tab-separated-values',
2438      'ics' => 'text/calendar',
2439      'rtx' => 'text/richtext',
2440      'css' => 'text/css',
2441      'htm|html' => 'text/html',
2442      'vtt' => 'text/vtt',
2443      'dfxp' => 'application/ttaf+xml',
2444      // Audio formats.
2445      'mp3|m4a|m4b' => 'audio/mpeg',
2446      'ra|ram' => 'audio/x-realaudio',
2447      'wav' => 'audio/wav',
2448      'ogg|oga' => 'audio/ogg',
2449      'mid|midi' => 'audio/midi',
2450      'wma' => 'audio/x-ms-wma',
2451      'wax' => 'audio/x-ms-wax',
2452      'mka' => 'audio/x-matroska',
2453      // Misc application formats.
2454      'rtf' => 'application/rtf',
2455      'js' => 'application/javascript',
2456      'pdf' => 'application/pdf',
2457      'swf' => 'application/x-shockwave-flash',
2458      'class' => 'application/java',
2459      'tar' => 'application/x-tar',
2460      'zip' => 'application/zip',
2461      'gz|gzip' => 'application/x-gzip',
2462      'rar' => 'application/rar',
2463      '7z' => 'application/x-7z-compressed',
2464      'exe' => 'application/x-msdownload',
2465      'psd' => 'application/octet-stream',
2466      'xcf' => 'application/octet-stream',
2467      // MS Office formats.
2468      'doc' => 'application/msword',
2469      'pot|pps|ppt' => 'application/vnd.ms-powerpoint',
2470      'wri' => 'application/vnd.ms-write',
2471      'xla|xls|xlt|xlw' => 'application/vnd.ms-excel',
2472      'mdb' => 'application/vnd.ms-access',
2473      'mpp' => 'application/vnd.ms-project',
2474      'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2475      'docm' => 'application/vnd.ms-word.document.macroEnabled.12',
2476      'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
2477      'dotm' => 'application/vnd.ms-word.template.macroEnabled.12',
2478      'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2479      'xlsm' => 'application/vnd.ms-excel.sheet.macroEnabled.12',
2480      'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
2481      'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
2482      'xltm' => 'application/vnd.ms-excel.template.macroEnabled.12',
2483      'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
2484      'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2485      'pptm' => 'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
2486      'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
2487      'ppsm' => 'application/vnd.ms-powerpoint.slideshow.macroEnabled.12',
2488      'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
2489      'potm' => 'application/vnd.ms-powerpoint.template.macroEnabled.12',
2490      'ppam' => 'application/vnd.ms-powerpoint.addin.macroEnabled.12',
2491      'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
2492      'sldm' => 'application/vnd.ms-powerpoint.slide.macroEnabled.12',
2493      'onetoc|onetoc2|onetmp|onepkg' => 'application/onenote',
2494      'oxps' => 'application/oxps',
2495      'xps' => 'application/vnd.ms-xpsdocument',
2496      // OpenOffice formats.
2497      'odt' => 'application/vnd.oasis.opendocument.text',
2498      'odp' => 'application/vnd.oasis.opendocument.presentation',
2499      'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
2500      'odg' => 'application/vnd.oasis.opendocument.graphics',
2501      'odc' => 'application/vnd.oasis.opendocument.chart',
2502      'odb' => 'application/vnd.oasis.opendocument.database',
2503      'odf' => 'application/vnd.oasis.opendocument.formula',
2504      // WordPerfect formats.
2505      'wp|wpd' => 'application/wordperfect',
2506      // iWork formats.
2507      'key' => 'application/vnd.apple.keynote',
2508      'numbers' => 'application/vnd.apple.numbers',
2509      'pages' => 'application/vnd.apple.pages',
2510      ) );
2511  }
2512  
2513  /**
2514   * Retrieves the list of common file extensions and their types.
2515   *
2516   * @since 4.6.0
2517   *
2518   * @return array Array of file extensions types keyed by the type of file.
2519   */
2520  function wp_get_ext_types() {
2521  
2522      /**
2523       * Filters file type based on the extension name.
2524       *
2525       * @since 2.5.0
2526       *
2527       * @see wp_ext2type()
2528       *
2529       * @param array $ext2type Multi-dimensional array with extensions for a default set
2530       *                        of file types.
2531       */
2532      return apply_filters( 'ext2type', array(
2533          'image'       => array( 'jpg', 'jpeg', 'jpe',  'gif',  'png',  'bmp',   'tif',  'tiff', 'ico' ),
2534          'audio'       => array( 'aac', 'ac3',  'aif',  'aiff', 'm3a',  'm4a',   'm4b',  'mka',  'mp1',  'mp2',  'mp3', 'ogg', 'oga', 'ram', 'wav', 'wma' ),
2535          'video'       => array( '3g2',  '3gp', '3gpp', 'asf', 'avi',  'divx', 'dv',   'flv',  'm4v',   'mkv',  'mov',  'mp4',  'mpeg', 'mpg', 'mpv', 'ogm', 'ogv', 'qt',  'rm', 'vob', 'wmv' ),
2536          'document'    => array( 'doc', 'docx', 'docm', 'dotm', 'odt',  'pages', 'pdf',  'xps',  'oxps', 'rtf',  'wp', 'wpd', 'psd', 'xcf' ),
2537          'spreadsheet' => array( 'numbers',     'ods',  'xls',  'xlsx', 'xlsm',  'xlsb' ),
2538          'interactive' => array( 'swf', 'key',  'ppt',  'pptx', 'pptm', 'pps',   'ppsx', 'ppsm', 'sldx', 'sldm', 'odp' ),
2539          'text'        => array( 'asc', 'csv',  'tsv',  'txt' ),
2540          'archive'     => array( 'bz2', 'cab',  'dmg',  'gz',   'rar',  'sea',   'sit',  'sqx',  'tar',  'tgz',  'zip', '7z' ),
2541          'code'        => array( 'css', 'htm',  'html', 'php',  'js' ),
2542      ) );
2543  }
2544  
2545  /**
2546   * Retrieve list of allowed mime types and file extensions.
2547   *
2548   * @since 2.8.6
2549   *
2550   * @param int|WP_User $user Optional. User to check. Defaults to current user.
2551   * @return array Array of mime types keyed by the file extension regex corresponding
2552   *               to those types.
2553   */
2554  function get_allowed_mime_types( $user = null ) {
2555      $t = wp_get_mime_types();
2556  
2557      unset( $t['swf'], $t['exe'] );
2558      if ( function_exists( 'current_user_can' ) )
2559          $unfiltered = $user ? user_can( $user, 'unfiltered_html' ) : current_user_can( 'unfiltered_html' );
2560  
2561      if ( empty( $unfiltered ) )
2562          unset( $t['htm|html'] );
2563  
2564      /**
2565       * Filters list of allowed mime types and file extensions.
2566       *
2567       * @since 2.0.0
2568       *
2569       * @param array            $t    Mime types keyed by the file extension regex corresponding to
2570       *                               those types. 'swf' and 'exe' removed from full list. 'htm|html' also
2571       *                               removed depending on '$user' capabilities.
2572       * @param int|WP_User|null $user User ID, User object or null if not provided (indicates current user).
2573       */
2574      return apply_filters( 'upload_mimes', $t, $user );
2575  }
2576  
2577  /**
2578   * Display "Are You Sure" message to confirm the action being taken.
2579   *
2580   * If the action has the nonce explain message, then it will be displayed
2581   * along with the "Are you sure?" message.
2582   *
2583   * @since 2.0.4
2584   *
2585   * @param string $action The nonce action.
2586   */
2587  function wp_nonce_ays( $action ) {
2588      if ( 'log-out' == $action ) {
2589          $html = sprintf(
2590              /* translators: %s: site name */
2591              __( 'You are attempting to log out of %s' ),
2592              get_bloginfo( 'name' )
2593          );
2594          $html .= '</p><p>';
2595          $redirect_to = isset( $_REQUEST['redirect_to'] ) ? $_REQUEST['redirect_to'] : '';
2596          $html .= sprintf(
2597              /* translators: %s: logout URL */
2598              __( 'Do you really want to <a href="%s">log out</a>?' ),
2599              wp_logout_url( $redirect_to )
2600          );
2601      } else {
2602          $html = __( 'Are you sure you want to do this?' );
2603          if ( wp_get_referer() ) {
2604              $html .= '</p><p>';
2605              $html .= sprintf( '<a href="%s">%s</a>',
2606                  esc_url( remove_query_arg( 'updated', wp_get_referer() ) ),
2607                  __( 'Please try again.' )
2608              );
2609          }
2610      }
2611  
2612      wp_die( $html, __( 'WordPress Failure Notice' ), 403 );
2613  }
2614  
2615  /**
2616   * Kill WordPress execution and display HTML message with error message.
2617   *
2618   * This function complements the `die()` PHP function. The difference is that
2619   * HTML will be displayed to the user. It is recommended to use this function
2620   * only when the execution should not continue any further. It is not recommended
2621   * to call this function very often, and try to handle as many errors as possible
2622   * silently or more gracefully.
2623   *
2624   * As a shorthand, the desired HTTP response code may be passed as an integer to
2625   * the `$title` parameter (the default title would apply) or the `$args` parameter.
2626   *
2627   * @since 2.0.4
2628   * @since 4.1.0 The `$title` and `$args` parameters were changed to optionally accept
2629   *              an integer to be used as the response code.
2630   *
2631   * @param string|WP_Error  $message Optional. Error message. If this is a WP_Error object,
2632   *                                  and not an Ajax or XML-RPC request, the error's messages are used.
2633   *                                  Default empty.
2634   * @param string|int       $title   Optional. Error title. If `$message` is a `WP_Error` object,
2635   *                                  error data with the key 'title' may be used to specify the title.
2636   *                                  If `$title` is an integer, then it is treated as the response
2637   *                                  code. Default empty.
2638   * @param string|array|int $args {
2639   *     Optional. Arguments to control behavior. If `$args` is an integer, then it is treated
2640   *     as the response code. Default empty array.
2641   *
2642   *     @type int    $response       The HTTP response code. Default 200 for Ajax requests, 500 otherwise.
2643   *     @type bool   $back_link      Whether to include a link to go back. Default false.
2644   *     @type string $text_direction The text direction. This is only useful internally, when WordPress
2645   *                                  is still loading and the site's locale is not set up yet. Accepts 'rtl'.
2646   *                                  Default is the value of is_rtl().
2647   * }
2648   */
2649  function wp_die( $message = '', $title = '', $args = array() ) {
2650  
2651      if ( is_int( $args ) ) {
2652          $args = array( 'response' => $args );
2653      } elseif ( is_int( $title ) ) {
2654          $args  = array( 'response' => $title );
2655          $title = '';
2656      }
2657  
2658      if ( wp_doing_ajax() ) {
2659          /**
2660           * Filters the callback for killing WordPress execution for Ajax requests.
2661           *
2662           * @since 3.4.0
2663           *
2664           * @param callable $function Callback function name.
2665           */
2666          $function = apply_filters( 'wp_die_ajax_handler', '_ajax_wp_die_handler' );
2667      } elseif ( defined( 'XMLRPC_REQUEST' ) && XMLRPC_REQUEST ) {
2668          /**
2669           * Filters the callback for killing WordPress execution for XML-RPC requests.
2670           *
2671           * @since 3.4.0
2672           *
2673           * @param callable $function Callback function name.
2674           */
2675          $function = apply_filters( 'wp_die_xmlrpc_handler', '_xmlrpc_wp_die_handler' );
2676      } else {
2677          /**
2678           * Filters the callback for killing WordPress execution for all non-Ajax, non-XML-RPC requests.
2679           *
2680           * @since 3.0.0
2681           *
2682           * @param callable $function Callback function name.
2683           */
2684          $function = apply_filters( 'wp_die_handler', '_default_wp_die_handler' );
2685      }
2686  
2687      call_user_func( $function, $message, $title, $args );
2688  }
2689  
2690  /**
2691   * Kills WordPress execution and display HTML message with error message.
2692   *
2693   * This is the default handler for wp_die if you want a custom one for your
2694   * site then you can overload using the {@see 'wp_die_handler'} filter in wp_die().
2695   *
2696   * @since 3.0.0
2697   * @access private
2698   *
2699   * @param string|WP_Error $message Error message or WP_Error object.
2700   * @param string          $title   Optional. Error title. Default empty.
2701   * @param string|array    $args    Optional. Arguments to control behavior. Default empty array.
2702   */
2703  function _default_wp_die_handler( $message, $title = '', $args = array() ) {
2704      $defaults = array( 'response' => 500 );
2705      $r = wp_parse_args($args, $defaults);
2706  
2707      $have_gettext = function_exists('__');
2708  
2709      if ( function_exists( 'is_wp_error' ) && is_wp_error( $message ) ) {
2710          if ( empty( $title ) ) {
2711              $error_data = $message->get_error_data();
2712              if ( is_array( $error_data ) && isset( $error_data['title'] ) )
2713                  $title = $error_data['title'];
2714          }
2715          $errors = $message->get_error_messages();
2716          switch ( count( $errors ) ) {
2717          case 0 :
2718              $message = '';
2719              break;
2720          case 1 :
2721              $message = "<p>{$errors[0]}</p>";
2722              break;
2723          default :
2724              $message = "<ul>\n\t\t<li>" . join( "</li>\n\t\t<li>", $errors ) . "</li>\n\t</ul>";
2725              break;
2726          }
2727      } elseif ( is_string( $message ) ) {
2728          $message = "<p>$message</p>";
2729      }
2730  
2731      if ( isset( $r['back_link'] ) && $r['back_link'] ) {
2732          $back_text = $have_gettext? __('&laquo; Back') : '&laquo; Back';
2733          $message .= "\n<p><a href='javascript:history.back()'>$back_text</a></p>";
2734      }
2735  
2736      if ( ! did_action( 'admin_head' ) ) :
2737          if ( !headers_sent() ) {
2738              status_header( $r['response'] );
2739              nocache_headers();
2740              header( 'Content-Type: text/html; charset=utf-8' );
2741          }
2742  
2743          if ( empty($title) )
2744              $title = $have_gettext ? __('WordPress &rsaquo; Error') : 'WordPress &rsaquo; Error';
2745  
2746          $text_direction = 'ltr';
2747          if ( isset($r['text_direction']) && 'rtl' == $r['text_direction'] )
2748              $text_direction = 'rtl';
2749          elseif ( function_exists( 'is_rtl' ) && is_rtl() )
2750              $text_direction = 'rtl';
2751  ?>
2752  <!DOCTYPE html>
2753  <!-- Ticket #11289, IE bug fix: always pad the error page with enough characters such that it is greater than 512 bytes, even after gzip compression abcdefghijklmnopqrstuvwxyz1234567890aabbccddeeffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz11223344556677889900abacbcbdcdcededfefegfgfhghgihihjijikjkjlklkmlmlnmnmononpopoqpqprqrqsrsrtstsubcbcdcdedefefgfabcadefbghicjkldmnoepqrfstugvwxhyz1i234j567k890laabmbccnddeoeffpgghqhiirjjksklltmmnunoovppqwqrrxsstytuuzvvw0wxx1yyz2z113223434455666777889890091abc2def3ghi4jkl5mno6pqr7stu8vwx9yz11aab2bcc3dd4ee5ff6gg7hh8ii9j0jk1kl2lmm3nnoo4p5pq6qrr7ss8tt9uuvv0wwx1x2yyzz13aba4cbcb5dcdc6dedfef8egf9gfh0ghg1ihi2hji3jik4jkj5lkl6kml7mln8mnm9ono
2754  -->
2755  <html xmlns="http://www.w3.org/1999/xhtml" <?php if ( function_exists( 'language_attributes' ) && function_exists( 'is_rtl' ) ) language_attributes(); else echo "dir='$text_direction'"; ?>>
2756  <head>
2757      <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
2758      <meta name="viewport" content="width=device-width">
2759      <?php
2760      if ( function_exists( 'wp_no_robots' ) ) {
2761          wp_no_robots();
2762      }
2763      ?>
2764      <title><?php echo $title ?></title>
2765      <style type="text/css">
2766          html {
2767              background: #f1f1f1;
2768          }
2769          body {
2770              background: #fff;
2771              color: #444;
2772              font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
2773              margin: 2em auto;
2774              padding: 1em 2em;
2775              max-width: 700px;
2776              -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2777              box-shadow: 0 1px 3px rgba(0,0,0,0.13);
2778          }
2779          h1 {
2780              border-bottom: 1px solid #dadada;
2781              clear: both;
2782              color: #666;
2783              font-size: 24px;
2784              margin: 30px 0 0 0;
2785              padding: 0;
2786              padding-bottom: 7px;
2787          }
2788          #error-page {
2789              margin-top: 50px;
2790          }
2791          #error-page p {
2792              font-size: 14px;
2793              line-height: 1.5;
2794              margin: 25px 0 20px;
2795          }
2796          #error-page code {
2797              font-family: Consolas, Monaco, monospace;
2798          }
2799          ul li {
2800              margin-bottom: 10px;
2801              font-size: 14px ;
2802          }
2803          a {
2804              color: #0073aa;
2805          }
2806          a:hover,
2807          a:active {
2808              color: #00a0d2;
2809          }
2810          a:focus {
2811              color: #124964;
2812              -webkit-box-shadow:
2813                  0 0 0 1px #5b9dd9,
2814                  0 0 2px 1px rgba(30, 140, 190, .8);
2815              box-shadow:
2816                  0 0 0 1px #5b9dd9,
2817                  0 0 2px 1px rgba(30, 140, 190, .8);
2818              outline: none;
2819          }
2820          .button {
2821              background: #f7f7f7;
2822              border: 1px solid #ccc;
2823              color: #555;
2824              display: inline-block;
2825              text-decoration: none;
2826              font-size: 13px;
2827              line-height: 26px;
2828              height: 28px;
2829              margin: 0;
2830              padding: 0 10px 1px;
2831              cursor: pointer;
2832              -webkit-border-radius: 3px;
2833              -webkit-appearance: none;
2834              border-radius: 3px;
2835              white-space: nowrap;
2836              -webkit-box-sizing: border-box;
2837              -moz-box-sizing:    border-box;
2838              box-sizing:         border-box;
2839  
2840              -webkit-box-shadow: 0 1px 0 #ccc;
2841              box-shadow: 0 1px 0 #ccc;
2842               vertical-align: top;
2843          }
2844  
2845          .button.button-large {
2846              height: 30px;
2847              line-height: 28px;
2848              padding: 0 12px 2px;
2849          }
2850  
2851          .button:hover,
2852          .button:focus {
2853              background: #fafafa;
2854              border-color: #999;
2855              color: #23282d;
2856          }
2857  
2858          .button:focus  {
2859              border-color: #5b9dd9;
2860              -webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
2861              box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
2862              outline: none;
2863          }
2864  
2865          .button:active {
2866              background: #eee;
2867              border-color: #999;
2868               -webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2869               box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
2870               -webkit-transform: translateY(1px);
2871               -ms-transform: translateY(1px);
2872               transform: translateY(1px);
2873          }
2874  
2875          <?php
2876          if ( 'rtl' == $text_direction ) {
2877              echo 'body { font-family: Tahoma, Arial; }';
2878          }
2879          ?>
2880      </style>
2881  </head>
2882  <body id="error-page">
2883  <?php endif; // ! did_action( 'admin_head' ) ?>
2884      <?php echo $message; ?>
2885  </body>
2886  </html>
2887  <?php
2888      die();
2889  }
2890  
2891  /**
2892   * Kill WordPress execution and display XML message with error message.
2893   *
2894   * This is the handler for wp_die when processing XMLRPC requests.
2895   *
2896   * @since 3.2.0
2897   * @access private
2898   *
2899   * @global wp_xmlrpc_server $wp_xmlrpc_server
2900   *
2901   * @param string       $message Error message.
2902   * @param string       $title   Optional. Error title. Default empty.
2903   * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2904   */
2905  function _xmlrpc_wp_die_handler( $message, $title = '', $args = array() ) {
2906      global $wp_xmlrpc_server;
2907      $defaults = array( 'response' => 500 );
2908  
2909      $r = wp_parse_args($args, $defaults);
2910  
2911      if ( $wp_xmlrpc_server ) {
2912          $error = new IXR_Error( $r['response'] , $message);
2913          $wp_xmlrpc_server->output( $error->getXml() );
2914      }
2915      die();
2916  }
2917  
2918  /**
2919   * Kill WordPress ajax execution.
2920   *
2921   * This is the handler for wp_die when processing Ajax requests.
2922   *
2923   * @since 3.4.0
2924   * @access private
2925   *
2926   * @param string       $message Error message.
2927   * @param string       $title   Optional. Error title (unused). Default empty.
2928   * @param string|array $args    Optional. Arguments to control behavior. Default empty array.
2929   */
2930  function _ajax_wp_die_handler( $message, $title = '', $args = array() ) {
2931      $defaults = array(
2932          'response' => 200,
2933      );
2934      $r = wp_parse_args( $args, $defaults );
2935  
2936      if ( ! headers_sent() && null !== $r['response'] ) {
2937          status_header( $r['response'] );
2938      }
2939  
2940      if ( is_scalar( $message ) )
2941          die( (string) $message );
2942      die( '0' );
2943  }
2944  
2945  /**
2946   * Kill WordPress execution.
2947   *
2948   * This is the handler for wp_die when processing APP requests.
2949   *
2950   * @since 3.4.0
2951   * @access private
2952   *
2953   * @param string $message Optional. Response to print. Default empty.
2954   */
2955  function _scalar_wp_die_handler( $message = '' ) {
2956      if ( is_scalar( $message ) )
2957          die( (string) $message );
2958      die();
2959  }
2960  
2961  /**
2962   * Encode a variable into JSON, with some sanity checks.
2963   *
2964   * @since 4.1.0
2965   *
2966   * @param mixed $data    Variable (usually an array or object) to encode as JSON.
2967   * @param int   $options Optional. Options to be passed to json_encode(). Default 0.
2968   * @param int   $depth   Optional. Maximum depth to walk through $data. Must be
2969   *                       greater than 0. Default 512.
2970   * @return string|false The JSON encoded string, or false if it cannot be encoded.
2971   */
2972  function wp_json_encode( $data, $options = 0, $depth = 512 ) {
2973      /*
2974       * json_encode() has had extra params added over the years.
2975       * $options was added in 5.3, and $depth in 5.5.
2976       * We need to make sure we call it with the correct arguments.
2977       */
2978      if ( version_compare( PHP_VERSION, '5.5', '>=' ) ) {
2979          $args = array( $data, $options, $depth );
2980      } elseif ( version_compare( PHP_VERSION, '5.3', '>=' ) ) {
2981          $args = array( $data, $options );
2982      } else {
2983          $args = array( $data );
2984      }
2985  
2986      // Prepare the data for JSON serialization.
2987      $args[0] = _wp_json_prepare_data( $data );
2988  
2989      $json = @call_user_func_array( 'json_encode', $args );
2990  
2991      // If json_encode() was successful, no need to do more sanity checking.
2992      // ... unless we're in an old version of PHP, and json_encode() returned
2993      // a string containing 'null'. Then we need to do more sanity checking.
2994      if ( false !== $json && ( version_compare( PHP_VERSION, '5.5', '>=' ) || false === strpos( $json, 'null' ) ) )  {
2995          return $json;
2996      }
2997  
2998      try {
2999          $args[0] = _wp_json_sanity_check( $data, $depth );
3000      } catch ( Exception $e ) {
3001          return false;
3002      }
3003  
3004      return call_user_func_array( 'json_encode', $args );
3005  }
3006  
3007  /**
3008   * Perform sanity checks on data that shall be encoded to JSON.
3009   *
3010   * @ignore
3011   * @since 4.1.0
3012   * @access private
3013   *
3014   * @see wp_json_encode()
3015   *
3016   * @param mixed $data  Variable (usually an array or object) to encode as JSON.
3017   * @param int   $depth Maximum depth to walk through $data. Must be greater than 0.
3018   * @return mixed The sanitized data that shall be encoded to JSON.
3019   */
3020  function _wp_json_sanity_check( $data, $depth ) {
3021      if ( $depth < 0 ) {
3022          throw new Exception( 'Reached depth limit' );
3023      }
3024  
3025      if ( is_array( $data ) ) {
3026          $output = array();
3027          foreach ( $data as $id => $el ) {
3028              // Don't forget to sanitize the ID!
3029              if ( is_string( $id ) ) {
3030                  $clean_id = _wp_json_convert_string( $id );
3031              } else {
3032                  $clean_id = $id;
3033              }
3034  
3035              // Check the element type, so that we're only recursing if we really have to.
3036              if ( is_array( $el ) || is_object( $el ) ) {
3037                  $output[ $clean_id ] = _wp_json_sanity_check( $el, $depth - 1 );
3038              } elseif ( is_string( $el ) ) {
3039                  $output[ $clean_id ] = _wp_json_convert_string( $el );
3040              } else {
3041                  $output[ $clean_id ] = $el;
3042              }
3043          }
3044      } elseif ( is_object( $data ) ) {
3045          $output = new stdClass;
3046          foreach ( $data as $id => $el ) {
3047              if ( is_string( $id ) ) {
3048                  $clean_id = _wp_json_convert_string( $id );
3049              } else {
3050                  $clean_id = $id;
3051              }
3052  
3053              if ( is_array( $el ) || is_object( $el ) ) {
3054                  $output->$clean_id = _wp_json_sanity_check( $el, $depth - 1 );
3055              } elseif ( is_string( $el ) ) {
3056                  $output->$clean_id = _wp_json_convert_string( $el );
3057              } else {
3058                  $output->$clean_id = $el;
3059              }
3060          }
3061      } elseif ( is_string( $data ) ) {
3062          return _wp_json_convert_string( $data );
3063      } else {
3064          return $data;
3065      }
3066  
3067      return $output;
3068  }
3069  
3070  /**
3071   * Convert a string to UTF-8, so that it can be safely encoded to JSON.
3072   *
3073   * @ignore
3074   * @since 4.1.0
3075   * @access private
3076   *
3077   * @see _wp_json_sanity_check()
3078   *
3079   * @staticvar bool $use_mb
3080   *
3081   * @param string $string The string which is to be converted.
3082   * @return string The checked string.
3083   */
3084  function _wp_json_convert_string( $string ) {
3085      static $use_mb = null;
3086      if ( is_null( $use_mb ) ) {
3087          $use_mb = function_exists( 'mb_convert_encoding' );
3088      }
3089  
3090      if ( $use_mb ) {
3091          $encoding = mb_detect_encoding( $string, mb_detect_order(), true );
3092          if ( $encoding ) {
3093              return mb_convert_encoding( $string, 'UTF-8', $encoding );
3094          } else {
3095              return mb_convert_encoding( $string, 'UTF-8', 'UTF-8' );
3096          }
3097      } else {
3098          return wp_check_invalid_utf8( $string, true );
3099      }
3100  }
3101  
3102  /**
3103   * Prepares response data to be serialized to JSON.
3104   *
3105   * This supports the JsonSerializable interface for PHP 5.2-5.3 as well.
3106   *
3107   * @ignore
3108   * @since 4.4.0
3109   * @access private
3110   *
3111   * @param mixed $data Native representation.
3112   * @return bool|int|float|null|string|array Data ready for `json_encode()`.
3113   */
3114  function _wp_json_prepare_data( $data ) {
3115      if ( ! defined( 'WP_JSON_SERIALIZE_COMPATIBLE' ) || WP_JSON_SERIALIZE_COMPATIBLE === false ) {
3116          return $data;
3117      }
3118  
3119      switch ( gettype( $data ) ) {
3120          case 'boolean':
3121          case 'integer':
3122          case 'double':
3123          case 'string':
3124          case 'NULL':
3125              // These values can be passed through.
3126              return $data;
3127  
3128          case 'array':
3129              // Arrays must be mapped in case they also return objects.
3130              return array_map( '_wp_json_prepare_data', $data );
3131  
3132          case 'object':
3133              // If this is an incomplete object (__PHP_Incomplete_Class), bail.
3134              if ( ! is_object( $data ) ) {
3135                  return null;
3136              }
3137  
3138              if ( $data instanceof JsonSerializable ) {
3139                  $data = $data->jsonSerialize();
3140              } else {
3141                  $data = get_object_vars( $data );
3142              }
3143  
3144              // Now, pass the array (or whatever was returned from jsonSerialize through).
3145              return _wp_json_prepare_data( $data );
3146  
3147          default:
3148              return null;
3149      }
3150  }
3151  
3152  /**
3153   * Send a JSON response back to an Ajax request.
3154   *
3155   * @since 3.5.0
3156   * @since 4.7.0 The `$status_code` parameter was added.
3157   *
3158   * @param mixed $response    Variable (usually an array or object) to encode as JSON,
3159   *                           then print and die.
3160   * @param int   $status_code The HTTP status code to output.
3161   */
3162  function wp_send_json( $response, $status_code = null ) {
3163      @header( 'Content-Type: application/json; charset=' . get_option( 'blog_charset' ) );
3164      if ( null !== $status_code ) {
3165          status_header( $status_code );
3166      }
3167      echo wp_json_encode( $response );
3168  
3169      if ( wp_doing_ajax() ) {
3170          wp_die( '', '', array(
3171              'response' => null,
3172          ) );
3173      } else {
3174          die;
3175      }
3176  }
3177  
3178  /**
3179   * Send a JSON response back to an Ajax request, indicating success.
3180   *
3181   * @since 3.5.0
3182   * @since 4.7.0 The `$status_code` parameter was added.
3183   *
3184   * @param mixed $data        Data to encode as JSON, then print and die.
3185   * @param int   $status_code The HTTP status code to output.
3186   */
3187  function wp_send_json_success( $data = null, $status_code = null ) {
3188      $response = array( 'success' => true );
3189  
3190      if ( isset( $data ) )
3191          $response['data'] = $data;
3192  
3193      wp_send_json( $response, $status_code );
3194  }
3195  
3196  /**
3197   * Send a JSON response back to an Ajax request, indicating failure.
3198   *
3199   * If the `$data` parameter is a WP_Error object, the errors
3200   * within the object are processed and output as an array of error
3201   * codes and corresponding messages. All other types are output
3202   * without further processing.
3203   *
3204   * @since 3.5.0
3205   * @since 4.1.0 The `$data` parameter is now processed if a WP_Error object is passed in.
3206   * @since 4.7.0 The `$status_code` parameter was added.
3207   *
3208   * @param mixed $data        Data to encode as JSON, then print and die.
3209   * @param int   $status_code The HTTP status code to output.
3210   */
3211  function wp_send_json_error( $data = null, $status_code = null ) {
3212      $response = array( 'success' => false );
3213  
3214      if ( isset( $data ) ) {
3215          if ( is_wp_error( $data ) ) {
3216              $result = array();
3217              foreach ( $data->errors as $code => $messages ) {
3218                  foreach ( $messages as $message ) {
3219                      $result[] = array( 'code' => $code, 'message' => $message );
3220                  }
3221              }
3222  
3223              $response['data'] = $result;
3224          } else {
3225              $response['data'] = $data;
3226          }
3227      }
3228  
3229      wp_send_json( $response, $status_code );
3230  }
3231  
3232  /**
3233   * Checks that a JSONP callback is a valid JavaScript callback.
3234   *
3235   * Only allows alphanumeric characters and the dot character in callback
3236   * function names. This helps to mitigate XSS attacks caused by directly
3237   * outputting user input.
3238   *
3239   * @since 4.6.0
3240   *
3241   * @param string $callback Supplied JSONP callback function.
3242   * @return bool True if valid callback, otherwise false.
3243   */
3244  function wp_check_jsonp_callback( $callback ) {
3245      if ( ! is_string( $callback ) ) {
3246          return false;
3247      }
3248  
3249      preg_replace( '/[^\w\.]/', '', $callback, -1, $illegal_char_count );
3250  
3251      return 0 === $illegal_char_count;
3252  }
3253  
3254  /**
3255   * Retrieve the WordPress home page URL.
3256   *
3257   * If the constant named 'WP_HOME' exists, then it will be used and returned
3258   * by the function. This can be used to counter the redirection on your local
3259   * development environment.
3260   *
3261   * @since 2.2.0
3262   * @access private
3263   *
3264   * @see WP_HOME
3265   *
3266   * @param string $url URL for the home location.
3267   * @return string Homepage location.
3268   */
3269  function _config_wp_home( $url = '' ) {
3270      if ( defined( 'WP_HOME' ) )
3271          return untrailingslashit( WP_HOME );
3272      return $url;
3273  }
3274  
3275  /**
3276   * Retrieve the WordPress site URL.
3277   *
3278   * If the constant named 'WP_SITEURL' is defined, then the value in that
3279   * constant will always be returned. This can be used for debugging a site
3280   * on your localhost while not having to change the database to your URL.
3281   *
3282   * @since 2.2.0
3283   * @access private
3284   *
3285   * @see WP_SITEURL
3286   *
3287   * @param string $url URL to set the WordPress site location.
3288   * @return string The WordPress Site URL.
3289   */
3290  function _config_wp_siteurl( $url = '' ) {
3291      if ( defined( 'WP_SITEURL' ) )
3292          return untrailingslashit( WP_SITEURL );
3293      return $url;
3294  }
3295  
3296  /**
3297   * Delete the fresh site option.
3298   *
3299   * @since 4.7.0
3300   * @access private
3301   */
3302  function _delete_option_fresh_site() {
3303      update_option( 'fresh_site', 0 );
3304  }
3305  
3306  /**
3307   * Set the localized direction for MCE plugin.
3308   *
3309   * Will only set the direction to 'rtl', if the WordPress locale has
3310   * the text direction set to 'rtl'.
3311   *
3312   * Fills in the 'directionality' setting, enables the 'directionality'
3313   * plugin, and adds the 'ltr' button to 'toolbar1', formerly
3314   * 'theme_advanced_buttons1' array keys. These keys are then returned
3315   * in the $mce_init (TinyMCE settings) array.
3316   *
3317   * @since 2.1.0
3318   * @access private
3319   *
3320   * @param array $mce_init MCE settings array.
3321   * @return array Direction set for 'rtl', if needed by locale.
3322   */
3323  function _mce_set_direction( $mce_init ) {
3324      if ( is_rtl() ) {
3325          $mce_init['directionality'] = 'rtl';
3326          $mce_init['rtl_ui'] = true;
3327  
3328          if ( ! empty( $mce_init['plugins'] ) && strpos( $mce_init['plugins'], 'directionality' ) === false ) {
3329              $mce_init['plugins'] .= ',directionality';
3330          }
3331  
3332          if ( ! empty( $mce_init['toolbar1'] ) && ! preg_match( '/\bltr\b/', $mce_init['toolbar1'] ) ) {
3333              $mce_init['toolbar1'] .= ',ltr';
3334          }
3335      }
3336  
3337      return $mce_init;
3338  }
3339  
3340  
3341  /**
3342   * Convert smiley code to the icon graphic file equivalent.
3343   *
3344   * You can turn off smilies, by going to the write setting screen and unchecking
3345   * the box, or by setting 'use_smilies' option to false or removing the option.
3346   *
3347   * Plugins may override the default smiley list by setting the $wpsmiliestrans
3348   * to an array, with the key the code the blogger types in and the value the
3349   * image file.
3350   *
3351   * The $wp_smiliessearch global is for the regular expression and is set each
3352   * time the function is called.
3353   *
3354   * The full list of smilies can be found in the function and won't be listed in
3355   * the description. Probably should create a Codex page for it, so that it is
3356   * available.
3357   *
3358   * @global array $wpsmiliestrans
3359   * @global array $wp_smiliessearch
3360   *
3361   * @since 2.2.0
3362   */
3363  function smilies_init() {
3364      global $wpsmiliestrans, $wp_smiliessearch;
3365  
3366      // don't bother setting up smilies if they are disabled
3367      if ( !get_option( 'use_smilies' ) )
3368          return;
3369  
3370      if ( !isset( $wpsmiliestrans ) ) {
3371          $wpsmiliestrans = array(
3372          ':mrgreen:' => 'mrgreen.png',
3373          ':neutral:' => "\xf0\x9f\x98\x90",
3374          ':twisted:' => "\xf0\x9f\x98\x88",
3375            ':arrow:' => "\xe2\x9e\xa1",
3376            ':shock:' => "\xf0\x9f\x98\xaf",
3377            ':smile:' => "\xf0\x9f\x99\x82",
3378              ':???:' => "\xf0\x9f\x98\x95",
3379             ':cool:' => "\xf0\x9f\x98\x8e",
3380             ':evil:' => "\xf0\x9f\x91\xbf",
3381             ':grin:' => "\xf0\x9f\x98\x80",
3382             ':idea:' => "\xf0\x9f\x92\xa1",
3383             ':oops:' => "\xf0\x9f\x98\xb3",
3384             ':razz:' => "\xf0\x9f\x98\x9b",
3385             ':roll:' => "\xf0\x9f\x99\x84",
3386             ':wink:' => "\xf0\x9f\x98\x89",
3387              ':cry:' => "\xf0\x9f\x98\xa5",
3388              ':eek:' => "\xf0\x9f\x98\xae",
3389              ':lol:' => "\xf0\x9f\x98\x86",
3390              ':mad:' => "\xf0\x9f\x98\xa1",
3391              ':sad:' => "\xf0\x9f\x99\x81",
3392                '8-)' => "\xf0\x9f\x98\x8e",
3393                '8-O' => "\xf0\x9f\x98\xaf",
3394                ':-(' => "\xf0\x9f\x99\x81",
3395                ':-)' => "\xf0\x9f\x99\x82",
3396                ':-?' => "\xf0\x9f\x98\x95",
3397                ':-D' => "\xf0\x9f\x98\x80",
3398                ':-P' => "\xf0\x9f\x98\x9b",
3399                ':-o' => "\xf0\x9f\x98\xae",
3400                ':-x' => "\xf0\x9f\x98\xa1",
3401                ':-|' => "\xf0\x9f\x98\x90",
3402                ';-)' => "\xf0\x9f\x98\x89",
3403          // This one transformation breaks regular text with frequency.
3404          //     '8)' => "\xf0\x9f\x98\x8e",
3405                 '8O' => "\xf0\x9f\x98\xaf",
3406                 ':(' => "\xf0\x9f\x99\x81",
3407                 ':)' => "\xf0\x9f\x99\x82",
3408                 ':?' => "\xf0\x9f\x98\x95",
3409                 ':D' => "\xf0\x9f\x98\x80",
3410                 ':P' => "\xf0\x9f\x98\x9b",
3411                 ':o' => "\xf0\x9f\x98\xae",
3412                 ':x' => "\xf0\x9f\x98\xa1",
3413                 ':|' => "\xf0\x9f\x98\x90",
3414                 ';)' => "\xf0\x9f\x98\x89",
3415                ':!:' => "\xe2\x9d\x97",
3416                ':?:' => "\xe2\x9d\x93",
3417          );
3418      }
3419  
3420      /**
3421       * Filters all the smilies.
3422       *
3423       * This filter must be added before `smilies_init` is run, as
3424       * it is normally only run once to setup the smilies regex.
3425       *
3426       * @since 4.7.0
3427       *
3428       * @param array $wpsmiliestrans List of the smilies.
3429       */
3430      $wpsmiliestrans = apply_filters('smilies', $wpsmiliestrans);
3431  
3432      if (count($wpsmiliestrans) == 0) {
3433          return;
3434      }
3435  
3436      /*
3437       * NOTE: we sort the smilies in reverse key order. This is to make sure
3438       * we match the longest possible smilie (:???: vs :?) as the regular
3439       * expression used below is first-match
3440       */
3441      krsort($wpsmiliestrans);
3442  
3443      $spaces = wp_spaces_regexp();
3444  
3445      // Begin first "subpattern"
3446      $wp_smiliessearch = '/(?<=' . $spaces . '|^)';
3447  
3448      $subchar = '';
3449      foreach ( (array) $wpsmiliestrans as $smiley => $img ) {
3450          $firstchar = substr($smiley, 0, 1);
3451          $rest = substr($smiley, 1);
3452  
3453          // new subpattern?
3454          if ($firstchar != $subchar) {
3455              if ($subchar != '') {
3456                  $wp_smiliessearch .= ')(?=' . $spaces . '|$)';  // End previous "subpattern"
3457                  $wp_smiliessearch .= '|(?<=' . $spaces . '|^)'; // Begin another "subpattern"
3458              }
3459              $subchar = $firstchar;
3460              $wp_smiliessearch .= preg_quote($firstchar, '/') . '(?:';
3461          } else {
3462              $wp_smiliessearch .= '|';
3463          }
3464          $wp_smiliessearch .= preg_quote($rest, '/');
3465      }
3466  
3467      $wp_smiliessearch .= ')(?=' . $spaces . '|$)/m';
3468  
3469  }
3470  
3471  /**
3472   * Merge user defined arguments into defaults array.
3473   *
3474   * This function is used throughout WordPress to allow for both string or array
3475   * to be merged into another array.
3476   *
3477   * @since 2.2.0
3478   * @since 2.3.0 `$args` can now also be an object.
3479   *
3480   * @param string|array|object $args     Value to merge with $defaults.
3481   * @param array               $defaults Optional. Array that serves as the defaults. Default empty.
3482   * @return array Merged user defined values with defaults.
3483   */
3484  function wp_parse_args( $args, $defaults = '' ) {
3485      if ( is_object( $args ) )
3486          $r = get_object_vars( $args );
3487      elseif ( is_array( $args ) )
3488          $r =& $args;
3489      else
3490          wp_parse_str( $args, $r );
3491  
3492      if ( is_array( $defaults ) )
3493          return array_merge( $defaults, $r );
3494      return $r;
3495  }
3496  
3497  /**
3498   * Clean up an array, comma- or space-separated list of IDs.
3499   *
3500   * @since 3.0.0
3501   *
3502   * @param array|string $list List of ids.
3503   * @return array Sanitized array of IDs.
3504   */
3505  function wp_parse_id_list( $list ) {
3506      if ( !is_array($list) )
3507          $list = preg_split('/[\s,]+/', $list);
3508  
3509      return array_unique(array_map('absint', $list));
3510  }
3511  
3512  /**
3513   * Clean up an array, comma- or space-separated list of slugs.
3514   *
3515   * @since 4.7.0
3516   *
3517   * @param  array|string $list List of slugs.
3518   * @return array Sanitized array of slugs.
3519   */
3520  function wp_parse_slug_list( $list ) {
3521      if ( ! is_array( $list ) ) {
3522          $list = preg_split( '/[\s,]+/', $list );
3523      }
3524  
3525      foreach ( $list as $key => $value ) {
3526          $list[ $key ] = sanitize_title( $value );
3527      }
3528  
3529      return array_unique( $list );
3530  }
3531  
3532  /**
3533   * Extract a slice of an array, given a list of keys.
3534   *
3535   * @since 3.1.0
3536   *
3537   * @param array $array The original array.
3538   * @param array $keys  The list of keys.
3539   * @return array The array slice.
3540   */
3541  function wp_array_slice_assoc( $array, $keys ) {
3542      $slice = array();
3543      foreach ( $keys as $key )
3544          if ( isset( $array[ $key ] ) )
3545              $slice[ $key ] = $array[ $key ];
3546  
3547      return $slice;
3548  }
3549  
3550  /**
3551   * Determines if the variable is a numeric-indexed array.
3552   *
3553   * @since 4.4.0
3554   *
3555   * @param mixed $data Variable to check.
3556   * @return bool Whether the variable is a list.
3557   */
3558  function wp_is_numeric_array( $data ) {
3559      if ( ! is_array( $data ) ) {
3560          return false;
3561      }
3562  
3563      $keys = array_keys( $data );
3564      $string_keys = array_filter( $keys, 'is_string' );
3565      return count( $string_keys ) === 0;
3566  }
3567  
3568  /**
3569   * Filters a list of objects, based on a set of key => value arguments.
3570   *
3571   * @since 3.0.0
3572   * @since 4.7.0 Uses WP_List_Util class.
3573   *
3574   * @param array       $list     An array of objects to filter
3575   * @param array       $args     Optional. An array of key => value arguments to match
3576   *                              against each object. Default empty array.
3577   * @param string      $operator Optional. The logical operation to perform. 'or' means
3578   *                              only one element from the array needs to match; 'and'
3579   *                              means all elements must match; 'not' means no elements may
3580   *                              match. Default 'and'.
3581   * @param bool|string $field    A field from the object to place instead of the entire object.
3582   *                              Default false.
3583   * @return array A list of objects or object fields.
3584   */
3585  function wp_filter_object_list( $list, $args = array(), $operator = 'and', $field = false ) {
3586      if ( ! is_array( $list ) ) {
3587          return array();
3588      }
3589  
3590      $util = new WP_List_Util( $list );
3591  
3592      $util->filter( $args, $operator );
3593  
3594      if ( $field ) {
3595          $util->pluck( $field );
3596      }
3597  
3598      return $util->get_output();
3599  }
3600  
3601  /**
3602   * Filters a list of objects, based on a set of key => value arguments.
3603   *
3604   * @since 3.1.0
3605   * @since 4.7.0 Uses WP_List_Util class.
3606   *
3607   * @param array  $list     An array of objects to filter.
3608   * @param array  $args     Optional. An array of key => value arguments to match
3609   *                         against each object. Default empty array.
3610   * @param string $operator Optional. The logical operation to perform. 'AND' means
3611   *                         all elements from the array must match. 'OR' means only
3612   *                         one element needs to match. 'NOT' means no elements may
3613   *                         match. Default 'AND'.
3614   * @return array Array of found values.
3615   */
3616  function wp_list_filter( $list, $args = array(), $operator = 'AND' ) {
3617      if ( ! is_array( $list ) ) {
3618          return array();
3619      }
3620  
3621      $util = new WP_List_Util( $list );
3622      return $util->filter( $args, $operator );
3623  }
3624  
3625  /**
3626   * Pluck a certain field out of each object in a list.
3627   *
3628   * This has the same functionality and prototype of
3629   * array_column() (PHP 5.5) but also supports objects.
3630   *
3631   * @since 3.1.0
3632   * @since 4.0.0 $index_key parameter added.
3633   * @since 4.7.0 Uses WP_List_Util class.
3634   *
3635   * @param array      $list      List of objects or arrays
3636   * @param int|string $field     Field from the object to place instead of the entire object
3637   * @param int|string $index_key Optional. Field from the object to use as keys for the new array.
3638   *                              Default null.
3639   * @return array Array of found values. If `$index_key` is set, an array of found values with keys
3640   *               corresponding to `$index_key`. If `$index_key` is null, array keys from the original
3641   *               `$list` will be preserved in the results.
3642   */
3643  function wp_list_pluck( $list, $field, $index_key = null ) {
3644      $util = new WP_List_Util( $list );
3645      return $util->pluck( $field, $index_key );
3646  }
3647  
3648  /**
3649   * Sorts a list of objects, based on one or more orderby arguments.
3650   *
3651   * @since 4.7.0
3652   *
3653   * @param array        $list          An array of objects to filter.
3654   * @param string|array $orderby       Optional. Either the field name to order by or an array
3655   *                                    of multiple orderby fields as $orderby => $order.
3656   * @param string       $order         Optional. Either 'ASC' or 'DESC'. Only used if $orderby
3657   *                                    is a string.
3658   * @param bool         $preserve_keys Optional. Whether to preserve keys. Default false.
3659   * @return array The sorted array.
3660   */
3661  function wp_list_sort( $list, $orderby = array(), $order = 'ASC', $preserve_keys = false ) {
3662      if ( ! is_array( $list ) ) {
3663          return array();
3664      }
3665  
3666      $util = new WP_List_Util( $list );
3667      return $util->sort( $orderby, $order, $preserve_keys );
3668  }
3669  
3670  /**
3671   * Determines if Widgets library should be loaded.
3672   *
3673   * Checks to make sure that the widgets library hasn't already been loaded.
3674   * If it hasn't, then it will load the widgets library and run an action hook.
3675   *
3676   * @since 2.2.0
3677   */
3678  function wp_maybe_load_widgets() {
3679      /**
3680       * Filters whether to load the Widgets library.
3681       *
3682       * Passing a falsey value to the filter will effectively short-circuit
3683       * the Widgets library from loading.
3684       *
3685       * @since 2.8.0
3686       *
3687       * @param bool $wp_maybe_load_widgets Whether to load the Widgets library.
3688       *                                    Default true.
3689       */
3690      if ( ! apply_filters( 'load_default_widgets', true ) ) {
3691          return;
3692      }
3693  
3694      require_once ( ABSPATH . WPINC . '/default-widgets.php' );
3695  
3696      add_action( '_admin_menu', 'wp_widgets_add_menu' );
3697  }
3698  
3699  /**
3700   * Append the Widgets menu to the themes main menu.
3701   *
3702   * @since 2.2.0
3703   *
3704   * @global array $submenu
3705   */
3706  function wp_widgets_add_menu() {
3707      global $submenu;
3708  
3709      if ( ! current_theme_supports( 'widgets' ) )
3710          return;
3711  
3712      $submenu['themes.php'][7] = array( __( 'Widgets' ), 'edit_theme_options', 'widgets.php' );
3713      ksort( $submenu['themes.php'], SORT_NUMERIC );
3714  }
3715  
3716  /**
3717   * Flush all output buffers for PHP 5.2.
3718   *
3719   * Make sure all output buffers are flushed before our singletons are destroyed.
3720   *
3721   * @since 2.2.0
3722   */
3723  function wp_ob_end_flush_all() {
3724      $levels = ob_get_level();
3725      for ($i=0; $i<$levels; $i++)
3726          ob_end_flush();
3727  }
3728  
3729  /**
3730   * Load custom DB error or display WordPress DB error.
3731   *
3732   * If a file exists in the wp-content directory named db-error.php, then it will
3733   * be loaded instead of displaying the WordPress DB error. If it is not found,
3734   * then the WordPress DB error will be displayed instead.
3735   *
3736   * The WordPress DB error sets the HTTP status header to 500 to try to prevent
3737   * search engines from caching the message. Custom DB messages should do the
3738   * same.
3739   *
3740   * This function was backported to WordPress 2.3.2, but originally was added
3741   * in WordPress 2.5.0.
3742   *
3743   * @since 2.3.2
3744   *
3745   * @global wpdb $wpdb WordPress database abstraction object.
3746   */
3747  function dead_db() {
3748      global $wpdb;
3749  
3750      wp_load_translations_early();
3751  
3752      // Load custom DB error template, if present.
3753      if ( file_exists( WP_CONTENT_DIR . '/db-error.php' ) ) {
3754          require_once( WP_CONTENT_DIR . '/db-error.php' );
3755          die();
3756      }
3757  
3758      // If installing or in the admin, provide the verbose message.
3759      if ( wp_installing() || defined( 'WP_ADMIN' ) )
3760          wp_die($wpdb->error);
3761  
3762      // Otherwise, be terse.
3763      status_header( 500 );
3764      nocache_headers();
3765      header( 'Content-Type: text/html; charset=utf-8' );
3766  ?>
3767  <!DOCTYPE html>
3768  <html xmlns="http://www.w3.org/1999/xhtml"<?php if ( is_rtl() ) echo ' dir="rtl"'; ?>>
3769  <head>
3770  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
3771      <title><?php _e( 'Database Error' ); ?></title>
3772  
3773  </head>
3774  <body>
3775      <h1><?php _e( 'Error establishing a database connection' ); ?></h1>
3776  </body>
3777  </html>
3778  <?php
3779      die();
3780  }
3781  
3782  /**
3783   * Convert a value to non-negative integer.
3784   *
3785   * @since 2.5.0
3786   *
3787   * @param mixed $maybeint Data you wish to have converted to a non-negative integer.
3788   * @return int A non-negative integer.
3789   */
3790  function absint( $maybeint ) {
3791      return abs( intval( $maybeint ) );
3792  }
3793  
3794  /**
3795   * Mark a function as deprecated and inform when it has been used.
3796   *
3797   * There is a {@see 'hook deprecated_function_run'} that will be called that can be used
3798   * to get the backtrace up to what file and function called the deprecated
3799   * function.
3800   *
3801   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
3802   *
3803   * This function is to be used in every function that is deprecated.
3804   *
3805   * @since 2.5.0
3806   * @access private
3807   *
3808   * @param string $function    The function that was called.
3809   * @param string $version     The version of WordPress that deprecated the function.
3810   * @param string $replacement Optional. The function that should have been called. Default null.
3811   */
3812  function _deprecated_function( $function, $version, $replacement = null ) {
3813  
3814      /**
3815       * Fires when a deprecated function is called.
3816       *
3817       * @since 2.5.0
3818       *
3819       * @param string $function    The function that was called.
3820       * @param string $replacement The function that should have been called.
3821       * @param string $version     The version of WordPress that deprecated the function.
3822       */
3823      do_action( 'deprecated_function_run', $function, $replacement, $version );
3824  
3825      /**
3826       * Filters whether to trigger an error for deprecated functions.
3827       *
3828       * @since 2.5.0
3829       *
3830       * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3831       */
3832      if ( WP_DEBUG && apply_filters( 'deprecated_function_trigger_error', true ) ) {
3833          if ( function_exists( '__' ) ) {
3834              if ( ! is_null( $replacement ) ) {
3835                  /* translators: 1: PHP function name, 2: version number, 3: alternative function name */
3836                  trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $function, $version, $replacement ) );
3837              } else {
3838                  /* translators: 1: PHP function name, 2: version number */
3839                  trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
3840              }
3841          } else {
3842              if ( ! is_null( $replacement ) ) {
3843                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $function, $version, $replacement ) );
3844              } else {
3845                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
3846              }
3847          }
3848      }
3849  }
3850  
3851  /**
3852   * Marks a constructor as deprecated and informs when it has been used.
3853   *
3854   * Similar to _deprecated_function(), but with different strings. Used to
3855   * remove PHP4 style constructors.
3856   *
3857   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
3858   *
3859   * This function is to be used in every PHP4 style constructor method that is deprecated.
3860   *
3861   * @since 4.3.0
3862   * @since 4.5.0 Added the `$parent_class` parameter.
3863   *
3864   * @access private
3865   *
3866   * @param string $class        The class containing the deprecated constructor.
3867   * @param string $version      The version of WordPress that deprecated the function.
3868   * @param string $parent_class Optional. The parent class calling the deprecated constructor.
3869   *                             Default empty string.
3870   */
3871  function _deprecated_constructor( $class, $version, $parent_class = '' ) {
3872  
3873      /**
3874       * Fires when a deprecated constructor is called.
3875       *
3876       * @since 4.3.0
3877       * @since 4.5.0 Added the `$parent_class` parameter.
3878       *
3879       * @param string $class        The class containing the deprecated constructor.
3880       * @param string $version      The version of WordPress that deprecated the function.
3881       * @param string $parent_class The parent class calling the deprecated constructor.
3882       */
3883      do_action( 'deprecated_constructor_run', $class, $version, $parent_class );
3884  
3885      /**
3886       * Filters whether to trigger an error for deprecated functions.
3887       *
3888       * `WP_DEBUG` must be true in addition to the filter evaluating to true.
3889       *
3890       * @since 4.3.0
3891       *
3892       * @param bool $trigger Whether to trigger the error for deprecated functions. Default true.
3893       */
3894      if ( WP_DEBUG && apply_filters( 'deprecated_constructor_trigger_error', true ) ) {
3895          if ( function_exists( '__' ) ) {
3896              if ( ! empty( $parent_class ) ) {
3897                  /* translators: 1: PHP class name, 2: PHP parent class name, 3: version number, 4: __construct() method */
3898                  trigger_error( sprintf( __( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.' ),
3899                      $class, $parent_class, $version, '<pre>__construct()</pre>' ) );
3900              } else {
3901                  /* translators: 1: PHP class name, 2: version number, 3: __construct() method */
3902                  trigger_error( sprintf( __( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ),
3903                      $class, $version, '<pre>__construct()</pre>' ) );
3904              }
3905          } else {
3906              if ( ! empty( $parent_class ) ) {
3907                  trigger_error( sprintf( 'The called constructor method for %1$s in %2$s is <strong>deprecated</strong> since version %3$s! Use %4$s instead.',
3908                      $class, $parent_class, $version, '<pre>__construct()</pre>' ) );
3909              } else {
3910                  trigger_error( sprintf( 'The called constructor method for %1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.',
3911                      $class, $version, '<pre>__construct()</pre>' ) );
3912              }
3913          }
3914      }
3915  
3916  }
3917  
3918  /**
3919   * Mark a file as deprecated and inform when it has been used.
3920   *
3921   * There is a hook {@see 'deprecated_file_included'} that will be called that can be used
3922   * to get the backtrace up to what file and function included the deprecated
3923   * file.
3924   *
3925   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
3926   *
3927   * This function is to be used in every file that is deprecated.
3928   *
3929   * @since 2.5.0
3930   * @access private
3931   *
3932   * @param string $file        The file that was included.
3933   * @param string $version     The version of WordPress that deprecated the file.
3934   * @param string $replacement Optional. The file that should have been included based on ABSPATH.
3935   *                            Default null.
3936   * @param string $message     Optional. A message regarding the change. Default empty.
3937   */
3938  function _deprecated_file( $file, $version, $replacement = null, $message = '' ) {
3939  
3940      /**
3941       * Fires when a deprecated file is called.
3942       *
3943       * @since 2.5.0
3944       *
3945       * @param string $file        The file that was called.
3946       * @param string $replacement The file that should have been included based on ABSPATH.
3947       * @param string $version     The version of WordPress that deprecated the file.
3948       * @param string $message     A message regarding the change.
3949       */
3950      do_action( 'deprecated_file_included', $file, $replacement, $version, $message );
3951  
3952      /**
3953       * Filters whether to trigger an error for deprecated files.
3954       *
3955       * @since 2.5.0
3956       *
3957       * @param bool $trigger Whether to trigger the error for deprecated files. Default true.
3958       */
3959      if ( WP_DEBUG && apply_filters( 'deprecated_file_trigger_error', true ) ) {
3960          $message = empty( $message ) ? '' : ' ' . $message;
3961          if ( function_exists( '__' ) ) {
3962              if ( ! is_null( $replacement ) ) {
3963                  /* translators: 1: PHP file name, 2: version number, 3: alternative file name */
3964                  trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.'), $file, $version, $replacement ) . $message );
3965              } else {
3966                  /* translators: 1: PHP file name, 2: version number */
3967                  trigger_error( sprintf( __('%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.'), $file, $version ) . $message );
3968              }
3969          } else {
3970              if ( ! is_null( $replacement ) ) {
3971                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.', $file, $version, $replacement ) . $message );
3972              } else {
3973                  trigger_error( sprintf( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.', $file, $version ) . $message );
3974              }
3975          }
3976      }
3977  }
3978  /**
3979   * Mark a function argument as deprecated and inform when it has been used.
3980   *
3981   * This function is to be used whenever a deprecated function argument is used.
3982   * Before this function is called, the argument must be checked for whether it was
3983   * used by comparing it to its default value or evaluating whether it is empty.
3984   * For example:
3985   *
3986   *     if ( ! empty( $deprecated ) ) {
3987   *         _deprecated_argument( __FUNCTION__, '3.0.0' );
3988   *     }
3989   *
3990   *
3991   * There is a hook deprecated_argument_run that will be called that can be used
3992   * to get the backtrace up to what file and function used the deprecated
3993   * argument.
3994   *
3995   * The current behavior is to trigger a user error if WP_DEBUG is true.
3996   *
3997   * @since 3.0.0
3998   * @access private
3999   *
4000   * @param string $function The function that was called.
4001   * @param string $version  The version of WordPress that deprecated the argument used.
4002   * @param string $message  Optional. A message regarding the change. Default null.
4003   */
4004  function _deprecated_argument( $function, $version, $message = null ) {
4005  
4006      /**
4007       * Fires when a deprecated argument is called.
4008       *
4009       * @since 3.0.0
4010       *
4011       * @param string $function The function that was called.
4012       * @param string $message  A message regarding the change.
4013       * @param string $version  The version of WordPress that deprecated the argument used.
4014       */
4015      do_action( 'deprecated_argument_run', $function, $message, $version );
4016  
4017      /**
4018       * Filters whether to trigger an error for deprecated arguments.
4019       *
4020       * @since 3.0.0
4021       *
4022       * @param bool $trigger Whether to trigger the error for deprecated arguments. Default true.
4023       */
4024      if ( WP_DEBUG && apply_filters( 'deprecated_argument_trigger_error', true ) ) {
4025          if ( function_exists( '__' ) ) {
4026              if ( ! is_null( $message ) ) {
4027                  /* translators: 1: PHP function name, 2: version number, 3: optional message regarding the change */
4028                  trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s'), $function, $version, $message ) );
4029              } else {
4030                  /* translators: 1: PHP function name, 2: version number */
4031                  trigger_error( sprintf( __('%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.'), $function, $version ) );
4032              }
4033          } else {
4034              if ( ! is_null( $message ) ) {
4035                  trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s! %3$s', $function, $version, $message ) );
4036              } else {
4037                  trigger_error( sprintf( '%1$s was called with an argument that is <strong>deprecated</strong> since version %2$s with no alternative available.', $function, $version ) );
4038              }
4039          }
4040      }
4041  }
4042  
4043  /**
4044   * Marks a deprecated action or filter hook as deprecated and throws a notice.
4045   *
4046   * Use the {@see 'deprecated_hook_run'} action to get the backtrace describing where
4047   * the deprecated hook was called.
4048   *
4049   * Default behavior is to trigger a user error if `WP_DEBUG` is true.
4050   *
4051   * This function is called by the do_action_deprecated() and apply_filters_deprecated()
4052   * functions, and so generally does not need to be called directly.
4053   *
4054   * @since 4.6.0
4055   * @access private
4056   *
4057   * @param string $hook        The hook that was used.
4058   * @param string $version     The version of WordPress that deprecated the hook.
4059   * @param string $replacement Optional. The hook that should have been used.
4060   * @param string $message     Optional. A message regarding the change.
4061   */
4062  function _deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
4063      /**
4064       * Fires when a deprecated hook is called.
4065       *
4066       * @since 4.6.0
4067       *
4068       * @param string $hook        The hook that was called.
4069       * @param string $replacement The hook that should be used as a replacement.
4070       * @param string $version     The version of WordPress that deprecated the argument used.
4071       * @param string $message     A message regarding the change.
4072       */
4073      do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
4074  
4075      /**
4076       * Filters whether to trigger deprecated hook errors.
4077       *
4078       * @since 4.6.0
4079       *
4080       * @param bool $trigger Whether to trigger deprecated hook errors. Requires
4081       *                      `WP_DEBUG` to be defined true.
4082       */
4083      if ( WP_DEBUG && apply_filters( 'deprecated_hook_trigger_error', true ) ) {
4084          $message = empty( $message ) ? '' : ' ' . $message;
4085          if ( ! is_null( $replacement ) ) {
4086              /* translators: 1: WordPress hook name, 2: version number, 3: alternative hook name */
4087              trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s! Use %3$s instead.' ), $hook, $version, $replacement ) . $message );
4088          } else {
4089              /* translators: 1: WordPress hook name, 2: version number */
4090              trigger_error( sprintf( __( '%1$s is <strong>deprecated</strong> since version %2$s with no alternative available.' ), $hook, $version ) . $message );
4091          }
4092      }
4093  }
4094  
4095  /**
4096   * Mark something as being incorrectly called.
4097   *
4098   * There is a hook {@see 'doing_it_wrong_run'} that will be called that can be used
4099   * to get the backtrace up to what file and function called the deprecated
4100   * function.
4101   *
4102   * The current behavior is to trigger a user error if `WP_DEBUG` is true.
4103   *
4104   * @since 3.1.0
4105   * @access private
4106   *
4107   * @param string $function The function that was called.
4108   * @param string $message  A message explaining what has been done incorrectly.
4109   * @param string $version  The version of WordPress where the message was added.
4110   */
4111  function _doing_it_wrong( $function, $message, $version ) {
4112  
4113      /**
4114       * Fires when the given function is being used incorrectly.
4115       *
4116       * @since 3.1.0
4117       *
4118       * @param string $function The function that was called.
4119       * @param string $message  A message explaining what has been done incorrectly.
4120       * @param string $version  The version of WordPress where the message was added.
4121       */
4122      do_action( 'doing_it_wrong_run', $function, $message, $version );
4123  
4124      /**
4125       * Filters whether to trigger an error for _doing_it_wrong() calls.
4126       *
4127       * @since 3.1.0
4128       *
4129       * @param bool $trigger Whether to trigger the error for _doing_it_wrong() calls. Default true.
4130       */
4131      if ( WP_DEBUG && apply_filters( 'doing_it_wrong_trigger_error', true ) ) {
4132          if ( function_exists( '__' ) ) {
4133              if ( is_null( $version ) ) {
4134                  $version = '';
4135              } else {
4136                  /* translators: %s: version number */
4137                  $version = sprintf( __( '(This message was added in version %s.)' ), $version );
4138              }
4139              /* translators: %s: Codex URL */
4140              $message .= ' ' . sprintf( __( 'Please see <a href="%s">Debugging in WordPress</a> for more information.' ),
4141                  __( 'https://codex.wordpress.org/Debugging_in_WordPress' )
4142              );
4143              /* translators: Developer debugging message. 1: PHP function name, 2: Explanatory message, 3: Version information message */
4144              trigger_error( sprintf( __( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s' ), $function, $message, $version ) );
4145          } else {
4146              if ( is_null( $version ) ) {
4147                  $version = '';
4148              } else {
4149                  $version = sprintf( '(This message was added in version %s.)', $version );
4150              }
4151              $message .= sprintf( ' Please see <a href="%s">Debugging in WordPress</a> for more information.',
4152                  'https://codex.wordpress.org/Debugging_in_WordPress'
4153              );
4154              trigger_error( sprintf( '%1$s was called <strong>incorrectly</strong>. %2$s %3$s', $function, $message, $version ) );
4155          }
4156      }
4157  }
4158  
4159  /**
4160   * Is the server running earlier than 1.5.0 version of lighttpd?
4161   *
4162   * @since 2.5.0
4163   *
4164   * @return bool Whether the server is running lighttpd < 1.5.0.
4165   */
4166  function is_lighttpd_before_150() {
4167      $server_parts = explode( '/', isset( $_SERVER['SERVER_SOFTWARE'] )? $_SERVER['SERVER_SOFTWARE'] : '' );
4168      $server_parts[1] = isset( $server_parts[1] )? $server_parts[1] : '';
4169      return  'lighttpd' == $server_parts[0] && -1 == version_compare( $server_parts[1], '1.5.0' );
4170  }
4171  
4172  /**
4173   * Does the specified module exist in the Apache config?
4174   *
4175   * @since 2.5.0
4176   *
4177   * @global bool $is_apache
4178   *
4179   * @param string $mod     The module, e.g. mod_rewrite.
4180   * @param bool   $default Optional. The default return value if the module is not found. Default false.
4181   * @return bool Whether the specified module is loaded.
4182   */
4183  function apache_mod_loaded($mod, $default = false) {
4184      global $is_apache;
4185  
4186      if ( !$is_apache )
4187          return false;
4188  
4189      if ( function_exists( 'apache_get_modules' ) ) {
4190          $mods = apache_get_modules();
4191          if ( in_array($mod, $mods) )
4192              return true;
4193      } elseif ( function_exists( 'phpinfo' ) && false === strpos( ini_get( 'disable_functions' ), 'phpinfo' ) ) {
4194              ob_start();
4195              phpinfo(8);
4196              $phpinfo = ob_get_clean();
4197              if ( false !== strpos($phpinfo, $mod) )
4198                  return true;
4199      }
4200      return $default;
4201  }
4202  
4203  /**
4204   * Check if IIS 7+ supports pretty permalinks.
4205   *
4206   * @since 2.8.0
4207   *
4208   * @global bool $is_iis7
4209   *
4210   * @return bool Whether IIS7 supports permalinks.
4211   */
4212  function iis7_supports_permalinks() {
4213      global $is_iis7;
4214  
4215      $supports_permalinks = false;
4216      if ( $is_iis7 ) {
4217          /* First we check if the DOMDocument class exists. If it does not exist, then we cannot
4218           * easily update the xml configuration file, hence we just bail out and tell user that
4219           * pretty permalinks cannot be used.
4220           *
4221           * Next we check if the URL Rewrite Module 1.1 is loaded and enabled for the web site. When
4222           * URL Rewrite 1.1 is loaded it always sets a server variable called 'IIS_UrlRewriteModule'.
4223           * Lastly we make sure that PHP is running via FastCGI. This is important because if it runs
4224           * via ISAPI then pretty permalinks will not work.
4225           */
4226          $supports_permalinks = class_exists( 'DOMDocument', false ) && isset($_SERVER['IIS_UrlRewriteModule']) && ( PHP_SAPI == 'cgi-fcgi' );
4227      }
4228  
4229      /**
4230       * Filters whether IIS 7+ supports pretty permalinks.
4231       *
4232       * @since 2.8.0
4233       *
4234       * @param bool $supports_permalinks Whether IIS7 supports permalinks. Default false.
4235       */
4236      return apply_filters( 'iis7_supports_permalinks', $supports_permalinks );
4237  }
4238  
4239  /**
4240   * File validates against allowed set of defined rules.
4241   *
4242   * A return value of '1' means that the $file contains either '..' or './'. A
4243   * return value of '2' means that the $file contains ':' after the first
4244   * character. A return value of '3' means that the file is not in the allowed
4245   * files list.
4246   *
4247   * @since 1.2.0
4248   *
4249   * @param string $file File path.
4250   * @param array  $allowed_files List of allowed files.
4251   * @return int 0 means nothing is wrong, greater than 0 means something was wrong.
4252   */
4253  function validate_file( $file, $allowed_files = '' ) {
4254      if ( false !== strpos( $file, '..' ) )
4255          return 1;
4256  
4257      if ( false !== strpos( $file, './' ) )
4258          return 1;
4259  
4260      if ( ! empty( $allowed_files ) && ! in_array( $file, $allowed_files ) )
4261          return 3;
4262  
4263      if (':' == substr( $file, 1, 1 ) )
4264          return 2;
4265  
4266      return 0;
4267  }
4268  
4269  /**
4270   * Whether to force SSL used for the Administration Screens.
4271   *
4272   * @since 2.6.0
4273   *
4274   * @staticvar bool $forced
4275   *
4276   * @param string|bool $force Optional. Whether to force SSL in admin screens. Default null.
4277   * @return bool True if forced, false if not forced.
4278   */
4279  function force_ssl_admin( $force = null ) {
4280      static $forced = false;
4281  
4282      if ( !is_null( $force ) ) {
4283          $old_forced = $forced;
4284          $forced = $force;
4285          return $old_forced;
4286      }
4287  
4288      return $forced;
4289  }
4290  
4291  /**
4292   * Guess the URL for the site.
4293   *
4294   * Will remove wp-admin links to retrieve only return URLs not in the wp-admin
4295   * directory.
4296   *
4297   * @since 2.6.0
4298   *
4299   * @return string The guessed URL.
4300   */
4301  function wp_guess_url() {
4302      if ( defined('WP_SITEURL') && '' != WP_SITEURL ) {
4303          $url = WP_SITEURL;
4304      } else {
4305          $abspath_fix = str_replace( '\\', '/', ABSPATH );
4306          $script_filename_dir = dirname( $_SERVER['SCRIPT_FILENAME'] );
4307  
4308          // The request is for the admin
4309          if ( strpos( $_SERVER['REQUEST_URI'], 'wp-admin' ) !== false || strpos( $_SERVER['REQUEST_URI'], 'wp-login.php' ) !== false ) {
4310              $path = preg_replace( '#/(wp-admin/.*|wp-login.php)#i', '', $_SERVER['REQUEST_URI'] );
4311  
4312          // The request is for a file in ABSPATH
4313          } elseif ( $script_filename_dir . '/' == $abspath_fix ) {
4314              // Strip off any file/query params in the path
4315              $path = preg_replace( '#/[^/]*$#i', '', $_SERVER['PHP_SELF'] );
4316  
4317          } else {
4318              if ( false !== strpos( $_SERVER['SCRIPT_FILENAME'], $abspath_fix ) ) {
4319                  // Request is hitting a file inside ABSPATH
4320                  $directory = str_replace( ABSPATH, '', $script_filename_dir );
4321                  // Strip off the sub directory, and any file/query params
4322                  $path = preg_replace( '#/' . preg_quote( $directory, '#' ) . '/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] );
4323              } elseif ( false !== strpos( $abspath_fix, $script_filename_dir ) ) {
4324                  // Request is hitting a file above ABSPATH
4325                  $subdirectory = substr( $abspath_fix, strpos( $abspath_fix, $script_filename_dir ) + strlen( $script_filename_dir ) );
4326                  // Strip off any file/query params from the path, appending the sub directory to the install
4327                  $path = preg_replace( '#/[^/]*$#i', '' , $_SERVER['REQUEST_URI'] ) . $subdirectory;
4328              } else {
4329                  $path = $_SERVER['REQUEST_URI'];
4330              }
4331          }
4332  
4333          $schema = is_ssl() ? 'https://' : 'http://'; // set_url_scheme() is not defined yet
4334          $url = $schema . $_SERVER['HTTP_HOST'] . $path;
4335      }
4336  
4337      return rtrim($url, '/');
4338  }
4339  
4340  /**
4341   * Temporarily suspend cache additions.
4342   *
4343   * Stops more data being added to the cache, but still allows cache retrieval.
4344   * This is useful for actions, such as imports, when a lot of data would otherwise
4345   * be almost uselessly added to the cache.
4346   *
4347   * Suspension lasts for a single page load at most. Remember to call this
4348   * function again if you wish to re-enable cache adds earlier.
4349   *
4350   * @since 3.3.0
4351   *
4352   * @staticvar bool $_suspend
4353   *
4354   * @param bool $suspend Optional. Suspends additions if true, re-enables them if false.
4355   * @return bool The current suspend setting
4356   */
4357  function wp_suspend_cache_addition( $suspend = null ) {
4358      static $_suspend = false;
4359  
4360      if ( is_bool( $suspend ) )
4361          $_suspend = $suspend;
4362  
4363      return $_suspend;
4364  }
4365  
4366  /**
4367   * Suspend cache invalidation.
4368   *
4369   * Turns cache invalidation on and off. Useful during imports where you don't want to do
4370   * invalidations every time a post is inserted. Callers must be sure that what they are
4371   * doing won't lead to an inconsistent cache when invalidation is suspended.
4372   *
4373   * @since 2.7.0
4374   *
4375   * @global bool $_wp_suspend_cache_invalidation
4376   *
4377   * @param bool $suspend Optional. Whether to suspend or enable cache invalidation. Default true.
4378   * @return bool The current suspend setting.
4379   */
4380  function wp_suspend_cache_invalidation( $suspend = true ) {
4381      global $_wp_suspend_cache_invalidation;
4382  
4383      $current_suspend = $_wp_suspend_cache_invalidation;
4384      $_wp_suspend_cache_invalidation = $suspend;
4385      return $current_suspend;
4386  }
4387  
4388  /**
4389   * Determine whether a site is the main site of the current network.
4390   *
4391   * @since 3.0.0
4392   *
4393   * @param int $site_id Optional. Site ID to test. Defaults to current site.
4394   * @return bool True if $site_id is the main site of the network, or if not
4395   *              running Multisite.
4396   */
4397  function is_main_site( $site_id = null ) {
4398      if ( ! is_multisite() )
4399          return true;
4400  
4401      if ( ! $site_id )
4402          $site_id = get_current_blog_id();
4403  
4404      return (int) $site_id === (int) get_network()->site_id;
4405  }
4406  
4407  /**
4408   * Determine whether a network is the main network of the Multisite install.
4409   *
4410   * @since 3.7.0
4411   *
4412   * @param int $network_id Optional. Network ID to test. Defaults to current network.
4413   * @return bool True if $network_id is the main network, or if not running Multisite.
4414   */
4415  function is_main_network( $network_id = null ) {
4416      if ( ! is_multisite() ) {
4417          return true;
4418      }
4419  
4420      if ( null === $network_id ) {
4421          $network_id = get_current_network_id();
4422      }
4423  
4424      $network_id = (int) $network_id;
4425  
4426      return ( $network_id === get_main_network_id() );
4427  }
4428  
4429  /**
4430   * Get the main network ID.
4431   *
4432   * @since 4.3.0
4433   *
4434   * @return int The ID of the main network.
4435   */
4436  function get_main_network_id() {
4437      if ( ! is_multisite() ) {
4438          return 1;
4439      }
4440  
4441      $current_network = get_network();
4442  
4443      if ( defined( 'PRIMARY_NETWORK_ID' ) ) {
4444          $main_network_id = PRIMARY_NETWORK_ID;
4445      } elseif ( isset( $current_network->id ) && 1 === (int) $current_network->id ) {
4446          // If the current network has an ID of 1, assume it is the main network.
4447          $main_network_id = 1;
4448      } else {
4449          $_networks = get_networks( array( 'fields' => 'ids', 'number' => 1 ) );
4450          $main_network_id = array_shift( $_networks );
4451      }
4452  
4453      /**
4454       * Filters the main network ID.
4455       *
4456       * @since 4.3.0
4457       *
4458       * @param int $main_network_id The ID of the main network.
4459       */
4460      return (int) apply_filters( 'get_main_network_id', $main_network_id );
4461  }
4462  
4463  /**
4464   * Determine whether global terms are enabled.
4465   *
4466   * @since 3.0.0
4467   *
4468   * @staticvar bool $global_terms
4469   *
4470   * @return bool True if multisite and global terms enabled.
4471   */
4472  function global_terms_enabled() {
4473      if ( ! is_multisite() )
4474          return false;
4475  
4476      static $global_terms = null;
4477      if ( is_null( $global_terms ) ) {
4478  
4479          /**
4480           * Filters whether global terms are enabled.
4481           *
4482           * Passing a non-null value to the filter will effectively short-circuit the function,
4483           * returning the value of the 'global_terms_enabled' site option instead.
4484           *
4485           * @since 3.0.0
4486           *
4487           * @param null $enabled Whether global terms are enabled.
4488           */
4489          $filter = apply_filters( 'global_terms_enabled', null );
4490          if ( ! is_null( $filter ) )
4491              $global_terms = (bool) $filter;
4492          else
4493              $global_terms = (bool) get_site_option( 'global_terms_enabled', false );
4494      }
4495      return $global_terms;
4496  }
4497  
4498  /**
4499   * gmt_offset modification for smart timezone handling.
4500   *
4501   * Overrides the gmt_offset option if we have a timezone_string available.
4502   *
4503   * @since 2.8.0
4504   *
4505   * @return float|false Timezone GMT offset, false otherwise.
4506   */
4507  function wp_timezone_override_offset() {
4508      if ( !$timezone_string = get_option( 'timezone_string' ) ) {
4509          return false;
4510      }
4511  
4512      $timezone_object = timezone_open( $timezone_string );
4513      $datetime_object = date_create();
4514      if ( false === $timezone_object || false === $datetime_object ) {
4515          return false;
4516      }
4517      return round( timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS, 2 );
4518  }
4519  
4520  /**
4521   * Sort-helper for timezones.
4522   *
4523   * @since 2.9.0
4524   * @access private
4525   *
4526   * @param array $a
4527   * @param array $b
4528   * @return int
4529   */
4530  function _wp_timezone_choice_usort_callback( $a, $b ) {
4531      // Don't use translated versions of Etc
4532      if ( 'Etc' === $a['continent'] && 'Etc' === $b['continent'] ) {
4533          // Make the order of these more like the old dropdown
4534          if ( 'GMT+' === substr( $a['city'], 0, 4 ) && 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4535              return -1 * ( strnatcasecmp( $a['city'], $b['city'] ) );
4536          }
4537          if ( 'UTC' === $a['city'] ) {
4538              if ( 'GMT+' === substr( $b['city'], 0, 4 ) ) {
4539                  return 1;
4540              }
4541              return -1;
4542          }
4543          if ( 'UTC' === $b['city'] ) {
4544              if ( 'GMT+' === substr( $a['city'], 0, 4 ) ) {
4545                  return -1;
4546              }
4547              return 1;
4548          }
4549          return strnatcasecmp( $a['city'], $b['city'] );
4550      }
4551      if ( $a['t_continent'] == $b['t_continent'] ) {
4552          if ( $a['t_city'] == $b['t_city'] ) {
4553              return strnatcasecmp( $a['t_subcity'], $b['t_subcity'] );
4554          }
4555          return strnatcasecmp( $a['t_city'], $b['t_city'] );
4556      } else {
4557          // Force Etc to the bottom of the list
4558          if ( 'Etc' === $a['continent'] ) {
4559              return 1;
4560          }
4561          if ( 'Etc' === $b['continent'] ) {
4562              return -1;
4563          }
4564          return strnatcasecmp( $a['t_continent'], $b['t_continent'] );
4565      }
4566  }
4567  
4568  /**
4569   * Gives a nicely-formatted list of timezone strings.
4570   *
4571   * @since 2.9.0
4572   * @since 4.7.0 Added the `$locale` parameter.
4573   *
4574   * @staticvar bool $mo_loaded
4575   * @staticvar string $locale_loaded
4576   *
4577   * @param string $selected_zone Selected timezone.
4578   * @param string $locale        Optional. Locale to load the timezones in. Default current site locale.
4579   * @return string
4580   */
4581  function wp_timezone_choice( $selected_zone, $locale = null ) {
4582      static $mo_loaded = false, $locale_loaded = null;
4583  
4584      $continents = array( 'Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific');
4585  
4586      // Load translations for continents and cities.
4587      if ( ! $mo_loaded || $locale !== $locale_loaded ) {
4588          $locale_loaded = $locale ? $locale : get_locale();
4589          $mofile = WP_LANG_DIR . '/continents-cities-' . $locale_loaded . '.mo';
4590          unload_textdomain( 'continents-cities' );
4591          load_textdomain( 'continents-cities', $mofile );
4592          $mo_loaded = true;
4593      }
4594  
4595      $zonen = array();
4596      foreach ( timezone_identifiers_list() as $zone ) {
4597          $zone = explode( '/', $zone );
4598          if ( !in_array( $zone[0], $continents ) ) {
4599              continue;
4600          }
4601  
4602          // This determines what gets set and translated - we don't translate Etc/* strings here, they are done later
4603          $exists = array(
4604              0 => ( isset( $zone[0] ) && $zone[0] ),
4605              1 => ( isset( $zone[1] ) && $zone[1] ),
4606              2 => ( isset( $zone[2] ) && $zone[2] ),
4607          );
4608          $exists[3] = ( $exists[0] && 'Etc' !== $zone[0] );
4609          $exists[4] = ( $exists[1] && $exists[3] );
4610          $exists[5] = ( $exists[2] && $exists[3] );
4611  
4612          $zonen[] = array(
4613              'continent'   => ( $exists[0] ? $zone[0] : '' ),
4614              'city'        => ( $exists[1] ? $zone[1] : '' ),
4615              'subcity'     => ( $exists[2] ? $zone[2] : '' ),
4616              't_continent' => ( $exists[3] ? translate( str_replace( '_', ' ', $zone[0] ), 'continents-cities' ) : '' ),
4617              't_city'      => ( $exists[4] ? translate( str_replace( '_', ' ', $zone[1] ), 'continents-cities' ) : '' ),
4618              't_subcity'   => ( $exists[5] ? translate( str_replace( '_', ' ', $zone[2] ), 'continents-cities' ) : '' )
4619          );
4620      }
4621      usort( $zonen, '_wp_timezone_choice_usort_callback' );
4622  
4623      $structure = array();
4624  
4625      if ( empty( $selected_zone ) ) {
4626          $structure[] = '<option selected="selected" value="">' . __( 'Select a city' ) . '</option>';
4627      }
4628  
4629      foreach ( $zonen as $key => $zone ) {
4630          // Build value in an array to join later
4631          $value = array( $zone['continent'] );
4632  
4633          if ( empty( $zone['city'] ) ) {
4634              // It's at the continent level (generally won't happen)
4635              $display = $zone['t_continent'];
4636          } else {
4637              // It's inside a continent group
4638  
4639              // Continent optgroup
4640              if ( !isset( $zonen[$key - 1] ) || $zonen[$key - 1]['continent'] !== $zone['continent'] ) {
4641                  $label = $zone['t_continent'];
4642                  $structure[] = '<optgroup label="'. esc_attr( $label ) .'">';
4643              }
4644  
4645              // Add the city to the value
4646              $value[] = $zone['city'];
4647  
4648              $display = $zone['t_city'];
4649              if ( !empty( $zone['subcity'] ) ) {
4650                  // Add the subcity to the value
4651                  $value[] = $zone['subcity'];
4652                  $display .= ' - ' . $zone['t_subcity'];
4653              }
4654          }
4655  
4656          // Build the value
4657          $value = join( '/', $value );
4658          $selected = '';
4659          if ( $value === $selected_zone ) {
4660              $selected = 'selected="selected" ';
4661          }
4662          $structure[] = '<option ' . $selected . 'value="' . esc_attr( $value ) . '">' . esc_html( $display ) . "</option>";
4663  
4664          // Close continent optgroup
4665          if ( !empty( $zone['city'] ) && ( !isset($zonen[$key + 1]) || (isset( $zonen[$key + 1] ) && $zonen[$key + 1]['continent'] !== $zone['continent']) ) ) {
4666              $structure[] = '</optgroup>';
4667          }
4668      }
4669  
4670      // Do UTC
4671      $structure[] = '<optgroup label="'. esc_attr__( 'UTC' ) .'">';
4672      $selected = '';
4673      if ( 'UTC' === $selected_zone )
4674          $selected = 'selected="selected" ';
4675      $structure[] = '<option ' . $selected . 'value="' . esc_attr( 'UTC' ) . '">' . __('UTC') . '</option>';
4676      $structure[] = '</optgroup>';
4677  
4678      // Do manual UTC offsets
4679      $structure[] = '<optgroup label="'. esc_attr__( 'Manual Offsets' ) .'">';
4680      $offset_range = array (-12, -11.5, -11, -10.5, -10, -9.5, -9, -8.5, -8, -7.5, -7, -6.5, -6, -5.5, -5, -4.5, -4, -3.5, -3, -2.5, -2, -1.5, -1, -0.5,
4681          0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5, 5.5, 5.75, 6, 6.5, 7, 7.5, 8, 8.5, 8.75, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 13.75, 14);
4682      foreach ( $offset_range as $offset ) {
4683          if ( 0 <= $offset )
4684              $offset_name = '+' . $offset;
4685          else
4686              $offset_name = (string) $offset;
4687  
4688          $offset_value = $offset_name;
4689          $offset_name = str_replace(array('.25','.5','.75'), array(':15',':30',':45'), $offset_name);
4690          $offset_name = 'UTC' . $offset_name;
4691          $offset_value = 'UTC' . $offset_value;
4692          $selected = '';
4693          if ( $offset_value === $selected_zone )
4694              $selected = 'selected="selected" ';
4695          $structure[] = '<option ' . $selected . 'value="' . esc_attr( $offset_value ) . '">' . esc_html( $offset_name ) . "</option>";
4696  
4697      }
4698      $structure[] = '</optgroup>';
4699  
4700      return join( "\n", $structure );
4701  }
4702  
4703  /**
4704   * Strip close comment and close php tags from file headers used by WP.
4705   *
4706   * @since 2.8.0
4707   * @access private
4708   *
4709   * @see https://core.trac.wordpress.org/ticket/8497
4710   *
4711   * @param string $str Header comment to clean up.
4712   * @return string
4713   */
4714  function _cleanup_header_comment( $str ) {
4715      return trim(preg_replace("/\s*(?:\*\/|\?>).*/", '', $str));
4716  }
4717  
4718  /**
4719   * Permanently delete comments or posts of any type that have held a status
4720   * of 'trash' for the number of days defined in EMPTY_TRASH_DAYS.
4721   *
4722   * The default value of `EMPTY_TRASH_DAYS` is 30 (days).
4723   *
4724   * @since 2.9.0
4725   *
4726   * @global wpdb $wpdb WordPress database abstraction object.
4727   */
4728  function wp_scheduled_delete() {
4729      global $wpdb;
4730  
4731      $delete_timestamp = time() - ( DAY_IN_SECONDS * EMPTY_TRASH_DAYS );
4732  
4733      $posts_to_delete = $wpdb->get_results($wpdb->prepare("SELECT post_id FROM $wpdb->postmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
4734  
4735      foreach ( (array) $posts_to_delete as $post ) {
4736          $post_id = (int) $post['post_id'];
4737          if ( !$post_id )
4738              continue;
4739  
4740          $del_post = get_post($post_id);
4741  
4742          if ( !$del_post || 'trash' != $del_post->post_status ) {
4743              delete_post_meta($post_id, '_wp_trash_meta_status');
4744              delete_post_meta($post_id, '_wp_trash_meta_time');
4745          } else {
4746              wp_delete_post($post_id);
4747          }
4748      }
4749  
4750      $comments_to_delete = $wpdb->get_results($wpdb->prepare("SELECT comment_id FROM $wpdb->commentmeta WHERE meta_key = '_wp_trash_meta_time' AND meta_value < '%d'", $delete_timestamp), ARRAY_A);
4751  
4752      foreach ( (array) $comments_to_delete as $comment ) {
4753          $comment_id = (int) $comment['comment_id'];
4754          if ( !$comment_id )
4755              continue;
4756  
4757          $del_comment = get_comment($comment_id);
4758  
4759          if ( !$del_comment || 'trash' != $del_comment->comment_approved ) {
4760              delete_comment_meta($comment_id, '_wp_trash_meta_time');
4761              delete_comment_meta($comment_id, '_wp_trash_meta_status');
4762          } else {
4763              wp_delete_comment( $del_comment );
4764          }
4765      }
4766  }
4767  
4768  /**
4769   * Retrieve metadata from a file.
4770   *
4771   * Searches for metadata in the first 8kiB of a file, such as a plugin or theme.
4772   * Each piece of metadata must be on its own line. Fields can not span multiple
4773   * lines, the value will get cut at the end of the first line.
4774   *
4775   * If the file data is not within that first 8kiB, then the author should correct
4776   * their plugin file and move the data headers to the top.
4777   *
4778   * @link https://codex.wordpress.org/File_Header
4779   *
4780   * @since 2.9.0
4781   *
4782   * @param string $file            Path to the file.
4783   * @param array  $default_headers List of headers, in the format array('HeaderKey' => 'Header Name').
4784   * @param string $context         Optional. If specified adds filter hook {@see 'extra_$context_headers'}.
4785   *                                Default empty.
4786   * @return array Array of file headers in `HeaderKey => Header Value` format.
4787   */
4788  function get_file_data( $file, $default_headers, $context = '' ) {
4789      // We don't need to write to the file, so just open for reading.
4790      $fp = fopen( $file, 'r' );
4791  
4792      // Pull only the first 8kiB of the file in.
4793      $file_data = fread( $fp, 8192 );
4794  
4795      // PHP will close file handle, but we are good citizens.
4796      fclose( $fp );
4797  
4798      // Make sure we catch CR-only line endings.
4799      $file_data = str_replace( "\r", "\n", $file_data );
4800  
4801      /**
4802       * Filters extra file headers by context.
4803       *
4804       * The dynamic portion of the hook name, `$context`, refers to
4805       * the context where extra headers might be loaded.
4806       *
4807       * @since 2.9.0
4808       *
4809       * @param array $extra_context_headers Empty array by default.
4810       */
4811      if ( $context && $extra_headers = apply_filters( "extra_{$context}_headers", array() ) ) {
4812          $extra_headers = array_combine( $extra_headers, $extra_headers ); // keys equal values
4813          $all_headers = array_merge( $extra_headers, (array) $default_headers );
4814      } else {
4815          $all_headers = $default_headers;
4816      }
4817  
4818      foreach ( $all_headers as $field => $regex ) {
4819          if ( preg_match( '/^[ \t\/*#@]*' . preg_quote( $regex, '/' ) . ':(.*)$/mi', $file_data, $match ) && $match[1] )
4820              $all_headers[ $field ] = _cleanup_header_comment( $match[1] );
4821          else
4822              $all_headers[ $field ] = '';
4823      }
4824  
4825      return $all_headers;
4826  }
4827  
4828  /**
4829   * Returns true.
4830   *
4831   * Useful for returning true to filters easily.
4832   *
4833   * @since 3.0.0
4834   *
4835   * @see __return_false()
4836   *
4837   * @return true True.
4838   */
4839  function __return_true() {
4840      return true;
4841  }
4842  
4843  /**
4844   * Returns false.
4845   *
4846   * Useful for returning false to filters easily.
4847   *
4848   * @since 3.0.0
4849   *
4850   * @see __return_true()
4851   *
4852   * @return false False.
4853   */
4854  function __return_false() {
4855      return false;
4856  }
4857  
4858  /**
4859   * Returns 0.
4860   *
4861   * Useful for returning 0 to filters easily.
4862   *
4863   * @since 3.0.0
4864   *
4865   * @return int 0.
4866   */
4867  function __return_zero() {
4868      return 0;
4869  }
4870  
4871  /**
4872   * Returns an empty array.
4873   *
4874   * Useful for returning an empty array to filters easily.
4875   *
4876   * @since 3.0.0
4877   *
4878   * @return array Empty array.
4879   */
4880  function __return_empty_array() {
4881      return array();
4882  }
4883  
4884  /**
4885   * Returns null.
4886   *
4887   * Useful for returning null to filters easily.
4888   *
4889   * @since 3.4.0
4890   *
4891   * @return null Null value.
4892   */
4893  function __return_null() {
4894      return null;
4895  }
4896  
4897  /**
4898   * Returns an empty string.
4899   *
4900   * Useful for returning an empty string to filters easily.
4901   *
4902   * @since 3.7.0
4903   *
4904   * @see __return_null()
4905   *
4906   * @return string Empty string.
4907   */
4908  function __return_empty_string() {
4909      return '';
4910  }
4911  
4912  /**
4913   * Send a HTTP header to disable content type sniffing in browsers which support it.
4914   *
4915   * @since 3.0.0
4916   *
4917   * @see https://blogs.msdn.com/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
4918   * @see https://src.chromium.org/viewvc/chrome?view=rev&revision=6985
4919   */
4920  function send_nosniff_header() {
4921      @header( 'X-Content-Type-Options: nosniff' );
4922  }
4923  
4924  /**
4925   * Return a MySQL expression for selecting the week number based on the start_of_week option.
4926   *
4927   * @ignore
4928   * @since 3.0.0
4929   *
4930   * @param string $column Database column.
4931   * @return string SQL clause.
4932   */
4933  function _wp_mysql_week( $column ) {
4934      switch ( $start_of_week = (int) get_option( 'start_of_week' ) ) {
4935      case 1 :
4936          return "WEEK( $column, 1 )";
4937      case 2 :
4938      case 3 :
4939      case 4 :
4940      case 5 :
4941      case 6 :
4942          return "WEEK( DATE_SUB( $column, INTERVAL $start_of_week DAY ), 0 )";
4943      case 0 :
4944      default :
4945          return "WEEK( $column, 0 )";
4946      }
4947  }
4948  
4949  /**
4950   * Find hierarchy loops using a callback function that maps object IDs to parent IDs.
4951   *
4952   * @since 3.1.0
4953   * @access private
4954   *
4955   * @param callable $callback      Function that accepts ( ID, $callback_args ) and outputs parent_ID.
4956   * @param int      $start         The ID to start the loop check at.
4957   * @param int      $start_parent  The parent_ID of $start to use instead of calling $callback( $start ).
4958   *                                Use null to always use $callback
4959   * @param array    $callback_args Optional. Additional arguments to send to $callback.
4960   * @return array IDs of all members of loop.
4961   */
4962  function wp_find_hierarchy_loop( $callback, $start, $start_parent, $callback_args = array() ) {
4963      $override = is_null( $start_parent ) ? array() : array( $start => $start_parent );
4964  
4965      if ( !$arbitrary_loop_member = wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override, $callback_args ) )
4966          return array();
4967  
4968      return wp_find_hierarchy_loop_tortoise_hare( $callback, $arbitrary_loop_member, $override, $callback_args, true );
4969  }
4970  
4971  /**
4972   * Use the "The Tortoise and the Hare" algorithm to detect loops.
4973   *
4974   * For every step of the algorithm, the hare takes two steps and the tortoise one.
4975   * If the hare ever laps the tortoise, there must be a loop.
4976   *
4977   * @since 3.1.0
4978   * @access private
4979   *
4980   * @param callable $callback      Function that accepts ( ID, callback_arg, ... ) and outputs parent_ID.
4981   * @param int      $start         The ID to start the loop check at.
4982   * @param array    $override      Optional. An array of ( ID => parent_ID, ... ) to use instead of $callback.
4983   *                                Default empty array.
4984   * @param array    $callback_args Optional. Additional arguments to send to $callback. Default empty array.
4985   * @param bool     $_return_loop  Optional. Return loop members or just detect presence of loop? Only set
4986   *                                to true if you already know the given $start is part of a loop (otherwise
4987   *                                the returned array might include branches). Default false.
4988   * @return mixed Scalar ID of some arbitrary member of the loop, or array of IDs of all members of loop if
4989   *               $_return_loop
4990   */
4991  function wp_find_hierarchy_loop_tortoise_hare( $callback, $start, $override = array(), $callback_args = array(), $_return_loop = false ) {
4992      $tortoise = $hare = $evanescent_hare = $start;
4993      $return = array();
4994  
4995      // Set evanescent_hare to one past hare
4996      // Increment hare two steps
4997      while (
4998          $tortoise
4999      &&
5000          ( $evanescent_hare = isset( $override[$hare] ) ? $override[$hare] : call_user_func_array( $callback, array_merge( array( $hare ), $callback_args ) ) )
5001      &&
5002          ( $hare = isset( $override[$evanescent_hare] ) ? $override[$evanescent_hare] : call_user_func_array( $callback, array_merge( array( $evanescent_hare ), $callback_args ) ) )
5003      ) {
5004          if ( $_return_loop )
5005              $return[$tortoise] = $return[$evanescent_hare] = $return[$hare] = true;
5006  
5007          // tortoise got lapped - must be a loop
5008          if ( $tortoise == $evanescent_hare || $tortoise == $hare )
5009              return $_return_loop ? $return : $tortoise;
5010  
5011          // Increment tortoise by one step
5012          $tortoise = isset( $override[$tortoise] ) ? $override[$tortoise] : call_user_func_array( $callback, array_merge( array( $tortoise ), $callback_args ) );
5013      }
5014  
5015      return false;
5016  }
5017  
5018  /**
5019   * Send a HTTP header to limit rendering of pages to same origin iframes.
5020   *
5021   * @since 3.1.3
5022   *
5023   * @see https://developer.mozilla.org/en/the_x-frame-options_response_header
5024   */
5025  function send_frame_options_header() {
5026      @header( 'X-Frame-Options: SAMEORIGIN' );
5027  }
5028  
5029  /**
5030   * Retrieve a list of protocols to allow in HTML attributes.
5031   *
5032   * @since 3.3.0
5033   * @since 4.3.0 Added 'webcal' to the protocols array.
5034   * @since 4.7.0 Added 'urn' to the protocols array.
5035   *
5036   * @see wp_kses()
5037   * @see esc_url()
5038   *
5039   * @staticvar array $protocols
5040   *
5041   * @return array Array of allowed protocols. Defaults to an array containing 'http', 'https',
5042   *               'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet',
5043   *               'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', and 'urn'.
5044   */
5045  function wp_allowed_protocols() {
5046      static $protocols = array();
5047  
5048      if ( empty( $protocols ) ) {
5049          $protocols = array( 'http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet', 'mms', 'rtsp', 'svn', 'tel', 'fax', 'xmpp', 'webcal', 'urn' );
5050  
5051          /**
5052           * Filters the list of protocols allowed in HTML attributes.
5053           *
5054           * @since 3.0.0
5055           *
5056           * @param array $protocols Array of allowed protocols e.g. 'http', 'ftp', 'tel', and more.
5057           */
5058          $protocols = apply_filters( 'kses_allowed_protocols', $protocols );
5059      }
5060  
5061      return $protocols;
5062  }
5063  
5064  /**
5065   * Return a comma-separated string of functions that have been called to get
5066   * to the current point in code.
5067   *
5068   * @since 3.4.0
5069   *
5070   * @see https://core.trac.wordpress.org/ticket/19589
5071   *
5072   * @param string $ignore_class Optional. A class to ignore all function calls within - useful
5073   *                             when you want to just give info about the callee. Default null.
5074   * @param int    $skip_frames  Optional. A number of stack frames to skip - useful for unwinding
5075   *                             back to the source of the issue. Default 0.
5076   * @param bool   $pretty       Optional. Whether or not you want a comma separated string or raw
5077   *                             array returned. Default true.
5078   * @return string|array Either a string containing a reversed comma separated trace or an array
5079   *                      of individual calls.
5080   */
5081  function wp_debug_backtrace_summary( $ignore_class = null, $skip_frames = 0, $pretty = true ) {
5082      if ( version_compare( PHP_VERSION, '5.2.5', '>=' ) )
5083          $trace = debug_backtrace( false );
5084      else
5085          $trace = debug_backtrace();
5086  
5087      $caller = array();
5088      $check_class = ! is_null( $ignore_class );
5089      $skip_frames++; // skip this function
5090  
5091      foreach ( $trace as $call ) {
5092          if ( $skip_frames > 0 ) {
5093              $skip_frames--;
5094          } elseif ( isset( $call['class'] ) ) {
5095              if ( $check_class && $ignore_class == $call['class'] )
5096                  continue; // Filter out calls
5097  
5098              $caller[] = "{$call['class']}{$call['type']}{$call['function']}";
5099          } else {
5100              if ( in_array( $call['function'], array( 'do_action', 'apply_filters' ) ) ) {
5101                  $caller[] = "{$call['function']}('{$call['args'][0]}')";
5102              } elseif ( in_array( $call['function'], array( 'include', 'include_once', 'require', 'require_once' ) ) ) {
5103                  $caller[] = $call['function'] . "('" . str_replace( array( WP_CONTENT_DIR, ABSPATH ) , '', $call['args'][0] ) . "')";
5104              } else {
5105                  $caller[] = $call['function'];
5106              }
5107          }
5108      }
5109      if ( $pretty )
5110          return join( ', ', array_reverse( $caller ) );
5111      else
5112          return $caller;
5113  }
5114  
5115  /**
5116   * Retrieve ids that are not already present in the cache.
5117   *
5118   * @since 3.4.0
5119   * @access private
5120   *
5121   * @param array  $object_ids ID list.
5122   * @param string $cache_key  The cache bucket to check against.
5123   *
5124   * @return array List of ids not present in the cache.
5125   */
5126  function _get_non_cached_ids( $object_ids, $cache_key ) {
5127      $clean = array();
5128      foreach ( $object_ids as $id ) {
5129          $id = (int) $id;
5130          if ( !wp_cache_get( $id, $cache_key ) ) {
5131              $clean[] = $id;
5132          }
5133      }
5134  
5135      return $clean;
5136  }
5137  
5138  /**
5139   * Test if the current device has the capability to upload files.
5140   *
5141   * @since 3.4.0
5142   * @access private
5143   *
5144   * @return bool Whether the device is able to upload files.
5145   */
5146  function _device_can_upload() {
5147      if ( ! wp_is_mobile() )
5148          return true;
5149  
5150      $ua = $_SERVER['HTTP_USER_AGENT'];
5151  
5152      if ( strpos($ua, 'iPhone') !== false
5153          || strpos($ua, 'iPad') !== false
5154          || strpos($ua, 'iPod') !== false ) {
5155              return preg_match( '#OS ([\d_]+) like Mac OS X#', $ua, $version ) && version_compare( $version[1], '6', '>=' );
5156      }
5157  
5158      return true;
5159  }
5160  
5161  /**
5162   * Test if a given path is a stream URL
5163   *
5164   * @since 3.5.0
5165   *
5166   * @param string $path The resource path or URL.
5167   * @return bool True if the path is a stream URL.
5168   */
5169  function wp_is_stream( $path ) {
5170      $wrappers = stream_get_wrappers();
5171      $wrappers_re = '(' . join('|', $wrappers) . ')';
5172  
5173      return preg_match( "!^$wrappers_re://!", $path ) === 1;
5174  }
5175  
5176  /**
5177   * Test if the supplied date is valid for the Gregorian calendar.
5178   *
5179   * @since 3.5.0
5180   *
5181   * @see checkdate()
5182   *
5183   * @param  int    $month       Month number.
5184   * @param  int    $day         Day number.
5185   * @param  int    $year        Year number.
5186   * @param  string $source_date The date to filter.
5187   * @return bool True if valid date, false if not valid date.
5188   */
5189  function wp_checkdate( $month, $day, $year, $source_date ) {
5190      /**
5191       * Filters whether the given date is valid for the Gregorian calendar.
5192       *
5193       * @since 3.5.0
5194       *
5195       * @param bool   $checkdate   Whether the given date is valid.
5196       * @param string $source_date Date to check.
5197       */
5198      return apply_filters( 'wp_checkdate', checkdate( $month, $day, $year ), $source_date );
5199  }
5200  
5201  /**
5202   * Load the auth check for monitoring whether the user is still logged in.
5203   *
5204   * Can be disabled with remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
5205   *
5206   * This is disabled for certain screens where a login screen could cause an
5207   * inconvenient interruption. A filter called {@see 'wp_auth_check_load'} can be used
5208   * for fine-grained control.
5209   *
5210   * @since 3.6.0
5211   */
5212  function wp_auth_check_load() {
5213      if ( ! is_admin() && ! is_user_logged_in() )
5214          return;
5215  
5216      if ( defined( 'IFRAME_REQUEST' ) )
5217          return;
5218  
5219      $screen = get_current_screen();
5220      $hidden = array( 'update', 'update-network', 'update-core', 'update-core-network', 'upgrade', 'upgrade-network', 'network' );
5221      $show = ! in_array( $screen->id, $hidden );
5222  
5223      /**
5224       * Filters whether to load the authentication check.
5225       *
5226       * Passing a falsey value to the filter will effectively short-circuit
5227       * loading the authentication check.
5228       *
5229       * @since 3.6.0
5230       *
5231       * @param bool      $show   Whether to load the authentication check.
5232       * @param WP_Screen $screen The current screen object.
5233       */
5234      if ( apply_filters( 'wp_auth_check_load', $show, $screen ) ) {
5235          wp_enqueue_style( 'wp-auth-check' );
5236          wp_enqueue_script( 'wp-auth-check' );
5237  
5238          add_action( 'admin_print_footer_scripts', 'wp_auth_check_html', 5 );
5239          add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 );
5240      }
5241  }
5242  
5243  /**
5244   * Output the HTML that shows the wp-login dialog when the user is no longer logged in.
5245   *
5246   * @since 3.6.0
5247   */
5248  function wp_auth_check_html() {
5249      $login_url = wp_login_url();
5250      $current_domain = ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'];
5251      $same_domain = ( strpos( $login_url, $current_domain ) === 0 );
5252  
5253      /**
5254       * Filters whether the authentication check originated at the same domain.
5255       *
5256       * @since 3.6.0
5257       *
5258       * @param bool $same_domain Whether the authentication check originated at the same domain.
5259       */
5260      $same_domain = apply_filters( 'wp_auth_check_same_domain', $same_domain );
5261      $wrap_class = $same_domain ? 'hidden' : 'hidden fallback';
5262  
5263      ?>
5264      <div id="wp-auth-check-wrap" class="<?php echo $wrap_class; ?>">
5265      <div id="wp-auth-check-bg"></div>
5266      <div id="wp-auth-check">
5267      <button type="button" class="wp-auth-check-close button-link"><span class="screen-reader-text"><?php _e( 'Close dialog' ); ?></span></button>
5268      <?php
5269  
5270      if ( $same_domain ) {
5271          ?>
5272          <div id="wp-auth-check-form" class="loading" data-src="<?php echo esc_url( add_query_arg( array( 'interim-login' => 1 ), $login_url ) ); ?>"></div>
5273          <?php
5274      }
5275  
5276      ?>
5277      <div class="wp-auth-fallback">
5278          <p><b class="wp-auth-fallback-expired" tabindex="0"><?php _e('Session expired'); ?></b></p>
5279          <p><a href="<?php echo esc_url( $login_url ); ?>" target="_blank"><?php _e('Please log in again.'); ?></a>
5280          <?php _e('The login page will open in a new window. After logging in you can close it and return to this page.'); ?></p>
5281      </div>
5282      </div>
5283      </div>
5284      <?php
5285  }
5286  
5287  /**
5288   * Check whether a user is still logged in, for the heartbeat.
5289   *
5290   * Send a result that shows a log-in box if the user is no longer logged in,
5291   * or if their cookie is within the grace period.
5292   *
5293   * @since 3.6.0
5294   *
5295   * @global int $login_grace_period
5296   *
5297   * @param array $response  The Heartbeat response.
5298   * @return array $response The Heartbeat response with 'wp-auth-check' value set.
5299   */
5300  function wp_auth_check( $response ) {
5301      $response['wp-auth-check'] = is_user_logged_in() && empty( $GLOBALS['login_grace_period'] );
5302      return $response;
5303  }
5304  
5305  /**
5306   * Return RegEx body to liberally match an opening HTML tag.
5307   *
5308   * Matches an opening HTML tag that:
5309   * 1. Is self-closing or
5310   * 2. Has no body but has a closing tag of the same name or
5311   * 3. Contains a body and a closing tag of the same name
5312   *
5313   * Note: this RegEx does not balance inner tags and does not attempt
5314   * to produce valid HTML
5315   *
5316   * @since 3.6.0
5317   *
5318   * @param string $tag An HTML tag name. Example: 'video'.
5319   * @return string Tag RegEx.
5320   */
5321  function get_tag_regex( $tag ) {
5322      if ( empty( $tag ) )
5323          return;
5324      return sprintf( '<%1$s[^<]*(?:>[\s\S]*<\/%1$s>|\s*\/>)', tag_escape( $tag ) );
5325  }
5326  
5327  /**
5328   * Retrieve a canonical form of the provided charset appropriate for passing to PHP
5329   * functions such as htmlspecialchars() and charset html attributes.
5330   *
5331   * @since 3.6.0
5332   * @access private
5333   *
5334   * @see https://core.trac.wordpress.org/ticket/23688
5335   *
5336   * @param string $charset A charset name.
5337   * @return string The canonical form of the charset.
5338   */
5339  function _canonical_charset( $charset ) {
5340      if ( 'utf-8' === strtolower( $charset ) || 'utf8' === strtolower( $charset) ) {
5341  
5342          return 'UTF-8';
5343      }
5344  
5345      if ( 'iso-8859-1' === strtolower( $charset ) || 'iso8859-1' === strtolower( $charset ) ) {
5346  
5347          return 'ISO-8859-1';
5348      }
5349  
5350      return $charset;
5351  }
5352  
5353  /**
5354   * Set the mbstring internal encoding to a binary safe encoding when func_overload
5355   * is enabled.
5356   *
5357   * When mbstring.func_overload is in use for multi-byte encodings, the results from
5358   * strlen() and similar functions respect the utf8 characters, causing binary data
5359   * to return incorrect lengths.
5360   *
5361   * This function overrides the mbstring encoding to a binary-safe encoding, and
5362   * resets it to the users expected encoding afterwards through the
5363   * `reset_mbstring_encoding` function.
5364   *
5365   * It is safe to recursively call this function, however each
5366   * `mbstring_binary_safe_encoding()` call must be followed up with an equal number
5367   * of `reset_mbstring_encoding()` calls.
5368   *
5369   * @since 3.7.0
5370   *
5371   * @see reset_mbstring_encoding()
5372   *
5373   * @staticvar array $encodings
5374   * @staticvar bool  $overloaded
5375   *
5376   * @param bool $reset Optional. Whether to reset the encoding back to a previously-set encoding.
5377   *                    Default false.
5378   */
5379  function mbstring_binary_safe_encoding( $reset = false ) {
5380      static $encodings = array();
5381      static $overloaded = null;
5382  
5383      if ( is_null( $overloaded ) )
5384          $overloaded = function_exists( 'mb_internal_encoding' ) && ( ini_get( 'mbstring.func_overload' ) & 2 );
5385  
5386      if ( false === $overloaded )
5387          return;
5388  
5389      if ( ! $reset ) {
5390          $encoding = mb_internal_encoding();
5391          array_push( $encodings, $encoding );
5392          mb_internal_encoding( 'ISO-8859-1' );
5393      }
5394  
5395      if ( $reset && $encodings ) {
5396          $encoding = array_pop( $encodings );
5397          mb_internal_encoding( $encoding );
5398      }
5399  }
5400  
5401  /**
5402   * Reset the mbstring internal encoding to a users previously set encoding.
5403   *
5404   * @see mbstring_binary_safe_encoding()
5405   *
5406   * @since 3.7.0
5407   */
5408  function reset_mbstring_encoding() {
5409      mbstring_binary_safe_encoding( true );
5410  }
5411  
5412  /**
5413   * Filter/validate a variable as a boolean.
5414   *
5415   * Alternative to `filter_var( $var, FILTER_VALIDATE_BOOLEAN )`.
5416   *
5417   * @since 4.0.0
5418   *
5419   * @param mixed $var Boolean value to validate.
5420   * @return bool Whether the value is validated.
5421   */
5422  function wp_validate_boolean( $var ) {
5423      if ( is_bool( $var ) ) {
5424          return $var;
5425      }
5426  
5427      if ( is_string( $var ) && 'false' === strtolower( $var ) ) {
5428          return false;
5429      }
5430  
5431      return (bool) $var;
5432  }
5433  
5434  /**
5435   * Delete a file
5436   *
5437   * @since 4.2.0
5438   *
5439   * @param string $file The path to the file to delete.
5440   */
5441  function wp_delete_file( $file ) {
5442      /**
5443       * Filters the path of the file to delete.
5444       *
5445       * @since 2.1.0
5446       *
5447       * @param string $file Path to the file to delete.
5448       */
5449      $delete = apply_filters( 'wp_delete_file', $file );
5450      if ( ! empty( $delete ) ) {
5451          @unlink( $delete );
5452      }
5453  }
5454  
5455  /**
5456   * Outputs a small JS snippet on preview tabs/windows to remove `window.name` on unload.
5457   *
5458   * This prevents reusing the same tab for a preview when the user has navigated away.
5459   *
5460   * @since 4.3.0
5461   *
5462   * @global WP_Post $post
5463   */
5464  function wp_post_preview_js() {
5465      global $post;
5466  
5467      if ( ! is_preview() || empty( $post ) ) {
5468          return;
5469      }
5470  
5471      // Has to match the window name used in post_submit_meta_box()
5472      $name = 'wp-preview-' . (int) $post->ID;
5473  
5474      ?>
5475      <script>
5476      ( function() {
5477          var query = document.location.search;
5478  
5479          if ( query && query.indexOf( 'preview=true' ) !== -1 ) {
5480              window.name = '<?php echo $name; ?>';
5481          }
5482  
5483          if ( window.addEventListener ) {
5484              window.addEventListener( 'unload', function() { window.name = ''; }, false );
5485          }
5486      }());
5487      </script>
5488      <?php
5489  }
5490  
5491  /**
5492   * Parses and formats a MySQL datetime (Y-m-d H:i:s) for ISO8601/RFC3339.
5493   *
5494   * Explicitly strips timezones, as datetimes are not saved with any timezone
5495   * information. Including any information on the offset could be misleading.
5496   *
5497   * @since 4.4.0
5498   *
5499   * @param string $date_string Date string to parse and format.
5500   * @return string Date formatted for ISO8601/RFC3339.
5501   */
5502  function mysql_to_rfc3339( $date_string ) {
5503      $formatted = mysql2date( 'c', $date_string, false );
5504  
5505      // Strip timezone information
5506      return preg_replace( '/(?:Z|[+-]\d{2}(?::\d{2})?)$/', '', $formatted );
5507  }
5508  
5509  /**
5510   * Attempts to raise the PHP memory limit for memory intensive processes.
5511   *
5512   * Only allows raising the existing limit and prevents lowering it.
5513   *
5514   * @since 4.6.0
5515   *
5516   * @param string $context Optional. Context in which the function is called. Accepts either 'admin',
5517   *                        'image', or an arbitrary other context. If an arbitrary context is passed,
5518   *                        the similarly arbitrary {@see '{$context}_memory_limit'} filter will be
5519   *                        invoked. Default 'admin'.
5520   * @return bool|int|string The limit that was set or false on failure.
5521   */
5522  function wp_raise_memory_limit( $context = 'admin' ) {
5523      // Exit early if the limit cannot be changed.
5524      if ( false === wp_is_ini_value_changeable( 'memory_limit' ) ) {
5525          return false;
5526      }
5527  
5528      $current_limit     = @ini_get( 'memory_limit' );
5529      $current_limit_int = wp_convert_hr_to_bytes( $current_limit );
5530  
5531      if ( -1 === $current_limit_int ) {
5532          return false;
5533      }
5534  
5535      $wp_max_limit     = WP_MAX_MEMORY_LIMIT;
5536      $wp_max_limit_int = wp_convert_hr_to_bytes( $wp_max_limit );
5537      $filtered_limit   = $wp_max_limit;
5538  
5539      switch ( $context ) {
5540          case 'admin':
5541              /**
5542               * Filters the maximum memory limit available for administration screens.
5543               *
5544               * This only applies to administrators, who may require more memory for tasks
5545               * like updates. Memory limits when processing images (uploaded or edited by
5546               * users of any role) are handled separately.
5547               *
5548               * The `WP_MAX_MEMORY_LIMIT` constant specifically defines the maximum memory
5549               * limit available when in the administration back end. The default is 256M
5550               * (256 megabytes of memory) or the original `memory_limit` php.ini value if
5551               * this is higher.
5552               *
5553               * @since 3.0.0
5554               * @since 4.6.0 The default now takes the original `memory_limit` into account.
5555               *
5556               * @param int|string $filtered_limit The maximum WordPress memory limit. Accepts an integer
5557               *                                   (bytes), or a shorthand string notation, such as '256M'.
5558               */
5559              $filtered_limit = apply_filters( 'admin_memory_limit', $filtered_limit );
5560              break;
5561  
5562          case 'image':
5563              /**
5564               * Filters the memory limit allocated for image manipulation.
5565               *
5566               * @since 3.5.0
5567               * @since 4.6.0 The default now takes the original `memory_limit` into account.
5568               *
5569               * @param int|string $filtered_limit Maximum memory limit to allocate for images.
5570               *                                   Default `WP_MAX_MEMORY_LIMIT` or the original
5571               *                                   php.ini `memory_limit`, whichever is higher.
5572               *                                   Accepts an integer (bytes), or a shorthand string
5573               *                                   notation, such as '256M'.
5574               */
5575              $filtered_limit = apply_filters( 'image_memory_limit', $filtered_limit );
5576              break;
5577  
5578          default:
5579              /**
5580               * Filters the memory limit allocated for arbitrary contexts.
5581               *
5582               * The dynamic portion of the hook name, `$context`, refers to an arbitrary
5583               * context passed on calling the function. This allows for plugins to define
5584               * their own contexts for raising the memory limit.
5585               *
5586               * @since 4.6.0
5587               *
5588               * @param int|string $filtered_limit Maximum memory limit to allocate for images.
5589               *                                   Default '256M' or the original php.ini `memory_limit`,
5590               *                                   whichever is higher. Accepts an integer (bytes), or a
5591               *                                   shorthand string notation, such as '256M'.
5592               */
5593              $filtered_limit = apply_filters( "{$context}_memory_limit", $filtered_limit );
5594              break;
5595      }
5596  
5597      $filtered_limit_int = wp_convert_hr_to_bytes( $filtered_limit );
5598  
5599      if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
5600          if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
5601              return $filtered_limit;
5602          } else {
5603              return false;
5604          }
5605      } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
5606          if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
5607              return $wp_max_limit;
5608          } else {
5609              return false;
5610          }
5611      }
5612  
5613      return false;
5614  }
5615  
5616  /**
5617   * Generate a random UUID (version 4).
5618   *
5619   * @since 4.7.0
5620   *
5621   * @return string UUID.
5622   */
5623  function wp_generate_uuid4() {
5624      return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
5625          mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
5626          mt_rand( 0, 0xffff ),
5627          mt_rand( 0, 0x0fff ) | 0x4000,
5628          mt_rand( 0, 0x3fff ) | 0x8000,
5629          mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
5630      );
5631  }
5632  
5633  /**
5634   * Get last changed date for the specified cache group.
5635   *
5636   * @since 4.7.0
5637   *
5638   * @param string $group Where the cache contents are grouped.
5639   *
5640   * @return string $last_changed UNIX timestamp with microseconds representing when the group was last changed.
5641   */
5642  function wp_cache_get_last_changed( $group ) {
5643      $last_changed = wp_cache_get( 'last_changed', $group );
5644  
5645      if ( ! $last_changed ) {
5646          $last_changed = microtime();
5647          wp_cache_set( 'last_changed', $last_changed, $group );
5648      }
5649  
5650      return $last_changed;
5651  }