最新のWeb開発では、PHPのセッション管理は重要なコンポーネントであり、ユーザーのステータスを維持し、異なるページリクエスト間でユーザーデータが保存および渡されるようにします。従来のセッションストレージ方法はファイルシステムに基づいていますが、いくつかのハイロードおよび高電流アプリケーションシナリオでは、ファイルストレージによりパフォーマンスボトルネックがもたらされる場合があります。したがって、データベースを使用してセッション情報を保存することは、徐々に一般的な慣行になりました。
PHPでは、 SessionHandlerクラスは、開発者がセッションストレージメソッドをカスタマイズできるメカニズムを提供します。 SessionHandlerインターフェイスを実装することにより、セッションをデータベースに保存して、セッション管理をより効率的で安定させることができます。
この記事では、 SessionHandler :: Databaseで開くセッションストレージを実装する方法について説明し、効率的で安定したデータベースセッションシステムを実装する方法について説明します。
PHPの組み込みセッション処理方法(デフォルトでは、ファイルストレージ)は、カスタムセッションハンドラーに置き換えることができます。 PHPがセッションを要求すると、 SessionHandlerは次の主な方法を実行します。
open($ savepath、$ sessionname) :セッションストレージを開きます。
close() :セッションストレージを閉じます。
読み取り($ sessionid) :指定されたセッションIDのセッションデータを読み取ります。
write($ sessionid、$ data) :セッションデータを書き込みます。
Destroy($ SessionID) :セッションを破壊します。
GC($ maxlifetime) :ガベージコレクションを実行します。
これらのメソッドを書き換えることにより、開発者はファイルシステムのみに依存するのではなく、セッションデータをデータベースに保存できます。
以下は、PHPを介してデータベースにセッションデータを保存するための基本的な手順です。
まず、セッション情報を保存するには、データベースにテーブルを作成する必要があります。テーブル構造の基本的な例は次のとおりです。
<span><span><span class="hljs-keyword">CREATE</span></span><span> </span><span><span class="hljs-keyword">TABLE</span></span><span> `sessions` (
`session_id` </span><span><span class="hljs-type">varchar</span></span><span>(</span><span><span class="hljs-number">255</span></span><span>) </span><span><span class="hljs-keyword">NOT</span></span><span> </span><span><span class="hljs-keyword">NULL</span></span><span>,
`session_data` text </span><span><span class="hljs-keyword">NOT</span></span><span> </span><span><span class="hljs-keyword">NULL</span></span><span>,
`last_access` </span><span><span class="hljs-type">int</span></span><span>(</span><span><span class="hljs-number">11</span></span><span>) </span><span><span class="hljs-keyword">NOT</span></span><span> </span><span><span class="hljs-keyword">NULL</span></span><span>,
</span><span><span class="hljs-keyword">PRIMARY</span></span><span> KEY (`session_id`)
);
</span></span>
この表では、セッションの一意の識別子としてSession_Idを使用し、 Session_Data Store Session Datasを使用し、 Last_Accessを使用してセッションの最後のアクセス時間を記録します。
次に、セッションハンドラーを継承するクラスが開発され、セッションストレージの機能を実装します。
<span><span><span class="hljs-class"><span class="hljs-keyword">class</span></span></span><span> </span><span><span class="hljs-title">DbSessionHandler</span></span><span> </span><span><span class="hljs-keyword">extends</span></span><span> </span><span><span class="hljs-title">SessionHandler</span></span><span>
{
</span><span><span class="hljs-keyword">protected</span></span><span> </span><span><span class="hljs-variable">$db</span></span><span>;
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">__construct</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$db</span></span></span><span>)
{
</span><span><span class="hljs-variable language_">$this</span></span><span>->db = </span><span><span class="hljs-variable">$db</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">open</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$savePath</span></span></span><span>, </span><span><span class="hljs-variable">$sessionName</span></span><span>)
{
</span><span><span class="hljs-comment">// ここでデータベース接続の初期化操作を実行することを選択できます</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">close</span></span><span>(</span><span><span class="hljs-params"></span></span><span>)
{
</span><span><span class="hljs-comment">// ここでは、データベース接続を閉じることができます</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">read</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$sessionId</span></span></span><span>)
{
</span><span><span class="hljs-comment">// データベースからセッションデータを読み取ります</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable language_">$this</span></span><span>->db-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"SELECT session_data FROM sessions WHERE session_id = :session_id"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-string">'session_id'</span></span><span> => </span><span><span class="hljs-variable">$sessionId</span></span><span>]);
</span><span><span class="hljs-variable">$row</span></span><span> = </span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">fetch</span></span><span>(PDO::</span><span><span class="hljs-variable constant_">FETCH_ASSOC</span></span><span>);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-variable">$row</span></span><span> ? </span><span><span class="hljs-variable">$row</span></span><span>[</span><span><span class="hljs-string">'session_data'</span></span><span>] : </span><span><span class="hljs-string">''</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">write</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$sessionId</span></span></span><span>, </span><span><span class="hljs-variable">$data</span></span><span>)
{
</span><span><span class="hljs-comment">// セッションデータを更新します</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable language_">$this</span></span><span>->db-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"REPLACE INTO sessions (session_id, session_data, last_access) VALUES (:session_id, :session_data, :last_access)"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([
</span><span><span class="hljs-string">'session_id'</span></span><span> => </span><span><span class="hljs-variable">$sessionId</span></span><span>,
</span><span><span class="hljs-string">'session_data'</span></span><span> => </span><span><span class="hljs-variable">$data</span></span><span>,
</span><span><span class="hljs-string">'last_access'</span></span><span> => </span><span><span class="hljs-title function_ invoke__">time</span></span><span>()
]);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">destroy</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$sessionId</span></span></span><span>)
{
</span><span><span class="hljs-comment">// セッションデータを削除します</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable language_">$this</span></span><span>->db-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"DELETE FROM sessions WHERE session_id = :session_id"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-string">'session_id'</span></span><span> => </span><span><span class="hljs-variable">$sessionId</span></span><span>]);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
</span><span><span class="hljs-keyword">public</span></span><span> </span><span><span class="hljs-function"><span class="hljs-keyword">function</span></span></span><span> </span><span><span class="hljs-title">gc</span></span><span>(</span><span><span class="hljs-params"><span class="hljs-variable">$maxlifetime</span></span></span><span>)
{
</span><span><span class="hljs-comment">// 期限切れのセッションをクリーンアップします</span></span><span>
</span><span><span class="hljs-variable">$stmt</span></span><span> = </span><span><span class="hljs-variable language_">$this</span></span><span>->db-></span><span><span class="hljs-title function_ invoke__">prepare</span></span><span>(</span><span><span class="hljs-string">"DELETE FROM sessions WHERE last_access < :expire_time"</span></span><span>);
</span><span><span class="hljs-variable">$stmt</span></span><span>-></span><span><span class="hljs-title function_ invoke__">execute</span></span><span>([</span><span><span class="hljs-string">'expire_time'</span></span><span> => </span><span><span class="hljs-title function_ invoke__">time</span></span><span>() - </span><span><span class="hljs-variable">$maxlifetime</span></span><span>]);
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-literal">true</span></span><span>;
}
}
</span></span>
この実装では、PDOを介してデータベースと対話し、特定の操作は次のとおりです。
オープン方法:データベース接続を初期化します。通常、データベース接続はこの方法で設定されています。
読み取り方法:セッションIDを介してデータベースから対応するセッションデータをクエリします。
書き込み方法:セッションデータをデータベースに書き込みます。セッションIDが存在しない場合は、新しいレコードを挿入し、既存のレコードを更新します。
メソッドを破壊する:指定されたセッションIDでデータを削除します。
GCメソッド:ガベージコレクション操作を実行し、期限切れのセッションレコードを削除します。
SessionHandlerの実装を完了したら、PHPでカスタムセッションストレージプロセッサを登録する必要があります。 session_set_save_handler関数を介してカスタムセッション処理方法を設定します。
<span><span><span class="hljs-comment">// データベース接続を作成します</span></span><span>
</span><span><span class="hljs-variable">$db</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title function_ invoke__">PDO</span></span><span>(</span><span><span class="hljs-string">'mysql:host=localhost;dbname=test'</span></span><span>, </span><span><span class="hljs-string">'username'</span></span><span>, </span><span><span class="hljs-string">'password'</span></span><span>);
</span><span><span class="hljs-comment">// カスタムセッションプロセッサをインスタンス化します</span></span><span>
</span><span><span class="hljs-variable">$sessionHandler</span></span><span> = </span><span><span class="hljs-keyword">new</span></span><span> </span><span><span class="hljs-title class_">DbSessionHandler</span></span><span>(</span><span><span class="hljs-variable">$db</span></span><span>);
</span><span><span class="hljs-comment">// カスタムセッションプロセッサを登録します</span></span><span>
</span><span><span class="hljs-title function_ invoke__">session_set_save_handler</span></span><span>(
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'open'</span></span><span>],
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'close'</span></span><span>],
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'read'</span></span><span>],
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'write'</span></span><span>],
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'destroy'</span></span><span>],
[</span><span><span class="hljs-variable">$sessionHandler</span></span><span>, </span><span><span class="hljs-string">'gc'</span></span><span>]
);
</span><span><span class="hljs-comment">// セッションを開始します</span></span><span>
</span><span><span class="hljs-title function_ invoke__">session_start</span></span><span>();
</span></span>
ここでは、 session_set_save_handlerは、PHPのセッション処理方法をカスタムdbsessionhandlerクラスに置き換え、セッションデータがデータベースに保存されるようにします。
効率的で安定したデータベースセッションストレージを実現するには、次の側面に特別な注意を払う必要があります。
セッションテーブルでは、セッション_IDフィールドは通常、プライマリキーとして使用され、一意性と効率的なクエリパフォーマンスを確保します。さらに、 LAST_ACCESSフィールドをインデックス作成して、ガベージコレクション中に期限切れのセッションを効率的に検索できるようにすることができます。
セッションの有効期間戦略は、効率的なデータベースセッションを確保するための鍵です。セッションの最大寿命( Maxlifetime )を合理的に設定し、 GCメソッドで期限切れのセッションを削除することにより、データベースのジャンクデータが多すぎることを防ぐことができます。
セッションデータが共有されるため、複数のリクエストが同時に同じセッションにアクセスして変更される場合があります。データの競合や矛盾を回避するために、セッションロック戦略を採用して、セッションデータの変更中に他の要求が同時に変更されないようにすることができます。
高い並行性アプリケーションの場合、毎回直接データベース接続を作成すると、パフォーマンスに影響を与える可能性があります。データベース接続プーリングテクノロジーの使用、またはデータベース接続を持続することでパフォーマンスを改善することを検討してください。
データベースへの圧力を減らすために、Redis、Memcachedなどのキャッシュテクノロジーをメモリにキャッシュすることにより、キャッシュテクノロジーを組み合わせることを検討することができます。これにより、データベースの負担が軽減され、セッションストレージの応答速度と安定性が向上します。
セッションハンドラーインターフェイスを実装し、データベースにセッションデータを保存することにより、セッション管理の柔軟性と安定性を効果的に改善できます。セッションストレージの実装方法を合理的に設計し、適切な最適化測定を行うことにより、効率的で安定したスケーラブルなデータベースセッションストレージシステムを実現できます。