Thorsten S.: Download-Skript mit Apache-Weiterleitung

Hallo Foruminner und Forumer,

verusche mal mein Problem zu schildern,

Es sollen verschiedene Dateien zum Download angeboten werden. Diese downloads sollen tagesaktuell geloggt werden, wichtig ist dabei (erstmal) nur die Anzahl der downloads, kam der download von einer anderen Seite aus und wann war der letzte zu dieser Datei.

Mit den log-files zu arbeiten bringt hier eher wenig, erstens werden diese vom Provider nur einmal pro Woche upgedated und zweitens ist eine eigene Lösung besser auf die Ziele ausrichtbar (und drittens ne grosse herausfordeung der ich mich stellen will ;) )

Dazu habe ich ein kleines download-skript in PHP geschrieben, welches dann mit download.php?file=xxx aufgerufen wird, das Skript funktionierte  soweit ganz gut, mit 2 problemen. 1.) Mozilla 1.0 unter Windows hat an den Dateinamen des downloads immer .php angehängt also aus setup.zip wurde setup.zip.php, erst nach der Einstellung für die Endung .php funktionierte das ganze Reibungslos, 2.) der T-Online-Browser (4.5) wollte die Datei immer unter download.php?file=xxx abspeicher, mit manuellen umbenennen ging der download dann aber reibungslos.

Obwohl beide Probleme mit wenigen Griffen lösbar wären hab ich die Lösung zunächst rausgenommen, da ich keinem user das nötige know-how von vorneherein abverlangen will (die zielgruppe sind eher nicht so versierte user) und eine FAQ will auch erstmal gelesen sein ;)

Eine zweite Lösung bestand darin das wenn eine Datei setup.zip heruntergeladen werden soll, dafür ein PHP-Skript mit genau diesem Namen anzulegen. Mit einer kleinen .htaccess-Datei dann sicherstellen das .zip-Dateien an den PHP-Parser übergeben werden. Also ist setup.zip eigentlich ein PHP-Skript welches die wirkliche setup.zip öffnet und an den Browser weiterleitet.
Diese Lösung funktioniert 1a, bisher in keinem Browser auch nur im Ansatz ein problem.

Nun hätte ich die Lösung gerne entwas flexibler (und da beginnen meine Probleme :( )

Bisher muss ich so für jede Datei ein PHP-Skript unter dem selben Namen anlegen. Deswegen habe ich versucht über RewriteRulez alle Anfragen die mit .zip enden an ein zentrales PHP-Skript zu übergeben, welches dann einfach das entsprechende File öffnet und weiterleitet.
Das Problem bei Rewrite liegt aber an dem HTTP_Status-Code 302, der ja zunächst den Browser von der neuen URL informiert. Somit habe ich aber wieder das Problem des falschen Dateinamen (s.o.)

Ich habe deswegen versucht das ganze über none-parsing-header zu realisieren, aber da bin ich nicht ganz durchgestiegen. Ich fand nur Beispiele für cgi's (bin mir immer noch nicht sicher ob das irgendwie ein ganz gewisses Schema erfüllen muss) und das ganze (so in etwa habe ich das verstanden) funktioniert nicht unter PHP in der CGI-Version(?)

Mein Provider benutzt Apache 1.3.24 und PHP 4.2 als CGI

2 Lösungen schweben mit vor.

1.) ich kann irgendwie verhindern, das die Standard-Header vom Apache geschickt werden und erlange vollständige Kontrolle über die HTTP-Header.
2.) Ich mache das über ne Weiterleitung an ein zentrales PHP-Skript falls die entsprechende "gefakte" zip nicht existiert, dieses erzeugt die zip (mit dem PHP-download-code) und leitet an diese zurück.

vielleicht hat ja noch irgendwer ne brauchbare Idee (mir gehen sie gerade akkut aus).

Hoffe mal ich konnte mich einigermassen verständlich ausdrücken.

Gruss

