show_errors(); } if ( function_exists( 'mysqli_connect' ) ) { if ( defined( 'WP_USE_EXT_MYSQL' ) ) { $this->use_mysqli = ! \WP_USE_EXT_MYSQL; } elseif ( version_compare( phpversion(), '5.5', '>=' ) || ! function_exists( 'mysql_connect' ) ) { $this->use_mysqli = true; } elseif ( false !== strpos( $GLOBALS['wp_version'], '-' ) ) { $this->use_mysqli = true; } } $this->dbuser = $dbuser; $this->dbpassword = $dbpassword; $this->dbname = $dbname; $this->dbhost = $dbhost; $this->dbport = $dbport ?? false; // wp-config.php creation will manually connect when ready. if ( defined( 'WP_SETUP_CONFIG' ) ) { return; } if ( $is_ssl && ! defined( 'MYSQL_CLIENT_FLAGS' ) ) { define( 'MYSQL_CLIENT_FLAGS', MYSQLI_CLIENT_SSL | MYSQLI_CLIENT_SSL_DONT_VERIFY_SERVER_CERT ); } if ( $is_cc ) { if ( ! empty( $ssl_key ) && is_file( $ssl_key ) && ! defined( 'MYSQL_SSL_KEY' ) ) { define( 'MYSQL_SSL_KEY', $ssl_key ); } if ( ! empty( $ssl_cert ) && is_file( $ssl_cert ) && ! defined( 'MYSQL_SSL_CERT' ) ) { define( 'MYSQL_SSL_CERT', $ssl_cert ); } if ( ! empty( $ssl_ca ) && is_file( $ssl_ca ) && ! defined( 'MYSQL_SSL_CA' ) ) { define( 'MYSQL_SSL_CA', $ssl_ca ); } } $this->db_connect( false ); } /** * Return an array with the Port and the Socket values for the MySQL connection. * * @return array - an array with the port and socket values. * * @since 5.5.0 */ private function get_port_and_socket() { $port = null; $socket = null; $host = $this->dbhost; // Check if host contains a colon (old WSAL format was: IP:PORT or IP:/socket). $port_or_socket = strstr( $host, ':' ); if ( ! empty( $this->dbport ) ) { // Prefer explicit port if provided. if ( is_numeric( $this->dbport ) ) { $port = intval( $this->dbport ); } elseif ( strpos( $this->dbport, '/' ) === 0 ) { $socket = $this->dbport; } // Remove port/socket from host if present. if ( ! empty( $port_or_socket ) ) { $host = substr( $host, 0, strpos( $host, ':' ) ); } } elseif ( ! empty( $port_or_socket ) ) { // Host contains :PORT or :/socket. $host_part = substr( $host, 0, strpos( $host, ':' ) ); $extra = substr( $port_or_socket, 1 ); $host = $host_part; if ( strpos( $extra, '/' ) === 0 ) { // If this is a socket path. $socket = $extra; } elseif ( is_numeric( $extra ) ) { // If it's a port number. $port = intval( $extra ); } else { // Rare case: port:socket (e.g., 3306:/tmp/mysql.sock). $parts = explode( ':', $extra, 2 ); if ( is_numeric( $parts[0] ) ) { $port = intval( $parts[0] ); } if ( isset( $parts[1] ) && strpos( $parts[1], '/' ) === 0 ) { $socket = $parts[1]; } } } return array( 'port' => $port, 'socket' => $socket, ); } /** * Connect to and select database. * * If $allow_bail is false, the lack of database connection will need * to be handled manually. * * @param bool $allow_bail Optional. Allows the function to bail. Default true. * * @return bool True with a successful connection, false on failure. * @since 3.0.0 * @since 3.9.0 $allow_bail parameter added. */ public function db_connect( $allow_bail = true ) { $this->is_mysql = true; $client_flags = defined( 'MYSQL_CLIENT_FLAGS' ) ? MYSQL_CLIENT_FLAGS : 0; if ( $this->use_mysqli ) { /* * Set the MySQLi error reporting off because WordPress handles its own. * This is due to the default value change from `MYSQLI_REPORT_OFF` * to `MYSQLI_REPORT_ERROR|MYSQLI_REPORT_STRICT` in PHP 8.1. */ mysqli_report( MYSQLI_REPORT_OFF ); // phpcs:ignore -- Direct DB access $this->dbh = mysqli_init(); // phpcs:ignore // mysqli_real_connect doesn't support the host param including a port or socket // like mysql_connect does. This duplicates how mysql_connect detects a port and/or socket file. $port_and_socket = $this->get_port_and_socket(); $port = $port_and_socket['port'] ?? null; $socket = $port_and_socket['socket'] ?? null; $host = $this->dbhost; // Set SSL certs if we want to use secure DB connections. $ssl_opts = array( 'KEY' => ( defined( 'MYSQL_SSL_KEY' ) && is_file( MYSQL_SSL_KEY ) ) ? MYSQL_SSL_KEY : null, 'CERT' => ( defined( 'MYSQL_SSL_CERT' ) && is_file( MYSQL_SSL_CERT ) ) ? MYSQL_SSL_CERT : null, 'CA' => ( defined( 'MYSQL_SSL_CA' ) && is_file( MYSQL_SSL_CA ) ) ? MYSQL_SSL_CA : null, 'CA_PATH' => ( defined( 'MYSQL_SSL_CA_PATH' ) && is_dir( \MYSQL_SSL_CA_PATH ) ) ? \MYSQL_SSL_CA_PATH : null, 'CIPHER' => ( defined( 'MYSQL_SSL_CIPHER' ) ) ? \MYSQL_SSL_CIPHER : null, ); $ssl_opts_set = false; foreach ( $ssl_opts as $ssl_opt_val ) { if ( ! is_null( $ssl_opt_val ) ) { $ssl_opts_set = true; break; } } if ( MYSQLI_CLIENT_SSL !== ( $client_flags & MYSQLI_CLIENT_SSL ) ) { $ssl_opts_set = false; } if ( $ssl_opts_set ) { mysqli_ssl_set( // phpcs:ignore $this->dbh, $ssl_opts['KEY'], $ssl_opts['CERT'], $ssl_opts['CA'], $ssl_opts['CA_PATH'], $ssl_opts['CIPHER'] ); } if ( WP_DEBUG ) { mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); // phpcs:ignore } else { @mysqli_real_connect( $this->dbh, $host, $this->dbuser, $this->dbpassword, null, $port, $socket, $client_flags ); // phpcs:ignore } if ( $this->dbh->connect_errno ) { if ( 2002 === (int) $this->dbh->connect_errno ) { self::$error_string = __( 'The plugin detected connectivity issues coming from your external database connection. Please check the status of your external database connection and try again!', 'wp-security-audit-log' ); } } if ( $this->dbh->connect_errno ) { $this->dbh = null; /** * It's possible ext/mysqli is misconfigured. Fall back to ext/mysql if: * - We haven't previously connected, and * - WP_USE_EXT_MYSQL isn't set to false, and * - ext/mysql is loaded. */ $attempt_fallback = true; if ( $this->has_connected || ( defined( 'WP_USE_EXT_MYSQL' ) && ! \WP_USE_EXT_MYSQL ) || ( ! function_exists( 'mysql_connect' ) ) ) { $attempt_fallback = false; } if ( $attempt_fallback ) { $this->use_mysqli = false; return $this->db_connect( $allow_bail ); } } } if ( ! $this->dbh && $allow_bail ) { return false; } elseif ( $this->dbh ) { if ( ! $this->has_connected ) { $this->init_charset(); } $this->has_connected = true; $this->set_charset( $this->dbh ); $this->ready = true; $this->set_sql_mode(); $this->select( $this->dbname, $this->dbh ); return true; } return false; } /** * Selects a database using the current database connection. * * The database name will be changed based on the current database * connection. On failure, the execution will bail and display an DB error. * * @since 0.71 * * @param string $db MySQL database name. * @param resource|null $dbh Optional link identifier. */ public function select( $db, $dbh = null ) { if ( is_null( $dbh ) ) { $dbh = $this->dbh; } if ( $this->use_mysqli ) { $success = mysqli_select_db( $dbh, $db ); // phpcs:ignore } else { $success = mysql_select_db( $db, $dbh ); // phpcs:ignore } if ( ! $success ) { $this->ready = false; $this->db_select_error = true; } } } }