セッションとクッキーを使用すると、複数のユーザーリクエストにわたってデータを永続化できます。プレーンなPHPでは、それぞれグローバル変数`$_SESSION`と`$_COOKIE`を通してアクセスできます。Yiiはセッションとクッキーをオブジェクトとしてカプセル化し、オブジェクト指向の方法でアクセスできるようにし、さらに便利な機能強化を提供します。
リクエストやレスポンスと同様に、デフォルトではyii\web\Sessionのインスタンスであるアプリケーションコンポーネントの`session`を通してセッションにアクセスできます。
セッションを開始および終了するには、次の操作を行います。
$session = Yii::$app->session;
// check if a session is already open
if ($session->isActive) ...
// open a session
$session->open();
// close a session
$session->close();
// destroys all data registered to a session.
$session->destroy();
open()とclose()を複数回呼び出してもエラーは発生しません。内部的には、メソッドは最初にセッションが既に開いているかどうかを確認します。
セッションに保存されているデータにアクセスするには、次の操作を行います。
$session = Yii::$app->session;
// get a session variable. The following usages are equivalent:
$language = $session->get('language');
$language = $session['language'];
$language = isset($_SESSION['language']) ? $_SESSION['language'] : null;
// set a session variable. The following usages are equivalent:
$session->set('language', 'en-US');
$session['language'] = 'en-US';
$_SESSION['language'] = 'en-US';
// remove a session variable. The following usages are equivalent:
$session->remove('language');
unset($session['language']);
unset($_SESSION['language']);
// check if a session variable exists. The following usages are equivalent:
if ($session->has('language')) ...
if (isset($session['language'])) ...
if (isset($_SESSION['language'])) ...
// traverse all session variables. The following usages are equivalent:
foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...
情報: `session`コンポーネントを介してセッションデータにアクセスすると、まだ行われていない場合は自動的にセッションが開かれます。これは`$_SESSION`を介してセッションデータにアクセスする場合とは異なり、`session_start()`を明示的に呼び出す必要があります。
配列であるセッションデータを使用する場合、`session`コンポーネントには、配列要素を直接変更できないという制限があります。例えば、
$session = Yii::$app->session;
// the following code will NOT work
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// the following code works:
$session['captcha'] = [
'number' => 5,
'lifetime' => 3600,
];
// the following code also works:
echo $session['captcha']['lifetime'];
この問題を解決するには、次の回避策のいずれかを使用できます。
$session = Yii::$app->session;
// directly use $_SESSION (make sure Yii::$app->session->open() has been called)
$_SESSION['captcha']['number'] = 5;
$_SESSION['captcha']['lifetime'] = 3600;
// get the whole array first, modify it and then save it back
$captcha = $session['captcha'];
$captcha['number'] = 5;
$captcha['lifetime'] = 3600;
$session['captcha'] = $captcha;
// use ArrayObject instead of array
$session['captcha'] = new \ArrayObject;
...
$session['captcha']['number'] = 5;
$session['captcha']['lifetime'] = 3600;
// store array data by keys with a common prefix
$session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
パフォーマンスとコードの可読性を向上させるために、最後の回避策をお勧めします。つまり、配列を単一のセッション変数として保存する代わりに、他の配列要素と共通のキープレフィックスを共有するセッション変数として各配列要素を保存します。
デフォルトの yii\web\Session クラスは、セッションデータをサーバー上のファイルとして保存します。Yii は、さまざまなセッションストレージを実装する以下のセッションクラスも提供しています。
これらのセッションクラスはすべて、同じAPIメソッドセットをサポートしています。その結果、セッションを使用するアプリケーションコードを変更する必要なく、別のセッションストレージクラスに切り替えることができます。
注記:カスタムセッションストレージを使用しながら
$_SESSION
経由でセッションデータにアクセスする場合、yii\web\Session::open()によってセッションが既に開始されていることを確認する必要があります。これは、カスタムセッションストレージハンドラーがこのメソッド内で登録されるためです。
注記:カスタムセッションストレージを使用する場合は、セッションガベージコレクターを明示的に構成する必要がある場合があります。PHPの一部のインストール(例:Debian)では、ガベージコレクターの確率が0に設定されており、セッションファイルはcronジョブでオフラインでクリーンアップされます。このプロセスはカスタムストレージには適用されないため、ゼロ以外の値を使用するようにyii\web\Session::$GCProbabilityを構成する必要があります。
これらのコンポーネントクラスの構成方法と使用方法については、APIドキュメントを参照してください。以下は、アプリケーション構成でyii\web\DbSessionを構成して、データベーステーブルをセッションストレージとして使用する例を示しています。
return [
'components' => [
'session' => [
'class' => 'yii\web\DbSession',
// 'db' => 'mydb', // the application component ID of the DB connection. Defaults to 'db'.
// 'sessionTable' => 'my_session', // session table name. Defaults to 'session'.
],
],
];
セッションデータを保存するための次のデータベーステーブルを作成する必要があります。
CREATE TABLE session
(
id CHAR(40) NOT NULL PRIMARY KEY,
expire INTEGER,
data BLOB
)
ここで「BLOB」は、使用するDBMSのBLOB型を表します。いくつかの一般的なDBMSで使用できるBLOB型を以下に示します。
注記:
session.hash_function
のphp.ini設定に従って、id
カラムの長さを調整する必要がある場合があります。たとえば、session.hash_function=sha256
の場合、40ではなく64の長さを使用する必要があります。
または、次のマイグレーションで実現できます。
<?php
use yii\db\Migration;
class m170529_050554_create_table_session extends Migration
{
public function up()
{
$this->createTable('{{%session}}', [
'id' => $this->char(64)->notNull(),
'expire' => $this->integer(),
'data' => $this->binary()
]);
$this->addPrimaryKey('pk-id', '{{%session}}', 'id');
}
public function down()
{
$this->dropTable('{{%session}}');
}
}
フラッシュデータは、あるリクエストで設定されると、次のリクエストでのみ使用可能になり、その後自動的に削除される特殊な種類のセッションデータです。フラッシュデータは、ユーザーがフォームを正常に送信した後に表示される確認メッセージなど、エンドユーザーに一度だけ表示する必要があるメッセージを実装するために最も一般的に使用されます。
session
アプリケーションコンポーネントを使用して、フラッシュデータを設定およびアクセスできます。例えば、
$session = Yii::$app->session;
// Request #1
// set a flash message named as "postDeleted"
$session->setFlash('postDeleted', 'You have successfully deleted your post.');
// Request #2
// display the flash message named "postDeleted"
echo $session->getFlash('postDeleted');
// Request #3
// $result will be false since the flash message was automatically deleted
$result = $session->hasFlash('postDeleted');
通常のセッションデータと同様に、任意のデータをフラッシュデータとして保存できます。
yii\web\Session::setFlash()を呼び出すと、同じ名前の既存のフラッシュデータは上書きされます。同じ名前の既存のメッセージに新しいフラッシュデータを追加するには、代わりにyii\web\Session::addFlash()を呼び出します。例えば
$session = Yii::$app->session;
// Request #1
// add a few flash messages under the name of "alerts"
$session->addFlash('alerts', 'You have successfully deleted your post.');
$session->addFlash('alerts', 'You have successfully added a new friend.');
$session->addFlash('alerts', 'You are promoted.');
// Request #2
// $alerts is an array of the flash messages under the name of "alerts"
$alerts = $session->getFlash('alerts');
注記:同じ名前のフラッシュデータに対してyii\web\Session::setFlash()とyii\web\Session::addFlash()を一緒に使用しないでください。後者のメソッドは、同じ名前の新しいフラッシュデータを追加できるように、フラッシュデータを自動的に配列に変換するためです。その結果、yii\web\Session::getFlash()を呼び出すと、これらの2つのメソッドの呼び出し順序によっては、配列が取得されたり、文字列が取得されたりする可能性があります。
ヒント:フラッシュメッセージを表示するには、次のようにyii\bootstrap\Alertウィジェットを使用できます。
echo Alert::widget([ 'options' => ['class' => 'alert-info'], 'body' => Yii::$app->session->getFlash('postDeleted'), ]);
Yiiは、各クッキーをyii\web\Cookieのオブジェクトとして表します。yii\web\Requestとyii\web\Responseの両方が、cookies
という名前のプロパティを介してクッキーのコレクションを保持します。前者にあるクッキーコレクションはリクエストで送信されたクッキーを表し、後者にあるクッキーコレクションはユーザーに送信されるクッキーを表します。
リクエストとレスポンスを直接扱うアプリケーションの部分はコントローラーです。したがって、クッキーはコントローラーで読み書きする必要があります。
次のコードを使用して、現在のリクエスト内のクッキーを取得できます。
// get the cookie collection (yii\web\CookieCollection) from the "request" component
$cookies = Yii::$app->request->cookies;
// get the "language" cookie value. If the cookie does not exist, return "en" as the default value.
$language = $cookies->getValue('language', 'en');
// an alternative way of getting the "language" cookie value
if (($cookie = $cookies->get('language')) !== null) {
$language = $cookie->value;
}
// you may also use $cookies like an array
if (isset($cookies['language'])) {
$language = $cookies['language']->value;
}
// check if there is a "language" cookie
if ($cookies->has('language')) ...
if (isset($cookies['language'])) ...
次のコードを使用して、エンドユーザーにクッキーを送信できます。
// get the cookie collection (yii\web\CookieCollection) from the "response" component
$cookies = Yii::$app->response->cookies;
// add a new cookie to the response to be sent
$cookies->add(new \yii\web\Cookie([
'name' => 'language',
'value' => 'zh-CN',
]));
// remove a cookie
$cookies->remove('language');
// equivalent to the following
unset($cookies['language']);
上記の例で示されているname、valueプロパティに加えて、yii\web\Cookieクラスは、domain、expireなど、利用可能なすべてのクッキー情報を完全に表す他のプロパティも定義しています。必要に応じてこれらのプロパティを構成してクッキーを準備し、レスポンスのクッキーコレクションに追加できます。
前述の2つのセクションで示されているように、request
コンポーネントとresponse
コンポーネントを介してクッキーを読み書きするときは、クライアント側でのクッキーの変更を防ぐクッキー検証の追加のセキュリティが提供されます。これは、各クッキーにハッシュ文字列を使用して署名することで実現され、アプリケーションはクライアント側でクッキーが変更されたかどうかを判断できます。変更された場合、クッキーはrequest
コンポーネントのcookieコレクションを介してアクセスできなくなります。
注記:クッキー検証は、クッキーの値が変更されるのを防ぐだけです。クッキーが検証に失敗した場合でも、
$_COOKIE
を介してアクセスできます。これは、サードパーティライブラリが独自の方法でクッキーを操作し、クッキー検証を伴わないためです。
クッキー検証はデフォルトで有効になっています。 yii\web\Request::$enableCookieValidationプロパティをfalse
に設定して無効にすることができますが、そうすることは強くお勧めしません。
注記:
$_COOKIE
とsetcookie()
を介して直接読み書きされるクッキーは、検証されません。
クッキー検証を使用する場合は、前述のハッシュ文字列の生成に使用されるyii\web\Request::$cookieValidationKeyを指定する必要があります。アプリケーション構成でrequest
コンポーネントを構成することで実行できます。
return [
'components' => [
'request' => [
'cookieValidationKey' => 'fill in a secret key here',
],
],
];
情報:cookieValidationKeyは、アプリケーションのセキュリティにとって非常に重要です。信頼できる人だけが知る必要があります。バージョン管理システムに保存しないでください。
yii\web\Cookieとyii\web\Sessionの両方が、次のセキュリティフラグをサポートしています。
セキュリティを強化するために、yii\web\Cookie::$httpOnlyのデフォルト値とyii\web\Session::$cookieParamsの 'httponly' パラメーターはtrue
に設定されています。これにより、クライアント側のスクリプトが保護されたクッキーにアクセスするリスクを軽減できます(ブラウザーがサポートしている場合)。詳細については、HttpOnly wiki記事を参照してください。
secureフラグの目的は、クッキーがクリアテキストで送信されるのを防ぐことです。ブラウザがsecureフラグをサポートしている場合、リクエストがセキュア(TLS)接続を介して送信された場合にのみ、クッキーが含まれます。詳細については、SecureFlag wiki記事を参照してください。
Yii 2.0.21以降、yii\web\Cookie::$sameSite設定がサポートされています。PHPバージョン7.3.0以降が必要です。sameSite
設定の目的は、CSRF(クロスサイトリクエストフォージェリ)攻撃を防ぐことです。ブラウザがsameSite
設定をサポートしている場合、指定されたポリシー( 'Lax'または 'Strict')に従ってのみクッキーが含まれます。詳細については、SameSite wiki記事を参照してください。セキュリティを強化するために、サポートされていないバージョンのPHPでsameSite
を使用すると、例外がスローされます。異なるPHPバージョンでこの機能を使用するには、最初にバージョンを確認します。例:
[
'sameSite' => PHP_VERSION_ID >= 70300 ? yii\web\Cookie::SAME_SITE_LAX : null,
]
注記:すべてのブラウザが
sameSite
設定をまだサポートしているわけではないため、追加のCSRF保護を含めることも強くお勧めします。
PHPマニュアルに記載されているように、php.ini
には重要なセッションセキュリティ設定があります。推奨される設定が適用されていることを確認してください。特に、PHPのインストールではデフォルトで有効になっていないsession.use_strict_mode
です。この設定は、yii\web\Session::$useStrictModeでも設定できます。
タイプミスを見つけたか、このページの改善が必要だと考えますか?
githubで編集する !
MSSQLの場合、ドキュメントで示されているマイグレーションは現在機能していません。つまり、間違った変換(char(64)など)に関連するエラーが発生します。代わりに、
@vendor/yiisoft/yii2/web/migrations
内のマイグレーションを使用する必要があります。現在の内容は次のとおりです。
<?php use yii\db\Migration; /** * Class m180611_154126_criar_tabela_sessoes */ class m180611_154126_criar_tabela_sessoes extends Migration { public function safeUp() { $dataType = $this->binary(); $tableOptions = null; switch ($this->db->driverName) { case 'mysql': // http://stackoverflow.com/questions/766809/whats-the-difference-between-utf8-general-ci-and-utf8-unicode-ci $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB'; break; case 'sqlsrv': case 'mssql': case 'dblib': $dataType = $this->text(); break; } $this->createTable('{{%SSL_SESSOES}}', [ 'id' => $this->string()->notNull(), 'expire' => $this->integer(), 'data' => $dataType, 'PRIMARY KEY ([[id]])', ], $tableOptions); } /** * {@inheritdoc} */ public function safeDown() { $this->dropTable('{{%SSL_SESSOES}}'); } }
ファイルベースからデータベースベースのセッションストレージに移行する場合は、セッションが
/tmp
に保存されているLinuxマシンでこのスクリプトを使用して、既存のセッションをデータベースに移動し、移行時に既存の訪問者がセッションを失わないようにすることができます。$tableName = 'system_sessions'; foreach (\yii\helpers\FileHelper::findFiles('/tmp', ['only' => ['sess_*'], 'recursive' => false]) as $file) { $sessionID = substr(basename($file), 5); $sessionExpire = filemtime($file) + 86400; $sessionData = file_get_contents($file); $affectedRows = \Yii::$app->db->createCommand()->upsert($tableName, [ 'id' => $sessionID, 'expire' => $sessionExpire, 'data' => $sessionData, ], [ 'expire' => $sessionExpire, 'data' => $sessionData, ])->execute(); echo $sessionID .' :: '. date('Y-m-d H:i', $sessionExpire) .' ::: '. $sessionData . PHP_EOL; }
識別クッキーによるログインの問題が発生している場合、PHPバージョン< 7.3では、sameSite属性をNoneに次のように設定できます。
**'identityCookie' => [
**'name' => 'name', 'httpOnly' => true** 'path' => '/;SameSite=None', 'secure' => true
]**
そして、セッションクッキーについては、クッキーパラメータを以下のように修正してください。
*'cookieParams' => [
'lifetime' => time()60,
'httpOnly' => true, 'secure'=>true, 'path' => '/;SameSite=None'
]**
cookieParams
にdomain
パラメータを設定しないでください。私のドメインに設定していましたが、それによってページをリロードした後にセッションが失われました。'session' => [ 'class' => 'yii\web\CacheSession', 'name' => 'naabnuts_session', 'timeout' => 30 * 24 * 3600, 'useCookies' => true, 'cookieParams' => [ 'httponly' => true, 'secure' => true, 'sameSite' => yii\web\Cookie::SAME_SITE_LAX, 'lifetime' => 30 * 24 * 3600, //'domain' => 'https://mydomain.com'=> 'will cause fault on phones' ] ]
クッキー名に、ピリオド(".")のような特殊文字を含めてはならないようです。
ピリオドを含む名前のクッキーを設定すると、Yii::$app->request->cookiesコレクションには表示されません。これは、名前のピリオドがアンダースコアに変換されるためですが、シリアライズされた名前のキーにはピリオドが残っているためです。
参照: https://www.php.net/manual/de/function.setcookie.php#120794
コメントするにはサインアップ または ログインしてください。