diff -r 48c4eec2b7e6 -r 8c2e4d02f4ef wp/wp-admin/includes/class-wp-upgrader.php --- a/wp/wp-admin/includes/class-wp-upgrader.php Fri Sep 05 18:40:08 2025 +0200 +++ b/wp/wp-admin/includes/class-wp-upgrader.php Fri Sep 05 18:52:52 2025 +0200 @@ -204,6 +204,7 @@ $this->strings['mkdir_failed'] = __( 'Could not create directory.' ); $this->strings['incompatible_archive'] = __( 'The package could not be installed.' ); $this->strings['files_not_writable'] = __( 'The update cannot be installed because some files could not be copied. This is usually due to inconsistent file permissions.' ); + $this->strings['dir_not_readable'] = __( 'A directory could not be read.' ); $this->strings['maintenance_start'] = __( 'Enabling Maintenance mode…' ); $this->strings['maintenance_end'] = __( 'Disabling Maintenance mode…' ); @@ -485,7 +486,7 @@ * @since 6.2.0 Use move_dir() instead of copy_dir() when possible. * * @global WP_Filesystem_Base $wp_filesystem WordPress filesystem subclass. - * @global array $wp_theme_directories + * @global string[] $wp_theme_directories * * @param array|string $args { * Optional. Array or string of arguments for installing a package. Default empty array. @@ -524,6 +525,11 @@ $destination = $args['destination']; $clear_destination = $args['clear_destination']; + /* + * Give the upgrade an additional 300 seconds (5 minutes) to ensure the install + * doesn't prematurely timeout having used up the maximum script execution time + * upacking and downloading in WP_Upgrader->run(). + */ if ( function_exists( 'set_time_limit' ) ) { set_time_limit( 300 ); } @@ -557,7 +563,13 @@ $remote_source = $args['source']; $local_destination = $destination; - $source_files = array_keys( $wp_filesystem->dirlist( $remote_source ) ); + $dirlist = $wp_filesystem->dirlist( $remote_source ); + + if ( false === $dirlist ) { + return new WP_Error( 'source_read_failed', $this->strings['fs_error'], $this->strings['dir_not_readable'] ); + } + + $source_files = array_keys( $dirlist ); $remote_destination = $wp_filesystem->find_folder( $local_destination ); // Locate which directory to copy to the new folder. This is based on the actual folder holding the files. @@ -604,7 +616,13 @@ // Has the source location changed? If so, we need a new source_files list. if ( $source !== $remote_source ) { - $source_files = array_keys( $wp_filesystem->dirlist( $source ) ); + $dirlist = $wp_filesystem->dirlist( $source ); + + if ( false === $dirlist ) { + return new WP_Error( 'new_source_read_failed', $this->strings['fs_error'], $this->strings['dir_not_readable'] ); + } + + $source_files = array_keys( $dirlist ); } /* @@ -990,8 +1008,18 @@ global $wp_filesystem; if ( ! $wp_filesystem ) { - require_once ABSPATH . 'wp-admin/includes/file.php'; - WP_Filesystem(); + if ( ! function_exists( 'WP_Filesystem' ) ) { + require_once ABSPATH . 'wp-admin/includes/file.php'; + } + + ob_start(); + $credentials = request_filesystem_credentials( '' ); + ob_end_clean(); + + if ( false === $credentials || ! WP_Filesystem( $credentials ) ) { + wp_trigger_error( __FUNCTION__, __( 'Could not access filesystem.' ) ); + return; + } } $file = $wp_filesystem->abspath() . '.maintenance'; @@ -1053,7 +1081,7 @@ } // Update the lock, as by this point we've definitely got a lock, just need to fire the actions. - update_option( $lock_option, time() ); + update_option( $lock_option, time(), false ); return true; }