Skip to content

Commit f9b8211

Browse files
authored
Handle key being larger than 2048 bytes (#20)
1 parent 4835c98 commit f9b8211

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

src/DynamoDbCache.php

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use AsyncAws\DynamoDb\ValueObject\AttributeValue;
99
use AsyncAws\DynamoDb\ValueObject\KeysAndAttributes;
1010
use DateInterval;
11+
use LogicException;
1112
use Psr\Cache\CacheItemInterface;
1213
use Psr\Cache\CacheItemPoolInterface;
1314
use Psr\SimpleCache\CacheInterface;
@@ -23,6 +24,7 @@
2324
final class DynamoDbCache implements CacheItemPoolInterface, CacheInterface
2425
{
2526
private const RESERVED_CHARACTERS = '{}()/\@:';
27+
private const MAX_KEY_LENGTH = 2048;
2628

2729
/**
2830
* @var string
@@ -107,6 +109,11 @@ public function __construct(
107109
);
108110
}
109111
$this->converter = $converter;
112+
if ($prefix !== null && strlen($prefix) >= self::MAX_KEY_LENGTH) {
113+
throw new LogicException(
114+
sprintf('The prefix cannot be longer or equal to the maximum length: %d bytes', self::MAX_KEY_LENGTH)
115+
);
116+
}
110117
$this->prefix = $prefix;
111118
}
112119

@@ -123,8 +130,13 @@ public function getItem($key)
123130
throw $exception;
124131
}
125132

133+
$finalKey = $this->getKey($key);
134+
if (strlen($finalKey) > self::MAX_KEY_LENGTH) {
135+
$finalKey = $this->generateCompliantKey($key);
136+
}
137+
126138
try {
127-
$item = $this->getRawItem($this->getKey($key));
139+
$item = $this->getRawItem($finalKey);
128140
if (!isset($item[$this->valueField])) {
129141
throw new CacheItemNotFoundException();
130142
}
@@ -133,7 +145,7 @@ public function getItem($key)
133145
assert(method_exists($this->clock->now(), 'setTimestamp'));
134146

135147
return new DynamoCacheItem(
136-
$this->getKey($key),
148+
$finalKey,
137149
$data !== null,
138150
$data !== null ? $this->encoder->decode($data) : null,
139151
isset($item[$this->ttlField]) && $item[$this->ttlField]->getN() !== null
@@ -144,7 +156,7 @@ public function getItem($key)
144156
);
145157
} catch (CacheItemNotFoundException $e) {
146158
return new DynamoCacheItem(
147-
$this->getKey($key),
159+
$finalKey,
148160
false,
149161
null,
150162
null,
@@ -575,4 +587,16 @@ private function getRawItem(string $key): array
575587

576588
return $item->getItem();
577589
}
590+
591+
private function generateCompliantKey(string $key): string
592+
{
593+
$key = $this->getKey($key);
594+
$suffix = '_trunc_' . md5($key);
595+
596+
return substr(
597+
$this->getKey($key),
598+
0,
599+
self::MAX_KEY_LENGTH - strlen($suffix)
600+
) . $suffix;
601+
}
578602
}

tests/DynamoDbCacheTest.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use DateInterval;
1919
use DateTime;
2020
use DateTimeImmutable;
21+
use LogicException;
2122
use PHPUnit\Framework\TestCase;
2223
use Psr\Cache\CacheItemInterface;
2324
use Psr\Log\NullLogger;
@@ -287,6 +288,44 @@ public function testGetItemsDefaultFields()
287288
}
288289
}
289290

291+
/**
292+
* @see https://github.com/RikudouSage/DynamoDbCachePsr6/issues/19
293+
*/
294+
public function testGetItemKeyTooLong()
295+
{
296+
$key = bin2hex(random_bytes(1025));
297+
298+
$item = $this->instance->getItem($key);
299+
self::assertNotEquals($key, $item->getKey());
300+
self::assertLessThanOrEqual(2048, strlen($item->getKey()));
301+
302+
$item = $this->instancePrefixed->getItem($key);
303+
self::assertNotEquals($key, $item->getKey());
304+
self::assertNotEquals($this->prefix . $key, $item->getKey());
305+
self::assertStringStartsWith($this->prefix, $item->getKey());
306+
self::assertLessThanOrEqual(2048, strlen($item->getKey()));
307+
308+
$key = bin2hex(random_bytes(1023));
309+
310+
$item = $this->instance->getItem($key);
311+
self::assertEquals($key, $item->getKey());
312+
$item = $this->instancePrefixed->getItem($key);
313+
self::assertNotEquals($key, $item->getKey());
314+
315+
$this->expectException(LogicException::class);
316+
new DynamoDbCache(
317+
'test',
318+
$this->getFakeClient($this->itemPoolPrefixed),
319+
'id',
320+
'ttl',
321+
'value',
322+
null,
323+
null,
324+
null,
325+
bin2hex(random_bytes(1024)),
326+
);
327+
}
328+
290329
public function testGetItemsPrefixed()
291330
{
292331
$result = $this->instancePrefixed->getItems([

0 commit comments

Comments
 (0)