Last active
June 24, 2024 04:49
-
-
Save avtobys/fe0b42470509002efa25b329b41d592d to your computer and use it in GitHub Desktop.
class Locker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Utils; | |
/** | |
* Class Locker | |
* | |
* This class is used to lock files for a given amount of time. | |
* | |
* @package App\Utils | |
*/ | |
class Locker | |
{ | |
/** | |
* The path to the directory where lock files will be stored. | |
*/ | |
const LOCK_PATH = __DIR__ . '/../../tmp/lock'; | |
/** | |
* The prefix of the lock file. | |
*/ | |
const LOCK_PREFIX = 'lock'; | |
/** | |
* The maximum time a lock should be held in seconds. | |
*/ | |
const CLEAN_TIME = 3600; | |
/** | |
* Variable used to store the path to the lock file. | |
*/ | |
private static $path; | |
/** | |
* Used to determine if the current process has locked the file. | |
*/ | |
private static $lock = false; | |
/** | |
* Locks the file with the given name for a specified period of time. | |
* | |
* @param int $id The name of the file to be locked. | |
* @param int $max_time The maximum time the lock should be held in seconds. | |
* @return bool True if the lock was successfully obtained, false otherwise. | |
*/ | |
public static function lock($id, $max_time = self::CLEAN_TIME) | |
{ | |
// Set the path of the lock file | |
self::setPath($id); | |
// If the lock file exists and the lock has expired, remove the file | |
if (file_exists(self::$path) && self::cleaner()) { | |
return false; | |
} | |
// Create a SplFileObject and lock the file | |
$file = new \SplFileObject(self::$path, 'a+b'); | |
if ($file->flock(LOCK_EX)) { | |
$file->rewind(); | |
// Read the time stored in the file | |
$time = $file->fgets(); | |
// If the file is empty, write the current time plus the maximum lock time to the file and return true | |
if (!$time) { | |
$file->ftruncate(0); | |
$file->fwrite(time() + $max_time); | |
touch(self::$path, time() + $max_time); | |
$file->flock(LOCK_UN); | |
self::$lock = true; | |
return true; // Lock obtained | |
} | |
// Unlock the file and return false | |
$file->flock(LOCK_UN); | |
} | |
return false; // Lock not obtained | |
} | |
/** | |
* Sets the path of the lock file. | |
* | |
* @param int $id The identifier used to create the lock file's filename. | |
* @throws \Error If the lock directory cannot be created. | |
*/ | |
private static function setPath($id) | |
{ | |
// Check if the lock directory exists, and if not, create it | |
if (!file_exists(self::LOCK_PATH)) { | |
mkdir(self::LOCK_PATH, 0755, true); | |
} | |
// If the lock directory still does not exist, throw an error | |
if (!file_exists(self::LOCK_PATH)) { | |
throw new \Error('Path does not create'); | |
} | |
// Set the path of the lock file | |
self::$path = self::LOCK_PATH . '/' . self::LOCK_PREFIX . '-' . $id . '.lock'; | |
// If the lock file exists, clear its last access time | |
file_exists(self::$path) && clearstatcache(true, self::$path); | |
} | |
/** | |
* Removes the lock file. | |
* | |
* @param int $id The name of the lock file. | |
* @param bool $force True if the lock should be removed, even if it was not created by the current process. | |
* @return bool True if the lock file was successfully removed, false otherwise. | |
*/ | |
public static function unlock($id, $force = false) | |
{ | |
// Set the path of the lock file | |
self::setPath($id); | |
// Use SplFileObject to handle the file | |
$lockFile = new \SplFileObject(self::$path, 'c'); | |
// Try to acquire an exclusive lock | |
if ($lockFile->flock(LOCK_EX)) { | |
// Check if the lock file exists and if it was created by the current process or if force is true | |
if (file_exists(self::$path) && (self::$lock || $force)) { | |
// Remove the lock file | |
@unlink(self::$path); | |
$lockFile->flock(LOCK_UN); // Release the lock | |
return true; // Lock file successfully removed | |
} | |
$lockFile->flock(LOCK_UN); // Release the lock | |
} | |
return false; // Lock file not removed | |
} | |
/** | |
* Deletes any lock files that are older than the current time. | |
* | |
* @return bool True if the current lock file still exists, false otherwise. | |
*/ | |
private static function cleaner() | |
{ | |
// Loop through all lock files in the lock directory. | |
foreach (glob(self::LOCK_PATH . '/' . self::LOCK_PREFIX . '-*.lock') as $path) { | |
// Check if the file is older than the current time and if the time stored in the file is older than the current time. | |
if (filemtime($path) < time() && intval(file_get_contents($path)) < time()) { | |
// Use SplFileObject to handle the file | |
$lockFile = new \SplFileObject($path, 'c'); | |
// Try to acquire an exclusive lock | |
if ($lockFile->flock(LOCK_EX)) { | |
// Delete the file. | |
@unlink($path); | |
$lockFile->flock(LOCK_UN); // Release the lock | |
} | |
} | |
} | |
// Return true if the current lock file still exists, false otherwise. | |
return file_exists(self::$path); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment