HEX
Server: Apache
System: Linux pdx1-shared-a1-38 6.6.104-grsec-jammy+ #3 SMP Tue Sep 16 00:28:11 UTC 2025 x86_64
User: mmickelson (3396398)
PHP: 8.1.31
Disabled: NONE
Upload Files
File: //usr/local/wp/vendor/dreamhost/wpcli-update-verify/src/CLI.php
<?php
/**
 * Provides CLI interfaces to safe upgrades.
 *
 * @package Update-Verify
 */

namespace UpdateVerify;

use WP_CLI;
use WP_CLI\Utils;

/**
 * Provides CLI interfaces to safe upgrades.
 */
class CLI {

	/**
	 * List of Valid HTTP Codes
	 *
	 * @return array valid HTTP codes
	 */
	public static function valid_http_codes() {
		$valid_http_codes = array(
			'200', // This is okay.
			'301', // Redirects are okay.
			'302', // Redirects are okay.
			'401', // This happens when there's an .htpassword.
			'503', // Many maintenance plugins throw this.
		);

		return $valid_http_codes;
	}

	/**
	 * Safely updates WordPress to a newer version.
	 *
	 * Performs a `wp core update` by checking site availability heuristics
	 * before and after to determine whether the update process proceeded
	 * without error. Aborts update process if errors are detected beforehand,
	 * and rolls back to the prior WP version if an error was detected afterward.
	 *
	 * ## OPTIONS
	 *
	 * [--path=<path>]
	 * : Specify the path in which to update WordPress. Defaults to current
	 * directory.
	 *
	 * [--version=<version>]
	 * : Update to a specific version, instead of to the latest version.
	 *
	 * @when before_wp_load
	 */
	public static function safe_update( $args, $assoc_args ) {

		if ( ! is_readable( ABSPATH . 'wp-includes/version.php' ) ) {
			WP_CLI::error(
				"This does not seem to be a WordPress install.\n" .
				'Pass --path=`path/to/wordpress` or run `wp core download`.'
			);
		}
		global $wp_version;
		include ABSPATH . 'wp-includes/version.php';
		$current_version = $wp_version;

		WP_CLI::log( 'Currently running version ' . $current_version );

		if ( ! empty( $assoc_args['version'] )
			&& version_compare( $assoc_args['version'], $current_version, '<=' ) ) {
			WP_CLI::success( 'WordPress is already at a newer version.' );
			return;
		}

		$is_site_response_errored = function( $site_response, $stage ) {
			if ( ! in_array( $http_code, self::valid_http_codes() ) ) {
				return sprintf( 'Failed %s-update status code check (HTTP code %d).', $stage, $site_response['status_code'] );
			} elseif ( ! empty( $site_response['php_fatal'] ) ) {
				return sprintf( 'Failed %s-update PHP fatal error check.', $stage );
			} elseif ( empty( $site_response['closing_body'] ) ) {
				return sprintf( 'Failed %s-update closing </body> tag check.', $stage );
			} else {
				return false;
			}
		};

		if ( version_compare( $current_version, '3.7', '<' ) ) {
			WP_CLI::log( 'Detected really old WordPress. First updating to version 3.7 ...' );
			self::load_wp_config();
			$home_url = self::get_home_url();
			if ( empty( $home_url ) ) {
				WP_CLI::error( 'No home URL found from database connection.' );
			}
			try {
				$site_response = Observer::check_site_response( $home_url );
			} catch ( \Requests_Exception $e ) {
				WP_CLI::error( 'Requests Exception - ' . $e->getMessage() );
			}
			$is_errored = $is_site_response_errored( $site_response, 'pre' );
			if ( $is_errored ) {
				WP_CLI::error( $is_errored );
			}
			WP_CLI::runcommand(
				'core download --skip-content --force --version=3.7',
				array(
					'launch' => true,
				)
			);
			try {
				$site_response = Observer::check_site_response( $home_url );
			} catch ( \Requests_Exception $e ) {
				WP_CLI::error( 'Requests Exception - ' . $e->getMessage() );
			}
			$is_errored = $is_site_response_errored( $site_response, 'post' );
			if ( $is_errored ) {
				WP_CLI::log( "Rolling WordPress back to version {$current_version}..." );
				WP_CLI::runcommand(
					'core download --skip-content --force --version=' . $current_version,
					array(
						'launch' => true,
					)
				);
				WP_CLI::error( $is_errored );
			}
			WP_CLI::log( 'Forced update to WordPress 3.7. Proceeding with remaining update...' );
		}

		// @codingStandardsIgnoreLine
		@WP_CLI::get_runner()->load_wordpress();

		/**
		 * Bail early if any errors are detected with the site.
		 */
		WP_CLI::add_wp_hook(
			'upgrade_verify_upgrader_pre_download',
			function( $retval, $site_response ) use ( $is_site_response_errored ) {
				$is_errored = $is_site_response_errored( $site_response, 'pre' );
				if ( $is_errored ) {
					if ( method_exists( 'WP_Upgrader', 'release_lock' ) ) {
						\WP_Upgrader::release_lock( 'core_updater' );
					}
					return new \WP_Error( 'upgrade_verify_fail', $is_errored );
				}
				return $retval;
			},
			10,
			2
		);

		/**
		 * Roll back to prior version if errors were detected post-update.
		 */
		WP_CLI::add_wp_hook(
			'upgrade_verify_upgrader_process_complete',
			function( $site_response ) use ( $current_version, $is_site_response_errored ) {
				$is_errored = $is_site_response_errored( $site_response, 'post' );
				if ( $is_errored ) {
					if ( method_exists( 'WP_Upgrader', 'release_lock' ) ) {
						\WP_Upgrader::release_lock( 'core_updater' );
					}
					WP_CLI::log( "Rolling WordPress back to version {$current_version}..." );
					WP_CLI::runcommand(
						'core download --skip-content --force --version=' . $current_version,
						array(
							'launch' => false,
						)
					);
					WP_CLI::error( $is_errored );
				}
			}
		);

		$update_version = ! empty( $assoc_args['version'] ) ? ' --version=' . $assoc_args['version'] : '';
		$response       = WP_CLI::runcommand(
			'core update' . $update_version,
			array(
				'launch' => false,
			)
		);

	}

