| Server IP : 82.208.35.60 / Your IP : 216.73.217.33 Web Server : Apache/2.4.55 (FreeBSD) OpenSSL/1.1.1q-freebsd PHP/7.3.31 System : FreeBSD server7.d2m.cz 12.4-RELEASE-p9 FreeBSD 12.4-RELEASE-p9 GENERIC amd64 User : studiokobylisy_cz ( 1008) PHP Version : 7.3.31 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : OFF | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/k633_cz/www/wp-content/plugins/backup-backup/includes/database/ |
Upload File : |
<?php
/**
* Author: Mikołaj `iClyde` Chodorowski
* Contact: kontakt@iclyde.pl
* Package: Backup Migration – WP Plugin
*/
// Namespace
namespace BMI\Plugin\Database;
// Use
use BMI\Plugin\BMI_Logger AS Logger;
use BMI\Plugin\Progress\BMI_ZipProgress AS Progress;
use BMI\Plugin\Dashboard AS Dashboard;
// Exit on direct access
if (!defined('ABSPATH')) exit;
// echo "Memory usage at the beginning: " . (memory_get_usage() / 1024 / 1024) . " MB \n";
// function bmi_find_wordpress_base_path() {
//
// $dir = dirname(__FILE__);
// $previous = null;
//
// do {
//
// if (file_exists($dir . '/wp-config.php')) return $dir;
// if ($previous == $dir) break;
// $previous = $dir;
//
// } while ($dir = dirname($dir));
//
// return null;
//
// }
//
// define('BASE_PATH', bmi_find_wordpress_base_path() . '/');
// define('WP_USE_THEMES', false);
//
// // Use WP Globals and load WordPress
// global $wp, $wp_query, $wp_the_query, $wp_rewrite, $wp_did_header;
// require_once BASE_PATH . 'wp-load.php';
// echo "Memory usage after core load: " . (memory_get_usage() / 1024 / 1024) . " MB \n";
// ini_set('memory_limit', '2M');
/**
* Database exporting
* Main Class, requires $wpdb
*/
class BMI_Database_Exporter {
/**
* Private local variables
*/
private $total_tables = 0;
private $recipes = [];
private $tables_by_size = [];
public $total_queries = 0;
public $total_rows = 0;
public $total_size = 0;
public $files = [];
/**
* __construct - Initialization and logger resolver
*
* @return self
*/
function __construct($storage, &$logger) {
/**
* WP Global Database variable
*/
global $wpdb;
$this->wpdb = &$wpdb;
/**
* Logger of BMI core
*/
$this->logger = &$logger;
/**
* Storage directory
*/
// $this->storage = trailingslashit(__DIR__) . 'data';
$this->storage = $storage;
/**
* Percentage escape to replace
* This way we know what the randomized string is
*/
$this->percentage = trim($this->wpdb->prepare('%s', '%'), "'");
/**
* Max rows to pass each query
*/
$this->max_rows = BMI_DB_MAX_ROWS_PER_QUERY;
$this->table_prefix = time();
$this->init_start = microtime(true);
$this->logger->log("Memory usage after initialization: " . number_format(memory_get_usage() / 1024 / 1024, 2) . " MB", 'INFO');
}
/**
* export - Export initializer
*
* @return filename/filenames
*/
public function export() {
// Table names
$this->get_table_names_and_sizes();
$this->logger->log("Scan found $this->total_tables tables ($this->total_rows rows), estimated total size: $this->total_size MB.", 'INFO');
$this->logger->log("Memory usage after getting table names: " . number_format(memory_get_usage() / 1024 / 1024, 2) . " MB ", 'INFO');
// Recipes
$this->logger->log("Getting table recipes...", 'INFO');
$this->table_recipes();
$this->logger->log("Table recipes have been exported.", 'INFO');
$this->logger->log("Memory usage after loading recipes: " . number_format(memory_get_usage() / 1024 / 1024, 2) . " MB ", 'INFO');
// Save Recipes
$this->logger->log("Saving recipes...", 'INFO');
$this->save_recipes();
$this->logger->log("Recipes saved.", 'INFO');
$this->logger->log("Memory usage after recipe off-load: " . number_format(memory_get_usage() / 1024 / 1024, 2) . " MB", 'INFO');
// Tables data
$this->logger->log("Exporting table data...", 'INFO');
$this->get_tables_data();
$this->logger->log("Table data exported.", 'INFO');
$this->logger->log("Memory usage after data export: " . number_format(memory_get_usage() / 1024 / 1024, 2) . " MB", 'INFO');
$end = number_format(microtime(true) - $this->init_start, 4);
$this->logger->log("Entire process took: $end s", 'INFO');
}
/**
* get_table_names_and_sizes - Gets table names and sizes
*
* @return {array} associative array table_name => [size => its size in MB, rows => rows count]
*/
private function get_table_names_and_sizes() {
$tables = $this->wpdb->get_results('SHOW TABLES');
$shouldExcludeTables = Dashboard\bmi_get_config('BACKUP:DATABASE:EXCLUDE');
$excludedTables = [];
if (defined('BMI_BACKUP_PRO') && BMI_BACKUP_PRO == 1) {
$excludedTables = Dashboard\bmi_get_config('BACKUP:DATABASE:EXCLUDE:LIST');
if (!is_array($excludedTables) || empty($excludedTables)) $excludedTables = [];
}
foreach ($tables as $table_index => $table_object) {
foreach ($table_object as $database_name => $table_name) {
if (in_array($table_name, $excludedTables) && $shouldExcludeTables) {
$str = __('Excluding %s table from backup (due to exclusion rules).', 'backup-backup');
$str = str_replace('%s', $table_name, $str);
$this->logger->log($str, 'INFO');
continue;
}
$query = "SELECT table_name AS `table`, round(((data_length + index_length) / 1024 / 1024), 2) AS `size`, ";
$query .= "(SELECT COUNT(*) FROM `$table_name`) AS `rows`";
$query .= "FROM information_schema.TABLES ";
$query .= "WHERE table_schema = %s AND table_name = %s";
$results = $this->wpdb->get_results($this->wpdb->prepare($query, DB_NAME, $table_name));
if (!is_object($results[0])) {
$this->logger->log("Could not get info about: $table_name (#01)", 'INFO');
continue;
}
$table_name_returned = trim($results[0]->table);
if ($table_name != $table_name_returned || strlen(trim($table_name)) <= 0) {
$this->logger->log("Could not get info about: $table_name (#02)", 'INFO');
continue;
}
$this->tables_by_size[$table_name_returned] = array(
'size' => floatval($results[0]->size),
'rows' => intval($results[0]->rows)
);
$this->total_size += floatval($results[0]->size);
$this->total_rows += intval($results[0]->rows);
$this->total_tables++;
}
}
return $this->tables_by_size;
}
/**
* table_recipes - Gets CREATION recipe of each table
*
* @return {array} - Creation recipes for each table_name => recipe
*/
private function table_recipes() {
foreach ($this->tables_by_size as $table_name => $table_object) {
$query = "SHOW CREATE TABLE $table_name";
$result = $this->wpdb->get_results($query);
foreach ($result as $index => $result_object) {
foreach ($result_object as $column_name => $column_value) {
if ($column_value == $table_name) continue;
else {
$column_value = str_replace("`" . $table_name . "`", "`" . $this->table_prefix . '_' . $table_name . "`", $column_value);
$recipe = 'CREATE TABLE IF NOT EXISTS ';
$recipe .= substr($column_value, 13);
$this->recipes[$table_name] = $recipe;
}
}
}
}
return $this->recipes;
}
/**
* save_recipes - Save recipes and off-load the memory
*
* @return {void}
*/
private function save_recipes() {
$time_prefix = $this->table_prefix;
foreach ($this->recipes as $table_name => $table_recipe) {
$this->total_queries += 4 + 3;
$recipe = "/* QUERY START */\n";
$recipe .= "SET foreign_key_checks = 0;\n";
$recipe .= "/* QUERY END */\n\n";
$recipe .= "/* QUERY START */\n";
$recipe .= "SET SQL_MODE = '';\n";
$recipe .= "/* QUERY END */\n\n";
$recipe .= "/* QUERY START */\n";
$recipe .= "SET time_zone = '+00:00';\n";
$recipe .= "/* QUERY END */\n\n";
$recipe .= "/* QUERY START */\n";
$recipe .= "SET NAMES 'utf8';\n";
$recipe .= "/* QUERY END */\n\n";
$recipe .= "/* CUSTOM VARS START */\n";
$recipe .= "/* REAL_TABLE_NAME: `$table_name`; */\n";
$recipe .= "/* PRE_TABLE_NAME: `$time_prefix" . "_" . "$table_name`; */\n";
$recipe .= "/* CUSTOM VARS END */\n\n";
$recipe .= "/* QUERY START */\n";
$recipe .= $table_recipe . ";\n";
$recipe .= "/* QUERY END */\n\n";
$this->total_rows++;
$location = $this->file_name($table_name);
$file = fopen($location, 'w');
fwrite($file, $recipe);
fclose($file);
unset($file);
$this->files[] = $location;
unset($location);
}
unset($this->recipes);
}
/**
* get_tables_data - Table data getter
*
* @return {int} Total rows count
*/
private function get_tables_data() {
foreach ($this->tables_by_size as $table_name => $table_object) {
$start_time = microtime(true);
$this->logger->log("Getting data of table: " . $table_name . " (" . number_format ($table_object['size'], 2) . " MB)", 'STEP');
$rows = intval($table_object['rows']);
$this->wpdb->query("SET foreign_key_checks = 0;");
for ($i = 0; $i < $rows; $i += $this->max_rows) {
$query = $this->wpdb->prepare("SELECT * FROM `$table_name` LIMIT %d, $this->max_rows", $i);
$result = $this->wpdb->get_results($query);
$this->save_data($result, $table_name);
unset($result);
}
$this->wpdb->query("SET foreign_key_checks = 1;");
$this->logger->log("Table: " . $table_name . " cloned, operation took: " . number_format((microtime(true) - $start_time), 5) . " ms", 'INFO');
unset($start_time);
}
}
/**
* save_data - Saves table data/row as query
*
* @param {wpdb object} &$result Database query result
* @param {string} &$table_name Table name
* @return {void}
*/
private function save_data(&$result, &$table_name) {
$columns_schema_added = false;
$file = fopen($this->file_name($table_name), 'a+');
$this->total_queries++;
$query = "/* QUERY START */\n";
$query .= "INSERT INTO `" . $this->table_prefix . "_" . $table_name . "` ";
foreach ($result as $index => $result_object) {
$data_in_order = array();
$format_in_order = array();
$columns_in_order = array();
foreach ($result_object as $column_name => $value) {
$data_in_order[] = $value;
$columns_in_order[] = "`$column_name`";
if (is_numeric($value)) {
if (is_float($value)) $format_in_order[] = '%f';
else $format_in_order[] = '%d';
} else $format_in_order[] = '%s';
}
if ($columns_schema_added === false) {
$query .= "(" . implode(', ', $columns_in_order) . ") VALUES ( \n";
$columns_schema_added = true;
} else {
$query = "), (\n";
}
$columns = sizeof($columns_in_order);
unset($columns_in_order);
$query .= "/* VALUES START */\n";
for ($i = 0; $i < $columns; ++$i) {
if ($format_in_order[$i] == '%f') {
$query .= floatval($data_in_order[$i]);
} elseif ($format_in_order[$i] == '%d') {
$query .= intval($data_in_order[$i]);
} else {
$query .= $this->wpdb->prepare("%s", $data_in_order[$i]);
$query = str_replace($this->percentage, '%', $query);
}
if ($i < ($columns - 1)) $query .= ",\n";
else $query .= "\n/* VALUES END */\n";
}
unset($data_in_order);
unset($format_in_order);
unset($columns_in_order);
fwrite($file, $query);
}
fwrite($file, ");\n/* QUERY END */\n\n");
fclose($file);
unset($file);
}
/**
* file_name - Replaces table name to file name friendly format
*
* @param {string} $table_name Table name
* @return {string} Friendly format for file
*/
private function file_name($table_name) {
$friendly_name = preg_replace("/[^A-Za-z0-9_-]/", '', $table_name);
$friendly_name = trailingslashit($this->storage) . $friendly_name . '.sql';
return $friendly_name;
}
}