File Locking in PHP using Flock
A nice feature MySQL is the automatic locking. If you write 100 records in a single operation and another program is trying to read at the same time, the table will lock and the read will be placed on hold until all 100 records are written. You don’t have to worry about errors or failures (unless the write is taking too long). If you try to do the same thing with files, you may end up with a situation where the read will return false if it is in the middle of a write operation.
If you correctly use file locking, you can mimic the behavior of a database. Let’s see the wrong and correct ways to interact with files in PHP.
Unsafe File Locking
This is problematic because if Program 1 has a lock on the file, then Program 2 will set $contents as false during the read. Again, this must happen at the exact same time, but if you are constantly reading and writing, there is a good possibility the read or another write will fail.
// Program 1
file_put_contents($file, 'This is a test.', LOCK_EX);
// Program 2
$contents = file_get_contents($file);
Safe File Locking using Flock
A best practice when writing and reading files is to use the flock() function in PHP. Flock works on multiple platforms as long as you use it in a while loop. I’ve found on Windows, the loop is required while on Linux, a loop is not required. One thing to note is when writing to a file, don’t use fopen($file, ‘w’) because file locking occurs after the truncate so it will automatically clear out the contents of the file before it has a lock.
// Program 1
$handle = fopen($file, 'r+');
while (!flock($handle, LOCK_EX)) { usleep(1); }
ftruncate($handle, 0);
fwrite($handle, 'This is a test.');
fflush($handle);
flock($handle, LOCK_UN);
fclose($handle);
// Program 2
$handle = fopen($file, 'r');
while (!flock($handle, LOCK_SH)) { usleep(1); }
$contents = fread($handle, filesize($file));
flock($handle, LOCK_UN);
fclose($handle);
Of course, it’s always a good idea to use buffers when reading and writing to files to control the memory usage, but that is outside the scope of this tutorial.