Search code examples
phpblockfile-locking

Lock files in PHP without using flock


When a user upload a file(users can upload multiple files)

exec('nohup php /main/apache2/work/upload/run.php &');

I am using nohup as the it needs to be executed in the back end.

In my original design run.php scans the directory using scandir everytime it's executed. Get an exclusive lock LOCK_EX on the file using flock and use LOCK_NB to skip the file if it has a lock and go the next one. If a file has a lock //Do logic. The problem is that the server is missing fcntl() library and since flock uses that library to execute the locking mechanism, flock won't work at the moment. It's going to take a month or two to get that installed(I have no control over that).

So my work around for that is have a temporary file lock.txt that acts a lock. If the filename exists in lock.txt skip the file and go to the next one.

$dir = "/main/apache2/work/upload/files/";
$files = scandir($dir);
$fileName = "lock.txt";

for($i=0; $i<count($files); $i++) 
{   
    if(substr(strrchr($files[$i],'.csv'),-4) == '.csv')
    {           
        if($file_handle = fopen("$fileName", "rb"))
        {
            while(!feof($file_handle))
            {
                $line = fgets($file_handle);
                $line = rtrim($line);
                if($line == "")
                {
                    break;
                }
                else
                {
                    if($files[$i] == $line)
                    {
                        echo "Reading from lock: ".$line."</br>";
                        $i++; //Go to next file
                    }
                }

            }
            fclose($file_handle);
        }

        if($i >= count($files))
        {
            die("$i End of file");
        }

        if($file_handle = fopen("$fileName", "a+"))
        {
            if(is_writable($fileName))
            {               
                $write = fputs($file_handle, "$files[$i]"."\n");
                //Do logic

                //Delete the file name - Stuck here

                fclose($file_handle);
            }

        }

    }
    else
    {
        //Do nothing
    }
}

How can I delete the filename from lock.txt?

More importantly, is there a better way to lock a file in php without using flock?


Solution

  • Having a shared lock database simply moves the locking problem to that file; it doesn't solve it.

    A much better solution is to use one lock file per real file. If you want to lock access to myFile.csv then you check file_exists('myFile.csv.lock') and touch('myFile.csv.lock') if it doesn't exist. And unlink('myFile.csv.lock') when done.

    Now, there is a possible race-condition between file_exists() and touch(), which can be mitigated by storing the PID in the file and checking if getmypid() is indeed the process holding the lock.