mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-14 22:30:27 +08:00
282 lines
8.2 KiB
PHP
282 lines
8.2 KiB
PHP
<?php
|
||
/**
|
||
* @link https://www.yiiframework.com/
|
||
* @copyright Copyright (c) 2008 Yii Software LLC
|
||
* @license https://www.yiiframework.com/license/
|
||
*/
|
||
|
||
namespace yiiunit\framework\web\session;
|
||
|
||
use Yii;
|
||
use yii\db\Connection;
|
||
use yii\db\Migration;
|
||
use yii\db\Query;
|
||
use yii\web\DbSession;
|
||
use yiiunit\framework\console\controllers\EchoMigrateController;
|
||
use yiiunit\TestCase;
|
||
|
||
/**
|
||
* @group db
|
||
*/
|
||
abstract class AbstractDbSessionTest extends TestCase
|
||
{
|
||
use SessionTestTrait;
|
||
|
||
/**
|
||
* @return string[] the driver names that are suitable for the test (mysql, pgsql, etc)
|
||
*/
|
||
abstract protected function getDriverNames();
|
||
|
||
protected function setUp()
|
||
{
|
||
parent::setUp();
|
||
|
||
$this->mockApplication();
|
||
Yii::$app->set('db', $this->getDbConfig());
|
||
$this->dropTableSession();
|
||
$this->createTableSession();
|
||
}
|
||
|
||
protected function tearDown()
|
||
{
|
||
$this->dropTableSession();
|
||
parent::tearDown();
|
||
}
|
||
|
||
protected function getDbConfig()
|
||
{
|
||
$driverNames = $this->getDriverNames();
|
||
$databases = self::getParam('databases');
|
||
foreach ($driverNames as $driverName) {
|
||
if (in_array($driverName, \PDO::getAvailableDrivers()) && array_key_exists($driverName, $databases)) {
|
||
$driverAvailable = $driverName;
|
||
break;
|
||
}
|
||
}
|
||
if (!isset($driverAvailable)) {
|
||
$this->markTestIncomplete(get_called_class() . ' requires ' . implode(' or ', $driverNames) . ' PDO driver! Configuration for connection required too.');
|
||
return [];
|
||
}
|
||
$config = $databases[$driverAvailable];
|
||
|
||
$result = [
|
||
'class' => Connection::className(),
|
||
'dsn' => $config['dsn'],
|
||
];
|
||
|
||
if (isset($config['username'])) {
|
||
$result['username'] = $config['username'];
|
||
}
|
||
if (isset($config['password'])) {
|
||
$result['password'] = $config['password'];
|
||
}
|
||
|
||
return $result;
|
||
}
|
||
|
||
protected function createTableSession()
|
||
{
|
||
$this->runMigrate('up');
|
||
}
|
||
|
||
protected function dropTableSession()
|
||
{
|
||
try {
|
||
$this->runMigrate('down', ['all']);
|
||
} catch (\Exception $e) {
|
||
// Table may not exist for different reasons, but since this method
|
||
// reverts DB changes to make next test pass, this exception is skipped.
|
||
}
|
||
}
|
||
|
||
// Tests :
|
||
|
||
public function testReadWrite()
|
||
{
|
||
$session = new DbSession();
|
||
|
||
$session->writeSession('test', 'session data');
|
||
$this->assertEquals('session data', $session->readSession('test'));
|
||
$session->destroySession('test');
|
||
$this->assertEquals('', $session->readSession('test'));
|
||
}
|
||
|
||
public function testInitializeWithConfig()
|
||
{
|
||
// should produce no exceptions
|
||
$session = new DbSession([
|
||
'useCookies' => true,
|
||
]);
|
||
|
||
$session->writeSession('test', 'session data');
|
||
$this->assertEquals('session data', $session->readSession('test'));
|
||
$session->destroySession('test');
|
||
$this->assertEquals('', $session->readSession('test'));
|
||
}
|
||
|
||
/**
|
||
* @depends testReadWrite
|
||
*/
|
||
public function testGarbageCollection()
|
||
{
|
||
$session = new DbSession();
|
||
|
||
$session->writeSession('new', 'new data');
|
||
$session->writeSession('expire', 'expire data');
|
||
|
||
$session->db->createCommand()
|
||
->update('session', ['expire' => time() - 100], 'id = :id', ['id' => 'expire'])
|
||
->execute();
|
||
$session->gcSession(1);
|
||
|
||
$this->assertEquals('', $session->readSession('expire'));
|
||
$this->assertEquals('new data', $session->readSession('new'));
|
||
}
|
||
|
||
/**
|
||
* @depends testReadWrite
|
||
*/
|
||
public function testWriteCustomField()
|
||
{
|
||
$session = new DbSession();
|
||
|
||
$session->writeCallback = function ($session) {
|
||
return ['data' => 'changed by callback data'];
|
||
};
|
||
|
||
$session->writeSession('test', 'session data');
|
||
|
||
$query = new Query();
|
||
$this->assertSame('changed by callback data', $session->readSession('test'));
|
||
}
|
||
|
||
/**
|
||
* @depends testReadWrite
|
||
*/
|
||
public function testWriteCustomFieldWithUserId()
|
||
{
|
||
$session = new DbSession();
|
||
$session->open();
|
||
$session->set('user_id', 12345);
|
||
|
||
// add mapped custom column
|
||
$migration = new Migration;
|
||
$migration->compact = true;
|
||
$migration->addColumn($session->sessionTable, 'user_id', $migration->integer());
|
||
|
||
$session->writeCallback = function ($session) {
|
||
return ['user_id' => $session['user_id']];
|
||
};
|
||
|
||
// here used to be error, fixed issue #9438
|
||
$session->close();
|
||
|
||
// reopen & read session from DB
|
||
$session->open();
|
||
$loadedUserId = empty($session['user_id']) ? null : $session['user_id'];
|
||
$this->assertSame($loadedUserId, 12345);
|
||
$session->close();
|
||
}
|
||
|
||
protected function buildObjectForSerialization()
|
||
{
|
||
$object = new \stdClass();
|
||
$object->nullValue = null;
|
||
$object->floatValue = pi();
|
||
$object->textValue = str_repeat('Qweå߃Тест', 200);
|
||
$object->array = [null, 'ab' => 'cd'];
|
||
$object->binary = base64_decode('5qS2UUcXWH7rjAmvhqGJTDNkYWFiOGMzNTFlMzNmMWIyMDhmOWIwYzAwYTVmOTFhM2E5MDg5YjViYzViN2RlOGZlNjllYWMxMDA0YmQxM2RQ3ZC0in5ahjNcehNB/oP/NtOWB0u3Skm67HWGwGt9MA==');
|
||
$object->with_null_byte = 'hey!' . "\0" . 'y"ûƒ^äjw¾bðúl5êù-Ö=W¿Š±¬GP¥Œy÷&ø';
|
||
|
||
if (version_compare(PHP_VERSION, '5.5.0', '<')) {
|
||
unset($object->binary);
|
||
// Binary data can not be inserted on PHP <5.5
|
||
}
|
||
|
||
return $object;
|
||
}
|
||
|
||
public function testSerializedObjectSaving()
|
||
{
|
||
$session = new DbSession();
|
||
|
||
$object = $this->buildObjectForSerialization();
|
||
$serializedObject = serialize($object);
|
||
$session->writeSession('test', $serializedObject);
|
||
$this->assertSame($serializedObject, $session->readSession('test'));
|
||
|
||
$object->foo = 'modification checked';
|
||
$serializedObject = serialize($object);
|
||
$session->writeSession('test', $serializedObject);
|
||
$this->assertSame($serializedObject, $session->readSession('test'));
|
||
}
|
||
|
||
protected function runMigrate($action, $params = [])
|
||
{
|
||
$migrate = new EchoMigrateController('migrate', Yii::$app, [
|
||
'migrationPath' => '@yii/web/migrations',
|
||
'interactive' => false,
|
||
]);
|
||
|
||
ob_start();
|
||
ob_implicit_flush(false);
|
||
$migrate->run($action, $params);
|
||
ob_get_clean();
|
||
|
||
return array_map(function ($version) {
|
||
return substr($version, 15);
|
||
}, (new Query())->select(['version'])->from('migration')->column());
|
||
}
|
||
|
||
public function testMigration()
|
||
{
|
||
$this->dropTableSession();
|
||
$this->mockWebApplication([
|
||
'components' => [
|
||
'db' => $this->getDbConfig(),
|
||
],
|
||
]);
|
||
|
||
$history = $this->runMigrate('history');
|
||
$this->assertEquals(['base'], $history);
|
||
|
||
$history = $this->runMigrate('up');
|
||
$this->assertEquals(['base', 'session_init'], $history);
|
||
|
||
$history = $this->runMigrate('down');
|
||
$this->assertEquals(['base'], $history);
|
||
$this->createTableSession();
|
||
}
|
||
|
||
public function testInstantiate()
|
||
{
|
||
$oldTimeout = ini_get('session.gc_maxlifetime');
|
||
// unset Yii::$app->db to make sure that all queries are made against sessionDb
|
||
Yii::$app->set('sessionDb', Yii::$app->db);
|
||
Yii::$app->set('db', null);
|
||
|
||
$session = new DbSession([
|
||
'timeout' => 300,
|
||
'db' => 'sessionDb',
|
||
]);
|
||
|
||
$this->assertSame(Yii::$app->sessionDb, $session->db);
|
||
$this->assertSame(300, $session->timeout);
|
||
$session->close();
|
||
|
||
Yii::$app->set('db', Yii::$app->sessionDb);
|
||
Yii::$app->set('sessionDb', null);
|
||
ini_set('session.gc_maxlifetime', $oldTimeout);
|
||
}
|
||
|
||
public function testInitUseStrictMode()
|
||
{
|
||
$this->initStrictModeTest(DbSession::className());
|
||
}
|
||
|
||
public function testUseStrictMode()
|
||
{
|
||
$this->useStrictModeTest(DbSession::className());
|
||
}
|
||
}
|