[PHP] headers / downloadscript

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Ik zit met een leuk probleem, en ik kom er niet meer uit. Ik heb een extranet gebouwd, waarbij werknemers van all over the world in kunnen loggen op een intranet-achtige omgeving. Hier vindt men nieuwsberichten, is een forum etcetera. Tevens kan men daar allerlei bestanden downloaden (handleidingen, templates, urenstaten, etc).

Je moet echter wel ingelogd zijn om zo'n file te kunnen downloaden, en dus moet de download van zo'n file via een scriptje lopen dat checkt of er een actieve session is met een geldige username & password. De link naar de file wordt dan iets als download.php?id=169.
Ook dat is geen probleem; met onderstaande code forceer ik een download van de betreffende file:

PHP:
1
2
3
4
5
    if ($fp = @fopen($savepath["documents"] . $rFilename, "r")) {
        header("Content-Type: application/octet-stream");
        header("Content-Disposition: attachment; filename=" . $rFilename);
        @fpassthru($fp);    
    }


Nu zijn ze bij dat bedrijf echter bezig met zich te conformeren aan een ISO-normering, en een van de regels waar men aan moet voldoen, is dat files op één centrale plaats opgeslagen moeten worden, zodat iedereen die kan gebruiken. Oftewel, een PDF moet niet gedownload worden, maar moet geopend worden in de browser.

Dat betekent dus dat ik in mijn scriptje onderscheid moet maken tussen de verschillende soorten files (ik check bij het uploaden op mimetype en sla dat op in een database) en of ze in de browser te openen zijn of niet. PDF's, DOC's, XSL's, JPEG's en GIF's zijn allemaal in de browser te openen. Maar dat zijn niet de enige files die men daar opslaat, men heeft ook EPS'en, DOT's, PSD's en meer van dat soort ongein.

Je ontkomt er dus niet aan dat sommige files wel gedownload moeten worden, in plaats van in de browser geopend.

In ieder geval, ik ga dus een check doen op mimetype om te kijken of de file in de browser weergegeven kan worden of niet, en zo ja dan geef ik in plaats van application/octet-stream bijvoorbeeld application/pdf mee.

PHP:
1
2
3
4
5
6
7
8
9
10
    // browserMimetypes is dus een array waarin de mimetypes van PDF, DOC etc staan
    if ($fp = @fopen($savepath["documents"] . $rFilename, "r")) {
        if (!in_array($rMimeType, $browserMimetypes)) {
            header("Content-Type: application/octet-stream");
            header("Content-Disposition: attachment; filename=" . $rFilename);
        } else {
            header("Content-Type: " . $rMimeType);
        }
        @fpassthru($fp);    
    }


Ik ging dit testen, en het werkte prima. Maar niet bij iedereen. Lang niet bij iedereen zelfs. Men kreeg toch een download dialog bij een PDF, waarna er een error gegeven werd. Of Acrobat Reader werd geladen, maar er verscheen geen PDF in de browser. Enzovoorts.

En nu weet ik dus niet meer waar ik het zoeken moet; ik heb op aanraden van kees eens wat headers vergeleken van een normale PDF en een PDF die via mijn scriptje wordt gedownload:

