Skip to content
Merged
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
36 changes: 36 additions & 0 deletions features/db-import.feature
Original file line number Diff line number Diff line change
Expand Up @@ -374,3 +374,39 @@ Feature: Import a WordPress database
"""
Success: Imported from 'zerodate_compose.sql'.
"""

@require-mysql-or-mariadb
Scenario: `wp db import` handles filenames containing semicolons and client directives
Given a WP install
And a prefix.sql;\!touch_side_effect.sql#.sql file:
"""
CREATE TABLE wp_cli_meta_test (id int NOT NULL);
INSERT INTO wp_cli_meta_test (id) VALUES (42);
"""

When I run `wp db import 'prefix.sql;\!touch_side_effect.sql#.sql'`
Then STDOUT should contain:
"""
Success: Imported from 'prefix.sql;\!touch_side_effect.sql#.sql'.
"""
And the side_effect.sql file should not exist
Comment thread
coderabbitai[bot] marked this conversation as resolved.

When I run `wp db query 'SELECT id FROM wp_cli_meta_test;' --skip-column-names`
Then STDOUT should be:
"""
42
"""

@require-mysql-or-mariadb
Scenario: `wp db import` does not execute embedded client meta-commands in dump content
Given a WP install
And a dump_with_command_injection.sql file:
"""
CREATE TABLE wp_cli_meta_content_test (id int NOT NULL);
INSERT INTO wp_cli_meta_content_test (id) VALUES (99);
\! touch side_effect_content.sql
"""

When I try `wp db import dump_with_command_injection.sql`
Then the side_effect_content.sql file should not exist

31 changes: 22 additions & 9 deletions src/DB_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -926,7 +926,7 @@ private function command_supports_option( $command, $option ) {
* : Extra arguments to pass to mysql. [Refer to mysql binary docs](https://dev.mysql.com/doc/refman/8.0/en/mysql-command-options.html).
*
* [--skip-optimization]
* : When using an SQL file, do not include speed optimization such as disabling auto-commit and key checks.
* : Do not disable unique checks and foreign key checks during import.
*
* [--skip-sql-mode-compat]
* : Do not adapt the session SQL mode for WordPress compatibility. By default, `wp db import` strips the SQL modes that WordPress Core disables (such as `STRICT_TRANS_TABLES` and `NO_ZERO_DATE`) so that dumps containing legacy values like `0000-00-00` import cleanly. Pass this flag to import under the server's own SQL modes instead.
Expand All @@ -943,8 +943,10 @@ private function command_supports_option( $command, $option ) {
public function import( $args, $assoc_args ) {
$this->maybe_load_sqlite_dropin();

$is_stdin = false;
if ( ! empty( $args[0] ) ) {
$result_file = $args[0];
$is_stdin = '-' === $result_file;
} else {
$result_file = sprintf( '%s.sql', DB_NAME );
}
Expand All @@ -956,7 +958,10 @@ public function import( $args, $assoc_args ) {

// Process options to MySQL.
$mysql_args = array_merge(
[ 'database' => DB_NAME ],
[
'database' => DB_NAME,
'binary-mode' => true,
],
self::get_dbuser_dbpass_args( $assoc_args ),
self::get_mysql_args( $assoc_args )
);
Expand All @@ -967,25 +972,33 @@ public function import( $args, $assoc_args ) {
// no separate probe connection.
$this->apply_sql_mode_compat_init_command( $mysql_args, $assoc_args );

if ( '-' !== $result_file ) {
if ( ! $is_stdin ) {
if ( ! is_readable( $result_file ) ) {
WP_CLI::error( sprintf( 'Import file missing or not readable: %s', $result_file ) );
}

$query = Utils\get_flag_value( $assoc_args, 'skip-optimization' )
? 'SOURCE %s;'
: 'SET autocommit = 0; SET unique_checks = 0; SET foreign_key_checks = 0; SOURCE %s; COMMIT;';

$mysql_args['execute'] = sprintf( $query, $result_file );
} else {
$result_file = 'STDIN';
}

if ( ! Utils\get_flag_value( $assoc_args, 'skip-optimization' ) ) {
$optimization_sql = 'SET unique_checks = 0; SET foreign_key_checks = 0;';
if ( isset( $mysql_args['init-command'] ) && '' !== trim( (string) $mysql_args['init-command'] ) ) {
$mysql_args['init-command'] .= '; ' . $optimization_sql;
} else {
$mysql_args['init-command'] = $optimization_sql;
}
}
Comment thread
swissspidy marked this conversation as resolved.

$command = sprintf(
'%s%s --no-auto-rehash',
Utils\get_mysql_binary_path(),
$this->get_defaults_flag_string( $assoc_args )
);

if ( ! $is_stdin ) {
$command .= ' < ' . escapeshellarg( $result_file );
}

WP_CLI::debug( "Running shell command: {$command}", 'db' );
WP_CLI::debug( 'Associative arguments: ' . json_encode( $assoc_args ), 'db' );

Expand Down
Loading