安全的PHP JSON日志记录

I am using JSON as a data store and over time I foresee that several parties might be wanting to write to my JSON file like a chat log within a short space of time.

<?php
$foo = json_decode(file_get_contents("foo.json"), true);
if (! is_array($foo["bar"])) { $foo["bar"] = array(); }
array_push($foo["bar"], array("time" => time(), "who" => $_SERVER['REMOTE_ADDR'], msg => $_GET['m']));
file_put_contents("foo.json", json_encode($foo, JSON_PRETTY_PRINT));
?>

So the above code works, but I am worried what happens if the file is read before it's written out, or some case where they are writing out at the same time, leading to some data loss?

What's a better or safer design, preferably using flat file storage (i.e. not databases)?

As for a bonus I really don't want to return to my client who made the request this that were was some "lock". Ideally the request is made to wait until it's safe to return.

You can use the flock() function for this. What it does is it locks the file for all processes except the current one.

http://php.net/manual/en/function.flock.php

Basic usage:

<?php

$fp = fopen('path/to/data.json', 'r+');

if (flock($fp, LOCK_EX)) // locks the file
{
    // write to the file

    flock($fp, LOCK_UN); // remove the lock
}

fclose($fp);

flock() is blocking by default. That means a process is waiting until it gets permission to access the lock. Have a look at the docs on how to implement a nonblocking version.

How a bout you create individual JSON for each line so you do not need load Json every time. and you just append JSON to the file. Each Joson will be in One line.

When you load it you will read each line in text file then convert it to Json within PHP.

The reason I recommend this way as we want to find other way to have better solution for file read and write using //http://php.net/manual/en/function.file-put-contents.php file_put_contents("foo.json", json_encode($foo, JSON_PRETTY_PRINT). JSON is just a format for text. So I believe that It is a good solution to do.

To write

<?php
$_SERVER['REMOTE_ADDR'], msg => $_GET['m']));

$foo =  array("time" => time(), "who" => $_SERVER['REMOTE_ADDR'], msg => $_GET['m']);
//http://php.net/manual/en/function.file-put-contents.php
file_put_contents("foo.json", json_encode($foo, JSON_PRETTY_PRINT), FILE_APPEND | LOCK_EX));
?>

As you mention it is a log, so you may not need to load to see it all the time. So we will to focus on writing. It may seem long process to read. TO read

<?php 

$log_array = array();
$handle = @fopen("foo.json", "r");
if ($handle) {
    while (($buffer = fgets($handle, 4096)) !== false) {

        $foo = json_decode($buffer, true);
        $log_array[] = $foo;

    }
    if (!feof($handle)) {
        echo "Error: unexpected fgets() fail
";
    }
    fclose($handle);
}

print_r($log_array);

?>