Bekijk Volledige Versie : [http / php] image caching
Tjerk Wolterink
17/03/05, 19:55
ik had een php script gemaakt die een plaatje op de server inlas, deze verkleinde
naar het gewenste formaat en het vervolgens uitpoept naar de browser,
maar hij cache niet. dus daar heb ik een oplossing voor gemaakt:
het gaat om deze regels php code:
---
header("Cache-Control:");
header("Expires:");
header("Pragma:");
$filename=$upload_dir."/".$image;
$last_modified=filemtime($filename);
$request_headers=apache_request_headers();
if(array_key_exists("If-Modified-Since", $request_headers) && $last_modified<=strtotime($request_headers["If-Modified-Since"])) {
header("HTTP/1.x 304 Not Modified");
die();
}
header("Last-Modified: ".gmdate("D, d M Y H:i:s \G\M\T", $last_modified));
---
Nu werkt het allemaal lekker als ik als client firefox gebruik,
maar in internet explorer blijven de plaatjes herladen, lijkt dus of er niet wordt gecached.
Overigens heb ik de script tijdens het maken getest met firefox,
in firefox kon ik namelijk met een plugin de http headers voorbij zien komen LiveHttpHeaders.
Maar waarom werkt het nu niet in Inernet Explorer, iemand een idee.
Weet niet zo 1 2 3 hoe ik de headers die internet explorer stuurt makkelijk kan bekijken.
Hier overigens een request response in firefox:
http://www.loonbedrijf-wildenbeest.nl/xcm/image.php?image=DSC00702.JPG&width=120
GET /xcm/image.php?image=DSC00702.JPG&width=120 HTTP/1.1
Host: www.loonbedrijf-wildenbeest.nl
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6) Gecko/20050225 Firefox/1.0.1
Accept: image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.loonbedrijf-wildenbeest.nl/index.php?page=pages/occasions.page.xml
Cookie: SESSID=b003c9e7a8da3291ba84dacb3665bc82
If-Modified-Since: Wed, 09 Mar 2005 14:41:18 GMT
Cache-Control: max-age=0
HTTP/1.x 304 Not Modified
Date: Thu, 17 Mar 2005 18:46:45 GMT
Server: Apache/1.3.33 (Unix) mod_perl/1.29 PHP/4.3.10 mod_ssl/2.8.22 OpenSSL/0.9.7b
X-Powered-By: PHP/4.3.10
Keep-Alive: timeout=15, max=471
Connection: Keep-Alive
Content-Type: text/html
Zoals je ziet zegt ie mooi 304 Not Modified, op de een of andere manier gebeurd dat niet bij msie.
Daniel Tryba
17/03/05, 20:15
Tjerk Wolterink <tjerk@wolterinkwebdesign.com> wrote:
[headers]
> Zoals je ziet zegt ie mooi 304 Not Modified, op de een of andere manier gebeurd dat niet bij msie.
Als je de headers van msie erbij pakt weet je (wellicht) waar het
probleem ligt.
Maar ik kan nu al gokken dat het aan de case van de header ligt, IIRC
stellen de betrokken RFCs dat dat case insensitive moet zijn.
BTW fix je regel lengte eens naar iets < 80.
Tjerk Wolterink
17/03/05, 20:45
Daniel Tryba wrote:
> Tjerk Wolterink <tjerk@wolterinkwebdesign.com> wrote:
> [headers]
>
>>Zoals je ziet zegt ie mooi 304 Not Modified, op de een of andere manier gebeurd dat niet bij msie.
>
>
> Als je de headers van msie erbij pakt weet je (wellicht) waar het
> probleem ligt.
>
Ja daar dacht ik ook al aan, maar hoe kan ik daar makkelijk bijkomen?
>
> Maar ik kan nu al gokken dat het aan de case van de header ligt, IIRC
> stellen de betrokken RFCs dat dat case insensitive moet zijn.
En dus, dan doe ik toch niks fout?
>
> BTW fix je regel lengte eens naar iets < 80.
done
Tjerk Wolterink
17/03/05, 20:45
Tjerk Wolterink wrote:
> ik had een php script gemaakt die een plaatje op de server inlas, deze
> verkleinde
> naar het gewenste formaat en het vervolgens uitpoept naar de browser,
>
> maar hij cache niet. dus daar heb ik een oplossing voor gemaakt:
>
> het gaat om deze regels php code:
>
> ---
> header("Cache-Control:");
> header("Expires:");
> header("Pragma:");
>
> $filename=$upload_dir."/".$image;
>
> $last_modified=filemtime($filename);
> $request_headers=apache_request_headers();
> if(array_key_exists("If-Modified-Since", $request_headers) &&
> $last_modified<=strtotime($request_headers["If-Modified-Since"])) {
> header("HTTP/1.x 304 Not Modified");
> die();
> }
> header("Last-Modified: ".gmdate("D, d M Y H:i:s \G\M\T", $last_modified));
> ---
>
> Nu werkt het allemaal lekker als ik als client firefox gebruik,
> maar in internet explorer blijven de plaatjes herladen, lijkt dus of er
> niet wordt gecached.
>
> Overigens heb ik de script tijdens het maken getest met firefox,
> in firefox kon ik namelijk met een plugin de http headers voorbij zien
> komen LiveHttpHeaders.
>
> Maar waarom werkt het nu niet in Inernet Explorer, iemand een idee.
> Weet niet zo 1 2 3 hoe ik de headers die internet explorer stuurt
> makkelijk kan bekijken.
>
>
>
> Hier overigens een request response in firefox:
>
> http://www.loonbedrijf-wildenbeest.nl/xcm/image.php?image=DSC00702.JPG&width=120
>
>
> GET /xcm/image.php?image=DSC00702.JPG&width=120 HTTP/1.1
> Host: www.loonbedrijf-wildenbeest.nl
> User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)
> Gecko/20050225 Firefox/1.0.1
> Accept: image/png,*/*;q=0.5
> Accept-Language: en-us,en;q=0.5
> Accept-Encoding: gzip,deflate
> Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
> Keep-Alive: 300
> Connection: keep-alive
> Referer:
> http://www.loonbedrijf-wildenbeest.nl/index.php?page=pages/occasions.page.xml
>
> Cookie: SESSID=b003c9e7a8da3291ba84dacb3665bc82
> If-Modified-Since: Wed, 09 Mar 2005 14:41:18 GMT
> Cache-Control: max-age=0
>
> HTTP/1.x 304 Not Modified
> Date: Thu, 17 Mar 2005 18:46:45 GMT
> Server: Apache/1.3.33 (Unix) mod_perl/1.29 PHP/4.3.10 mod_ssl/2.8.22
> OpenSSL/0.9.7b
> X-Powered-By: PHP/4.3.10
> Keep-Alive: timeout=15, max=471
> Connection: Keep-Alive
> Content-Type: text/html
>
> Zoals je ziet zegt ie mooi 304 Not Modified, op de een of andere manier
> gebeurd dat niet bij msie.
>
>
>
mm een header("Expires: zinnige tijd") erbij werkt wel,
zou zonder eigenlijk ook moeten werken.
Daniel Tryba
18/03/05, 00:45
Tjerk Wolterink <tjerk@wolterinkwebdesign.com> wrote:
>> Als je de headers van msie erbij pakt weet je (wellicht) waar het
>> probleem ligt.
> >
>
> Ja daar dacht ik ook al aan, maar hoe kan ik daar makkelijk bijkomen?
Met een packetsniffer, bv ethereal
>> Maar ik kan nu al gokken dat het aan de case van de header ligt, IIRC
>> stellen de betrokken RFCs dat dat case insensitive moet zijn.
>
> En dus, dan doe ik toch niks fout?
Juist wel, je array_key_exists is case-sensitive, de $_SERVER variant is
altijd in uppercase, wat het gedrag van apache_request_headers is mij
onbekend (maar ik neem aan dat die gewoon de headers doorgeeft zoals de
browser ze verstuurd heeft.
>> BTW fix je regel lengte eens naar iets < 80.
> done
Sure, dat heb ik al eerder gehoord :)
Daniel Tryba
18/03/05, 01:05
Tjerk Wolterink <tjerk@wolterinkwebdesign.com> wrote:
> header("HTTP/1.x 304 Not Modified");
Dit is gewoon kei illegaal volgense de specs:
HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
Maar ik heb net maar een IE opgegraven en op eigen gevaar even deze
headers onderschept:
GET /xcm/image.php?image=DSC00872.JPG&width=120 HTTP/1.1
Accept: */*
Referer: http://www.loonbedrijf-wildenbeest.nl/index.php?page=pages/occasions.page.xml
Accept-Language: nl
Accept-Encoding: gzip, deflate
If-Modified-Since: Tue, 08 Mar 2005 21:01:44 GMT
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
Host: www.loonbedrijf-wildenbeest.nl
Connection: Keep-Alive
Cookie: SESSID=31a8479d79c83200c7d03b7389133946
HTTP/1.1 304 Not Modified
Date: Thu, 17 Mar 2005 23:52:59 GMT
Server: Apache/1.3.33 (Unix) mod_perl/1.29 PHP/4.3.10 mod_ssl/2.8.22 OpenSSL/0.9.7b
X-Powered-By: PHP/4.3.10
Expires:
Cache-Control:
Pragma:
Keep-Alive: timeout=15, max=499
Connection: Keep-Alive
Content-Type: text/html
Maar ik zie dat je de http versie al hebt gefixed, en laat IE het nu
toevallig wel goed doen!
Tjerk Wolterink wrote:
> ik had een php script gemaakt die een plaatje op de server inlas, deze
> verkleinde
> naar het gewenste formaat en het vervolgens uitpoept naar de browser,
Als dat resizen zo veel werk is dan zou ik dat echt niet voor elke
bezoeker opnieuw gaan doen (zelfs niet 1 keer per bezoeker). Je kan in
zo'n geval beter server-side cachen door het resultaat van die
verkleiningen zelf op te slaan en her te gebruiken.
- kijk in de cache-directory: is er al een bestand "$filename$width" ?
- zo nee, resize de afbeelding en sla die op in cache/$filename$width
- header("Content-Type:image/jpeg"); readfile("cache/$filename$width");
--
groeten,
Boudewijn
Daniel Tryba
18/03/05, 02:05
Boudewijn <me@privacy.org> wrote:
> - kijk in de cache-directory: is er al een bestand "$filename$width" ?
> - zo nee, resize de afbeelding en sla die op in cache/$filename$width
> - header("Content-Type:image/jpeg"); readfile("cache/$filename$width");
ipv die laatste zou ik naar de betreffende cache file redirecten. Als je
letterlijk bovenstaande doet wordt het plaatje weer elke keer opgehaalt.
Als je naar de url naar het plaatje wijst kunnen de client en server hun
eigen truckendoos open trekken om te controleren of de file moet worden
opgehaalt.
bv http://tmp.tryba.nl/resize/img.phps welke dat dus voor de raw en
thumb versies doet (het niet opslaan van de andere versies is een
afwegig van diskspace tegen cpu tijd).
John Bokma
18/03/05, 02:15
Boudewijn wrote:
> Tjerk Wolterink wrote:
>> ik had een php script gemaakt die een plaatje op de server inlas, deze
>> verkleinde
>> naar het gewenste formaat en het vervolgens uitpoept naar de browser,
>
> Als dat resizen zo veel werk is dan zou ik dat echt niet voor elke
> bezoeker opnieuw gaan doen (zelfs niet 1 keer per bezoeker).
Hangt van dingen af als disk space, snelheid, en hoeveel keer het plaatje
bekeken wordt.
Zelfs als je om een bepaalde reden 1 methode kiest kan het geen kwaad om
die na bepaalde tijd te evalueren. (Om wellicht onaangenaam verast te
worden :-D ).
--
John Voorbeeldscripts in Perl: http://johnbokma.com/perl/
Website design: http://johnbokma.com/websitedesign/
Ervaren Perl / Java programmeur beschikbaar: http://castleamber.com/
Tevreden opdrachtgevers: http://castleamber.com/testimonials.html
Daniel Tryba wrote:
> Boudewijn <me@privacy.org> wrote:
>
>>- kijk in de cache-directory: is er al een bestand "$filename$width" ?
>>- zo nee, resize de afbeelding en sla die op in cache/$filename$width
>>- header("Content-Type:image/jpeg"); readfile("cache/$filename$width");
>
>
> ipv die laatste zou ik naar de betreffende cache file redirecten. Als je
> letterlijk bovenstaande doet wordt het plaatje weer elke keer opgehaalt.
> Als je naar de url naar het plaatje wijst kunnen de client en server hun
> eigen truckendoos open trekken om te controleren of de file moet worden
> opgehaalt.
>
> bv http://tmp.tryba.nl/resize/img.phps welke dat dus voor de raw en
> thumb versies doet (het niet opslaan van de andere versies is een
> afwegig van diskspace tegen cpu tijd).
Mwah. Die readfile() geeft niet zoveel overhead, terwijl een externe
redirect weer een complete communicatie tussen client en server betekent
(met weer een RTT ertussen).
Ook is het nog maar de vraag of het afhandelen van twee requests (1 voor
de PHP-redirect en 1 statische thumbnail) minder CPU-tijd kost dan het
afhandelen van 1 request waarbij het bestand door PHP ingelezen wordt.
--
groeten,
Boudewijn.
Daniel Tryba
18/03/05, 02:45
Boudewijn <me@privacy.org> wrote:
>> ipv die laatste zou ik naar de betreffende cache file redirecten. Als je
>> letterlijk bovenstaande doet wordt het plaatje weer elke keer opgehaalt.
>> Als je naar de url naar het plaatje wijst kunnen de client en server hun
>> eigen truckendoos open trekken om te controleren of de file moet worden
>> opgehaalt.
>
> Mwah. Die readfile() geeft niet zoveel overhead, terwijl een externe
> redirect weer een complete communicatie tussen client en server betekent
> (met weer een RTT ertussen).
Je mist mijn punt: tenzij je alle functionaliteit erin bakt die een
normale browser en server aan boord hebben (en dat is meer dan een
expires en if-not-modified-since header) ben je niet echt efficient
bezig.
> Ook is het nog maar de vraag of het afhandelen van twee requests (1 voor
> de PHP-redirect en 1 statische thumbnail) minder CPU-tijd kost dan het
> afhandelen van 1 request waarbij het bestand door PHP ingelezen wordt.
Welkom in de wondere wereld van HTTP/1.1, dat gaat in die gevallen over
de zelfde connectie.
Tjerk Wolterink
18/03/05, 10:15
Daniel Tryba wrote:
> Tjerk Wolterink <tjerk@wolterinkwebdesign.com> wrote:
>
>>header("HTTP/1.x 304 Not Modified");
>
>
> Dit is gewoon kei illegaal volgense de specs:
Ja stom foutje, gefixed naar HTTP:/1.1
>
> HTTP-Version = "HTTP" "/" 1*DIGIT "." 1*DIGIT
>
> Maar ik heb net maar een IE opgegraven en op eigen gevaar even deze
> headers onderschept:
>
> GET /xcm/image.php?image=DSC00872.JPG&width=120 HTTP/1.1
> Accept: */*
> Referer: http://www.loonbedrijf-wildenbeest.nl/index.php?page=pages/occasions.page.xml
> Accept-Language: nl
> Accept-Encoding: gzip, deflate
> If-Modified-Since: Tue, 08 Mar 2005 21:01:44 GMT
> User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 1.1.4322)
> Host: www.loonbedrijf-wildenbeest.nl
> Connection: Keep-Alive
> Cookie: SESSID=31a8479d79c83200c7d03b7389133946
>
>
> HTTP/1.1 304 Not Modified
> Date: Thu, 17 Mar 2005 23:52:59 GMT
> Server: Apache/1.3.33 (Unix) mod_perl/1.29 PHP/4.3.10 mod_ssl/2.8.22 OpenSSL/0.9.7b
> X-Powered-By: PHP/4.3.10
> Expires:
> Cache-Control:
> Pragma:
huh hoe kan dat,
die expires cache control en pragma die moeten toch weg worden gelaten
als je in php bijvoorbeeld header("Pragma:"); plaatst?
> Keep-Alive: timeout=15, max=499
> Connection: Keep-Alive
> Content-Type: text/html
>
> Maar ik zie dat je de http versie al hebt gefixed, en laat IE het nu
> toevallig wel goed doen!
Tjerk Wolterink
18/03/05, 10:15
Boudewijn wrote:
> Tjerk Wolterink wrote:
>
>> ik had een php script gemaakt die een plaatje op de server inlas, deze
>> verkleinde
>> naar het gewenste formaat en het vervolgens uitpoept naar de browser,
>
>
> Als dat resizen zo veel werk is dan zou ik dat echt niet voor elke
> bezoeker opnieuw gaan doen (zelfs niet 1 keer per bezoeker). Je kan in
> zo'n geval beter server-side cachen door het resultaat van die
> verkleiningen zelf op te slaan en her te gebruiken.
>
> - kijk in de cache-directory: is er al een bestand "$filename$width" ?
> - zo nee, resize de afbeelding en sla die op in cache/$filename$width
> - header("Content-Type:image/jpeg"); readfile("cache/$filename$width");
>
>
Dat is een goed idee. Maar het werkt nu en niet langszaam, dit is een
verbetering die ik er later nog in kan brengen.
Daniel Tryba wrote:
> Boudewijn <me@privacy.org> wrote:
>
>>>ipv die laatste zou ik naar de betreffende cache file redirecten. Als je
>>>letterlijk bovenstaande doet wordt het plaatje weer elke keer opgehaalt.
>>>Als je naar de url naar het plaatje wijst kunnen de client en server hun
>>>eigen truckendoos open trekken om te controleren of de file moet worden
>>>opgehaalt.
>>
>>Mwah. Die readfile() geeft niet zoveel overhead, terwijl een externe
>>redirect weer een complete communicatie tussen client en server betekent
>>(met weer een RTT ertussen).
>
> Je mist mijn punt: tenzij je alle functionaliteit erin bakt die een
> normale browser en server aan boord hebben (en dat is meer dan een
> expires en if-not-modified-since header) ben je niet echt efficient
> bezig.
Blijkbaar mis ik je punt nog steeds, want ik zie echt niet waar die
inefficientie nou zit.
Bij een 302-redirect mag de browser geen gebruik maken van caching [1].
Bij een refresh wordt dus gewoon weer de .php aangevraagd, die stuurt
weer een redirect naar de jpeg, dan vraagt de browser de jpeg op (deze
keer met If-Modified-Since) en dan pas mag de server een 304 Not
Modified geven. Aan die PHP-aanroep ontkom je zo dus niet.
>>Ook is het nog maar de vraag of het afhandelen van twee requests (1 voor
>>de PHP-redirect en 1 statische thumbnail) minder CPU-tijd kost dan het
>>afhandelen van 1 request waarbij het bestand door PHP ingelezen wordt.
>
> Welkom in de wondere wereld van HTTP/1.1, dat gaat in die gevallen over
> de zelfde connectie.
Uiteraard, maar die nieuwe request moet nog steeds afgehandeld worden
*en* er zit netwerkvertraging tussen. Zelfs als een redirect minder
zwaar op de server is, dan zal het voor de client langer duren door die
extra communicatie-stap.
Het beste is natuurlijk om meteen de statische thumbnail in de HTML te
zetten :-).
--
[1] tenzij aangegeven met Cache-Control/Expires in de redirect zelf,
maar dat doet je script niet.
Daniel Tryba
18/03/05, 18:25
Boudewijn <me@privacy.org> wrote:
>> Je mist mijn punt: tenzij je alle functionaliteit erin bakt die een
>> normale browser en server aan boord hebben (en dat is meer dan een
>> expires en if-not-modified-since header) ben je niet echt efficient
>> bezig.
>
> Blijkbaar mis ik je punt nog steeds, want ik zie echt niet waar die
> inefficientie nou zit.
Het ophalen van de data.
> Bij een 302-redirect mag de browser geen gebruik maken van caching [1].
De 302 hoeft ook helemaal niet gecached te worden.
> Bij een refresh wordt dus gewoon weer de .php aangevraagd, die stuurt
> weer een redirect naar de jpeg, dan vraagt de browser de jpeg op (deze
> keer met If-Modified-Since) en dan pas mag de server een 304 Not
> Modified geven. Aan die PHP-aanroep ontkom je zo dus niet.
Een 301 lost dat op.
>> Welkom in de wondere wereld van HTTP/1.1, dat gaat in die gevallen over
>> de zelfde connectie.
>
> Uiteraard, maar die nieuwe request moet nog steeds afgehandeld worden
> *en* er zit netwerkvertraging tussen. Zelfs als een redirect minder
> zwaar op de server is, dan zal het voor de client langer duren door die
> extra communicatie-stap.
17ms, van het closen van de socket die bij de 302 hoort tot de response
op statische URL.
> Het beste is natuurlijk om meteen de statische thumbnail in de HTML te
> zetten :-).
Er is maar 1 browser die dat niet onderstuend, 3 maal raden welke :(