PHPでセッションタイムアウトを変更する方法


154

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

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

それでは、phpコードでのみそれを行うことは可能ですか?



1
関連して、これはphp.iniであるが、私は@matinoが言ったようにヨーヨーをini_set使用することができると思うstackoverflow.com/questions/520237/...
J-ROU

回答:


324

セッションタイムアウトは、厳密な保証が必要な場合にコードに実装する必要がある概念です。それはだ唯一の方法あなたは何のセッションは、これまで非アクティブのX分後に存続しないことを絶対的に特定することができます。

この要件を緩和した場合、ほとんどは許容可能であり、あなたが置くとうまくある下限期間に厳密に制限するのではなく、あなたが簡単にそれを行うと、カスタム・ロジックを記述することなくすることができます。

リラックスした環境での利便性:方法と理由

セッションがCookieを使用して実装されている場合(おそらくそうである場合)、クライアントが悪意のあるものでない場合は、特定のパラメーターを調整することにより、セッション期間の上限を設定できます。PHPのデフォルトセッション処理をCookieで使用している場合は、と一緒に設定session.gc_maxlifetimeするとsession_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、必要に応じてそれらを再生成するように注意する必要があることに注意してください。


質問:これを呼び出す場合、毎分jsutと言いましょう。制限を増やしますか?例:10:00に呼び出したので、制限は11:00になります。1分の10:01の後、制限は11:01になりますか?
oneofakind 2014年

@oneofakind:あなたが正確に何を呼ぶなら?
Jon

1
これらは:ini_set( 'session.gc_maxlifetime'、3600); session_set_cookie_params(3600);
oneofakind 2014年

@oneofakind:はい、ただし、同じように呼び出した場合のみsession_start()(そうでない場合はまったく効果がありません)、常にこれら2つ前に呼び出す場合のみsession_start(そうでない場合gc_maxlifetime、現在開いているすべてのセッションに影響する可能性がありますsession_set_cookie_paramsが、現在のリクエスト)。
Jon

@Jon session_start()をもう一度呼び出すと、$ _ SESSIONのすべてがリセットされますか?「すべてのセッションに影響を与える可能性がありますか」とはどういう意味ですか?返信いただきありがとうございます。
oneofakind 2014年

33

PHPのデフォルトのセッション処理を使用する場合、すべてのプラットフォームでセッション期間を確実に変更する唯一の方法は、php.iniを変更することです。これは、一部のプラットフォームでは、ガベージコレクションがphp.iniから直接読み取る特定の時間ごとに実行されるスクリプト(cronスクリプト)を介して実装されるため、実行時に(たとえばを介して)変更しようとすると、信頼性が低く、最も可能性が高いためです。動作しません。ini_set()

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

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

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

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

  2. PHPの内部セッション処理を完全に忘れ、独自のセッション管理を実装します。この方法には2つの主な欠点があります。独自のグローバルセッション変数が必要になるため、$_SESSIONスーパーグローバルの利点が失われ、さらに多くのコードが必要になるため、バグやセキュリティ上の欠陥が発生する可能性が高くなります。最も重要なのは、セッションIDは、セッションIDの予測可能性(セッションハイジャックの可能性につながる)を回避するために、暗号で保護された乱数または疑似乱数から生成する必要があることです。主な利点は、すべてのプラットフォームで一貫して機能し、コードを完全に制御できることです。これは、たとえばphpBBフォーラムソフトウェア(少なくともバージョン1。最近のバージョンについてはわかりません)が採用したアプローチです。

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

<?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)はより複雑です。基本的に、すべてのセッション関数を自分で再実装する必要があります。ここでは詳しく説明しません。


誰かがそれを確認できますか?
Oli、2013

@オリ:ざっと読んだ後、それは正しいようです。また、stackoverflow.com / questions / 520237 /…を参照することもできますがphp.ini、実際のオプションへのアクセス権がない場合は厳しく制限されます。
Jon

