Make WordPress Core

Opened 5 years ago

Closed 2 years ago

#47357 closed defect (bug) (fixed)

$allowedentitynames could be null

Reported by: doctorlai's profile doctorlai Owned by: sergeybiryukov's profile SergeyBiryukov
Milestone: 6.2 Priority: normal
Severity: normal Version:
Component: Formatting Keywords: has-patch needs-testing
Focuses: Cc:

Description

Every time when I upgrade wordpress to latest version, the wp-include/kses.php gets overwritten and the line 1758 where $allowedentitynames could be null.

It throws lots of warnings saying $allowedentitynames is null and function in_array cannot accept null as second parameter.

My manual fix is to add the following check before return:

if (!$allowedentitynames) return "&$i;";

if would be nice to have this investigated and fixed.

Attachments (2)

47357.diff (1.4 KB) - added by SergeyBiryukov 2 years ago.
47357.2.diff (1.6 KB) - added by SergeyBiryukov 2 years ago.

Download all attachments as: .zip

Change History (20)

#1 @SergeyBiryukov
5 years ago

  • Component changed from General to Formatting
  • Keywords reporter-feedback added

Hi @doctorlai, welcome to WordPress Trac! Thanks for the report.

Does the issue still happen with all plugins disabled and a default theme (Twenty Nineteen) activated?

It sounds like some plugin mistakenly overrides the $allowedentitynames with null instead of an empty array. This would indicate a developer error, so a warning seems appropriate here.

#2 @doctorlai
5 years ago

Hello,
I add these to my template, which causes the problem

function add_scriptfilter( $string ) {
  global $allowedtags;
  $allowedtags['script'] = array( 'src' => array () );
  return $string;
}
add_filter( 'pre_kses', 'add_scriptfilter' );

#3 @pento
5 years ago

  • Keywords reporter-feedback removed
  • Milestone Awaiting Review deleted
  • Resolution set to wontfix
  • Status changed from new to closed

Thank you for the extra information, @doctorlai.

As at @SergeyBiryukov suggested, allowing this warning to occur is the correct behaviour. $allowedentitynames should never be set to null, as there are multiple locations where it's expected to be an array.

#4 @KnowingArt_com
2 years ago

  • Resolution wontfix deleted
  • Status changed from closed to reopened

This is still a problem, and it crashes WordPress with a fatal error.

https://wordpress.stackexchange.com/questions/408101/broken-kses-php-function-wp-kses-named-entities-crashes-wordpress/408137#408137

As you can see from the stack trace -- and I checked all plugins and themes with grep -- no plugin or theme is setting $allowedentitynames

How is it getting set to null? No idea.

Anyway, the solution is pretty simple:

wp-includes/kses.php line 1866

