From 60af8557320bab97108304ef873da91a61528b23 Mon Sep 17 00:00:00 2001 From: Yamilov Stepan Date: Thu, 29 Sep 2016 15:52:49 +0500 Subject: [PATCH 1/6] Add support for mysql 5.6.x. It will fix this warning: "Warning: Using a password on the command line interface can be insecure." --- Database/MySQL.php | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index 341dd2a..e55b421 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -57,11 +57,27 @@ public function __construct($params, $basePath) /* if user is set, we add authentification */ if ($params['db_user']) { - $this->auth = sprintf('-u%s', $params['db_user']); + $cnfFile = "[client]\n"; + $cnfPath = $basePath."mysql.cnf"; + $cnfParams['user'] = $params['db_user']; if ($params['db_password']) { - $this->auth = sprintf("--host=\"%s\" --port=\"%d\" --user=\"%s\" --password=\"%s\"", $params['db_host'], $params['db_port'], $params['db_user'], $params['db_password']); + $cnfParams = array_merge( + $cnfParams, + array( + "password" => $params['db_password'], + "host" => $params['db_host'], + "port" => $params['db_port'] + ) + ); } + + foreach ($cnfParams as $key => $value) { + $cnfFile .= "$key = \"$value\"\n"; + } + + $this->filesystem->dumpFile($cnfPath, $cnfFile, 0600); + $this->auth = sprintf("--defaults-extra-file=\"%s\" ", $cnfPath); } } From 8e231ee12e244882961dc15d4eabf47bf2ba752e Mon Sep 17 00:00:00 2001 From: Yamilov Stepan Date: Thu, 29 Sep 2016 22:36:46 +0500 Subject: [PATCH 2/6] Refactoring MySQL constructor. Now configuration file, that used for authorization, will be removed from backup dump. --- Database/MySQL.php | 80 +++++++++++++++++++++++++++++++++------------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index e55b421..b027aaa 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -12,37 +12,46 @@ class MySQL extends BaseDatabase { const DB_PATH = 'mysql'; - private $allDatabases; private $database; private $auth = ''; private $fileName; private $ignoreTables = ''; + private $params; /** * DB Auth. * - * @param array $params + * @param array $params * @param string $basePath */ public function __construct($params, $basePath) { parent::__construct($basePath); + $this->params = $params['mysql']; + } - $params = $params['mysql']; - $this->allDatabases = $params['all_databases']; - $this->database = $params['database']; - $this->auth = ''; - - if ($this->allDatabases) { + /** + * Prepare a database name and a file dump name for mysqldump command + */ + protected function prepareFileName() + { + if ($this->params['all_databases']) { $this->database = '--all-databases'; $this->fileName = 'all-databases.sql'; } else { - $this->fileName = $this->database.'.sql'; + $this->database = $this->params['database']; + $this->fileName = $this->database . '.sql'; } + } - if (isset($params['ignore_tables'])) { - foreach ($params['ignore_tables'] as $ignoreTable) { - if ($this->allDatabases) { + /** + * Prepare ignore tables attribute for mysqldump command + */ + protected function prepareIgnoreTables() + { + if (isset($this->params['ignore_tables'])) { + foreach ($this->params['ignore_tables'] as $ignoreTable) { + if ($this->params['all_databases']) { if (false === strpos($ignoreTable, '.')) { throw new \LogicException( 'When dumping all databases both database and table must be specified when ignoring table' @@ -50,24 +59,28 @@ public function __construct($params, $basePath) } $this->ignoreTables .= sprintf('--ignore-table=%s ', $ignoreTable); } else { - $this->ignoreTables .= sprintf('--ignore-table=%s.%s ', $this->database, $ignoreTable); + $this->ignoreTables .= sprintf('--ignore-table=%s.%s ', $this->params['database'], $ignoreTable); } } } + } - /* if user is set, we add authentification */ - if ($params['db_user']) { + /** + * Prepare mysql configuration file for connection + */ + protected function prepareConfigurationFile() + { + if ($this->params['db_user']) { + $cnfParams['user'] = $this->params['db_user']; $cnfFile = "[client]\n"; - $cnfPath = $basePath."mysql.cnf"; - $cnfParams['user'] = $params['db_user']; - if ($params['db_password']) { + if ($this->params['db_password']) { $cnfParams = array_merge( $cnfParams, array( - "password" => $params['db_password'], - "host" => $params['db_host'], - "port" => $params['db_port'] + "password" => $this->params['db_password'], + "host" => $this->params['db_host'], + "port" => $this->params['db_port'] ) ); } @@ -76,18 +89,39 @@ public function __construct($params, $basePath) $cnfFile .= "$key = \"$value\"\n"; } - $this->filesystem->dumpFile($cnfPath, $cnfFile, 0600); - $this->auth = sprintf("--defaults-extra-file=\"%s\" ", $cnfPath); + $this->filesystem->dumpFile($this->getConfigurationFilePath(), $cnfFile, 0600); + $this->auth = sprintf("--defaults-extra-file=\"%s\" ", $this->getConfigurationFilePath()); } } + /** + * Remove mysql configuration file from backup files + */ + protected function removeConfigurationFile() + { + $this->filesystem->remove($this->getConfigurationFilePath()); + } + + /** + * Gets mysql configuration file full path + * @return string + */ + protected function getConfigurationFilePath() + { + return $this->dataPath . "mysql.cnf"; + } + /** * {@inheritdoc} */ public function dump() { $this->preparePath(); + $this->prepareFileName(); + $this->prepareIgnoreTables(); + $this->prepareConfigurationFile(); $this->execute($this->getCommand()); + $this->removeConfigurationFile(); } /** From 209a6f79da71c77de12fe18456bf8e8b3eeada9c Mon Sep 17 00:00:00 2001 From: Stepan Yamilov Date: Wed, 12 Oct 2016 12:41:19 +0500 Subject: [PATCH 3/6] Rewrite MySQL tests for usage with configuration file --- Database/MySQL.php | 14 ++++++----- Tests/Database/MySQLTest.php | 46 ++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 21 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index b027aaa..07544d1 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -11,6 +11,7 @@ class MySQL extends BaseDatabase { const DB_PATH = 'mysql'; + const CONFIGURATION_FILE_NAME = 'mysql.cnf'; private $database; private $auth = ''; @@ -28,6 +29,11 @@ public function __construct($params, $basePath) { parent::__construct($basePath); $this->params = $params['mysql']; + + $this->preparePath(); + $this->prepareFileName(); + $this->prepareIgnoreTables(); + $this->prepareConfigurationFile(); } /** @@ -90,7 +96,7 @@ protected function prepareConfigurationFile() } $this->filesystem->dumpFile($this->getConfigurationFilePath(), $cnfFile, 0600); - $this->auth = sprintf("--defaults-extra-file=\"%s\" ", $this->getConfigurationFilePath()); + $this->auth = sprintf("--defaults-extra-file=\"%s\"", $this->getConfigurationFilePath()); } } @@ -108,7 +114,7 @@ protected function removeConfigurationFile() */ protected function getConfigurationFilePath() { - return $this->dataPath . "mysql.cnf"; + return $this->dataPath . static::CONFIGURATION_FILE_NAME; } /** @@ -116,10 +122,6 @@ protected function getConfigurationFilePath() */ public function dump() { - $this->preparePath(); - $this->prepareFileName(); - $this->prepareIgnoreTables(); - $this->prepareConfigurationFile(); $this->execute($this->getCommand()); $this->removeConfigurationFile(); } diff --git a/Tests/Database/MySQLTest.php b/Tests/Database/MySQLTest.php index bdca425..561b745 100644 --- a/Tests/Database/MySQLTest.php +++ b/Tests/Database/MySQLTest.php @@ -9,6 +9,15 @@ */ class MySQLTest extends \PHPUnit_Framework_TestCase { + protected function checkConfigurationFileExistsAndValid($user, $password, $host, $port) + { + $filePath = '/tmp/backup/mysql/mysql.cnf'; + $cnfFileContent = "[client]\nuser = \"$user\"\npassword = \"$password\"\nhost = \"$host\"\nport = \"$port\"\n"; + + $this->assertFileExists($filePath); + $this->assertContains(file_get_contents($filePath), $cnfFileContent); + } + /** * @test */ @@ -23,9 +32,11 @@ public function shouldDumpAllDatabases() 'db_user' => 'root', 'db_password' => 'test', ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), "mysqldump --host=\"localhost\" --port=\"3306\" --user=\"root\" --password=\"test\" --all-databases > '/var/backup/mysql/all-databases.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); + $this->assertFileExists('/tmp/backup/mysql/mysql.cnf'); + $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" --all-databases > '/tmp/backup/mysql/all-databases.sql'"); } /** @@ -42,7 +53,10 @@ public function shouldDumpSpecifiedDatabase() 'db_user' => 'root', 'db_password' => 'test', ), - ), '/var/backup/'); + ), '/tmp/backup/'); + + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); + $this->assertEquals($mysql1->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" dizbdd > '/tmp/backup/mysql/dizbdd.sql'"); $mysql2 = new MySQLDummy(array( 'mysql' => array( @@ -53,10 +67,10 @@ public function shouldDumpSpecifiedDatabase() 'db_user' => 'mysql', 'db_password' => 'somepwd', ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql1->getCommand(), "mysqldump --host=\"localhost\" --port=\"3306\" --user=\"root\" --password=\"test\" dizbdd > '/var/backup/mysql/dizbdd.sql'"); - $this->assertEquals($mysql2->getCommand(), "mysqldump --host=\"somehost\" --port=\"2222\" --user=\"mysql\" --password=\"somepwd\" somebdd > '/var/backup/mysql/somebdd.sql'"); + $this->checkConfigurationFileExistsAndValid('mysql', 'somepwd', 'somehost', '2222'); + $this->assertEquals($mysql2->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" somebdd > '/tmp/backup/mysql/somebdd.sql'"); // dump specified database with no auth $mysql = new MySQLDummy(array( @@ -68,9 +82,9 @@ public function shouldDumpSpecifiedDatabase() 'db_user' => null, 'db_password' => null, ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), 'mysqldump somebdd > \'/var/backup/mysql/somebdd.sql\''); + $this->assertEquals($mysql->getCommand(), 'mysqldump somebdd > \'/tmp/backup/mysql/somebdd.sql\''); } /** @@ -88,9 +102,9 @@ public function shouldDumpAllDatabasesWithNoAuth() 'db_user' => null, 'db_password' => null, ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), 'mysqldump --all-databases > \'/var/backup/mysql/all-databases.sql\''); + $this->assertEquals($mysql->getCommand(), 'mysqldump --all-databases > \'/tmp/backup/mysql/all-databases.sql\''); } /** @@ -108,9 +122,10 @@ public function shouldIgnoreSpecifiedTablesForSpecifiedDatabase() 'db_password' => 'test', 'ignore_tables' => array('table1', 'table2'), ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), "mysqldump --host=\"localhost\" --port=\"3306\" --user=\"root\" --password=\"test\" dizbdd --ignore-table=dizbdd.table1 --ignore-table=dizbdd.table2 > '/var/backup/mysql/dizbdd.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); + $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" dizbdd --ignore-table=dizbdd.table1 --ignore-table=dizbdd.table2 > '/tmp/backup/mysql/dizbdd.sql'"); } /** @@ -128,9 +143,10 @@ public function shouldIgnoreSpecifiedTablesForAllDatabase() 'db_password' => 'test', 'ignore_tables' => array('db1.table1', 'db2.table2'), ), - ), '/var/backup/'); + ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), "mysqldump --host=\"localhost\" --port=\"3306\" --user=\"root\" --password=\"test\" --all-databases --ignore-table=db1.table1 --ignore-table=db2.table2 > '/var/backup/mysql/all-databases.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); + $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" --all-databases --ignore-table=db1.table1 --ignore-table=db2.table2 > '/tmp/backup/mysql/all-databases.sql'"); } /** @@ -149,7 +165,7 @@ public function shouldThrowExceptionIfDatabaseIsNotSpecifiedForIgnoredTableDumpi 'db_password' => 'test', 'ignore_tables' => array('table1'), ), - ), '/var/backup/'); + ), '/tmp/backup/'); $mysql->getCommand(); } From 5bbc9d1a5cb7579a1900bcd89d3d768024a7d0dd Mon Sep 17 00:00:00 2001 From: Stepan Yamilov Date: Wed, 12 Oct 2016 12:51:57 +0500 Subject: [PATCH 4/6] rewrite array connection to avoid array merge function --- Database/MySQL.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index 07544d1..035cd31 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -81,13 +81,10 @@ protected function prepareConfigurationFile() $cnfFile = "[client]\n"; if ($this->params['db_password']) { - $cnfParams = array_merge( - $cnfParams, - array( - "password" => $this->params['db_password'], - "host" => $this->params['db_host'], - "port" => $this->params['db_port'] - ) + $cnfParams += array( + "password" => $this->params['db_password'], + "host" => $this->params['db_host'], + "port" => $this->params['db_port'] ); } From debfc1f90661438da3abc6f93c6bb6415f15ca1e Mon Sep 17 00:00:00 2001 From: Stepan Yamilov Date: Wed, 12 Oct 2016 13:55:37 +0500 Subject: [PATCH 5/6] Move environment configuration from constructor method to separate one and rewrite tests to use it. --- Database/MySQL.php | 17 ++++++++++++----- Tests/Database/MySQLTest.php | 14 +++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index 035cd31..682334f 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -29,11 +29,6 @@ public function __construct($params, $basePath) { parent::__construct($basePath); $this->params = $params['mysql']; - - $this->preparePath(); - $this->prepareFileName(); - $this->prepareIgnoreTables(); - $this->prepareConfigurationFile(); } /** @@ -114,11 +109,23 @@ protected function getConfigurationFilePath() return $this->dataPath . static::CONFIGURATION_FILE_NAME; } + /** + * Prepare all necessary configurations for mysqldump command + */ + protected function prepareEnvironment() + { + $this->preparePath(); + $this->prepareFileName(); + $this->prepareIgnoreTables(); + $this->prepareConfigurationFile(); + } + /** * {@inheritdoc} */ public function dump() { + $this->prepareEnvironment(); $this->execute($this->getCommand()); $this->removeConfigurationFile(); } diff --git a/Tests/Database/MySQLTest.php b/Tests/Database/MySQLTest.php index 561b745..63a5cfc 100644 --- a/Tests/Database/MySQLTest.php +++ b/Tests/Database/MySQLTest.php @@ -34,9 +34,8 @@ public function shouldDumpAllDatabases() ), ), '/tmp/backup/'); - $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); - $this->assertFileExists('/tmp/backup/mysql/mysql.cnf'); $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" --all-databases > '/tmp/backup/mysql/all-databases.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); } /** @@ -55,9 +54,9 @@ public function shouldDumpSpecifiedDatabase() ), ), '/tmp/backup/'); - $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); $this->assertEquals($mysql1->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" dizbdd > '/tmp/backup/mysql/dizbdd.sql'"); - + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); + $mysql2 = new MySQLDummy(array( 'mysql' => array( 'all_databases' => false, @@ -69,8 +68,8 @@ public function shouldDumpSpecifiedDatabase() ), ), '/tmp/backup/'); - $this->checkConfigurationFileExistsAndValid('mysql', 'somepwd', 'somehost', '2222'); $this->assertEquals($mysql2->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" somebdd > '/tmp/backup/mysql/somebdd.sql'"); + $this->checkConfigurationFileExistsAndValid('mysql', 'somepwd', 'somehost', '2222'); // dump specified database with no auth $mysql = new MySQLDummy(array( @@ -124,8 +123,8 @@ public function shouldIgnoreSpecifiedTablesForSpecifiedDatabase() ), ), '/tmp/backup/'); - $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" dizbdd --ignore-table=dizbdd.table1 --ignore-table=dizbdd.table2 > '/tmp/backup/mysql/dizbdd.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); } /** @@ -145,8 +144,8 @@ public function shouldIgnoreSpecifiedTablesForAllDatabase() ), ), '/tmp/backup/'); - $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); $this->assertEquals($mysql->getCommand(), "mysqldump --defaults-extra-file=\"/tmp/backup/mysql/mysql.cnf\" --all-databases --ignore-table=db1.table1 --ignore-table=db2.table2 > '/tmp/backup/mysql/all-databases.sql'"); + $this->checkConfigurationFileExistsAndValid('root', 'test', 'localhost', '3306'); } /** @@ -175,6 +174,7 @@ class MySQLDummy extends MySQL { public function getCommand() { + $this->prepareEnvironment(); return parent::getCommand(); } } From b7a18354502fa850e757474a7327d6fd7b65a244 Mon Sep 17 00:00:00 2001 From: Stepan Yamilov Date: Wed, 12 Oct 2016 14:48:33 +0500 Subject: [PATCH 6/6] Rewrite MySQL configuration file formation. Rewrite file test to handle that some params may be missing. --- Database/MySQL.php | 24 ++++++++++++++---------- Tests/Database/MySQLTest.php | 12 +++++++++--- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/Database/MySQL.php b/Database/MySQL.php index 682334f..b2939d2 100644 --- a/Database/MySQL.php +++ b/Database/MySQL.php @@ -71,18 +71,22 @@ protected function prepareIgnoreTables() */ protected function prepareConfigurationFile() { - if ($this->params['db_user']) { - $cnfParams['user'] = $this->params['db_user']; - $cnfFile = "[client]\n"; - - if ($this->params['db_password']) { - $cnfParams += array( - "password" => $this->params['db_password'], - "host" => $this->params['db_host'], - "port" => $this->params['db_port'] - ); + $cnfFile = "[client]\n"; + $cnfParams = array(); + $configurationMapping = array( + 'user' => 'db_user', + 'password' => 'db_password', + 'host' => 'db_host', + 'port' => 'db_port', + ); + + foreach ($configurationMapping as $key => $param) { + if ($this->params[$param]) { + $cnfParams[$key] = $this->params[$param]; } + } + if (!empty($cnfParams)) { foreach ($cnfParams as $key => $value) { $cnfFile .= "$key = \"$value\"\n"; } diff --git a/Tests/Database/MySQLTest.php b/Tests/Database/MySQLTest.php index 63a5cfc..a93f209 100644 --- a/Tests/Database/MySQLTest.php +++ b/Tests/Database/MySQLTest.php @@ -12,7 +12,11 @@ class MySQLTest extends \PHPUnit_Framework_TestCase protected function checkConfigurationFileExistsAndValid($user, $password, $host, $port) { $filePath = '/tmp/backup/mysql/mysql.cnf'; - $cnfFileContent = "[client]\nuser = \"$user\"\npassword = \"$password\"\nhost = \"$host\"\nport = \"$port\"\n"; + $cnfFileContent = "[client]\n"; + $cnfFileContent .= $user ? "user = \"$user\"\n" : ""; + $cnfFileContent .= $password ? "password = \"$password\"\n" : ""; + $cnfFileContent .= $host ? "host = \"$host\"\n" : ""; + $cnfFileContent .= $port ? "port = \"$port\"\n" : ""; $this->assertFileExists($filePath); $this->assertContains(file_get_contents($filePath), $cnfFileContent); @@ -83,7 +87,8 @@ public function shouldDumpSpecifiedDatabase() ), ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), 'mysqldump somebdd > \'/tmp/backup/mysql/somebdd.sql\''); + $this->assertEquals($mysql->getCommand(), 'mysqldump --defaults-extra-file="/tmp/backup/mysql/mysql.cnf" somebdd > \'/tmp/backup/mysql/somebdd.sql\''); + $this->checkConfigurationFileExistsAndValid(null, null, 'somehost', '2222'); } /** @@ -103,7 +108,8 @@ public function shouldDumpAllDatabasesWithNoAuth() ), ), '/tmp/backup/'); - $this->assertEquals($mysql->getCommand(), 'mysqldump --all-databases > \'/tmp/backup/mysql/all-databases.sql\''); + $this->assertEquals($mysql->getCommand(), 'mysqldump --defaults-extra-file="/tmp/backup/mysql/mysql.cnf" --all-databases > \'/tmp/backup/mysql/all-databases.sql\''); + $this->checkConfigurationFileExistsAndValid(null, null, 'somehost', '2222'); } /**