また、Ubuntu 14では/usr/lib/php5/maxlifetime、24分未満の値は計算されないようです。したがって、セッションタイムアウトをそれよりも低く設定することはできません。
Henry

「PHPの内部セッション処理を完全に忘れて、独自のセッション管理を実装してください。」それは危険なアドバイスです。セキュリティの悪夢は必然的に生じます。
クツァイ

@Kzqaiまた、「より多くのコードが必要であるため、バグやセキュリティの欠陥が発生する可能性がさらにある」とも述べています。それはアドバイスではありません、私は代替案を列挙していますが、それを改善するための提案がある場合は、実行してください。
ペドロギメノ

3

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

私はこの問題を回避するためにcronジョブを毎時から毎日に移動する以下のリンクに投稿されたソリューションを使用しました。

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

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


3

入れて$_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()悪意のあるクライアントやロボットの場合は、リダイレクトに依存するのではなく、セッションを直接破棄する方が、より適切なオプションになる可能性があります。


2

のためのちょうど通知 共有ホスティングサーバーのまたはドメインに追加=

設定を機能させるには、php_value session.save_path "folderA / sessionsA"を使用して、追加したドメインに別の保存セッションディレクトリを設定する必要があります。

そのため、public_html内ではなく、外部からアクセスして公開されないように、ルートサーバーにフォルダを作成します。私のcpanel / serverの場合、フォルダのアクセス許可0700は正常に機能しました。試してください...

  • PHPコード =

     #Session timeout, 2628000 sec = 1 month, 604800 = 1 week, 57600 = 16 hours, 86400 = 1 day
     ini_set('session.save_path', '/home/server/.folderA_sessionsA');
     ini_set('session.gc_maxlifetime', 57600); 
     ini_set('session.cookie_lifetime', 57600);
     ini_set('session.cache_expire', 57600);
     ini_set('session.name', 'MyDomainA');

session_start();の前

または

  • .htaccess =

     php_value session.save_path /home/server/.folderA_sessionsA
     php_value session.gc_maxlifetime 57600
     php_value session.cookie_lifetime 57600
     php_value session.cache_expire 57600
     php_value session.name MyDomainA

多くの調査とテストを行った後、これは共有cpanel / php7サーバーで問題なく動作しました。おかげで:NoiS


1

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

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


こんにちは、こんにちは。私はあなたに連絡する方法を見つけるためにこの場所をあちこち見てきました。締め切られた最後の投稿(日曜日)でいくつかの提案があったことを確認しました。別のプロジェクトで忙しくなり、今はなくなりました。私は本当にあなたの提案を試してみたいと思います。これはとにかくあなたが書いたものを見つけるためにありますか?
老犬

私が見る限り、それは閉じられただけでなく削除されました。これらの人々には名誉がない。はい、あなたの問題は私が話していた一般的な解決策を持っています。メールでお送りします。つまり、これらのprev / next値を取得するために2つの追加クエリを実行することでした。SELECT id FROM gallery WHERE SortOrder > $currentsortorder LIMIT 1
常識

0

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


4
-1:session.gc_maxlifetimeセッションの存続時間を制御する設定ではありません。に設定session.gc_divisorする1と、そのように動作するように荒らされる可能性がありますが、それは恐ろしいことです。
Jon

1
@ジョン私はSOで非常に多くの答えを見て、反対を示唆していますが、それはなぜですか?stackoverflow.com/questions/514155/...の stackoverflow.com/questions/9904105/...
giannis christofakis

2
@yannishristofakis:gc_maxlifetimeセッションデータがガベージコレクションの対象となるまでの間隔を設定します。その時間が経過した後にGCが発生した場合、セッションデータは破棄されます(デフォルトの設定では、これはセッションの有効期限と同じです)。ただし、GCは各セッションの開始時に確率的にトリガーされるため、セッションが実際に期限切れになる保証はありません。確率対時間の曲線をプロットできますが、ブリックウォールのようには見えません。それは氷山の一角にすぎません。stackoverflow.com/questions/520237/…を
Jon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.