Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 87 additions & 0 deletions src/wp-admin/includes/class-wp-site-health.php
Original file line number Diff line number Diff line change
Expand Up @@ -2835,6 +2835,89 @@ public function get_test_opcode_cache(): array {
return $result;
}

/**
* Tests whether any of the site's database tables use the legacy utf8/utf8mb3 charset.
*
* The utf8mb3 charset (historically also exposed as `utf8` in MySQL) can only store
* 3-byte characters, so it cannot store emoji and some other multi-byte characters.
* It has been deprecated by MySQL and may be removed in a future release.
*
* @since 7.2.0
*
* @return array<string, string|array<string, string>> The test result.
*/
public function get_test_utf8mb3_usage() {
global $wpdb;

$result = array(
'label' => __( 'Your database tables use the current character encoding' ),
'status' => 'good',
'badge' => array(
'label' => __( 'Security' ),
'color' => 'blue',
),
'description' => sprintf(
'<p>%s</p>',
__( 'The utf8mb3 character set (sometimes shown as utf8) can only store 3-byte characters, so it cannot store emoji and some other characters. It has been deprecated by MySQL and may be removed in a future release.' )
),
'actions' => '',
'test' => 'utf8mb3_usage',
);

if ( empty( $wpdb->is_mysql ) ) {
return $result;
}

/**
* Filters the list of database tables to check for the legacy utf8/utf8mb3 character set.
*
* @since 7.2.0
*
* @param string[] $tables Prefixed names of the tables to check.
*/
$tables = apply_filters( 'site_status_utf8mb3_usage_tables', array_values( $wpdb->tables( 'all', true ) ) );

$affected_list = array();

foreach ( $tables as $table ) {
$columns = $wpdb->get_results( "SHOW FULL COLUMNS FROM `$table`" );

if ( ! $columns ) {
continue;
}

foreach ( $columns as $column ) {
if ( empty( $column->Collation ) ) {
continue;
}

list( $charset ) = explode( '_', $column->Collation );

if ( in_array( strtolower( $charset ), array( 'utf8', 'utf8mb3' ), true ) ) {
$affected_list[] = sprintf( '%s.%s', $table, $column->Field );
}
}
}

if ( empty( $affected_list ) ) {
return $result;
}

$result['status'] = 'recommended';
$result['label'] = __( 'Some database tables use the outdated utf8mb3 character set' );

$result['description'] .= sprintf(
'<p>%s</p>',
sprintf(
/* translators: %s: Comma-separated list of affected table and column names. */
__( 'The following tables and columns use the utf8mb3 character set: %s. Consider converting them to utf8mb4.' ),
implode( ', ', $affected_list )
)
);

return $result;
}

/**
* Returns a set of tests that belong to the site status page.
*
Expand Down Expand Up @@ -2935,6 +3018,10 @@ public static function get_tests() {
'label' => __( 'Opcode cache' ),
'test' => 'opcode_cache',
),
'utf8mb3_usage' => array(
'label' => __( 'Database character encoding' ),
'test' => 'utf8mb3_usage',
),
),
'async' => array(
'dotorg_communication' => array(
Expand Down
71 changes: 71 additions & 0 deletions tests/phpunit/tests/admin/wpSiteHealth.php
Original file line number Diff line number Diff line change
Expand Up @@ -707,4 +707,75 @@
$this->assertStringContainsString( __( 'Enabling this cache can significantly improve the performance of your site.' ), $result['description'] );
}
}

/**
* Tests get_test_utf8mb3_usage() when no tables use the legacy utf8/utf8mb3 charset.
*
* @ticket 66109
*
* @covers ::get_test_utf8mb3_usage()
*/
public function test_get_test_utf8mb3_usage_no_legacy_charset() {
global $wpdb;

if ( empty( $wpdb->is_mysql ) ) {
$this->markTestSkipped( 'This test requires a MySQL server.' );
}

$table_name = $wpdb->prefix . 'test_utf8mb3_usage_good';
$wpdb->query( "DROP TABLE IF EXISTS `$table_name`" );

Check warning on line 726 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "DROP TABLE IF EXISTS `$table_name`"
$wpdb->query( "CREATE TABLE `$table_name` ( some_column VARCHAR(50) CHARACTER SET utf8mb4 )" );

Check warning on line 727 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "CREATE TABLE `$table_name` ( some_column VARCHAR(50) CHARACTER SET utf8mb4 )"

$filter = self::only_table_filter( $table_name );
add_filter( 'site_status_utf8mb3_usage_tables', $filter );
$result = $this->instance->get_test_utf8mb3_usage();
remove_filter( 'site_status_utf8mb3_usage_tables', $filter );

$wpdb->query( "DROP TABLE `$table_name`" );

Check warning on line 734 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "DROP TABLE `$table_name`"

$this->assertSame( 'good', $result['status'], 'Status should be "good" when no tables use the legacy utf8/utf8mb3 charset.' );
$this->assertSame( 'utf8mb3_usage', $result['test'] );
}

/**
* Tests get_test_utf8mb3_usage() when a table uses the legacy utf8/utf8mb3 charset.
*
* @ticket 66109
*
* @covers ::get_test_utf8mb3_usage()
*/
public function test_get_test_utf8mb3_usage_with_legacy_charset() {
global $wpdb;

if ( empty( $wpdb->is_mysql ) ) {
$this->markTestSkipped( 'This test requires a MySQL server.' );
}

$table_name = $wpdb->prefix . 'test_utf8mb3_usage';
$wpdb->query( "DROP TABLE IF EXISTS `$table_name`" );

Check warning on line 755 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "DROP TABLE IF EXISTS `$table_name`"
$wpdb->query( "CREATE TABLE `$table_name` ( legacy_column VARCHAR(50) CHARACTER SET utf8mb3, other_column VARCHAR(50) CHARACTER SET utf8mb4 )" );

Check warning on line 756 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "CREATE TABLE `$table_name` ( legacy_column VARCHAR(50) CHARACTER SET utf8mb3, other_column VARCHAR(50) CHARACTER SET utf8mb4 )"

$filter = self::only_table_filter( $table_name );
add_filter( 'site_status_utf8mb3_usage_tables', $filter );
$result = $this->instance->get_test_utf8mb3_usage();
remove_filter( 'site_status_utf8mb3_usage_tables', $filter );

$wpdb->query( "DROP TABLE `$table_name`" );

Check warning on line 763 in tests/phpunit/tests/admin/wpSiteHealth.php

View workflow job for this annotation

GitHub Actions / Coding standards / PHP checks

Use placeholders and $wpdb->prepare(); found interpolated variable $table_name at "DROP TABLE `$table_name`"

$this->assertSame( 'recommended', $result['status'], 'Status should be "recommended" when a table uses the legacy utf8/utf8mb3 charset.' );
$this->assertStringContainsString( $table_name . '.legacy_column', $result['description'] );
$this->assertStringNotContainsString( $table_name . '.other_column', $result['description'] );
}

/**
* Builds a `site_status_utf8mb3_usage_tables` filter callback scoped to a single table.
*
* @param string $table_name The only table name the filtered test should scan.
* @return callable The filter callback.
*/
private static function only_table_filter( $table_name ) {
return static function () use ( $table_name ) {
return array( $table_name );
};
}
}
Loading