Skip to content
Draft
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 49 additions & 4 deletions src/Core_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@
add_filter( 'send_site_admin_email_change_email', '__return_false' );
}

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$this->require_upgrade_file( 'WordPress installation' );

$defaults = [
'title' => '',
Expand Down Expand Up @@ -715,7 +715,7 @@
private function multisite_convert_( $assoc_args ) {
global $wpdb;

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$this->require_upgrade_file( 'multisite conversion' );

$domain = self::get_clean_basedomain();
if ( 'localhost' === $domain && ! empty( $assoc_args['subdomains'] ) ) {
Expand Down Expand Up @@ -1211,7 +1211,7 @@
&& ( $update->version !== $wp_version
|| Utils\get_flag_value( $assoc_args, 'force' ) ) ) {

require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$this->require_upgrade_file( 'WordPress core update' );

if ( $update->version ) {
WP_CLI::log( "Updating to version {$update->version} ({$update->locale})..." );
Expand Down Expand Up @@ -1371,7 +1371,7 @@
}
WP_CLI::success( "WordPress database upgraded on {$success}/{$total} sites." );
} else {
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
$this->require_upgrade_file( 'WordPress database update' );

/**
* @var string $wp_current_db_version
Expand Down Expand Up @@ -1663,4 +1663,49 @@
WP_CLI::error( 'ZipArchive failed to open ZIP file.' );
}
}

/**
* Safely requires the WordPress upgrade.php file with error handling.
*
* This method checks for file existence and readability before requiring,
* and registers a shutdown function to catch fatal errors during file loading
* (e.g., missing PHP extensions or other runtime issues).
*
* @param string $context Context for error messages (e.g., 'installation', 'upgrade', 'database update').
*/
private function require_upgrade_file( $context = 'WordPress operation' ) {
$upgrade_file = ABSPATH . 'wp-admin/includes/upgrade.php';

if ( ! file_exists( $upgrade_file ) ) {
WP_CLI::error( "WordPress installation is incomplete. The file '{$upgrade_file}' is missing." );
}

if ( ! is_readable( $upgrade_file ) ) {
WP_CLI::error( "Cannot read WordPress installation file '{$upgrade_file}'. Check file permissions." );
}

// Register a shutdown function to catch fatal errors during require_once.
$shutdown_handler = function () use ( $upgrade_file, $context ) {

Check failure on line 1688 in src/Core_Command.php

View workflow job for this annotation

GitHub Actions / code-quality / PHPStan

Anonymous function has an unused use $upgrade_file.
$error = error_get_last();
if ( null !== $error && in_array( $error['type'], [ E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR ], true ) ) {
// Check if error occurred in the upgrade file or files it includes.
if ( false !== strpos( $error['file'], 'wp-admin/includes/' ) || false !== strpos( $error['file'], 'wp-includes/' ) ) {
WP_CLI::error(
sprintf(
"Failed to load WordPress files for %s. This often indicates a missing PHP extension or a corrupted WordPress installation.\n\nError: %s in %s on line %d\n\nPlease check that all required PHP extensions are installed and that your WordPress installation is complete.",
$context,
$error['message'],
$error['file'],
$error['line']
)
);
}
}
};

register_shutdown_function( $shutdown_handler );

// phpcs:ignore WordPressVIPMinimum.Files.IncludingFile.UsingVariable -- Path comes from WordPress itself.
require_once $upgrade_file;
}
}
Loading