Tengo que lidiar con un proyecto heredado, donde una API PHP crea una exportación CSV desde MySQL y proporciona el archivo para descargarlo más tarde.
El problema es que la API no puede copiar el archivo CSV al directorio desde el cual se puede descargar (a través de Apache)
El proceso es el siguiente:
- Alguien hace clic en un botón de un sitio web para crear una exportación csv.
- La API crea una declaración SQL y la ejecuta con shell_exec(mysql...);
- La base de datos crea un archivo CSV con los datos y lo coloca en /tmp/
- La API copia el archivo en un directorio de descarga dedicado para Apache.
- La API envía un correo con un enlace de descarga al usuario que hizo clic en el botón.
Todo lo anterior funciona excepto el paso 4.
Lo que encontré en la API fue:
$exportCommand = "mysql ....";
// mysqlExportTmpDir = /tmp
// mysqlExportTargetDirectory = download directory for apache
$moveExportFileCommand = "cp ".$this->mysqlExportTmpDir."/$filename ".$this->mysqlExportTargetDirectory;
shell_exec("( $exportCommand; $moveExportFileCommand; $sendNotificationCommand) &");
Como dije, el comando MySQL funciona, la notificación por correo funciona, pero el comando cp no.
Cuando miro los registros veo este error:
cp: no se puede establecer '/tmp/610278f414d84.csv': no existe tal archivo o directorio
También intenté shell_exec("ls /tmp/*.csv");
verificar si los archivos de exportación más antiguos son visibles para la API, pero aparece esto:
ls: no se puede acceder a '/tmp/*.csv': no existe tal archivo o directorio
Definitivamente hay archivos CSV ahí. Por lo tanto, pensé que podría ser un problema de permisos e intenté ejecutar esto en la terminal: sudo -u www-data cp /tmp/610274ad5a8a5.csv /path/to/api/download
. Copié el comando cp de los registros, por lo tanto debería ser exactamente igual.
Eso funciona. Ahora estoy confundido porque www-data ejecuta Apache y con shell_exec("whoami") también obtengo www-data de la API de PHP. Quizás el sudo -u www-data cp ...
comando no funcione como esperaba (esperaba tener los mismos permisos que ese usuario). Pero no lo sé.
¿Alguien sabe por qué PHP no puede acceder a los archivos csv en/tmp y copiarlos a un directorio diferente?
El directorio de destino pertenece al grupo www-data y los archivos que contiene se pueden descargar desde un navegador.
Sé que el método para exportar datos desde una base de datos es extraño, pero parecía funcionar hasta hace un año. Ahora ya no hay nadie de este proyecto en mi empresa y no sé qué cambió.
Respuesta1
Hay un directorio tmp privado para Apache ubicado en /tmp/*apache2.service*/tmp
. Esto existe debido a la configuración de tmp privado en /lib/systemd/system/apache2.service
. encontré un pocoartículo aquí.
Cada vez que invoco copy(/tmp/....)
el script PHP, buscará en el directorio tmp privado específico de Apache. Apache no puede ver el contenido /tmp
con esta opción habilitada.
Por lo tanto, sólo puedo desactivar esta opción o hacer que MySQL descargue los archivos CSV en otro lugar.