Skip to content
Draft
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
3 changes: 3 additions & 0 deletions .github/workflows/phpstan-static-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ on:
- 'phpstan.neon.dist'
- 'tests/phpstan/base.neon'
- 'tests/phpstan/baselines/**'
# These files configure the tests of the PHPStan extensions.
- 'tests/phpstan/phpunit.xml.dist'
- 'tests/phpstan/Tests/tests.neon'
# Confirm any changes to relevant workflow files.
- '.github/workflows/phpstan-static-analysis.yml'
- '.github/workflows/reusable-phpstan-static-analysis-v1.yml'
Expand Down
7 changes: 7 additions & 0 deletions .github/workflows/reusable-phpstan-static-analysis-v1.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
# - Logs debug information.
# - Installs Composer dependencies.
# - Make Composer packages available globally.
# - Runs the tests of the WordPress-specific PHPStan extensions.
# - Builds WordPress.
# - Configures caching for PHPStan static analysis scans.
# - Runs PHPStan static analysis.
Expand Down Expand Up @@ -75,6 +76,12 @@ jobs:
- name: Make Composer packages available globally
run: echo "${PWD}/vendor/bin" >> "$GITHUB_PATH"

# The extensions in `tests/phpstan` are tested against fixtures rather than against
# core, so a defect in one is reported here as a failing test rather than as a
# change in what the analysis below reports.
- name: Run the tests of the PHPStan extensions
run: composer run phpstan:test

