I have this website, where if the user submits a form, a python script is executed through a php page, and the python script creates a zip file and should offer it to the user for download through a link. The file could be huge (a few GB).
As I'm working on a university server, I'm strictly bound to their server rules and capabilities. Here's the problem:
The website is stored in /data/mywebsite
, which has limited diskspace. Of course this is owned by www-data
as it's mainly accessible by my Apache server.
I'm offered 1 TB storage in /experimentdata/
, which is ONLY ACCESSIBLE by a single, specific user, say theuser
. This is because this folder is a samba mount that can be accessed by a single and specific user-id.
To create the file in /experimentdata
, I use a sudo -u theuser
command that will create the file /experimentdata/downloadme.zip
as user theuser
. Now my problem is: How can I offer this file through a link for download through Apache?
I thought of using a symbolic link that I put in, e.g., /data/mywebsite/download/downloadme.zip
. The problem with that is that the user www-data
has absolutely no permission to read the file!
How can I let the user download the file /experimentdata/downloadme.zip
with the user www-data
through the user theuser
?
I would like to explicitly say that involving sudo -u theuser
is absolutely fine. But I don't know how to make a link out of that to somewhere outside my website folder.
PS: If you require any additional information, please ask.
Best Answer
I think the thing to do is have your
php
/python
return the data directly instead ofapache
. Your code can do the same thing thatapache
does. In my experience this is much better than opening up another directory and/or usingsudo
, or changing file permissions forapache
, etc.If the program produces the large file faster than the internet connection, then you can stream the data directly from your program, which eliminates the extra data file and the code to manage it and the mechanisms to remember it.
This answer on Stack Overflow shows how the code works in
php
. https://stackoverflow.com/a/4357904/5484716.For programs that will be called this way, eliminate all
stderr
stream output and make sure the return code from your python process accurately reflects the success or failure of the process.The examples below show the
popen()
calls you would use in the above example scenario from stackoverflow. I've prependedexec 2>/dev/null;
to the shell command. This ensures that no output goes to stdandard error, even from the shell itself, because having data coming on bothstderr
andstdout
can be a source of deadlocks withpopen()
.If you want to download the disk file to your user:
If you want to download the data from the active process:
These command lines are shell commands and need to be quoted appropriately for shell meta characters.
In the second method, the server would begin sending the data immediately. When the user successfully submits the form, they immediately see a "save as" dialog from their browser. As soon as the user selects the output file, your
php
script transmits the data directly across the wire and into the remote file.The
python
script should print only the zip data on standard output, and return an exit code that accurately represents the success or failure of the zip process. Inpython
the script should write the output onsys.stdout
, for examplezf = ZipFile(sys.stdout, ...
.It is critical to call
pclose()
and check the return value, because that will be the only way you know if the zip succeeded or not. Ifpclose()
returns anything other than 0, something is wrong.How the file is handled by the client depends on the settings of these
response headers
and others:content-type:
,content-encoding:
, andcontent-disposition:
See: http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html, look at theresponse-header
and theentity-header
information.