	/**
	 * Load the wp-config.php file into scope.
	 */
	private static function load_wp_config() {
		$path = Utils\locate_wp_config();
		if ( ! $path ) {
			WP_CLI::error( "'wp-config.php' not found." );
		}

		// Load wp-config.php code, in the global scope.
		$wp_cli_original_defined_vars = get_defined_vars();
		// @codingStandardsIgnoreLine
		eval( WP_CLI::get_runner()->get_wp_config_code() );
		foreach ( get_defined_vars() as $key => $var ) {
			if ( array_key_exists( $key, $wp_cli_original_defined_vars ) || 'wp_cli_original_defined_vars' === $key ) {
				continue;
			}
			global ${$key};
			${$key} = $var;
		}
	}

	/**
	 * Get the home URL from the database.
	 */
	private static function get_home_url() {
		global $table_prefix;
		$assoc_args = array(
			'host'     => DB_HOST,
			'user'     => DB_USER,
			'pass'     => DB_PASSWORD,
			'database' => DB_NAME,
			'execute'  => "SELECT option_value FROM {$table_prefix}options WHERE option_name='home'",
		);

		if ( defined( 'DB_CHARSET' ) && constant( 'DB_CHARSET' ) ) {
			$assoc_args['default-character-set'] = constant( 'DB_CHARSET' );
		}
		$cmd         = '/usr/bin/env mysql --no-defaults --no-auto-rehash --skip-column-names';
		$descriptors = array(
			0 => STDIN,
			1 => array( 'pipe', 'w' ),
			2 => array( 'pipe', 'w' ),
		);
		if ( isset( $assoc_args['host'] ) ) {
			//@codingStandardsIgnoreStart
			$assoc_args = array_merge( $assoc_args, Utils\mysql_host_to_cli_args( $assoc_args['host'] ) );
			//@codingStandardsIgnoreEnd
		}

		$pass = $assoc_args['pass'];
		unset( $assoc_args['pass'] );

		$old_pass = getenv( 'MYSQL_PWD' );
		putenv( 'MYSQL_PWD=' . $pass );

		$final_cmd = Utils\force_env_on_nix_systems( $cmd ) . Utils\assoc_args_to_str( $assoc_args );

		$proc = proc_open( $final_cmd, $descriptors, $pipes );
		if ( ! $proc ) {
			WP_CLI::error( 'Failed to open MySQL process.' );
			exit( 1 );
		}

		$retval = stream_get_contents( $pipes[1] );
		fclose( $pipes[1] );

		$stderr = stream_get_contents( $pipes[2] );
		fclose( $pipes[2] );

		$r = proc_close( $proc );

		putenv( 'MYSQL_PWD=' . $old_pass );

		if ( $r ) {
			WP_CLI::error( 'Failed to execute MySQL query: ' . $stderr );
		}
		return $retval;
	}

}