Browser caching aanzetten vanuit PHP

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Hoi,

Via Google kan ik alleen maar informatie vinden over het uitzetten van browser caching voor PHP scripts, maar ik wil het tegenovergestelde: ik wil het aanzetten.

Ik heb een PHP script die, in de basis, een bestand uitleest en naar de browser stuurt (dmv readfile()). Het probleem is echter dat de browser dit elke keer doet, ook al is het bestand niet veranderd. Ik heb geprobeerd dit gedrag met headers aan te passen, maar dat is tot op heden niet gelukt.

Een voorbeeld met een opvraag.
/some_image.jpg: de eerste keer wordt die gedownload van de server (dat kan je zien, hij bouwd langzaam op van boven naar beneden). De tweede keer staat die er meteen, dus komt die uit de cache.

/test.php: wordt elke keer opnieuw gedownload van de server (want je ziet dat die elke keer langzaam opgebouwd wordt).

Het PHP script ziet er dan ongeveer zo uit (ik heb dus de modification date ge-hardcode om te testen, maar normaal zou ik dat met een filemtime() en gmdate() doen):

code:
1
2
3
4
5
6
7
header("Last-Modified: Fri, 09 Oct 2009 17:26:17 GMT");
header("Accept-Ranges: bytes");
header("Content-Length:" . filesize("some_image.jpg"));
header("Content-Type: image/jpeg");

readfile("some_image.jpg");
exit();


Hoe kan ik dus voor zorgen dat de browser de output van test.php cached en de volgende keer het uit de cache haalt ipv. van de server download?

Acties:
  • 0 Henk 'm!

  • Matis
  • Registratie: Januari 2007
  • Laatst online: 17-09 18:39

Matis

Rubber Rocket

Volgens mij moet je dat juist in de html header aangeven, dat er niets gewijzigd is.

If money talks then I'm a mime
If time is money then I'm out of time


Acties:
  • 0 Henk 'm!

  • HuHu
  • Registratie: Maart 2005
  • Niet online
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, hoofstuk 14.9: Cache-Control.

Je moet dan nog wat extra headers meesturen. Kijk bijvoorbeeld ook eens wat andere sites meesturen met iets als LiveHttpHeaders in Firefox. Controleer dan ook meteen wat je zelf mee stuurt.

Acties:
  • 0 Henk 'm!

  • Joolee
  • Registratie: Juni 2005
  • Niet online
De client zal sowieso aan de server vragen of er iets veranderd is. Als dat niet het geval is dan lees je in jouw geval alsnog het bestand in en stuur je deze terug. De bedoeling is dat je dan aan de browser doorgeeft dat er niets veranderd is en het script afkapt.

Een mogelijkheid is om bij ieder bestand een E-tag mee te sturen welke wordt samengesteld uit bijv. een hash van het bestand. Bij terugkomst stuurt de browser de oude E-tag mee en daarmee kun je zien of je de request moet afkappen.
PHP:
1
2
3
4
5
6
7
8
9
10
11
    if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && 
        stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) 
    {
        // Return visit and no modifications, so do not send anything
        header ("HTTP/1.0 304 Not Modified");
        header ('Content-Length: 0');
    } 
    else 
    {
                // Stuur bestand op met E-tag
        }

[ Voor 52% gewijzigd door Joolee op 27-10-2009 11:25 ]


Acties:
  • 0 Henk 'm!

  • Nick_S
  • Registratie: Juni 2003
  • Laatst online: 17-09 12:49

Nick_S

++?????++ Out of Cheese Error

In je html headers kun je niks aangeven, aangezien er geen html verstuurd wordt. ;)

Je zet nu alleen de last-modified, je moet ook nog aangeven hoe lang een browser deze mag cachen. Dit kun je doen met de expires header of de max-age header.

Je zou ook aan de serverkant kunnen kijken of het bestand gewijzigd is(lees de http request headers uit voor de versie van de client) en zo niet kun je een http status 304 terugsturen ipv. een 400 status + bestand.

Edit: 403 is natuurlijk "not authorized" en niet "not modified"

[ Voor 8% gewijzigd door Nick_S op 27-10-2009 16:14 ]

