Parsed: 111480

function update_core( $from, $to ) {
  global $wp_filesystem, $_old_files, $_new_bundled_files, $wpdb;

  set_time_limit( 300 );

  
/**
 * Filters feedback messages displayed during the core update process.
 *
 * The filter is first evaluated after the zip file for the latest version
 * has been downloaded and unzipped. It is evaluated five more times during
 * the process:
 *
 * 1. Before WordPress begins the core upgrade process.
 * 2. Before Maintenance Mode is enabled.
 * 3. Before WordPress begins copying over the necessary files.
 * 4. Before Maintenance Mode is disabled.
 * 5. Before the database is upgraded.
 *
 * @since 2.5.0
 *
 * @param string $feedback The core update feedback messages.
 */
  apply_filters( 'update_feedback', __( 'Verifying the unpacked files…' ) );

  // Sanity check the unzipped distribution.
  $distro = '';
  $roots  = array( '/wordpress/', '/wordpress-mu/' );

  foreach ( $roots as $root ) {
    if ( $wp_filesystem->WP_Filesystem_ftpsockets::exists( $from . $root . 'readme.html' )
      && $wp_filesystem->WP_Filesystem_ftpsockets::exists( $from . $root . 'wp-includes/version.php' )
    ) {
      $distro = $root;
      break;
    }
  }

  if ( ! $distro ) {
    $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );

    return new WP_Error( 'insane_distro', __( 'The update could not be unpacked' ) );
  }

  /*
	 * Import $wp_version, $required_php_version, and $required_mysql_version from the new version.
	 * DO NOT globalize any variables imported from `version-current.php` in this function.
	 *
	 * BC Note: $wp_filesystem->wp_content_dir() returned unslashed pre-2.8.
	 */
  $versions_file = trailingslashit( $wp_filesystem->wp_content_dir() ) . 'upgrade/version-current.php';

  if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::copy( $from . $distro . 'wp-includes/version.php', $versions_file ) ) {
    $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );

    return new WP_Error(
      'copy_failed_for_version_file',
      __( 'The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions.' ),
      'wp-includes/version.php'
    );
  }

  $wp_filesystem->WP_Filesystem_ftpsockets::chmod( $versions_file, FS_CHMOD_FILE );

  /*
	 * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later,
	 * so don't run it when upgrading from older versions.
	 */
  if ( function_exists( 'wp_opcache_invalidate' ) ) {
    wp_opcache_invalidate( $versions_file );
  }

  require WP_CONTENT_DIR . '/upgrade/version-current.php';
  $wp_filesystem->WP_Filesystem_ftpsockets::delete( $versions_file );

  $php_version       = PHP_VERSION;
  $mysql_version     = $wpdb->db_version();
  $old_wp_version    = $GLOBALS['wp_version']; // The version of WordPress we're updating from.
  $development_build = ( false !== strpos( $old_wp_version . $wp_version, '-' ) ); // A dash in the version indicates a development release.
  $php_compat        = version_compare( $php_version, $required_php_version, '>=' );

  if ( file_exists( WP_CONTENT_DIR . '/db.php' ) && empty( $wpdb->is_mysql ) ) {
    $mysql_compat = true;
  } else {
    $mysql_compat = version_compare( $mysql_version, $required_mysql_version, '>=' );
  }

  if ( ! $mysql_compat || ! $php_compat ) {
    $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );
  }

  $php_update_message = '';

  if ( function_exists( 'wp_get_update_php_url' ) ) {
    $php_update_message = '</p><p>' . sprintf(
      /* translators: %s: URL to Update PHP page. */
      __( '<a href="%s">Learn more about updating PHP</a>.' ),
      esc_url( wp_get_update_php_url() )
    );

    if ( function_exists( 'wp_get_update_php_annotation' ) ) {
      $annotation = wp_get_update_php_annotation();

      if ( $annotation ) {
        $php_update_message .= '</p><p><em>' . $annotation . '</em>';
      }
    }
  }

  if ( ! $mysql_compat && ! $php_compat ) {
    return new WP_Error(
      'php_mysql_not_compatible',
      sprintf(
        /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Minimum required MySQL version number, 4: Current PHP version number, 5: Current MySQL version number. */
        __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher and MySQL version %3$s or higher. You are running PHP version %4$s and MySQL version %5$s.' ),
        $wp_version,
        $required_php_version,
        $required_mysql_version,
        $php_version,
        $mysql_version
      ) . $php_update_message
    );
  } elseif ( ! $php_compat ) {
    return new WP_Error(
      'php_not_compatible',
      sprintf(
        /* translators: 1: WordPress version number, 2: Minimum required PHP version number, 3: Current PHP version number. */
        __( 'The update cannot be installed because WordPress %1$s requires PHP version %2$s or higher. You are running version %3$s.' ),
        $wp_version,
        $required_php_version,
        $php_version
      ) . $php_update_message
    );
  } elseif ( ! $mysql_compat ) {
    return new WP_Error(
      'mysql_not_compatible',
      sprintf(
        /* translators: 1: WordPress version number, 2: Minimum required MySQL version number, 3: Current MySQL version number. */
        __( 'The update cannot be installed because WordPress %1$s requires MySQL version %2$s or higher. You are running version %3$s.' ),
        $wp_version,
        $required_mysql_version,
        $mysql_version
      )
    );
  }

  // Add a warning when the JSON PHP extension is missing.
  if ( ! extension_loaded( 'json' ) ) {
    return new WP_Error(
      'php_not_compatible_json',
      sprintf(
        /* translators: 1: WordPress version number, 2: The PHP extension name needed. */
        __( 'The update cannot be installed because WordPress %1$s requires the %2$s PHP extension.' ),
        $wp_version,
        'JSON'
      )
    );
  }

  
