[wp-trac] [WordPress Trac] #64347: Fatal error when `wxr_cdata()` is called with non-string value
WordPress Trac
noreply at wordpress.org
Wed Dec 17 23:33:22 UTC 2025
#64347: Fatal error when `wxr_cdata()` is called with non-string value
----------------------------------------+---------------------
Reporter: desrosj | Owner: (none)
Type: defect (bug) | Status: new
Priority: normal | Milestone: 6.9.1
Component: Export | Version: 6.9
Severity: normal | Resolution:
Keywords: has-patch needs-unit-tests | Focuses:
----------------------------------------+---------------------
Comment (by westonruter):
In looking at the original error stack trace, the source of the error is
at [https://github.com/WordPress/wordpress-
develop/blob/5df78618d61c91194c40223cfc07f2eb6d01ac96/src/wp-
admin/includes/export.php#L682 /wp-admin/includes/export.php(682)]:
{{{#!php
<wp:meta_value><?php echo wxr_cdata( $meta->meta_value );
?></wp:meta_value>
}}}
The problem is that `$meta->meta_value` may be `null` here, although I'm
not sure why. The `$meta` variable is coming iterating over this array:
{{{#!php
<?php
$wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE
post_id = %d", $post->ID ) )
}}}
It appears the issue is that the `wp_postmeta.meta_value` column is
defined as a `LONGTEXT` which may also be `NULL`
([https://github.com/WordPress/wordpress-
develop/blob/5df78618d61c91194c40223cfc07f2eb6d01ac96/src/wp-
admin/includes/schema.php#L150-L158 source]):
{{{
CREATE TABLE $wpdb->postmeta (
meta_id bigint(20) unsigned NOT NULL auto_increment,
post_id bigint(20) unsigned NOT NULL default '0',
meta_key varchar(255) default NULL,
meta_value longtext,
PRIMARY KEY (meta_id),
KEY post_id (post_id),
KEY meta_key (meta_key($max_index_length))
) $charset_collate;
}}}
According to the [https://dev.mysql.com/doc/refman/8.4/en/create-
table.html MySQL reference]:
> If neither NULL nor NOT NULL is specified, the column is treated as
though NULL had been specified.
So this appears to be the source of the non-string value.
It didn't cause an error in WordPress 6.8 because `wxr_cdata()` was
defined as:
{{{#!php
<?php
function wxr_cdata( $str ) {
if ( ! seems_utf8( $str ) ) {
$str = utf8_encode( $str );
}
// $str = ent2ncr(esc_html($str));
$str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str )
. ']]>';
return $str;
}
}}}
Whereas in WP 6.9 it is:
{{{#!php
<?php
function wxr_cdata( $str ) {
if ( ! wp_is_valid_utf8( $str ) ) {
$str = utf8_encode( $str );
}
// $str = ent2ncr(esc_html($str));
$str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str )
. ']]>';
return $str;
}
}}}
The difference is that `seems_utf8()` didn't have any PHP type defined for
the `$str` argument:
{{{
function seems_utf8( $str )
}}}
Whereas `wp_is_valid_utf8` does:
{{{
function wp_is_valid_utf8( string $string )
}}}
So to fix this issue, it seems casting the `$str` to a `string` will
preserve the original behavior which would happen implicitly when `$str`
is passed through `str_replace()`. Note that in PHP 8.1 this would have
caused a deprecation error already anyway when the `$str` was passed into
`seems_utf8()` in 6.8:
> Deprecated: strlen(): Passing null to parameter #1 ($string) of type
string is deprecated in /var/www/src/wp-includes/formatting.php on line
888
The deprecation in 6.8 has become a fatal error in 6.9 due to the use of a
PHP type for the `$str` param.
All this to say, I think at the beginning of `wxr_cdata()` can simply do
this:
{{{#!php
<?php
if ( is_scalar( $str ) ) {
$str = (string) $str;
}
}}}
If, by chance, a non-scalar value (an array or object) is passed in
erroneously, then this will cause a PHP fatal error in the same way as
would be happening in 6.8 already.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/64347#comment:13>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list