LockableFile.php
TLDR
This file contains the implementation of the LockableFile
class, which provides methods for creating, reading, writing, truncating, and locking files.
Classes
LockableFile
The LockableFile
class allows you to work with files and provides the following methods:
-
__construct($path, $mode)
: Constructs a newLockableFile
instance with the specified file path and mode. -
read($length = null)
: Reads the file contents up to the specified length. If no length is provided, it reads the entire file. -
size()
: Retrieves the size of the file. -
write($contents)
: Writes the specified contents to the file. -
truncate()
: Truncates the file, removing all contents. -
getSharedLock($block = false)
: Attempts to acquire a shared lock on the file. If$block
is set to true, it will block until the lock is acquired; otherwise, it will throw aLockTimeoutException
if the lock cannot be acquired immediately. -
getExclusiveLock($block = false)
: Attempts to acquire an exclusive lock on the file. If$block
is set to true, it will block until the lock is acquired; otherwise, it will throw aLockTimeoutException
if the lock cannot be acquired immediately. -
releaseLock()
: Releases the lock on the file. -
close()
: Closes the file.
Note: If the file cannot be created or opened, an Exception
will be thrown.
<?php
namespace Illuminate\Filesystem;
use Exception;
use Illuminate\Contracts\Filesystem\LockTimeoutException;
class LockableFile
{
/**
* The file resource.
*
* @var resource
*/
protected $handle;
/**
* The file path.
*
* @var string
*/
protected $path;
/**
* Indicates if the file is locked.
*
* @var bool
*/
protected $isLocked = false;
/**
* Create a new File instance.
*
* @param string $path
* @param string $mode
* @return void
*/
public function __construct($path, $mode)
{
$this->path = $path;
$this->ensureDirectoryExists($path);
$this->createResource($path, $mode);
}
/**
* Create the file's directory if necessary.
*
* @param string $path
* @return void
*/
protected function ensureDirectoryExists($path)
{
if (! file_exists(dirname($path))) {
@mkdir(dirname($path), 0777, true);
}
}
/**
* Create the file resource.
*
* @param string $path
* @param string $mode
* @return void
*
* @throws \Exception
*/
protected function createResource($path, $mode)
{
$this->handle = @fopen($path, $mode);
if (! $this->handle) {
throw new Exception('Unable to create lockable file: '.$path.'. Please ensure you have permission to create files in this location.');
}
}
/**
* Read the file contents.
*
* @param int|null $length
* @return string
*/
public function read($length = null)
{
clearstatcache(true, $this->path);
return fread($this->handle, $length ?? ($this->size() ?: 1));
}
/**
* Get the file size.
*
* @return int
*/
public function size()
{
return filesize($this->path);
}
/**
* Write to the file.
*
* @param string $contents
* @return $this
*/
public function write($contents)
{
fwrite($this->handle, $contents);
fflush($this->handle);
return $this;
}
/**
* Truncate the file.
*
* @return $this
*/
public function truncate()
{
rewind($this->handle);
ftruncate($this->handle, 0);
return $this;
}
/**
* Get a shared lock on the file.
*
* @param bool $block
* @return $this
*
* @throws \Illuminate\Contracts\Filesystem\LockTimeoutException
*/
public function getSharedLock($block = false)
{
if (! flock($this->handle, LOCK_SH | ($block ? 0 : LOCK_NB))) {
throw new LockTimeoutException("Unable to acquire file lock at path [{$this->path}].");
}
$this->isLocked = true;
return $this;
}
/**
* Get an exclusive lock on the file.
*
* @param bool $block
* @return bool
*
* @throws \Illuminate\Contracts\Filesystem\LockTimeoutException
*/
public function getExclusiveLock($block = false)
{
if (! flock($this->handle, LOCK_EX | ($block ? 0 : LOCK_NB))) {
throw new LockTimeoutException("Unable to acquire file lock at path [{$this->path}].");
}
$this->isLocked = true;
return $this;
}
/**
* Release the lock on the file.
*
* @return $this
*/
public function releaseLock()
{
flock($this->handle, LOCK_UN);
$this->isLocked = false;
return $this;
}
/**
* Close the file.
*
* @return bool
*/
public function close()
{
if ($this->isLocked) {
$this->releaseLock();
}
return fclose($this->handle);
}
}