PHPでセッションが効かない気がする時に確認したこと
PHPに限ったことではないが
セッション開始してる?
そもそも sesson_start()
忘れてたらダメ。
セッションを利用する全ての処理より手前で sesson_start()
してることを確認。
あと、session_start()
は失敗した時に false
を返すらしいから、それも確認しておいた方がいいかもしれない。
セッションファイルは作成できてる?
セッション情報はサーバー側でファイルに書いて保存されるわけだから、ファイルが作れないとダメ。
1. ファイル置き場の場所を確認
サーバー上でのセッションファイル置き場を確認するには、phpinfo()
の session.save_path
を見るのが早い。
このとき、phpinfo()
用のページを作らず以下コマンドでも確認できる。が、コマンドライン用とサーバー用で違う設定ファイルを使ってる環境の場合、これで確認できるのはコマンドライン用の方の設定になるので留意。正確に確認したければ、phpinfo()
用のページを作ってブラウザから閲覧したほうがいい。
パスが二つ表示されてるけど、左側が Local Value で右側が Master Value。たぶん左を見ればいいと思う。
以下、この項ではセッション置き場は /var/lib/php/sessions
とする。
2. ファイル置き場のパーミッションを確認
場所が分かったら、まずセッションファイル置き場のパーミッションを確認する。(一つ上のディレクトリで ls
)
この時、Apacheの実行ユーザーが書き込みできるパーミッションになってなければアウト。↑の例では誰でも書き込み可能 (w) だから大丈夫だったけど、ダメだったら chmod
なり chown
で適切に設定する。
なおApacheの実行ユーザーは、筆者環境では /etc/apache2/envvars
に APACHE_RUN_USER
で定義されてて www-data
という名前だった。所有者・グループで絞るなら参考に。
3. ファイル置き場の中身を確認
パーミッションが大丈夫だったら、セッションファイル置き場の中にセッションファイルが作成されているか確認する。
↑こんな感じで、最後に対象のページにアクセスした日時のファイルがあれば、セッションファイルはちゃんと作成できてる。
あとは cat
なりで中身も見て、プログラム内から書き込んだものが入ってるか確認する。
見慣れない形式で格納されてるけど、それっぽいものが入ってればセッションは書けてるからOK。
サーバーはセッションCookieを返してる?
異なる通信で同じセッション情報を使うには、サーバー側で保持してるセッションIDをクライアントに教えてあげる必要がある。
セッションIDの共有にはCookieを使う。これがいわゆるセッションCookieで、PHPで session_start()
してれば、スクリプト終了時に自動でクライアントにセッションCookieが返される。
これは、実際にはレスポンスに Set-Cookie
ヘッダを付与することで行われる。ただしリクエスト時に、すでに開始済みのセッションIDを Cookie
ヘッダで送ってる場合、新たにセッションCookieは返されてこない。
よって、セッションを使うページに Cookie
ヘッダ無しでリクエストを投げた時、レスポンスヘッダに Set-Cookie
が設定されており、その内容にセッションIDが入ってることを確認する。
ここでは curl
コマンドを使うが、レスポンスヘッダが見られさえすればブラウザの開発者ツールでも何でもいい。ただしブラウザの場合、リクエスト時に Cookie
ヘッダが付与されないように、あらかじめCookieを消すなどしておくこと。
↑のようにレスポンスヘッダに Set-Cookie
があって、値に PHPSESSID
が入ってればOK。
PHPSESSID
という名前はPHPの設定によるので、別の名前を使ってるならそっちで見ること。設定値は phpinfo()
の session.name
で確認できる。
ちなみにっ かなりレアケースだと思うけど、筆者はたまたま header_remove()
使ってたら、巻き込まれて Set-Cookie
ヘッダが消えててダメだった!!!!
クライアントはCookieを記憶してる?
ちゃんと Set-Cookie
できてればあり得ないと思うけど一応。
ブラウザの設定とかから当該サイトのCookieを見て、前項のセッションCookieが記録されてるかどうかを確認する。
Chromeだったら開発者ツールのコンソールに document.cookie
と入力して実行するとCookieを表示できて楽だけど、Set-Cookie
時に HttpOnly
が指定されてたら無理かも。(未確認)
クライアントはセッションCookieを送ってる?
最後。ここまででクライアントはサーバーからセッションIDを受け取ってるけど、次の通信時にそのセッションIDをサーバーに送らなければ、セッションは続かない。
セッションが持続するはずのリクエストを行った時、リクエストヘッダに Cookie
が設定されており、その内容にセッションIDが入ってることを確認する。
ここは実際にブラウザで当該のボタンを押すなりして、開発者ツールでリクエストヘッダを見るのがいいと思う。
↑のようにリクエストヘッダに Cookie
があって、値に Set-Cookie
で送られてきた時と同じセッションCookieが設定されてればOK。ここでは PHPSESSID
があるから正しい。
(CookieはPHPのセッションのためだけのものじゃないから、Cookie
ヘッダには当該サイトで使ってる全ての値が入ってるので注意。この例ではGoogleアナリティクスとかの値も入ってるけど、セッションCookieが正しければ他の値は関係無い。)
ここでダメだった場合はどうすればいいかわからないけど、Ajaxかつクライアントとサーバーのドメインが別の場合はCORS制約があるので、クライアント側とサーバー側の両方に細工を入れないとCookieが送れないらしい。詳しくはMDNのAccess-Control-Allow-Credentials
のページなど参照。WebAPIなら、そもそもCookie使うの自体がしんどい気もするけど。
以上!