web-dev-qa-db-ja.com

PHPでセッションタイムアウトを変更するにはどうすればいいですか?

Phpでセッションタイムアウトを延長したい

Php.iniファイルを修正することで可能になることを私は知っています。しかし、私はそれにアクセスできません。

それでそれはPHPコードだけでそれをすることが可能ですか?

137
Oli

厳密な保証が必要な場合は、セッションタイムアウトをコードに実装する必要があります。それは唯一の方法あなたは、セッションがX分の非アクティブの後に生き残ることは絶対にないことを絶対に確信できます。

この要件を少し緩和しても問題がない場合は、期間を厳密に制限するのではなく下限を設定しても問題ありません。カスタムロジックを作成しなくても簡単に実行できます。

リラックスした環境での利便性:どのようにそしてなぜ

あなたのセッションがクッキーで実装されている場合(おそらくそれはそうです)、そしてifクライアントは悪意を持っていません。特定のパラメータを微調整することでセッション期間の上限を設定できます。もしあなたがPHPのデフォルトのセッションハンドリングをクッキーと一緒に使っているのであれば、 session.gc_maxlifetimesession_set_cookie_params と一緒に設定すればうまくいくでしょう:

// server should keep session data for AT LEAST 1 hour
ini_set('session.gc_maxlifetime', 3600);

// each client should remember their session id for EXACTLY 1 hour
session_set_cookie_params(3600);

session_start(); // ready to go!

これは、少なくとも1時間非アクティブの間セッションデータを保持するようにサーバーを設定し、同じ期間の後にセッションIDを「忘れる」ようにクライアントに指示することで機能します。 これらのステップは両方とも、期待される結果を達成するために必要です。

  • 1時間後にセッションIDを忘れるようにクライアントに指示しない場合(またはクライアントが悪意を持っていて指示を無視する場合)、同じセッションIDを使用し続け、その有効期間は不確定になります。これは、サーバーサイドで有効期限が切れたセッションはただちにガベージコレクションされるのではなく、 セッションGCが開始されるたびに に限られるためです。

    GCはコストがかかる可能性があるため、通常は確率がかなり小さいかゼロになります(大量のヒットがあるWebサイトはおそらく確率的GCを完全に見逃し、X分ごとにバックグラウンドで実行されるようにスケジュールします)。どちらの場合も(非協力クライアントを想定して)、有効なセッション存続期間の下限はsession.gc_maxlifetimeになりますが、上限は予測できません。

  • session.gc_maxlifetimeを同じ期間に設定しないと、サーバーはアイドルセッションデータをそれより早く破棄することがあります。この場合、まだセッションIDを記憶しているクライアントはそれを表示しますが、サーバーはそのセッションに関連付けられたデータを見つけられず、セッションが開始されたかのように効果的に動作します。

重要な環境での確実性

カスタムロジックを使用してセッションの非アクティブ状態に上限を設定することで、物事を完全に制御可能にすることができます。上からの下限と合わせて厳密な設定になります。

これを行うには、上限を残りのセッションデータと一緒に保存します。

session_start(); // ready to go!

$now = time();
if (isset($_SESSION['discard_after']) && $now > $_SESSION['discard_after']) {
    // this session has worn out its welcome; kill it and start a brand new one
    session_unset();
    session_destroy();
    session_start();
}

// either new or old, it should live at most for another hour
$_SESSION['discard_after'] = $now + 3600;

セッションIDの永続化

これまでのところ、各セッションIDの正確な値についてはまったく考慮されていません。必要な限りデータが存在する必要があるという要件だけが考慮されています。 (ありそうもない)セッションIDが問題になる場合は、必要に応じてsession_regenerate_idでセッションIDを再生成するように注意する必要があります。

291
Jon

PHPのデフォルトのセッション処理を使用している場合、すべてのプラットフォームで確実にセッション期間を変更する唯一の方法は、php.iniを変更することです。これは、プラットフォームによっては、ガベージコレクションが、一定時間ごとに実行されるスクリプト(php.iniから直接読み込まれるcronスクリプト)を介して実装されているためです。実行時にそれを変更しようとする試みini_set()経由では、信頼性が低く、おそらくうまくいかないでしょう。

たとえば、Debian Linuxシステムでは、PHPの内部ガベージコレクションは設定でデフォルトでsession.gc_probability=0を設定することで無効にされ、代わりにXX:09とXX:39で実行される/etc/cron.d/phpを通して行われます。 (30分ごと)このcronジョブは、設定で指定されたsession.gc_maxlifetimeより古いセッションを探し、見つかった場合はそれらを削除します。結果として、これらのシステムではini_set('session.gc_maxlifetime', ...)は無視されます。これはまた、この質問の理由も説明しています。 PHPセッションのタイムアウトが早すぎる 1つのホストでOPに問題がありましたが、別のホストに切り替えると問題が解決しました。

ですから、php.iniにアクセスできない場合、移植性の高い方法でこれを行うには、デフォルトのセッション処理を使用することはできません。明らかに、Cookieの寿命を延ばすだけで十分ですが、ホストを切り替えても確実に機能するソリューションが必要な場合は、別の方法を使用する必要があります。

