WordPressでのセッションについて:メモ

WordPress自体はセッションを使っていないようなので(この件についての記事をどこかで見たのですが再度探しても見つからず)、セッションを使う場合は独自にsession_start()を書く必要があります。

しかし実際に使おうとすると初手で悩む部分があり、個人的にまとめたいと思います。

実現したいこと

  • WordPressでセッションを使う
  • 安全第一

試す際に気になったことは以下の点。

  1. session_start()は2つ以上書くとエラーがでる
  2. プラグインがsession_start()をすでに書いている可能性がある
  3. エラーを出さないようにsession_start()を書く必要がある

WordPressでセッションを使うこと自体の是非も気になるのですが、その件の情報が見つけられていないのでとりあえず今はおいておきます(WPについてではありませんが記事末尾で少しこの件に触れています)。

対応策

基本的な対応策は以下のようになりそうです。

  • セッションがすでに開始されているかを判定する
  • エラーの出力を止める

セッションがすでに開始されているかを判定する

上記ページ内の書かれた方法を以下に記載します。


//PHP 5 >= 5.4.0
//php5.4.0より低いバージョンではsession_status()が使えない
if(session_status() !== PHP_SESSION_ACTIVE) session_start();
//または
if(session_status() === PHP_SESSION_NONE) session_start();

このページに書かれている内容として、以下のようにも書かれています。

Don’t use
if(!isset($_SESSION)) session_start();
or
if(session_id() === “”) session_start();

They will not work properly after a call to session_write_close().
Both functions will continue to report, that the session exists.
And this is right, you can read from $_SESSION, but if you want to write,
you need session_start() again.

session_write_close()があると上記のisset($_SESSION)session_id()を使った書き方では対応できないとのこと。

なお、session_status()はPHP5.4.0以上しか使えませんが、WPの最低要件が5.6になっているため問題はないと思われます。

ここまでを踏まえると以下のようになるかと。


function my_session(){
 if(session_status() !== PHP_SESSION_ACTIVE){
  session_start();
 }
 $_SESSION['foo'] = 'var'; 
}
add_action('init', 'my_session');

エラーの出力を止める

同じく上記ページに以下のように書かれています。

As a shorthand you can use
@session_start()
with the @ at the beginning to suppress the
PHP notice “A session had already been started – ignoring session_start()”

As stated in the manual for session_start(), a second call will do no harm,
it will be simply ignored. But you need the @, if you don’t want to get the notice.

そもそもsession_start()を2回以上書いても、2つ目以降が無視されるため、@をつけてエラー出力を抑制するだけでよいという方法で以下のようになります。


function my_session(){
 @session_start();
 $_SESSION['foo'] = 'var'; 
}
add_action('init', 'my_session');

問題点

  • 自作ではない方のsession_start()があとで実行されるとエラーがでる

上記に対して良い解決策が浮かばないのですが、現状でできることといえば以下のいずれかではと思います。

  • フックの優先度を低くする
  • できるだけ実行が遅いフィルターにフックする

WordPressでsession_start()を使うことを説明している記事では大抵がinitにフックしています。
そのため全ての製作者がここにフックするなら、優先度の数値を操作することで安全性が高まります。

他方この仮定が正しい場合、おそらく他の方もsession_start()の重複エラー出力に対する回避手段を講じている可能性が高く、そうであるなら問題は発生しにくいのではと思います。

問題が発生するのは重複が気にされていない場合で、対応策としては実行が遅いフィルターにフックさせるぐらいしか思いつきませんでした。
一応session_start()に絡んだフックの情報として以下のような記述は見つけました。

There is no regular output and hence no header sent before template_redirect on the front end.
If you need sessions on the back end too, use the action wp_loaded to cover both.

上記を参考にすると以下のようになります。

  • template_redirectより前でないと動作しない(headerが送信されないため)
  • バックエンドでもセッションが必要ならwp_loadedを使う

試したところwp_headでも動きましたが、ともかくinit以降にフックするのもありなのかもしれません。

もちろんセッションをどこにどう使うのか次第ではあるので、最終的にはinitを使うことになりそうですが。

結び

上記の記事には以下のような注記があります。

Keep in mind that using sessions adds a whole set of very complex problems to your code, including security, scalability (load balancers), and following time consuming support issues. I don’t recommend it.

要約すると、セッションを導入するとセキュリティや構造の複雑化などの問題が発生するので勧められない、ということになるかと。

もちろん「だから使うな」ということではありません。むしろセキュリティ面では必要な機能ですし。

ただ、使うなら慎重な方がよいはずです。

17人がこの記事を評価

役に立ったよという方は上の「記事を評価する」ボタンをクリックしてもらえると嬉しいです。

連投防止のためにCookie使用。SNSへの投稿など他サービスとの連動は一切ありません。

コメント欄