I have a process that writes a file using file_put_contents()
:
file_put_contents ( $file, $data, LOCK_EX );
I have added the LOCK_EX
parameter to prevent concurrent processes from writing to the same file, and prevent trying to read it when it's still being written to.
I'm having difficulties testing this properly due to the concurrent nature, and I'm not sure how to approach this. I've got this so far:
if (file_exists($file)) {
$fp = fopen($file, 'r+');
if (!flock($fp, LOCK_EX|LOCK_NB, $wouldblock)) {
if ($wouldblock) {
// how can I wait until the file is unlocked?
} else {
// what other reasons could there be for not being able to lock?
}
}
// does calling fclose automatically close all locks even is a flock was not obtained above?
fclose($file);
}
Questions being:
fclose()
automatically unlock all locks when there would be another process that had locked the file?I wrote a small test that uses sleep()
so that I could simulate concurrent read/write processes with a simple AJAX call. It seems this answers both questions:
fclose()
does indeed not remove the lock from the process that's already running as confirmed in some of the answers.PHP5.5 and lower on windows does not support the $wouldblock
parameter according to the docs,
I was able to test this on Windows + PHP5.3 and concluded that the file_is_locked()
from my test still worked in this scenario:
flock()
would still return false just not have the $wouldblock
parameter but it would still be caught in my else
check.
if (isset($_POST['action'])) {
$file = 'file.txt';
$fp = fopen($file, 'r+');
if ($wouldblock = file_is_locked($fp)) {
// wait and then try again;
sleep(5);
$wouldblock = file_is_locked($fp);
}
switch ($_POST['action']) {
case 'write':
if ($wouldblock) {
echo 'already writing';
} else {
flock($fp, LOCK_EX);
fwrite($fp, 'yadayada');
sleep(5);
echo 'done writing';
}
break;
case 'read':
if ($wouldblock) {
echo 'cant read, already writing';
} else {
echo fread($fp, filesize($file));
}
break;
}
fclose($fp);
die();
}
function file_is_locked( $fp ) {
if (!flock($fp, LOCK_EX|LOCK_NB, $wouldblock)) {
if ($wouldblock) {
return 'locked'; // file is locked
} else {
return 'no idea'; // can't lock for whatever reason (for example being locked in Windows + PHP5.3)
}
} else {
return false;
}
}