Headers van een 'normale' PDF (i.e. http://blaat/file.pdf) :
HTTP/1.1 200 OK
Date: Mon, 10 Feb 2003 16:03:13 GMT
Server: Apache/2.0.40 (Red Hat Linux)
Last-Modified: Fri, 28 Jun 2002 13:21:48 GMT
ETag: "8e4da-87eb-646d9300"
Accept-Ranges: bytes
Content-Length: 34795
Connection: close
Content-Type: application/pdf
Headers van een pdf via mijn script (i.e. http://blaat/download.php?id=169) :
Date: Wed, 12 Feb 2003 11:00:02 GMT
Server: Apache/2.0.40 (Red Hat Linux)
Accept-Ranges: bytes
X-Powered-By: PHP/4.2.2
Set-Cookie: PHPSESSID=ed25289b13be3e334584eb1b610b6b71; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Connection: close
Content-Type: application/pdf
Wat valt hierin op? In de eerste headers wordt melding gemaakt van Last-Modified, maar ik verwacht niet dat dat boeiend is. Ten tweede is er een ETag-header, en die zie ik ook niet terug bij mijn scriptje. Tenslotte is er de Content-Length. Omdat ik dacht dat het hier misschien aan zou kunnen liggen, heb ik die ook aan mijn script meegegeven, maar die header werd simpelweg NIET teruggegeven door de webserver...
De zaken die wel in mijn scriptje staan maar niet bij een gewone PDF terugkomen: de Expire/Cache-headers, en de X-Powered-By en de Set-Cookie headers.

Waar komt het nu op neer? Ik weet het niet meer :) Ik ben uren aan het klooien geweest en kom er niet meer uit. Ik zoek dus naar een oplossing waarbij 'bekende' files in de browser geopend worden, en overige files een download dialog genereren. Wie helpt me uit de brand?

Acties:
  • 0 Henk 'm!

  • Glock
  • Registratie: November 2001
  • Niet online
Via php files moet je al je headers handmatig meegeven, de headers via 'normaal' worden gegenereerd via apache.
Maar omdat nu php de file doorgeeft doet apache er niks meer mee wat betekend dat jij alles handmatig moet programmeren in je script als daadwerkelijk die headers wil en wat dus waarschijnlijk ook de oplossing is tot je probleem.
edit:
en die extra headers maken niks uit btw, zijn standaard headers die php nog eens meegeeft

[ Voor 29% gewijzigd door Glock op 12-02-2003 12:37 ]


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Zoals je ziet geef ik alleen de Content-type header mee, maar geeft Apache toch 9 andere headers mee. Dat is onzin dus. Zelfs al wil ik zelf de Content-Length header meegeven, dan kan dat niet (wordt namelijk niet meegenomen in de headers die Apache meestuurt, ondanks dat ik het specifiek heb opgegeven).

Acties:
  • 0 Henk 'm!

  • Glock
  • Registratie: November 2001
  • Niet online
Pelle schreef op 12 februari 2003 @ 12:37:
Zoals je ziet geef ik alleen de Content-type header mee, maar geeft Apache toch 9 andere headers mee. Dat is onzin dus. Zelfs al wil ik zelf de Content-Length header meegeven, dan kan dat niet (wordt namelijk niet meegenomen in de headers die Apache meestuurt, ondanks dat ik het specifiek heb opgegeven).
Even ter verduideling hoe apache werkt en dus wat ik zeg wel degelijk geen onzin is...

Er word een aanvraag gestuurd naar een bestand, bv een php bestand, apache kijkt naar het bestand wat er mee gedaan moet worden. Zo geeft apache standaard een paar headers mee en aan de hand van het type bestand nog wat extra headers. PHP heeft de mogelijkheid om nog wat extra headers mee te geven welke jij nu moet gebruiken omdat apache denk dat er een standaard pagina word verstuurd en niet een specifiek bestand aangezien php de inhoud van het bestand behandeld en niet apache.

Headers als Content_Length kan jij wel degelijk zelf meegeven, je moet dan nml gewoon de die lengte zelf bepalen en meesturen, iets wat allemaal prima kan met php.
edit:
Hopelijk heb ik er niet een te grote warboel van deze uitleg gemaakt :D

[ Voor 4% gewijzigd door Glock op 12-02-2003 12:42 ]


Acties:
  • 0 Henk 'm!

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Geen antwoord, maar een aanvulling mbt het bepalen van mimetypes; PHP 4.3 kent namelijk de functie mime_content_type() waarmee aan de hand van de inhoud van een bestand bepaald kan worden wat de mimetype is :)
(ws kon je 'm al, maar het kan zijn dat je het nog niet was tegengekomen)

Intentionally left blank


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Glock schreef op 12 February 2003 @ 12:41:
Headers als Content_Length kan jij wel degelijk zelf meegeven, je moet dan nml gewoon de die lengte zelf bepalen en meesturen, iets wat allemaal prima kan met php.

Zucht.. ik vertel je net dat als ik zelf een Content-Length header meegeef, deze niet wordt doorgegeven door Apache. Je kunt nu wel gaan beweren van wel, maar ik zie hier zelf van niet.

Acties:
  • 0 Henk 'm!

  • Glock
  • Registratie: November 2001
  • Niet online
PHP:
1
2
3
<?
header("Content-Length: 12345");
?>


code:
1
2
3
4
5
6
7
+++RESP 1+++
HTTP/1.1 200 OK
Date: Wed, 12 Feb 2003 12:03:12 GMT
Server: Apache/1.3.26 (Win32)
X-Powered-By: PHP/4.3.0
Content-Length: 12345
Content-Type: text/html


edit:
Misschien dat jij tegen het probleem loopt aan te hikken dat PHP gewoon nog niet goed werkt met Apache 2, hoewel het me wel lijkt dat als 1 type header word doorgegeven dat ze ALLEMAAL worden doorgegeven...

[ Voor 35% gewijzigd door Glock op 12-02-2003 13:05 ]


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Glock schreef op 12 February 2003 @ 13:04:
PHP:
1
2
3
<?
header("Content-Length: 12345");
?>

edit:
Misschien dat jij tegen het probleem loopt aan te hikken dat PHP gewoon nog niet goed werkt met Apache 2, hoewel het me wel lijkt dat als 1 type header word doorgegeven dat ze ALLEMAAL worden doorgegeven...


Ja, ik weet hoe je een Content-Length header mee moet geven :/
Het zou inderdaad een Apache2 probleem kunnen zijn, feit is in ieder geval dat ik 'm niet teruglees in m'n headers.

Acties:
  • 0 Henk 'm!

  • Glock
  • Registratie: November 2001
  • Niet online
Pelle schreef op 12 February 2003 @ 13:10:

[...]


Ja, ik weet hoe je een Content-Length header mee moet geven :/
Het zou inderdaad een Apache2 probleem kunnen zijn, feit is in ieder geval dat ik 'm niet teruglees in m'n headers.
Was alleen ter illustratie dat het hoort te werken, maar in principe moet jij gewoon de headers die Apache nu niet voor je zou genereren zelf in je script inbouwen en als die niet mee worden gestuurd, tjah, of apache downgraden om het te testen of w8ten tot PHP volledig compitabel met Apache 2 is (aannemende dat Apache 2 het probleem is. :o)

Acties:
  • 0 Henk 'm!

Verwijderd

of je een dialoog krijgt te zien hangt niet alleen af van het soort bestand wat je te zien krijgt, ook van je instellingen per computer ergens bij "file types" geloof ik

Acties:
  • 0 Henk 'm!

  • wustenveld
  • Registratie: Februari 2002
  • Laatst online: 07-07 13:36
Bij PDF files is het volgens mij ook weer afhankelijk van de webbrowser / adobe plugin. Ik gebruik op mijn pc Adobe Acrobat en bij mij worden PDF's gewoon in de browser geopend. Een collega van mij heeft Adobe Acrobat Reader geïnstalleerd en bij hem komt het download dialoog altijd in beeld. Misschien dat je het een beetje meer in die richting moet zoeken.

[ Voor 4% gewijzigd door wustenveld op 12-02-2003 14:11 ]


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Nee, nee, en nee :)

