I'm using a very simple script where some users data are stored in a text file beside a database because this file needs to be read by a specific process on the system .
The php expire date update code for a line in the following format like this :
U: w w { enddate=2022-10-18 }
The function code goes like this:
$date = "enddate=";
$date .= setExpireDate($duration);
$Read = file($fileDir);
foreach ($Read as $LineNum => $line) {
$LineParts = explode(' ', $line);
if (count($LineParts) == 1) {continue;}
if ($LineParts[1] == $username) {
$LineParts[4] = $date;
$Read[$LineNum] = implode(' ', $LineParts);
break;
}
}
file_put_contents($fileDir, $Read, LOCK_EX);
some users have reported problems , after doing some search i found that the data in the database is updated fine , but the not in the text file as the data is not updated for some users .
as i think it is a file locking problem , that prevents some users under heavy load to write on the file , but the database can handle multiple writes just fine .
So is there anyway to handle the multiple writes on the file at the same time better than this ?
and is there a way to simulate this in php like locking the file by a form submit ?
i tried this :
function lock(){
$fp = fopen("file.txt", "r ");
flock($fp, LOCK_EX);
echo "file is locked <br>";
}
but it is not working at all ,and others can write to the file .
P.S: I know there are a lot of questions about file locking ,but non of the answers did help !
Regards
CodePudding user response:
Here is an example of the file locking approach
First you attempt to lock the Lock file, if you can all well and good proceed to edit the real file. If you cannot get a lock you retry until you can.
// this is not the file you are attempting to update, its just the lock file
// it must already exist and its bext if you place it in a specific directory,
// not accessable from the web.
$fplock = fopen("/some/path/lock.txt", "r ");
// attempt to get an exclusive lock on the lock file
while ( ! flock($fplock, LOCK_EX) ) {
// this has failed to get the lock so do nothing but retry,
// it should be only milli seconds until the other process finishes
// and releases the lock
}
// the lock must have been released by the other process when you get here
// or you got a lock on your first attempt and never ran the wait loop
// at this point this script has the lock
$date = "enddate=";
$date .= setExpireDate($duration);
$Read = file($fileDir);
foreach ($Read as $LineNum => $line) {
$LineParts = explode(' ', $line);
if (count($LineParts) == 1) {continue;}
if ($LineParts[1] == $username) {
$LineParts[4] = $date;
$Read[$LineNum] = implode(' ', $LineParts);
break;
}
}
file_put_contents($fileDir, $Read, LOCK_EX);
/*
closing the lock file has the effect of releasing the lock, or simply finishing this
script will do the same, but do it yourself as soon as you have finished updating the
real file, so other process's dont have to wait until the script finishes,
I assume you may have other code after this
*/
fclose($fplock);
Of course ALL scripts that access the Real File, must also attempt to lock the lock file before accessing the real file, or this all falls down in a mess.