PHP で Apache2 ライクな ETag を生成する

2007-08-12 22:30:03 | | このエントリーを含むはてなブックマーク | Tag: apache php プログラミング

静的ページに見せかけるために調べてみた。

Google で検索したところ、drry+@-> PHP で Apache 風 ETag の生成が見つかった。この方法だと、確かにハイフンで区切られた最後の部分が、Apache で生成されるべき値ではなかった。

そこで少し調べてみた。まず、「そもそもファイルの更新時刻ではない」というところから。これは Apache のドキュメントファイルの更新時刻を ETag 生成に利用できると書いてあるので否定される。つまり、最後のパートはファイルの更新時刻となる。

続いて「ファイルの更新時刻だけなのか」という点について。これについてはファイルの更新時刻を変更するほか無い。ファイルの更新時刻にだけ依るならば、2 つ以上の内容の異なるファイルで、唯一更新時刻だけを同じにすれば分かる。ファイルの更新時刻を任意に設定するには touch コマンドを使うと便利。例えば 2007-08-12T01:23:45 に設定するならば、touch -t 200708120123.45 FILENAME となる。結果、最後のパートは同じ ETag が生成されたので更新時刻にだけ依ると分かった。

そして最後は「更新時刻を基にハッシュ値を用いているのではないか」という点。ハッシュ値ならば諦めるしかないかと思ったが、Apache のソースコードより httpd-2.2.4/modules/http/http_etag.c に含まれる ap_make_etag 関数を見てみるとハッシュ値ではないと分かった。

ap_make_etag 関数の一部

        if (etag_bits & ETAG_INODE) {
            next = etag_ulong_to_hex(next, (unsigned long)r->finfo.inode);
            bits_added |= ETAG_INODE;
        }
        if (etag_bits & ETAG_SIZE) {
            if (bits_added != 0) {
                *next++ = '-';
            }
            next = etag_ulong_to_hex(next, (unsigned long)r->finfo.size);
            bits_added |= ETAG_SIZE;
        }
        if (etag_bits & ETAG_MTIME) {
            if (bits_added != 0) {
                *next++ = '-';
            }
            next = etag_ulong_to_hex(next, (unsigned long)r->mtime);
        }

というわけで、恐らく利用されている mtime が違うのだろうということが分かった。因みに ap_make_etag 関数中で利用されている etag_ulong_to_hex 関数は、単純に long 型を 16 進数に変換しているだけである。

あとは複数のサンプルを取って、数学的に解くほか無い。まず 1 秒ごとに更新時刻を変更したファイルにアクセスし、ETag がどのように変化するか調べた。

  • a296aac0 (12:20:35)
  • a2a5ed00 (12:20:36)
  • a2b52f40 (12:20:37)

差を取ると、どれも F4240(16)、即ち 1,000,000 だった。ということで、drry+@-> PHP で Apache 風 ETag の生成を次のように変えると Apache と全く同じ ETag を生成できる。

修正した ETag 生成コード

$etag    = sprintf( '"%x-%x-%x"', $stats['ino'], $stats['size'], $stats['mtime'] * 1000000 );

これからすると、Apache の内部では更新時刻をマイクロタイム単位で扱っているようだ。

Related Entries

There is not related articles.

Trackbacks

Trackback URI: http://blog.c--v.net/trackback/2007/08/12/1

There is no trackback.

Comments

There is no comment.

Name
URI (Homepage or Email)
Body