フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援
フリーランスのためのネットビジネス専門学校 ネットで独立開業を目指す人を応援

PHP の http クライアントの使い方 (Post)

経緯

アクセスする度にセッションIDが新たに生成されてしまい、小一時間ほど浪費してしまった。

環境

  • XAMPP 7.2.5
  • Apache 2.4.33
  • PHP 7.2.5
  • CodeIgniter3.1.0

原因

このコードが原因だった。

system/core/libraries/Session/Session.php(L131)
// Sanitize the cookie, because apparently PHP doesn't do that for userspace handlers
if (isset($_COOKIE[$this->_config['cookie_name']])
    && (
        ! is_string($_COOKIE[$this->_config['cookie_name']])
        OR ! preg_match('/^[0-9a-f]{40}$/', $_COOKIE[$this->_config['cookie_name']])
    )
)
{
    unset($_COOKIE[$this->_config['cookie_name']]);
}

PHPのバージョンとの組み合わせが原因だった

PHP7.1未満と以降でsession_id()で生成されるsession_idの長さや含まれる文字が違うらしい。
↓CodeIgniter3.2.0(現時点ではdev版て書いてある)では対応済みなのを確認。

CodeIgniter3.2.0ではPHPの設定から正規表現を作るようにしてるっぽい
/**
 * Configure session ID length
 *
 * To make life easier, we used to force SHA-1 and 4 bits per
 * character on everyone. And of course, someone was unhappy.
 *
 * Then PHP 7.1 broke backwards-compatibility because ext/session
 * is such a mess that nobody wants to touch it with a pole stick,
 * and the one guy who does, nobody has the energy to argue with.
 *
 * So we were forced to make changes, and OF COURSE something was
 * going to break and now we have this pile of shit. -- Narf
 *
 * @return  void
 */
protected function _configure_sid_length()
{
    if (PHP_VERSION_ID < 70100)
    {
        $hash_function = ini_get('session.hash_function');
        if (ctype_digit($hash_function))
        {
            if ($hash_function !== '1')
            {
                ini_set('session.hash_function', 1);
            }

            $bits = 160;
        }
        elseif ( ! in_array($hash_function, hash_algos(), TRUE))
        {
            ini_set('session.hash_function', 1);
            $bits = 160;
        }
        elseif (($bits = strlen(hash($hash_function, 'dummy', false)) * 4) < 160)
        {
            ini_set('session.hash_function', 1);
            $bits = 160;
        }

        $bits_per_character = (int) ini_get('session.hash_bits_per_character');
        $sid_length         = (int) ceil($bits / $bits_per_character);
    }
    else
    {
        $bits_per_character = (int) ini_get('session.sid_bits_per_character');
        $sid_length         = (int) ini_get('session.sid_length');
        if (($bits = $sid_length * $bits_per_character) < 160)
        {
            // Add as many more characters as necessary to reach at least 160 bits
            $sid_length += (int) ceil((160 % $bits) / $bits_per_character);
            ini_set('session.sid_length', $sid_length);
        }
    }

    // Yes, 4,5,6 are the only known possible values as of 2016-10-27
    switch ($bits_per_character)
    {
        case 4:
            $this->_sid_regexp = '[0-9a-f]';
            break;
        case 5:
            $this->_sid_regexp = '[0-9a-v]';
            break;
        case 6:
            $this->_sid_regexp = '[0-9a-zA-Z,-]';
            break;
    }

    $this->_sid_regexp .= '{'.$sid_length.'}';
}

解決策

主に2つ。
1. CodeIgniterのバージョンを3.2.0に上げる
2. 当該コードを書き換える

両方の手段を試してみて、自分の環境ではどちらでも解決できることを確認しました。
ちなみに自分は前者で対応しました。
サーバ環境的にもPHPのバージョンは7.2以降で進めていますし、開発も序の口なので今のうちに上げておこうと。

当該コードの書き換えに関しては、動作させるサーバ上で生成されるセッションIDのルールに合わせて正規表現を変えるだけで問題ありませんでした。

自分の環境の場合
preg_match('/^[0-9a-f]{40}$/', $_COOKIE[$this->_config['cookie_name']])
// ↓に変更
preg_match('/^[0-9a-z]{26}$/', $_COOKIE[$this->_config['cookie_name']])

引用元

記事内のコードは全てCodeIgniter3.1.0及び3.2.0から引用しています。
CodeIgniter Web Framework

[紹介元] PHPタグが付けられた新着投稿 – Qiita PHP の http クライアントの使い方 (Post)

コメント

記事に戻る

コメントを残す