9

Let's consider a sample php script which deletes a line by user input:

$DELETE_LINE = $_GET['line'];
$out = array();
$data = @file("foo.txt");
if($data)
{
    foreach($data as $line)
        if(trim($line) != $DELETE_LINE)
            $out[] = $line;
}
$fp = fopen("foo.txt", "w+");
flock($fp, LOCK_EX);
foreach($out as $line)
    fwrite($fp, $line);
flock($fp, LOCK_UN);
fclose($fp); 

I want to know if some user is currently executing this script and file "foo.txt" is locked, in same time or before completion of its execution, if some other user calls this script, then what will happen? Will second users process wait for unlocking of file by first users? or line deletion by second users input will fail?

YakovL
  • 7,557
  • 12
  • 62
  • 102
Dr. DS
  • 984
  • 1
  • 13
  • 31

1 Answers1

25

If you try to acquire an exclusive lock while another process has the file locked, your attempt will wait until the file is unlocked. This is the whole point of locking.

See the Linux documentation of flock(), which describes how it works in general across operating systems. PHP uses fcntl() under the hood so NFS shares are generally supported.

There's no timeout. If you want to implement a timeout yourself, you can do something like this:

$count = 0;
$timeout_secs = 10; //number of seconds of timeout
$got_lock = true;
while (!flock($fp, LOCK_EX | LOCK_NB, $wouldblock)) {
    if ($wouldblock && $count++ < $timeout_secs) {
        sleep(1);
    } else {
        $got_lock = false;
        break;
    }
}
if ($got_lock) {
    // Do stuff with file
}
Mimouni
  • 3,564
  • 3
  • 28
  • 37
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • 1
    So it means, another process will wait while previous process unlocks the file. I want to know for how long another process will wait for unlocking of file? is there any timeout ? – Dr. DS Sep 16 '13 at 17:15
  • 1
    There's no timeout. I added code to implement a timeout using the non-blocking option. – Barmar Sep 16 '13 at 17:24
  • 1
    Take note that `LOCK_NB` and the `$wouldblock` argument are not supported on Windows, according to the PHP documentation: http://ca1.php.net/manual/en/function.flock.php If you can't control which servers are going to be running your software, then you also can't realistically use the above code. In such cases, it seems to me that there is simply _no way_ to achieve a "lock timeout" of any kind. – JMTyler Mar 05 '14 at 11:49
  • Try this alternative if you use windows: http://stackoverflow.com/a/7927642/318765 I'm not able to test it, but it works in linux better than `flock()` – mgutt Sep 08 '14 at 14:33
  • @Barmar instead of polling and wasting precious seconds by sleeping you can implement timeout by setting up an alarm with `pcntl_alarm`, which will interrupt `flock` system call. I'm not sure how well it works on Windows. – AnyDev Oct 23 '14 at 04:26
  • 4
    Bear in mind when using this technique, that different processes requesting the lock won't be in a strict queue. Each time the process enters the `sleep()` stage, it jumps out of the queue and goes back to the end of the queue after it has sleeped. That may be fine for your application, but it just means there is no guarantee about how long each process has to wait and what order they will run in. – Jason Nov 19 '15 at 10:37
  • 1
    It should be noted that the process will terminate if the max script execution time is exceeded while waiting for the lock. That's the most definitive timeout that comes out of the box. – Luke A. Leber Dec 19 '16 at 15:13
  • Is it correct that `flock` does not effect `max-execution-time`? So in theory, a badly written code which locks a file twice without unlocking would just load forever? – Adam Dec 15 '17 at 10:27
  • @Adam I haven't tried, but I doubt that it overrides `max-execution-time`. The point I was making in my answer that `flock()` itself has no timeout. Of course, anything that stops the script will cancel the lock request. – Barmar Dec 15 '17 at 16:34
  • I'm puzzled. In [this answer](https://stackoverflow.com/a/5663294/3995261) Nemoden shows code which seemingly works without a loop and `sleep`ing. What am I missing? Do the 2 answers address cases different in some way? I need to implement a script which may read/write a file in a concurrent manner but don't understand what's the "correct" implementation – YakovL Jan 04 '19 at 21:34
  • @YakovL The answer there doesn't have a timeout, it will wait forever for the lock. The `sleep()` is just to hold the lock for a period of time, so you can see the difference in the times between the two processes getting the lock. – Barmar Jan 04 '19 at 22:16
  • 1
    @YakovL This answer uses the `LOCK_NB` flag, which prevents it from waiting for the lock. Then it keeps trying until it times out, and sets a variable to indicate whether it got the lock or timed out. – Barmar Jan 04 '19 at 22:18
  • @Barmar: What's the point of using no blocking option with combination of the while loop? Is this just for illustration how to skip waiting? So I don't need to use any while loops when i want the second script to wait till the first script finishes its write operation? I.e there are two waiting solution one is no loop&LOC_EX and the second solution is loop&LOC_NB – John Boe Oct 08 '19 at 13:02
  • 1
    @JohnBoe Yes, this is how to implement a timeout, since there's no built-in way to do that. – Barmar Oct 08 '19 at 15:08