Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue/147 - improve compat with PHP 8.1 and newer #152

Merged
merged 14 commits into from
Apr 5, 2024
18 changes: 12 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "stuttter/ludicrousdb",
"description": "LudicrousDB is a database class that supports replication, failover, load balancing, & partitioning, based on Automattic's HyperDB drop-in.",
"homepage": "https://github.com/stuttter/ludicrousdb",
"type": "wordpress-muplugin",
"type": "wordpress-plugin",
"license" : "GPL-2.0-or-later",
"authors": [
{
Expand All @@ -14,7 +14,7 @@
"email": "[email protected]"
}
],
"support" : {
"support": {
"issues": "https://github.com/stuttter/ludicrousdb/issues",
"source": "https://github.com/stuttter/ludicrousdb"
},
Expand All @@ -23,10 +23,10 @@
"composer/installers": "~1.0 || ~2.0"
},
"require-dev": {
"wp-coding-standards/wpcs": "^2.2",
"dealerdirect/phpcodesniffer-composer-installer": "^0.6.2",
"phpcompatibility/phpcompatibility-wp": "^2.1",
"sirbrillig/phpcs-variable-analysis": "^2.8"
"wp-coding-standards/wpcs": "*",
"dealerdirect/phpcodesniffer-composer-installer": "*",
"phpcompatibility/phpcompatibility-wp": "*",
"sirbrillig/phpcs-variable-analysis": "*"
},
"scripts": {
"format": [
Expand All @@ -35,5 +35,11 @@
"lint": [
"vendor/bin/phpcs . -v"
]
},
"config": {
"allow-plugins": {
"composer/installers": true,
"dealerdirect/phpcodesniffer-composer-installer": true
}
}
}
149 changes: 102 additions & 47 deletions ludicrousdb/includes/class-ludicrousdb.php
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ public function is_write_query( $q = '' ) {
$q = ltrim( $q, "\r\n\t (" );

// Possible writes
if ( preg_match( '/(?:^|\s)(?:ALTER|CREATE|ANALYZE|CHECK|OPTIMIZE|REPAIR|CALL|DELETE|DROP|INSERT|LOAD|REPLACE|UPDATE|SET|RENAME\s+TABLE)(?:\s|$)/i', $q ) ) {
if ( preg_match( '/(?:^|\s)(?:ALTER|CREATE|ANALYZE|CHECK|OPTIMIZE|REPAIR|CALL|DELETE|DROP|INSERT|LOAD|REPLACE|UPDATE|SET|RENAME\s+TABLE|[a-z]+_LOCKS?\()(?:\s|$)/i', $q ) ) {
return true;
}

Expand Down Expand Up @@ -456,7 +456,7 @@ public function run_callbacks( $group, $args = null ) {
}

/**
* Figure out which db server should handle the query, and connect to it
* Figure out which db server should handle the query, and connect to it.
*
* @since 1.0.0
*
Expand All @@ -471,7 +471,13 @@ public function db_connect( $query = '' ) {
return false;
}

// can be empty/false if the query is e.g. "COMMIT"
// Fix error reporting change (in PHP 8.1) causing fatal errors
// See: https://php.watch/versions/8.1/mysqli-error-mode
if ( true === $this->use_mysqli ) {
mysqli_report( MYSQLI_REPORT_OFF );
}

// Can be empty/false if the query is e.g. "COMMIT"
$this->table = $this->get_table_from_query( $query );
if ( empty( $this->table ) ) {
$this->table = 'no-table';
Expand Down Expand Up @@ -914,8 +920,8 @@ protected function single_db_connect( $dbhname, $host, $user, $password ) {

// 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 = null;
$socket = null;
$port = 0;
$socket = '';
$port_or_socket = strstr( $host, ':' );

if ( ! empty( $port_or_socket ) ) {
Expand Down Expand Up @@ -943,7 +949,7 @@ protected function single_db_connect( $dbhname, $host, $user, $password ) {
$pre_host = 'p:';
}

mysqli_real_connect( $this->dbhs[ $dbhname ], $pre_host . $host, $user, $password, null, $port, $socket, $client_flags );
mysqli_real_connect( $this->dbhs[ $dbhname ], $pre_host . $host, $user, $password, '', $port, $socket, $client_flags );

if ( $this->dbhs[ $dbhname ]->connect_errno ) {
$this->dbhs[ $dbhname ] = false;
Expand All @@ -962,15 +968,19 @@ protected function single_db_connect( $dbhname, $host, $user, $password ) {
}

/**
* Change the current SQL mode, and ensure its WordPress compatibility
* Change the current SQL mode, and ensure its WordPress compatibility.
*
* If no modes are passed, it will ensure the current MySQL server
* modes are compatible
* modes are compatible.
*
* @since 1.0.0
*
* @param array $modes Optional. A list of SQL modes to set.
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param array $modes Optional. A list of SQL modes to set.
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
* @return void
*/
public function set_sql_mode( $modes = array(), $dbh_or_table = false ) {
$dbh = $this->get_db_object( $dbh_or_table );
Expand All @@ -990,13 +1000,15 @@ public function set_sql_mode( $modes = array(), $dbh_or_table = false ) {
return;
}

$modes_str = '';

if ( true === $this->use_mysqli ) {
$modes_array = mysqli_fetch_array( $res );
if ( empty( $modes_array[0] ) ) {
return;
}
$modes_str = $modes_array[0];
} else {
} elseif ( function_exists( 'mysql_result' ) ) {
$modes_str = mysql_result( $res, 0 );
}

Expand Down Expand Up @@ -1031,15 +1043,18 @@ public function set_sql_mode( $modes = array(), $dbh_or_table = false ) {
}

/**
* Selects a database using the current database connection
* 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
* connection. On failure, the execution will bail and display an DB error.
*
* @since 1.0.0
*
* @param string $db MySQL database name
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param string $db MySQL database name.
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*/
public function select( $db, $dbh_or_table = false ) {
$dbh = $this->get_db_object( $dbh_or_table );
Expand Down Expand Up @@ -1101,6 +1116,11 @@ protected function load_col_info() {
*/
public function _real_escape( $string ) { // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore

// Bail if not a scalar
if ( ! is_scalar( $string ) ) {
return '';
}

// Slash the query part
$escaped = addslashes( $string );

Expand All @@ -1117,35 +1137,47 @@ public function _real_escape( $string ) { // phpcs:ignore PSR2.Methods.MethodDec
*
* @since 1.0.0
*
* @param resource $dbh The resource given by mysql_connect
* @param string $charset The character set (optional)
* @param string $collate The collation (optional)
* @param mysqli|resource $dbh The resource given by mysqli_connect
* @param string $charset Optional. The character set.
* @param string $collate Optional. The collation.
*/
public function set_charset( $dbh, $charset = null, $collate = null ) {
if ( ! isset( $charset ) ) {
$charset = $this->charset;
}

if ( ! isset( $collate ) ) {
$collate = $this->collate;
}

if ( empty( $charset ) || empty( $collate ) ) {
wp_die( "{$charset} {$collate}" );
}
if ( ! in_array( strtolower( $charset ), array( 'utf8', 'utf8mb4', 'latin1' ), true ) ) {

$allowed = array( 'utf8', 'utf8mb4', 'latin1' );

if ( ! in_array( strtolower( $charset ), $allowed, true ) ) {
wp_die( "{$charset} charset isn't supported in LudicrousDB for security reasons" );
}
if ( $this->has_cap( 'collation', $dbh ) && ! empty( $charset ) ) {

if ( ! empty( $charset ) && $this->has_cap( 'collation', $dbh ) ) {
$set_charset_succeeded = true;
if ( ( true === $this->use_mysqli ) && function_exists( 'mysqli_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
$set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
} elseif ( function_exists( 'mysql_set_charset' ) && $this->has_cap( 'set_charset', $dbh ) ) {
$set_charset_succeeded = mysql_set_charset( $charset, $dbh );

if ( $this->has_cap( 'set_charset', $dbh ) ) {
if ( ( true === $this->use_mysqli ) && function_exists( 'mysqli_set_charset' ) ) {
$set_charset_succeeded = mysqli_set_charset( $dbh, $charset );
} elseif ( function_exists( 'mysql_set_charset' ) ) {
$set_charset_succeeded = mysql_set_charset( $charset, $dbh );
}
}
if ( $set_charset_succeeded ) {

if ( true === $set_charset_succeeded ) {
$query = $this->prepare( 'SET NAMES %s', $charset );

if ( ! empty( $collate ) ) {
$query .= $this->prepare( ' COLLATE %s', $collate );
}

$this->_do_query( $query, $dbh );
}
}
Expand Down Expand Up @@ -1543,13 +1575,16 @@ protected function _do_query( $query, $dbh_or_table = false ) { // phpcs:ignore
}

/**
* Closes the current database connection
* Closes the current database connection.
*
* @since 1.0.0
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return bool True if the connection was successfully closed, false if it wasn't,
* @return bool True if the connection was successfully closed. False if it wasn't
* or the connection doesn't exist.
*/
public function close( $dbh_or_table = false ) {
Expand All @@ -1574,14 +1609,17 @@ public function close( $dbh_or_table = false ) {

/**
* Whether or not MySQL database is at least the required minimum version.
* The additional argument allows the caller to check a specific database
* The additional argument allows the caller to check a specific database.
*
* @since 1.0.0
*
* @global $wp_version
* @global $required_mysql_version
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return WP_Error
*/
Expand All @@ -1597,14 +1635,18 @@ public function check_database_version( $dbh_or_table = false ) {
}

/**
* This function is called when WordPress is generating the table schema to determine whether or not the current database
* supports or needs the collation statements
* This function is called when WordPress is generating the table schema to
* determine whether or not the current database supports or needs the
* collation statements.
*
* The additional argument allows the caller to check a specific database
* The additional argument allows the caller to check a specific database.
*
* @since 1.0.0
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return bool
*/
Expand All @@ -1615,13 +1657,16 @@ public function supports_collation( $dbh_or_table = false ) {
}

/**
* Generic function to determine if a database supports a particular feature
* The additional argument allows the caller to check a specific database
* Generic function to determine if a database supports a particular feature.
* The additional argument allows the caller to check a specific database.
*
* @since 1.0.0
*
* @param string $db_cap the feature
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param string $db_cap The feature.
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return bool
*/
Expand Down Expand Up @@ -1686,13 +1731,16 @@ public function get_caller() {
}

/**
* The database version number
* The database version number.
*
* @since 1.0.0
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return false|string false on failure, version number on success
* @return false|string False on failure. Version number on success.
*/
public function db_version( $dbh_or_table = false ) {
return preg_replace( '/[^0-9.].*/', '', $this->db_server_info( $dbh_or_table ) );
Expand All @@ -1703,7 +1751,10 @@ public function db_version( $dbh_or_table = false ) {
*
* @since 5.0.0
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
*
* @return string|false Server info on success, false on failure.
*/
Expand All @@ -1726,7 +1777,11 @@ public function db_server_info( $dbh_or_table = false ) {
*
* @since 1.0.0
*
* @param false|string|resource $dbh_or_table the database (the current database, the database housing the specified table, or the database of the MySQL resource)
* @param false|string|mysqli|resource $dbh_or_table Optional. The database. One of:
* - the current database
* - the database housing the specified table
* - the database of the MySQL resource
* @return false|mysqli|resource
*/
private function get_db_object( $dbh_or_table = false ) {

Expand All @@ -1737,11 +1792,11 @@ private function get_db_object( $dbh_or_table = false ) {
if ( $this->dbh_type_check( $dbh_or_table ) ) {
$dbh = &$dbh_or_table;

// Database
// Database
} elseif ( ( false === $dbh_or_table ) && $this->dbh_type_check( $this->dbh ) ) {
$dbh = &$this->dbh;

// Table name
// Table name
} elseif ( is_string( $dbh_or_table ) ) {
$dbh = $this->db_connect( "SELECT FROM {$dbh_or_table} {$this->users}" );
}
Expand All @@ -1752,10 +1807,10 @@ private function get_db_object( $dbh_or_table = false ) {
/**
* Check database object type.
*
* @param resource|mysqli $dbh Database resource.
*
* @since 1.0.0
*
* @param mysqli|resource $dbh Database resource.
*
* @return bool
*/
private function dbh_type_check( $dbh ) {
Expand Down