利用可能な代替方法は次のとおりです。

  1. PHPに別のセッション(保存)ハンドラを設定して、 PHP:カスタムセッションハンドラ(PHPマニュアル) に指定されているように、セッションを別のディレクトリまたはデータベースに保存します。 cronジョブが到達せず、PHPの内部ガベージコレクションのみが行われます。このオプションはおそらくini_set()を使用してsession.gc_maxlifetimeを設定することができますが、私はgc()コールバックのmaxlifetimeパラメータを無視して最大値を決定することを好みます。一生で一生。

  2. PHP内部セッション処理を完全に忘れて、あなた自身のセッション管理を実装してください。この方法には2つの主な欠点があります。独自のグローバルセッション変数が必要になるため、$_SESSION superglobalの利点を失い、さらに多くのコードが必要になるため、バグやセキュリティ上の欠陥が発生する機会が増えます。最も重要なのは、セッションIDの予測可能性を回避するために暗号的に安全な乱数または擬似乱数からセッション識別子を生成する必要があり(セッションハイジャックを招く可能性がある)、PHPを移植するのはそれほど簡単ではないことです。主な利点は、すべてのプラットフォームで一貫して機能し、コードを完全に制御できることです。それが取られたアプローチです。 phpBBフォーラムソフトウェア(少なくともバージョン1;もっと最近のバージョンについてはよくわかりません)。

session_set_save_handler()のドキュメント に(1)の例があります。例は長いですが、セッションの期間を延長するために必要な変更を加えて、ここで再現します。クッキーの寿命を延ばすためにsession_set_cookie_params()を含めることにも注意してください。

<?php
class FileSessionHandler
{

    private $savePath;
    private $lifetime;

    function open($savePath, $sessionName)
    {
        $this->savePath = 'my_savepath'; // Ignore savepath and use our own to keep it safe from automatic GC
        $this->lifetime = 3600; // 1 hour minimum session duration
        if (!is_dir($this->savePath)) {
            mkdir($this->savePath, 0777);
        }

        return true;
    }

    function close()
    {
        return true;
    }

    function read($id)
    {
        return (string)@file_get_contents("$this->savePath/sess_$id");
    }

    function write($id, $data)
    {
        return file_put_contents("$this->savePath/sess_$id", $data) === false ? false : true;
    }

    function destroy($id)
    {
        $file = "$this->savePath/sess_$id";
        if (file_exists($file)) {
            unlink($file);
        }

        return true;
    }

    function gc($maxlifetime)
    {
        foreach (glob("$this->savePath/sess_*") as $file) {
            if (filemtime($file) + $this->lifetime < time() && file_exists($file)) { // Use our own lifetime
                unlink($file);
            }
        }

        return true;
    }
}

$handler = new FileSessionHandler();
session_set_save_handler(
    array($handler, 'open'),
    array($handler, 'close'),
    array($handler, 'read'),
    array($handler, 'write'),
    array($handler, 'destroy'),
    array($handler, 'gc')
    );

// the following prevents unexpected effects when using objects as save handlers
register_shutdown_function('session_write_close');

session_set_cookie_params(3600); // Set session cookie duration to 1 hour
session_start();
// proceed to set and retrieve values by key from $_SESSION

アプローチ(2)はもっと複雑です。基本的には、すべてのセッション機能を自分で実装し直す必要があります。ここでは詳しく説明しません。

28
Pedro Gimeno

Pleskを使用している人に上記のいずれかの問題が発生したためにコメントを追加してください。自分のPHPスクリプトからsession.gc_maxlifetimeを設定すると、Pleskが独自のガベージコレクションスクリプトをcronから実行するため機能しません。

この問題を回避するために、cronジョブを1時間ごとから1日ごとに移動させるという、下記のリンクに掲載されている解決策を使用しました。

mv /etc/cron.hourly/plesk-php-cleanuper /etc/cron.daily/

https://websavers.ca/plesk-php-sessions-timing-earlier-expected

3
Neil Walden

前の認証ページに$_SESSION['login_time'] = time();を入れます。そして、セッションタイムアウトを確認したい他のすべてのページの下の部分を抜粋しました。

if(time() - $_SESSION['login_time'] >= 1800){
    session_destroy(); // destroy session.
    header("Location: logout.php");
    die(); // See https://thedailywtf.com/articles/WellIntentioned-Destruction
    //redirect if the page is inactive for 30 minutes
}
else {        
   $_SESSION['login_time'] = time();
   // update 'login_time' to the last time a page containing this code was accessed.
}

編集:これは、他の投稿で調整を既に使用していた場合、またはガベージコレクションを無効にしていて、セッション期間を手動で確認したい場合にのみ機能します。スクリプトやロボットによっては無視される可能性があるため、リダイレクト後にdie()を追加することを忘れないでください。また、悪意のあるクライアントやロボットの場合は、リダイレクトに頼らずにsession_destroy()でセッションを直接破棄することをお勧めします。

3

いいえ。php.iniにアクセスできない場合は、変更が影響を与えることを保証することはできません。

セッション時間を延長する必要はないでしょうか。
現時点ではかなり賢明なタイムアウトがあり、それを拡張する理由はありません。

1

ini_set()を使用してPHPコードからphp.iniの値を上書きすることができます。

0
Nathan Q