'Nae King! Nae quin! Nae Laird! Nae master! We willna' be fooled agin!'


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Als je mod_expires aan hebt staan is het mogelijk om ETags mee te sturen en Expires headers te sturen.

Van http://shiftingpixel.com heb ik een functie gevonden waarmee je in php dit best gemakkelijk kan aanvullen:
PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function sendCacheHeaders ($etag, $lastModified)
{
    header('Last-Modified: ' . $lastModified);
    header('ETag: "' . $etag . '"');

    $if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH']) ?
    stripslashes($_SERVER['HTTP_IF_NONE_MATCH']) :
    false;

    $if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) ?
    stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']) :
    false;

    if (!$if_modified_since && !$if_none_match)
    return;

    if ($if_none_match && $if_none_match != $etag && $if_none_match != '"' . $etag . '"')
    return; // etag is there but doesn't match

    if ($if_modified_since && $if_modified_since != $lastModified)
    return; // if-modified-since is there but doesn't match

    // Nothing has changed since their last request
    returnNotModified();
}


Dan zit je met je afbeelding in php en doe je eigenlijk alleen maar dit:
PHP:
1
2
3
$lastModifiedString = gmdate('D, d M Y H:i:s', filemtime($src)) . ' GMT';
$etag = md5($data);
sendCacheHeaders($etag, $lastModifiedString);


De functie returnNotModified() returnt een 304 header en exit het script.

Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Bedankt voor de reacties! Ik dacht dat er helemaal geen server aanvraag gedaan zou worden, maar ik ben uiteraard vergeten aan te geven voor hoelang de data geldig was. Ik zag bij het inspecteren van de headers van een "normale" aanvraag al zo'n E-tag en vroeg me af wat dat was.

Ik zal wel even Googlen op wat precies zo'n E-tag inhoudt... maar als het in principe van alles kan zijn wordt het vrij gemakkelijk (zoals ook al aangegeven met het voorbeeld met md5()). :)

Oh en als laatste vraag, ik weet wel dat je headers kan opsturen met header(), maar hoe stuur je dan vanuit PHP een 304?

Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Gewoon header($inhoud_header); :) Wat die inhoud moet zijn staat beschreven op verschillende sites. Ook http://php.net/header geeft je wat informatie.

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op dinsdag 27 oktober 2009 @ 14:49:
Oh en als laatste vraag, ik weet wel dat je headers kan opsturen met header(), maar hoe stuur je dan vanuit PHP een 304?
Het is een header, dus met header(). Heb je überhaupt de documentatie van die functie gelezen? Staat er toch duidelijk in.

.edit: anders vergeet ik even de laatste reactie in de draad te lezen 8)7

[ Voor 9% gewijzigd door .oisyn op 27-10-2009 15:20 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
.oisyn schreef op dinsdag 27 oktober 2009 @ 15:20:
[...]

Het is een header, dus met header(). Heb je überhaupt de documentatie van die functie gelezen? Staat er toch duidelijk in.

.edit: anders vergeet ik even de laatste reactie in de draad te lezen 8)7
Nee ik keek uit het raam en toen dacht ik uuuuuuhm TE MOEILIJK ik post het wel ff op Got..

Duh tuurlijk heb ik het gelezen... maar dan weet ik nog steeds niet wat je precies moet opsturen voor een correcte 304...

Maar toch bedankt he!

Acties:
  • 0 Henk 'm!

  • Peedy
  • Registratie: Februari 2002
  • Laatst online: 06-11-2024
Verwijderd schreef op dinsdag 27 oktober 2009 @ 15:27:
[...]

Nee ik keek uit het raam en toen dacht ik uuuuuuhm TE MOEILIJK ik post het wel ff op Got..

Duh tuurlijk heb ik het gelezen... maar dan weet ik nog steeds niet wat je precies moet opsturen voor een correcte 304...

Maar toch bedankt he!
In deze reactie staat notabene de letterlijke code, dus niet zo bijdehand joh, die mensen zijn hier om je te helpen.

PHP:
1
2
3
4
5
6
7
8
9
10
11
12
13
<?php 
$last_modified_time = filemtime($file); 
$etag = md5_file($file); 

header("Last-Modified: ".gmdate("D, d M Y H:i:s", $last_modified_time)." GMT"); 
header("Etag: $etag"); 

