diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 49821a043de57..70b48f208df70 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2009,7 +2009,7 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont $storeDefinition = new Definition(PersistingStoreInterface::class); $storeDefinition ->setFactory([StoreFactory::class, 'createStore']) - ->setArguments([$resourceStore]) + ->setArguments([$resourceStore, new Parameter('kernel.secret')]) ->addTag('lock.store'); $container->setDefinition($storeDefinitionId = '.lock.'.$resourceName.'.store.'.$container->hash($storeDsn), $storeDefinition); diff --git a/src/Symfony/Component/Lock/CHANGELOG.md b/src/Symfony/Component/Lock/CHANGELOG.md index 3c7f1b834bc83..3a71980b05b21 100644 --- a/src/Symfony/Component/Lock/CHANGELOG.md +++ b/src/Symfony/Component/Lock/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +7.2 +--- + + * Add parameter `$prefix` to `FlockStore::__construct()` + 7.0 --- diff --git a/src/Symfony/Component/Lock/Store/FlockStore.php b/src/Symfony/Component/Lock/Store/FlockStore.php index 403aede6c2bae..911a915981dc1 100644 --- a/src/Symfony/Component/Lock/Store/FlockStore.php +++ b/src/Symfony/Component/Lock/Store/FlockStore.php @@ -32,12 +32,15 @@ class FlockStore implements BlockingStoreInterface, SharedLockStoreInterface { private ?string $lockPath; + private ?string $prefix; + /** * @param string|null $lockPath the directory to store the lock, defaults to the system's temporary directory + * @param string|null $prefix a prefix to add to the lock filenames to avoid collision * * @throws LockStorageException If the lock directory doesn’t exist or is not writable */ - public function __construct(?string $lockPath = null) + public function __construct(?string $lockPath = null, ?string $prefix = null) { if (!is_dir($lockPath ??= sys_get_temp_dir())) { if (false === @mkdir($lockPath, 0777, true) && !is_dir($lockPath)) { @@ -48,6 +51,7 @@ public function __construct(?string $lockPath = null) } $this->lockPath = $lockPath; + $this->prefix = $prefix; } public function save(Key $key): void @@ -83,8 +87,9 @@ private function lock(Key $key, bool $read, bool $blocking): void } if (!$handle) { - $fileName = \sprintf('%s/sf.%s.%s.lock', + $fileName = \sprintf('%s/sf.%s%s.%s.lock', $this->lockPath, + $this->prefix ? $this->prefix.'.' : '', substr(preg_replace('/[^a-z0-9\._-]+/i', '-', $key), 0, 50), strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') ); diff --git a/src/Symfony/Component/Lock/Store/StoreFactory.php b/src/Symfony/Component/Lock/Store/StoreFactory.php index bc65182e45dde..9a3a0ad0fc282 100644 --- a/src/Symfony/Component/Lock/Store/StoreFactory.php +++ b/src/Symfony/Component/Lock/Store/StoreFactory.php @@ -24,7 +24,7 @@ */ class StoreFactory { - public static function createStore(#[\SensitiveParameter] object|string $connection): PersistingStoreInterface + public static function createStore(#[\SensitiveParameter] object|string $connection, #[\SensitiveParameter] ?string $secret = null): PersistingStoreInterface { switch (true) { case $connection instanceof \Redis: @@ -54,6 +54,9 @@ public static function createStore(#[\SensitiveParameter] object|string $connect case 'flock' === $connection: return new FlockStore(); + case str_starts_with($connection, 'flock+exclusive://'): + return new FlockStore(substr($connection, 15), $secret); + case str_starts_with($connection, 'flock://'): return new FlockStore(substr($connection, 8)); diff --git a/src/Symfony/Component/Lock/Tests/Store/FlockStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/FlockStoreTest.php index 910dd1800ec78..49e66c2c59e79 100644 --- a/src/Symfony/Component/Lock/Tests/Store/FlockStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/FlockStoreTest.php @@ -25,9 +25,9 @@ class FlockStoreTest extends AbstractStoreTestCase use SharedLockStoreTestTrait; use UnserializableTestTrait; - protected function getStore(): PersistingStoreInterface + protected function getStore(?string $prefix = null): PersistingStoreInterface { - return new FlockStore(); + return new FlockStore(null, $prefix); } public function testConstructWhenRepositoryCannotBeCreated() @@ -101,4 +101,25 @@ public function testSaveSanitizeLongName() $store->delete($key); } + + public function testSavePrefix() + { + $store = $this->getStore('FlockSecret'); + + $key = new Key(__CLASS__); + + $file = \sprintf( + '%s/sf.FlockSecret.Symfony-Component-Lock-Tests-Store-FlockStoreTest.%s.lock', + sys_get_temp_dir(), + strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') + ); + // ensure the file does not exist before the store + @unlink($file); + + $store->save($key); + + $this->assertFileExists($file); + + $store->delete($key); + } } diff --git a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php index 6d2319c8d760e..09a88b5753639 100644 --- a/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/StoreFactoryTest.php @@ -92,5 +92,6 @@ public static function validConnections(): \Generator yield ['flock', FlockStore::class]; yield ['flock://'.sys_get_temp_dir(), FlockStore::class]; + yield ['flock+exclusive://'.sys_get_temp_dir(), FlockStore::class]; } }