Reputation: 144
I have a problem with a counter. I need to count two variables, separated with a |, but sometimes the counter doesn't increase a variable's value.
numeri.txt (the counter):
5240|593389
This is the PHP script:
$filename="numeri.txt";
$fp=fopen($filename,"r");
if(!flock($fp,LOCK_SH))
{
while(true)
{
usleep(100000);
if(flock($fp,LOCK_SH))
{
break;
}
}
}
$contents=fread($fp,filesize($filename));
flock($fp,LOCK_UN);
fclose($fp);
$fp=fopen($filename,'a');
if(!flock($fp,LOCK_EX))
{
while(true)
{
usleep(100000);
if(flock($fp,LOCK_EX))
{
break;
}
}
}
ftruncate($fp,0);
$contents=explode("|",$contents);
$clicks=$contents[0];
$impressions=$contents[1]+1;
fwrite($fp,$clicks."|".$impressions);
flock($fp,LOCK_UN);
fclose($fp);
I set the counter to the right value but after 3-4 days the counter hasn't counted about 50 impressions (the number after "|")
How to fix the code?
Upvotes: 2
Views: 312
Reputation: 17710
Two problems:
1) There is still the opportunity to do a read, another process to write the file, then this process write the file. Millisecond timing required, but it's possible.
2) You don't actually verify the "open" works - it can fail.
The solution is to firstly check for open failure and retry, and secondly do one lock - exclusive. Paraphrased code:
while (!$fh = fopen($file, 'c+')) { // Read write, do not truncate, place pointer at start.
usleep(100000);
}
while (!flock(LOCK_EX)) {
usleep(100000);
}
$content = fread();
// Process content...
ftruncate();
fseek(0); // Or frewind();
fwrite();
fclose(); // Also releases the lock.
Upvotes: 3