Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

php

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

append($file, $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?

like image 369
Jaka Jančar Avatar asked Feb 01 '12 13:02

Jaka Jančar


2 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).

like image 155
FtDRbwLXw6 Avatar answered Nov 09 '22 08:11

FtDRbwLXw6


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)

like image 23
catalint Avatar answered Nov 09 '22 09:11

catalint