Files
dostavka_vodi/wp-content/plugins/all-in-one-wp-security-and-firewall/admin/wp-security-database-menu.php
User A0264400 a766acdc90 first commit
2026-04-01 23:20:16 +03:00

409 lines
19 KiB
PHP

<?php
if (!defined('ABSPATH')) {
exit; // Exit if accessed directly
}
class AIOWPSecurity_Database_Menu extends AIOWPSecurity_Admin_Menu {
/**
* Database menu slug
*
* @var string
*/
protected $menu_page_slug = AIOWPSEC_DB_SEC_MENU_SLUG;
/**
* Constructor adds menu for Database security
*/
public function __construct() {
parent::__construct(__('Database security', 'all-in-one-wp-security-and-firewall'));
}
/**
* Return installation or activation link of UpdraftPlus plugin
*
* @return String
*/
private function get_install_activate_link_of_updraft_plugin() {
// If UpdraftPlus is activated, then return empty.
if (class_exists('UpdraftPlus')) return '';
// Generally it is 'updraftplus/updraftplus.php',
// but we can't assume that the user hasn't renamed the plugin folder - with 3 million UDP users and 1 million AIOWPS, there will be some who have.
$updraftplus_plugin_file_rel_to_plugins_dir = $this->get_updraftplus_plugin_file_rel_to_plugins_dir();
// If UpdraftPlus is installed but not activated, then return activate link.
if ($updraftplus_plugin_file_rel_to_plugins_dir) {
$activate_url = add_query_arg(array(
'_wpnonce' => wp_create_nonce('activate-plugin_'.$updraftplus_plugin_file_rel_to_plugins_dir),
'action' => 'activate',
'plugin' => $updraftplus_plugin_file_rel_to_plugins_dir,
), network_admin_url('plugins.php'));
// If is network admin then add to link network activation.
if (is_network_admin()) {
$activate_url = add_query_arg(array('networkwide' => 1), $activate_url);
}
return sprintf('<a href="%s">%s</a>',
$activate_url,
__('UpdraftPlus is installed but currently not active.', 'all-in-one-wp-security-and-firewall') .' '. __('Follow this link to activate UpdraftPlus, to take a backup.', 'all-in-one-wp-security-and-firewall')
);
}
// If UpdraftPlus is not activated or installed, then return the installation link
return '<a href="'.wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=updraftplus'), 'install-plugin_updraftplus').'">'.__('Follow this link to install UpdraftPlus, to take a database backup.', 'all-in-one-wp-security-and-firewall').'</a>';
}
/**
* Get path to the UpdraftPlus plugin file relative to the plugins directory.
*
* @return String|false path to the UpdraftPlus plugin file relative to the plugins directory
*/
private function get_updraftplus_plugin_file_rel_to_plugins_dir() {
if (!function_exists('get_plugins')) {
include_once ABSPATH . '/wp-admin/includes/plugin.php';
}
$installed_plugins = get_plugins();
$installed_plugins_keys = array_keys($installed_plugins);
foreach ($installed_plugins_keys as $plugin_file_rel_to_plugins_dir) {
$temp_plugin_file_name = substr($plugin_file_rel_to_plugins_dir, strpos($plugin_file_rel_to_plugins_dir, '/') + 1);
if ('updraftplus.php' == $temp_plugin_file_name) {
return $plugin_file_rel_to_plugins_dir;
}
}
return false;
}
/**
* This function will setup the menus tabs by setting the array $menu_tabs
*
* @return void
*/
protected function setup_menu_tabs() {
$menu_tabs = array(
'database-prefix' => array(
'title' => __('Database prefix', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_database_prefix'),
'display_condition_callback' => 'is_main_site',
),
'database-backup' => array(
'title' => __('Database backup', 'all-in-one-wp-security-and-firewall'),
'render_callback' => array($this, 'render_database_backup'),
),
);
$this->menu_tabs = array_filter($menu_tabs, array($this, 'should_display_tab'));
}
/**
* Renders the submenu's database prefix tab
*
* @return Void
*/
protected function render_database_prefix() {
global $wpdb, $aio_wp_security, $aiowps_feature_mgr;
$old_db_prefix = $wpdb->prefix;
$new_db_prefix = '';
$perform_db_change = false;
if (isset($_POST['aiowps_db_prefix_change'])) { // Do form submission tasks
$nonce = $_REQUEST['_wpnonce'];
if (!wp_verify_nonce($nonce, 'aiowpsec-db-prefix-change-nonce')) {
$aio_wp_security->debug_logger->log_debug("Nonce check failed for DB prefix change operation.", 4);
die(__('Nonce check failed for DB prefix change operation.', 'all-in-one-wp-security-and-firewall'));
}
// Let's first check if user's system allows writing to wp-config.php file. If plugin cannot write to wp-config we will not do the prefix change.
$config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
$file_write = AIOWPSecurity_Utility_File::is_file_writable($config_file);
if (!$file_write) {
$this->show_msg_error(__('The plugin has detected that it cannot write to the wp-config.php file.', 'all-in-one-wp-security-and-firewall') . ' ' . __('This feature can only be used if the plugin can successfully write to the wp-config.php file.', 'all-in-one-wp-security-and-firewall'));
} else {
if (isset($_POST['aiowps_enable_random_prefix'])) { // User has elected to generate a random DB prefix
$string = AIOWPSecurity_Utility::generate_alpha_random_string('5');
$new_db_prefix = $string . '_';
$perform_db_change = true;
} else {
if (empty($_POST['aiowps_new_manual_db_prefix'])) {
$this->show_msg_error(__('Please enter a value for the DB prefix.', 'all-in-one-wp-security-and-firewall'));
} else {
// User has chosen their own DB prefix value
$new_db_prefix = wp_strip_all_tags(trim($_POST['aiowps_new_manual_db_prefix']));
if ($new_db_prefix !== $_POST['aiowps_new_manual_db_prefix']) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> ".__('prefix contains HTML tags', 'all-in-one-wp-security-and-firewall'));
}
if (preg_match('|[^a-z0-9_]|i', $new_db_prefix)) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> ".__('prefix contains invalid characters, the prefix should only contain alphanumeric and underscore characters.', 'all-in-one-wp-security-and-firewall'));
}
$error = $wpdb->set_prefix($new_db_prefix); // validate the user chosen prefix
if (is_wp_error($error)) {
wp_die("<strong>".__('Error:', 'all-in-one-wp-security-and-firewall')."</strong> (".$error->get_error_code()."): ".$error->get_error_message());
}
$wpdb->set_prefix($old_db_prefix);
$perform_db_change = true;
}
}
}
}
if ($perform_db_change) {
// Do the DB prefix change operations
$this->change_db_prefix($old_db_prefix, $new_db_prefix);
}
$aio_wp_security->include_template('wp-admin/database-security/database-prefix.php', false, array('aiowps_feature_mgr' => $aiowps_feature_mgr, 'old_db_prefix' => $old_db_prefix));
}
/**
* Renders the submenu's database backup tab
*
* @return Void
*/
protected function render_database_backup() {
global $aio_wp_security;
$updraftplus_admin = !empty($GLOBALS['updraftplus_admin']) ? $GLOBALS['updraftplus_admin'] : null;
if ($updraftplus_admin) {
$updraftplus_admin->add_backup_scaffolding(__('Take a database backup using UpdraftPlus', 'all-in-one-wp-security-and-firewall'), array($updraftplus_admin, 'backupnow_modal_contents'));
}
$install_activate_link = $this->get_install_activate_link_of_updraft_plugin();
$aio_wp_security->include_template('wp-admin/database-security/database-backup.php', false, array('install_activate_link' => $install_activate_link));
}
/*
* Changes the DB prefix
*/
/**
* This function will change the DB prefix
*
* @param string $table_old_prefix - the old table prefix
* @param string $table_new_prefix - the new table prefix
*
* @return void
*/
private function change_db_prefix($table_old_prefix, $table_new_prefix) {
global $wpdb, $aio_wp_security;
$old_prefix_length = strlen($table_old_prefix);
$error = 0;
// Config file path
$config_file = AIOWPSecurity_Utility_File::get_wp_config_file_path();
// Get the table resource
// $result = mysql_list_tables(DB_NAME);
$result = $this->get_mysql_tables(DB_NAME); //Fix for deprecated php mysql_list_tables function
// Count the number of tables
if (is_array($result) && count($result) > 0) {
$num_rows = count($result);
} else {
echo '<div class="aio_red_box"><p>'.__('Error - Could not get tables or no tables found!', 'all-in-one-wp-security-and-firewall').'</p></div>';
return;
}
$table_count = 0;
$info_msg_string = '<p class="aio_info_with_icon">'.__('Starting DB prefix change operations.....', 'all-in-one-wp-security-and-firewall').'</p>';
$info_msg_string .= '<p class="aio_info_with_icon">'.sprintf(__('Your WordPress system has a total of %s tables and your new DB prefix will be: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$num_rows.'</strong>', '<strong>'.$table_new_prefix.'</strong>').'</p>';
echo $info_msg_string;
// Do a back of the config file
if (!AIOWPSecurity_Utility_File::backup_and_rename_wp_config($config_file)) {
echo '<div class="aio_red_box"><p>'.__('Failed to make a backup of the wp-config.php file.', 'all-in-one-wp-security-and-firewall') . ' ' .__('This operation will not go ahead.', 'all-in-one-wp-security-and-firewall').'</p></div>';
return;
} else {
echo '<p class="aio_success_with_icon">'.__('A backup copy of your wp-config.php file was created successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
}
// Get multisite blog_ids if applicable
if (is_multisite()) {
$blog_ids = AIOWPSecurity_Utility::get_blog_ids();
}
// Rename all the table names
foreach ($result as $db_table) {
// Get table name with old prefix
$table_old_name = $db_table;
if (strpos($table_old_name, $table_old_prefix) === 0) {
// Get table name with new prefix
$table_new_name = AIOWPSecurity_Utility::backquote($table_new_prefix . substr($table_old_name, $old_prefix_length));
$table_old_name = AIOWPSecurity_Utility::backquote($table_old_name);
// Write query to rename tables name
$sql = "RENAME TABLE ".$table_old_name." TO ".$table_new_name;
// $sql = "RENAME TABLE %s TO %s";
// Execute the query
if (false === $wpdb->query($sql)) {
$error = 1;
echo '<p class="aio_error_with_icon">'.sprintf(__('%s table name update failed', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_old_name.'</strong>').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to change prefix of table ".$table_old_name, 4);
} else {
$table_count++;
}
} else {
continue;
}
}
if (1 == $error) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Please change the prefix manually for the above tables to: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_new_prefix.'</strong>').'</p>';
} else {
echo '<p class="aio_success_with_icon">'.sprintf(__('%s tables had their prefix updated successfully!', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_count.'</strong>').'</p>';
}
// Let's check for mysql tables of type "view"
$this->alter_table_views($table_old_prefix, $table_new_prefix);
// Get wp-config.php file contents and modify it with new info
$config_contents = file($config_file);
$prefix_match_string = '$table_prefix='; //this is our search string for the wp-config.php file
foreach ($config_contents as $line_num => $line) {
$no_ws_line = preg_replace('/\s+/', '', $line); //Strip white spaces
if (false !== strpos($no_ws_line, $prefix_match_string)) {
$prefix_parts = explode("=", $line);
$prefix_parts[1] = str_replace($table_old_prefix, $table_new_prefix, $prefix_parts[1]);
$config_contents[$line_num] = implode("=", $prefix_parts);
break;
}
}
// Now let's modify the wp-config.php file
if (AIOWPSecurity_Utility_File::write_content_to_file($config_file, $config_contents)) {
echo '<p class="aio_success_with_icon">'. __('wp-config.php file was updated successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
} else {
echo '<p class="aio_error_with_icon">'.sprintf(__('The "wp-config.php" file was not able to be modified.', 'all-in-one-wp-security-and-firewall').' '.__('Please modify this file manually using your favourite editor and search for variable "$table_prefix" and assign the following value to that variable: %s', 'all-in-one-wp-security-and-firewall'), '<strong>'.$table_new_prefix.'</strong>').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Unable to modify wp-config.php", 4);
}
// Now let's update the options table
$update_option_table_query = $wpdb->prepare("UPDATE " . $table_new_prefix . "options SET option_name = '".$table_new_prefix ."user_roles' WHERE option_name = %s LIMIT 1", $table_old_prefix."user_roles");
if (false === $wpdb->query($update_option_table_query)) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $table_new_prefix.'options', $table_old_prefix.'user_roles', $table_new_prefix.'user_roles').'</p>';
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Error when updating the options table", 4);//Log the highly unlikely event of DB error
} else {
echo '<p class="aio_success_with_icon">'. __('The options table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall') .'</p>';
}
// Now let's update the options tables for the multisite subsites if applicable
if (is_multisite()) {
if (!empty($blog_ids)) {
$main_site_id = get_main_site_id();
foreach ($blog_ids as $blog_id) {
if ($blog_id == $main_site_id) continue;
$new_pref_and_site_id = $table_new_prefix.$blog_id.'_';
$old_pref_and_site_id = $table_old_prefix.$blog_id.'_';
$update_ms_option_table_query = $wpdb->prepare("UPDATE " . $new_pref_and_site_id . "options SET option_name = '".$new_pref_and_site_id."user_roles' WHERE option_name = %s LIMIT 1", $old_pref_and_site_id."user_roles");
if (false === $wpdb->query($update_ms_option_table_query)) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of table %s failed: unable to change %s to %s', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options', $old_pref_and_site_id.'user_roles', $new_pref_and_site_id.'user_roles').'</p>';
$aio_wp_security->debug_logger->log_debug("DB change prefix feature - Error when updating the subsite options table: ".$new_pref_and_site_id.'options', 4);//Log the highly unlikely event of DB error
} else {
echo '<p class="aio_success_with_icon">'.sprintf(__('The %s table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall'), $new_pref_and_site_id.'options').'</p>';
}
}
}
}
//Now let's update the user meta table
$custom_sql = "SELECT user_id, meta_key FROM " . $table_new_prefix . "usermeta WHERE meta_key LIKE '" . $table_old_prefix . "%'";
$meta_keys = $wpdb->get_results($custom_sql);
$error_update_usermeta = '';
// Update all meta_key field values which have the old table prefix in user_meta table
foreach ($meta_keys as $meta_key) {
// Create new meta key
$new_meta_key = $table_new_prefix . substr($meta_key->meta_key, $old_prefix_length);
$update_user_meta_sql = $wpdb->prepare("UPDATE " . $table_new_prefix . "usermeta SET meta_key='" . $new_meta_key . "' WHERE meta_key=%s AND user_id=%s", $meta_key->meta_key, $meta_key->user_id);
if (false === $wpdb->query($update_user_meta_sql)) {
$error_update_usermeta .= '<p class="aio_error_with_icon">'.sprintf(__('Error updating user_meta table where new meta_key = %s, old meta_key = %s and user_id = %s.', 'all-in-one-wp-security-and-firewall'), $new_meta_key, $meta_key->meta_key, $meta_key->user_id).'</p>';
echo $error_update_usermeta;
$aio_wp_security->debug_logger->log_debug("DB Security Feature - Error updating user_meta table where new meta_key = ".$new_meta_key." old meta_key = ".$meta_key->meta_key." and user_id = ".$meta_key->user_id, 4);//Log the highly unlikely event of DB error
}
}
echo '<p class="aio_success_with_icon">'.__('The usermeta table records which had references to the old DB prefix were updated successfully!', 'all-in-one-wp-security-and-firewall').'</p>';
// Display tasks finished message
$tasks_finished_msg_string = '<p class="aio_info_with_icon">'. __('The database prefix change tasks have been completed.', 'all-in-one-wp-security-and-firewall').'</p>';
echo $tasks_finished_msg_string;
}
/**
* This is an alternative to the deprecated "mysql_list_tables
*
* @param string $database - database name
*
* @returns array - an array of table names
*/
public function get_mysql_tables($database = '') {
global $aio_wp_security;
$tables = array();
$list_tables_sql = "SHOW TABLES FROM `{$database}`;";
$mysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_NAME);
if ($mysqli->connect_errno) {
$aio_wp_security->debug_logger->log_debug("AIOWPSecurity_Database_Menu->get_mysql_tables() - DB connection error.", 4);
return false;
}
$result = $mysqli->query($list_tables_sql, MYSQLI_USE_RESULT);
if ($result) {
//Alternative way to get the tables
while ($row = $result->fetch_assoc()) {
foreach ($row as $value) {
$tables[] = $value;
}
}
$result->close();
}
$mysqli->close();
return $tables;
}
/**
* Will modify existing table view definitions to reflect the new DB prefix change
*
* @param string $old_db_prefix - old database prefix
* @param string $new_db_prefix - new database prefix
*
* @returns void
*/
private function alter_table_views($old_db_prefix, $new_db_prefix) {
global $wpdb, $aio_wp_security;
$db_name = $wpdb->dbname;
$info_msg_string = '<p class="aio_info_with_icon">'.__('Checking for MySQL tables of type "view".....', 'all-in-one-wp-security-and-firewall').'</p>';
echo $info_msg_string;
// get tables which are views
$query = "SELECT * FROM INFORMATION_SCHEMA.VIEWS WHERE TABLE_SCHEMA LIKE '".$db_name."'";
$res = $wpdb->get_results($query);
if (empty($res)) return;
$view_count = 0;
foreach ($res as $item) {
$old_def = $item->VIEW_DEFINITION;
$new_def = AIOWPSecurity_Utility::str_replace_once($old_db_prefix, $new_db_prefix, $old_def);
$new_def = AIOWPSecurity_Utility::backquote($new_def);
$view_name = AIOWPSecurity_Utility::backquote($item->TABLE_NAME);
$chg_view_sql = "ALTER VIEW $view_name AS $new_def";
$view_res = $wpdb->query($chg_view_sql);
if (false === $view_res) {
echo '<p class="aio_error_with_icon">'.sprintf(__('Update of the following MySQL view definition failed: %s', 'all-in-one-wp-security-and-firewall'), $old_def).'</p>';
$aio_wp_security->debug_logger->log_debug("Update of the following MySQL view definition failed: ".$old_def, 4);//Log the highly unlikely event of DB error
} else {
$view_count++;
}
}
if ($view_count > 0) {
echo '<p class="aio_success_with_icon">'.sprintf(__('%s view definitions were updated successfully.', 'all-in-one-wp-security-and-firewall'), '<strong>'.$view_count.'</strong>').'</p>';
}
return;
}
}