wp/wp-admin/includes/class-wp-site-health-auto-updates.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
     8  */
     8  */
     9 
     9 
    10 class WP_Site_Health_Auto_Updates {
    10 class WP_Site_Health_Auto_Updates {
    11 	/**
    11 	/**
    12 	 * WP_Site_Health_Auto_Updates constructor.
    12 	 * WP_Site_Health_Auto_Updates constructor.
       
    13 	 *
    13 	 * @since 5.2.0
    14 	 * @since 5.2.0
    14 	 */
    15 	 */
    15 	public function __construct() {
    16 	public function __construct() {
    16 		include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
    17 		require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
    17 	}
    18 	}
    18 
    19 
    19 
    20 
    20 	/**
    21 	/**
    21 	 * Run tests to determine if auto-updates can run.
    22 	 * Run tests to determine if auto-updates can run.
    24 	 *
    25 	 *
    25 	 * @return array The test results.
    26 	 * @return array The test results.
    26 	 */
    27 	 */
    27 	public function run_tests() {
    28 	public function run_tests() {
    28 		$tests = array(
    29 		$tests = array(
    29 			$this->test_constants( 'DISALLOW_FILE_MODS', false ),
    30 			$this->test_constants( 'WP_AUTO_UPDATE_CORE', array( true, 'minor' ) ),
    30 			$this->test_constants( 'AUTOMATIC_UPDATER_DISABLED', false ),
       
    31 			$this->test_constants( 'WP_AUTO_UPDATE_CORE', true ),
       
    32 			$this->test_wp_version_check_attached(),
    31 			$this->test_wp_version_check_attached(),
    33 			$this->test_filters_automatic_updater_disabled(),
    32 			$this->test_filters_automatic_updater_disabled(),
       
    33 			$this->test_wp_automatic_updates_disabled(),
    34 			$this->test_if_failed_update(),
    34 			$this->test_if_failed_update(),
    35 			$this->test_vcs_abspath(),
    35 			$this->test_vcs_abspath(),
    36 			$this->test_check_wp_filesystem_method(),
    36 			$this->test_check_wp_filesystem_method(),
    37 			$this->test_all_files_writable(),
    37 			$this->test_all_files_writable(),
    38 			$this->test_accepts_dev_updates(),
    38 			$this->test_accepts_dev_updates(),
    58 
    58 
    59 	/**
    59 	/**
    60 	 * Test if auto-updates related constants are set correctly.
    60 	 * Test if auto-updates related constants are set correctly.
    61 	 *
    61 	 *
    62 	 * @since 5.2.0
    62 	 * @since 5.2.0
    63 	 *
    63 	 * @since 5.5.1 The `$value` parameter can accept an array.
    64 	 * @param string $constant The name of the constant to check.
    64 	 *
    65 	 * @param bool   $value    The value that the constant should be, if set.
    65 	 * @param string $constant         The name of the constant to check.
       
    66 	 * @param bool|string|array $value The value that the constant should be, if set,
       
    67 	 *                                 or an array of acceptable values.
    66 	 * @return array The test results.
    68 	 * @return array The test results.
    67 	 */
    69 	 */
    68 	public function test_constants( $constant, $value ) {
    70 	public function test_constants( $constant, $value ) {
    69 		if ( defined( $constant ) && constant( $constant ) != $value ) {
    71 		$acceptable_values = (array) $value;
       
    72 
       
    73 		if ( defined( $constant ) && ! in_array( constant( $constant ), $acceptable_values, true ) ) {
    70 			return array(
    74 			return array(
    71 				'description' => sprintf(
    75 				'description' => sprintf(
    72 					/* translators: %s: Name of the constant used. */
    76 					/* translators: %s: Name of the constant used. */
    73 					__( 'The %s constant is defined and enabled.' ),
    77 					__( 'The %s constant is defined and enabled.' ),
    74 					"<code>$constant</code>"
    78 					"<code>$constant</code>"
    93 		$cookies = wp_unslash( $_COOKIE );
    97 		$cookies = wp_unslash( $_COOKIE );
    94 		$timeout = 10;
    98 		$timeout = 10;
    95 		$headers = array(
    99 		$headers = array(
    96 			'Cache-Control' => 'no-cache',
   100 			'Cache-Control' => 'no-cache',
    97 		);
   101 		);
       
   102 		/** This filter is documented in wp-includes/class-wp-http-streams.php */
       
   103 		$sslverify = apply_filters( 'https_local_ssl_verify', false );
    98 
   104 
    99 		// Include Basic auth in loopback requests.
   105 		// Include Basic auth in loopback requests.
   100 		if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
   106 		if ( isset( $_SERVER['PHP_AUTH_USER'] ) && isset( $_SERVER['PHP_AUTH_PW'] ) ) {
   101 			$headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
   107 			$headers['Authorization'] = 'Basic ' . base64_encode( wp_unslash( $_SERVER['PHP_AUTH_USER'] ) . ':' . wp_unslash( $_SERVER['PHP_AUTH_PW'] ) );
   102 		}
   108 		}
   106 				'health-check-test-wp_version_check' => true,
   112 				'health-check-test-wp_version_check' => true,
   107 			),
   113 			),
   108 			admin_url( 'site-health.php' )
   114 			admin_url( 'site-health.php' )
   109 		);
   115 		);
   110 
   116 
   111 		$test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
   117 		$test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout', 'sslverify' ) );
   112 
   118 
   113 		if ( is_wp_error( $test ) ) {
   119 		if ( is_wp_error( $test ) ) {
   114 			return array(
   120 			return array(
   115 				'description' => sprintf(
   121 				'description' => sprintf(
   116 					/* translators: %s: Name of the filter used. */
   122 					/* translators: %s: Name of the filter used. */
   141 	 * @since 5.2.0
   147 	 * @since 5.2.0
   142 	 *
   148 	 *
   143 	 * @return array The test results.
   149 	 * @return array The test results.
   144 	 */
   150 	 */
   145 	public function test_filters_automatic_updater_disabled() {
   151 	public function test_filters_automatic_updater_disabled() {
       
   152 		/** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
   146 		if ( apply_filters( 'automatic_updater_disabled', false ) ) {
   153 		if ( apply_filters( 'automatic_updater_disabled', false ) ) {
   147 			return array(
   154 			return array(
   148 				'description' => sprintf(
   155 				'description' => sprintf(
   149 					/* translators: %s: Name of the filter used. */
   156 					/* translators: %s: Name of the filter used. */
   150 					__( 'The %s filter is enabled.' ),
   157 					__( 'The %s filter is enabled.' ),
   154 			);
   161 			);
   155 		}
   162 		}
   156 	}
   163 	}
   157 
   164 
   158 	/**
   165 	/**
       
   166 	 * Check if automatic updates are disabled.
       
   167 	 *
       
   168 	 * @since 5.3.0
       
   169 	 *
       
   170 	 * @return array|bool The test results. False if auto-updates are enabled.
       
   171 	 */
       
   172 	public function test_wp_automatic_updates_disabled() {
       
   173 		if ( ! class_exists( 'WP_Automatic_Updater' ) ) {
       
   174 			require_once ABSPATH . 'wp-admin/includes/class-wp-automatic-updater.php';
       
   175 		}
       
   176 
       
   177 		$auto_updates = new WP_Automatic_Updater();
       
   178 
       
   179 		if ( ! $auto_updates->is_disabled() ) {
       
   180 			return false;
       
   181 		}
       
   182 
       
   183 		return array(
       
   184 			'description' => __( 'All automatic updates are disabled.' ),
       
   185 			'severity'    => 'fail',
       
   186 		);
       
   187 	}
       
   188 
       
   189 	/**
   159 	 * Check if automatic updates have tried to run, but failed, previously.
   190 	 * Check if automatic updates have tried to run, but failed, previously.
   160 	 *
   191 	 *
   161 	 * @since 5.2.0
   192 	 * @since 5.2.0
   162 	 *
   193 	 *
   163 	 * @return array|bool The test results. false if the auto updates failed.
   194 	 * @return array|bool The test results. False if the auto-updates failed.
   164 	 */
   195 	 */
   165 	function test_if_failed_update() {
   196 	function test_if_failed_update() {
   166 		$failed = get_site_option( 'auto_core_update_failed' );
   197 		$failed = get_site_option( 'auto_core_update_failed' );
   167 
   198 
   168 		if ( ! $failed ) {
   199 		if ( ! $failed ) {
   217 			// Walk up from $context_dir to the root.
   248 			// Walk up from $context_dir to the root.
   218 			do {
   249 			do {
   219 				$check_dirs[] = $context_dir;
   250 				$check_dirs[] = $context_dir;
   220 
   251 
   221 				// Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
   252 				// Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
   222 				if ( dirname( $context_dir ) == $context_dir ) {
   253 				if ( dirname( $context_dir ) === $context_dir ) {
   223 					break;
   254 					break;
   224 				}
   255 				}
   225 
   256 
   226 				// Continue one level at a time.
   257 				// Continue one level at a time.
   227 			} while ( $context_dir = dirname( $context_dir ) );
   258 			} while ( $context_dir = dirname( $context_dir ) );
   237 					break 2;
   268 					break 2;
   238 				}
   269 				}
   239 			}
   270 			}
   240 		}
   271 		}
   241 
   272 
       
   273 		/** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
   242 		if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, ABSPATH ) ) {
   274 		if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, ABSPATH ) ) {
   243 			return array(
   275 			return array(
   244 				'description' => sprintf(
   276 				'description' => sprintf(
   245 					// translators: 1: Folder name. 2: Version control directory. 3: Filter name.
   277 					/* translators: 1: Folder name. 2: Version control directory. 3: Filter name. */
   246 					__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.' ),
   278 					__( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.' ),
   247 					'<code>' . $check_dir . '</code>',
   279 					'<code>' . $check_dir . '</code>',
   248 					"<code>$vcs_dir</code>",
   280 					"<code>$vcs_dir</code>",
   249 					'<code>automatic_updates_is_vcs_checkout</code>'
   281 					'<code>automatic_updates_is_vcs_checkout</code>'
   250 				),
   282 				),
   253 		}
   285 		}
   254 
   286 
   255 		if ( $checkout ) {
   287 		if ( $checkout ) {
   256 			return array(
   288 			return array(
   257 				'description' => sprintf(
   289 				'description' => sprintf(
   258 					// translators: 1: Folder name. 2: Version control directory.
   290 					/* translators: 1: Folder name. 2: Version control directory. */
   259 					__( 'The folder %1$s was detected as being under version control (%2$s).' ),
   291 					__( 'The folder %1$s was detected as being under version control (%2$s).' ),
   260 					'<code>' . $check_dir . '</code>',
   292 					'<code>' . $check_dir . '</code>',
   261 					"<code>$vcs_dir</code>"
   293 					"<code>$vcs_dir</code>"
   262 				),
   294 				),
   263 				'severity'    => 'fail',
   295 				'severity'    => 'warning',
   264 			);
   296 			);
   265 		}
   297 		}
   266 
   298 
   267 		return array(
   299 		return array(
   268 			'description' => __( 'No version control systems were detected.' ),
   300 			'description' => __( 'No version control systems were detected.' ),
   302 	 *
   334 	 *
   303 	 * @since 5.2.0
   335 	 * @since 5.2.0
   304 	 *
   336 	 *
   305 	 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
   337 	 * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
   306 	 *
   338 	 *
   307 	 * @return array|bool The test results. false if they're not writeable.
   339 	 * @return array|bool The test results. False if they're not writeable.
   308 	 */
   340 	 */
   309 	function test_all_files_writable() {
   341 	function test_all_files_writable() {
   310 		global $wp_filesystem;
   342 		global $wp_filesystem;
   311 
   343 
   312 		include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
   344 		require ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
   313 
   345 
   314 		$skin    = new Automatic_Upgrader_Skin;
   346 		$skin    = new Automatic_Upgrader_Skin;
   315 		$success = $skin->request_filesystem_credentials( false, ABSPATH );
   347 		$success = $skin->request_filesystem_credentials( false, ABSPATH );
   316 
   348 
   317 		if ( ! $success ) {
   349 		if ( ! $success ) {
   318 			return false;
   350 			return false;
   319 		}
   351 		}
   320 
   352 
   321 		WP_Filesystem();
   353 		WP_Filesystem();
   322 
   354 
   323 		if ( 'direct' != $wp_filesystem->method ) {
   355 		if ( 'direct' !== $wp_filesystem->method ) {
   324 			return false;
   356 			return false;
   325 		}
   357 		}
   326 
   358 
   327 		$checksums = get_core_checksums( $wp_version, 'en_US' );
   359 		$checksums = get_core_checksums( $wp_version, 'en_US' );
   328 		$dev       = ( false !== strpos( $wp_version, '-' ) );
   360 		$dev       = ( false !== strpos( $wp_version, '-' ) );
   329 		// Get the last stable version's files and test against that
   361 		// Get the last stable version's files and test against that.
   330 		if ( ! $checksums && $dev ) {
   362 		if ( ! $checksums && $dev ) {
   331 			$checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
   363 			$checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
   332 		}
   364 		}
   333 
   365 
   334 		// There aren't always checksums for development releases, so just skip the test if we still can't find any
   366 		// There aren't always checksums for development releases, so just skip the test if we still can't find any.
   335 		if ( ! $checksums && $dev ) {
   367 		if ( ! $checksums && $dev ) {
   336 			return false;
   368 			return false;
   337 		}
   369 		}
   338 
   370 
   339 		if ( ! $checksums ) {
   371 		if ( ! $checksums ) {
   340 			$description = sprintf(
   372 			$description = sprintf(
   341 				// translators: %s: WordPress version
   373 				/* translators: %s: WordPress version. */
   342 				__( "Couldn't retrieve a list of the checksums for WordPress %s." ),
   374 				__( "Couldn't retrieve a list of the checksums for WordPress %s." ),
   343 				$wp_version
   375 				$wp_version
   344 			);
   376 			);
   345 			$description .= ' ' . __( 'This could mean that connections are failing to WordPress.org.' );
   377 			$description .= ' ' . __( 'This could mean that connections are failing to WordPress.org.' );
   346 			return array(
   378 			return array(
   349 			);
   381 			);
   350 		}
   382 		}
   351 
   383 
   352 		$unwritable_files = array();
   384 		$unwritable_files = array();
   353 		foreach ( array_keys( $checksums ) as $file ) {
   385 		foreach ( array_keys( $checksums ) as $file ) {
   354 			if ( 'wp-content' == substr( $file, 0, 10 ) ) {
   386 			if ( 'wp-content' === substr( $file, 0, 10 ) ) {
   355 				continue;
   387 				continue;
   356 			}
   388 			}
   357 			if ( ! file_exists( ABSPATH . $file ) ) {
   389 			if ( ! file_exists( ABSPATH . $file ) ) {
   358 				continue;
   390 				continue;
   359 			}
   391 			}
   382 	/**
   414 	/**
   383 	 * Check if the install is using a development branch and can use nightly packages.
   415 	 * Check if the install is using a development branch and can use nightly packages.
   384 	 *
   416 	 *
   385 	 * @since 5.2.0
   417 	 * @since 5.2.0
   386 	 *
   418 	 *
   387 	 * @return array|bool The test results. false if it isn't a development version.
   419 	 * @return array|bool The test results. False if it isn't a development version.
   388 	 */
   420 	 */
   389 	function test_accepts_dev_updates() {
   421 	function test_accepts_dev_updates() {
   390 		include ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
   422 		require ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
   391 		// Only for dev versions
   423 		// Only for dev versions.
   392 		if ( false === strpos( $wp_version, '-' ) ) {
   424 		if ( false === strpos( $wp_version, '-' ) ) {
   393 			return false;
   425 			return false;
   394 		}
   426 		}
   395 
   427 
   396 		if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
   428 		if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
   402 				),
   434 				),
   403 				'severity'    => 'fail',
   435 				'severity'    => 'fail',
   404 			);
   436 			);
   405 		}
   437 		}
   406 
   438 
       
   439 		/** This filter is documented in wp-admin/includes/class-core-upgrader.php */
   407 		if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
   440 		if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
   408 			return array(
   441 			return array(
   409 				'description' => sprintf(
   442 				'description' => sprintf(
   410 					/* translators: %s: Name of the filter used. */
   443 					/* translators: %s: Name of the filter used. */
   411 					__( 'WordPress development updates are blocked by the %s filter.' ),
   444 					__( 'WordPress development updates are blocked by the %s filter.' ),
   433 				),
   466 				),
   434 				'severity'    => 'fail',
   467 				'severity'    => 'fail',
   435 			);
   468 			);
   436 		}
   469 		}
   437 
   470 
       
   471 		/** This filter is documented in wp-admin/includes/class-core-upgrader.php */
   438 		if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
   472 		if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
   439 			return array(
   473 			return array(
   440 				'description' => sprintf(
   474 				'description' => sprintf(
   441 					/* translators: %s: Name of the filter used. */
   475 					/* translators: %s: Name of the filter used. */
   442 					__( 'WordPress security and maintenance releases are blocked by the %s filter.' ),
   476 					__( 'WordPress security and maintenance releases are blocked by the %s filter.' ),