You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
189 lines
4.7 KiB
PHTML
189 lines
4.7 KiB
PHTML
8 months ago
|
<?php
|
||
|
/**
|
||
|
* DB helpers.
|
||
|
*
|
||
|
* @since 1.0.9
|
||
|
* @package RankMath
|
||
|
* @subpackage RankMath\Helpers
|
||
|
* @author Rank Math <support@rankmath.com>
|
||
|
*/
|
||
|
|
||
|
namespace RankMath\Helpers;
|
||
|
|
||
|
use RankMath\Admin\Database\Database;
|
||
|
|
||
|
defined( 'ABSPATH' ) || exit;
|
||
|
|
||
|
/**
|
||
|
* DB class.
|
||
|
*/
|
||
|
class DB {
|
||
|
|
||
|
/**
|
||
|
* Check and fix collation of table and columns.
|
||
|
*
|
||
|
* @param string $table Table name (without prefix).
|
||
|
* @param array $columns Columns.
|
||
|
* @param string $set_collation Collation.
|
||
|
*/
|
||
|
public static function check_collation( $table, $columns = 'all', $set_collation = null ) {
|
||
|
global $wpdb;
|
||
|
$changed_collations = 0;
|
||
|
|
||
|
$prefixed = $wpdb->prefix . $table;
|
||
|
|
||
|
$sql = "SHOW TABLES LIKE '{$wpdb->prefix}%'";
|
||
|
$res = $wpdb->get_col( $sql ); // phpcs:ignore
|
||
|
if ( ! in_array( $prefixed, $res, true ) ) {
|
||
|
return $changed_collations;
|
||
|
}
|
||
|
|
||
|
// Collation to set.
|
||
|
$collate = $set_collation ? $set_collation : self::get_default_collation();
|
||
|
|
||
|
$sql = "SHOW CREATE TABLE `{$prefixed}`";
|
||
|
$res = $wpdb->get_row( $sql ); // phpcs:ignore
|
||
|
|
||
|
$table_collate = $res->{'Create Table'};
|
||
|
|
||
|
// Determine current collation value.
|
||
|
$current_collate = '';
|
||
|
if ( preg_match( '/COLLATE=([a-zA-Z0-9_-]+)/', $table_collate, $matches ) ) {
|
||
|
$current_collate = $matches[1];
|
||
|
}
|
||
|
|
||
|
// If collation is not set or is incorrect, fix it.
|
||
|
if ( ! $current_collate || $current_collate !== $collate ) {
|
||
|
$sql = "ALTER TABLE `{$prefixed}` COLLATE={$collate}";
|
||
|
error_log( sprintf( 'Rank Math: Changing collation of `%1$s` table from %2$s to %3$s. SQL: "%4$s"', $prefixed, $current_collate, $collate, $sql ) ); // phpcs:ignore
|
||
|
$wpdb->query( $sql ); // phpcs:ignore
|
||
|
$changed_collations++;
|
||
|
}
|
||
|
|
||
|
// Now handle columns if needed.
|
||
|
if ( ! $columns ) {
|
||
|
return $changed_collations;
|
||
|
}
|
||
|
|
||
|
$sql = "SHOW FULL COLUMNS FROM {$prefixed}";
|
||
|
$res = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore
|
||
|
if ( ! $res ) {
|
||
|
return $changed_collations;
|
||
|
}
|
||
|
|
||
|
$columns = 'all' === $columns ? wp_list_pluck( $res, 'Field' ) : $columns;
|
||
|
|
||
|
foreach ( $res as $col ) {
|
||
|
if ( ! in_array( $col['Field'], $columns, true ) ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$current_collate = $col['Collation'];
|
||
|
if ( ! $current_collate || $current_collate === $collate ) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
$null = 'NO' === $col['Null'] ? 'NOT NULL' : 'NULL';
|
||
|
$default = ! empty( $col['Default'] ) ? "DEFAULT '{$col['Default']}'" : '';
|
||
|
|
||
|
$sql = "ALTER TABLE `{$prefixed}` MODIFY `{$col['Field']}` {$col['Type']} COLLATE {$collate} {$null} {$default}";
|
||
|
error_log( sprintf( 'Rank Math: Changing collation of `%1$s`.`%2$s` column from %3$s to %4$s. SQL: "%5$s"', $prefixed, $col['Field'], $current_collate, $collate, $sql ) ); // phpcs:ignore
|
||
|
$wpdb->query( $sql ); // phpcs:ignore
|
||
|
$changed_collations++;
|
||
|
}
|
||
|
|
||
|
return $changed_collations;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get collation of a specific table.
|
||
|
*
|
||
|
* @param string $table Table name.
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function get_table_collation( $table ) {
|
||
|
global $wpdb;
|
||
|
|
||
|
$sql = "SHOW CREATE TABLE `{$wpdb->prefix}{$table}`";
|
||
|
$res = $wpdb->get_row( $sql ); // phpcs:ignore
|
||
|
|
||
|
if ( ! $res ) {
|
||
|
return '';
|
||
|
}
|
||
|
|
||
|
$table_collate = $res->{'Create Table'};
|
||
|
|
||
|
// Determine current collation value.
|
||
|
$current_collate = '';
|
||
|
if ( preg_match( '/COLLATE=([a-zA-Z0-9_-]+)/', $table_collate, $matches ) ) {
|
||
|
$current_collate = $matches[1];
|
||
|
}
|
||
|
|
||
|
return $current_collate;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get default collation.
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
public static function get_default_collation() {
|
||
|
if ( defined( 'DB_COLLATE' ) && DB_COLLATE ) {
|
||
|
return DB_COLLATE;
|
||
|
}
|
||
|
|
||
|
$posts_table_collation = self::get_table_collation( 'posts' );
|
||
|
if ( $posts_table_collation ) {
|
||
|
return $posts_table_collation;
|
||
|
}
|
||
|
|
||
|
return 'utf8mb4_unicode_ci';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Retrieve a Database instance by table name.
|
||
|
*
|
||
|
* @param string $table_name A Database instance id.
|
||
|
*
|
||
|
* @return Database Database object instance.
|
||
|
*/
|
||
|
public static function query_builder( $table_name ) {
|
||
|
return Database::table( $table_name );
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if table exists in db or not.
|
||
|
*
|
||
|
* @param string $table_name Table name to check for existance.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public static function check_table_exists( $table_name ) {
|
||
|
global $wpdb;
|
||
|
|
||
|
if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $wpdb->prefix . $table_name ) ) ) === $wpdb->prefix . $table_name ) {
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if table has more rows than X.
|
||
|
*
|
||
|
* @since 1.1.16
|
||
|
*
|
||
|
* @param string $table_name Table name to check.
|
||
|
* @param int $limit Number of rows to check against.
|
||
|
*
|
||
|
* @return bool
|
||
|
*/
|
||
|
public static function table_size_exceeds( $table_name, $limit ) {
|
||
|
global $wpdb;
|
||
|
|
||
|
$check_table = $wpdb->query( "SELECT 1 FROM {$table_name} LIMIT {$limit}, 1" );
|
||
|
|
||
|
return ! empty( $check_table );
|
||
|
}
|
||
|
}
|