446 lines
12 KiB
PHP
446 lines
12 KiB
PHP
<?php
|
|
/**
|
|
* MainWP Database Controller
|
|
*
|
|
* This file handles all interactions with the DB.
|
|
*
|
|
* @package MainWP/Dashboard
|
|
*/
|
|
|
|
namespace MainWP\Dashboard;
|
|
|
|
/**
|
|
* Class MainWP_DB_Base
|
|
*
|
|
* @package MainWP\Dashboard
|
|
*/
|
|
class MainWP_DB_Base { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
|
|
|
|
// phpcs:disable WordPress.DB.RestrictedFunctions, WordPress.DB.PreparedSQL.NotPrepared -- unprepared SQL ok, accessing the database directly to custom database functions.
|
|
|
|
/**
|
|
* Private static instance.
|
|
*
|
|
* @static
|
|
* @var $instance MainWP_DB_Base.
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Table prefix.
|
|
*
|
|
* @var string $table_prefix
|
|
*/
|
|
protected $table_prefix;
|
|
|
|
/**
|
|
* WordPress Database.
|
|
*
|
|
* @var mixed $wpdb WordPress Database.
|
|
*/
|
|
protected $wpdb;
|
|
|
|
/**
|
|
* MainWP_DB_Base constructor.
|
|
*
|
|
* Run each time the class is called.
|
|
*/
|
|
public function __construct() {
|
|
|
|
self::$instance = $this;
|
|
|
|
/**
|
|
* WordPress Database.
|
|
*
|
|
* @var mixed $wpdb Global WordPress Database.
|
|
*/
|
|
global $wpdb;
|
|
|
|
$this->wpdb = &$wpdb;
|
|
$this->table_prefix = $wpdb->prefix . 'mainwp_';
|
|
}
|
|
|
|
/**
|
|
* Method test_connection()
|
|
*
|
|
* Test db connection.
|
|
*
|
|
* @uses \MainWP\Dashboard\MainWP_Logger::info()
|
|
*/
|
|
protected function test_connection() {
|
|
if ( ! static::ping( $this->wpdb->dbh ) ) {
|
|
MainWP_Logger::instance()->info( esc_html__( 'Trying to reconnect WordPress database connection...', 'mainwp' ) );
|
|
$this->wpdb->db_connect();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method table_name()
|
|
*
|
|
* Create entire table name.
|
|
*
|
|
* @param mixed $suffix Table suffix.
|
|
* @param null $tablePrefix Table prefix.
|
|
*
|
|
* @return string Table name.
|
|
*/
|
|
protected function table_name( $suffix, $tablePrefix = null ) {
|
|
return ( null === $tablePrefix ? $this->table_prefix : $tablePrefix ) . $suffix;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method get_table_name()
|
|
*
|
|
* Create entire table name.
|
|
*
|
|
* @param mixed $suffix Table suffix.
|
|
*
|
|
* @return string Table name.
|
|
*/
|
|
public function get_table_name( $suffix ) {
|
|
return $this->table_name( $suffix );
|
|
}
|
|
|
|
/**
|
|
* Method get_my_sql_version()
|
|
*
|
|
* Get MySQL Version.
|
|
*
|
|
* @return mixed MySQL vresion.
|
|
*/
|
|
public function get_my_sql_version() {
|
|
return $this->wpdb->get_var( 'SHOW VARIABLES LIKE "version"', 1 );
|
|
}
|
|
|
|
/**
|
|
* Method get_var_field()
|
|
*
|
|
* Execute a SQL query and return a single variable.
|
|
* This is a low-level wrapper for WPDB that expects SQL to be safely pre-constructed by callers.
|
|
* Callers must ensure all dynamic values are either validated primitives or safely escaped.
|
|
* See usage in get_sql_*() methods which construct safe SQL using whitelisted operations.
|
|
*
|
|
* @param string $sql Safe SQL query string. Must be pre-constructed safely by caller.
|
|
*
|
|
* @return mixed Database query result or null.
|
|
*/
|
|
public function get_var_field( $sql ) {
|
|
if ( null === $sql ) {
|
|
return null;
|
|
}
|
|
// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- $sql is safe by contract; callers construct via get_sql_*() methods with validated/escaped values. All call sites verified in mainwp-db.php.
|
|
return $this->wpdb->get_var( $sql );
|
|
}
|
|
|
|
/**
|
|
* Method get_row_result()
|
|
*
|
|
* Execute a SQL query and return a single row result.
|
|
* This is a low-level wrapper for WPDB that expects SQL to be safely pre-constructed by callers.
|
|
* Callers must ensure all dynamic values are either validated primitives or safely escaped.
|
|
* See usage in get_sql_*() methods which construct safe SQL using whitelisted operations.
|
|
*
|
|
* @param mixed $sql Safe SQL query string. Must be pre-constructed safely by caller.
|
|
* @param int $obj Return type: OBJECT or ARRAY_A (defaults to OBJECT).
|
|
*
|
|
* @return mixed Single row result or null.
|
|
*/
|
|
public function get_row_result( $sql, $obj = OBJECT ) {
|
|
if ( null === $sql ) {
|
|
return null;
|
|
}
|
|
|
|
if ( ! in_array( $obj, array( OBJECT, ARRAY_A ) ) ) {
|
|
$obj = OBJECT;
|
|
}
|
|
|
|
// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- $sql is safe by contract; callers construct via get_sql_*() methods with validated/escaped values. All call sites verified in mainwp-db.php.
|
|
return $this->wpdb->get_row( $sql, $obj );
|
|
}
|
|
|
|
/**
|
|
* Method get_results_result()
|
|
*
|
|
* Execute a SQL query and return multiple results indexed by primary key.
|
|
* This is a low-level wrapper for WPDB that expects SQL to be safely pre-constructed by callers.
|
|
* Callers must ensure all dynamic values are either validated primitives or safely escaped.
|
|
* See usage in get_sql_*() methods which construct safe SQL using whitelisted operations.
|
|
*
|
|
* @param mixed $sql Safe SQL query string. Must be pre-constructed safely by caller.
|
|
*
|
|
* @return mixed Array of results indexed by primary key, or null.
|
|
*/
|
|
public function get_results_result( $sql ) {
|
|
if ( null === $sql ) {
|
|
return null;
|
|
}
|
|
|
|
// phpcs:ignore PluginCheck.Security.DirectDB.UnescapedDBParameter -- $sql is safe by contract; callers construct via get_sql_*() methods with validated/escaped values. All call sites verified in mainwp-db.php.
|
|
return $this->wpdb->get_results( $sql, OBJECT_K );
|
|
}
|
|
|
|
/**
|
|
* Method query()
|
|
*
|
|
* SQL Query.
|
|
*
|
|
* @param mixed $sql SQL Query.
|
|
*
|
|
* @return mixed false|$result.
|
|
*/
|
|
public function query( $sql ) {
|
|
if ( null === $sql ) {
|
|
return false;
|
|
}
|
|
|
|
$result = static::m_query( $sql, $this->wpdb->dbh ); // NOSONAR - required.
|
|
|
|
if ( ! $result || ( empty( self::num_rows( $result ) ) ) ) { // NOSONAR - required.
|
|
return false;
|
|
}
|
|
|
|
return $result;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method get_last_query()
|
|
*
|
|
* @return string Get last query.
|
|
*/
|
|
public function get_last_query() {
|
|
return $this->wpdb->last_query;
|
|
}
|
|
|
|
|
|
/**
|
|
* Method escape_array()
|
|
*
|
|
* Escape SQL Data.
|
|
*
|
|
* @param mixed $data_arr Data array to escape.
|
|
*
|
|
* @return mixed Escapped SQL Data.
|
|
*/
|
|
public function escape_array( $data_arr ) {
|
|
if ( ! is_array( $data_arr ) || empty( $data_arr ) ) {
|
|
return false;
|
|
}
|
|
$tmp_arr = array();
|
|
foreach ( $data_arr as $dt ) {
|
|
$tmp_arr[] = $this->escape( $dt );
|
|
}
|
|
return $tmp_arr;
|
|
}
|
|
|
|
/**
|
|
* Method escape()
|
|
*
|
|
* Escape SQL Data.
|
|
*
|
|
* @param mixed $data Data to escape.
|
|
*
|
|
* @return mixed Escapped SQL Data.
|
|
*/
|
|
public function escape( $data ) {
|
|
if ( function_exists( 'esc_sql' ) ) {
|
|
return esc_sql( $data );
|
|
} else {
|
|
return $this->wpdb->escape( $data );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method use_mysqli()
|
|
*
|
|
* Use MySQLi, Support old & new versions of WordPress (3.9+).
|
|
*
|
|
* @return boolean|self false|$instance Instance of \mysqli
|
|
*/
|
|
public static function use_mysqli() {
|
|
if ( ! function_exists( '\mysqli_connect' ) ) {
|
|
return false;
|
|
}
|
|
return self::$instance->wpdb->dbh instanceof \mysqli; // NOSONAR - required.
|
|
}
|
|
|
|
/**
|
|
* Method ping()
|
|
*
|
|
* Ping MySQLi.
|
|
*
|
|
* @param mixed $link Query link.
|
|
*
|
|
* @return mixed \mysqli_ping
|
|
*/
|
|
public static function ping( $link ) {
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
if ( version_compare( phpversion(), '8.4', '<' ) ) {
|
|
return \mysqli_ping( $link );
|
|
} else {
|
|
try {
|
|
self::$instance->wpdb->query( 'DO 1' );
|
|
return true;
|
|
} catch ( \mysqli_sql_exception $e ) { // NOSONAR - ok.
|
|
// error.
|
|
return false;
|
|
}
|
|
}
|
|
} else {
|
|
return \mysql_ping( $link );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method m_query()
|
|
*
|
|
* MySQLi m_query.
|
|
*
|
|
* @param mixed $query Query params.
|
|
* @param mixed $link Query link.
|
|
*
|
|
* @return mixed \mysqli_query
|
|
*/
|
|
public static function m_query( $query, $link ) {
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
return \mysqli_query( $link, $query );
|
|
} else {
|
|
return \mysql_query( $query, $link );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method fetch_object()
|
|
*
|
|
* Fetch object.
|
|
*
|
|
* @param mixed $result Query result.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_fetch_object
|
|
*/
|
|
public static function fetch_object( $result ) {
|
|
if ( is_bool( $result ) ) {
|
|
return $result;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
return \mysqli_fetch_object( $result );
|
|
} else {
|
|
return \mysql_fetch_object( $result );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method free_result()
|
|
*
|
|
* MySQLi free result.
|
|
*
|
|
* @param mixed $result Query result.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_free_result
|
|
*/
|
|
public static function free_result( $result ) {
|
|
if ( is_bool( $result ) ) {
|
|
return $result;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
\mysqli_free_result( $result );
|
|
} else {
|
|
\mysql_free_result( $result );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method data_seek()
|
|
*
|
|
* MySQLi data seek.
|
|
*
|
|
* @param mixed $result Query result.
|
|
* @param mixed $offset Query offset.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_data_seek
|
|
*/
|
|
public static function data_seek( $result, $offset ) {
|
|
if ( is_bool( $result ) ) {
|
|
return $result;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
if ( ! ( $result instanceof \mysqli_result ) ) {
|
|
return $result;
|
|
}
|
|
return \mysqli_data_seek( $result, $offset );
|
|
} else {
|
|
return \mysql_data_seek( $result, $offset );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method fetch_array()
|
|
*
|
|
* MySQLi fetch array.
|
|
*
|
|
* @param mixed $result Query result.
|
|
* @param null $result_type Query result type.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_fetch_array.
|
|
*/
|
|
public static function fetch_array( $result, $result_type = null ) {
|
|
if ( is_bool( $result ) ) {
|
|
return $result;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
return \mysqli_fetch_array( $result, ( null === $result_type ? MYSQLI_BOTH : $result_type ) );
|
|
} else {
|
|
return \mysql_fetch_array( $result, ( null === $result_type ? MYSQL_BOTH : $result_type ) );
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Method num_rows()
|
|
*
|
|
* MySQLi number of rows.
|
|
*
|
|
* @param mixed $result Query result.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_num_rows.
|
|
*/
|
|
public static function num_rows( $result ) {
|
|
if ( ! self::is_result( $result ) ) { // NOSONAR - required.
|
|
return false;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
return \mysqli_num_rows( $result );
|
|
} else {
|
|
return \mysql_num_rows( $result );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Method is_result()
|
|
*
|
|
* Return instance of \mysqli_result
|
|
*
|
|
* @param mixed $result Query result.
|
|
*
|
|
* @return boolean|mixed false|\mysqli_result
|
|
*/
|
|
public static function is_result( $result ) {
|
|
if ( is_bool( $result ) ) {
|
|
return $result;
|
|
}
|
|
|
|
if ( self::use_mysqli() ) { // NOSONAR - required.
|
|
return $result instanceof \mysqli_result;
|
|
} else {
|
|
return is_resource( $result );
|
|
}
|
|
}
|
|
// phpcs:enable
|
|
}
|