10000 feature #20037 [Cache] Handle arbitrary key length when the backend c… · symfony/symfony@6479f49 · GitHub
[go: up one dir, main page]

Skip to content

Commit 6479f49

Browse files
committed
feature #20037 [Cache] Handle arbitrary key length when the backend cant using hashing (nicolas-grekas)
This PR was merged into the 3.2-dev branch. Discussion ---------- [Cache] Handle arbitrary key length when the backend cant using hashing | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - Saving some bits from #19521 :) Already awaited by PdoAdapter which defines the property. Commits ------- 11f448f [Cache] Handle arbitrary key length when the backend cant using hashing
2 parents e215e4f + 11f448f commit 6479f49

File tree

3 files changed

+76
-4
lines changed

3 files changed

+76
-4
lines changed

src/Symfony/Component/Cache/Adapter/AbstractAdapter.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Psr\Log\LoggerAwareTrait;
1717
use Psr\Log\LoggerInterface;
1818
use Symfony\Component\Cache\CacheItem;
19+
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1920

2021
/**
2122
* @author Nicolas Grekas <p@tchwork.com>
@@ -32,9 +33,17 @@ abstract class AbstractAdapter implements AdapterInterface, LoggerAwareInterface
3233
private $createCacheItem;
3334
private $mergeByLifetime;
3435

36+
/**
37+
* @var int|null The maximum length to enforce for identifiers or null when no limit applies
38+
*/
39+
protected $maxIdLength;
40+
3541
protected function __construct($namespace = '', $defaultLifetime = 0)
3642
{
37-
$this->namespace = '' === $namespace ? '' : $this->getId($namespace);
43+
$this->namespace = '' === $namespace ? '' : $this->getId($namespace).':';
44+
if (null !== $this->maxIdLength && strlen($namespace) > $this->maxIdLength - 24) {
45+
throw new InvalidArgumentException(sprintf('Namespace must be %d chars max, %d given ("%s")', $this->maxIdLength - 24, strlen($namespace), $namespace));
46+
}
3847
$this->createCacheItem = \Closure::bind(
3948
function ($key, $value, $isHit) use ($defaultLifetime) {
4049
$item = new CacheItem();
@@ -401,7 +410,14 @@ private function getId($key)
401410
{
402411
CacheItem::validateKey($key);
403412

404-
return $this->namespace.$key;
413+
if (null === $this->maxIdLength) {
414+
return $this->namespace.$key;
415+
}
416+
if (strlen($id = $this->namespace.$key) > $this->maxIdLength) {
417+
$id = $this->namespace.substr_replace(base64_encode(md5($key, true)), ':', -2);
418+
}
419+
420+
return $id;
405421
}
406422

407423
private function generateItems($items, &$keys)

src/Symfony/Component/Cache/Adapter/ApcuAdapter.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ public function __construct($namespace = '', $defaultLifetime = 0, $version = nu
3737
if (null !== $version) {
3838
CacheItem::validateKey($version);
3939

40-
if (!apcu_exists($version.':'.$namespace)) {
40+
if (!apcu_exists($version.'@'.$namespace)) {
4141
$this->clear($namespace);
42-
apcu_add($version.':'.$namespace, null);
42+
apcu_add($version.'@'.$namespace, null);
4343
}
4444
}
4545
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Cache\Tests\Adapter;
13+
14+
use Symfony\Component\Cache\Adapter\AbstractAdapter;
15+
16+
class MaxIdLengthAdapterTest extends \PHPUnit_Framework_TestCase
17+
{
18+
public function testLongKey()
19+
{
20+
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
21+
->setConstructorArgs(array(str_repeat('-', 10)))
22+
->setMethods(array('doHave', 'doFetch', 'doDelete', 'doSave', 'doClear'))
23+
->getMock();
24+
25+
$cache->expects($this->exactly(2))
26+
->method('doHave')
27+
->withConsecutive(
28+
array($this->equalTo('----------:nWfzGiCgLczv3SSUzXL3kg:')),
29+
array($this->equalTo('----------:---------------------------------------'))
30+
);
31+
32+
$cache->hasItem(str_repeat('-', 40));
33+
$cache->hasItem(str_repeat('-', 39));
34+
}
35+
36+
/**
37+
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
38+
* @expectedExceptionMessage Namespace must be 26 chars max, 40 given ("----------------------------------------")
39+
*/
40+
public function testTooLongNamespace()
41+
{
42+
$cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
43+
->setConstructorArgs(array(str_repeat('-', 40)))
44+
->getMock();
45+
}
46+
}
47+
48+
abstract class MaxIdLengthAdapter extends AbstractAdapter
49+
{
50+
protected $maxIdLength = 50;
51+
52+
public function __construct($ns)
53+
{
54+
parent::__construct($ns);
55+
}
56+
}

0 commit comments

Comments
 (0)
0