I have to deal with a legacy project, where a PHP API creates a CSV export from MySQL and provides the file to download it later.
The problem is that the API can't copy the CSV file to the directory, from which it can be downloaded (through Apache)
The process goes like this:
- Someone clicks a button on a website to create a csv export.
- The API creates a SQL statement and executes it with shell_exec(mysql ...);
- The Database creates a CSV file with the data and puts it into /tmp/
- The API copies the file into a dedicated download directory for apache
- The API sends a mail with a download link to the user, who clicked the button.
Everything of the above works except step 4.
What I found in the API was:
$exportCommand = "mysql ....";
// mysqlExportTmpDir = /tmp
// mysqlExportTargetDirectory = download directory for apache
$moveExportFileCommand = "cp ".$this->mysqlExportTmpDir."/$filename ".$this->mysqlExportTargetDirectory;
shell_exec("( $exportCommand; $moveExportFileCommand; $sendNotificationCommand) &");
As I said the MySQL Command works, the mail notification works, but the cp command doesn't.
When I look into the logs I see this error:
cp: cannot stat '/tmp/610278f414d84.csv': No such file or directory
I also tried shell_exec("ls /tmp/*.csv");
to check if the older export files are visible to the API, but then I get this:
ls: cannot access '/tmp/*.csv': No such file or directory
There are definitely CSV files in there. Therefore I thought it might be a permission problem and tried to execute this in the terminal: sudo -u www-data cp /tmp/610274ad5a8a5.csv /path/to/api/download
. I copied the cp command from the logs, therefore it should be exactly the same.
That works. Now I'm confused because www-data runs Apache and with shell_exec("whoami") I also get www-data from the PHP API. Maybe the sudo -u www-data cp ...
command doens't work as I expected (I expected to have the same permissions as that user). But I don't know.
Does somebody know, why PHP can't access the csv Files in /tmp and copy them to a different directory?
The target directory belongs to the group www-data and files in there can be downloaded from a browser.
I know the approach to export data from a database is strange, but it seemed to work until a year ago. Now there is no one from this project in my company anymore and I don't know what changed.
sestatus
. What SE Linux does is add another layer of security on top of the basic Linux stuff like permissions. If the output includes the word,enforcing
in it, try to disable it by usingpermissive
mode like this:sudo setenforce permissive
. If the file copies then, you know it is an SE Linux issue. If not? You can re-enable SE Linux like this:sudo setenforce enforcing
. There are ways to have enforcing behavior and permit stuff like this. But that would need to be a fuller answer.shell_exec
being used at all in the code? Why not userename
which I the PHP version ofmv
orcp
on the command line? The command would be:rename($this->mysqlExportTmpDir."/'.$filename, $this->mysqlExportTargetDirectory."/'.$filename);
In general, one should avoid usingshell_exec
in PHP and use native functions likerename
instead.rename(/tmp/6103ae729858b.csv): failed to open stream: No such file or directory
, but the file exists, when I typefile /tmp/6103ae729858b.csv
into the terminal. I also tried to chown www-data on that file. Didn't help either. Permission are 666, when MySQL puts the files into that directory.