Media: Check the return type of _get_cron_array() in WP_Media_List_Table::prepare_items().

The following warnings could, in very select circumstances, be shown:
{{{
// PHP 8.0 and higher:
Warning: foreach() argument must be of type array|object, bool given

// PHP 5.6 – 7.4
Warning: Invalid argument supplied for foreach()
}}}

In `WP_Media_List_Table::prepare_items()`, the cron info array is retrieved via a call to `_get_cron_array()`, but as the documentation (correctly) states, the return type of that function is `array|false`, where `false` is returned for a virgin site, with no cron jobs scheduled yet.

However, no type check is done on the return value, and the method just blindly continues by using it in a `foreach`.

Fixed by adding validation for the returned value from `_get_cron_array()` and only running the `foreach` when the returned value is an array.

Reference: [https://developer.wordpress.org/reference/functions/_get_cron_array/ WordPress Developer Resources: _get_cron_array()]

Follow-up to [48417].

Props jrf, hellofromTonya, mukesh27.
Fixes #53949.

git-svn-id: https://develop.svn.wordpress.org/trunk@51638 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Sergey Biryukov 2021-08-19 12:43:03 +00:00
parent 0222625c37
commit 05f28947e7
2 changed files with 59 additions and 5 deletions

View File

@ -78,12 +78,16 @@ class WP_Media_List_Table extends WP_List_Table {
*/
$not_in = array();
foreach ( _get_cron_array() as $cron ) {
if ( isset( $cron['upgrader_scheduled_cleanup'] ) ) {
$details = reset( $cron['upgrader_scheduled_cleanup'] );
$crons = _get_cron_array();
if ( ! empty( $details['args'][0] ) ) {
$not_in[] = (int) $details['args'][0];
if ( is_array( $crons ) ) {
foreach ( $crons as $cron ) {
if ( isset( $cron['upgrader_scheduled_cleanup'] ) ) {
$details = reset( $cron['upgrader_scheduled_cleanup'] );
if ( ! empty( $details['args'][0] ) ) {
$not_in[] = (int) $details['args'][0];
}
}
}
}

View File

@ -0,0 +1,50 @@
<?php
/**
* @group admin
*/
class Tests_Admin_includesMediaListTable extends WP_UnitTestCase {
public static function set_up_before_class() {
parent::set_up_before_class();
require_once ABSPATH . 'wp-admin/includes/class-wp-media-list-table.php';
}
/**
* Tests that a call to WP_Media_List_Table::prepare_items() on a site without any scheduled events
* does not result in a PHP warning.
*
* The warning that we should not see:
* PHP 5.6 - 7.4: `Invalid argument supplied for foreach()`.
* PHP 8.0 and higher: `Warning: foreach() argument must be of type array|object, bool given`.
*
* Note: This does not test the actual functioning of the WP_Media_List_Table::prepare_items() method.
* It just and only tests for/against the PHP warning.
*
* @ticket 53949
* @covers WP_Media_List_Table::prepare_items
*/
public function test_prepare_items_without_cron_option_does_not_throw_warning() {
global $wp_query;
// Note: setMethods() is deprecated in PHPUnit 9, but still supported.
$mock = $this->getMockBuilder( WP_Media_List_Table::class )
->disableOriginalConstructor()
->disallowMockingUnknownTypes()
->setMethods( array( 'set_pagination_args' ) )
->getMock();
$mock->expects( $this->once() )
->method( 'set_pagination_args' );
$wp_query->query_vars['posts_per_page'] = 10;
delete_option( 'cron' );
// Verify that the cause of the error is in place.
$this->assertFalse( _get_cron_array(), '_get_cron_array() does not return false' );
// If this test does not error out due to the PHP warning, we're good.
$mock->prepare_items();
}
}