# The directory holds more than the analysis results. PHPStan also stores what it read out of
# each source file there, the docblocks and signatures it found, keyed by that file's contents
# and nothing else. The extensions in `tests/phpstan` change what reading a file yields without
Expand Down
1 change: 1 addition & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@
"scripts": {
"phpstan": "@php ./vendor/bin/phpstan analyse --memory-limit=2G",
"phpstan:baselines": [ "Composer\\Config::disableProcessTimeout", "@php ./tests/phpstan/generate-baselines.php" ],
"phpstan:test": "@php ./vendor/phpunit/phpunit/phpunit -c tests/phpstan/phpunit.xml.dist",
"compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source",
"format": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf --report=summary,source",
"lint": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --report=summary,source",
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@
"test:visual": "wp-scripts test-playwright --config tests/visual-regression/playwright.config.js",
"typecheck:php": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan --",
"typecheck:php:baselines": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan:baselines --",
"typecheck:php:test": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan:test --",
"gutenberg:copy": "node tools/gutenberg/copy.js",
"gutenberg:verify": "node tools/gutenberg/utils.js",
"gutenberg:download": "node tools/gutenberg/download.js && npm run build:gutenberg"
Expand Down
12 changes: 5 additions & 7 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,11 @@
#############################################################################
-->

<rule ref="WordPress-Core"/>
<rule ref="WordPress-Core">
<!-- PHPStan reports these, under the same codes. See tests/phpstan/README.md. -->
<exclude name="WordPress.DB.PreparedSQL.InterpolatedNotPrepared"/>
<exclude name="WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare"/>
</rule>


<!--
Expand All @@ -140,9 +144,6 @@
<!-- Exclude the unit tests as no warnings are allowed there. Note: these issues should be fixed and the exclude removed! -->
<exclude-pattern>/tests/phpunit/*</exclude-pattern>
</rule>
<rule ref="WordPress.DB.PreparedSQL.InterpolatedNotPrepared">
<type>warning</type>
</rule>
<rule ref="WordPress.DB.PreparedSQL.NotPrepared">
<type>warning</type>
</rule>
Expand Down Expand Up @@ -313,9 +314,6 @@

<!-- Allow the WP DB related tests for issues with prepared SQL placeholders
(as the handling of those are being tested). -->
<rule ref="WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare">
<exclude-pattern>/tests/phpunit/tests/db\.php</exclude-pattern>
</rule>
<rule ref="WordPress.DB.PreparedSQLPlaceholders.UnsupportedPlaceholder">
<exclude-pattern>/tests/phpunit/tests/db\.php</exclude-pattern>
</rule>
Expand Down
2 changes: 2 additions & 0 deletions phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ includes:
# Regenerate with `composer phpstan:baselines`, which rewrites both the files
# and the list between the markers. Do not edit that list by hand.
# phpstan:baselines start
- tests/phpstan/baselines/WordPress.DB.PreparedSQL.InterpolatedNotPrepared.neon
- tests/phpstan/baselines/WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare.neon
- tests/phpstan/baselines/argument.type.neon
- tests/phpstan/baselines/argument.unresolvableType.neon
- tests/phpstan/baselines/assign.propertyType.neon
Expand Down
1 change: 0 additions & 1 deletion src/wp-admin/includes/class-wp-site-health.php
Original file line number Diff line number Diff line change
Expand Up @@ -3810,7 +3810,6 @@ public function should_suggest_persistent_object_cache() {
// With InnoDB the `TABLE_ROWS` are estimates, which are accurate enough and faster to retrieve than individual `COUNT()` queries.
$results = $wpdb->get_results(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- This query cannot use interpolation.
"SELECT TABLE_NAME AS 'table', TABLE_ROWS AS 'rows', SUM(data_length + index_length) as 'bytes' FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s AND TABLE_NAME IN ('$table_names') GROUP BY TABLE_NAME;",
DB_NAME
),
Expand Down
1 change: 0 additions & 1 deletion src/wp-admin/includes/export.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,6 @@ function export_wp( $args = array() ) {
$post_types = get_post_types( array( 'can_export' => true ) );
$esses = array_fill( 0, count( $post_types ), '%s' );

// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types );
}

Expand Down
2 changes: 1 addition & 1 deletion src/wp-admin/includes/schema.php
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ function populate_options( array $options = array() ) {
);

$keys = "'" . implode( "', '", array_keys( $options ) ) . "'";
$existing_options = $wpdb->get_col( "SELECT option_name FROM $wpdb->options WHERE option_name in ( $keys )" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$existing_options = $wpdb->get_col( "SELECT option_name FROM $wpdb->options WHERE option_name in ( $keys )" );

$insert = '';

Expand Down
5 changes: 0 additions & 5 deletions src/wp-admin/install-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ function maybe_create_table( $table_name, $create_ddl ) {
function maybe_add_column( $table_name, $column_name, $create_ddl ) {
global $wpdb;

// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Cannot be prepared. Fetches columns for table names.
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {
return true;
Expand All @@ -103,7 +102,6 @@ function maybe_add_column( $table_name, $column_name, $create_ddl ) {
$wpdb->query( $create_ddl );

// We cannot directly tell whether this succeeded!
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Cannot be prepared. Fetches columns for table names.
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {
return true;
Expand All @@ -129,7 +127,6 @@ function maybe_add_column( $table_name, $column_name, $create_ddl ) {
function maybe_drop_column( $table_name, $column_name, $drop_ddl ) {
global $wpdb;

// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Cannot be prepared. Fetches columns for table names.
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {

Expand All @@ -138,7 +135,6 @@ function maybe_drop_column( $table_name, $column_name, $drop_ddl ) {
$wpdb->query( $drop_ddl );

// We cannot directly tell whether this succeeded!
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Cannot be prepared. Fetches columns for table names.
foreach ( $wpdb->get_col( "DESC $table_name", 0 ) as $column ) {
if ( $column === $column_name ) {
return false;
Expand Down Expand Up @@ -185,7 +181,6 @@ function check_column( $table_name, $col_name, $col_type, $is_null = null, $key

$diffs = 0;

// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Cannot be prepared. Fetches columns for table names.
$results = $wpdb->get_results( "DESC $table_name" );

foreach ( $results as $row ) {
Expand Down
2 changes: 0 additions & 2 deletions src/wp-includes/class-wp-comment-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -864,7 +864,6 @@ protected function get_comment_ids() {
// $field_value may be an array.
$esses = array_fill( 0, count( (array) $field_value ), '%s' );

// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
$this->sql_clauses['where'][ $field_name ] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $field_value );
}
}
Expand All @@ -887,7 +886,6 @@ protected function get_comment_ids() {

$esses = array_fill( 0, count( $q_values ), '%s' );

// phpcs:ignore WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
$this->sql_clauses['where'][ $field_name ] = $wpdb->prepare( " {$wpdb->posts}.{$field_name} IN (" . implode( ',', $esses ) . ')', $q_values );
}
}
Expand Down
6 changes: 3 additions & 3 deletions src/wp-includes/class-wp-meta-query.php
Original file line number Diff line number Diff line change
Expand Up @@ -668,11 +668,11 @@ public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' )
switch ( $meta_compare_key ) {
case '=':
case 'EXISTS':
$where = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$where = $wpdb->prepare( "$alias.meta_key = %s", trim( $clause['key'] ) );
break;
case 'LIKE':
$meta_compare_value = '%' . $wpdb->esc_like( trim( $clause['key'] ) ) . '%';
$where = $wpdb->prepare( "$alias.meta_key LIKE %s", $meta_compare_value ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$where = $wpdb->prepare( "$alias.meta_key LIKE %s", $meta_compare_value );
break;
case 'IN':
$meta_compare_string = "$alias.meta_key IN (" . substr( str_repeat( ',%s', count( $clause['key'] ) ), 1 ) . ')';
Expand All @@ -688,7 +688,7 @@ public function get_sql_for_clause( &$clause, $parent_query, $clause_key = '' )
$cast = '';
$meta_key = "$alias.meta_key";
}
$where = $wpdb->prepare( "$meta_key $operator $cast %s", trim( $clause['key'] ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$where = $wpdb->prepare( "$meta_key $operator $cast %s", trim( $clause['key'] ) );
break;

case '!=':
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -4604,7 +4604,7 @@ function _wp_batch_update_comment_type() {
"UPDATE {$wpdb->comments}
SET comment_type = 'comment'
WHERE comment_type = ''
AND comment_ID IN ({$comment_id_list})" // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
AND comment_ID IN ({$comment_id_list})"
);

// Make sure to clean the comment cache.
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/link-template.php
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ function get_adjacent_post( $in_same_term = false, $excluded_terms = '', $previo
$join = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_term, $excluded_terms, $taxonomy, $post );

// Prepare the where clause for the adjacent post query.
$where_prepared = $wpdb->prepare( "WHERE (p.post_date $comparison_operator %s OR (p.post_date = %s AND p.ID $comparison_operator %d)) AND p.post_type = %s $where", $current_post_date, $current_post_date, $post->ID, $post->post_type ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $comparison_operator is a string literal, either '<' or '>'.
$where_prepared = $wpdb->prepare( "WHERE (p.post_date $comparison_operator %s OR (p.post_date = %s AND p.ID $comparison_operator %d)) AND p.post_type = %s $where", $current_post_date, $current_post_date, $post->ID, $post->post_type );

/**
* Filters the WHERE clause in the SQL for an adjacent post query.
Expand Down
2 changes: 1 addition & 1 deletion src/wp-includes/ms-site.php
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ function wp_uninitialize_site( $site_id ) {
$drop_tables = apply_filters( 'wpmu_drop_tables', $tables, $site->id );

foreach ( (array) $drop_tables as $table ) {
$wpdb->query( "DROP TABLE IF EXISTS `$table`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
$wpdb->query( "DROP TABLE IF EXISTS `$table`" );
}

/**
Expand Down
1 change: 0 additions & 1 deletion src/wp-includes/option.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,6 @@ function wp_set_option_autoload_values( array $options ) {
* Determine the relevant options that do not already use the given autoload value.
* If no options are returned, no need to update.
*/
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared,WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
$options_to_update = $wpdb->get_col( $wpdb->prepare( "SELECT option_name FROM $wpdb->options $where", $where_args ) );
if ( ! $options_to_update ) {
return $results;
Expand Down
1 change: 0 additions & 1 deletion src/wp-includes/update.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ function wp_version_check( $extra_stats = array(), $force_check = false ) {
$table_names = implode( "','", $wpdb->tables() );
$myisam_tables = $wpdb->get_results(
$wpdb->prepare(
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- This query cannot use interpolation.
"SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = %s AND TABLE_NAME IN ('$table_names') AND ENGINE = %s;",
DB_NAME,
'MyISAM'
Expand Down
Loading
Loading