if (@strtotime($_SERVER['HTTP_IF_MODIFIED_SINCE']) == $last_modified_time || 
    trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { 
    header("HTTP/1.1 304 Not Modified"); 
    exit; 
} 
?>

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

Verwijderd schreef op dinsdag 27 oktober 2009 @ 15:27:
[...]

Nee ik keek uit het raam en toen dacht ik uuuuuuhm TE MOEILIJK ik post het wel ff op Got..

Duh tuurlijk heb ik het gelezen... maar dan weet ik nog steeds niet wat je precies moet opsturen voor een correcte 304...

Maar toch bedankt he!
Sorry, mijn fout, ik ging er vanuit dat je zelf na kon denken, maar blijkbaar moeten we het voorkauwen. Het is idd lastig om te bedenken dat die header dan "HTTP/1.1 304 Not Modified" moet zijn, zoals [google="http status codes"] laat zien...

Voor de goede orde, voordat jij die vraag stelde wist ik het zelf ook nog niet. Toch was ik er binnen 5 minuten achter. En ik weiger te geloven dat dat komt omdat ik met zo'n fantastisch stel hersens zou zijn gezegend oid.

[ Voor 32% gewijzigd door .oisyn op 27-10-2009 17:04 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

  • mithras
  • Registratie: Maart 2003
  • Niet online
Ik stuur trouwens twee headers:
PHP:
1
2
header('HTTP/1.1 304 Not Modified');
header('Status: 304 Not Modified');

Waarom weet ik eigenlijk niet meer (alleen op het feit na dat je met #1 HTTP 1.1 expliciet definieert). Maar het werkt prima :p

En tot slot: vergeet na zo'n header niet om je script te stoppen (exit). Het is zonde van de resources als je vervolgens lekker dat bestand gaat zitten doorgeven ;)

Acties:
  • 0 Henk 'm!

  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

mithras schreef op dinsdag 27 oktober 2009 @ 16:27:
Ik stuur trouwens twee headers:
PHP:
1
2
header('HTTP/1.1 304 Not Modified');
header('Status: 304 Not Modified');
Wat dacht je van
PHP:
1
header(' ', true, 304);

;)

On track


Acties:
  • 0 Henk 'm!

  • Olaf van der Spek
  • Registratie: September 2000
  • Niet online
Waarom een spatie en geen lege string?

Acties:
  • 0 Henk 'm!

  • WouZz
  • Registratie: Mei 2000
  • Niet online

WouZz

Elvis is alive!

Olaf van der Spek schreef op dinsdag 27 oktober 2009 @ 16:51:
Waarom een spatie en geen lege string?
Alles behalve een lege string werkt. (Don't ask me why) :)

On track


Acties:
  • 0 Henk 'm!

  • Tharulerz
  • Registratie: April 2009
  • Laatst online: 10-04 05:16
.oisyn schreef op dinsdag 27 oktober 2009 @ 16:09:
Voor de goede orde, voordat jij die vraag stelde wist ik het zelf ook nog niet. Toch was ik er binnen 5 minuten achter. En ik wijger te geloven dat dat komt omdat ik met zo'n fantastisch stel hersens zou zijn gezegend oid.
Ik weiger dat ook te geloven, omdat zo'n fantastisch stel hersenen niet zo'n spelfout zou maken _/-\o_

Acties:
  • 0 Henk 'm!

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 17-09 14:05

.oisyn

Moderator Devschuur®

Demotivational Speaker

I rest my case :Y)

[ Voor 118% gewijzigd door .oisyn op 27-10-2009 17:05 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


Acties:
  • 0 Henk 'm!

Verwijderd

Topicstarter
Blijkbaar is mod zijn een vrijbrief om onvriendelijk te doen. Ik wordt al vaak genoeg getreiterd (t?) dat ik niet één van de slimsten ben, en ik vind het vrij vervelend om dat hier dan ook nog te horen, terwijl ik hier naartoe kom met het idee dat ik hier hulp kan krijgen (hoewel blijkbaar alles op Google te vinden is, dus Got kan ook wel gesloten worden).

In ieder geval toch bedankt voor de hulp, want die heeft echt heel erg geholpen. :) Ik heb het inmiddels naar wens aan de praat.

[ Voor 4% gewijzigd door Verwijderd op 27-10-2009 19:54 ]


Acties:
  • 0 Henk 'm!

  • Jory
  • Registratie: Mei 2006
  • Laatst online: 10:18
WouZz schreef op dinsdag 27 oktober 2009 @ 16:49:
[...]


Wat dacht je van
PHP:
1
header(' ', true, 304);

;)
Liever niet. Ik heb namelijk - zonder op te zoeken wat de derde parameter ook alweer is, en wat HTTP status code 304 ook alweer betekend - geen idee wat dat doet. En dat opzoeken, daar ben ik uiteraard te lui voor. :)
(Leesbare code > korte code, zegmaar)

