LoginSignup
3
1

More than 3 years have passed since last update.

PHPのsessionでセットされるレスポンスヘッダー

Last updated at Posted at 2019-05-14

PHPのプロジェクトの挙動を追ってたら予想外の挙動に遭遇したのでメモがてら。

TL;DR;

session_startを呼ぶとhttp response headerの中身に書き換わるものがある

詳しく

途中でセットしてあるはずのヘッダーが実際にはサーバーから送信されず、どこからも指定していないヘッダーが送信される、という挙動に遭遇した。

具体的には

header('Cache-Control: pre-check=0');

のようにカスタム?値をセットしているはずがレスポンスには現れず、代わりに以下の3行が追加されていた。ちなみにpre-checkというのは仕様には無く、IE5の独自ヘッダーらしい?

Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache

この値をセットしている記述はどこにもないが、ローカル環境でもプロダクション環境でも同様の値がセットされているため、何かしらの処理が入っているはず。全く当たりがつかないので、ステップ実行しながら怪しい箇所で headers_listを実行して、何に起因しているかを追ってみた。すると、どうやらsession_startをコールした前後で書き換わっているようだった。

なぜこんなことが起きるか分からないのでsession拡張のコードを見てみると
session_start 関数からphp_session_cache_limiter が呼ばれていた。
気になったらこの辺から追ってみると良いでしょう。
https://github.com/php/php-src/blob/f009d6e7c3ce124d1a5a602e7532f93ed55ebae0/ext/session/session.c#L2431

その中ではiniの設定値の session.cache_limiter の中身に従ってヘッダーを設定する処理が記述されている。
https://github.com/php/php-src/blob/f009d6e7c3ce124d1a5a602e7532f93ed55ebae0/ext/session/session.c#L1180-L1208

関連していそうなsession_cache_limiter関数のドキュメントはこちら
https://www.php.net/manual/ja/function.session-cache-limiter.php

私の手元ではsession.cache_limtiernocacheが設定されていたため、

CACHE_LIMITER_FUNC(nocache) /* {{{ */
{
    ADD_HEADER("Expires: Thu, 19 Nov 1981 08:52:00 GMT");

    /* For HTTP/1.1 conforming clients */
    ADD_HEADER("Cache-Control: no-store, no-cache, must-revalidate");

    /* For HTTP/1.0 conforming clients */
    ADD_HEADER("Pragma: no-cache");
}

この処理が実行されて上で記述したヘッダーがセットされているようだった。
このExpiresの日付はなんなんだと思ったけど、この変更が入ったのはどうやら16年も前らしい・・・

試しにExpiresやContent-Typeがどうなるかを見るために

test.php

<?php
header('Content-Type: application/json');
header('Expires: Wed, 18 Nov 1981 00:00:00 GMT');
session_start();

echo json_encode([
    'foo' => 'bar',
]);

という適当なPHPコードを書いてBuilt inサーバーで実行したところ

Content-Type: application/json
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache

というヘッダーが返ってきた。Expiresは上書きされてConetnt-Typeはそのままという想定した挙動になった。

session_startをコールする前にheaderをセットするのはお行儀の悪さが感じられてあまり見ることは無いんじゃないかと思うが、久しぶりにPHPの想定しない挙動に巡り会った。

header関数が呼ばれたらすぐに出力に乗るのかと思っていたけど、headers_sentを実行してもfalseが返ってくるしsession_startも警告を出さないのでどうやら違うらしい。
これも調べてみた方が良さそう。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1