[ Index ]

PHP Cross Reference of WordPress

title

Body

[close]

/wp-admin/includes/ -> class-wp-site-health-auto-updates.php (source)

   1  <?php
   2  /**
   3   * Class for testing automatic updates in the WordPress code.
   4   *
   5   * @package WordPress
   6   * @subpackage Site_Health
   7   * @since 5.2.0
   8   */
   9  
  10  class WP_Site_Health_Auto_Updates {
  11      /**
  12       * WP_Site_Health_Auto_Updates constructor.
  13       * @since 5.2.0
  14       */
  15  	public function __construct() {
  16          include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
  17      }
  18  
  19  
  20      /**
  21       * Run tests to determine if auto-updates can run.
  22       *
  23       * @since 5.2.0
  24       *
  25       * @return array The test results.
  26       */
  27  	public function run_tests() {
  28          $tests = array(
  29              $this->test_constants( 'DISALLOW_FILE_MODS', false ),
  30              $this->test_constants( 'AUTOMATIC_UPDATER_DISABLED', false ),
  31              $this->test_constants( 'WP_AUTO_UPDATE_CORE', true ),
  32              $this->test_wp_version_check_attached(),
  33              $this->test_filters_automatic_updater_disabled(),
  34              $this->test_if_failed_update(),
  35              $this->test_vcs_abspath(),
  36              $this->test_check_wp_filesystem_method(),
  37              $this->test_all_files_writable(),
  38              $this->test_accepts_dev_updates(),
  39              $this->test_accepts_minor_updates(),
  40          );
  41  
  42          $tests = array_filter( $tests );
  43          $tests = array_map(
  44              function( $test ) {
  45                  $test = (object) $test;
  46  
  47                  if ( empty( $test->severity ) ) {
  48                      $test->severity = 'warning';
  49                  }
  50  
  51                  return $test;
  52              },
  53              $tests
  54          );
  55  
  56          return $tests;
  57      }
  58  
  59      /**
  60       * Test if auto-updates related constants are set correctly.
  61       *
  62       * @since 5.2.0
  63       *
  64       * @param string $constant The name of the constant to check.
  65       * @param bool   $value    The value that the constant should be, if set.
  66       * @return array The test results.
  67       */
  68  	public function test_constants( $constant, $value ) {
  69          if ( defined( $constant ) && constant( $constant ) != $value ) {
  70              return array(
  71                  'description' => sprintf(
  72                      /* translators: %s: Name of the constant used. */
  73                      __( 'The %s constant is defined and enabled.' ),
  74                      "<code>$constant</code>"
  75                  ),
  76                  'severity'    => 'fail',
  77              );
  78          }
  79      }
  80  
  81      /**
  82       * Check if updates are intercepted by a filter.
  83       *
  84       * @since 5.2.0
  85       *
  86       * @return array The test results.
  87       */
  88  	public function test_wp_version_check_attached() {
  89          if ( ! is_main_site() ) {
  90              return;
  91          }
  92  
  93          $cookies = wp_unslash( $_COOKIE );
  94          $timeout = 10;
  95          $headers = array(
  96              'Cache-Control' => 'no-cache',
  97          );
  98  
  99          // Include Basic auth in loopback requests.
 100          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'] ) );
 102          }
 103  
 104          $url = add_query_arg(
 105              array(
 106                  'health-check-test-wp_version_check' => true,
 107              ),
 108              admin_url( 'site-health.php' )
 109          );
 110  
 111          $test = wp_remote_get( $url, compact( 'cookies', 'headers', 'timeout' ) );
 112  
 113          if ( is_wp_error( $test ) ) {
 114              return array(
 115                  'description' => sprintf(
 116                      /* translators: %s: Name of the filter used. */
 117                      __( 'Could not confirm that the %s filter is available.' ),
 118                      '<code>wp_version_check()</code>'
 119                  ),
 120                  'severity'    => 'warning',
 121              );
 122          }
 123  
 124          $response = wp_remote_retrieve_body( $test );
 125  
 126          if ( 'yes' !== $response ) {
 127              return array(
 128                  'description' => sprintf(
 129                      /* translators: %s: Name of the filter used. */
 130                      __( 'A plugin has prevented updates by disabling %s.' ),
 131                      '<code>wp_version_check()</code>'
 132                  ),
 133                  'severity'    => 'fail',
 134              );
 135          }
 136      }
 137  
 138      /**
 139       * Check if automatic updates are disabled by a filter.
 140       *
 141       * @since 5.2.0
 142       *
 143       * @return array The test results.
 144       */
 145  	public function test_filters_automatic_updater_disabled() {
 146          /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
 147          if ( apply_filters( 'automatic_updater_disabled', false ) ) {
 148              return array(
 149                  'description' => sprintf(
 150                      /* translators: %s: Name of the filter used. */
 151                      __( 'The %s filter is enabled.' ),
 152                      '<code>automatic_updater_disabled</code>'
 153                  ),
 154                  'severity'    => 'fail',
 155              );
 156          }
 157      }
 158  
 159      /**
 160       * Check if automatic updates have tried to run, but failed, previously.
 161       *
 162       * @since 5.2.0
 163       *
 164       * @return array|bool The test results. false if the auto updates failed.
 165       */
 166  	function test_if_failed_update() {
 167          $failed = get_site_option( 'auto_core_update_failed' );
 168  
 169          if ( ! $failed ) {
 170              return false;
 171          }
 172  
 173          if ( ! empty( $failed['critical'] ) ) {
 174              $description  = __( 'A previous automatic background update ended with a critical failure, so updates are now disabled.' );
 175              $description .= ' ' . __( 'You would have received an email because of this.' );
 176              $description .= ' ' . __( "When you've been able to update using the \"Update Now\" button on Dashboard > Updates, we'll clear this error for future update attempts." );
 177              $description .= ' ' . sprintf(
 178                  /* translators: %s: Code of error shown. */
 179                  __( 'The error code was %s.' ),
 180                  '<code>' . $failed['error_code'] . '</code>'
 181              );
 182              return array(
 183                  'description' => $description,
 184                  'severity'    => 'warning',
 185              );
 186          }
 187  
 188          $description = __( 'A previous automatic background update could not occur.' );
 189          if ( empty( $failed['retry'] ) ) {
 190              $description .= ' ' . __( 'You would have received an email because of this.' );
 191          }
 192  
 193          $description .= ' ' . __( "We'll try again with the next release." );
 194          $description .= ' ' . sprintf(
 195              /* translators: %s: Code of error shown. */
 196              __( 'The error code was %s.' ),
 197              '<code>' . $failed['error_code'] . '</code>'
 198          );
 199          return array(
 200              'description' => $description,
 201              'severity'    => 'warning',
 202          );
 203      }
 204  
 205      /**
 206       * Check if WordPress is controlled by a VCS (Git, Subversion etc).
 207       *
 208       * @since 5.2.0
 209       *
 210       * @return array The test results.
 211       */
 212  	public function test_vcs_abspath() {
 213          $context_dirs = array( ABSPATH );
 214          $vcs_dirs     = array( '.svn', '.git', '.hg', '.bzr' );
 215          $check_dirs   = array();
 216  
 217          foreach ( $context_dirs as $context_dir ) {
 218              // Walk up from $context_dir to the root.
 219              do {
 220                  $check_dirs[] = $context_dir;
 221  
 222                  // Once we've hit '/' or 'C:\', we need to stop. dirname will keep returning the input here.
 223                  if ( dirname( $context_dir ) == $context_dir ) {
 224                      break;
 225                  }
 226  
 227                  // Continue one level at a time.
 228              } while ( $context_dir = dirname( $context_dir ) );
 229          }
 230  
 231          $check_dirs = array_unique( $check_dirs );
 232  
 233          // Search all directories we've found for evidence of version control.
 234          foreach ( $vcs_dirs as $vcs_dir ) {
 235              foreach ( $check_dirs as $check_dir ) {
 236                  // phpcs:ignore
 237                  if ( $checkout = @is_dir( rtrim( $check_dir, '\\/' ) . "/$vcs_dir" ) ) {
 238                      break 2;
 239                  }
 240              }
 241          }
 242  
 243          /** This filter is documented in wp-admin/includes/class-wp-automatic-updater.php */
 244          if ( $checkout && ! apply_filters( 'automatic_updates_is_vcs_checkout', true, ABSPATH ) ) {
 245              return array(
 246                  'description' => sprintf(
 247                      // translators: 1: Folder name. 2: Version control directory. 3: Filter name.
 248                      __( 'The folder %1$s was detected as being under version control (%2$s), but the %3$s filter is allowing updates.' ),
 249                      '<code>' . $check_dir . '</code>',
 250                      "<code>$vcs_dir</code>",
 251                      '<code>automatic_updates_is_vcs_checkout</code>'
 252                  ),
 253                  'severity'    => 'info',
 254              );
 255          }
 256  
 257          if ( $checkout ) {
 258              return array(
 259                  'description' => sprintf(
 260                      // translators: 1: Folder name. 2: Version control directory.
 261                      __( 'The folder %1$s was detected as being under version control (%2$s).' ),
 262                      '<code>' . $check_dir . '</code>',
 263                      "<code>$vcs_dir</code>"
 264                  ),
 265                  'severity'    => 'fail',
 266              );
 267          }
 268  
 269          return array(
 270              'description' => __( 'No version control systems were detected.' ),
 271              'severity'    => 'pass',
 272          );
 273      }
 274  
 275      /**
 276       * Check if we can access files without providing credentials.
 277       *
 278       * @since 5.2.0
 279       *
 280       * @return array The test results.
 281       */
 282  	function test_check_wp_filesystem_method() {
 283          $skin    = new Automatic_Upgrader_Skin;
 284          $success = $skin->request_filesystem_credentials( false, ABSPATH );
 285  
 286          if ( ! $success ) {
 287              $description  = __( 'Your installation of WordPress prompts for FTP credentials to perform updates.' );
 288              $description .= ' ' . __( '(Your site is performing updates over FTP due to file ownership. Talk to your hosting company.)' );
 289  
 290              return array(
 291                  'description' => $description,
 292                  'severity'    => 'fail',
 293              );
 294          }
 295  
 296          return array(
 297              'description' => __( "Your installation of WordPress doesn't require FTP credentials to perform updates." ),
 298              'severity'    => 'pass',
 299          );
 300      }
 301  
 302      /**
 303       * Check if core files are writable by the web user/group.
 304       *
 305       * @since 5.2.0
 306       *
 307       * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass.
 308       *
 309       * @return array|bool The test results. false if they're not writeable.
 310       */
 311  	function test_all_files_writable() {
 312          global $wp_filesystem;
 313  
 314          include  ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
 315  
 316          $skin    = new Automatic_Upgrader_Skin;
 317          $success = $skin->request_filesystem_credentials( false, ABSPATH );
 318  
 319          if ( ! $success ) {
 320              return false;
 321          }
 322  
 323          WP_Filesystem();
 324  
 325          if ( 'direct' != $wp_filesystem->method ) {
 326              return false;
 327          }
 328  
 329          $checksums = get_core_checksums( $wp_version, 'en_US' );
 330          $dev       = ( false !== strpos( $wp_version, '-' ) );
 331          // Get the last stable version's files and test against that
 332          if ( ! $checksums && $dev ) {
 333              $checksums = get_core_checksums( (float) $wp_version - 0.1, 'en_US' );
 334          }
 335  
 336          // There aren't always checksums for development releases, so just skip the test if we still can't find any
 337          if ( ! $checksums && $dev ) {
 338              return false;
 339          }
 340  
 341          if ( ! $checksums ) {
 342              $description = sprintf(
 343                  // translators: %s: WordPress version
 344                  __( "Couldn't retrieve a list of the checksums for WordPress %s." ),
 345                  $wp_version
 346              );
 347              $description .= ' ' . __( 'This could mean that connections are failing to WordPress.org.' );
 348              return array(
 349                  'description' => $description,
 350                  'severity'    => 'warning',
 351              );
 352          }
 353  
 354          $unwritable_files = array();
 355          foreach ( array_keys( $checksums ) as $file ) {
 356              if ( 'wp-content' == substr( $file, 0, 10 ) ) {
 357                  continue;
 358              }
 359              if ( ! file_exists( ABSPATH . $file ) ) {
 360                  continue;
 361              }
 362              if ( ! is_writable( ABSPATH . $file ) ) {
 363                  $unwritable_files[] = $file;
 364              }
 365          }
 366  
 367          if ( $unwritable_files ) {
 368              if ( count( $unwritable_files ) > 20 ) {
 369                  $unwritable_files   = array_slice( $unwritable_files, 0, 20 );
 370                  $unwritable_files[] = '...';
 371              }
 372              return array(
 373                  'description' => __( 'Some files are not writable by WordPress:' ) . ' <ul><li>' . implode( '</li><li>', $unwritable_files ) . '</li></ul>',
 374                  'severity'    => 'fail',
 375              );
 376          } else {
 377              return array(
 378                  'description' => __( 'All of your WordPress files are writable.' ),
 379                  'severity'    => 'pass',
 380              );
 381          }
 382      }
 383  
 384      /**
 385       * Check if the install is using a development branch and can use nightly packages.
 386       *
 387       * @since 5.2.0
 388       *
 389       * @return array|bool The test results. false if it isn't a development version.
 390       */
 391  	function test_accepts_dev_updates() {
 392          include  ABSPATH . WPINC . '/version.php'; // $wp_version; // x.y.z
 393          // Only for dev versions
 394          if ( false === strpos( $wp_version, '-' ) ) {
 395              return false;
 396          }
 397  
 398          if ( defined( 'WP_AUTO_UPDATE_CORE' ) && ( 'minor' === WP_AUTO_UPDATE_CORE || false === WP_AUTO_UPDATE_CORE ) ) {
 399              return array(
 400                  'description' => sprintf(
 401                      /* translators: %s: Name of the constant used. */
 402                      __( 'WordPress development updates are blocked by the %s constant.' ),
 403                      '<code>WP_AUTO_UPDATE_CORE</code>'
 404                  ),
 405                  'severity'    => 'fail',
 406              );
 407          }
 408  
 409          /** This filter is documented in wp-admin/includes/class-core-upgrader.php */
 410          if ( ! apply_filters( 'allow_dev_auto_core_updates', $wp_version ) ) {
 411              return array(
 412                  'description' => sprintf(
 413                      /* translators: %s: Name of the filter used. */
 414                      __( 'WordPress development updates are blocked by the %s filter.' ),
 415                      '<code>allow_dev_auto_core_updates</code>'
 416                  ),
 417                  'severity'    => 'fail',
 418              );
 419          }
 420      }
 421  
 422      /**
 423       * Check if the site supports automatic minor updates.
 424       *
 425       * @since 5.2.0
 426       *
 427       * @return array The test results.
 428       */
 429  	function test_accepts_minor_updates() {
 430          if ( defined( 'WP_AUTO_UPDATE_CORE' ) && false === WP_AUTO_UPDATE_CORE ) {
 431              return array(
 432                  'description' => sprintf(
 433                      /* translators: %s: Name of the constant used. */
 434                      __( 'WordPress security and maintenance releases are blocked by %s.' ),
 435                      "<code>define( 'WP_AUTO_UPDATE_CORE', false );</code>"
 436                  ),
 437                  'severity'    => 'fail',
 438              );
 439          }
 440  
 441          /** This filter is documented in wp-admin/includes/class-core-upgrader.php */
 442          if ( ! apply_filters( 'allow_minor_auto_core_updates', true ) ) {
 443              return array(
 444                  'description' => sprintf(
 445                      /* translators: %s: Name of the filter used. */
 446                      __( 'WordPress security and maintenance releases are blocked by the %s filter.' ),
 447                      '<code>allow_minor_auto_core_updates</code>'
 448                  ),
 449                  'severity'    => 'fail',
 450              );
 451          }
 452      }
 453  }


Generated: Mon Jul 22 01:00:03 2019 Cross-referenced by PHPXref 0.7.1