/** This filter is documented in wp-admin/includes/update-core.php */
  apply_filters( 'update_feedback', __( 'Preparing to install the latest version&#8230;' ) );

  // Don't copy wp-content, we'll deal with that below.
  // We also copy version.php last so failed updates report their old version.
  $skip              = array( 'wp-content', 'wp-includes/version.php' );
  $check_is_writable = array();

  // Check to see which files don't really need updating - only available for 3.7 and higher.
  if ( function_exists( 'get_core_checksums' ) ) {
    // Find the local version of the working directory.
    $working_dir_local = WP_CONTENT_DIR . '/upgrade/' . basename( $from ) . $distro;

    $checksums = get_core_checksums( $wp_version, isset( $wp_local_package ) ? $wp_local_package : 'en_US' );

    if ( is_array( $checksums ) && isset( $checksums[ $wp_version ] ) ) {
      $checksums = $checksums[ $wp_version ]; // Compat code for 3.7-beta2.
    }

    if ( is_array( $checksums ) ) {
      foreach ( $checksums as $file => $checksum ) {
        if ( 'wp-content' === substr( $file, 0, 10 ) ) {
          continue;
        }

        if ( ! file_exists( ABSPATH . $file ) ) {
          continue;
        }

        if ( ! file_exists( $working_dir_local . $file ) ) {
          continue;
        }

        if ( '.' === dirname( $file )
          && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true )
        ) {
          continue;
        }

        if ( md5_file( ABSPATH . $file ) === $checksum ) {
          $skip[] = $file;
        } else {
          $check_is_writable[ $file ] = ABSPATH . $file;
        }
      }
    }
  }

  // If we're using the direct method, we can predict write failures that are due to permissions.
  if ( $check_is_writable && 'direct' === $wp_filesystem->method ) {
    $files_writable = array_filter( $check_is_writable, array( $wp_filesystem, 'is_writable' ) );

    if ( $files_writable !== $check_is_writable ) {
      $files_not_writable = array_diff_key( $check_is_writable, $files_writable );

      foreach ( $files_not_writable as $relative_file_not_writable => $file_not_writable ) {
        // If the writable check failed, chmod file to 0644 and try again, same as copy_dir().
        $wp_filesystem->WP_Filesystem_ftpsockets::chmod( $file_not_writable, FS_CHMOD_FILE );

        if ( $wp_filesystem->WP_Filesystem_ftpsockets::is_writable( $file_not_writable ) ) {
          unset( $files_not_writable[ $relative_file_not_writable ] );
        }
      }

      // Store package-relative paths (the key) of non-writable files in the WP_Error object.
      $error_data = version_compare( $old_wp_version, '3.7-beta2', '>' ) ? array_keys( $files_not_writable ) : '';

      if ( $files_not_writable ) {
        return new WP_Error(
          'files_not_writable',
          __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ),
          implode( ', ', $error_data )
        );
      }
    }
  }

  
