Runtime PHP TypeError when comparing broken revisions

Created on 17 October 2023, almost 2 years ago

Problem/Motivation

When comparing revisions that have unexpectedly missing data, PHP 8.0 and above will return a TypeError:
Argument #1 ($value) must be of type Countable|array, int given in diff_process_state_lines() (line 521 of /code/profiles/openberkeley/modules/contrib/diff/diff.pages.inc).

Steps to reproduce

Unfortunately it's difficult to reproduce the issue; it involves a combination of the Panels IPE and Workbench Moderation. The Panels IPE allows unchecking the Create Revision checkbox when customizing a page. In some cases, unchecking this box when saving a draft of a moderated node results in a broken revision. When you compare revisions, any comparison that encompasses the broken revision will return the TypeError.

Proposed resolution

Here's the function in question:

/**
 * Helper function to get line counts per field.
 */
function diff_process_state_lines(&$diff, $key) {
  foreach ($diff['#states'] as $state => $data) {
    if (isset($data['#old'])) {
      if (is_string($data['#old'])) {
        $diff['#states'][$state]['#old'] = explode("\n", $data['#old']);
      }
      $diff['#states'][$state]['#count_old'] = count($diff['#states'][$state]['#old']);
    }
    else {
      $diff['#states'][$state]['#count_old'] = 0;
    }
    if (isset($data['#new'])) {
      if (is_string($data['#new'])) {
        $diff['#states'][$state]['#new'] = explode("\n", $data['#new']);
      }
      $diff['#states'][$state]['#count_new'] = count($diff['#states'][$state]['#new']);
    }
    else {
      $diff['#states'][$state]['#count_new'] = 0;
    }
  }
}

This function assumes that if the incoming data isn't a string, it's an array. In the broken case, it's neither, it's an integer. We can add a conditional to check whether the non-string is an array. However, in versions of PHP prior to 8.0, in some cases count() would return 1 instead of 0 when trying to count a non-array/non-string, so behavior might change.

It's tempting to just cast the non-array to a string - this would work for booleans, integers, and floats, but not for objects that don't implement toString.

Remaining tasks

Patch and test.

User interface changes

None.

API changes

None.

Data model changes

None.

πŸ› Bug report
Status

Active

Version

3.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States cboyden

Live updates comments and jobs are added and updated live.
  • PHP 8.0

    The issue particularly affects sites running on PHP version 8.0.0 or later.

Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024