#navi_header|PHP| きっかけは画像を出力するPHPを作ってたときに、Last-Modifiedを作る必要があって。 で、 http://www.studyinghttp.net/header#Last-Modified を読んでたらHTTP-Dateというのが出てきて、 http://www.studyinghttp.net/header#HTTP-Date を読んでたら"GMT表記"が必要らしい。 #more|| 今まであまり気にしてきませんでしたが、Last-Modified や If-Modified-Since は特に画像などをPHPでブリッジして出力させるとき、パケット量を抑える為に必須です。である以上、それなりにきっちりしておかないと、せっかく実装してもGMT関連の認識ズレで304が返せない・・・ってなことにもなりかねません。 で、基本。 #pre||> DOS>php -r "echo mktime(0, 0, 0, 1, 1, 1970);" Warning: mktime(): Windows does not support negative values for this function in Command line code on line 1 -1 DOS>php -r "echo mktime(9, 0, 0, 1, 1, 1970);" 0 DOS>php -r "echo gmmktime(9, 0, 0, 1, 1, 1970);" 32400 ||< ええっと、つまり、mktimeは「その地域での時刻表記→GMTでは何秒経過しているか」を算出。 で、gmmktimeは「今いる場所をGMTとして、今の時刻表記をそのままGMTでは何秒経過しているか」を算出。 だから、 32400 = 3600 * 9 つまり9時間分、ずれているわけ。 DOS>php -r "echo strftime('%a, %d %b %Y %H:%M:%S', mktime(9, 0, 0, 1, 1,1970));" Thu, 01 Jan 1970 09:00:00 →これは、mktime()は・・・0を返す。つまり、日本時間で9時というのは、GMTでは0 秒ということ。 で、strftimeの引数は、GMTでのタイムスタンプ。つまり、0秒→GMTでの0秒→当然、 日本時間では9時。 DOS>php -r "echo gmstrftime('%a, %d %b %Y %H:%M:%S', mktime(9, 0, 0,1, 1, 1970));" Thu, 01 Jan 1970 00:00:00 →gmstrftimeの引数も当然GMTでのタイムスタンプ。ただし、表記した結果はGMTでの 表記になる。 つまり、0秒→GMTでの0秒→GMTでの表記になるから、当然、00:00:00. DOS>php -r "echo strftime('%a, %d %b %Y %H:%M:%S', gmmktime(9, 0, 0,1, 1, 1970));" Thu, 01 Jan 1970 18:00:00 →これは間違えたパターン。gmmktimeで返されるのは、引数をGMTとみなしたときの秒数。つまり、9*3600が返される。 で、これをそのままGMTでの9*3600と考えたので、strftimeは日本時間に直すときにさらに9時間足すため、18時になる。 DOS>php -r "echo gmstrftime('%a, %d %b %Y %H:%M:%S', gmmktime(9, 0, 0, 1, 1, 1970));" Thu, 01 Jan 1970 09:00:00 →これは、IN/OUT両方ともGMTでそろえた場合。引数にはGMTでの時間を渡し、GMTでの秒が返され、gmstrftimeではGMTでの秒数として受け取り、GMTでの表記で出力している。 こう考えると、引数や返り値の"timestamp"はあくまでも"GMT「としてみなされる」"ことが暗黙の前提と考えてよいような気がする。 例えば、2007-04-25 18:15:XX付近で以下のコードを実行してみる。 DOS>php -r "echo gmmktime(18, 15, 0, 4, 25, 2007);" 1177524900 DOS>php -r "echo time();" 1177492531 これ、コマンドラインで実行する時差を補正すれば、ちょうど9時間ずれている。逆に、mktime()だとちょうど同じ。 ようするに、time()は、現在のロケールと同時点でのGMTの秒数を返す。 つまり、ロケールに基づく時差をZとし、現在ロケールの時刻表現をargとすれば、 mktime = arg - Z = time() gmmktime = arg = time() + Z よって、以下になる。 DOS>php -r "echo gmmktime(18, 15, 0, 4, 25, 2007) - mktime(18, 15, 0, 4, 25, 2007);" 32400(=9 * 3600) (= arg - (arg - Z)) 通常のmktimeやstrftimeが、内部的にZを補正するのは・・・time()の挙動に引きずられているとみなせる。 time()自体はGMT秒数を出力するため、常に GMT となる。 strftimeを、f(ARG) = ARG + Z として定義すれば、 strftime(GMT) = GMT + Z となり、現在ロケールでの表記が取得できる。ここで、 X(ARG) = strftime(mktime(ARG)) とすれば、 X(ARG) = mktime(ARG) + Z = ARG - Z + Z = ARG として、最初にmktimeに渡した、現在ロケールに基づくタイムスタンプと同一の、文字表現が取得できる。 "同時点"というのがキーワードになる。 mktime, strftimeは、結局"同時点"でのGMTを返したり、引数にとる。 gmktime, gmstrftimeは、同時点補正を行わない。つまり、今いる位置がグリニッジと想定する。 逆に言えば、"同時点でのGMTでの表記がほしい!"となれば?time()はGMT時間を返す。 あとはそれをそのまま、グリニッジにいると思わせればよいので、gmstrftimeに mktime() か time() を食わせればよい。 しかしこれ、実際にHTTP Headerで使うとしたら、ブラウザ側どうして来るんだろうな・・・。 結局"同時点でのGMT"を中心に動かすわけで・・・動くんだよな・・・。 echo strftime('%a, %d %b %Y %H:%M:%S GMT', mktime(9, 0, 0, 1, 1, 1970)); (→PHP4.3.6 on Windowsだと、%T(=%H:%M:%S)が認識されなかった) Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format #navi_footer|PHP|