In a Laravel (PHP framework) project, we implemented a backup feature - backing up user-generated files and database tables. What we've searched so far, the best solution in backing up mysql database is to run the mysqldump
command.
So we made the command:
<?php
$storage_path = 'path/to/backups';
$database = env('DB_DATABASE');
$user = env('DB_USERNAME');
$pass = env('DB_PASSWORD');
$host = env('DB_HOST');
$dir_file = "{$storage_path}/{now()->timestamp}-database.sql.gzip";
$backup_cmd = "mysqldump --user={$user} --password={$pass} --host={$host} {$database} | gzip > {$dir_file}";
// Run the command and take the backup.
exec( $backup_cmd, $output, $mysql_backup_status );
In our MS Windows development environment, we got the errors:
dump($output);
array(
"'mysqldump' is not recognized as an internal or external command",
"operable program or batch file."
)
The issue is, path to mysqld
or mysqldump
is not in the system PATH. After adding the path to PATH and restarting the system the command works fine and take backup.
To make the solution cross-platform-friendly we took an initiative to check whether the command mysqldump
is available or not, if not we'll gonna take the path to mysqldump.exe
from the user.
And with user input we will change the command like below:
// Check default way - the PATH.
exec( 'mysqldump --version 2>&1', $output, $return_val );
if( $return_val != 0 ) {
//mysqldump in undefined, so get the user defined path to it
$path = "C:\laragon\bin\mysql\mysql-5.7.19-winx64\bin"; //get as user input
$mysqldump = "{$path}\mysqldump.exe";
} else {
$mysqldump = 'mysqldump';
}
$backup_cmd = "{$mysqldump} --user={$user} --password={$pass} --host={$host} {$database} | gzip > {$dir_file}";
// Run the command and take the backup.
exec( $backup_cmd, $output, $mysql_backup_status );
With this measure the code is working well in both the cases:
mysqldump
is in PATHmysqldump
is in NOT in PATH
In our mini test unit it worked. But I wonder:
Is it a balanced way of doing this?
Means, the workaround we did (with all the UI/UX, unwanted trailing slash removal, using ofexec()
etc.) to simply check how we can runmysqldump
without glitch - are we doing good? Or, simply making an easy thing critical?Is the code cross-OS-friendly?
PS:
We're checking --version
but finally executing backup command, because running backup command for testing executes it even with PHP system()
function, and create a backup file, and we don't want that. We took exec()
over system()
as it's $output
and $return_value
seemed more reliable and silent than of system()
.
Edit
With the answer by baot a good point came into view, the unescaped user-provided data into exec()
command. I's aware about it, but finally forgot it to escape.
I now escaped the user input with escapeshellarg()
before using 'em into the exec()
:
// escape unwanted shell command
$mysqldump = escapeshellarg($mysqldump);
$backup_cmd = "{$mysqldump} --user={$user} --password={$pass} --host={$host} {$database} | gzip > {$dir_file}";