Dateidownload mit PHP und Textausgabe

Hallo,

ich habe dieses Script um Daten von meinem Webserver laden zu können.
(Quelle: http://www.php-faq.de/q-datei-download.html)

<?php # $download sei der Bezeichner für die zu ladende Datei<br />$download = $\_GET['download'];

# Dieses Verzeichnis liegt außerhalb der Document\_Root und
# ist nicht per URL zuzugreifen.
$basedir = "/home/xxx/html/daten";

# Übersetzung von Download-Bezeichner in Dateinamen.
$filelist = array(
 "test" =\> "test.zip",
 "bild" =\> "/ein\_bild.png"
);

# Einbruchsversuch abfangen.
if ($filelist[$download] == "")

 die("Die Datei \*$download\* is nicht vorhanden.");


# Vertrauenswürdigen Dateinamen basteln.
$filename = sprintf("%s/%s", $basedir, $filelist[$download]);

# Passenden Datentyp erzeugen.
header("Content-Type: application/octet-stream");

# Passenden Dateinamen im Download-Requester vorgeben,
# z.B. den Original-Dateinamen
$save\_as\_name = basename($filelist[$download]);
header("Content-Disposition: attachment; filename=\"".$save\_as\_name."\"");

# Datei ausgeben.
readfile($filename);
?\>

Aufgerufen wird das dann mit:
example.org/download/download.php?download=test

Dieses öffnet nur kein Fenster im Browser wenn die Datei vorhanden ist. Sondern nur wenn sie es nicht ist. Dann kommt die Meldung:
Die Datei *xyz* is nicht vorhanden.

Soweit so gut.
Allerdings möchte ich das auch dann Text ausgegeben wird wenn die Datei vorhanden ist.
In etwa so:
Die Datei *bild* ist vorhanden.

Außerdem möchte ich das ganze mit meiner Statistik verbinden. Um den Aufruf der Seite/des Downloads sehen so können.
Dazu muss ich dieses Script in die zu zählende Seite einbinden:

Aber ich schaffe es noch nicht mal den „normalen Text“ (Die Datei *name* ist vorhanden) auszugeben!

Habe es schon ewig mit „if“ , „else“ und „echo“ versucht. Komme aber nicht weiter.

Und zu dem „Einbruchsversuch abfangen“ würde ich kurz den unterschied dieser 2 Versionen erfahren:
Version 1 (original)

# Einbruchsversuch abfangen.
if ($filelist[$download] == "")

 die("Die Datei \*$download\* is nicht vorhanden.");

Version 2:

// Einbruchsversuch abfangen.
 if (!isset($filelist[$download]))
 die("Datei $download nicht vorhanden.");

Bitte hier um Hilfe.
Ich weiss nicht mehr weiter und bin vor lauter Forumslesen und PHP.net/manual lesen voll wirr.

Schon mal vielen vielen Dank für Hilfe!

Hi
Da wirst du auch noch länger basteln können ohne eine Lösung zu finden.

Da du in deinem Script den Download direkt startest wenn die Seite aufgerufen wird und nur abbrichst wenn die Datei nicht vorhanden ist wirst du so nie eine Seite sehen sondern immer direkt dem Browser sagen „Achtung hier kommt ein Download“.

Was du machen kannst du schaltest noch eine Seite dazwischen die das ausgibt was du willst und dort ist ein LINK/Javascript zu der Seite die du da oben gepostet hast. In der neuen Seite prüfst du also ob das file da ist wenn nicht dann schreibst du „ist nicht da“, wenn doch dann schreibst du „ist da“ und machst deine Statistiken und dazu dann den link zum download. Wenn er da drauf klickt lädst du die Seite so wie du sie oben hast (da kann auch ruhig noch mal geprüft werden ob er wirklich klickt) und er bekommt seinen download.

Das ganze kannst du auch mit javascript/metarefresh automatisieren.

Gruß Lamer

Oh Danke.

Muss zugeben das ich mir die Antwort nicht so vorgestellt habe.

Eine Seite dazwischen schalten scheidet aus, da man diese ja auch wieder umgehen kann und den Link dann direkt aufrufen könnte. Hatte es so schon gemacht gehabt.

Das mit dem Metarefresh habe ich auch in Verwendung. Scheidet ebenfalls aus. Selber Grund wie oben.

Gibt es denn absolut keine Möglichkeit die Ausgabe („Achtung Browser, hier kommt ne Datei“) solange zu puffern bzw. zu verzögern bis das andere ausgeben ist?

Mit ob_start, ob_end_flush, file_get_contents , sleep ,evtl?
Mein Kopf ist schon ganz voll Matsch.

Mit:

sleep(2);
header ("location: http://www.example.org/download/download.php?download=test");
?\> 

kann ich leider keinen Text vorher ausgeben. Oder doch?

Hi

Nein das geht nicht. Denn mit dem Sleep(2) hälst du das PHP ja nur 2 Sekunden an. Danach läuft alles normal weiter.

Hier mal ein Lösungsansatz der funktionieren sollte

  1. Der User klickt auf den Link zum Download
  2. Die Seite mit der Ausgabe wird aufgerufen
  3. In der Seite ist ein Link (Metarefresh mit einem GetParameter der so aussieht ?zufallszahl= und nun eine Zufallszahl die du auch in der Session speicherst.
  4. Der Metarefresh wird ausgeführt/Der Link wird geklickt
  5. In der Datei die nun den Download startet überprüfst du die Sessionvariable aus dem 1. Skript mit dem übergebenen Wert.
  6. Ist der Wert gleich kannst du ihn durchlassen ist er nicht gleich machst du deine DIE ausgabe

Wie hört sich das für dich an.
Und wenn du in diese Richtung weiter überlegst glaub ich ganz feste daran das du auf noch mehr Lösungen und noch sicherere Lösungen als meine kommst.

Gruß Lamer

Hallo.

Danke für deine Antwort!
Dein Vorschlag ist etwas zu hoch für mich. Bin schon ganz Banane.
Hab schon soviel versucht um dann festzustellen das diese auch nicht gehen. Oder ich hab „fopen“ und Konsorten nur falsch genutzt.

Gibt es denn keine Möglichkeit eine URL ( einen Verweis) „automatisch“ zu starten oder dem Browser extra zu senden?

Include , require und und und. Liste rauf und runter. Mööp.

Nur mit Get habs ich noch nicht versucht.
Quasi den Link über ein Formularknopf aufrufen zu lassen.
Wäre das möglich? Weiß natürlich dann auch nicht ob er wirklich gedrückt wurde.

Wichtig ist nur das die Url die den Download startet nicht sichtbar ist. Auch nicht im Quelltext.

Wenn garnix geht würde es mir schon reichen wenn nur das Script angestoßen würde.

Grüße

Hi LilaPo

Danke für deine Antwort!
Dein Vorschlag ist etwas zu hoch für mich. Bin schon ganz
Banane.
Hab schon soviel versucht um dann festzustellen das diese auch
nicht gehen. Oder ich hab „fopen“ und Konsorten nur falsch
genutzt.

Du bist zu sehr mit dem Mitleid mit dir und dem was du schon versucht hast beschäftigt als konstruktiv an deinem Problem zu arbeiten.

Gibt es denn keine Möglichkeit eine URL ( einen Verweis)
„automatisch“ zu starten oder dem Browser extra zu senden?

Doch die gibt es, das machst du ja auch schon. Nur kannst du dem Browser nicht gleichzeitig mitteilen das du ein HTML-Code schickst und dann gleichzeitig noch eine Downloaddatei. Das geht vom Aufbau her schon nicht. Daher mußt du es nach einander machen. Und da du die Seite erst angezeigt haben willst und dann den Download mußt du halt erst die Seite anzeigen und dann den Download starten.

Include , require und und und. Liste rauf und runter. Mööp.

Das sind alles PHP Methoden die eine Datei zum PHP hinzufügen was dann abgearbeitet wird. Jedoch schickst du damit keine Dateien zum Browser als Download

Nur mit Get habs ich noch nicht versucht.
Quasi den Link über ein Formularknopf aufrufen zu lassen.
Wäre das möglich? Weiß natürlich dann auch nicht ob er
wirklich gedrückt wurde.

Ja, das ist möglich. Und klar weißt du ob er gedrückt wurde. Denn wie ich schon in meiner vorhergehenden Antwort geschrieben habe, wenn du dem LINK, der FORM, dem METAaufruf eine Variable mitgibst die du vorher erstellst und sie dann kontrollierst wenn die Datei für den Download aufgerufen wird, dann hast du sogar 100%ige Kontrolle das sie nur über die Seite kommen die den Aufruf mit dem LINK, der FORM, dem META gemacht haben.

Wichtig ist nur das die Url die den Download startet nicht
sichtbar ist. Auch nicht im Quelltext.

Warum eigentlich nicht. Wenn du jetzt angst hast das die URL direkt angewählt würde, siehe dsa was ich oben und im vorhergehenden Post geschrieben habe. Dann können sie diese Datei so oft aufrufen wie sie wollen aber kommen niemals durch da ihnen ja der übergebene Parameter fehlt.

Wenn garnix geht würde es mir schon reichen wenn nur das
Script angestoßen würde.

Ich dachte die lösung hast du schon … das der Download direkt kommt und das dein Problem sei das du vorher noch eine Seite anzeigen lassen willst.

Gruß Lamer

Hallo!

Du bist zu sehr mit dem Mitleid mit dir und dem was du schon
versucht hast beschäftigt als konstruktiv an deinem Problem zu
arbeiten.

Naja, Mitleid würde ich das nicht nennen. Habe nur alle halbe Jahre mal damit was zu tun. Ich guck immer nach Scriptfetzen und versuch mir das schnell in Foren zusammen zu lesen. Nur man muss wissen was man sucht.
Und da wird einem schon schnell das Hirn matschig.

Wenn garnix geht würde es mir schon reichen wenn nur das
Script angestoßen würde.

Ich dachte die lösung hast du schon … das der Download direkt
kommt und das dein Problem sei das du vorher noch eine Seite
anzeigen lassen willst.

Schon richtig. Den Download konnte ich direkt starten.
Dachte nur ich kann das so starten das vorher einfach noch etwas ausgegeben wird. Aber da war doch ein Denkfehler drin.

Ich hab es jetzt so gelöst.
Bei mir klappt das jetzt. Ist da noch ein Fehler zu finden?

Dies Seite wird als erstes Aufgerufen
<?php session_start();<br />
$zahl=mt\_rand(99, 950);
$\_SESSION['test'] = "$zahl";

echo "Die Variable (Zufallszahl) für diese Session ist: " .$\_SESSION['test'];


echo '<meta http-equiv="refresh" content="3; URL=dr.php?zufallszahl='.$zahl.'&amp;download=test">
';
echo '[Ich bin der Link der auch im Metarefresh ist](dr.php?zufallszahl='.%2524zahl.'&download=test)
';
echo '[Ich bin der Link mit einer Datei welche es nicht gibt](dr.php?zufallszahl='.%2524zahl.'&download=tes)
';

?\>



[Ich bin ein Link mit einer falschen Zahl](dr.php?zufallszahl=1234&download=test)

[Ich bin ein Link ohne Zahl](dr.php?download=test)




----------------fuss:---------------


Hier unten noch die Statistik 

######### Scriptseite welche den Download startet #######

<?php session_start();<br />

# $download sei der Bezeichner für die zu ladende Datei
$download = $\_GET['download'];

#Die Zufallszahl aus dem Link auslesen
$zufallszahl\_2= $\_GET['zufallszahl'];

# Dieses Verzeichnis liegt außerhalb der Document\_Root und
# ist nicht per URL zuzugreifen.
$basedir = "/home/xxx/html/daten";

# Übersetzung von Download-Bezeichner in Dateinamen.
$filelist = array(
 "test" =\> "test.zip",
 "file2" =\> "/test.zip",
 "file3" =\> "area2/datei1.zip"
);

#Zufallszahl pruefen
 if($zufallszahl\_2==$test) {

 # Einbruchsversuch abfangen.
 if ($filelist[$download] == "")
 die("Die Datei \*$download\* is nicht vorhanden.");
 } else {

 die("Zahl passt nicht. 
 Der Link wurde evtl. manipuliert oder die Session ist abgelaufen.
 .");
 }



# Vertrauenswürdigen Dateinamen basteln.
$filename = sprintf("%s/%s", $basedir, $filelist[$download]);

# Passenden Datentyp erzeugen.
header("Content-Type: application/octet-stream");

# Passenden Dateinamen im Download-Requester vorgeben,
# z.B. den Original-Dateinamen
$save\_as\_name = basename($filelist[$download]);
header("Content-Disposition: attachment; filename=\"".$save\_as\_name."\"");

session\_unset();

 # Datei ausgeben.
readfile($filename);

?\>

Warum ist bei diesem Vergleich nichts in den Anfürungszeichen? Nach dem Vergleichsoperator (==) ist nichts da.

if ($filelist[$download] == "")
 die("Die Datei \*$download\* is nicht vorhanden.");

Vielen Dank für deine Antworten. Hat mich gut in die richtige Richtung gebracht.

Gruß

HI

Warum ist bei diesem Vergleich nichts in den Anfürungszeichen?
Nach dem Vergleichsoperator (==) ist nichts da.

if ($filelist[$download] == "")
 die("Die Datei \*$download\* is nicht vorhanden.");

Das ist schon richtig … du bastelst ja oben ein assoziatives Array zusammen das die DownloadDateinamen als assoziation hat. Wird nun in dem Array keine Assoziation gefunden liefert der Vergleich nichts zurück.

Man könnte auch if( empty( $filelist[$download] ) ){ schreiben

Gruß Lamer

Hallo.

Aha, mich hat nur verwirrt das man auch mit nix vergleichen kann.
War also soweit schon richtig gedacht.

Allerdings habe ich noch eine Frage zu:

# Dieses Verzeichnis liegt außerhalb der Document\_Root und
# ist nicht per URL zuzugreifen.
$basedir = "/home/xxxx/html/daten";

Der Ordner „daten“ liegt außerhalb. Kann also nicht per URL aufgerufen werden. Jetzt habe ich darin noch ein paar Bilder die in auf der Seite mit angezeigt werden sollen. (Dieser Bereich wird auch durch ein Passwort geschützt)

Ich hab es so versucht. Wird aber nicht angezeigt. Nur „bild“ ist zu lesen.

$ordner = $\_SERVER['DOCUMENT\_ROOT'];

echo "";
?\>

Ausgegeben wird im Quelltext nur:

Selbiges bei basedir:

$basedir = "/home/xxx/html/daten";

echo "";
?\>

Was habe ich denn vergessen?

Viele Grüße

Edit:
Man kann seine Einträge garnicht bearbeiten. hmpf.
So hatte ich es ebenfalls versucht. Erfolglos.
Wollte ich nur noch Nachreichen.

$ordner = $\_SERVER['DOCUMENT\_ROOT'].'/../daten';

echo "
";

Gibt aus: bild

Quelltext:

Auch damit hast du dir eigentlich die Frage selbst beantwortet.
Denn ein vorangestelltes / in HTML-Angaben verweist eben auf den DOCUMENT_ROOT, in deinem Fall also /home/xxx/html. Du willst doch schließlich nicht, dass man im Browser alle Daten abgreifen kann die auf der Festplatte rumliegen. Also ein korrekter aufruf wäre „/daten/ultra5.jpg“, aber nur solange /home/xxx/html auch tatsächlich dein Root ist.

Ansonsten gibt es zwei Möglichkeiten, an andere Daten in anderen Ordnern heranzukommen. Nehmen wir an, du hast deine Fotos in /home/xxx/Photos und willst der einfachheit halber alle freigeben.

Möglichkeit 1: Einen Symbolischen Link erstellen. Da gibt es unter Unix verschiedene Möglichkeiten. Zum Beispiel „ln -s /home/xxx/Photos /home/xxx/html/Bilder“. Damit hättest du den Ordner verlinkt. Eigentlich müsste der Server dann auch auf „http://deineip/Bilder/“ mit deinem Fotoordner antworten. Geht das nicht, so kannst du immernoch „Harte links“ erzeugen. Das geht mit „ln /home/xxx/Photos /home/xxx/html/Bilder“, also ohne den -s Parameter. Damit ist Bilder ein richtiger Ordner auf dem Dateisystem, der trotzdem immer identischen Inhalt zu Photos hat.

Möglichkeit 2: Ein PHP-Downloadskript. Ich gehe da mal nicht viel näher drauf ein, da du das ja schon in etwa gemacht hast :wink:

<?php $dir = "/home/xxx/Photos/";<br /> $file = $dir.$\_GET["Bild"]; // z.B. ![](skript.php?Bild=image.jpg)
 if(substr(realpath($file),0,strlen($dir))!=$dir)
 exit("Unerlaubter Zugriff"); // Nur innerhalb von $dir möglich!
 if(!is\_file($file)||!getimagesize($file)) // Letzteres lässt nur lesbare Bilder durch
 exit("Es können nur Bilder gesendet werden!");
 header("Content-Type: image");
 readfile($file);
?\>