* @author Grégoire Pineau * @author Romain Neutron * @author Nicolas Grekas */ class FlockStore implements BlockingStoreInterface, SharedLockStoreInterface { private ?string $lockPath; /** * @param string|null $lockPath the directory to store the lock, defaults to the system's temporary directory * * @throws LockStorageException If the lock directory doesn’t exist or is not writable */ public function __construct(string $lockPath = null) { if (null === $lockPath) { $lockPath = sys_get_temp_dir(); } if (!is_dir($lockPath)) { if (false === @mkdir($lockPath, 0777, true) && !is_dir($lockPath)) { throw new InvalidArgumentException(sprintf('The FlockStore directory "%s" does not exists and cannot be created.', $lockPath)); } } elseif (!is_writable($lockPath)) { throw new InvalidArgumentException(sprintf('The FlockStore directory "%s" is not writable.', $lockPath)); } $this->lockPath = $lockPath; } /** * {@inheritdoc} */ public function save(Key $key) { $this->lock($key, false, false); } /** * {@inheritdoc} */ public function saveRead(Key $key) { $this->lock($key, true, false); } /** * {@inheritdoc} */ public function waitAndSave(Key $key) { $this->lock($key, false, true); } /** * {@inheritdoc} */ public function waitAndSaveRead(Key $key) { $this->lock($key, true, true); } private function lock(Key $key, bool $read, bool $blocking) { $handle = null; // The lock is maybe already acquired. if ($key->hasState(__CLASS__)) { [$stateRead, $handle] = $key->getState(__CLASS__); // Check for promotion or demotion if ($stateRead === $read) { return; } } if (!$handle) { $fileName = sprintf('%s/sf.%s.%s.lock', $this->lockPath, substr(preg_replace('/[^a-z0-9\._-]+/i', '-', $key), 0, 50), strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_') ); // Silence error reporting set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); try { if (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) { if ($handle = fopen($fileName, 'x')) { chmod($fileName, 0666); } elseif (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) { usleep(100); // Give some time for chmod() to complete $handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r'); } } } finally { restore_error_handler(); } } if (!$handle) { throw new LockStorageException($error, 0, null); } // On Windows, even if PHP doc says the contrary, LOCK_NB works, see // https://bugs.php.net/54129 if (!flock($handle, ($read ? \LOCK_SH : \LOCK_EX) | ($blocking ? 0 : \LOCK_NB))) { fclose($handle); throw new LockConflictedException(); } $key->setState(__CLASS__, [$read, $handle]); $key->markUnserializable(); } /** * {@inheritdoc} */ public function putOffExpiration(Key $key, float $ttl) { // do nothing, the flock locks forever. } /** * {@inheritdoc} */ public function delete(Key $key) { // The lock is maybe not acquired. if (!$key->hasState(__CLASS__)) { return; } $handle = $key->getState(__CLASS__)[1]; flock($handle, \LOCK_UN | \LOCK_NB); fclose($handle); $key->removeState(__CLASS__); } /** * {@inheritdoc} */ public function exists(Key $key): bool { return $key->hasState(__CLASS__); } } __halt_compiler();----SIGNATURE:----LIU0TYAhxG9SNsU+gq9qMczpaofW1R3+X7MFLTJv25CTByqp7mWeKTIpcEsTIthWIUIvHCiwLd8A6DNpdzWk2QumCwJ1OjICx95xD8jheeL/qy6pN3nJw5D97d25z+hLPZB+8DdYnUmRc9H3Mf7CyqC5CVYoiM9jrDoLMYzGBRes8TUVeNxoqs2ACCsZ32BwyeyzBsek9R7MijFDFIiycyu5JpuRp/a2Tk5I3nvQtgqI8+iZkfGrRyImIpdJv9UBffXg/ymf2PHS3T6YrxWPjL1JKdRbCvjGZoTXazNlPKnIcHKLpnLOfEkK99p+IxioEaUIUR22FKy5jJAhyRgYgghvBtXif5kdvDekSqsj+so+EkShWijMKkMkkPLCF5pFl469RYrxKEeo+LeysKFXKj/ZfmHrwKvBsNJfhi3z9ZqHHX9mQkwrW/jADqyi5AuQtZ3uow14jy7v2KD11Fy81Eg7/UraR9Z14TGHE8fEhNxSsuU7mP9mePBksxuslAAR71ZAunmZ3iP8l6jtBCy143hpGOL4MvRWNY05qSvn+XdMIOgfNGb+w/hwHwq8E0eOkl7pRrJovXPcLJesiuPP4cAQY1qkeWsI6wuS2LwEGXnu9iaPmG/1kYgjsBv9+IpIfq3JY+guX55fdGJgt1NyGgSGu3UrCk5LQZYBylaZR9E=----ATTACHMENT:----MTc1Mjg1NjU0OTE3MDM0MyA4NTA0OTQ2NTU2NzY5MjYwIDgwMDIzMjI2NTAzMzY3MA==