From 1b571dd9ce615069c3e4e711f8fb693aebb9400e Mon Sep 17 00:00:00 2001 From: Adam Kiss Date: Sat, 4 Jan 2025 20:37:50 +0100 Subject: [PATCH 1/2] Cache: base74 value if it contains `\0` and the connection is sqlite3 --- src/Illuminate/Cache/DatabaseStore.php | 5 ++-- tests/Cache/CacheDatabaseStoreTest.php | 32 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 3210b718de61..08ad09a6bc16 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -7,6 +7,7 @@ use Illuminate\Contracts\Cache\Store; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\PostgresConnection; +use Illuminate\Database\SQLiteConnection; use Illuminate\Database\QueryException; use Illuminate\Database\SqlServerConnection; use Illuminate\Support\Arr; @@ -487,7 +488,7 @@ protected function serialize($value) { $result = serialize($value); - if ($this->connection instanceof PostgresConnection && str_contains($result, "\0")) { + if (($this->connection instanceof PostgresConnection || $this->connection instanceof SQLiteConnection) && str_contains($result, "\0")) { $result = base64_encode($result); } @@ -502,7 +503,7 @@ protected function serialize($value) */ protected function unserialize($value) { - if ($this->connection instanceof PostgresConnection && ! Str::contains($value, [':', ';'])) { + if (($this->connection instanceof PostgresConnection || $this->connection instanceof SQLiteConnection) && ! Str::contains($value, [':', ';'])) { $value = base64_decode($value); } diff --git a/tests/Cache/CacheDatabaseStoreTest.php b/tests/Cache/CacheDatabaseStoreTest.php index 639373c3751d..72daaa3d4130 100755 --- a/tests/Cache/CacheDatabaseStoreTest.php +++ b/tests/Cache/CacheDatabaseStoreTest.php @@ -6,6 +6,7 @@ use Illuminate\Cache\DatabaseStore; use Illuminate\Database\Connection; use Illuminate\Database\PostgresConnection; +use Illuminate\Database\SQLiteConnection; use Mockery as m; use PHPUnit\Framework\TestCase; use stdClass; @@ -68,6 +69,16 @@ public function testValueIsReturnedOnPostgres() $this->assertSame('bar', $store->get('foo')); } + public function testValueIsReturnedOnSqlite() { + $store = $this->getSqliteStore(); + $table = m::mock(stdClass::class); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $table->shouldReceive('whereIn')->once()->with('key', ['prefixfoo'])->andReturn($table); + $table->shouldReceive('get')->once()->andReturn(collect([(object)['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0bar\0")), 'expiration' => 999999999999999]])); + + $this->assertSame("\0bar\0", $store->get('foo')); + } + public function testValueIsUpserted() { $store = $this->getMockBuilder(DatabaseStore::class)->onlyMethods(['getTime'])->setConstructorArgs($this->getMocks())->getMock(); @@ -92,6 +103,17 @@ public function testValueIsUpsertedOnPostgres() $this->assertTrue($result); } + public function testValueIsUpsertedOnSqlite() { + $store = $this->getMockBuilder(DatabaseStore::class)->onlyMethods(['getTime'])->setConstructorArgs($this->getSqliteMocks())->getMock(); + $table = m::mock(stdClass::class); + $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); + $store->expects($this->once())->method('getTime')->willReturn(1); + $table->shouldReceive('upsert')->once()->with([['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0")), 'expiration' => 61]], 'key')->andReturn(1); + + $result = $store->put('foo', "\0", 60); + $this->assertTrue($result); + } + public function testForeverCallsStoreItemWithReallyLongTime() { $store = $this->getMockBuilder(DatabaseStore::class)->onlyMethods(['put'])->setConstructorArgs($this->getMocks())->getMock(); @@ -210,6 +232,11 @@ protected function getPostgresStore() return new DatabaseStore(m::mock(PostgresConnection::class), 'table', 'prefix'); } + protected function getSqliteStore() + { + return new DatabaseStore(m::mock(SQLiteConnection::class), 'table', 'prefix'); + } + protected function getMocks() { return [m::mock(Connection::class), 'table', 'prefix']; @@ -219,4 +246,9 @@ protected function getPostgresMocks() { return [m::mock(PostgresConnection::class), 'table', 'prefix']; } + + protected function getSqliteMocks() + { + return [m::mock(SQLiteConnection::class), 'table', 'prefix']; + } } From 0391e92e58dffbe9d1389535ba48ffff303d6cb5 Mon Sep 17 00:00:00 2001 From: Adam Kiss Date: Sat, 4 Jan 2025 20:42:37 +0100 Subject: [PATCH 2/2] Fix formatting --- src/Illuminate/Cache/DatabaseStore.php | 2 +- tests/Cache/CacheDatabaseStoreTest.php | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/Illuminate/Cache/DatabaseStore.php b/src/Illuminate/Cache/DatabaseStore.php index 08ad09a6bc16..1ed9ad84363b 100755 --- a/src/Illuminate/Cache/DatabaseStore.php +++ b/src/Illuminate/Cache/DatabaseStore.php @@ -7,8 +7,8 @@ use Illuminate\Contracts\Cache\Store; use Illuminate\Database\ConnectionInterface; use Illuminate\Database\PostgresConnection; -use Illuminate\Database\SQLiteConnection; use Illuminate\Database\QueryException; +use Illuminate\Database\SQLiteConnection; use Illuminate\Database\SqlServerConnection; use Illuminate\Support\Arr; use Illuminate\Support\Collection; diff --git a/tests/Cache/CacheDatabaseStoreTest.php b/tests/Cache/CacheDatabaseStoreTest.php index 72daaa3d4130..e069421b2c43 100755 --- a/tests/Cache/CacheDatabaseStoreTest.php +++ b/tests/Cache/CacheDatabaseStoreTest.php @@ -69,12 +69,13 @@ public function testValueIsReturnedOnPostgres() $this->assertSame('bar', $store->get('foo')); } - public function testValueIsReturnedOnSqlite() { + public function testValueIsReturnedOnSqlite() + { $store = $this->getSqliteStore(); $table = m::mock(stdClass::class); $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table); $table->shouldReceive('whereIn')->once()->with('key', ['prefixfoo'])->andReturn($table); - $table->shouldReceive('get')->once()->andReturn(collect([(object)['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0bar\0")), 'expiration' => 999999999999999]])); + $table->shouldReceive('get')->once()->andReturn(collect([(object) ['key' => 'prefixfoo', 'value' => base64_encode(serialize("\0bar\0")), 'expiration' => 999999999999999]])); $this->assertSame("\0bar\0", $store->get('foo')); } @@ -103,7 +104,8 @@ public function testValueIsUpsertedOnPostgres() $this->assertTrue($result); } - public function testValueIsUpsertedOnSqlite() { + public function testValueIsUpsertedOnSqlite() + { $store = $this->getMockBuilder(DatabaseStore::class)->onlyMethods(['getTime'])->setConstructorArgs($this->getSqliteMocks())->getMock(); $table = m::mock(stdClass::class); $store->getConnection()->shouldReceive('table')->once()->with('table')->andReturn($table);