Cross-platform MySQL database backup using mysqldump 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:

&lt;?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()-&gt;timestamp}-database.sql.gzip";

$backup_cmd = "mysqldump --user={$user} --password={$pass} --host={$host} {$database} | gzip &gt; {$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&gt;&amp;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 &gt; {$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 PATH
mysqldump 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 of exec() etc.) to simply check how we can run mysqldump 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 &gt; {$dir_file}";
Is the code cross-OS-friendly?

Sure it is working, but IMHO one should never use exec() especially in costumer software with user supplied data to it. I'am gueesing you have to logged in to a admin account but still it's a huge security risk. But if you insist on using it, you should at a minimum check that the user supplied path is a vaild path and do a md5 hash of mysqldump. 

I would just use a php native solution like mysqldump-php instead of using exec().

Is it a balanced way of doing this?

You have solved the problem in a simple way, so thats good. The only thing i can see as a hurdle is if you have costumers that isn't that tech savvy. it could be hard for them to find the correct path and/or knowing if mysqldump is installed.

could you flesh out this question further, i dont understand what you are asking? (cant comment yet)