PHPに限ったことではないが

[ Ubuntu 18.04.1 / PHP 7.2.24 / Apache 2.4.29 ]

  1. セッション開始してる?
  2. セッションファイルは作成できてる?
  3. サーバーはセッションCookieを返してる?
  4. クライアントはCookieを記憶してる?
  5. クライアントはセッションCookieを送ってる?

セッション開始してる?

そもそも sesson_start() 忘れてたらダメ。

セッションを利用する全ての処理より手前で sesson_start() してることを確認。

あと、session_start() は失敗した時に false を返すらしいから、それも確認しておいた方がいいかもしれない。

if (!session_start()) {
	echo 'セッション開始失敗!';
}

セッションファイルは作成できてる?

セッション情報はサーバー側でファイルに書いて保存されるわけだから、ファイルが作れないとダメ。

ファイル置き場の場所を確認

サーバー上でのセッションファイル置き場を確認するには、phpinfo()session.save_path を見るのが早い。

このとき、phpinfo() 用のページを作らず以下コマンドでも確認できる。が、コマンドライン用とサーバー用で違う設定ファイルを使ってる環境の場合、これで確認できるのはコマンドライン用の方の設定になるので留意。正確に確認したければ、phpinfo() 用のページを作ってブラウザから閲覧したほうがいい。

コマンド
php -r 'phpinfo();' | grep session.save_path
実行結果
session.save_path => /var/lib/php/sessions => /var/lib/php/sessions

パスが二つ表示されてるけど、左側が Local Value で右側が Master Value。たぶん左を見ればいいと思う。

以下、この項ではセッション置き場は /var/lib/php/sessions とする。

ファイル置き場のパーミッションを確認

場所が分かったら、まずセッションファイル置き場のパーミッションを確認する。(一つ上のディレクトリで ls)

コマンド
sudo ls -l /var/lib/php
実行結果 (例:抜粋)
drwx-wx-wt 2 root     root     4096 Nov 24 23:09 sessions

この時、Apacheの実行ユーザーが書き込みできるパーミッションになってなければアウト。↑の例では誰でも書き込み可能 (w) だから大丈夫だったけど、ダメだったら chmod なり chown で適切に設定する。

なおApacheの実行ユーザーは、筆者環境では /etc/apache2/envvarsAPACHE_RUN_USER で定義されてて www-data という名前だった。所有者・グループで絞るなら参考に。

ファイル置き場の中身を確認

パーミッションが大丈夫だったら、セッションファイル置き場の中にセッションファイルが作成されているか確認する。

コマンド
sudo ls -l /var/lib/php/sessions
実行結果 (例)
-rw------- 1 www-data www-data 54 Nov 24 22:58 sess_4qn7ujubnsgrb12k3aulec1098
-rw------- 1 www-data www-data 54 Nov 24 22:34 sess_n5ntm58rps7pb0vcncoh07hgj5

↑こんな感じで、最後に対象のページにアクセスした日時のファイルがあれば、セッションファイルはちゃんと作成できてる。

あとは cat なりで中身も見て、プログラム内から書き込んだものが入ってるか確認する。

コマンド
sudo cat /var/lib/php/sessions/sess_4qn7ujubnsgrb12k3aulec1098
実行結果 (例)
myname|s:8:"kiriukun";

見慣れない形式で格納されてるけど、それっぽいものが入ってればセッションは書けてるからOK。

サーバーはセッションCookieを返してる?

異なる通信で同じセッション情報を使うには、サーバー側で保持してるセッションIDをクライアントに教えてあげる必要がある。

セッションIDの共有にはCookieを使う。これがいわゆるセッションCookieで、PHPで session_start() してれば、スクリプト終了時に自動でクライアントにセッションCookieが送信される。

これは、実際にはレスポンスに Set-Cookie ヘッダを付与することで行われる。ただしリクエスト時に、すでに開始済みのセッションIDを Cookie ヘッダで送信してる場合、新たにセッションCookieは送られてこない。

よって、セッションを使うページに Cookie ヘッダ無しでリクエストを投げた時、レスポンスヘッダに Set-Cookie が設定されており、その内容にセッションIDが入ってることを確認する。

ここでは curl コマンドを使うが、レスポンスヘッダが見られさえすればブラウザの開発者ツールでも何でもいい。ただしブラウザの場合、リクエスト時に Cookie ヘッダが付与されないように、あらかじめCookieを消すなどしておくこと。

コマンド
curl -i https://example.com
実行結果 (例:前項との一貫性は無いです)
HTTP/1.1 200 OK
Date: Sun, 24 Nov 2019 14:56:05 GMT
Set-Cookie: PHPSESSID=cv7c99fu57jqh3q9adpjqipbg5; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Vary: Accept-Encoding
Transfer-Encoding: chunked
Content-Type: text/html;charset=UTF-8

(以下、レスポンスボディにつき省略)

↑のようにレスポンスヘッダに 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が入ってることを確認する。

ここは実際にブラウザで当該のボタンを押すなりして、開発者ツールでリクエストヘッダを見るのがいいと思う。

リクエストヘッダ (例:前項との一貫性は無いです)
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: ja,en-US;q=0.9,en;q=0.8
Cache-Control: no-cache
Connection: keep-alive
Content-Length: 152
Content-type: application/x-www-form-urlencoded
Cookie: PHPSESSID=3opcd00pugvs1mft0e4o425ea0; _ga=GA1.2.1502909853.1519540516; __gads=Test; _gid=GA1.2.903538077.1574432300
Host: wwv.kiriukun.com
Origin: https://wwv.kiriukun.com

↑のようにリクエストヘッダに Cookie があって、値に Set-Cookie で送られてきた時と同じセッションCookieが設定されてればOK。

CookieはPHPのセッションのためだけのものじゃないから、Cookie ヘッダには当該サイトで使ってる全ての値が入ってることを留意。この例ではGoogleアナリティクスとかの値も入ってるけど、セッションCookieが正しければ他の値は関係無い。

ここでダメだった場合はどうすればいいかわからないけど、Ajaxかつクライアントとサーバーのドメインが別の場合はCORS制約があるので、クライアント側とサーバー側の両方に細工を入れないとCookieが送れないらしい。詳しくはMDNのAccess-Control-Allow-Credentialsのページなど参照。WebAPIなら、そもそもCookie使うの自体がしんどい気もするけどっ。

以上!