セッション処理は、すべての Web アプリケーションが直面する必要がある問題です。 PHP でのセッション有効期間の処理は、他のソリューションとは大きく異なります。これは、PHP の動作メカニズムに関連しています。
従来のクライアント/サーバー アプリケーションでは、セッションの失敗はネットワーク プロトコル自体によって処理できます。クライアントが積極的に接続を閉じた場合でも、ネットワーク異常により接続が中断された場合でも、サーバーに通知され、接続中断イベントをトリガーできます。このイベントに応答して指定された操作を実行するようにプログラムするだけです。しかし、Web アプリケーションの場合は状況がまったく異なります。 HTTP プロトコル自体はステートレスです。つまり、クライアント/サーバーが要求/応答プロセスを完了するたびに、接続は切断されます。切断後、サーバーはクライアントが引き続き「オンライン」であり、次のリクエストを送信し続けるかどうかを知りません。言い換えれば、クライアント側のユーザーがブラウザ ウィンドウを閉じたか、ユーザーが現在の Web ページを読んで次の秒で閲覧を続ける準備をしているか、またはユーザーが Windows のクラッシュ/停電/その他の影響を受けているかどうかに関係なく、ハードドライブの障害/ネットワークケーブルの接続が外れている/地球の爆発 次のリクエストを送信することは完全に不可能であり、サーバーはそれについて何も知りません。 (HTTP 1.1 では、ブラウザはキープアライブ パラメータを使用して、リクエストに応答した後に積極的に切断しないようにサーバーに通知し、物理的に長時間の接続を実現できます。ただし、これはネットワーク送信のパフォーマンスを向上させるために取られる措置にすぎません) 、HTTP は依然として論理的にステートレスです。) したがって、現在のセッションが有効かどうかは、何らかのシミュレーション方法を通じてのみ判断できます。一定時間が経過してもセッションがサーバーにリクエストを行わない場合、サーバーはユーザーが「オフライン」であると判断し、現在のセッションは無効になり、接続中断イベントがトリガーされます。これを行うには、サーバーはバックグラウンド スレッドを実行して、すべてのセッション情報を定期的にスキャンし、セッションがタイムアウトしたかどうかを判断する必要があります。
PHPのセッション処理の原理も例外ではありませんが、具体的な実装方法は異なります。これは、PHP の動作メカニズムにより、セッション情報を定期的にスキャンしてセッション情報が無効かどうかを判断するバックグラウンド スレッドが存在しないためです。この解決策は、有効なリクエストが発生したときに、PHP が一定の確率に基づいて GC (ガベージ コレクター) を呼び出すかどうかを決定することです。 GC の仕事は、すべてのセッション情報をスキャンし、現在の時刻からセッションの最終変更時刻 (変更日) を減算し、それを構成パラメーター (構成オプション) session.gc_maxlifetime の値と比較することです。時間が gc_maxlifetime を超えました。セッションは削除されます。これは簡単に理解できます。リクエストごとに GC コードが呼び出されると、PHP の効率が耐えられないほど低下するからです。この確率は、設定パラメータ session.gc_probability/session.gc_divisor の値によって異なります (php.ini または ini_set() 関数を通じて変更できます)。デフォルトでは、session.gc_probability = 1、session.gc_divisor=100 です。これは、GC が開始される確率が 1% であることを意味します。 これら 3 つのパラメータ session.gc_maxlifetime/session.gc_probability/session.gc_divisor は、php.ini または ini_set() 関数を通じて変更できます。ただし、ini_set() 関数を使用する場合は、各ページの先頭で ini_set() を呼び出す必要があることに注意してください。
これは別の問題を引き起こします。gc_maxlifetime はセッションの存続期間の最短時間を保証するだけであり、この期間を過ぎるとセッション情報はすぐに削除されます。 GC は確率に基づいて開始され、長期間開始されない可能性があるため、gc_maxlifetime を超えた後も多数のセッションが有効になります。もちろん、これが起こる可能性は非常に低いですが、アプリケーションが非常に正確なセッションの有効期限を必要とする場合、これは深刻な問題を引き起こす可能性があります。この問題を解決する 1 つの方法は、session.gc_probability/session.gc_divisor の確率を 100% まで高めることです。ただし、この問題は明らかにパフォーマンスに重大な影響を及ぼします。もう 1 つの方法は、PHP の GC を放棄し、コード内で現在のセッションの有効期間を判断し、gc_maxlifetime を超えた場合に現在のセッションをクリアすることです。
PHP のデフォルトのセッション有効期間は 1440 秒 (24 分) です。つまり、クライアントが 24 分を超えて更新されない場合、現在のセッションは期限切れになります。このデフォルト値を変更するには、構成パラメータ session.gc_maxlifetime を変更するのが正しい解決策です。
私はかつてこの問題の解決策をインターネットで検索しましたが、見つかった結果はあらゆる種類の奇妙なものでした。 「session_life_time」を設定する必要があると言う人もいますが、私の知る限り、PHPにはそのようなパラメータはありません。 session_set_cookie_params を呼び出す必要がある、または session.cookie_lifetime を設定する必要があるという人もいます。これは、クライアント側で Cookie の有効期間を設定するためにのみ使用されます。つまり、この値の変更は、クライアントでの Cookie の有効期間が終了する場合にのみ有効です。理由は非常に単純で、サーバー側のセッションが期限切れになっている場合、どれだけ長くても意味がありません。クライアント側 Cookie の有効期間は次のとおりです。このパラメータは、現在のページのコンテンツをキャッシュする期間をブラウザとプロキシに通知するために使用され、セッションの存続期間には直接関係しません。
このソリューションは完璧だと思われます。ただし、実際に session.gc_maxlifetime の値を変更しようとすると、このパラメータは基本的には効果がなく、セッションの有効期間はデフォルト値の 24 分のままであることがわかります。開発環境では正常に動作しても、サーバーでは正常に動作しない場合もあります。
この問題を完全に解決するには、PHP の動作詳細をさらに分析する必要があります。
デフォルトでは、PHP のセッション情報はテキスト ファイルの形式でシステムの一時ファイル ディレクトリに保存されます。このパスは、構成パラメータ session.save_path によって指定されます。 Linux では、このパスは通常 tmp であり、Windows では通常 C:WindowsTemp です。サーバー上に複数の PHP アプリケーションがある場合、それらは同じディレクトリにセッション ファイルを保存します (同じ session.save_path パラメータを使用するため)。同様に、これらの PHP アプリケーションも一定の確率で GC を開始し、すべてのセッション ファイルをスキャンします。
問題は、GC が動作しているときに、異なるサイト上のセッションが区別されないことです。たとえば、サイト A の gc_maxlifetime は 2 時間に設定され、サイト B の gc_maxlifetime はデフォルトの 24 分に設定されます。サイト B の GC が開始されると、パブリック一時ファイル ディレクトリがスキャンされ、サイト A からのものかサイト B からのものかに関係なく、24 分より古いすべてのセッション ファイルが削除されます。このように、サイト A の gc_maxlifetime 設定は役に立ちません。
問題を見つけたら、解決するのは簡単です。ページの先頭で session_save_path() 関数を呼び出します。これにより、session.save_path パラメータが変更され、セッションが保存されるディレクトリが tmpmyapp などの専用ディレクトリに指定されます。このようにして、gc_maxlifetime パラメータは正常に機能します。
公開 session.save_path を使用すると、同じサーバー上の他の PHP プログラムもサイトのセッション ファイルを読み取ることができ、ハッカー攻撃に使用される可能性があるため、セキュリティの問題が発生する可能性があります。もう 1 つの問題は効率です。混雑したサイトでは何千ものセッション ファイルが存在する可能性があり、単一のファイルの読み取りと書き込みを行う場合でも、すべてのファイルの GC をトラバースする場合でも、多くの異なる Web サイトのセッション ファイルが同じディレクトリに配置されます。間違いなくパフォーマンスの低下につながります。したがって、PHP アプリケーションが他の PHP アプリケーションと同じサーバー上で実行される場合は、独自の session.save_path を使用することを強くお勧めします。
厳密に言えば、これは PHP のバグです。 PHP が GC を実行する場合、異なるサイトからのセッション ファイルを区別し、異なる gc_maxlifetime 値を適用する必要があります。現在、最新の PHP 5.2.X でもこの問題は依然として発生しています。
前述したように、混雑したサイトでは数千のセッション ファイルが存在する可能性があり、異なるサイトの session.save_path ディレクトリが区別されている場合でも、単一サイト内のセッション ファイルの数によって効率の問題が発生する可能性があります。この問題を解決するには、いくつかの実現可能な方法があります:
PHP が Linux システムで実行されている場合は、デフォルトの ext2/ext3 ファイル システムの代わりに ReiserFS ファイル システムを使用します。 ReiserFS は、ext2/ext3 と比較して、多数の小さなファイルに対するアクセス パフォーマンスが大幅に向上しています。
session.save_path をメモリ パスにポイントします。これは、セッション ファイルの読み取りと書き込みはメモリ内でのみ実行され、ディスク操作は実行されないことを意味します。
session.save_path は、ディレクトリのレベルを指定する追加の N パラメータを受け入れます。たとえば、「5;/tmp」を指定すると、/tmp/4/b/1/e/3/sess_4b1e384ad74619bd212e236e52a5a174If のようなセッション ファイルが作成されます。具体的な手順については、http://cn.php.net/manual/en/session.configuration.php#ini.session.save-path を参照してください
究極の解決策は、PHP のセッション処理メカニズムを放棄し、すべてのセッション処理操作を引き継ぐように自分でコーディングし、session_set_save_handler() 関数を通じて実装することです。セッション処理を自分で引き継ぐことで、すべてのセッションを特別なデータベース (多くの場合、メモリ テーブルを使用) に保存できるため、セッション ファイルによって引き起こされる問題が完全に解決され、セッションの共有とコピーが簡単に実現できます。これは、大規模な PHP アプリケーションで一般的に使用される方法でもあります。 session_set_save_handler() 関数の使用方法については、インターネットや関連書籍に詳細な説明があるため、ここでは詳しく説明しません。この方法でも、GC が開始される確率は依然として session.gc_probability/session.gc_divisor に依存することに注意してください。
。