Php Lock files when writte

338 views Asked by At

I am testing my code using little database in txt files. The most important problem that I have found is: when users write at the same time into one file. To solve this I am using flock. OS of my computer is windows with xampp installed (comment this because i understand flocks works fine over linux no windows) However I need to do this test over linux server.

Actually I have tested my code by loading the same script in 20 windows at the same time. The firsts results works fine, but after test database file appears empty.

My Code :

$file_db=file("test.db");
$fd=fopen("".$db_name."","w");

if (flock($fd, LOCK_EX)) 
    { 
    ftruncate($fd,0); 
    for ($i=0;$i<sizeof($file_db);$i++)
        {
        fputs($fd,"$file_db[$i]"."\n");
        }
    fflush($fd); 
    flock($fd, LOCK_UN);
    fclose($fd);
    }
else
    {
    print "Db Busy";
    }

How it's possible that the script deletes database file content. What is proper way: use flock with fixing of existing code or use some other alternative technique of flock?

2

There are 2 answers

1
khany On

I have re-wrote the script using @lolka_bolka's answer and it works. So in answer to your question, the file $db_name could be empty if the file test.db is empty.

0
sectus On

ftruncate after fopen with "w" is useless.

file function

Returns the file in an array. Each element of the array corresponds to a line in the file, with the newline still attached. Upon failure, file() returns FALSE.

You do not have to add additional end of line symbol.

flock function

PHP supports a portable way of locking complete files in an advisory way (which means all accessing programs have to use the same way of locking or it will not work).

It means that file function not affected by the lock. It means that $file_db=file("test.db"); could read file while other process somewhere between ftruncate($fd,0); and fflush($fd);. So, you need read file content inside lock.

$db_name = "file.db";
$fd = fopen($db_name, "r+"); // w changed to r+ for getting file resource but not truncate it

if (flock($fd, LOCK_EX))
    {
    $file_db = file($db_name); // read file contents while lock obtained
    ftruncate($fd, 0);
    for ($i = 0; $i < sizeof($file_db); $i++)
        {
        fputs($fd, "$file_db[$i]");
        }
    fflush($fd);
    flock($fd, LOCK_UN);
    }
else
    {
    print "Db Busy";
    }
fclose($fd); // fclose should be called anyway

P.S. you could test this script using console

$  for i in {1..20}; do php 'file.php' >> file.log 2>&1 & done