[PHP] Re: generate an etag header that apache can subsequently use, how?

2007-06-22 Thread M. Sokolewicz

hey Jochem,
as far as I can see, this should work for you:
?php
$stats = stat('/dev/shm/file');
$etag = sprintf('%x-%x-%x', $stats['ino'], $stats['size'], 
$stats['mtime']); // lowercase hexadecimal numbers separated by dashes

header('Etag: '.$etag);
?

Assuming your apache is configured to use the inode, modification time 
and filesize in its etag.


The function you attached simply converts integers of type long to 
hexadecimal strings. It is not the actual function creating the etag itself.


- Tul

Jochem Maas wrote:

I have an image.php script that generates images on the fly,
way back when this didn't even cache it's result! over time it's got better
and better so that now it caches resampled images and outputs Last-Modified
headers so that it can send subsequent requests and send out a 304
if appropriate.

but ... I need more speed ... so I changed the way in which the cached
files were named, setup apache Rewrite rules to serve images directly
from the cache of resampled images (stored in /dev/shm) and offered
up urls in the form /cache/foo.jpg rather than /image.php?f=foo.jpg - this 
works fine
and apache automatically sends out Etag headers when it serves up the resampled
files from the cache, additionally handing out a 304 when it receives a
valid Etag in a request.

when a cached, resampled image does not exist an apache Rewrite rule
will call image.php which will generate the image and output it... BUT it
won't generate an Etag header which means that on the second request to an
image it will downloaded again because apache does not find an Etag header.

I'd like to be able to generate an Etag header in php that matches
what Apache generates, I ended up in the apache source code here:

http://svn.apache.org/viewvc/httpd/httpd/branches/2.0.x/modules/http/http_protocol.c?view=markup

specifically this function, which is used to create each of
various 'bits' of the Etag apache generates (by default: Inode, FileSize and
FileModificationTime are used but this can be controlled with
the FileEtag apache directive):

static char *etag_ulong_to_hex(char *next, unsigned long u)
{
int printing = 0;
int shift = sizeof(unsigned long) * 8 - 4;
do {
unsigned long next_digit = ((u  shift)  (unsigned long)0xf);
if (next_digit) {
*next++ = HEX_DIGITS[next_digit];
printing = 1;
}
else if (printing) {
*next++ = HEX_DIGITS[next_digit];
}
shift -= 4;
} while (shift);
*next++ = HEX_DIGITS[u  (unsigned long)0xf];
return next;
}

I have been trying to translate what this does to php code without
any luck, dechex() it is not! basically I don't really understand what this
function is doing. can anyone help?


--
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



Re: [PHP] Re: generate an etag header that apache can subsequently use, how?

2007-06-22 Thread Jochem Maas
hi Tul,

thanks for the feedback ... can I borrow your brain for a little longer? 

M. Sokolewicz wrote:
 hey Jochem,
 as far as I can see, this should work for you:
 ?php
 $stats = stat('/dev/shm/file');
 $etag = sprintf('%x-%x-%x', $stats['ino'], $stats['size'],
 $stats['mtime']); // lowercase hexadecimal numbers separated by dashes
 header('Etag: '.$etag);
 ?

this is what I thought - actually I originally used dechex() - which gave the
same output as sprintf(%x, ...) ... which is not surprising.

sidenote: I'm actually only using the modification time in the etag right now.
I figure this keeps it a little faster - there is next to no chance to
that the filemtime will change and the file will be the same and using the inode
info is silly because moving the files locally (for whatever reason) shouldn't 
affect
whether a 304 can be given (imho). the fact that this may result in many files 
with
identical Etags maybe incorrect but I don't see the problem as the URL (and 
therefore
the local file) is going to be different.

BIG BUT: apache is not generating the same hexadecimal value for the filemtime 
of a
given file as I get from the various attempts with php

for a given file I get:

apache Etag : 8e6bbb80
mtime via stat(): 1182540030
mtime via filemtime()   : 1182540030
sprintf(%x) Etag  : 467c20fe
dechex() Etag   : 467c20fe

the http headers for the URL of the file in question are:

Date: Fri, 22 Jun 2007 23:00:13 GMT
Server: Apache
Last-Modified: Fri, 22 Jun 2007 19:20:30 GMT
Etag: 8e6bbb80
Accept-Ranges: bytes
Content-Length: 11924
Content-Type: image/jpeg
X-lori-time-2: 1182553213537

an 'ls -l' on the file in question gives (name of file changed to protect the 
innocent):

-rw-r--r-- 1 apache apache 11924 Jun 22 21:20 foo.jpg

I swear it's the same file but apache is generating the hexadecimal 
representation of the
filemtime differently than a 'straight' dec2hex conversion (ala dechex() and 
sprintf())

doing a hexdec() on the apache generated Etag shows that this is not a question
of mtimes being slightly off (for some reason):

hexdec(8e6bbb80) = 2389425024

I'm stumped, the comments for etag_ulong_to_hex() in the apache source even 
states:

Generate the human-readable hex representation of an unsigned long
 (basically a faster version of 'sprintf(%lx)')

I'm rather wary of the 'basically' it smells fishy to me ... rather like saying 
I'm basically
a women - sure there is a resemblance, but bit of investigation will show 
plenty of differences.

I have been checking with static image files (ones that go no where near a 
resampling script)
and the same problem occurs.




my desk is covered in hair :-/

PS - completely offtrack but what's X-lori-time-2 - I've noticed since not 
long ago,
I have no idea what it is or what purpose it serves, and seemingly nor do the 
search engines.

 
 Assuming your apache is configured to use the inode, modification time
 and filesize in its etag.
 
 The function you attached simply converts integers of type long to
 hexadecimal strings. It is not the actual function creating the etag
 itself.

...


 I'd like to be able to generate an Etag header in php that matches
 what Apache generates, I ended up in the apache source code here:

 http://svn.apache.org/viewvc/httpd/httpd/branches/2.0.x/modules/http/http_protocol.c?view=markup



...


 static char *etag_ulong_to_hex(char *next, unsigned long u)
 {
 int printing = 0;
 int shift = sizeof(unsigned long) * 8 - 4;
 do {
 unsigned long next_digit = ((u  shift)  (unsigned long)0xf);
 if (next_digit) {
 *next++ = HEX_DIGITS[next_digit];
 printing = 1;
 }
 else if (printing) {
 *next++ = HEX_DIGITS[next_digit];
 }
 shift -= 4;
 } while (shift);
 *next++ = HEX_DIGITS[u  (unsigned long)0xf];
 return next;
 }


...

-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php