Reputation: 2004
I have created a simple databaseless CMS. When saving a file, the PHP opens the corresponding file, adds the new data, and closes the file (using file_put_contents).
This all works well - until the same file is saved twice (or more) simultaneously. By which I mean when a file_put_contents function is started on a file that is already experiencing another file_put_contents function. In this case, only the changes for the second file_put_contents are saved to the file.
So my question is - is there a way of checking if a file is already being written to, and waiting until it has finished being written to, before starting the second file_put_contents?
Upvotes: 1
Views: 1072
Reputation: 16253
Yes, LOCK_EX
support was added to file_put_contents
in PHP 5.1 which will wait until any other lock on the file is released before writing to it. You can easily test this yourself.
#!/usr/bin/env php
<?php
$h = fopen(__DIR__ . DIRECTORY_SEPARATOR . "lock.txt", "c");
register_shutdown_function(function () use ($h) {
fclose($h);
});
flock($h, LOCK_EX);
while (true);
#!/usr/bin/env php
<?php
$f = __DIR__ . DIRECTORY_SEPARATOR . "lock.txt";
file_put_contents($f, "foo", LOCK_EX);
echo file_get_contents($f) , PHP_EOL;
Put both scripts in the same directory and open two shells. Execute lock.php
in shell one and keep it open, execute put.php
in shell two and you'll see that it is waiting, because an exclusive write lock was acquired by the other script for the file. Now go back to shell one and hit Ctrl + c to abort execution (you may close the shell) and go back to your second shell. It should output foo
and the script should terminate.
Reading of the file is not locked for this file, if this is a requirement use flock
since it supports all operations (LOCK_SH | LOCK_EX
).
PDO SQLite would give you the ability to work with simple text files as your database and take care of problems like locking for you. If you need to work with a lot of files and data consider using it as it features everything you need out of the box.
Upvotes: 1