/** This filter is documented in wp-admin/includes/update-core.php */
  apply_filters( 'update_feedback', __( 'Enabling Maintenance mode&#8230;' ) );

  // Create maintenance file to signal that we are upgrading.
  $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
  $maintenance_file   = $to . '.maintenance';
  $wp_filesystem->WP_Filesystem_ftpsockets::delete( $maintenance_file );
  $wp_filesystem->WP_Filesystem_ftpsockets::put_contents( $maintenance_file, $maintenance_string, FS_CHMOD_FILE );

  
/** This filter is documented in wp-admin/includes/update-core.php */
  apply_filters( 'update_feedback', __( 'Copying the required files&#8230;' ) );

  // Copy new versions of WP files into place.
  $result = copy_dir( $from . $distro, $to, $skip );

  if ( is_wp_error( $result ) ) {
    $result = new WP_Error(
      $result->get_error_code(),
      $result->get_error_message(),
      substr( $result->get_error_data(), strlen( $to ) )
    );
  }

  // Since we know the core files have copied over, we can now copy the version file.
  if ( ! is_wp_error( $result ) ) {
    if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::copy( $from . $distro . 'wp-includes/version.php', $to . 'wp-includes/version.php', true /* overwrite */ ) ) {
      $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );
      $result = new WP_Error(
        'copy_failed_for_version_file',
        __( 'The update cannot be installed because your site is unable to copy some files. This is usually due to inconsistent file permissions.' ),
        'wp-includes/version.php'
      );
    }

    $wp_filesystem->WP_Filesystem_ftpsockets::chmod( $to . 'wp-includes/version.php', FS_CHMOD_FILE );

    /*
		 * `wp_opcache_invalidate()` only exists in WordPress 5.5 or later,
		 * so don't run it when upgrading from older versions.
		 */
    if ( function_exists( 'wp_opcache_invalidate' ) ) {
      wp_opcache_invalidate( $to . 'wp-includes/version.php' );
    }
  }

  // Check to make sure everything copied correctly, ignoring the contents of wp-content.
  $skip   = array( 'wp-content' );
  $failed = array();

  if ( isset( $checksums ) && is_array( $checksums ) ) {
    foreach ( $checksums as $file => $checksum ) {
      if ( 'wp-content' === substr( $file, 0, 10 ) ) {
        continue;
      }

      if ( ! file_exists( $working_dir_local . $file ) ) {
        continue;
      }

      if ( '.' === dirname( $file )
        && in_array( pathinfo( $file, PATHINFO_EXTENSION ), array( 'html', 'txt' ), true )
      ) {
        $skip[] = $file;
        continue;
      }

      if ( file_exists( ABSPATH . $file ) && md5_file( ABSPATH . $file ) === $checksum ) {
        $skip[] = $file;
      } else {
        $failed[] = $file;
      }
    }
  }

  // Some files didn't copy properly.
  if ( ! empty( $failed ) ) {
    $total_size = 0;

    foreach ( $failed as $file ) {
      if ( file_exists( $working_dir_local . $file ) ) {
        $total_size += filesize( $working_dir_local . $file );
      }
    }

    // If we don't have enough free space, it isn't worth trying again.
    // Unlikely to be hit due to the check in unzip_file().
    $available_space = function_exists( 'disk_free_space' ) ? @disk_free_space( ABSPATH ) : false;

    if ( $available_space && $total_size >= $available_space ) {
      $result = new WP_Error( 'disk_full', __( 'There is not enough free disk space to complete the update.' ) );
    } else {
      $result = copy_dir( $from . $distro, $to, $skip );

      if ( is_wp_error( $result ) ) {
        $result = new WP_Error(
          $result->get_error_code() . '_retry',
          $result->get_error_message(),
          substr( $result->get_error_data(), strlen( $to ) )
        );
      }
    }
  }

  // Custom content directory needs updating now.
  // Copy languages.
  if ( ! is_wp_error( $result ) && $wp_filesystem->WP_Filesystem_ftpsockets::is_dir( $from . $distro . 'wp-content/languages' ) ) {
    if ( WP_LANG_DIR !== ABSPATH . WPINC . '/languages' || @WP_Filesystem_ftpsockets::is_dir( WP_LANG_DIR ) ) {
      $lang_dir = WP_LANG_DIR;
    } else {
      $lang_dir = WP_CONTENT_DIR . '/languages';
    }

    // Check if the language directory exists first.
    if ( ! @is_dir( $lang_dir ) && 0 === strpos( $lang_dir, ABSPATH ) ) {
      // If it's within the ABSPATH we can handle it here, otherwise they're out of luck.
      $wp_filesystem->WP_Filesystem_ftpsockets::mkdir( $to . str_replace( ABSPATH, '', $lang_dir ), FS_CHMOD_DIR );
      clearstatcache(); // For FTP, need to clear the stat cache.
    }

    if ( @is_dir( $lang_dir ) ) {
      $wp_lang_dir = $wp_filesystem->find_folder( $lang_dir );

      if ( $wp_lang_dir ) {
        $result = copy_dir( $from . $distro . 'wp-content/languages/', $wp_lang_dir );

        if ( is_wp_error( $result ) ) {
          $result = new WP_Error(
            $result->get_error_code() . '_languages',
            $result->get_error_message(),
            substr( $result->get_error_data(), strlen( $wp_lang_dir ) )
          );
        }
      }
    }
  }

  
