Paolo
Paolo

Reputation: 15847

file_put_contents appending data on a file being written by another process

I have

$bytesCount = file_put_contents( "somefile.log", "some text\n", FILE_APPEND | LOCK_EX );

What happens if another process is writing** on somefile.log?

Does file_put_contents fails with a runtime error ?

Does if fails with $bytesCount === false

Or does does it pause the script until the file is unlocked and then performs the write operation?


(**) or more generally another process has an exclusive lock on the file


[ I'm on a *nix platform with php 5.6 ]

Upvotes: 0

Views: 18175

Answers (2)

Paolo
Paolo

Reputation: 15847

When file_put_contents attempts to write on a locked file waits until the file is unlocked then performs the write and returns the number of bytes written.


Proof:

I wrote a simple two-scripts test:

the first script writes a 100MB file (on a slow USB2-connected drive);

the second script appends a short string to the same file.

The core of the two scripts are these four lines:

echo Milliseconds() . ": Start writing file on file\n";
$bytesCount = file_put_contents( "/Volumes/myHD/somefile.txt", $buffer, FILE_APPEND | LOCK_EX );
var_export( $bytesCount );
echo "\n" . Milliseconds() . ": Done writing on file\n";

Where Milliseconds() is a function that returns the current unix timestamp in milliseconds.

In the first script $buffer is a 100MB string, in the second script $buffer = "MORE-DATA\n";

Running the first script and quickly starting the second one result in this output:

Script 1:

$ php test1.php
1481892766645: Start writing file on file
100000000
1481892769680: Done writing on file
$

Script 2:

$ php test2.php
1481892766831: Start writing file on locked file
10
1481892769909: Done writing file on locked file
$

Note that:

  • the second script attempted writing 186 ms after the first one but before the second script was done writing. So the second script actually accessed a locked file.

  • the second script termiated writing 229 ms after the first one

Checking the result after both scripts terminated execution:

$ stat -f%z /Volumes/myHD/somefile.txt 
100000010
$

10MB + 10 bytes were written

$ tail -c 20 /Volumes/myHD/somefile.txt
0123456789MORE-DATA 
$

The second script actually appended the string at the end of the file

Upvotes: 2

fizzi
fizzi

Reputation: 116

It should be obvious that this should only be used if you're making one write, if you are writing multiple times to the same file you should handle it yourself with fopen and fwrite, the fclose when you are done writing.

Benchmark below:

file_put_contents() for 1,000,000 writes - average of 3 benchmarks:

real 0m3.932s user 0m2.487s sys 0m1.437s

fopen() fwrite() for 1,000,000 writes, fclose() - average of 3 benchmarks:

real 0m2.265s user 0m1.819s sys 0m0.445s

For overwriting when using ftp, this is helpful:

/* create a stream context telling PHP to overwrite the file */ 
$options = array('ftp' => array('overwrite' => true)); 
$stream = stream_context_create($options);

http://php.net/manual/en/function.file-put-contents.php

Upvotes: 0

Related Questions