Zugriff auf Dateien ohne htacess blockieren?
__pat__
- php
Hallo zusammen,
Ich möchte auf meinem Server eine Dateiablage machen. Diese sollte nur verfügbar sein, wenn man im Loginbereich ist. Wenn nun eine angemeldete Person diese Datei herunterladen möchte, was ja dann via Adresszeile (Link) passiert, sollte dies ohne Abfrage von htaccess passieren. Wenn eine Person von aussen die Adresse der Datei in die Adresszeile eingibt, so sollte diese nicht verfügbar sein.
Kann ich den Zugriff irgendwie verbieten, ohne das Passwort von htaccess eingeben zu müssen? Kann das Script den htaccess für eine IP eingeben oder sowas?
Vielen Dank für eure Hilfe!
pat
Ich habe diese Frage ebenfalls auf:
http://www.tutorials.de/forum/hosting-webserver/357596-textdatei-auf-server-schuetzen.html#post1865629
gestellt. Allerdings ist sie dort fehl am Platz (thema veraltet)!
Hi!
Ich möchte auf meinem Server eine Dateiablage machen. Diese sollte nur verfügbar sein, wenn man im Loginbereich ist.
Du hast diese beiden Möglichkeiten:
Lo!
Danke für deine rasche Antwort
- Ein Download-Script, dass auf irgendeine Weise die Berechtigung prüft und die geforderte Datei durchreicht. Dabei darf die Datei nicht anderweitig erreichbar sein, sollte also am besten außerhalb eines DocumentRoot liegen oder als Notlösung mit verbotenem Web-Zugriff konfiguriert sein.
Wie würde das Script dann aussehen, finde es eine gute Möglichkeit, wüsste aber nicht, wie das zu realisieren wäre, ohne dass die Datei von aussen erreichbar ist. Wäre mega cool, wenn du es mir genauer erklären könntest.
Gruss
pat
Hi!
Wie würde das Script dann aussehen, finde es eine gute Möglichkeit, wüsste aber nicht, wie das zu realisieren wäre, ohne dass die Datei von aussen erreichbar ist. Wäre mega cool, wenn du es mir genauer erklären könntest.
Es wäre megacool, wenn du zunächst erst einmal die Suchmaschine deiner Wahl nach php download script befragen würdest. Denn da waren schon Heerscharen vor dir mit dem Problem beschäftigt. Wenn du dann noch Fragen hast, kannst du sie ja hier stellen.
Das nicht so leicht Verständliche ist, seinen Platz beim Hoster so zu konfigurieren, dass man Platz bekommt, der nicht übers Web erreichbar ist, also außerhalb des/der DocumentRoots liegt. Hier muss der Hoster mitspielen, was aber im Prinzip bei allen Hostern mit mehreren Domains pro Hostingpaket einzurichten gehen muss. Zur Aufteilung der Verzeichnisse siehe </archiv/2009/4/t185288/#m1229257>.
Lo!
Hallo
Es wäre megacool, wenn du zunächst erst einmal die Suchmaschine deiner Wahl nach php download script befragen würdest. Denn da waren schon Heerscharen vor dir mit dem Problem beschäftigt. Wenn du dann noch Fragen hast, kannst du sie ja hier stellen.
Ich bin absolut deiner Meinung, zuerst Suchmaschinen zu benützen, was ich auch getan habe. Allerdings ist wohl mit den falschen Suchwörtern gesucht. Habe nach "zugriff auf dateien auf server schützen" gesucht, was natürlich nicht sehr ergiebig war bzw. nicht mein Problem anspricht. Ich danke dir aber, dass du dir trotzdem die Mühe gemacht hast und geantwortet hast.
lg
pat
Hallo
Es wäre megacool, wenn du zunächst erst einmal die Suchmaschine deiner Wahl nach php download script befragen würdest. Denn da waren schon Heerscharen vor dir mit dem Problem beschäftigt. Wenn du dann noch Fragen hast, kannst du sie ja hier stellen.
Ich bin absolut deiner Meinung, zuerst Suchmaschinen zu benützen, was ich auch getan habe. Allerdings ist wohl mit den falschen Suchwörtern gesucht. Habe nach "zugriff auf dateien auf server schützen" gesucht, was natürlich nicht sehr ergiebig war bzw. nicht mein Problem anspricht. Ich danke dir aber, dass du dir trotzdem die Mühe gemacht hast und geantwortet hast.
lg
pat
Das erste was du hierzu wissen musst ist wie du ein Loginsystem baust, und wie du verhinderst, dass ein Benutzer welcher nicht eingeloggt ist eine bestimmte Seite nicht angezeigt bekommt. Aus dem Eingangspost lese ich heraus, dass du so etwas bereits gebaut hast.
Außerdem solltest du wissen wie du mit PHP eine Datei öffnen kannst und aus ihr lesen (ohne Include).
Nun erstellst du eine PHP Datei und suchst dir für den Anfang ein einfaches Bild. Die beiden Dateien kopierst du erst einmal in den selben Ordner. Nun musst du mit dem PHP Skript das Bild wie eine Textdatei öffnen und gibst das mit echo aus.
Wenn du nun mit dem Browser die PHP Datei aufrufst müsstest du eine Reihe von wirren Zeichen sehen. Das ist soweit korrekt, da der Webserver deinen Browser mitteilt das dieser Text HTML ist. Dies ist natürlich falsch, aber das weiß der Webserver auch nicht, daher musst du es dem Browser selbst mitteilen. Hierzu benutzt du folgende Funktion: header();
Mit dieser kannst du die Antworten des Webservers selber manipulieren. Nun sagst du dem Browser dass es sich hierbei um ein Bild handelt. Dazu musst du wissen wie der Mimetype einer Datei aussieht. Hierzu empfehle ich Google oder SELFHTML (http://de.selfhtml.org/diverses/mimetypen.htm)
Rufst du nun die Seite auf wirst du dein Bild sehen.
Wenn du nun die PHP Datei noch so erweiterst, dass man wenn man eingeloggt ist einen Text angezeigt bekommt "Bitte einloggen". Ist dein Skript fast fertig. Nun musst du nur noch dafür sorgen, dass man das Bild nicht über einen direkten Aufruf anzeigen kann. Hierzu verschiebst du das Bild in einen Ordner auf den Besucher keinen Zugriff haben und passt das PHP Skript nun an.
Den Rest schaffst du nun alleine denke ich. Wenn nicht Google ist dein Freund:
http://www.php-faq.de/q-datei-download.html
Die Überprüfung auf einen autorisierten Benutzer musst du selber einbauen.
Hi!
Außerdem solltest du wissen wie du mit PHP eine Datei öffnen kannst und aus ihr lesen (ohne Include).
[...] Nun musst du mit dem PHP Skript das Bild wie eine Textdatei öffnen und gibst das mit echo aus.
readfile() ist dafür besser geeignet.
Lo!
Hello,
readfile() ist dafür besser geeignet.
Das ist aber nett geworden im Manual. Unter "Example #1 Forcing a download using readfile()" ist ja auch genau das Beispiel, das pat benötigt und das ich eigentlich unter header() vermutet hatte...
Ich sollte das Manual von Zeit zu Zeit mal wieder lesen. Da hat sich viel getan :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
Das ist aber nett geworden im Manual. Unter "Example #1 Forcing a download using readfile()" ist ja auch genau das Beispiel, das pat benötigt und das ich eigentlich unter header() vermutet hatte...
Allerdings habe ich schon die ganze Zeit darüber nachgedacht, welchen praktischen Nutzen das jetzt haben soll, dass dort
ob_clean();
flush();
eingesetzt wird, _nachdem_ die Header gesetzt wurden. Und auch der Einsatz von file_exists() ist nicht ganz sauber.
Das sollte mMn besser so aussehen. Wenn schon ein Output-Buffering durchgeführt wurde, hat der Programmierer sowieso den Plan verloren. Aber so ist es mMn logischer.
#if (ob_get_level() == 0 and !headers_sent()) ## dachte ich erst, aber OB kann
## ja noch geschachtelt werden
ini_set('track_errors', 1);
if (!headers_sent())
{
ob_start();
if (false !== ($len == @readfile($file))) ## File in den neuen OB laden
{
## Nur bei Erfolg Header ausgeben
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $len);
ob_end_clean();
exit; ## alle anderen OBs werden geschlosen
## und weggeschmissen?
}
else
{
## ## Fehlerbehandlung, Ausgabe oder Logging...
## echo $php_errormsg; ## hierfür ist 'track_errors = 1' notwendig
##
}
ob_end_clean();
}
Somit müsste sowohl das TOCTOU-Problem als auch das Senden von falschen Headern für den Fall, dass keine Datei da ist, oder diese nicht lesbar ist, gelöst sein.
Mir ist im Moment die Wirkung von exit auf gestaffelte OBs noch nicht sicher klar...
Werden die offenen OBs bei exit alle weggeschmissen?
Wie ist Eure Meinung dazu?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
ini_set('track_errors', 1);
if (!headers_sent())
{
ob_start();
if (false !== ($len == @readfile($file))) ## File in den neuen OB laden
{
## Nur bei Erfolg Header ausgeben
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $len);
#> ob_end_clean();
ob_end_flush();
exit; ## alle anderen OBs werden geschlosen
## und weggeschmissen?
}
else
{
## ## Fehlerbehandlung, Ausgabe oder Logging...
## echo $php_errormsg; ## hierfür ist 'track_errors = 1' notwendig
##
}
#> ob_end_clean();
ob_end_flush();
}
*ups*. Der Buffer sollte ausgegeben und nicht weggeschmissen werden...
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo,
Nun ist mir klar...Wie ich eine Datei lese wusste ich auch, mir war allerdings nicht klar, dass ich mit php ein Bild einfach so öffnen kann, obwohl es ja auch mit Zeichen (binär oder hexadezimal?) codiert ist. Was ein Mimetyp ist wusste ich auch ungefähr. Dass das mit header etc. so funktioniert kam ich aber beim Besten willen nicht drauf. Das obige script muss ich mir noch genauer anschauen, ich denke, ich werde es verstehen. Die Dateien kann ich ja einfach in ein anderes Verzeichnis im html Ordner legen und den mit htaccess schützen. Die Einstellungen von htaccess zählen auch für die Unterordner oder?
Vielen Dank an aller für eure aktive Teilnahme! Hilft mir sehr!
lg
pat
Hello,
Die Dateien kann ich ja einfach in ein anderes Verzeichnis im html Ordner legen und den mit htaccess schützen. Die Einstellungen von htaccess zählen auch für die Unterordner oder?
Das ginge. Aber probier doch erstmal, ob Du mit PHP auf das Verzeichnis "files" zugreifen darfst und ob Du per HTTP wirklich NICHT darauf zugreifen darfst.
Dazu musst Du do nur mal eine kleine Textdatei dort hineinlegen und dan in deinem Script, dass unter
|
+--files
| |
| +---datei1.txt
| +---datei2.txt
|
+--html
| |
| +---list.php
+---download.php
<?php ###download.php###
error_reporting (E_ALL);
readfile('../files/datei1.txt');
?>
Wenn das dann klappt und keine Fehlermeldung kommt, dann kannst Du die Files doch im Verzeichnis 'files' ablegen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Das ginge. Aber probier doch erstmal, ob Du mit PHP auf das Verzeichnis "files" zugreifen darfst und ob Du per HTTP wirklich NICHT darauf zugreifen darfst.
Wie auch, html ist der oberste Ordner nach dem Homepagename, also nicht
www.example.ch/html/test.php sondern
www.example.ch/test.php
Wie sollte ich nun auf /files zugreifen?
Wenn das dann klappt und keine Fehlermeldung kommt, dann kannst Du die Files doch im Verzeichnis 'files' ablegen.
Es klappt!
Liebe Grüße aus dem schönen Oberharz
Gruss auch aus der schönen Schweiz...und vielen herzlichen Dank!
Tom vom Berg
Patrick
Hello,
Es klappt!
Liebe Grüße aus dem schönen Oberharz
Gruss auch aus der schönen Schweiz...und vielen herzlichen Dank!
Bitte. Gerne geschehen.
Dann gibt es also wieder einen Provider mehr, der seine Virtual Hosts brauchbar einrichtet ;-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
habe darüber nochmal etwas länger nachgedacht und so ergab sich diese Funktion für den Download für Files. Ich bitte um Diskussion.
<?php ### download.php ###
# Download-Funktion für beliebige Files
#
# Stand: 20100515-0821
#
# Author: Tom, bitworks@online.de
#
# Sinn: Nur dann Download starten, wenn noch keine Nutzlast-Übertragung
# stattgefunden hat. Die Headers dürfen noch nicht gesendet sein!
# Nur dann Download-Headers setzen, wenn das File wirklich lesbar war
# Vermeidung des TOCTOU-Problemes, das bei "if (file_exists())" enstehen würde
# Abfangen der Fehlermeldung von readfile()
#
# Nachteil: Das File muss in den Output-Buffer passen
#
#--------------------------------------------------------------------------------------------------
function download_file($filename)
{
if (!headers_sent())
{
ob_start(); ## neuen Puffer aufmachen
if (false !== ($len = readfile($filename))) ## File in den neuen OB laden und header
{ ## nur bei Erfolg Header ausgeben
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($filename));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $len);
ob_end_flush(); ## neuen Output-Buffer ausgeben
exit; ## alle anderen OBs werden geschlosen
## und weggeschmissen, Script beendet.
}
else
{
return ob_get_clean(); ## die Fehlermeldung von readfile() ausgeben
}
}
return "Headers already sent";
}
#===================================================================================================
# php main
#===================================================================================================
$error = download_file ('testdatei.txt');
# als Beweis dafür, dass die Fehlermeldung von readfile() wirklich eingefangen wird:
echo "Fehlermeldung: $error ENDE";
?>
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
habe darüber nochmal etwas länger nachgedacht und so ergab sich diese Funktion für den Download für Files. Ich bitte um Diskussion.
Zunächst: Ich bin ein Perlianer, nix PHP ;-)
Ein Problem deutest du in den Kommentaren bereits an:
if (false !== ($len = readfile($filename)))
Das kann bei größeren Dateien problematisch werden. Eine sequentielle Verarbeitung wäre besser.
$error = download_file ('testdatei.txt');
als Beweis dafür, dass die Fehlermeldung von readfile() wirklich eingefangen wird:
echo "Fehlermeldung: $error ENDE";
Solche Konstrukte halte ich für sehr unglücklich. download_file() beendet eigenständig die Verarbeitung, dass ist an zitierter Stelle nicht erkenntlich. Das ist natürlich eine Stilfrage, nicht der Funktionalität.
if (false !== ($len = readfile($filename)))
Das kann bei größeren Dateien problematisch werden. Eine sequentielle Verarbeitung wäre besser.
Darf ich fragen warum? Bin halt noch nicht so weit...
lg
patrick
Hello,
Das kann bei größeren Dateien problematisch werden. Eine sequentielle Verarbeitung wäre besser.
Nein, die wäre nicht besser, weil erst sichergestellt sein muss, dass die herunterzuladene Datei vollständig lesbar ist, bevor die Daownload-Header überhaupt gesetzt werden.
Es hat soch keinen Sinn, dem Client die Download-Header zu senden und dann keine (oder nur eine unvollständige) Datei hinterherzuschicken.
Darf ich fragen warum? Bin halt noch nicht so weit...
Weil manche Programmierer mit der vierten Dimension nicht umgehen können und daher die Probleme solange vereinfacehn, bis nur noch Schrott dabei herauskommt.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Das kann bei größeren Dateien problematisch werden. Eine sequentielle Verarbeitung wäre besser.
Nein, die wäre nicht besser, weil erst sichergestellt sein muss, dass die herunterzuladene Datei vollständig lesbar ist, bevor die Daownload-Header überhaupt gesetzt werden.
Nein, muss es nicht. Siehe unten.
Es hat soch keinen Sinn, dem Client die Download-Header zu senden und dann keine (oder nur eine unvollständige) Datei hinterherzuschicken.
Doch, diese sehr seltene Situation (mit verschmerzbaren Konsequenzen: der User kriegt ne Fehlermeldung, so what?) möchte man in Anbetracht der Gefahren liebend gerne in Kauf nehmen.
Darf ich fragen warum? Bin halt noch nicht so weit...
Weil manche Programmierer mit der vierten Dimension nicht umgehen können und daher die Probleme solange vereinfacehn, bis nur noch Schrott dabei herauskommt.
LOL. Du schreibst so erfrischend blumig. Hast du auch ne Tüte Inhalt dazu? Das wäre fantastique!
if (false !== ($len = readfile($filename)))
Das kann bei größeren Dateien problematisch werden. Eine sequentielle Verarbeitung wäre besser.
Darf ich fragen warum? Bin halt noch nicht so weit...
In Toms Funktion wird die Datei zunächst komplett in den Hauptspeicher geladen. Krasses Beispiel: Du stellst ein 2 Gigabyte Video der letzten Weihnachstfeier ins Netz. 2 Gigabyte RAM-Verbrauch für einen Prozess/Download sind ungünstig. Logisch, oder? Parallele Downloads würden die Problematik entsprechend vervielfachen. Womöglich könnte auch das PHP Memory-Limit betroffen sein. Letzteres dann pro Client und unter Vorbehalt! PHP ist nicht meine Welt.
Würde man die Datei sequentiell auslesen und ausgeben, hätte man dieses Problem nicht. Den Code dazu kann ich dir mangels PHP-Kenntnissen nicht sagen, sollte sich aber fix googlen lassen.
Womöglich ist das für dich auch nicht relevant, weil bei dir z.B. nur Dateien mit max. 300 KB in Frage kommen. Aber Tom bat ja um die grundsätzliche Bewertung seiner Funktion, daher mein Einwand.
Hello,
In Toms Funktion wird die Datei zunächst komplett in den Hauptspeicher geladen.
Klar. Darum habe ich diesen Nachteil ja auch erwähnt.
Man kann sicherlich auch ein anderes Speixchermanagement wählen, wenn dies erforderlich ist, also z.B. die Datei vorher in den Einflussbereich der Funktion kopieren, oder andere schöne Dinge, die das jeweilige OS und sein Filesystem hergeben.
Wichtig ist aber, dass der Download-Prozess erst sicherstellt, dass er vollständigen Lesezugriff auf dei Datei hat, bevor die Header gesendet werden. Alles andere wäre Schmuddelkram.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi,
Krasses Beispiel: Du stellst ein 2 Gigabyte Video der letzten >>Weihnachstfeier ins Netz. 2 Gigabyte RAM-Verbrauch für einen >>Prozess/Download sind ungünstig.
Wenn du grad von einer 2GB datei sprichst: Ist es möglich so eine Datei auszulasten. Sprich ich melde mich bei einem Gratis Online Speicher an, lade dort die Datei hoch. Mit dem Script würde ich dann die login.php Datei vom Speicher aufrufen, ihm die Informationen übergeben und dann den File herunterzuladen. Gibt es da eine Möglichkeit?
sry, wenn ich vom thema wegkomme.
lg
pat
Wenn du grad von einer 2GB datei sprichst: Ist es möglich so eine Datei auszulasten. Sprich ich melde mich bei einem Gratis Online Speicher an, lade dort die Datei hoch. Mit dem Script würde ich dann die login.php Datei vom Speicher aufrufen, ihm die Informationen übergeben und dann den File herunterzuladen. Gibt es da eine Möglichkeit?
Technisch möglich sein wird es, aber vermutlich gegen die AGB des Speicheranbieters verstoßen! Das bisschen Werbung solltest du ihm für das kostenlose Angebot auch gönnen ;-)
Hello,
$error = download_file ('testdatei.txt');
als Beweis dafür, dass die Fehlermeldung von readfile() wirklich eingefangen wird:
echo "Fehlermeldung: $error ENDE";
Solche Konstrukte halte ich für sehr unglücklich. download_file() beendet eigenständig die Verarbeitung, dass ist an zitierter Stelle nicht erkenntlich. Das ist natürlich eine Stilfrage, nicht der Funktionalität.
Das geht hier aber im Client-Server-Dialog nicht anders umd MUSS SO SEIN, dass keine weiteren Ausgaben mehr folgen.
Wenn im Script noch Dinge erledigt werden sollen, sollte man diese in die Shutdown-Funktion verlegen.
Das ist die von PHP im Rahmenprogramm vorgesehene Funktion.
Anders wird es echt kompliziert und unübrschaubar und man würde dem vorhandenen PHP-Rahmenwerk nochmals einen Rahmen einbauen...
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Das geht hier aber im Client-Server-Dialog nicht anders umd MUSS SO SEIN, dass keine weiteren Ausgaben mehr folgen.
Wer sagt denn, dass unbedingt der Client was gesagt bekommen soll?
Unüberschaubar und kompliziert sind gekapselte Funktionen, die einfach so "mein" Script beenden ;-)
<schnipp>
$error = download_file ('testdatei.txt');
if ($error) {
echo "Lieber User, leider ist etwas schief gegangen";
warn "Fehler beim Downloadscript: $error"
}
meinlogger();
meinwasweissich();
exit;
</schnipp>
Wenn im Script noch Dinge erledigt werden sollen, sollte man diese in die Shutdown-Funktion verlegen.
Das ist die von PHP im Rahmenprogramm vorgesehene Funktion.
Hmmm... Ich mag Scripte, die sich leicht lesen lassen.
Anders wird es echt kompliziert und unübrschaubar und man würde dem vorhandenen PHP-Rahmenwerk nochmals einen Rahmen einbauen...
Was spricht gegen obigen Vorschlag?
...Ich bitte um Diskussion.
Beim erneuten Lesen des Threads kamen mir da gerade Zweifel :-(
Hallo,
Sorry, dass ich wieder mal nachfragen muss, bin halt noch nicht so erfahren...=) Kann mir jemand ein Link geben, was alles für Argumente in header() möglich sind. Google hat mir nicht wirklich weitergeholfen.
Dann gibt es also wieder einen Provider mehr, der seine Virtual Hosts brauchbar einrichtet ;-)
WAS?!
Vielen herzlichen Dank!
lg
patrick
Hello,
Sorry, dass ich wieder mal nachfragen muss, bin halt noch nicht so erfahren...=) Kann mir jemand ein Link geben, was alles für Argumente in header() möglich sind. Google hat mir nicht wirklich weitergeholfen.
Ich habe nach Eingabe von "http response header" gleich als ersten Treffer diese Ressource bekommen:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
Bitte beachte, dass sie sowohl Request- als auch Response-Headers auflistet.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Ich habe nach Eingabe von "http response header" gleich als ersten Treffer diese Ressource bekommen:
Habe halt nach "php header()" gesucht, da ich mich gar nicht auskenne...
thx
pat
Hello,
Ich habe nach Eingabe von "http response header" gleich als ersten Treffer diese Ressource bekommen:
Habe halt nach "php header()" gesucht, da ich mich gar nicht auskenne...
Na, dann viel Spaß beim Lesen :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hier stehen einige Infos.
http://www.phpbar.de/w/Header
Na, dann viel Spaß beim Lesen :-)
Das kannst du laut sagen... melde mich in einer Woche wieder...;-)
Das, was in deinem Link steht, muss man nicht alles wissen, oder?
lg
pat
Hello,
Hier stehen einige Infos.
http://www.phpbar.de/w/HeaderNa, dann viel Spaß beim Lesen :-)
Das kannst du laut sagen... melde mich in einer Woche wieder...;-)
Das, was in deinem Link steht, muss man nicht alles wissen, oder?
Man sollte es zumindest einmal durchgelesen haben, wenn man PHP-Scripte schreibt. Viele Header davon setzt PHP ja schon automatisch, und ich finde, sogar ziemlich intelligent.
Schau Dir mal die Header an, die ein Browser so sendet und die PHP vom Server zurücksendet. Mit dem Live HTP Headers Plugin für den Firefox ist das ziemlicu bequem möglich.
https://addons.mozilla.org/en-US/firefox/addon/3829/
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi
Mit dem Live HTP Headers Plugin für den Firefox ist das ziemlicu bequem möglich.
Das werde ich mir mal anschauen, benutze eh firefox.
Danke
patrick
Hello,
noch einen Fehler gefunden...
ini_set('track_errors', 1);
if (!headers_sent())
{
ob_start();
if (false !== ($len = @readfile($file))) ## File in den neuen OB laden
# ---
{
## Nur bei Erfolg Header ausgeben
header('Content-Description: File Transfer');
header('Content-Type: application/octet-stream');
header('Content-Disposition: attachment; filename='.basename($file));
header('Content-Transfer-Encoding: binary');
header('Expires: 0');
header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
header('Pragma: public');
header('Content-Length: ' . $len);
ob_end_flush();
exit; ## alle anderen OBs werden geschlosen
## und weggeschmissen?
}
else
{
## ## Fehlerbehandlung, Ausgabe oder Logging...
## echo $php_errormsg; ## hierfür ist 'track_errors = 1' notwendig
##
}
ob_end_flush();
}
Kommt davon, wenn man an anderer Leute Code herumnörgelt :-)
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hello,
Wie würde das Script dann aussehen, finde es eine gute Möglichkeit, wüsste aber nicht, wie das zu realisieren wäre, ohne dass die Datei von aussen erreichbar ist. Wäre mega cool, wenn du es mir genauer erklären könntest.
Du möchtest also über HTTP auf Dateien zugreifen, die auf dem Filesystem des Webservers liegen. Dazu musst Du aus den Dateien ersteinmal HTTP-Ressourcen machen...
Am besten fängst Du vorne an:
Lege die Dateien außerhalb der Document Root im Filesystem des Webservers ab.
Gebe dem PHP-Prozess (lesenden) Zugriff auf die Verzeichnisse, in denen die Dateien liegen.
Bastel Dir eine Funktion, die ein solches Verzeichnis scannen kann und die Namen der (lesbaren) Dateien dem Browser anzeigen kann.
Mache aus der Anzeige der Namen valides HTML, z.B. eine formatierte Liste mit Links
scriptname.php?file=123
Wenn Du jetzt schon an Sicherheit denken willst, dann speicherst Du die Pfade der Dateien, die Du z.B. mit der Funktion glob() ausgelesen hast in einem Array in Deiner Session und lieferst jetzt nur einen Klartextnamen mit hintliegendem Link aus, wie ich ihn oben dargestellt habe. Das sorgt dafür, dass man nur auf Files zugreifen kann, die Du auch dafür freigegeben hast.
Wenn jetzt ein Request mit
http://example.org/scriptname.php?file=123
auf Deinem Webserver eintrifft, dann muss das Script scriptname.php wissen, dass es im Array in der Session nachgucken soll, ob unter dem Index 123 ein gültiger Pfad zu einer Datei eingetragen ist und diesen dann an die Ausgabefunktion weiterreichen.
Die Ausgabefunktion macht nichts anderes, als dass sie das File mittels
header('Content-Type: application/octet-stream');
readfile($path);
ausgibt...
Siehe hierzu die Benutzerkommentare von http://php.net/manual/de/function.header.php
In das von mir beschriebene Modell kannst Du nun leicht benutzerspezifische Zugriffsrechte einbauen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi Tom
Vielen Dank für die ausführliche Antwort. Ich verstehe dein Vorgehen im Grossen und Ganzen, jedoch ist mir nicht ganz klar wie die Datei ausgegeben wird. Das liegt wohl daran, dass ich die Funktion header() nicht kenne. Ich werde mich mal damit befassen und melde mich dann wieder.
Ist es richtig, dass nur die Dateien im Ordner html vom Browser erreicht werden können? Ich habe auf meinem Server 7 Ordner (html, .configs, atd, backup, files, log, phptmp, restore). Wenn ich die Dateien nun in den Ordner files (was mir am logisten erscheint) stecke, sind sie dann vom Browser aus nicht erreichbar?
Vielen Dank
lg
pat
Hello,
Vielen Dank für die ausführliche Antwort. Ich verstehe dein Vorgehen im Grossen und Ganzen, jedoch ist mir nicht ganz klar wie die Datei ausgegeben wird. Das liegt wohl daran, dass ich die Funktion header() nicht kenne. Ich werde mich mal damit befassen und melde mich dann wieder.
Ausgegeben wird die Datei dann duch readfile(). Mit Header sendet man dem Browser nur vorher einen HTTP-Header, der ihm sagt, dass da eine Datei (Applikation) kommt. Üblicherweise bietet der Browser dann seinem User den Öffnen mit/Downloaddialog an.
Ist es richtig, dass nur die Dateien im Ordner html vom Browser erreicht werden können? Ich habe auf meinem Server 7 Ordner (html, .configs, atd, backup, files, log, phptmp, restore). Wenn ich die Dateien nun in den Ordner files (was mir am logisten erscheint) stecke, sind sie dann vom Browser aus nicht erreichbar?
Was liegt denn Ordner "files"?
Wie sieht Deine Ausgabe der Konfiguration bei Verwendung der Funktion phpinfo() aus?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hi
Was liegt denn Ordner "files"?
Der Ordner ist leer.
Wie sieht Deine Ausgabe der Konfiguration bei Verwendung der Funktion phpinfo() aus?
Was meinst du genau mit der Konfiguration? Was für eine Einstellung?
Vielen Dank
lg
patrick
Wenn Du jetzt schon an Sicherheit denken willst, dann speicherst Du die Pfade der Dateien, die Du z.B. mit der Funktion glob() ausgelesen hast in einem Array in Deiner Session
Warum hältst du Sessions hier für einen guten Ort der Ablage? Mir fallen spontan nur Probleme ein: Was, wenn der Ordnerinhalt sich ändert? Redundanz...
Hello,
Wenn Du jetzt schon an Sicherheit denken willst, dann speicherst Du die Pfade der Dateien, die Du z.B. mit der Funktion glob() ausgelesen hast in einem Array in Deiner Session
Warum hältst du Sessions hier für einen guten Ort der Ablage? Mir fallen spontan nur Probleme ein: Was, wenn der Ordnerinhalt sich ändert? Redundanz...
Wenn der Ordnerinhalt sich ändert, ist die Datei eben nicht mehr da, wenn der Request zum Download kommt. Das fängt meine weiter unten skizzierte Lösung (nach der Vorlage im PHP-Manual, die tut das nicht wirklich...) ab.
Wenn eine Datei dazu gekommen ist seit dem letzten Listen, muss der User sowieso erst die Liste aktualisieren lassen. Dabei wird dann Verzeichnis-Array in der Session gelöscht und ein neues aufgebaut.
Der Eintrag in der Session ist praktisch, weil dadurch eine Transformation zur Entkopplung der wahren Dateipfade von den dem Browser gelieferten Ressourcennamen möglich ist. Es geht den Endbenutzer nämlich nichts an, wo die Dateien auf der Platte wirklich liegen bzw. wie sie vollständig heißen. Er soll sich mit einem Index oder Schlüssel zufriedengeben. Der könnte/sollte dann auch als Zufallszahl (und nicht als lfd. Nummer) ausgeführt werden, da es ja keine Verbindung zwischen Browserfenster und Sessiondatei gibt und leicht das gleiche Browserfenster mehrfach geöffnet sein könnte...
(Das könnte man mit einem Formular-Zertifikat abfangen.)
Man spart sich damit einen Filesystem-Scan, der ja zur Erstellung der Liste und zur Feststellung, ob die angeforderte Datei wirklich im erlaubten Verzeichnis liegt, sonst notwendig wäre.
Außerdem kann man bereits hier den Filter für die jeweiligen Benutzerrechte sehr einfach ansetzen.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo Tom
Der könnte/sollte dann auch als Zufallszahl (und nicht als lfd. Nummer) ausgeführt werden, da es ja keine Verbindung zwischen Browserfenster und Sessiondatei gibt und leicht das gleiche Browserfenster mehrfach geöffnet sein könnte...
Worauf willst du da hinaus? Die Benutzer dürfen die Filenames ja gerne erfahren, oder? Was heisst "lfd." ?
(Das könnte man mit einem Formular-Zertifikat abfangen.)
Man spart sich damit einen Filesystem-Scan, der ja zur Erstellung der Liste und zur Feststellung, ob die angeforderte Datei wirklich im erlaubten Verzeichnis liegt, sonst notwendig wäre.
Den Scan muss man ja trotzdem machen? Sorry, verstehe das nicht ganz.
Ich danke für die aktive Mithilfe! Selber wäre ich nie auf diese Lösung gekommen, da ich viele Möglichkeiten gar nicht kannte (header, readfile).
lg
patrick
Hello,
Der könnte/sollte dann auch als Zufallszahl (und nicht als lfd. Nummer) ausgeführt werden, da es ja keine Verbindung zwischen Browserfenster und Sessiondatei gibt und leicht das gleiche Browserfenster mehrfach geöffnet sein könnte...
Worauf willst du da hinaus? Die Benutzer dürfen die Filenames ja gerne erfahren, oder? Was heisst "lfd." ?
Die Benutzer sollten aber keine beliebigen Filenames vorgeben dürfen.
Machen wir es doch zum Verständnis mal anders herum:
Diese ganzen Prüfungen kann man sich sparen, wenn man die Selektion der für den Bentzer erlaubten Dateien (sessionbasierte Rechteverwaltung) in die Session einträgt. Dann kann der Benutzer nur Dateien anfordern, die ihm zustehen und nicht wild auf der Platte herumsurfen.
Das ist dann, wie schon erwähnt, eine sessionbasierte Rechteverwaltung. Wenn man eine requestbasierte Rechteverwaltung verwendet, sollte man es tatsächlich anders herum machen...
Unterschied ist, dass aufgrund der möglichen Dauer einer Session (bei meinfachen Systemen quasi ewig) von der Abfrage bis zum tatsächlichen Download der Datei die Rechte darauf geändert haben könnten.
Man muss also wissen, wie das eigene System arbeiten soll.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Warum hältst du Sessions hier für einen guten Ort der Ablage?
Wenn eine Datei dazu gekommen ist seit dem letzten Listen, muss der User sowieso erst die Liste aktualisieren lassen. Dabei wird dann Verzeichnis-Array in der Session gelöscht und ein neues aufgebaut.
Halten wir fest: Statt nur zu scannen und auszugeben, muss bei Ausgabe der Liste jedes mal das Scanergebnis zusätzlich in die Session gedumpt werden. Für jeden Client!
Der Eintrag in der Session ist praktisch, weil dadurch eine Transformation zur Entkopplung der wahren Dateipfade von den dem Browser gelieferten Ressourcennamen möglich ist...
Abseits der Frage, ob es sinnvoll ist: Es gibt viele Möglichkeiten, um von dir beschriebenes zu erreichen, das ist keine Frage des Speicherorts.
Man spart sich damit einen Filesystem-Scan, der ja zur Erstellung der Liste notwendig wäre.
Liest sich gut, stimmt aber nicht(siehe oben)!
und zur Feststellung, ob die angeforderte Datei wirklich im erlaubten Verzeichnis liegt, sonst notwendig wäre.
Dafür braucht es keinen Scan, sondern einen simplen Test.
Hello,
Dafür braucht es keinen Scan, sondern einen simplen Test.
Zeig mal bitte...
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Dafür braucht es keinen Scan, sondern einen simplen Test.
Zeig mal bitte...
Antworte zunächst mal bitte auf die anderen drei Einwände...
Hello,
Dafür braucht es keinen Scan, sondern einen simplen Test.
Zeig mal bitte...Antworte zunächst mal bitte auf die anderen drei Einwände...
Ok, mach ich, auch wenn das nicht die feine Art ist von Dir, hier Bedingungen zu stellen. Aber so
bist Du sicherlich bereit dazu, nochmals These und Antithese zusammenzufassen, damit dann alles in einem Posting steht?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Antworte zunächst mal bitte auf die anderen drei Einwände...
Ok, mach ich, auch wenn das nicht die feine Art ist von Dir, hier Bedingungen zu stellen.
Deine selektive Rückfrage auf einen Punkt bei gleichzeitigem Weglassen der weiteren Punkte steht dem in nichts nach. Und: du hast angefangen ;-)
Aber so bist Du sicherlich bereit dazu, nochmals These und Antithese zusammenzufassen, damit dann alles in einem Posting steht?
Eher nicht. ME habe ich sehr konkret nachgefragt und argumentiert, du gehst nur leider nicht auf die Argumente ein :-(
Ein guter Einstieg: These und Antithese
Hello,
Warum hältst du Sessions hier für einen guten Ort der Ablage?
Wenn eine Datei dazu gekommen ist seit dem letzten Listen, muss der User sowieso erst die Liste aktualisieren lassen. Dabei wird dann Verzeichnis-Array in der Session gelöscht und ein neues aufgebaut.Halten wir fest: Statt nur zu scannen und auszugeben, muss bei Ausgabe der Liste jedes mal das Scanergebnis zusätzlich in die Session gedumpt werden. Für jeden Client!
a) Derartige Aktionen würde ich ohne Authentifizierung sowieso nicht zulassen.
b) Für die Authentifizierung beiten sich nur HTTP Basic Auth und Sessions (mit Cookies) an.
Ich tendiere hier zu Sessions.
c) Wenn eine Session eröffnet ist, wird das $_SESSION-Array ohnehin beim Script-Exit in die
Sessiondatei zurückgeschrieben.
d) ein
$_SESSION['filesearch'] = glob( ...);
ist der einfachste Weg, das Ergebnis der (gefilterten) Suche abzulegen, um es dann
anschließend der Ausgabefunktion zu übergeben (Listenelemente für HTML aufbauen)
Der Eintrag in der Session ist praktisch, weil dadurch eine Transformation zur Entkopplung der wahren Dateipfade von den dem Browser gelieferten Ressourcennamen möglich ist...
Abseits der Frage, ob es sinnvoll ist: Es gibt viele Möglichkeiten, um von dir beschriebenes zu erreichen, das ist keine Frage des Speicherorts.
Hier irrst Du. Der praktischste Speicherort für eine Übersetzungsliste in einem authentifizierten Client-Server-Dialog ist die Sessiondatei. Über die Sessiondatei sind diese Daten dann automatisch kit dem Client in Verbindung zu bringen. WIr erinnern uns: HTTP ist von Haus aus zustandslos, ein gestaffelter Dialog ist aber zustandsorientiert. Durch die Session wird diese Zustandsorientierung herbeigeführt.
Man spart sich damit einen Filesystem-Scan, der ja zur Erstellung der Liste notwendig wäre.
das sollte heißen: ...der ja bei der Erstellung der Liste ohnehin durchgeführt wurde und daher beim Request zum Download nicht unbedingt ein zweites Mal durchgeführt werden muss.
Liest sich gut, stimmt aber nicht(siehe oben)!
Wieso stimmt das nicht?
Wieso soll eine Information weggeschmissen werden, die ich später nochmal benötige?
Der Ablauf ist:
Dokument 1:
bietet das Scannen von Dateien an.
Dokument 2 (überschreibt Dokument 1):
bietet die gescannte Liste an für den Download
und. einen Zurück-Link oder z.B. die Standardnavigation
Dokument 3 (eigenes Fenster für den Download-Dialog):
liefert das angeforderte File aus
Die Liste (Dokument 2) kann dabei solange stehen bleiben, bis der User meint, sie neu einlesen lassen zu müssen, weil sich etwas geändert haben könnte.
und zur Feststellung, ob die angeforderte Datei wirklich im erlaubten Verzeichnis liegt, sonst notwendig wäre.
Dafür braucht es keinen Scan, sondern einen simplen Test.
So, nun möchte ich den _einfachen_ Test sehen, mit dem festgestellt wird, ob die Datei dem User zusteht!
Um das nochmals in Erinnerung zu bringen:
Mein obiger Vorschlag ist nur für sessionorientierte Rechteverwaltung (Login/Rechteprüfung bei Sessionstart) sinnvoll, nicht jedoch bei requestbasierten (Login/Rechteprüfung bei jedem Request).
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Hallo,
Finde das ganz toll, wie hier diskutiert wird. Da verstehe ich es sicher...
Der Ablauf ist:
Dokument 1:
bietet das Scannen von Dateien an.Dokument 2 (überschreibt Dokument 1):
bietet die gescannte Liste an für den Download
und. einen Zurück-Link oder z.B. die Standardnavigation
Das würde ich doch zusammen nehmen. Der User ruft dann Seite "dateien.php" auf und hat gleich die Liste.
Dokument 3 (eigenes Fenster für den Download-Dialog):
liefert das angeforderte File aus
Könnte man doch im gleichen Fenster machen, mit dem Fenster vom Browser. Mit header() und readfile() irgendwie.
So, nun möchte ich den _einfachen_ Test sehen, mit dem festgestellt wird, ob die Datei dem User zusteht!
Könnte man da nicht einfach eine If Schleife einbauen, mit der Bedingung, dass der User das Recht hat darauf zuzugreifen, die den File aufruft? Ist doch simpel, oder?
Um das nochmals in Erinnerung zu bringen:
Mein obiger Vorschlag ist nur für sessionorientierte Rechteverwaltung (Login/Rechteprüfung bei Sessionstart) sinnvoll, nicht jedoch bei requestbasierten (Login/Rechteprüfung bei jedem Request).
Die Rechte müssen ja nur bei einem Download geprüft werden. Ist ja egal.
Korrigiere mich doch, wenn ich was falsch verstanden habe.
lg
pat
Hello,
Der Ablauf ist:
Dokument 1:
bietet das Scannen von Dateien an.Dokument 2 (überschreibt Dokument 1):
bietet die gescannte Liste an für den Download
und. einen Zurück-Link oder z.B. die Standardnavigation
Das würde ich doch zusammen nehmen. Der User ruft dann Seite "dateien.php" auf und hat gleich die Liste.
Nee, die gescannte Liste kann im Client doch stehenbleiben. Die kann doch am Client mittels CSS kenntlich machen, welche Files-Links schon "visited" und damit abgearbeitet sind.
Da muss der Server doch nicht dauern neu scannen und neue Listen aufbauen. Das wäre nur dann sinnvoll, wenn der Datenbestand _sehr_ dynamisch ist, die Liste isch also innerhalb weniger Sekunden stark ändert...
Dokument 3 (eigenes Fenster für den Download-Dialog):
liefert das angeforderte File aus
Könnte man doch im gleichen Fenster machen, mit dem Fenster vom Browser. Mit header() und readfile() irgendwie.So, nun möchte ich den _einfachen_ Test sehen, mit dem festgestellt wird, ob die Datei dem User zusteht!
Könnte man da nicht einfach eine If Schleife einbauen, mit der Bedingung, dass der User das Recht hat darauf zuzugreifen, die den File aufruft? Ist doch simpel, oder?
Bahnhof? If-Schleife? Was ist das?
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg
Warum hältst du Sessions hier für einen guten Ort der Ablage?
Wenn eine Datei dazu gekommen ist seit dem letzten Listen, muss der User sowieso erst die Liste aktualisieren lassen. Dabei wird dann Verzeichnis-Array in der Session gelöscht und ein neues aufgebaut.
Halten wir fest: Statt nur zu scannen und auszugeben, muss bei Ausgabe der Liste jedes mal das Scanergebnis zusätzlich in die Session gedumpt werden. Für jeden Client!
a) Derartige Aktionen würde ich ohne Authentifizierung sowieso nicht zulassen.
Okay, entspricht ja auch der OP Anforderung. Die Problematik bleibt allerdings bestehen, nur die potentielle Anzahl der Clients wird reduziert.
b) Für die Authentifizierung beiten sich nur HTTP Basic Auth und Sessions (mit Cookies) an. Ich tendiere hier zu Sessions.
Allgemein präferiere ich auch Sessions via Cookies, halte es bzgl. der Fragestellung aber nicht für relevant. Für deinen Ansatz ist es Bedingung.
c) Wenn eine Session eröffnet ist, wird das $_SESSION-Array ohnehin beim Script-Exit in die Sessiondatei zurückgeschrieben.
d) ein $_SESSION['filesearch'] = glob( ...); ist der einfachste Weg, das Ergebnis der (gefilterten) Suche abzulegen, um es dann anschließend der Ausgabefunktion zu übergeben (Listenelemente für HTML aufbauen)
Dass zur Ablage einer gefilterten Suche ein Dump in die Session zunächst als _einfachster_ Weg erscheint, _kann_ sein. Im konkreten Fall bedeutet es, höchst redundante Daten(immer wieder) zu erzeugen. Ich halte das für schlechtes Design und bei hinreichend vielen Dateien(evtl. in weiteren Unterordner) / Clients wird das ein Problem.
Der Eintrag in der Session ist praktisch, weil dadurch eine Transformation zur Entkopplung der wahren Dateipfade von den dem Browser gelieferten Ressourcennamen möglich ist...
Auf den ersten Blick womöglich praktisch, ich halte es für den falschen Weg. BTW: "Tansformation zur Entkopplung" = B.....bingo? ;-)
Abseits der Frage, ob es sinnvoll ist: Es gibt viele Möglichkeiten, um von dir beschriebenes zu erreichen, das ist keine Frage des Speicherorts.
Hier irrst Du. Der praktischste Speicherort für eine Übersetzungsliste in einem authentifizierten Client-Server-Dialog ist die Sessiondatei. Über die Sessiondatei sind diese Daten dann automatisch kit dem Client in Verbindung zu bringen.
Sehe ich natürlich anders ;-) Sofern du unterstellst, die Erzeugung einer Übersetzungliste pro Client sei hier sinnvoll, ist ein Dump womöglich auf den ersten Blick praktisch, einige Nachteile habe weiter oben skizziert.
Ich sehe zwei Möglichkeiten, wie die "Übersetzungsliste" enstehen kann:
1. Der vielbesagte Scan, ein Abbild der Ordnerstruktur. Das pro Client zu speichern, ist schlechtes Design - egal wo! Wenn ich es seperat speichere, dann zentral. Ein Grund hierfür könnten sehr viele Dateien plus etwaiges Paging sein. Sonst sehe ich bei besagter Aufgabenstellung den Scan "Just in time" zur Generierung der Liste. Also genau wie du, nur eben ohne das Ergebnis in die User-Session zu klatschen.
2. Womöglich sogar individuell, feinkörnig gesteuert? Wenn ich sowas brauche, muss ich es auch irgendwo pflegen. Die Session wäre ein ziemlich doofer Ort dafür.
WIr erinnern uns: HTTP ist von Haus aus zustandslos,
Danke für den Hinweis. Ich gebe dir Recht: Man kann es nicht oft genug sagen.
ein gestaffelter Dialog ist aber zustandsorientiert.
Gestaffelter Dialog? Noch nie gehört. Ist das ein spezifizierter Begriff?
Durch die Session wird diese Zustandsorientierung herbeigeführt.
Yes yes.
Man spart sich damit einen Filesystem-Scan, der ja zur Erstellung der Liste notwendig wäre.
das sollte heißen: ...der ja bei der Erstellung der Liste ohnehin durchgeführt wurde und daher beim Request zum Download nicht unbedingt ein zweites Mal durchgeführt werden muss.
Liest sich gut, stimmt aber nicht(siehe oben)!
Wieso stimmt das nicht?
Es stimmt(e) nicht, weil dein nachgereichter Hinweis "das sollte heißen:..." fehlte?!
Wieso soll eine Information weggeschmissen werden, die ich später nochmal benötige?
Sie ist nur unter dem von dir gewählten Modell "später benötigt". Du skizzierst also einen Vorteil der _einen_ Nachteil _einer_ Phase des von dir als "good practice" beschriebenen Modells abmildert!
Der Ablauf ist:
Dokument 1:
bietet das Scannen von Dateien an.Dokument 2 (überschreibt Dokument 1):
bietet die gescannte Liste an für den Download
und. einen Zurück-Link oder z.B. die StandardnavigationDokument 3 (eigenes Fenster für den Download-Dialog):
liefert das angeforderte File ausDie Liste (Dokument 2) kann dabei solange stehen bleiben, bis der User meint, sie neu einlesen lassen zu müssen, weil sich etwas geändert haben könnte.
Mir war das von dir entworfene Modell soweit schon klar, trotzdem danke für die Skizze. Sie bringt mich auf einen weiteren Punkt: Die Weitergabe von Direktlinks (z.B. via E-Mail, Messenger) á la "Hey du! Unter http://www.example.org/secure.php?file=hammer.pdf liegt das neue PDF!" für bereits eingeloggte Clients ist so unmöglich, bzw. erfordert den Hinweis: "Bevor der Link funktioniert, aktualisiere bitte zuerst die Übersicht". Ich finde das ziemlich uncool.
und zur Feststellung, ob die angeforderte Datei wirklich im erlaubten Verzeichnis liegt, sonst notwendig wäre.
Dafür braucht es keinen Scan, sondern einen simplen Test.
So, nun möchte ich den _einfachen_ Test sehen, mit dem festgestellt wird, ob die Datei dem User zusteht!
Gerne. Um es noch simpler zu halten, zwinge ich den Request in den erlaubten Bereich. Folgender Pseudocode ist zwar Perl, dürfte aber für PHP analog abbildbar sein:
<pseudocode>
...
my $erlaubterOrdner = '/var/www/secure/';
my $gewuenschteDatei = $ENV{'gewuenschteDatei'};
# Nur erlaubte Zeichen zulassen - Slash erlauben, vielleicht sind ja Unterordner relevant
$gewuenschteDatei =~ s/[^a-zA-Z0-9./]//g;
# "dir escape" entfernen - wg. erlaubtem Slash
$gewuenschteDatei =~ s/..///g;
# Zieldatei bestimmen
my $zielDatei = $erlaubterOrdner . $gewuenschteDatei;
# Datei verarbeiten
open($zielDatei)
...
</pseudocode>
Um das nochmals in Erinnerung zu bringen:
Mein obiger Vorschlag ist nur für sessionorientierte Rechteverwaltung (Login/Rechteprüfung bei Sessionstart) sinnvoll, nicht jedoch bei requestbasierten (Login/Rechteprüfung bei jedem Request).
Auch wenn mir nicht 100% klar ist, worauf du hinaus willst: würdest du diese Einschränkung bei meinem Vorschlag auch machen?
Hallo,
Das ist ein ein bisschen höheres Niveau... ;-)
- Der vielbesagte Scan, ein Abbild der Ordnerstruktur. Das pro Client zu speichern, ist schlechtes Design - egal wo! Wenn ich es seperat speichere, dann zentral. Ein Grund hierfür könnten sehr viele Dateien plus etwaiges Paging sein. Sonst sehe ich bei besagter Aufgabenstellung den Scan "Just in time" zur Generierung der Liste. Also genau wie du, nur eben ohne das Ergebnis in die User-Session zu klatschen.
Was haltet ihr also davon, eine Datenbank zu führen, in der die Daten mit den Pfaden gespeichert wird? Führt halt in gewisser Weise zu Redunanz. Und wenn die Daten mal nicht übers Script laufen würden, könnte es zu Inkonsistenzen kommen.
Lg
patrick
Das ist ein ein bisschen höheres Niveau... ;-)
Es ist ne Diskussion entstanden, die dir wohl nur teilweise weiterhilft. Sorry dafür :-(
Was haltet ihr also davon, eine Datenbank zu führen, in der die Daten mit den Pfaden gespeichert wird? ...
Ich bin grundsätzlich ein Freund von angemessenen Lösungen. Sowohl für die Aufgabenstellung, wie auch den "Umsetzer". Vielleicht habe ich was überlesen, aber ich würde hier tatsächlich in eine Richtung tendieren, die du in deinem OP schon angeschnitten hast:
Die Manipulation der .htaccess Datei über dein Script. Die von dir angerissene Verwendung der IP-Adresse ist aus verschiedenen Gründen doof. Du kannst aber dem Webserver auch mitteilen(eben via .htaccess), dass nur Clients auf einen Ordner zugreifen dürfen, die einen bestimmten Cookie senden. Oder genauer gesagt: Du leitest Clients um, die einen bestimmten Cookie nicht liefern. Stichworte: RewriteEngine und RewriteCond %{HTTP_COOKIE}.
Der große Vorteil hierbei wäre, dass der Webserver sich weiter um die ganze Kiste kümmert und sich Fragen nach Memory-Limit (Time-Limit?) nicht stellen.
Den fraglichen Cookie könntest du (automatisiert oder manuell) regelmäßig ändern, sonst wird der unerlaubte Zugriff zu simpel ;-)
Das alles matürlich nur, sofern du keine wirklich kritischen Daten verwaltest. In dem Fall würde ich dir aber eh raten, einen Profi zu engagieren ;-)
Wie gesagt, der Lösungsvorschlag ist weit weg von "optimal", aber vielleicht passt er ja für dich.
Wenn Du jetzt schon an Sicherheit denken willst, dann speicherst Du die Pfade der Dateien, die Du z.B. mit der Funktion glob() ausgelesen hast in einem Array in Deiner Session
Warum hältst du Sessions hier für einen guten Ort der Ablage? Mir fallen spontan nur Probleme ein: Was, wenn der Ordnerinhalt sich ändert? Redundanz...
Warum sollte sich der Ordnerinhalt ändern? In der Session sind ja eben diese Pfade der kürzlich gefundenen Objekte gespeichert.
Hello,
Wenn Du jetzt schon an Sicherheit denken willst, dann speicherst Du die Pfade der Dateien, die Du z.B. mit der Funktion glob() ausgelesen hast in einem Array in Deiner Session
Warum hältst du Sessions hier für einen guten Ort der Ablage? Mir fallen spontan nur Probleme ein: Was, wenn der Ordnerinhalt sich ändert? Redundanz...
Warum sollte sich der Ordnerinhalt ändern? In der Session sind ja eben diese Pfade der kürzlich gefundenen Objekte gespeichert.
Der Ordnerinhalt kann sich in einem gemeinsam benutzten Datenbestand schon ändern. Deshalb soll man ja auch nicht die Kombination
if (file_exists($filename))
{
readfile($filename);
}
benutzen, bzw. sie nützt überhauot nichts. Denn zwischen der Abfrage, ob die Datei vorhanden ist und der Ausgabe liegen tausende Nanosekundenm und damit auch mindestens hunderte Möglichkeiten für ander Prozesse, daziwschenzuschlüpfen.
Readfile() wird schon merken, wenn es ins Leere greift und liefert dann eine Fehlerkennung (false) und in $php_errormsg steht dann bei passender Konfiguration die Fehlermeldung, die der User gar nicht direkt sehen muss.
Liebe Grüße aus dem schönen Oberharz
Tom vom Berg