/** This filter is documented in wp-admin/includes/update-core.php */
  apply_filters( 'update_feedback', __( 'Disabling Maintenance mode&#8230;' ) );

  // Remove maintenance file, we're done with potential site-breaking changes.
  $wp_filesystem->WP_Filesystem_ftpsockets::delete( $maintenance_file );

  // 3.5 -> 3.5+ - an empty twentytwelve directory was created upon upgrade to 3.5 for some users,
  // preventing installation of Twenty Twelve.
  if ( '3.5' === $old_wp_version ) {
    if ( is_dir( WP_CONTENT_DIR . '/themes/twentytwelve' )
      && ! file_exists( WP_CONTENT_DIR . '/themes/twentytwelve/style.css' )
    ) {
      $wp_filesystem->WP_Filesystem_ftpsockets::delete( $wp_filesystem->wp_themes_dir() . 'twentytwelve/' );
    }
  }

  /*
	 * Copy new bundled plugins & themes.
	 * This gives us the ability to install new plugins & themes bundled with
	 * future versions of WordPress whilst avoiding the re-install upon upgrade issue.
	 * $development_build controls us overwriting bundled themes and plugins when a non-stable release is being updated.
	 */
  if ( ! is_wp_error( $result )
    && ( ! defined( 'CORE_UPGRADE_SKIP_NEW_BUNDLED' ) || ! CORE_UPGRADE_SKIP_NEW_BUNDLED )
  ) {
    foreach ( (array) $_new_bundled_files as $file => $introduced_version ) {
      // If a $development_build or if $introduced version is greater than what the site was previously running.
      if ( $development_build || version_compare( $introduced_version, $old_wp_version, '>' ) ) {
        $directory = ( '/' === $file[ strlen( $file ) - 1 ] );

        list( $type, $filename ) = explode( '/', $file, 2 );

        // Check to see if the bundled items exist before attempting to copy them.
        if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::exists( $from . $distro . 'wp-content/' . $file ) ) {
          continue;
        }

        if ( 'plugins' === $type ) {
          $dest = $wp_filesystem->wp_plugins_dir();
        } elseif ( 'themes' === $type ) {
          // Back-compat, ::wp_themes_dir() did not return trailingslash'd pre-3.2.
          $dest = trailingslashit( $wp_filesystem->wp_themes_dir() );
        } else {
          continue;
        }

        if ( ! $directory ) {
          if ( ! $development_build && $wp_filesystem->WP_Filesystem_ftpsockets::exists( $dest . $filename ) ) {
            continue;
          }

          if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::copy( $from . $distro . 'wp-content/' . $file, $dest . $filename, FS_CHMOD_FILE ) ) {
            $result = new WP_Error( "copy_failed_for_new_bundled_$type", __( 'Could not copy file.' ), $dest . $filename );
          }
        } else {
          if ( ! $development_build && $wp_filesystem->WP_Filesystem_ftpsockets::is_dir( $dest . $filename ) ) {
            continue;
          }

          $wp_filesystem->WP_Filesystem_ftpsockets::mkdir( $dest . $filename, FS_CHMOD_DIR );
          $_result = copy_dir( $from . $distro . 'wp-content/' . $file, $dest . $filename );

          // If a error occurs partway through this final step, keep the error flowing through, but keep process going.
          if ( is_wp_error( $_result ) ) {
            if ( ! is_wp_error( $result ) ) {
              $result = new WP_Error;
            }

            $result->add(
              $_result->get_error_code() . "_$type",
              $_result->get_error_message(),
              substr( $_result->get_error_data(), strlen( $dest ) )
            );
          }
        }
      }
    } // End foreach.
  }

  // Handle $result error from the above blocks.
  if ( is_wp_error( $result ) ) {
    $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );

    return $result;
  }

  // Remove old files.
  foreach ( $_old_files as $old_file ) {
    $old_file = $to . $old_file;

    if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::exists( $old_file ) ) {
      continue;
    }

    // If the file isn't deleted, try writing an empty string to the file instead.
    if ( ! $wp_filesystem->WP_Filesystem_ftpsockets::delete( $old_file, true ) && $wp_filesystem->WP_Filesystem_ftpsockets::is_file( $old_file ) ) {
      $wp_filesystem->WP_Filesystem_ftpsockets::put_contents( $old_file, '' );
    }
  }

  // Remove any Genericons example.html's from the filesystem.
  _upgrade_422_remove_genericons();

  // Deactivate the REST API plugin if its version is 2.0 Beta 4 or lower.
  _upgrade_440_force_deactivate_incompatible_plugins();

  // Deactivate incompatible plugins.
  _upgrade_core_deactivate_incompatible_plugins();

  // Upgrade DB with separate request.
  