Thorsten

  1. Hi,

    Dazu habe ich ein kleines download-skript in PHP geschrieben, welches dann mit download.php?file=xxx aufgerufen wird, das Skript funktionierte  soweit ganz gut, mit 2 problemen. 1.) Mozilla 1.0 unter Windows hat an den Dateinamen des downloads immer .php angehängt also aus setup.zip wurde setup.zip.php, erst nach der Einstellung für die Endung .php funktionierte das ganze Reibungslos, 2.) der T-Online-Browser (4.5) wollte die Datei immer unter download.php?file=xxx abspeicher, mit manuellen umbenennen ging der download dann aber reibungslos.

    hast Du einen Content-Disposition-Header mitgeliefert? Wenn ja, wie sieht der genau aus?

    Eine zweite Lösung bestand darin das wenn eine Datei setup.zip heruntergeladen werden soll, dafür ein PHP-Skript mit genau diesem Namen anzulegen. Mit einer kleinen .htaccess-Datei dann sicherstellen das .zip-Dateien an den PHP-Parser übergeben werden. Also ist setup.zip eigentlich ein PHP-Skript welches die wirkliche setup.zip öffnet und an den Browser weiterleitet.

    Ja, das ist sauber. Wobei natürlich eine .htaccess, die normalerweise nicht gebraucht würde, eine potentielle Performance-Falle ist - das macht sich aber bei "normalem" Traffic nicht bemerkbar.

    Bisher muss ich so für jede Datei ein PHP-Skript unter dem selben Namen anlegen.

    Nö:

    RewriteRule /download/(.+) /download.php?file=$1

    Zumindest grob gesehen. Details entnimm bitte der Apache.Doku zu mod_rewrite.

    Das Problem bei Rewrite liegt aber an dem HTTP_Status-Code 302, der ja zunächst den Browser von der neuen URL informiert. Somit habe ich aber wieder das Problem des falschen Dateinamen (s.o.)

    Wie gesagt: Details siehe Doku ;-)

    Mein Provider benutzt Apache 1.3.24 und PHP 4.2 als CGI

    Du solltest ihn darauf hinweisen, dass er aus Sicherheitsgründen einen 1.3.26 installieren soll. Bei Apache ist vor wenigen Wochen eine Sicherheitslücke aufgetreten, die eine schwere DoS-Attacke ermöglicht; in Version 1.3.26 ist dies gefixt.

    1.) ich kann irgendwie verhindern, das die Standard-Header vom Apache geschickt werden und erlange vollständige Kontrolle über die HTTP-Header.

    Ja! Die Macht ist mit Dir! *g*

    Ernsthaft: mod_rewrite bietet Dir eine Menge Möglichkeiten; und ist möglicherweise sogar unnötig, wenn nämlich Deine bisherigen Header suboptimal waren.

    2.) Ich mache das über ne Weiterleitung an ein zentrales PHP-Skript falls die entsprechende "gefakte" zip nicht existiert, dieses erzeugt die zip (mit dem PHP-download-code) und leitet an diese zurück.

    Beziehungsweise Du machst Dich mit dem Begriff PATH_INFO vertraut und umgehst die gesamte Problematik. Aber das wäre ja zu einfach ;-)

    Hoffe mal ich konnte mich einigermassen verständlich ausdrücken.

    Sehr. Ich glaube, Du bist einfach nur kräftig in den Wald gerannt, den Du jetzt vor lauter Bäumen nicht mehr siehst, weil Dir einer von den Dingern ein mächtiges Brett vor den Kopf genagelt hat *g*

    Cheatah

    1. Hi Cheatah,

      (ist das der name einer bekannten Katze? irgendwie ist das das erste das mit bei dem namen einfällt -> katze, ka warum ;)

      hast Du einen Content-Disposition-Header mitgeliefert? Wenn ja, wie sieht der genau aus?

      ja, header("Content-Disposition: attachment; filename=$Filename");

      war die letzte Version, ich habe es auch mit

      header("Content-Disposition: attachment; filename="$Filename"");
      und
      header("Content-Disposition: inline; filename=$Filename");

      probiert, alles was ich in Lösungsvorschlägen im Netz gefunden habe.
      Ich denke mal die erste Variante ist ok, aber wer sagt den das jeder Browser _wirklich_ ne ahnung von HTTP hat. Beim T-online hab ich da ein paar Zweifel ...

      Ja, das ist sauber. Wobei natürlich eine .htaccess, die normalerweise nicht gebraucht würde, eine potentielle Performance-Falle ist - das macht sich aber bei "normalem" Traffic nicht bemerkbar.

      der Traffic dürfte wirklich nicht so extrem hoch werden

      Nö:

      RewriteRule /download/(.+) /download.php?file=$1

      hmm, da muss ich nochmal in den dokus blättern, aber kommt so nicht wieder ein 302? und der dateiname wäre dann wieder download.php?file=xxx was der T-Online-Browser nicht checken will?

      Du solltest ihn darauf hinweisen, dass er aus Sicherheitsgründen einen 1.3.26 installieren soll. Bei Apache ist vor wenigen Wochen eine Sicherheitslücke aufgetreten, die eine schwere DoS-Attacke ermöglicht; in Version 1.3.26 ist dies gefixt.

      ui, mach ich lieber mal

      1.) ich kann irgendwie verhindern, das die Standard-Header vom Apache geschickt werden und erlange vollständige Kontrolle über die HTTP-Header.

      Ja! Die Macht ist mit Dir! *g*

      Beziehungsweise Du machst Dich mit dem Begriff PATH_INFO vertraut und umgehst die gesamte Problematik. Aber das wäre ja zu einfach ;-)

      Mein Skript arbeitet mit PATH_INFO, genauer gesagt steht in der "gefakten" setup.zip nur
      <?php
      include("download.php");
      ?>
      dieses liesst dann über PATH_INFO den Dateinamen aus.

      Wie gesagt, brauchbare (dem user gegenüber vertretbare Ergebnisse habe ich nur hinbekommen wenn ich dafür Sorge das er _genau_ die selben header bekommt als wenn der Server direkt die .zip liefert)

      Sehr. Ich glaube, Du bist einfach nur kräftig in den Wald gerannt, den Du jetzt vor lauter Bäumen nicht mehr siehst, weil Dir einer von den Dingern ein mächtiges Brett vor den Kopf genagelt hat *g*

      hmm, jetzt wo du es sagst sehe ich da etwas vor meinem Kopf hängen, konnte ein Brett sein, bin aber nicht ganz sicher. Die Frage ist nur, wie bekomme ich das wieder los? ;)

      erstmal thx für deine rasche und konstruktive Antwort, werde nochmal  in der apache-doku schmökern und veruschen deinen rat zu beherzigen und nach einer einfachen lösung suchen (sobald ich das Brett los bin)

      gruss

      Thorsten

      1. Hi,

        Hi Cheatah,
        (ist das der name einer bekannten Katze?

        nein, aber "cheetah" ist das englische Wort für "Gepard".

        hast Du einen Content-Disposition-Header mitgeliefert? Wenn ja, wie sieht der genau aus?
        ja, header("Content-Disposition: attachment; filename=$Filename");

        Ist korrekt.

        header("Content-Disposition: attachment; filename="$Filename"");

        Ist falsch :-) Hier schlägst Du einen Dateinamen vor, der Anführungszeichen enthält.

        header("Content-Disposition: inline; filename=$Filename");

        Hm, hab ich noch nie verwendet, kann ich nichts zu sagen.

        Ich denke mal die erste Variante ist ok, aber wer sagt den das jeder Browser _wirklich_ ne ahnung von HTTP hat.

        Niemand. Vom IE beispielsweise lässt sich eher das Gegenteil behaupten...

        RewriteRule /download/(.+) /download.php?file=$1
        hmm, da muss ich nochmal in den dokus blättern, aber kommt so nicht wieder ein 302?

        Auf die Gefahr hin, mich zu wiederholen: Die Details lies bitte selbst nach ;-)

        Mein Skript arbeitet mit PATH_INFO,

        Hm, eigentlich braucht es nur entweder $_GET['file'] oder getenv('PATH_INFO'); aus beiden erhälst Du den Dateinamen. Im letzteren Fall ist das, was Client und Server als Dateiname ansehen, exakt das selbe.

        Wie gesagt, brauchbare (dem user gegenüber vertretbare Ergebnisse habe ich nur hinbekommen wenn ich dafür Sorge das er _genau_ die selben header bekommt als wenn der Server direkt die .zip liefert)

        Naja, im Prinzip ist das ja auch Dein Ziel... :-)

        hmm, jetzt wo du es sagst sehe ich da etwas vor meinem Kopf hängen, konnte ein Brett sein, bin aber nicht ganz sicher. Die Frage ist nur, wie bekomme ich das wieder los? ;)

        Nicht mit Gewalt! Nimm einfach einen größeren Hammer *g*

        Cheatah

        1. Hi Cheatah,

          hmm, jetzt wo du es sagst sehe ich da etwas vor meinem Kopf hängen, konnte ein Brett sein, bin aber nicht ganz sicher. Die Frage ist nur, wie bekomme ich das wieder los? ;)

          Nicht mit Gewalt! Nimm einfach einen größeren Hammer *g*

          hmm, ohne Gewalt aber nen _größeren_ Hammer, wie geht das ? ;)

          gruss

          Thorsten

      2. Aloha!

        RewriteRule /download/(.+) /download.php?file=$1

        hmm, da muss ich nochmal in den dokus blättern, aber kommt so nicht wieder ein 302? und der dateiname wäre dann wieder download.php?file=xxx was der T-Online-Browser nicht checken will?

        Wenn du ein Redirect haben willst auf den per Rewriting gefundenen Dateinamen, dann mußt du an die RewriteRule hinten ein "[R]" dranhängen für Redirect. Ansonsten wird einfach unsichtbar intern die URL umgeschrieben und (wenn die Umschreibungen alle fertig sind) dann endlich ausgeführt. Praktisch dabei ist, daß die Servervariablen immer noch (auch?) den Originalzustand widerspiegeln. Du könntest also mit $_SERVER['REQUEST_URI'] im PHP-Script ganz leicht herausfinden, was der User-Agent denn so gewollt hat - ganz ohne Parameter in der RewriteRule.

        Zu Details lies besser die Doku auf Apache.org und auch den RewriteGuide. :)

        - Sven Rautenberg

  2. Es sollen verschiedene Dateien zum Download angeboten werden. Diese downloads sollen tagesaktuell geloggt werden, wichtig ist dabei (erstmal) nur die Anzahl der downloads, kam der download von einer anderen Seite aus und wann war der letzte zu dieser Datei.

    Einen anderen Ansatz als das, was Du vorschlaegst und was Cheatah kommentiert hat, waere, mit PHP einerseits das "Logbuch" zu schreiben und andererseits einfach mit einem Header: ***.zip Befehl den Browser zur eigentlichen Download-Datei umzuleiten.
    Dann kriegt der Browser/Benutzer halt die richtige URL der Download-Datei mit, dafuer wird es AFAIK mit jedem Browser gleich mit dem richtigen Dateinamen zum Download angeboten.

    Das ganze habe ich kuerzlich in de.comp.lang.php beschrieben; ich versuch jetzt mal, hier einen Link zum Google-Archiv zu machen.

    mfg
    Thomas

    http://groups.google.ch/groups?selm=48b90e76.0207151034.41e366ea%40posting.google.com

    Message-ID: 48b90e76.0207151034.41e366ea@posting.google.com

    1. Hi Thomas,

      Einen anderen Ansatz als das, was Du vorschlaegst und was Cheatah kommentiert hat, waere, mit PHP einerseits das "Logbuch" zu schreiben und andererseits einfach mit einem Header: ***.zip Befehl den Browser zur eigentlichen Download-Datei umzuleiten.
      Dann kriegt der Browser/Benutzer halt die richtige URL der Download-Datei mit, dafuer wird es AFAIK mit jedem Browser gleich mit dem richtigen Dateinamen zum Download angeboten.

      solangsam geht mir ein Licht auf, ich glaub jetzt hab ichs gecheckt, genau das ist die Lösung :)

      1000xthx an dich und Cheatah,

      (brauchte wohl nen moment ums zu blicken)

      gruss

      Thorsten

    2. Hi,

      Einen anderen Ansatz als das, was Du vorschlaegst und was Cheatah kommentiert hat, waere, mit PHP einerseits das "Logbuch" zu schreiben und andererseits einfach mit einem Header: ***.zip Befehl den Browser zur eigentlichen Download-Datei umzuleiten.

      der Nachteil bei der Location-Header-Variante ist allerdings, dass die Datei an sich, also ohne PHP "dazwischen", per HTTP direkt erreichbar sein muss - mit der Folge, dass die URL bekannt wird (das passiert quasi selbsttätig), und somit das Logging niemals vollständig sein wird. Es ist eine Entscheidungsfrage, ob man den geringen Fehler tolerieren möchte.

      Cheatah