if ( empty( $matches[1] ) OR empty( $allowedentitynames ) ) {

#5 follow-up: @KnowingArt_com
2 years ago

FWIW I have define( 'CUSTOM_TAGS', true ); on this blog. Is that supposed to crash WordPress? LOL

#6 in reply to: ↑ 5 @bosconiandynamics
2 years ago

  • Resolution set to wontfix
  • Status changed from reopened to closed

Replying to KnowingArt_com:

FWIW I have define( 'CUSTOM_TAGS', true ); on this blog. Is that supposed to crash WordPress? LOL

If CUSTOM_TAGS is set, WordPress expects that third-party code will provide a substitution for the $allowedentitynames global. If no substitution is provided, then $allowedentitynames will remain unset, triggering this error. This is an intended behavior as mentioned by @pento above.

CUSTOM_TAGS was soft deprecated in WordPress 3.5 - it is recommended to use the 'wp_kses_allowed_html' filter instead.

#7 @TJNowell
2 years ago

If you do not create the variables at the top of kses.php with your custom values, yes!

/**
 * Specifies the default allowable HTML tags.
 *
 * Using `CUSTOM_TAGS` is not recommended and should be considered deprecated. The
 * {@see 'wp_kses_allowed_html'} filter is more powerful and supplies context.
 *
 * @see wp_kses_allowed_html()
 * @since 1.2.0
 *
 * @var array[]|false Array of default allowable HTML tags, or false to use the defaults.
 */
if ( ! defined( 'CUSTOM_TAGS' ) ) {
	define( 'CUSTOM_TAGS', false );
}

I'd suggest using the wp_kses_allowed_html filter as the documentation suggests.

#8 @SergeyBiryukov
2 years ago

Should we consider a _doing_it_wrong() message here instead of a fatal error to improve the developer experience?

#9 follow-up: @TJNowell
2 years ago

Given that this has security implications, allowing null while warning the user in the log could lull them into a false sense of security if they've just followed an old article that mentions CUSTOM_TAGS and don't know about error logs etc.

Perhaps the else case would be a good place for it though, as well as checks if those variables exist and have values. It would still result in the same situation but the user would have an idea of how to fix it rather than being stuck not knowing what to do.

@SergeyBiryukov
2 years ago

#10 in reply to: ↑ 9 @SergeyBiryukov
2 years ago

  • Keywords has-patch needs-testing added
  • Milestone set to 6.1
  • Resolution wontfix deleted
  • Status changed from closed to reopened

Replying to TJNowell:

Perhaps the else case would be a good place for it though, as well as checks if those variables exist and have values. It would still result in the same situation but the user would have an idea of how to fix it rather than being stuck not knowing what to do.

Thanks! 47357.diff goes in that direction.

This still leads to a fatal error if any of the globals are not set, but displays a more helpful message.

To test the patch:

  1. Add define( 'CUSTOM_TAGS', true ); to wp-config.php.
  2. Set WP_DEBUG to true.
  3. Make sure any of these globals is not set:
    • $allowedposttags
    • $allowedtags
    • $allowedentitynames
    • $allowedxmlentitynames
  4. Check if an appropriate message from the patch is displayed or logged.
Last edited 2 years ago by SergeyBiryukov (previous) (diff)

#11 @bosconiandynamics
2 years ago

I think that this is a very beneficial change.

I'm not positive, but I think that the immediately previous confusion may have been the result of a third-party plugin having previously required the end-user to set CUSTOM_TAGS, then later updating to implement their functionality to leverage a 'wp_kses_allowed_html' filter instead and not implementing an end-user notice to relay the importance of removing the CUSTOM_TAGS definition, or any backwards-compatibility functionality to assist the transition.

The changes in the diff remove a lot of burden from third-party developers who might as of yet still be relying on the CUSTOM_TAGS constant and significantly improves the experience and troubleshooting capabilities for end-users.

#12 @audrasjb
2 years ago

  • Milestone changed from 6.1 to 6.2

With WP 6.1 RC 1 scheduled today (Oct 11, 2022), there is not much time left to address this ticket. Let's move it to the next milestone.

Ps: if you were about to send a patch and if you feel it is realistic to commit it in the next one or two hours, please feel free to move this ticket back to milestone 6.1.

#13 @ironprogrammer
2 years ago

Test Report

Patch tested: https://core.trac.wordpress.org/attachment/ticket/47357/47357.diff 👍🏻

Expected Results

  • ❌ Was able to reproduce the error by adding define( 'CUSTOM_TAGS', true ); to wp-config.php with TT3 theme active. The errors logged are:

PHP Warning: in_array() expects parameter 2 to be array, null given in ../wordpress-develop/src/wp-includes/kses.php on line 1872

Environment

  • Hardware: MacBook Pro Apple M1 Pro
  • OS: macOS 12.6
  • Browser: Google Chrome 105.0.5195.125
  • Server: nginx/1.23.1
  • PHP: 7.4.32
  • WordPress: 6.1-beta3-54390-src
  • Theme: twentytwentythree v1.0

Actual Results

  • ✅ After patching, the newly introduced _doing_it_wrong() notice was output in logs:

PHP Notice: Function wp_kses_allowed_html was called <strong>incorrectly</strong>. When using the <code>CUSTOM_TAGS</code> constant, make sure to set the <code>$allowedposttags</code> global to an array. Please see <a href="https://wordpress.org/support/article/debugging-in-wordpress/">Debugging in WordPress</a> for more information. (This message was added in version 6.1.0.) in ../wordpress-develop/src/wp-includes/functions.php on line 5836

This notice appeared for $allowedposttags (above), $allowedtags, $allowedentitynames, and $allowedxmlentitynames.

#14 @SergeyBiryukov
2 years ago

  • Owner set to SergeyBiryukov
  • Status changed from reopened to accepted

#15 @SergeyBiryukov
2 years ago

47357.2.diff is a minor update to include all missing globals in the notice, instead of displaying them one by one.

#16 follow-up: @mukesh27
2 years ago

@SergeyBiryukov The 47357.2.diff looks good. Do we needs unit test to check this behavior?

#17 in reply to: ↑ 16 @SergeyBiryukov
2 years ago

Replying to mukesh27:

The 47357.2.diff looks good. Do we needs unit test to check this behavior?

Thanks! I thought about that, but a unit test does not seem feasible here, as it would need to define the CUSTOM_TAGS constant, which cannot be unset and would then affect all the other KSES tests.

#18 @SergeyBiryukov
2 years ago

  • Resolution set to fixed
  • Status changed from accepted to closed

In 54672:

KSES: Display a notice if any of the required globals are not set.

When using the CUSTOM_TAGS constant, these global variables should be set to arrays:

  • $allowedposttags
  • $allowedtags
  • $allowedentitynames
  • $allowedxmlentitynames

This commit aims to improve developer experience by displaying a more helpful message to explain a PHP fatal error further in the code if any of these globals are either not set or not an array.

Note Using CUSTOM_TAGS is not recommended and should be considered deprecated. The wp_kses_allowed_html filter is more powerful and supplies context.

Follow-up to [832], [834], [2896], [13358], [21796], [28845], [43016], [48072].

Props doctorlai, pento, KnowingArt_com, bosconiandynamics, TJNowell, ironprogrammer, audrasjb, mukesh27, SergeyBiryukov.
Fixes #47357.

Note: See TracTickets for help on using tickets.