Skip to content

Commit 6414ec5

Browse files
Copilotswissspidy
andauthored
Replace maybe_load_wpdb() with direct mysqli in wpdb_query() and wpdb_import()
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
1 parent 23355d6 commit 6414ec5

1 file changed

Lines changed: 77 additions & 136 deletions

File tree

src/DB_Command.php

Lines changed: 77 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,6 @@ public function query( $args, $assoc_args ) {
606606
}
607607

608608
WP_CLI::debug( 'MySQL/MariaDB binary not available, falling back to wpdb.', 'db' );
609-
$this->maybe_load_wpdb();
610609
$this->wpdb_query( $query, $assoc_args );
611610
return;
612611
}
@@ -958,7 +957,6 @@ public function import( $args, $assoc_args ) {
958957
}
959958

960959
WP_CLI::debug( 'MySQL/MariaDB binary not available, falling back to wpdb for import.', 'db' );
961-
$this->maybe_load_wpdb();
962960
$this->wpdb_import( (string) $sql_content, $assoc_args );
963961
WP_CLI::success( sprintf( "Imported from '%s'.", $result_file ) );
964962
return;
@@ -1969,37 +1967,8 @@ private static function get_create_query() {
19691967
* @param string $query SQL query to execute.
19701968
*/
19711969
protected function run_query_via_mysqli( $query ) {
1972-
$db_host = DB_HOST;
1973-
$port = null;
1974-
$socket = null;
1975-
1976-
if ( ':' === substr( $db_host, 0, 1 ) ) {
1977-
$socket = substr( $db_host, 1 );
1978-
$db_host = 'localhost';
1979-
} else {
1980-
$parts = explode( ':', $db_host, 2 );
1981-
$db_host = $parts[0];
1982-
if ( isset( $parts[1] ) ) {
1983-
$port_or_socket = trim( $parts[1] );
1984-
if ( '' !== $port_or_socket && '/' === $port_or_socket[0] ) {
1985-
$socket = $port_or_socket;
1986-
} elseif ( '' !== $port_or_socket ) {
1987-
$port = (int) $port_or_socket;
1988-
}
1989-
}
1990-
}
1991-
1992-
// When using a socket, pass 0 for port. When a port is explicitly set, use it; otherwise use the default.
1993-
$port_value = null !== $port ? $port : 0;
1994-
$socket_value = null !== $socket ? $socket : '';
1995-
1996-
// No database is selected intentionally — DDL operations like DROP/CREATE DATABASE work at the server level.
1997-
// phpcs:ignore WordPress.DB.RestrictedClasses.mysql__mysqli -- direct mysqli required as wpdb fallback when mysql binary is unavailable.
1998-
$conn = new mysqli( $db_host, DB_USER, DB_PASSWORD, '', $port_value, $socket_value );
1999-
2000-
if ( $conn->connect_errno ) {
2001-
WP_CLI::error( sprintf( 'Failed to connect to the database: %s', $conn->connect_error ) );
2002-
}
1970+
// No database selected — DDL operations like DROP/CREATE DATABASE work at the server level.
1971+
$conn = $this->get_db_connection( false );
20031972

20041973
if ( ! $conn->query( $query ) ) {
20051974
$error = $conn->error;
@@ -2507,140 +2476,116 @@ protected function is_mysql_binary_available() {
25072476
}
25082477

25092478
/**
2510-
* Load WordPress's wpdb if not already available.
2479+
* Open a mysqli connection using the WordPress database credentials.
2480+
*
2481+
* Used as a fallback when the mysql/mariadb binary is not available.
2482+
* Parses DB_HOST the same way WordPress does (host:port, host:/socket, :/socket).
25112483
*
2512-
* Loads the minimal required WordPress files to make $wpdb available,
2513-
* including any db.php drop-in (e.g., HyperDB or other custom drivers).
2484+
* @param bool $select_db Whether to select DB_NAME on connect. Pass false for
2485+
* server-level DDL (DROP/CREATE DATABASE).
2486+
* @return mysqli Connected mysqli instance. Calls WP_CLI::error() on failure.
25142487
*/
2515-
protected function maybe_load_wpdb() {
2516-
global $wpdb;
2517-
2518-
if ( isset( $wpdb ) ) {
2519-
return;
2520-
}
2521-
2522-
if ( ! defined( 'WPINC' ) ) {
2523-
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound
2524-
define( 'WPINC', 'wp-includes' );
2525-
}
2526-
2527-
if ( ! defined( 'WP_CONTENT_DIR' ) ) {
2528-
define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' );
2529-
}
2488+
protected function get_db_connection( $select_db = true ) {
2489+
$db_host = DB_HOST;
2490+
$port = null;
2491+
$socket = null;
25302492

2531-
// Load prerequisite files if not already loaded.
2532-
if ( ! function_exists( 'add_action' ) ) {
2533-
foreach ( [ 'load.php', 'compat.php', 'plugin.php' ] as $file ) {
2534-
$path = ABSPATH . WPINC . '/' . $file;
2535-
if ( file_exists( $path ) ) {
2536-
require_once $path;
2493+
if ( ':' === substr( $db_host, 0, 1 ) ) {
2494+
$socket = substr( $db_host, 1 );
2495+
$db_host = 'localhost';
2496+
} else {
2497+
$parts = explode( ':', $db_host, 2 );
2498+
$db_host = $parts[0];
2499+
if ( isset( $parts[1] ) ) {
2500+
$port_or_socket = trim( $parts[1] );
2501+
if ( '' !== $port_or_socket && '/' === $port_or_socket[0] ) {
2502+
$socket = $port_or_socket;
2503+
} elseif ( '' !== $port_or_socket ) {
2504+
$port = (int) $port_or_socket;
25372505
}
25382506
}
25392507
}
25402508

2541-
// Load class-wpdb.php if the wpdb class is not yet available.
2542-
// This is checked independently of add_action, since WP-CLI's config loading
2543-
// may have already loaded plugin.php (defining add_action) without loading wpdb.
2544-
if ( ! class_exists( 'wpdb' ) ) {
2545-
// Defines `wp_debug_backtrace_summary()` as used by wpdb.
2546-
if ( ! function_exists( 'wp_debug_backtrace_summary' ) ) {
2547-
$functions_file = ABSPATH . WPINC . '/functions.php';
2548-
if ( file_exists( $functions_file ) ) {
2549-
require_once $functions_file;
2550-
}
2551-
}
2509+
$port_value = null !== $port ? $port : 0;
2510+
$socket_value = null !== $socket ? $socket : '';
2511+
$database = $select_db ? DB_NAME : '';
25522512

2553-
$wpdb_file = ABSPATH . WPINC . '/class-wpdb.php';
2554-
if ( file_exists( $wpdb_file ) ) {
2555-
require_once $wpdb_file;
2556-
}
2557-
}
2513+
// phpcs:ignore WordPress.DB.RestrictedClasses.mysql__mysqli -- direct mysqli required as fallback when mysql binary is unavailable.
2514+
$conn = new mysqli( $db_host, DB_USER, DB_PASSWORD, $database, $port_value, $socket_value );
25582515

2559-
// Load db.php drop-in if it exists (e.g., HyperDB or other custom drivers).
2560-
$db_dropin_path = WP_CONTENT_DIR . '/db.php';
2561-
if ( file_exists( $db_dropin_path ) && ! $this->is_sqlite() ) {
2562-
require_once $db_dropin_path;
2516+
if ( $conn->connect_errno ) {
2517+
WP_CLI::error( sprintf( 'Failed to connect to the database: %s', $conn->connect_error ) );
25632518
}
25642519

2565-
// If $wpdb is still not set (e.g. no drop-in), create a new instance using the DB credentials from wp-config.php.
2566-
if ( ! isset( $GLOBALS['wpdb'] ) && class_exists( 'wpdb' ) ) {
2567-
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
2568-
$wpdb = new wpdb( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST );
2569-
if ( isset( $GLOBALS['table_prefix'] ) && is_string( $GLOBALS['table_prefix'] ) ) {
2570-
$wpdb->set_prefix( $GLOBALS['table_prefix'] );
2571-
}
2572-
}
2520+
return $conn;
25732521
}
25742522

25752523
/**
2576-
* Execute a query against the database using wpdb.
2524+
* Execute a query against the database using mysqli.
25772525
*
25782526
* Used as a fallback when the mysql/mariadb binary is not available.
2527+
* Outputs results in the same tab-separated format as the mysql binary.
25792528
*
25802529
* @param string $query SQL query to execute.
25812530
* @param array $assoc_args Associative arguments.
25822531
*/
25832532
protected function wpdb_query( $query, $assoc_args = [] ) {
2584-
global $wpdb;
2585-
2586-
if ( ! isset( $wpdb ) || ! ( $wpdb instanceof wpdb ) ) {
2587-
WP_CLI::error( 'WordPress database (wpdb) is not available. Please install MySQL or MariaDB client tools.' );
2588-
}
2533+
$conn = $this->get_db_connection();
25892534

2590-
$skip_column_names = Utils\get_flag_value( $assoc_args, 'skip-column-names', false );
2591-
2592-
$is_row_modifying_query = preg_match( '/\b(UPDATE|DELETE|INSERT|REPLACE(?!\s*\()|LOAD DATA)\b/i', $query );
2535+
$skip_column_names = Utils\get_flag_value( $assoc_args, 'skip-column-names', false );
2536+
$is_row_modifying_query = (bool) preg_match( '/\b(UPDATE|DELETE|INSERT|REPLACE(?!\s*\()|LOAD DATA)\b/i', $query );
25932537

25942538
if ( $is_row_modifying_query ) {
2595-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2596-
$affected_rows = $wpdb->query( $query );
2597-
if ( false === $affected_rows ) {
2598-
// phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
2599-
WP_CLI::error( 'Query failed: ' . strip_tags( $wpdb->last_error ) );
2539+
if ( ! $conn->query( $query ) ) {
2540+
$error = $conn->error;
2541+
$conn->close();
2542+
WP_CLI::error( "Query failed: {$error}" );
26002543
}
2544+
$affected_rows = $conn->affected_rows;
2545+
$conn->close();
26012546
WP_CLI::success( "Query succeeded. Rows affected: {$affected_rows}" );
26022547
} else {
2603-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2604-
$results = $wpdb->get_results( $query, ARRAY_A );
2605-
2606-
if ( $wpdb->last_error ) {
2607-
// phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
2608-
WP_CLI::error( 'Query failed: ' . strip_tags( $wpdb->last_error ) );
2548+
$result = $conn->query( $query );
2549+
if ( ! $result ) {
2550+
$error = $conn->error;
2551+
$conn->close();
2552+
WP_CLI::error( "Query failed: {$error}" );
26092553
}
26102554

2611-
if ( empty( $results ) ) {
2612-
return;
2555+
if ( $result instanceof mysqli_result ) {
2556+
$fields = $result->fetch_fields();
2557+
$headers = $fields ? array_column( (array) $fields, 'name' ) : [];
2558+
if ( ! $skip_column_names && ! empty( $headers ) ) {
2559+
WP_CLI::line( implode( "\t", $headers ) );
2560+
}
2561+
$all_rows = $result->fetch_all( MYSQLI_NUM );
2562+
foreach ( $all_rows as $row ) {
2563+
WP_CLI::line( implode( "\t", array_map( 'strval', $row ) ) );
2564+
}
2565+
$result->free();
26132566
}
26142567

2615-
$headers = array_keys( $results[0] );
2616-
$this->display_query_results( $headers, $results, $skip_column_names );
2568+
$conn->close();
26172569
}
26182570
}
26192571

26202572
/**
2621-
* Import SQL content into the database using wpdb.
2573+
* Import SQL content into the database using mysqli.
26222574
*
26232575
* Used as a fallback when the mysql/mariadb binary is not available.
26242576
*
26252577
* @param string $sql_content SQL content to import.
26262578
* @param array $assoc_args Associative arguments.
26272579
*/
26282580
protected function wpdb_import( $sql_content, $assoc_args = [] ) {
2629-
global $wpdb;
2630-
2631-
if ( ! isset( $wpdb ) || ! ( $wpdb instanceof wpdb ) ) {
2632-
WP_CLI::error( 'WordPress database (wpdb) is not available. Please install MySQL or MariaDB client tools.' );
2633-
}
2581+
$conn = $this->get_db_connection();
26342582

26352583
$skip_optimization = Utils\get_flag_value( $assoc_args, 'skip-optimization', false );
26362584

26372585
if ( ! $skip_optimization ) {
2638-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2639-
$wpdb->query( 'SET autocommit = 0' );
2640-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2641-
$wpdb->query( 'SET unique_checks = 0' );
2642-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2643-
$wpdb->query( 'SET foreign_key_checks = 0' );
2586+
$conn->query( 'SET autocommit = 0' );
2587+
$conn->query( 'SET unique_checks = 0' );
2588+
$conn->query( 'SET foreign_key_checks = 0' );
26442589
}
26452590

26462591
$statements = $this->split_sql_statements( $sql_content );
@@ -2650,28 +2595,24 @@ protected function wpdb_import( $sql_content, $assoc_args = [] ) {
26502595
if ( '' === $statement ) {
26512596
continue;
26522597
}
2653-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2654-
$result = $wpdb->query( $statement );
2655-
if ( false === $result ) {
2598+
if ( ! $conn->query( $statement ) ) {
2599+
$error = $conn->error;
26562600
if ( ! $skip_optimization ) {
2657-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2658-
$wpdb->query( 'ROLLBACK' );
2601+
$conn->query( 'ROLLBACK' );
26592602
}
2660-
// phpcs:ignore WordPress.WP.AlternativeFunctions.strip_tags_strip_tags
2661-
WP_CLI::error( 'Import failed: ' . strip_tags( $wpdb->last_error ) );
2603+
$conn->close();
2604+
WP_CLI::error( "Import failed: {$error}" );
26622605
}
26632606
}
26642607

26652608
if ( ! $skip_optimization ) {
2666-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2667-
$wpdb->query( 'COMMIT' );
2668-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2669-
$wpdb->query( 'SET autocommit = 1' );
2670-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2671-
$wpdb->query( 'SET unique_checks = 1' );
2672-
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
2673-
$wpdb->query( 'SET foreign_key_checks = 1' );
2609+
$conn->query( 'COMMIT' );
2610+
$conn->query( 'SET autocommit = 1' );
2611+
$conn->query( 'SET unique_checks = 1' );
2612+
$conn->query( 'SET foreign_key_checks = 1' );
26742613
}
2614+
2615+
$conn->close();
26752616
}
26762617

26772618
/**

0 commit comments

Comments
 (0)