410 lines
15 KiB
PHP
410 lines
15 KiB
PHP
<?php /** @noinspection ALL */
|
|
/** @noinspection PhpUnused */
|
|
/** @noinspection PhpUndefinedFunctionInspection */
|
|
/** @noinspection PhpUndefinedNamespaceInspection */
|
|
/** @noinspection PhpUndefinedClassInspection */
|
|
|
|
/**
|
|
* Index WP MySQL For Speed plugin
|
|
*
|
|
* ## OPTIONS
|
|
*
|
|
* [--all]
|
|
* : Process all eligible tables.
|
|
*
|
|
* [--dry-run]
|
|
* : Show SQL statements to change keys but don't run them. If you use this option you can pipe the output to wp db query. For example:
|
|
* wp index-mysql enable --all --dryrun | wp db query
|
|
*
|
|
* [--dryrun]
|
|
* : Same as --dry-run
|
|
*
|
|
* [--exclude=<table[,table...]]
|
|
* : Exclude named tables.
|
|
*
|
|
* [--format=<format>]
|
|
* : The display format. table, csv, json, yaml.
|
|
*
|
|
* [--blogid=<blogid>]
|
|
* : The blog id for a multisite network. --url also selects the blog if you prefer.
|
|
*
|
|
*/
|
|
class ImsfCli extends WP_CLI_Command {
|
|
|
|
public $db;
|
|
public $assoc_args;
|
|
public $cmd = 'wp index-mysql';
|
|
public $allSwitch = false;
|
|
public $rekeying;
|
|
public $errorMessages = [];
|
|
public $dryrun;
|
|
private $commentPrefix;
|
|
|
|
/**
|
|
* Display version information.
|
|
*
|
|
*/
|
|
function version( $args, $assoc_args ) {
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$wpDescription = ImfsQueries::toResultSet( ImfsQueries::getWpDescription( $this->db ) );
|
|
$format = array_key_exists( 'format', $assoc_args ) ? $assoc_args['format'] : null;
|
|
WP_CLI\Utils\format_items( $format, $wpDescription, [ 'Item', 'Value' ] );
|
|
}
|
|
|
|
/** @noinspection PhpUnusedParameterInspection */
|
|
private function setupCliEnvironment( $args, $assoc_args ) {
|
|
global $wp_version;
|
|
global $wp_db_version;
|
|
$this->allSwitch = ! empty( $assoc_args['all'] );
|
|
$this->dryrun = ! empty( $assoc_args['dry-run'] ) || ! empty( $assoc_args['dryrun'] );
|
|
$this->assoc_args = $assoc_args;
|
|
if ( is_multisite() ) {
|
|
$restoreBlogId = get_current_blog_id();
|
|
if ( ! empty( $assoc_args['blogid'] ) ) {
|
|
$this->cmd .= ' --blogid=' . $assoc_args['blogid'];
|
|
switch_to_blog( $assoc_args['blogid'] );
|
|
} else {
|
|
switch_to_blog( $restoreBlogId );
|
|
}
|
|
}
|
|
$this->db = new ImfsDb( index_mysql_for_speed_major_version, index_mysql_for_speed_inception_major_version );
|
|
$this->db->init();
|
|
$this->rekeying = $this->db->getRekeying();
|
|
|
|
if ( true ) {
|
|
/* -- comment is the form of comments in SQL, with dash dash space */
|
|
$this->commentPrefix = $this->dryrun ? '-- ' : '';
|
|
$wpDescription = ImfsQueries::getWpDescription( $this->db );
|
|
WP_CLI::log( $this->commentPrefix . __( 'Index WP MySQL For Speed', 'index-wp-mysql-for-speed' ) . ' ' . index_wp_mysql_for_speed_VERSION_NUM );
|
|
$versions = ' Plugin:' . $wpDescription['pluginversion'] . ' MySQL:' . $wpDescription['mysqlversion'] . ' WordPress:' . $wp_version . ' WordPress database:' . $wp_db_version . ' php:' . phpversion();
|
|
WP_CLI::log( $this->commentPrefix . __( 'Versions', 'index-wp-mysql-for-speed' ) . ' ' . $versions );
|
|
}
|
|
|
|
if ( ! $this->db->canReindex ) {
|
|
if ( $wp_db_version < index_wp_mysql_for_speed_first_compatible_db_version ||
|
|
$wp_db_version > index_wp_mysql_for_speed_last_compatible_db_version ) {
|
|
$fmt = __( 'Sorry, this plugin\'s version is not compatible with your WordPress database version.', 'index-wp-mysql-for-speed' );
|
|
} else {
|
|
$fmt = __( 'Sorry, you cannot use this plugin with your version of MySQL.', 'index-wp-mysql-for-speed' ) . ' ' .
|
|
__( 'Your MySQL version is outdated. Please consider upgrading,', 'index-wp-mysql-for-speed' );
|
|
}
|
|
WP_CLI::warning( $this->commentPrefix . $fmt );
|
|
}
|
|
if ( ! $this->db->unconstrained ) {
|
|
$fmt = __( 'Upgrading your MySQL server to a later version will give you better performance when you add high-performance keys.', 'index-wp-mysql-for-speed' );
|
|
WP_CLI::warning( $this->commentPrefix . $fmt );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show indexing status.
|
|
*
|
|
* @param $args
|
|
* @param $assoc_args
|
|
*/
|
|
function status( $args, $assoc_args ) {
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
|
|
$fmt = __( 'Database tables need upgrading to MySQL\'s latest table storage format, InnoDB with dynamic rows.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'upgrade', 'upgrade', $fmt, true, true );
|
|
|
|
$fmt = __( 'Add or upgrade high-performance keys to make your WordPress database faster.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'enable', 'enable', $fmt, false, false );
|
|
|
|
$fmt = __( 'You set some keys from outside this plugin. You can convert them to this plugin\'s high-performance keys.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'nonstandard', 'enable', $fmt, false, false );
|
|
$fmt = __( 'Or, you can revert them to WordPress\'s standard keys.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'nonstandard', 'disable', $fmt, false, false );
|
|
|
|
$fmt = __( 'You added high-performance keys using an earlier version of this plugin. You can update them to the latest high-performance keys.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'old', 'enable', $fmt, false, false );
|
|
$fmt = __( 'Or, you can revert them to WordPress\'s standard keys.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'old', 'disable', $fmt, false, false );
|
|
|
|
$fmt = __( 'You successfully added high-performance keys.', 'index-wp-mysql-for-speed' ) . ' ' .
|
|
__( 'You can revert them to WordPress\'s standard keys.', 'index-wp-mysql-for-speed' );
|
|
$this->showCommandLine( 'fast', 'disable', $fmt, false, false );
|
|
|
|
/* store current version of schema to suppress nag in UI */
|
|
$this->setCurrentVersion();
|
|
|
|
}
|
|
|
|
/** display sample command line to user.
|
|
*
|
|
* @param $actionKey string enable/disable/rekey/reset.
|
|
* @param $action string command to display
|
|
* @param $caption string prefix text.
|
|
* @param $warning boolean display warning not log.
|
|
* @param $alreadyPrefixed boolean tables in list already have wp_ style prefixes.
|
|
*/
|
|
private function showCommandLine( $actionKey, $action, $caption, $warning, $alreadyPrefixed ) {
|
|
$array = $this->rekeying;
|
|
if ( array_key_exists( $actionKey, $array ) && count( $array[ $actionKey ] ) > 0 ) {
|
|
$msg = $caption . ' ' . __( 'Use this command:', 'index-wp-mysql-for-speed' );
|
|
$tbls = $this->addPrefixes( $array[ $actionKey ], $alreadyPrefixed );
|
|
if ( $warning ) {
|
|
WP_CLI::warning( $this->commentPrefix . $msg );
|
|
} else {
|
|
WP_CLI::log( $this->commentPrefix . $msg );
|
|
}
|
|
WP_CLI::log( $this->commentPrefix . $this->getCommand( $action, $tbls ) );
|
|
if ( count( $this->errorMessages ) > 0 ) {
|
|
WP_CLI::log( $this->commentPrefix . implode( PHP_EOL, $this->errorMessages ) );
|
|
$this->errorMessages = [];
|
|
}
|
|
}
|
|
}
|
|
|
|
private function addPrefixes( $tbls, $alreadyPrefixed ) {
|
|
global $wpdb;
|
|
if ( $alreadyPrefixed ) {
|
|
return $tbls;
|
|
}
|
|
$res = [];
|
|
foreach ( $tbls as $tbl ) {
|
|
$res[] = $wpdb->prefix . $tbl;
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/** format actual cmd
|
|
*
|
|
* @param $cmd string
|
|
* @param $tbls array
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getCommand( $cmd, $tbls ) {
|
|
if ( count( $tbls ) > 0 ) {
|
|
$list = implode( ' ', $tbls );
|
|
|
|
return sprintf( ' ' . "%s %s %s", $this->cmd, $cmd, $list );
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Add high-performance keys.
|
|
*/
|
|
function enable( $args, $assoc_args ) {
|
|
$targetAction = 1;
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$this->doRekeying( $args, $assoc_args, $targetAction );
|
|
}
|
|
|
|
/** @noinspection PhpSameParameterValueInspection */
|
|
private function doRekeying( $args, $assoc_args, $targetAction, $alreadyPrefixed = true ) {
|
|
$action = $targetAction === 0 ? 'disable' : 'enable';
|
|
if ( $this->dryrun ) {
|
|
/* translators: this appears in wpcli output. 1: site name 2: site URL 3: localized date and time */
|
|
$dateMessage = __( 'Generated from %1$s (%2$s) at %3$s.', 'index-wp-mysql-for-speed' );
|
|
$dateMessage = sprintf( $dateMessage, get_option( 'blogname' ), get_option( 'siteurl' ), index_wp_mysql_for_speed_timestamp( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) );
|
|
WP_CLI::log( $this->commentPrefix . __( $dateMessage ) );
|
|
WP_CLI::log( $this->commentPrefix . __( 'Do not save these statements for later use. Instead, regenerate them.', 'index-wp-mysql-for-speed' ) );
|
|
WP_CLI::log( $this->commentPrefix . __( 'Dry run SQL statements. These statements were NOT run.', 'index-wp-mysql-for-speed' ) );
|
|
WP_CLI::log( "SET @@sql_mode := REPLACE(@@sql_mode, 'NO_ZERO_DATE', '');" );
|
|
$max_statement_time = $this->db->get_max_statement_time();
|
|
if ( $max_statement_time ) {
|
|
WP_CLI::log( "SET SESSION max_statement_time=$max_statement_time;" );
|
|
}
|
|
}
|
|
$tbls = $this->getTablesToProcess( $args, $assoc_args, $action );
|
|
foreach ( $tbls as $tbl ) {
|
|
$this->db->timings = [];
|
|
$arr = [ $tbl ];
|
|
$statements = $this->db->rekeyTables( $targetAction, $arr, index_mysql_for_speed_major_version, $alreadyPrefixed, $this->dryrun );
|
|
if ( $this->dryrun ) {
|
|
WP_CLI::log( implode( PHP_EOL, $statements ) );
|
|
} else {
|
|
WP_CLI::log( $this->commentPrefix . $this->reportCompletion( $action, $tbl ) );
|
|
}
|
|
}
|
|
/* store current version of schema to suppress nag in UI */
|
|
$this->setCurrentVersion();
|
|
}
|
|
|
|
/** Filter and validate the list of tables.
|
|
*
|
|
* @param $args array incoming args
|
|
* @param $assoc_args array incoming switch args
|
|
* @param $action string enable/disable/rekey/reset
|
|
*
|
|
* @return array list of tables
|
|
*/
|
|
private function getTablesToProcess( array $args, array $assoc_args, $action ) {
|
|
|
|
$alreadyPrefixed = ( $action === 'upgrade' );
|
|
$tbls = $this->rekeying[ $action ];
|
|
if ( $action === 'enable' ) {
|
|
$tbls = array_merge( $tbls, $this->rekeying['old'], $this->rekeying['nonstandard'] );
|
|
}
|
|
$tbls = $this->addPrefixes( $tbls, $alreadyPrefixed );
|
|
$res = [];
|
|
$exclude = [];
|
|
if ( ! empty( $assoc_args['exclude'] ) ) {
|
|
$exclude = explode( ',', $assoc_args['exclude'] );
|
|
}
|
|
|
|
if ( $this->allSwitch ) {
|
|
$args = $tbls;
|
|
}
|
|
|
|
$err = [];
|
|
foreach ( $args as $arg ) {
|
|
if ( in_array( $arg, $tbls ) ) {
|
|
if ( ! in_array( $arg, $exclude ) ) {
|
|
$res[] = $arg;
|
|
}
|
|
} else {
|
|
$err[] = $arg;
|
|
}
|
|
}
|
|
if ( count( $err ) > 0 ) {
|
|
$fmt = __( 'These tables are not found or not eligible to', 'index-wp-mysql-for-speed' ) . ' ' . $action . ': ' . implode( ' ', $err ) . '.';
|
|
WP_CLI::log( $this->commentPrefix . $fmt );
|
|
}
|
|
if ( count( $res ) == 0 ) {
|
|
$fmt = __( 'No tables are eligible to', 'index-wp-mysql-for-speed' ) . ' ' . $action . '.';
|
|
WP_CLI::log( $this->commentPrefix . $fmt );
|
|
}
|
|
|
|
return $res;
|
|
}
|
|
|
|
/** Display a line showing completion, with time.
|
|
*
|
|
* @param string $action
|
|
* @param string $tbl
|
|
*
|
|
* @return string
|
|
*/
|
|
private function reportCompletion( $action, $tbl ) {
|
|
$time = 0.0;
|
|
$queries = 0;
|
|
foreach ( $this->db->timings as $item ) {
|
|
$time += $item['t'];
|
|
$queries ++;
|
|
}
|
|
$this->db->timings = [];
|
|
$msg = _n( 'MySQL statement', 'MySQL statements', $queries, 'index-wp-mysql-for-speed' );
|
|
|
|
return sprintf( "%s %s %s (%d %s, %ss)",
|
|
$action, $tbl, __( "complete.", 'index-wp-mysql-for-speed' ), $queries, $msg, number_format_i18n( $time, 2 ) );
|
|
}
|
|
|
|
/** set the current majorVersion into the options structure.
|
|
* (The UI checks this to see whether it should nag the user a bit
|
|
* about adding / updating keys.
|
|
*
|
|
* @param $optName
|
|
*
|
|
* @return void
|
|
*/
|
|
private function setCurrentVersion( $optName = 'ImfsPage' ) {
|
|
global $wp_version, $wp_db_version;
|
|
$opts = get_option( $optName );
|
|
if ( ! $opts ) {
|
|
$opts = [];
|
|
}
|
|
$opts['majorVersion'] = index_mysql_for_speed_major_version;
|
|
$opts['wp_version'] = $wp_version;
|
|
$opts['wp_db_version'] = $wp_db_version;
|
|
|
|
update_option( $optName, $opts );
|
|
}
|
|
|
|
/**
|
|
* Remove high-performance keys, reverting to WordPress standard.
|
|
*/
|
|
function disable( $args, $assoc_args ) {
|
|
$targetAction = 0;
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$this->doRekeying( $args, $assoc_args, $targetAction );
|
|
}
|
|
|
|
/**
|
|
* Upgrade the storage engine and row format to InnoDB and Dynamic
|
|
*/
|
|
function upgrade( $args, $assoc_args ) {
|
|
$action = 'upgrade';
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$tbls = $this->getTablesToProcess( $args, $assoc_args, $action );
|
|
if ( $this->dryrun ) {
|
|
WP_CLI::log( $this->commentPrefix . __( 'Dry run SQL statements. These statements were NOT run.', 'index-wp-mysql-for-speed' ) );
|
|
}
|
|
try {
|
|
if ( count( $tbls ) > 0 ) {
|
|
$this->db->lock( $tbls, true );
|
|
}
|
|
foreach ( $tbls as $tbl ) {
|
|
$this->db->timings = [];
|
|
$arr = [ $tbl ];
|
|
$statements = $this->db->upgradeTableStorageEngines( $arr, $this->dryrun );
|
|
if ( $this->dryrun ) {
|
|
WP_CLI::log( implode( PHP_EOL, $statements ) );
|
|
} else {
|
|
WP_CLI::log( $this->commentPrefix . $this->reportCompletion( $action, $tbl ) );
|
|
}
|
|
}
|
|
} catch ( ImfsException $ex ) {
|
|
WP_CLI::error( $this->commentPrefix . $ex->getMessage() );
|
|
} finally {
|
|
if ( count( $tbls ) > 0 ) {
|
|
$this->db->unlock();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Display information about tables.
|
|
*/
|
|
function tables( $args, $assoc_args ) {
|
|
global $wpdb;
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$list = $this->db->tableFormats;
|
|
$hdrs = [];
|
|
$row = reset( $list );
|
|
foreach ( $row as $key => $val ) {
|
|
$hdrs[] = $key;
|
|
}
|
|
$format = array_key_exists( 'format', $assoc_args ) ? $assoc_args['format'] : 'table';
|
|
WP_CLI\Utils\format_items( $format, $list, $hdrs );
|
|
|
|
$list = [];
|
|
$tables = $this->db->tables();
|
|
foreach ( $tables as $table ) {
|
|
$outrow = [];
|
|
$ddls = $this->db->getKeyDDL( $table );
|
|
foreach ( $ddls as $keyname => $row ) {
|
|
$outrow['table'] = $wpdb->prefix . $table;
|
|
$outrow['key'] = $keyname;
|
|
$outrow['definition'] = $row->add;
|
|
$list[] = $outrow;
|
|
}
|
|
}
|
|
$hdrs = [];
|
|
$row = reset( $list );
|
|
foreach ( $row as $key => $val ) {
|
|
$hdrs[] = $key;
|
|
}
|
|
WP_CLI\Utils\format_items( $format, $list, $hdrs );
|
|
}
|
|
|
|
/**
|
|
* Upload diagnostic metadata to plugin developers' site.
|
|
* Uploads are anonymous. We use your data only to help with support issues
|
|
* and improve the plugin. We never sell or give it to any third party.
|
|
*/
|
|
function upload_metadata( $args, $assoc_args ) {
|
|
$this->setupCliEnvironment( $args, $assoc_args );
|
|
$id = ImfsQueries::getRandomString( 8 );
|
|
$id = imfs_upload_stats( $this->db, $id );
|
|
WP_CLI::log( __( 'Metadata uploaded to id ', 'index-wp-mysql-for-speed' ) . $id );
|
|
}
|
|
|
|
}
|
|
|
|
WP_CLI::add_command( 'index-mysql', 'ImsfCli' );
|