10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

PHP7調査(33)カスタムセッションハンドラの返り値の意味を変更

Last updated at Posted at 2015-05-20

PHPでは独自のセッションハンドラをプログラマが実装することができます。具体的には、session_set_save_handler関数を使うことで、標準のセッションハンドラが対応していないようなストレージにセッション情報を保存することができます。

ところで、PHP5まではカスタムセッションハンドラの返り値の扱いが間違っていました。マニュアルではtruefalseを返すことになっているのですが、実際には失敗なら-1を、成功ならそれ以外を返すというインターフェースになっていました。

これが、PHP7ではマニュアル通りになるよう修正されます。

以下、PHP5でのセッションハンドラの利用例です。

<?php
ini_set('session.gc_divisor',1);

/* PHP5用のカスタムセッションハンドラ */
session_set_save_handler(
    /* open */
    function ($savePath, $sessionName) { return 0; }, /* -1だとFatal error */
    /* close */
    function () { return 0; }, /* -1でもエラーにならない */
    /* read */
    function ($sessionId) { return ['foo' => 'bar']; },
    /* write */
    function ($sessionId, $data) { return 0; }, /* -1だとWarning */
    /* destroy */
    function ($sessionId) { return 0; }, /* -1だとWarning */
    /* gc */
    function ($lifetime) { return 0; },  /* -1でもエラーにならない */
    /* create_sid */
    function () { return 'baz'; }
);

session_id('baaz');
session_start();
session_regenerate_id(TRUE);
session_write_close();

このように、セッションハンドラ内でエラーが起きたときは-1を返す必要がありました。驚くべきことに、マニュアル通りにtrueを返そうがfalseを返そうが成功として扱われていたのです(truefalseを整数にキャストしても10なので、失敗ではない=成功として扱われる)。

一方、PHP7では次のように記述できます。

<?php
ini_set('session.gc_divisor',1);

/* PHP7用のカスタムセッションハンドラ */
session_set_save_handler(
    /* open */
    function ($savePath, $sessionName) { return true; }, /* falseだとFatal error */
    /* close */
    function () { return true; }, /* falseでもエラーにならない */
    /* read */
    function ($sessionId) { return ['foo' => 'bar']; },
    /* write */
    function ($sessionId, $data) { return true; }, /* falseだとWarning */
    /* destroy */
    function ($sessionId) { return true; }, /* falseだとWarning */
    /* gc */
    function ($lifetime) { return true; },  /* falseでもエラーにならない */
    /* create_sid */
    function () { return 'baz'; }
);

session_id('baaz');
session_start();
session_regenerate_id(TRUE);
session_write_close();

成功ならtrueを、失敗ならfalseを返すというわけです。平和ですね。

どうしてこうなった

PHP内部のCの関数は次のような返り値で成功失敗を受け渡しています。

typedef enum {
  SUCCESS =  0,
  FAILURE = -1,		/* this MUST stay a negative number, or it may affect functions! */
} ZEND_RESULT_CODE;

今回のセッションハンドラはbooleanを返すPHP関数ですが、この返り値をそのままC関数の返り値に利用していたために意味が変わっていたというわけです。Cでありがちなうっかりミスと言えなくもないですが、今まで誰も気がつかなかったのがビックリですね。

参照

10
7
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
10
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?