23

I have two different PHP files that both write to the same file. Each PHP script is called by a user action of two different HTML pages. I know it will be possible for the two PHP files to be called, but will both PHP files attempt to write to the file at the same time? If yes, what will happen? Also, it is possible to make one of the PHP fail gracefully (file write will just fail, and the other PHP can write to the file) as one PHP function is less important that the other.

Amandeep Grewal
  • 1,801
  • 3
  • 19
  • 30

5 Answers5

35

The usual way of addressing this is to have both scripts use flock() for locking:

$f = fopen('some_file', 'a');
flock($f, LOCK_EX);
fwrite($f, "some_line\n");
flock($f, LOCK_UN);
fclose($f);

This will cause the scripts to wait for each other to get done with the file before writing to it. If you like, the "less important" script can do:

$f = fopen('some_file', 'a');
if(flock($f, LOCK_EX | LOCK_NB)) {
    fwrite($f, "some_line\n");
    flock($f, LOCK_UN);
}
fclose($f);

so that it will just not do anything if it finds that something is busy with the file.

chaos
  • 122,029
  • 33
  • 303
  • 309
  • Exactly what I was looking for! That was so easy, I should have checked the PHP documentation more. – Amandeep Grewal Jul 30 '09 at 22:30
  • Take care using flock() since the function isn't atomic. – arul Jul 30 '09 at 22:42
  • Another tip to prevent file contents from becoming empty on two exactly simultaneous writes. That happened to me a lot with one popular page with a flatfile visitor counter. The solution: I added a random delay of 20-80 ms before fwrite(), and that fixed the problem, even to date with much higher visitor counts. – Juha Untinen Jan 30 '13 at 20:18
12

Please note posix states atomic access if files are opened as append. This means you can just append to the file with several threads and they lines will not get corrupted.

I did test this with a dozen threads and few hundred thousand lines. None of the lines were corrupted.

This might not work with strings over 1kB as buffersize might exceed.

This might also not work on windows which is not posix compliant.

Antti Rytsölä
  • 1,485
  • 14
  • 24
10

Please note:

As of PHP 5.3.2, the automatic unlocking when the file's resource handle is closed was removed. Unlocking now always has to be done manually.

The updated backward compatible code is:

if (($fp = fopen('locked_file', 'ab')) !== FALSE) {
    if (flock($fp, LOCK_EX) === TRUE) {
        fwrite($fp, "Write something here\n");
        flock($fp, LOCK_UN);
    }

    fclose($fp);
}

i.e. you have to call flock(.., LOCK_UN) explicitly because fclose() does not do it anymore.

Marcello Nuccio
  • 3,901
  • 2
  • 28
  • 28
1

Take a look at the flock function.

cdmckay
  • 31,832
  • 25
  • 83
  • 114
-4

FYI: flock only works on *nix and is not available on Windows

xentek
  • 2,555
  • 2
  • 20
  • 12
  • 2
    From the PHP documentation: "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)." – cdmckay Jul 31 '09 at 00:45
  • 1
    While `flock` as a system call is not implemented on Windows, this is abstracted away in the `flock` PHP function. – Piskvor left the building Dec 15 '10 at 17:25
  • 1
    yeah, I mis-spoke. This is the bug I was thinking of when I said that wasn't available on Windows: http://bugs.php.net/bug.php?id=39138 (the time I needed it on a windows local dev server, I ran into this and have avoided it on Windows machines ever since). Keep calm and carry on. – xentek Jan 09 '11 at 05:08