├── .coveralls.yml ├── .gitignore ├── CONTRIBUTING.md ├── src ├── FSLockIOException.php ├── FSLockInterface.php └── FSLock.php ├── .travis.yml ├── .editorconfig ├── composer.json ├── phpunit.xml.dist ├── CHANGELOG.md ├── LICENSE ├── README.md └── tests └── FSLockTest.php /.coveralls.yml: -------------------------------------------------------------------------------- 1 | service_name: travis-ci 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | vendor/ 2 | build/ 3 | bin/ 4 | *.lock 5 | 6 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Have an idea? Found a bug?, contributions are welcome :) 2 | -------------------------------------------------------------------------------- /src/FSLockIOException.php: -------------------------------------------------------------------------------- 1 | =7.0.0" 14 | }, 15 | "require-dev": { 16 | "phpunit/phpunit": "^6.0.0", 17 | "php-coveralls/php-coveralls": "^2.1.0", 18 | "phpstan/phpstan": "^0.9.2" 19 | }, 20 | "autoload": { 21 | "psr-4": { 22 | "FSLock\\": "src/" 23 | } 24 | }, 25 | "autoload-dev": { 26 | "psr-4": { 27 | "FSLock\\Tests\\": "tests/" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | 20 | ./src 21 | ./vendor 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## 3.0.1 - 2020-01-05 6 | 7 | - Configure Travis to run tests with new versions of PHP. 8 | 9 | ## 3.0.0 - 2018-10-01 10 | 11 | - Bump minimal PHP version to 7.x. 12 | - Declare explicit return values in methods. 13 | - Destroy method removed, after call destroy method, the instance is useless and 14 | it can not be initialized again. 15 | - Allow lock bucket to be configurable when FSLock instance it's declared. 16 | 17 | 18 | ## 2.0.0 - 2016-01-31 19 | 20 | ### Added 21 | - New method destroy, allows manually destruction of the lock. Internally release the lock and perform a cleanup operation. It's the same process used by the `__destruct` magic method. 22 | - FSLock now implements FSLockInterface. 23 | 24 | ### Changed 25 | - Improve test suit. 26 | - Update PSR-0 autoload to PSR-4 format. 27 | - Update README. 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Yago Riveiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FSLock 2 | 3 | [![Build Status](https://travis-ci.org/yriveiro/php-fslock.png?branch=master)](https://travis-ci.org/yriveiro/php-fslock) 4 | [![Coverage Status](https://coveralls.io/repos/yriveiro/php-fslock/badge.png)](https://coveralls.io/r/yriveiro/php-fslock) 5 | [![Total Downloads](https://poser.pugx.org/yriveiro/php-fslock/downloads.svg)](https://packagist.org/packages/yriveiro/php-fslock) 6 | 7 | A simple lock implementation using flock. 8 | 9 | *NOTE:* to use php-backoff with PHP 5.x please use the lastet release of branch 2.x 10 | 11 | # Usage 12 | 13 | ```PHP 14 | 15 | use FSLock\FSLock; 16 | 17 | $lock = new FSLock('test'); 18 | 19 | if ($lock->acquire()) { 20 | // Critical code. 21 | 22 | $lock->release(); 23 | } 24 | ``` 25 | 26 | If you want to use a custom path to store the locks, you should instantiate the FSLock like that 27 | 28 | ```PHP 29 | $lock = new FSLock('test', '/tmp/'); 30 | ``` 31 | 32 | # API 33 | 34 | - `acquire`: Acquires the lock, returns _true_ if the operation was successful otherwise the return is _false_. 35 | - `release`: Releases the lock, returns _true_ if the operation was successful otherwise the return is _false_. 36 | - `id`: returns the lock id. 37 | - `getPath`: returns the lock path 38 | 39 | # Install 40 | 41 | The recommended way to install this package is through [Composer](http://getcomposer.org/download/). 42 | 43 | ```sh 44 | composer require yriveiro/php-fslock:3.0.0 45 | ``` 46 | 47 | # Tests 48 | 49 | Tests are performed using the `phpunit` library, to run them: 50 | 51 | ```sh 52 | php vendor/bin/phpunit tests 53 | ``` 54 | 55 | # License 56 | 57 | FSLock is licensed under MIT license. -------------------------------------------------------------------------------- /tests/FSLockTest.php: -------------------------------------------------------------------------------- 1 | lockBucket = sys_get_temp_dir(); 14 | } 15 | 16 | public function tearDown() 17 | { 18 | @unlink("$this->lockBucket/unittest.fslock"); 19 | } 20 | 21 | public function testCreateFSLockInstance() 22 | { 23 | $this->assertEquals( 24 | "$this->lockBucket/unittest.fslock", 25 | (new FSLock('unittest'))->getPath() 26 | ); 27 | } 28 | 29 | public function testBucketWorksInSystemTempDir() 30 | { 31 | $this->assertInstanceOf('FSLock\\FSLock', new FSLock('unittest')); 32 | } 33 | 34 | /** 35 | * @expectedException \FSLock\FSLockIOException 36 | */ 37 | public function testBucketIsNotWritable() 38 | { 39 | new FSLock('unittest', '/foo'); 40 | } 41 | 42 | public function testAcquire() 43 | { 44 | $mutex1 = new FSLock('unittest'); 45 | $mutex2 = new FSLock('unittest'); 46 | 47 | $this->assertTrue($mutex1->acquire()); 48 | $this->assertFalse($mutex2->acquire()); 49 | } 50 | 51 | public function testRelease() 52 | { 53 | $mutex1 = new FSLock('unittest'); 54 | $mutex2 = new FSLock('unittest'); 55 | 56 | $this->assertTrue($mutex1->acquire()); 57 | $this->assertFalse($mutex2->acquire()); 58 | 59 | $mutex1->release(); 60 | 61 | $this->assertTrue($mutex2->acquire()); 62 | } 63 | 64 | public function testGetFSLockID() 65 | { 66 | $this->assertEquals('unittest', (new FSLock('unittest'))->id()); 67 | } 68 | 69 | public function testReleaseUnlockedFile() 70 | { 71 | $mutex = new FSLock('unittest'); 72 | 73 | $lock = new ReflectionProperty($mutex, 'lock'); 74 | $lock->setAccessible(true); 75 | $lock->setValue($mutex, null); 76 | 77 | $this->assertTrue($mutex->release()); 78 | } 79 | 80 | public function testAcquireFSLockNoResource() 81 | { 82 | $mutex = new FSLock('unittest'); 83 | 84 | $lock = new ReflectionProperty($mutex, 'lock'); 85 | $lock->setAccessible(true); 86 | $lock->setValue($mutex, null); 87 | 88 | $this->assertFalse($mutex->acquire()); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/FSLock.php: -------------------------------------------------------------------------------- 1 | lockID = $lockID; 37 | $this->lockBucket = $bucket ?: sys_get_temp_dir(); 38 | $lockFile = sprintf('%s/%s.fslock', $this->lockBucket, $this->lockID); 39 | 40 | $this->lock = @fopen($lockFile, 'c'); 41 | 42 | if ($this->lock === false) { 43 | throw new FSLockIOException("$bucket is not writable"); 44 | } 45 | } 46 | 47 | /** 48 | * Clean up. 49 | */ 50 | public function __destruct() 51 | { 52 | if (is_resource($this->lock)) { 53 | flock($this->lock, LOCK_UN); 54 | fclose($this->lock); 55 | 56 | $this->lock = null; 57 | } 58 | } 59 | 60 | /** 61 | * Acquires the lock. 62 | * 63 | * @param bool $blocker if the lock is acquire by other process before, 64 | * and we call acquire as blocker, this call blocks 65 | * after previous acquire release the lock 66 | * 67 | * @return bool 68 | */ 69 | public function acquire(bool $blocker = false): bool 70 | { 71 | if (!is_resource($this->lock)) { 72 | return false; 73 | } 74 | 75 | return flock($this->lock, ($blocker) ? LOCK_EX : LOCK_EX | LOCK_NB); 76 | } 77 | 78 | /** 79 | * Releases the lock. 80 | * 81 | * @return bool 82 | */ 83 | public function release(): bool 84 | { 85 | if (!is_resource($this->lock)) { 86 | return true; 87 | } 88 | 89 | return flock($this->lock, LOCK_UN); 90 | } 91 | 92 | /** 93 | * Returns the lock id. 94 | * 95 | * @return string 96 | */ 97 | public function id(): string 98 | { 99 | return $this->lockID; 100 | } 101 | 102 | /** 103 | * Returns the lock path. 104 | * 105 | * @return string 106 | */ 107 | public function getPath(): string 108 | { 109 | return "$this->lockBucket/$this->lockID.fslock"; 110 | } 111 | } 112 | --------------------------------------------------------------------------------