Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fopen(file,w+) truncates the file before I can check if it's locked with flock()

Tags:

php

fopen

flock

I have a function which receives a filename and a json object to write to a text file.

The object is updated and needs to entirely replace the current contents of the file. Each site visitor has their own file. Multiple rapid changes create a situation where the file is truncated by fopen(file,w+), then not written to as it's locked. End result is empty file.

I'm sure there's a standard simply way to do this as it's such a usual activity. Ideally what I'm looking for is a way to check if a file has a lock before truncating the file with fopen in w+ mode or a way to switch modes.

It seems strange that you would have to truncate the file with fopen() to get a file handle to pass to flock() to check if it's locked -- but you just truncated it, so what's the point?

Here's the function I have so far:

function updateFile($filename, $jsonFileData) {
    $fp = fopen($filename,"w+");
    if (flock($fp, LOCK_EX)) {  
        fwrite($fp, $jsonFileData);
        flock($fp, LOCK_UN);
        fclose($fp);
        return true;
    } else {
        fclose($fp);
        return false;
    }
}
like image 858
Peter Oram Avatar asked Dec 27 '22 15:12

Peter Oram


1 Answers

Example #1 from the PHP manual will do what you want with a slight modification. Use the "c" mode to open the file for writing, create it if it doesn't exist, and don't truncate it.

$fp = fopen("/tmp/lock.txt", "c");

if (flock($fp, LOCK_EX)) {  // acquire an exclusive lock
    ftruncate($fp, 0);      // truncate file
    fwrite($fp, "Write something here\n");
    fflush($fp);            // flush output before releasing the lock
    flock($fp, LOCK_UN);    // release the lock
} else {
    echo "Couldn't get the lock!";
}

fclose($fp);

Full description of the "c" mode:

Open the file for writing. If the file does not exist, it is created. If it exists, it is neither truncated (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer is positioned on the beginning of the file. This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file, as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can be used after the lock is requested).

It doesn't look like you need it, but there's also a corresponding "c+" mode if you want to both read and write.

like image 129
John Kugelman Avatar answered Dec 29 '22 05:12

John Kugelman