Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 0201f9f

Browse filesBrowse files
committed
[Filesystem] Added a lock handler
1 parent e86fe91 commit 0201f9f
Copy full SHA for 0201f9f

File tree

3 files changed

+193
-1
lines changed
Filter options

3 files changed

+193
-1
lines changed

‎src/Symfony/Component/Filesystem/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Filesystem/CHANGELOG.md
+6-1Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
2.6.0
5+
-----
6+
7+
* added LockHandler
8+
49
2.3.12
510
------
611

@@ -10,7 +15,7 @@ CHANGELOG
1015
-----
1116

1217
* added the dumpFile() method to atomically write files
13-
18+
1419
2.2.0
1520
-----
1621

+102Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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\Filesystem;
13+
14+
use Symfony\Component\Filesystem\Exception\IOException;
15+
16+
/**
17+
* LockHandler class provides a simple abstraction to lock anything by means of
18+
* a file lock. A locked file is created based on the lock name when calling
19+
* lock(). Other processes will not be able to lock the same name until it is
20+
* released.
21+
*
22+
* @author Grégoire Pineau <lyrixx@lyrixx.info>
23+
* @author Romain Neutron <imprec@gmail.com>
24+
* @author Nicolas Grekas <p@tchwork.com>
25+
*/
26+
class LockHandler
27+
{
28+
private $file;
29+
private $handle;
30+
31+
/**
32+
* @param string $name The lock name
33+
* @param string|null $lockPath The directory to store the lock
34+
* @throws IOException If the lock directory could not be created or is not writable
35+
*/
36+
public function __construct($name, $lockPath = null)
37+
{
38+
$name = sprintf('%s-%s', preg_replace('/[^a-z0-9\._-]+/i', '-', $name), hash('sha256', $name));
39+
40+
$lockPath = $lockPath ?: sys_get_temp_dir();
41+
42+
$file = sprintf('%s/%s', $lockPath, $name);
43+
44+
if (!is_dir($lockPath)) {
45+
$fs = new Filesystem();
46+
$fs->mkdir($lockPath);
47+
}
48+
49+
if (!is_writable($lockPath)) {
50+
throw new IOException(sprintf('The directory "%s" is not writable.', $lockPath), 0, null, $lockPath);
51+
}
52+
53+
$this->file = $file;
54+
}
55+
56+
/**
57+
* Lock the resource
58+
*
59+
* @param bool $blocking wait until the lock is released
60+
* @return bool Returns true if the lock was acquired, false otherwise
61+
* @throws IOException If the lock file could not be created or opened
62+
*/
63+
public function lock($blocking = false)
64+
{
65+
if ($this->handle) {
66+
return true;
67+
}
68+
69+
// Set an error handler to not trigger the registered error handler if
70+
// the file can not be opened.
71+
set_error_handler('var_dump', 0);
72+
$this->handle = @fopen($this->file, 'c');
73+
restore_error_handler();
74+
75+
if (!$this->handle) {
76+
throw new IOException(sprintf('Unable to fopen "%s".', $this->file), 0, null, $this->file);
77+
}
78+
79+
// On Windows, even if PHP doc says the contrary, LOCK_NB works, see
80+
// https://bugs.php.net/54129
81+
if (!flock($this->handle, LOCK_EX | ($blocking ? 0 : LOCK_NB))) {
82+
fclose($this->handle);
83+
$this->handle = null;
84+
85+
return false;
86+
}
87+
88+
return true;
89+
}
90+
91+
/**
92+
* Unlock the resource
93+
*/
94+
public function unlock()
95+
{
96+
if ($this->handle) {
97+
flock($this->handle, LOCK_UN | LOCK_NB);
98+
fclose($this->handle);
99+
$this->handle = null;
100+
}
101+
}
102+
}
+85Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<?php
2+
3+
namespace Symfony\Component\Filesystem\Tests;
4+
5+
use Symfony\Component\Filesystem\LockHandler;
6+
7+
class LockHandlerTest extends \PHPUnit_Framework_TestCase
8+
{
9+
/**
10+
* @expectedException Symfony\Component\Filesystem\Exception\IOException
11+
* @expectedExceptionMessage Failed to create "/a/b/c/d/e": mkdir(): Permission denied.
12+
*/
13+
public function testConstructWhenRepositoryDoesNotExist()
14+
{
15+
new LockHandler('lock', '/a/b/c/d/e');
16+
}
17+
18+
/**
19+
* @expectedException Symfony\Component\Filesystem\Exception\IOException
20+
* @expectedExceptionMessage The directory "/" is not writable.
21+
*/
22+
public function testConstructWhenRepositoryIsNotWriteable()
23+
{
24+
new LockHandler('lock', '/');
25+
}
26+
27+
public function testConstructSanitizeName()
28+
{
29+
$lock = new LockHandler('<?php echo "% hello word ! %" ?>');
30+
31+
$file = sprintf('%s/-php-echo-hello-word--4b3d9d0d27ddef3a78a64685dda3a963e478659a9e5240feaf7b4173a8f28d5f', sys_get_temp_dir());
32+
// ensure the file does not exist before the lock
33+
@unlink($file);
34+
35+
$lock->lock();
36+
37+
$this->assertFileExists($file);
38+
39+
$lock->unlock();
40+
}
41+
42+
public function testLockUnlock()
43+
{
44+
$name = 'symfony-test-filesystem.lock';
45+
46+
$l1 = new LockHandler($name);
47+
$l2 = new LockHandler($name);
48+
49+
$this->assertTrue($l1->lock());
50+
$this->assertFalse($l2->lock());
51+
52+
$l1->unlock();
53+
54+
$this->assertTrue($l2->lock());
55+
$l2->unlock();
56+
}
57+
58+
public function testLockTwice()
59+
{
60+
$name = 'symfony-test-filesystem.lock';
61+
62+
$lockHandler = new LockHandler($name);
63+
64+
$this->assertTrue($lockHandler->lock());
65+
$this->assertTrue($lockHandler->lock());
66+
67+
$lockHandler->unlock();
68+
}
69+
70+
public function testLockIsReleased()
71+
{
72+
$name = 'symfony-test-filesystem.lock';
73+
74+
$l1 = new LockHandler($name);
75+
$l2 = new LockHandler($name);
76+
77+
$this->assertTrue($l1->lock());
78+
$this->assertFalse($l2->lock());
79+
80+
$l1 = null;
81+
82+
$this->assertTrue($l2->lock());
83+
$l2->unlock();
84+
}
85+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.