Home » Php » php – Atomically appending a line to a file and creating it if it doesn't exist

php – Atomically appending a line to a file and creating it if it doesn't exist

Posted by: admin April 23, 2020 Leave a comment

Questions:

I’m trying to create a function (for purposes of logging)

append($path, $data)

that

  1. creates $file if it doesn’t exist and
  2. atomically appends $data to it.

It has to

  • support high concurrency,
  • support long strings and
  • be as performant as possible.

So far the best attempt is:

function append($file, $data)
{
    // Ensure $file exists. Just opening it with 'w' or 'a' might cause
    // 1 process to clobber another's.
    $fp = @fopen($file, 'x');
    if ($fp)
        fclose($fp);

    // Append
    $lock = strlen($data) > 4096; // assume PIPE_BUF is 4096 (Linux)

    $fp = fopen($file, 'a');
    if ($lock && !flock($fp, LOCK_EX))
        throw new Exception('Cannot lock file: '.$file);
    fwrite($fp, $data);
    if ($lock)
        flock($fp, LOCK_UN);
    fclose($fp);
}

It works OK, but it seems to be a quite complex. Is there a cleaner (built-in?) way to do it?

How to&Answers:

PHP already has a built-in function to do this, file_put_contents(). The syntax is:

file_put_contents($filename, $data, FILE_APPEND);

Note that file_put_contents() will create the file if it does not already exist (as long as you have file system permissions to do so).

Answer:

using PHP’s internal function http://php.net/manual/en/function.file-put-contents.php

file_put_contents($file, $data, FILE_APPEND | LOCK_EX);

FILE_APPEND => flag to append the content to the end of the file

LOCK_EX => flag to prevent anyone else writing to the file at the same time (Available since PHP 5.1)