Dat zijn allemaal zaken die ik al heb uitgesloten, door bijvoorbeeld ook met een 'normale' PDF die online staat te experimenteren. Het heeft niets met client-side settings te maken; hooguit met de manier waarop de verschillende browsers met HTTP-headers omgaan.

Inmiddels ben ik hard op weg om deze oplossing op een andere manier te implementeren (middels .htaccess en PHP_AUTH_USER) maar dat vereist een stuk meer coding dan wanneer bovenstaand probleem op een andere manier op te lossen geweest zou zijn.

Acties:
  • 0 Henk 'm!

  • ACM
  • Registratie: Januari 2000
  • Niet online

ACM

Software Architect

Werkt hier


Acties:
  • 0 Henk 'm!

  • Pelle
  • Registratie: Januari 2001
  • Laatst online: 12:00

Pelle

🚴‍♂️

Topicstarter
Thnks :)

Ik heb nog een paar uur over zitten werken, en heb met een aantal kleine wijzigingen (oa het toevoegen van een class die bij elke update in de user-table een nieuwe .htpasswd schrijft) de boel redelijk op de rails kunnen krijgen. Er wordt nu gelinked naar fysieke locaties op de webserver, en dat levert geen problemen op (zonder tussenkomst van een download-script dus).

Had ik vantevoren geweten dat men die ISO-normering aan wilde houden, dan had ik het heeeel anders opgezet. Morgen hoor ik of de klant tevreden is; mocht dat niet het geval zijn dan weet ik jullie te vinden ;)
Pagina: 1