File "smart-sort.php"
Full path: /home/bud/public_html/swamp/wp-admin/wp-content/plugins/backup-backup/includes/database/smart-sort.php
File size: 32.95 KB
MIME-type: text/x-php
Charset: utf-8
<?php
/**
* Author: Mikołaj `iClyde` Chodorowski
* Contact: kontakt@iclyde.pl
* Package: Backup Migration – WP Plugin
* Version: 2.0
*/
// Namespace
namespace BMI\Plugin\Database;
// Use
use BMI\Plugin\BMI_Logger AS Logger;
use BMI\Plugin\Progress\BMI_ZipProgress AS Progress;
// // Exit on direct access
if (!defined('ABSPATH')) exit;
/**
* Database sort method
* Usage: Create new object and use "sortUnsorted" function
*/
class BMI_Database_Sorting {
/**
* Path to database files made with V2 engine
*/
private $db_files_root;
private $output_file_stream;
private $name_of_finished_tables_dir = 'bmi_converted_completed_tables';
private $progress;
private $isCLI;
private $unwantedTables = [
'wfblockediplog',
'wfblocks7',
'wfcrawlers',
'wffilechanges',
'wffilemods',
'wfhits',
'wfhoover',
'wfissues',
'wfknownfilelist',
'wflivetraffichuman',
'wflocs',
'wflogins',
'wfnotifications',
'wfpendingissues',
'wfreversecache',
'wfsnipcache',
'wfstatus',
'wftrafficrate',
'actionscheduler_logs',
'slim_stats',
'woocommerce_sessions',
'yoast_indexable',
'slim_events',
'cerber_files',
'cerber_traffic',
'cerber_log',
'cerber_countries',
'cerber_blocks',
'cerber_acl'
];
/**
* __construct - description
*
* @param {string} $db_root Path to database files
* @return void
*/
function __construct($db_root, &$progress, $isCLI) {
/**
* Set path to the root directory
*/
$this->db_files_root = $db_root;
$this->progress = $progress;
$this->isCLI = $isCLI;
}
/**
* sortUnsorted - Main function which dynamically sorts the tables (main function)
*
* @param {array} $processData = [] Data of process to be continued or empty array to start
* Requires keys [ 'index', 'insert', 'file', 'table_name', 'dir', 'unique', 'destinationFile' ]
* Optional key: convertionFinished
*
* @return array of [ 'index', 'insert', 'file', 'table_name', 'dir', 'unique', 'destinationFile' ]
*/
public function sortUnsorted($processData = []) {
// Sort the SQL files into directories
$this->putDatabaseFilesInDirectories();
// Split files into partial files (query per batch)
$process = $this->splitFilesInSeparateDirectories($processData);
// Check if all tables finished and move them outside completed directory
if ($this->doesTablesFinished()) {
// Move them outside
$this->moveAllConvertedTables();
// Check if process finished
if ($this->isCLI || (is_array($process) && array_key_exists('completed', $process) && $process['completed'] == 'yes')) {
$process['convertionFinished'] = 'yes';
}
}
// Return process for that
return $process;
}
/**
* doesTablesFinished - Checks if there is any table that didn't finish
*
* @return {bool} true or false
*/
private function doesTablesFinished() {
// Scan all files in root
$allFiles = scandir($this->db_files_root);
$files = array_diff($allFiles, array('.', '..', $this->name_of_finished_tables_dir));
// If no other directories here that means nothing to convert left
if (sizeof($files) <= 0) {
// Return true for that
return true;
} else {
// Otherwise it's false
return false;
}
}
/**
* putDatabaseFilesInDirectories - It puts all SQL files into table directories
* Does nothing if the root directory does not contain any SQL files
*
* @return void
*/
private function putDatabaseFilesInDirectories() {
// Scan all files in root
$allFiles = scandir($this->db_files_root);
$files = array_diff($allFiles, array('.', '..'));
// For each found file make sure it's SQL and run merge function
foreach ($files as $index => $filename) {
// Exclude non .sql files
if (substr($filename, -4) != '.sql') continue;
// It may be directory with .sql ending, make sure it's not
$pathToFile = $this->db_files_root . DIRECTORY_SEPARATOR . $filename;
if (is_dir($pathToFile)) continue;
// Merge the file
$this->mergeFileWithDirectory($filename);
}
}
/**
* mergeFileWithDirectory - Merges the file into proper directory
*
* @param {string} $filename File name which is located in root
* @return bool true on success false on failed file move
*/
private function mergeFileWithDirectory($filename) {
// Suffix size which stands for ending ".sql"
$suffix_size = 4;
// Match output for table name with different name than just table
// It may happen when our support used their tools for optimization
$match_output = [];
preg_match('/_(\d+)\_of\_(\d+)/', $filename, $match_output);
// If that's the case, add suffix size as we don't need that info here
if (sizeof($match_output) > 0) {
$suffix_size += strlen($match_output[0]);
}
// If we know the suffix size, get table name
$table_name = substr($filename, 0, -$suffix_size);
// Prepare future paths of the file
$dest_dir = $this->db_files_root . DIRECTORY_SEPARATOR . $table_name;
$source_path = $this->db_files_root . DIRECTORY_SEPARATOR . $filename;
$dest_path = $dest_dir . DIRECTORY_SEPARATOR . $filename;
// Check if the directory exists and if it's not make new one
if (!file_exists($dest_dir) && !is_dir($dest_dir)) {
@mkdir($dest_dir, 0755, true);
}
// Check if the files is not an duplicate and make sure both will be merged
$tries = 2;
while (file_exists($dest_path)) {
// If file exists already add number at the suffix and try again until unique name
$dest_path = substr($dest_path, 0, -4) . '_' . $tries . '.sql';
$tries++;
}
// If we're sure move the file to correct directory
if (rename($source_path, $dest_path)) {
// Return true on success
return true;
} else {
// Return false on fail
return false;
}
}
/**
* countAllFilesAndQueries - Counts all files inside directory and returns all query count
*
* @return {array} of total_queries, total_size, all_tables and all_files
*/
public function countAllFilesAndQueries() {
// Scan all files in root
$allFiles = scandir($this->db_files_root);
$folders = array_diff($allFiles, array('.', '..', $this->name_of_finished_tables_dir));
// Tables
$tables = [];
// Files
$files = [];
// Total size
$total_size = 0;
// For each found file make sure it's SQL and run merge function
foreach ($folders as $index => $filename) {
// Path to that file/directory
$pathToFile = $this->db_files_root . DIRECTORY_SEPARATOR . $filename;
// Hanlde only dirs
if (is_dir($pathToFile)) {
// Add table information
$tables[$filename] = 0;
// Scan SQL files
$allSQLFiles = scandir($pathToFile);
$allSQLFilesParsed = array_diff($allSQLFiles, array('.', '..'));
// Go throught these files
foreach ($allSQLFilesParsed as $indexSQL => $filenameSQL) {
// Exclude non .sql files
if (substr($filenameSQL, -4) != '.sql') continue;
// Get size of that file
$size = filesize($pathToFile . DIRECTORY_SEPARATOR . $filenameSQL);
// Add size in total and table
$tables[$filename] += $size;
$total_size += $size;
// Add that file to all files
$files[] = $filenameSQL;
}
}
}
// Prepare stats variable
$stats = [
'total_queries' => (sizeof($files) * 5),
'total_size' => $total_size,
'all_tables' => $tables,
'all_files' => $files
];
return $stats;
}
/**
* countTablesDuringProcess - Counts tables even during process
*
* @return array $done, $progress, $total
*/
private function countTablesDuringProcess() {
$theFinalCount = 0;
$progressCount = 0;
$doneCount = 0;
// Scan all files in root (now everything should be directory)
$allFiles = scandir($this->db_files_root);
$files = array_diff($allFiles, array('.', '..', $this->name_of_finished_tables_dir));
foreach ($files as $index => $filename) {
if (is_dir($this->db_files_root . DIRECTORY_SEPARATOR . $filename)) {
$theFinalCount++;
$progressCount++;
}
}
$doneDir = $this->db_files_root . DIRECTORY_SEPARATOR . $this->name_of_finished_tables_dir;
if (file_exists($doneDir) && is_dir($doneDir)) {
$allDoneFiles = scandir($doneDir);
$doneFiles = array_diff($allDoneFiles, array('.', '..'));
foreach ($doneFiles as $index => $filename) {
if (is_dir($doneDir . DIRECTORY_SEPARATOR . $filename)) {
$theFinalCount++;
$doneCount++;
}
}
}
return [
'done' => $doneCount,
'in_progress' => $progressCount,
'total' => $theFinalCount
];
}
/**
* logFinished - Shows progress of the process in the log file
*
* @return void
*/
private function logFinished($dir, $filename) {
$counts = $this->countTablesDuringProcess();
$progress = ($counts['done'] + 1) . '/' . $counts['total'] . ' (' . number_format((($counts['done'] + 1) / $counts['total']) * 100, 2) . '%)';
$translated = __('Finished %progress%: %filename% table, total of %parts% parts.', 'backup-backup');
// Get part amount
$partsAll = scandir($dir);
$parts = sizeof(array_diff($partsAll, array('.', '..', $this->name_of_finished_tables_dir)));
$theLog = str_replace('%progress%', $progress, $translated);
$theLog = str_replace('%filename%', $filename, $theLog);
$theLog = str_replace('%parts%', $parts, $theLog);
$this->progress->log($theLog, 'SUCCESS');
$percentage = number_format((($counts['done'] + 1) / $counts['total']) * 100, 2);
$this->progress->progress((50 + ($percentage / 4)), 'INFO');
}
/**
* splitInDirectories - Splits file into parts inside proper directory
* @param {array} $processData Process data to be continued
*
* @return void
*/
private function splitFilesInSeparateDirectories($processData = []) {
// Local process variable
$process = [];
// Scan all files in root (now everything should be directory)
$allFiles = scandir($this->db_files_root);
$files = array_diff($allFiles, array('.', '..', $this->name_of_finished_tables_dir));
// Loop all tables and split them one by one
foreach ($files as $index => $filename) {
// Prepate path to the SQL file which should be converted
$dir = $this->db_files_root . DIRECTORY_SEPARATOR . $filename;
// Always double check if it's directory otherwise we may get some unexpected errors
if (!is_dir($dir)) continue;
// Log the new file which will be processed
$destinationFile = $this->makeDestinationFilename($dir, $filename);
$destinationIndex = $destinationFile['index'];
// Log only if it's first batch
if ($destinationIndex == 1) {
$this->progress->log(str_replace('%s', $filename, __('Starting conversion of: %s table.', 'backup-backup')), 'INFO');
}
// Dynamically find file to shrink and split it
$process = $this->splitFileInTableDirectory($dir, $filename, $processData);
// If it's not CLI use batching
if (!$this->isCLI) {
// If process finished
if (is_array($process) && array_key_exists('completed', $process) && $process['completed'] == 'yes') {
// Show in the log file the progress
$this->logFinished($dir, $filename);
// Check if directory for completed tables exist and make it if it is not
$doneDirectory = $this->db_files_root . DIRECTORY_SEPARATOR . $this->name_of_finished_tables_dir;
if (!file_exists($doneDirectory) && !is_dir($doneDirectory)) {
@mkdir($doneDirectory, 0755, true);
}
// Move the table into completed directory
rename($dir, $doneDirectory . DIRECTORY_SEPARATOR . $filename);
// Return process even empty
return $process;
} else {
// If didn't finished that table return process data for next batch to finish
return $process;
}
} else {
// Show in the log file the progress
$this->logFinished($dir, $filename);
// Check if directory for completed tables exist and make it if it is not
$doneDirectory = $this->db_files_root . DIRECTORY_SEPARATOR . $this->name_of_finished_tables_dir;
if (!file_exists($doneDirectory) && !is_dir($doneDirectory)) {
@mkdir($doneDirectory, 0755, true);
}
// Move the table into completed directory
rename($dir, $doneDirectory . DIRECTORY_SEPARATOR . $filename);
}
}
}
/**
* splitFileInTableDirectory - Splits file into parts for easier progress read and performance
*
* @param {string} $dir Path to parent directory of table SQL files
* @param {string} $table_name Table name (current directory name)
* @param {array} $processData Process data to be continued
* @return void
*/
private function splitFileInTableDirectory($dir, $table_name, $processData = []) {
// Prepare local var for process data
$process = [];
// Get all database files inside that directory (it can contain multiple files alrady)
$allFiles = scandir($dir);
$files = array_diff($allFiles, array('.', '..'));
// Loop throught all of them and apply splitting
foreach ($files as $index => $filename) {
// Just to triple check that parent is a valid directory
if (!is_dir($dir)) continue;
// Prepare exact path to the SQL file
$file = $dir . DIRECTORY_SEPARATOR . $filename;
// Run splitting function for that file
$process = $this->splitDatabaseFile($file, $dir, $table_name, $processData);
// Break each query if not CLI
if (!$this->isCLI) {
break;
}
}
// If CLI only rename files without return
if ($this->isCLI) {
// Rename splited files
$this->renameSplitedFiles($dir);
} else {
// Check if process for that table completed and rename if so
if (is_array($process) && array_key_exists('completed', $process) && $process['completed'] == 'yes') {
// Rename splited files
$this->renameSplitedFiles($dir);
// Return empty process data as we will iterate new file in next batch
return [
'index' => 0,
'insert' => 'no',
'completed' => 'yes'
];
} else {
// Or just return process data for future use (next batch)
return $process;
}
}
}
/**
* logPartial - Logs partial progress to the output log
*
* @param {string} $dir Directory of the table
* @param {string} $table_name Name of the table
* @return void
*/
private function logPartial($dir, $table_name) {
// Get part amount
$partsAll = scandir($dir);
$parts = sizeof(array_diff($partsAll, array('.', '..', $this->name_of_finished_tables_dir)));
$parts = $parts - 1;
// Prepare log string
$logString = __('Finished part %part% of %table% table.', 'backup-backup');
$logString = str_replace('%table%', $table_name, $logString);
$logString = str_replace('%part%', $parts, $logString);
// Log the string to output
$this->progress->log($logString, 'INFO');
}
/**
* splitDatabaseFile - Splits a SQL file into parts
*
* @param {string} $file Name of the SQL File
* @param {string} $dir Full path to the SQL file
* @param {string} $table_name Name of the table to which SQL file belong
* @param {array} $processData Process data to be continued
* @return void
*/
private function splitDatabaseFile($file, $dir, $table_name, $processData = []) {
// Make destionation file and prepare output file stream
$destinationFile = $this->makeDestinationFilename($dir, $table_name);
$destinationFile = $destinationFile['file'];
// Local variables required for the process
$table_unique = 0;
$is_converted = false;
$query_started = false;
$custom_vars_started = false;
$values_started = false;
$insert_next = false;
$last_seek = 0;
// Resolve not finished process
if (!$this->isCLI && is_array($processData) && !empty($processData)) {
// Should be file path $file_path & $file (check if the file exist)
if (array_key_exists('file', $processData) && file_exists($processData['file'])) {
// Set existing file path
$file = $processData['file'];
// Should be int<make sure> of $last_seek
if (array_key_exists('index', $processData)) {
$last_seek = intval($processData['index']) + 1;
}
// Yes | No values {string} of $insert_next
if (array_key_exists('insert', $processData)) {
$ins = $processData['insert'];
if ($ins == 'yes') $insert_next = true;
else $insert_next = false;
}
// Table name of $table_name
if (array_key_exists('table_name', $processData)) {
$table_name = $processData['table_name'];
}
// Directory of that table $dir
if (array_key_exists('dir', $processData)) {
$dir = $processData['dir'];
}
// Unique for that table $table_unique
if (array_key_exists('unique', $processData)) {
$table_unique = $processData['unique'];
}
// Destination File (output) of $destinationFile
if (array_key_exists('destinationFile', $processData)) {
$destinationFile = $processData['destinationFile'];
}
}
}
// Open stream for output file
$this->output_file_stream = fopen($destinationFile, 'a+');
// Keep original filename
$file_path = $file;
// Open SplObject for seek-based reading
$file = new \SplFileObject($file);
// Go to last line to check how many lines are there
$file->seek($file->getSize());
// Calculate total lines in that file
$total_lines = $file->key() + 1;
for ($i = $last_seek; $i < $total_lines; ++$i) {
// Start seek frrom the loop index
$file->seek($i);
// Get line into string and trim it (it contains new line at the end)
$line = trim($file->current());
// Variable for that line, if it's a comment or not
$hasComment = false;
// Check this only if the size of line is below 24
// Otherwise it's not a comment line and we can ignore that check for better performance
if (strlen($line) < 24) {
// List of all our comments
$c_fs = "/* CONVERTED DB FILE */";
$q_s = "/* QUERY START */";
$q_e = "/* QUERY END */";
$cq_s = "/* CUSTOM VARS START */";
$cq_e = "/* CUSTOM VARS END */";
$v_s = "/* VALUES START */";
$v_e = "/* VALUES END */";
// If it's converted already ignore the file
if ($line === $c_fs) {
// Mark as converted (it output file be removed by this)
$is_converted = true;
// And break the loop, no need to continue
break;
}
// Check if it's a query start comment and adjust local variables for that for future know
if ($line === $q_s) {
$query_started = true;
$hasComment = true;
}
// Check if it's a custom variable section start comment and adjust local variables for that for future know
if ($line === $cq_s) {
$custom_vars_started = true;
$hasComment = true;
}
// Check if it's a values section start comment and adjust local variables for that for future know
if ($line === $v_s) {
$values_started = true;
$hasComment = true;
}
// If we are behind a heading insert this line into new output file
if ($insert_next && $hasComment) {
// Add new line as we trimed it before
$line .= "\n";
// Push this to output file
$this->insertIntoOutputFile($line, $table_name);
// If we already added this line continue to new line
continue;
}
// Handle query ending comment
if ($line === $q_e) {
// Adjust local variable for that file
$query_started = false;
// If it's below heading, add new output and generate new heading for output file
if ($insert_next) {
// Add double ending – it looks much better for our eyes :)
$line .= "\n\n";
// Add this line
$this->insertIntoOutputFile($line, $table_name);
// Close the file as we split per query, we will need new one for new query
if (is_resource($this->output_file_stream) || get_resource_type($this->output_file_stream) === 'file') {
fclose($this->output_file_stream);
}
// Check if it's end of the file add 4 lines offset for empty lines
// If it's not the end make new heading, otherwise remove new output file
if (($i + 4) < $total_lines) {
// Make new destination file
$destinationFile = $this->makeDestinationFilename($dir, $table_name);
$destinationFile = $destinationFile['file'];
// Check if we really need that table contents
if ($this->checkIfContainName($table_name, $this->unwantedTables)) {
$this->progress->log(str_replace('%s', $table_name, __('Cleaning up contents of %s table.', 'backup-backup')), 'INFO');
$insert_next = false;
if (!$this->isCLI) {
$file = null;
if (is_resource($this->output_file_stream) || get_resource_type($this->output_file_stream) === 'file') {
fclose($this->output_file_stream);
}
if (file_exists($destinationFile)) {
@unlink($destinationFile);
}
if (file_exists($file_path)) {
@unlink($file_path);
}
// Return empty for new file
return [
'index' => 0,
'insert' => 'no',
'completed' => 'yes'
];
}
} else {
// Log partial progress
$this->logPartial($dir, $table_name);
// Open new stream for new output file
$this->output_file_stream = fopen($destinationFile, 'a+');
// Generate new heading
$heading = $this->generateNewHeading($table_unique, $table_name);
// Put the heading into new file
$this->insertIntoOutputFile($heading, $table_name);
// Technically only few bytes but with 200 tables it may be few MBs :)
// Always unset variables if you don't need them anymore
unset($heading);
}
if (!$this->isCLI) {
// Check if the output file is open and close it if it is
$file = null;
if (is_resource($this->output_file_stream) || get_resource_type($this->output_file_stream) === 'file') {
fclose($this->output_file_stream);
}
// Return latest insert query
return [
'index' => $i,
'insert' => ($insert_next == true ? 'yes' : 'no'),
'file' => $file_path,
'table_name' => $table_name,
'dir' => $dir,
'unique' => $table_unique,
'destinationFile' => $destinationFile
];
}
} else {
// Log partial progress
$this->logPartial($dir, $table_name);
}
// Continue to new line as we handled this one already
continue;
}
}
// Handle Custom Variables ending comment
if ($line === $cq_e) {
// Adjust local variables for next loops
$custom_vars_started = false;
}
// Handle values ending
if ($line === $v_e) {
// Adjust local variables for next loops
$values_started = false;
// If it's after heading add this line into new output file
if ($insert_next) {
// Add new line as we trimed it before
$line .= "\n";
// Insert that line into new file
$this->insertIntoOutputFile($line, $table_name);
// As we added the line continue to new one
continue;
}
}
}
// Check if the line is not a comment
if (!$hasComment) {
// If the line should be a part of query handle that case
if ($query_started === true) {
// If it's after heading allow to add this line to new output file
if ($insert_next) {
// Add new line as we trimed it earlier
$line .= "\n";
// Insert the line into new file
$this->insertIntoOutputFile($line, $table_name);
// As we added that line continue to new one
continue;
}
}
// Handle custom variables
if ($custom_vars_started === true) {
// We are interested only into PRE TABLE NAME which contains unique timestamp
if (strpos($line, 'PRE_TABLE_NAME')) {
// Prepare variable for preg match output
$output = [];
// Run the preg match function to find the
preg_match('/\`(.*)\`/', $line, $output);
// Get the unique value from regex output
$unique = substr($output[1], 0, 10);
// Set the local variable to found unique for future use in the heading
$table_unique = $unique;
// As we went throught old heading let the script know that it can insert new lines in next loops
$insert_next = true;
// Prepare new heading for file which will be used in next loops
$heading = $this->generateNewHeading($unique, $table_name);
// Insert that heading
$this->insertIntoOutputFile($heading, $table_name);
}
}
// Handle casual variable line
if ($values_started === true) {
// If it can insert new output handle it
if ($insert_next) {
// Insert that line into new file
$this->insertIntoOutputFile($line, $table_name);
// Free up the memory as this line may be actually above few MBs.
unset($line);
// Continue to new line as we inserted this one already
continue;
}
}
}
// Free up the memory as this line may be actually above few MBs.
unset($line);
}
// $total_lines
// File size: $file->getSize() / 1024 / 1024
// Check if the output file is open and close it if it is
if (is_resource($this->output_file_stream) || get_resource_type($this->output_file_stream) === 'file') {
fclose($this->output_file_stream);
}
// If the file was already converted
if ($is_converted === false) {
// Empty the SplFileObject stream
$file = null;
// Remove new output file as there's nothing to do with it
@unlink($file_path);
} else {
// If the convert finished, remove source file as we now have splited files
@unlink($destinationFile);
}
// Empty SplFileObject stream
$file = null;
// Only if not CLI
if (!$this->isCLI) {
// Return empty process data as we will iterate new file in next batch
return [
'index' => 0,
'insert' => 'no',
'completed' => 'yes'
];
}
}
/**
* makeHeading - Generates new heading (converted) for output file
*
* @param {string/int} $unique Unique timestamp generated during backup (all tables have to be part of it)
* @param {string} $table_name Table name of current file, required to generate the heading
* @return {string} New heading
*/
private function generateNewHeading($unique, $table_name) {
$heading = '';
$heading .= "/* CONVERTED DB FILE */\n\n";
$heading .= "/* QUERY START */\n";
$heading .= "SET foreign_key_checks = 0;\n";
$heading .= "/* QUERY END */\n";
$heading .= "\n";
$heading .= "/* QUERY START */\n";
$heading .= "SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';\n";
$heading .= "/* QUERY END */\n";
$heading .= "\n";
$heading .= "/* QUERY START */\n";
$heading .= "SET time_zone = '+00:00';\n";
$heading .= "/* QUERY END */\n";
$heading .= "\n";
$heading .= "/* QUERY START */\n";
$heading .= "SET NAMES 'utf8';\n";
$heading .= "/* QUERY END */\n";
$heading .= "\n";
$heading .= "/* CUSTOM VARS START */\n";
$heading .= "/* REAL_TABLE_NAME: `" . $table_name . "`; */\n";
$heading .= "/* PRE_TABLE_NAME: `" . $unique . "_" . $table_name . "`; */\n";
$heading .= "/* CUSTOM VARS END */\n";
$heading .= "\n";
return $heading;
}
/**
* insertIntoOutputFile - Puts and output data into new (current) file
*
* @param {string} &$line Pointer to line, to save the memory
* @param {string} $table_name Table name, may be useful for future use
* @return void
*/
private function insertIntoOutputFile(&$line, $table_name) {
if (is_resource($this->output_file_stream) || get_resource_type($this->output_file_stream) === 'file') {
fwrite($this->output_file_stream, $line);
}
}
/**
* destinationFile - Makes unique destionation file name
*
* @param {string} $dir Full path to the SQL file
* @param {string} $table_name Name of the table to which SQL file belong
* @return {string} name of the destionation SQL file
*/
private function makeDestinationFilename($dir, $table_name) {
// Start from file number one
$i = 1;
// Make an assumption that it will be the first file
$file = $table_name . '_' . $i . '.sql';
// Loop until it find unqiue name
while (file_exists($dir . DIRECTORY_SEPARATOR . $file)) {
// Increment each iteration for new filename
$i++;
// Set new name to check
$file = $table_name . '_' . $i . '.sql';
}
// Return final file name
return ['file' => $dir . DIRECTORY_SEPARATOR . $file, 'index' => $i];
}
/**
*
* renameSplitedFiles - Renames all files after splitting into sorted SQL files
* It also gives better progress experience for the user
*
* @param {string} $directory Path to directory where the rename function should run
* @return void
*/
private function renameSplitedFiles($directory) {
// Scan all files after splitting
$allFiles = scandir($directory);
$files = array_diff($allFiles, array('.', '..'));
// Loop throught them and add proper number for each
foreach ($files as $index => $filename) {
// Make new destination name
$newName = substr($filename, 0, -4) . '_of_' . sizeof($files) . '.sql';
// Current file path
$file = $directory . DIRECTORY_SEPARATOR . $filename;
// Final path (after rename)
$finalPathWithName = $directory . DIRECTORY_SEPARATOR . $newName;
// Finally rename the file
rename($file, $finalPathWithName);
}
}
/**
* checkIfContainName - Checks if A (string) is part of B array
*
* @return bool
*/
private function checkIfContainName($tableName, $unwantedTables) {
$found = false;
$tableName = str_replace('-', '', $tableName);
$tableName = str_replace('_', '', $tableName);
$tableName = strtolower($tableName);
for ($i = 0; $i < sizeof($unwantedTables); ++$i) {
$name = $unwantedTables[$i];
$name = str_replace('-', '', $name);
$name = str_replace('_', '', $name);
$name = strtolower($name);
if (strpos($tableName, $name) !== false) {
$found = true;
break;
}
}
return $found;
}
/**
* moveAllConvertedTables - Moves all completed tables outside
*
* @return void
*/
private function moveAllConvertedTables() {
// Finished directory path
$finishedDBDir = $this->db_files_root . DIRECTORY_SEPARATOR . $this->name_of_finished_tables_dir;
// Check if it exists
if (!file_exists($finishedDBDir) || !is_dir($finishedDBDir)) {
return;
}
// Scan all tables in finished directory
$allFiles = scandir($finishedDBDir);
$files = array_diff($allFiles, array('.', '..'));
// Loop throught them and move outside
foreach ($files as $index => $filename) {
// Old path
$old = $this->db_files_root . DIRECTORY_SEPARATOR . $this->name_of_finished_tables_dir . DIRECTORY_SEPARATOR . $filename;
// New path
$new = $this->db_files_root . DIRECTORY_SEPARATOR . $filename;
// Move that directory to parent
rename($old, $new);
}
// Unlink directory that won't be used as it's (and it should) be empty.
if (file_exists($finishedDBDir) && is_dir($finishedDBDir)) {
@rmdir($finishedDBDir);
}
// Return void
return;
}
}