/** This filter is documented in wp-admin/includes/update-core.php */
  apply_filters( 'update_feedback', __( 'Upgrading database&#8230;' ) );

  $db_upgrade_url = admin_url( 'upgrade.php?step=upgrade_db' );
  wp_remote_post( $db_upgrade_url, array( 'timeout' => 60 ) );

  // Clear the cache to prevent an update_option() from saving a stale db_version to the cache.
  wp_cache_flush();
  // Not all cache back ends listen to 'flush'.
  wp_cache_delete( 'alloptions', 'options' );

  // Remove working directory.
  $wp_filesystem->WP_Filesystem_ftpsockets::delete( $from, true );

  // Force refresh of update information.
  if ( function_exists( 'delete_site_transient' ) ) {
    delete_site_transient( 'update_core' );
  } else {
    delete_option( 'update_core' );
  }

  
/**
 * Fires after WordPress core has been successfully updated.
 *
 * @since 3.3.0
 *
 * @param string $wp_version The current WordPress version.
 */
  do_action( '_core_updated_successfully', $wp_version );

  // Clear the option that blocks auto-updates after failures, now that we've been successful.
  if ( function_exists( 'delete_site_option' ) ) {
    delete_site_option( 'auto_core_update_failed' );
  }

  return $wp_version;
}