Acties:
  • 0 Henk 'm!

  • Patriot
  • Registratie: December 2004
  • Laatst online: 16-09 13:49

Patriot

Fulltime #whatpulsert

Verwijderd schreef op dinsdag 27 oktober 2009 @ 19:54:
Blijkbaar is mod zijn een vrijbrief om onvriendelijk te doen. Ik wordt al vaak genoeg getreiterd (t?) dat ik niet één van de slimsten ben, en ik vind het vrij vervelend om dat hier dan ook nog te horen, terwijl ik hier naartoe kom met het idee dat ik hier hulp kan krijgen (hoewel blijkbaar alles op Google te vinden is, dus Got kan ook wel gesloten worden).
Niet om lullig te doen, maar jij begon (al dan niet bewust) met onvriendelijk gedrag door zo enorm bijdehand te doen ;) Zijn opmerking over zelf kunnen denken moest je ook wat sarcastischer opvatten. Hij bedoelde niet dat je dom was, maar dat hij je nogal lui vond omdat het er niet op leek dat je veel moeite stak in het oplossen van je eigen probleem. Verder is .oisyn geen moderator op het forum, ProMod is een functie op de frontpage en er is geen forummod die .oisyn onbeschoft gedrag zou vergeven enkel op basis van dat ondertiteltje.

Ook hoeft GoT niet te sluiten omdat veel informatie op Google te vinden is. Wel is het zo dat de meeste GoT-users er niet zo van houden als ze moeten werken als Google-by-proxy. Als wij de vraag kunnen beantwoorden door te googlen op steekwoorden uit de vraag, dan is het meestal zo dat je de vraag niet op GoT had hoeven stellen.
Liever niet. Ik heb namelijk - zonder op te zoeken wat de derde parameter ook alweer is, en wat HTTP status code 304 ook alweer betekend - geen idee wat dat doet. En dat opzoeken, daar ben ik uiteraard te lui voor. :)
(Leesbare code > korte code, zegmaar)
Eens, hoewel dat in dit geval ook met een comment nog wel opgelost had kunnen worden. Maarja, dan is je winst weer weg die je verkreeg door het zo te doen :P
mithras schreef op dinsdag 27 oktober 2009 @ 16:27:
Ik stuur trouwens twee headers:
PHP:
1
2
header('HTTP/1.1 304 Not Modified');
header('Status: 304 Not Modified');

Waarom weet ik eigenlijk niet meer (alleen op het feit na dat je met #1 HTTP 1.1 expliciet definieert). Maar het werkt prima :p

En tot slot: vergeet na zo'n header niet om je script te stoppen (exit). Het is zonde van de resources als je vervolgens lekker dat bestand gaat zitten doorgeven ;)
Heb er even naar gekeken, maar het lijkt afhankelijk te zijn van hoe PHP is gecompileerd? Mogelijkerwijs omdat bepaalde headers standaard al worden verstuurd als hij als apache module is gecompileerd (of juist als cgi, weet niet precies wat het verschil is).

edit: hmm, via cgi is er blijkbaar een bepaalde 'vertaalslag' die ervoor zorgt dat de eerste vorm niet werkt (dan krijg je een internal server error). Je moet dan dus de tweede gebruiken. Er is dan echter geen reden om de tweede te gebruiken als de eerste gewoon werkt (als PHP als apache module draait)

In ieder geval is het volgens mij dubbel en onnodig om het beiden te doen.

[ Voor 37% gewijzigd door Patriot op 28-10-2009 05:27 . Reden: extra quote ]

Pagina: 1