PHP's documentation page for flock()
indicates that it's not safe to use under IIS. If I can't rely on flock
under all circumstances, is there another way I could safely achieve the same thing?
flock() function in PHP The flock() function locks or releases a file. The function returns TRUE on success and FALSE on failure.
flock() allows you to perform a simple reader/writer model which can be used on virtually every platform (including most Unix derivatives and even Windows). The lock is released also by fclose(), or when stream is garbage collected.
LOCK_NB means non-blocking. Usually when you try to lock a file, your PHP script execution will stop. The call to flock() then blocks it from resuming. It does so until a concurrent lock on the accessed file is removed.
php") . ". lock"); if (! tryLock()) die("Already running.
There is no alternative available to safely achieve the same under all imaginary possible circumstances. That's by design of computer systems and the job is not trivial for cross-platform code.
If you need to make safe use of flock()
, document the requirements for your application instead.
Alternatively you can create your own locking mechanism, however you must ensure it's atomic. That means, you must test for the lock and if it does not exists, establish the lock while you need to ensure that nothing else can acquire the lock in-between.
This can be done by creating a lock-file representing the lock but only if it does not exists. Unfortunately, PHP does not offer such a function to create a file in such a way.
Alternatively you can create a directory with mkdir()
and work with the result because it will return true
when the directory was created and false
if it already existed.
You can implement a filelock - unlock pattern around your read/write operations based on mkdir, since that is atomic and pretty fast. I've stress tested this and unlike mgutt did not find a bottleneck. You have to take care of deadlock situations though, which is probably what mgutt experienced. A dead lock is when two lock attempts keep waiting on each other. It can be remedied by a random interval on the lock attempts. Like so:
// call this always before reading or writing to your filepath in concurrent situations
function lockFile($filepath){
clearstatcache();
$lockname=$filepath.".lock";
// if the lock already exists, get its age:
$life=@filectime($lockname);
// attempt to lock, this is the really important atomic action:
while (!@mkdir($lockname)){
if ($life)
if ((time()-$life)>120){
//release old locks
rmdir($lockname);
$life=false;
}
usleep(rand(50000,200000));//wait random time before trying again
}
}
Then work on your file in filepath and when you're done, call:
function unlockFile($filepath){
$unlockname= $filepath.".lock";
return @rmdir($unlockname);
}
I've chosen to remove old locks, well after the maximum PHP execution time in case a script exits before it has unlocked. A better way would be to remove locks always when the script fails. There is a neat way for this, but I have forgotten.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With