Last active
July 6, 2017 03:00
-
-
Save pento/714bfd58c423ff06a37d8268a5af5cd3 to your computer and use it in GitHub Desktop.
🙃db, the next evolution of wpdb.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class 🙃db extends wpdb { | |
public $tables🙃 = array( | |
// Tables | |
'posts' => '⭕', | |
'postmeta' => '⭕➡️', | |
'comments' => '♻', | |
'commentmeta' => '♻➡️', | |
'terms' => '↔️', | |
'termmeta' => '↔️➡️', | |
'term_taxonomy' => '↔️➰', | |
'term_relationships' => '↔️➿', | |
'options' => 'ℹ', | |
'links' => '❌', | |
// Global tables | |
'users' => '⚜', | |
'usermeta' => '⚜➡️', | |
// Multisite global tables | |
'blogs' => '✴', | |
'signups' => '‼', | |
'site' => '❇', | |
'sitemeta' => '❇➡️', | |
'sitecategories' => '❇↔️', | |
'registration_log' => '⁉_〽', | |
'blog_versions' => '✴_〰', | |
); | |
public function tables( $scope = 'all', $prefix = true, $blog_id = 0 ) { | |
$tables = parent::tables( $scope, $prefix, $blog_id ); | |
foreach ( $this->tables🙃 as $name => $replacement ) { | |
if ( $prefix && ! empty( $tables[ $name ] ) ) { | |
$tables[ $name ] = str_replace( $name, $replacement, $tables[ $name ] ); | |
} | |
if ( ! $prefix && in_array( $name, $tables, true ) ) { | |
$tables = str_replace( $name, $replacement, $tables ); | |
} | |
} | |
return $tables; | |
} | |
protected function get_table_from_query( $query ) { | |
// Remove characters that can legally trail the table name. | |
$query = rtrim( $query, ';/-#' ); | |
// Allow (select...) union [...] style queries. Use the first query's table name. | |
$query = ltrim( $query, "\r\n\t (" ); | |
// Strip everything between parentheses except nested selects. | |
$query = preg_replace( '/\((?!\s*select)[^(]*?\)/is', '()', $query ); | |
// Quickly match most common queries. | |
if ( preg_match( '/^\s*(?:' | |
. 'SELECT.*?\s+FROM' | |
. '|INSERT(?:\s+LOW_PRIORITY|\s+DELAYED|\s+HIGH_PRIORITY)?(?:\s+IGNORE)?(?:\s+INTO)?' | |
. '|REPLACE(?:\s+LOW_PRIORITY|\s+DELAYED)?(?:\s+INTO)?' | |
. '|UPDATE(?:\s+LOW_PRIORITY)?(?:\s+IGNORE)?' | |
. '|DELETE(?:\s+LOW_PRIORITY|\s+QUICK|\s+IGNORE)*(?:.+?FROM)?' | |
. ')\s+((?:[^\s,])+)/is', $query, $maybe ) ) { | |
return str_replace( '`', '', $maybe[1] ); | |
} | |
// SHOW TABLE STATUS and SHOW TABLES WHERE Name = 'wp_posts' | |
if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES).+WHERE\s+Name\s*=\s*("|\')((?:[^\s,])+)\\1/is', $query, $maybe ) ) { | |
return $maybe[2]; | |
} | |
// SHOW TABLE STATUS LIKE and SHOW TABLES LIKE 'wp\_123\_%' | |
// This quoted LIKE operand seldom holds a full table name. | |
// It is usually a pattern for matching a prefix so we just | |
// strip the trailing % and unescape the _ to get 'wp_123_' | |
// which drop-ins can use for routing these SQL statements. | |
if ( preg_match( '/^\s*SHOW\s+(?:TABLE\s+STATUS|(?:FULL\s+)?TABLES)\s+(?:WHERE\s+Name\s+)?LIKE\s*("|\')((?:[^\s,])+)%?\\1/is', $query, $maybe ) ) { | |
return str_replace( '\\_', '_', $maybe[2] ); | |
} | |
// Big pattern for the rest of the table-related queries. | |
if ( preg_match( '/^\s*(?:' | |
. '(?:EXPLAIN\s+(?:EXTENDED\s+)?)?SELECT.*?\s+FROM' | |
. '|DESCRIBE|DESC|EXPLAIN|HANDLER' | |
. '|(?:LOCK|UNLOCK)\s+TABLE(?:S)?' | |
. '|(?:RENAME|OPTIMIZE|BACKUP|RESTORE|CHECK|CHECKSUM|ANALYZE|REPAIR).*\s+TABLE' | |
. '|TRUNCATE(?:\s+TABLE)?' | |
. '|CREATE(?:\s+TEMPORARY)?\s+TABLE(?:\s+IF\s+NOT\s+EXISTS)?' | |
. '|ALTER(?:\s+IGNORE)?\s+TABLE' | |
. '|DROP\s+TABLE(?:\s+IF\s+EXISTS)?' | |
. '|CREATE(?:\s+\w+)?\s+INDEX.*\s+ON' | |
. '|DROP\s+INDEX.*\s+ON' | |
. '|LOAD\s+DATA.*INFILE.*INTO\s+TABLE' | |
. '|(?:GRANT|REVOKE).*ON\s+TABLE' | |
. '|SHOW\s+(?:.*FROM|.*TABLE)' | |
. ')\s+\(*\s*((?:[^\s,])+)\s*\)*/is', $query, $maybe ) ) { | |
return str_replace( '`', '', $maybe[1] ); | |
} | |
return false; | |
} | |
public function query( $query ) { | |
// WP_Date_Query::validate_column() strips non-ASCII table names, which makes 🙃db sad. | |
$known_columns = array( | |
$this->posts => array( | |
'post_date', | |
'post_date_gmt', | |
'post_modified', | |
'post_modified_gmt', | |
), | |
$this->comments => array( | |
'comment_date', | |
'comment_date_gmt', | |
), | |
$this->users => array( | |
'user_registered', | |
), | |
$this->blogs => array( | |
'registered', | |
'last_updated', | |
), | |
); | |
foreach ( $known_columns as $table => $columns ) { | |
foreach ( $columns as $column ) { | |
$query = str_replace( "$this->prefix.$column", "$table.$column", $query ); | |
} | |
} | |
// Tests_List_Pages::setUp() assumes the posts table name. | |
$query = str_replace( "TRUNCATE {$this->prefix}posts", "TRUNCATE $this->posts", $query ); | |
// WP_User_Query::prepare_query() assumes the posts table name. | |
$wrong_name = $this->prefix . 'posts'; | |
$right_name = $this->tables()['posts']; | |
$query = str_replace( "FROM $wrong_name WHERE", "FROM $right_name WHERE", $query ); | |
$query = str_replace( " $wrong_name.", " $right_name.", $query ); | |
$matches = array(); | |
if ( is_multisite() && preg_match( "/{$this->prefix}(\d+)_posts/", $query, $matches ) ) { | |
$wrong_name = $this->prefix . $matches[1] . '_posts'; | |
$right_name = $this->tables( 'all', true, $matches[1] )['posts']; | |
$query = str_replace( "FROM $wrong_name WHERE", "FROM $right_name WHERE", $query ); | |
$query = str_replace( " $wrong_name.", " $right_name.", $query ); | |
} | |
// No need to check DROP TABLE queries | |
if ( strpos( $query, 'DROP TABLE' ) === 0 ) { | |
$this->check_current_query = false; | |
} | |
return parent::query( $query ); | |
} | |
} | |
$wpdb = new 🙃db( DB_USER, DB_PASSWORD, DB_NAME, DB_HOST ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment