
Ich habe diese Website, auf der, wenn der Benutzer ein Formular absendet, ein Python-Skript über eine PHP-Seite ausgeführt wird. Das Python-Skript erstellt eine ZIP-Datei und sollte sie dem Benutzer über einen Link zum Download anbieten. Die Datei könnte riesig sein (einige GB).
Da ich auf einem Universitätsserver arbeite, bin ich strikt an deren Serverregeln und -funktionen gebunden. Hier ist das Problem:
Die Website ist in gespeichert /data/mywebsite
, das nur über begrenzten Speicherplatz verfügt. Natürlich gehört es, www-data
da es hauptsächlich über meinen Apache-Server zugänglich ist.
Mir wird 1 TB Speicher in angeboten /experimentdata/
, der NUR für einen einzigen, bestimmten Benutzer, sagen wir , ZUGÄNGLICH ist theuser
. Das liegt daran, dass dieser Ordner ein Samba-Mount ist, auf den nur eine einzige, bestimmte Benutzer-ID zugreifen kann.
Um die Datei in zu erstellen /experimentdata
, verwende ich einen Befehl, der die Datei als Benutzer sudo -u theuser
erstellt . Jetzt ist mein Problem: Wie kann ich diese Datei über einen Link zum Download über Apache anbieten?/experimentdata/downloadme.zip
theuser
Ich habe überlegt, einen symbolischen Link zu verwenden, den ich beispielsweise einfüge /data/mywebsite/download/downloadme.zip
. Das Problem dabei ist, dass der Benutzer www-data
absolut keine Berechtigung hat, die Datei zu lesen!
Wie kann ich dem Benutzer ermöglichen, die Datei /experimentdata/downloadme.zip
mit dem Benutzer www-data
über den Benutzer herunterzuladen theuser
?
Ich möchte ausdrücklich darauf hinweisen, dass das Einbinden sudo -u theuser
absolut in Ordnung ist. Ich weiß jedoch nicht, wie ich daraus einen Link zu einem Ort außerhalb meines Website-Ordners erstellen kann.
PS: Wenn Sie weitere Informationen benötigen, fragen Sie bitte nach.
Antwort1
Ich denke, das Beste ist, dass Ihr php
/ python
die Daten direkt zurückgibt, anstatt apache
. Ihr Code kann dasselbe tun, was apache
. Meiner Erfahrung nach ist das viel besser, als ein anderes Verzeichnis zu öffnen und/oder zu verwenden sudo
oder die Dateiberechtigungen für zu ändern apache
usw.
Wenn das Programm die große Datei schneller erstellt als die Internetverbindung, können Sie die Daten direkt aus Ihrem Programm streamen, wodurch die zusätzliche Datendatei und der Code zu ihrer Verwaltung sowie die Mechanismen zu ihrer Speicherung entfallen.
Diese Antwort auf Stack Overflow zeigt, wie der Code in funktioniert php
.https://stackoverflow.com/a/4357904/5484716.
Eliminieren Sie bei Programmen, die auf diese Weise aufgerufen werden, die gesamte stderr
Stream-Ausgabe und stellen Sie sicher, dass der Rückgabecode Ihres Python-Prozesses den Erfolg oder Misserfolg des Prozesses genau widerspiegelt.
Die folgenden Beispiele zeigen die popen()
Aufrufe, die Sie im obigen Beispielszenario von Stackoverflow verwenden würden. Ich habe exec 2>/dev/null;
dem Shell-Befehl vorangestellt. Dadurch wird sichergestellt, dass keine Ausgabe an den Standardfehler geht, auch nicht von der Shell selbst, da eingehende Daten sowohl auf stderr
als auch stdout
eine Quelle von Deadlocks mit sein können popen()
.
Wenn Sie die Disk-Datei für Ihren Benutzer herunterladen möchten:
$fp = popen('exec 2>/dev/null; sudo -u theuser cat yourfile.zip', 'r');
Wenn Sie die Daten aus dem aktiven Prozess herunterladen möchten:
$fp = popen('exec 2>/dev/null; sudo yourpythonscript arg argN', 'r');
Diese BefehlszeilenSindShell-Befehle und müssen für Shell-Metazeichen entsprechend in Anführungszeichen gesetzt werden.
Bei der zweiten Methode würde der Server sofort mit dem Senden der Daten beginnen. Wenn der Benutzer das Formular erfolgreich absendet, wird ihm in seinem Browser sofort ein „Speichern unter“-Dialog angezeigt. Sobald der Benutzer die Ausgabedatei auswählt, php
überträgt Ihr Skript die Daten direkt über die Leitung in die Remote-Datei.
Das python
Skript sollte druckennurdie Zip-Daten auf der Standardausgabe und gibt einen Exit-Code zurück, der den Erfolg oder Misserfolg des Zip-Vorgangs genau wiedergibt. Im python
Skript sollte die Ausgabe sys.stdout
beispielsweise auf geschrieben werden zf = ZipFile(sys.stdout, ...
.
pclose()
Es ist wichtig , den Rückgabewert aufzurufen und zu überprüfen, denn nur so können Sie feststellen, ob das Zip erfolgreich war oder nicht. Wenn pclose()
etwas anderes als 0 zurückgegeben wird, stimmt etwas nicht.
Wie die Datei vom Client behandelt wird, hängt von den folgenden response headers
und anderen Einstellungen ab: content-type:
, content-encoding:
, und content-disposition:
Siehe:http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html, sehen Sie sich die response-header
und die entity-header
Informationen an.