Opened 3 months ago
Last modified 3 months ago
#61114 new defect (bug)
PHP 8+ Fatal Error in WP_Upgrader due to TypeError in array_keys() Call
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | 2.8 |
Component: | Upgrade/Install | Keywords: | needs-patch |
Focuses: | Cc: |
Description
Aa PHP 8+ Fatal error occurs in multiple instances within class-wp-upgrader.php
when array_keys()
is called with a boolean argument instead of an array. This error is triggered under conditions where $wp_filesystem->dirlist()
fails to read a directory and returns false.
This often leads to the plugins/theme being missing from the site.
It appears the error stems from the function $wp_filesystem->dirlist()
returning false
-- likely due to a previously reported and unfixed bug where the upgrader deletes files related to other in-progress upgrades as reported by @bpayton in https://core.trac.wordpress.org/ticket/53705
Errors Observed
As of 6.5.2, the TypeError occurs in the install_package(
) method at the following lines when attempting to handle plugin, theme, or language pack upgrades or installations:
- Line 556: During the initial directory listing as part of a plugin or theme installation. https://core.trac.wordpress.org/browser/trunk/src/wp-admin/includes/class-wp-upgrader.php?rev=56550#L556
- Line 603: When checking if the source location has changed and requires a refresh of the directory listing. https://core.trac.wordpress.org/browser/trunk/src/wp-admin/includes/class-wp-upgrader.php?rev=56550#L603
PHP Fatal error: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, bool given in /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php:556 Stack trace: #0 /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php(556): array_keys(false) #1 /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php(883): WP_Upgrader->install_package(Array) #2 /wordpress/core/6.5.2/wp-admin/includes/class-plugin-upgrader.php(137): WP_Upgrader->run(Array) #3 /srv/htdocs/wp-content/themes/hello-shoppable/inc/getting-started/getting-started.php(193): Plugin_Upgrader->install('https://downloa...') #4 /wordpress/core/6.5.2/wp-includes/class-wp-hook.php(324): Hello_Shoppable_Notice_Handler->hello_shoppable_getting_started('') #5 /wordpress/core/6.5.2/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters('', Array) #6 /wordpress/core/6.5.2/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #7 /wordpress/core/6.5.2/wp-admin/admin-ajax.php(192): do_action('wp_ajax_hello_s...') #8 {main} thrown in /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php on line 556
PHP Fatal error: Uncaught TypeError: array_keys(): Argument #1 ($array) must be of type array, bool given in /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php:556 Stack trace: #0 /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php(556): array_keys(false) #1 /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php(883): WP_Upgrader->install_package(Array) #2 /wordpress/core/6.5.2/wp-admin/includes/class-plugin-upgrader.php(237): WP_Upgrader->run(Array) #3 /srv/htdocs/wp-content/plugins/elementor/includes/rollback.php(171): Plugin_Upgrader->upgrade('elementor/eleme...') #4 /srv/htdocs/wp-content/plugins/elementor/includes/rollback.php(184): Elementor\Rollback->upgrade() #5 /srv/htdocs/wp-content/plugins/elementor/includes/settings/tools.php(172): Elementor\Rollback->run() #6 /wordpress/core/6.5.2/wp-includes/class-wp-hook.php(324): Elementor\Tools->post_elementor_rollback('') #7 /wordpress/core/6.5.2/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters('', Array) #8 /wordpress/core/6.5.2/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #9 /wordpress/core/6.5.2/wp-admin/admin-post.php(85): do_action('admin_post_elem...') #10 {main} thrown in /wordpress/core/6.5.2/wp-admin/includes/class-wp-upgrader.php on line 556
Steps to Reproduce
- Attempt to install or upgrade a plugin, theme, or language pack on a WordPress installation running under PHP 8.0 or later.
- Ensure that the
$wp_filesystem->dirlist()
function fails to return a directory list (can be simulated by providing a non-existent source directory via deletion or other methods). - Observe the fatal error logs as the install_package() method fails due to array_keys() receiving false.
Expected Behavior
While this could likely be alleviated by resolving https://core.trac.wordpress.org/ticket/53705 , the install_package()
method should handle cases where the directory listing is unavailable (i.e., when $wp_filesystem->dirlist()
returns false
) without resulting in a fatal error. Appropriate error handling should be in place to manage such failures gracefully.
Actual Behavior
Actual Behavior:
When $wp_filesystem->dirlist()
returns false, the absence of a check before the array_keys() function call leads to a fatal error due to a type mismatch (boolean given instead of array).
Change History (9)
#2
@
3 months ago
- Keywords needs-patch added
- Severity changed from major to normal
- Version changed from 6.5 to 2.8
This ticket was mentioned in Slack in #core-upgrade-install by afragen. View the logs.
3 months ago
#5
@
3 months ago
This is the line.
So perhaps casting to an array?
$source_files = array_keys( (array) $wp_filesystem->dirlist( $source ) );
#6
@
3 months ago
@afragen PHP 8.1 was the primary version I've seen but this can occur on any current PHP version ≥8
#7
@
3 months ago
Thanks @verygoode that confirms my suspicions. The above casting should fix the issue, can you test and report back?
#8
@
3 months ago
A quick way to reproduce is to spin up a site, set one or more plugins to a previous version like wp plugin install hello-dolly --version=1.6 --force
Then, run multiple requests at the same time to wp plugin update hello-dolly
and/or other plugin updates -- simulating a situation where multiple events are firing off to update something and leading to failures like reported on #53705
Without the casting, we can observe the fatal.
wp plugin update hello-dolly Enabling Maintenance mode... Downloading update from https://downloads.wordpress.org/plugin/hello-dolly.1.7.3.zip... Unpacking the update... Installing the latest version... Error: There has been a critical error on this website.Learn more about troubleshooting WordPress. There has been a critical error on this website.
With your casting recommendation, this fails without a fatal @afragen
wp plugin update hello-dolly Enabling Maintenance mode... Downloading update from https://downloads.wordpress.org/plugin/hello-dolly.1.7.3.zip Unpacking the update... Installing the latest version... Warning: Could not move the old version to the upgrade-temp-backup directory. Plugin update failed. Disabling Maintenance mode... +-------------+-------------+-------------+--------+ | name | old_version | new_version | status | +-------------+-------------+-------------+--------+ | hello-dolly | 1.6 | 1.7.2 | Error | +-------------+-------------+-------------+--------+ Error: No plugins updated (1 failed).
#9
@
3 months ago
With the casting, without a fatal, a warning may also be observed in WP-CLI
Warning: Directory listing failed. "hello-dolly"
The following warning is also logged in some cases, given that other events are clearing out the upgrade folder.
[02-May-2024 19:28:03 UTC] PHP Warning: dir(/Users/test/Local Sites/testing-upgrader/app/public/wp-content/upgrade/woocommerce.8.8.3-6ZaMui/woocommerce/src/Internal/Admin/Onboarding/): Failed to open directory: No such file or directory in /Users/test/Local Sites/testing-upgrader/app/public/wp-admin/includes/class-wp-filesystem-direct.php on line 636
Error for line 603.