Skip to main content

Here's a handy class to allow retrying a write with flock a set number of times. If it can't flock, it will sleep for a brief random interval and try again. If you have a lot of concurrent writes going on, you can use it to avoid data corruption.

<?php

/**
 * Here's a handy class to allow retrying a write with flock a set
 * number of times. If it can't flock, it will sleep for a brief random interval
 * and try again. If you have a lot of concurrent writes going on, you can use
 * it to avoid data corruption.
 *
 * @link http://php.net/manual/en/function.flock.php#84824
 */
class SafeWriter
{

	/**
	 * Write Data
	 *
	 * @param string $path File path.
	 * @param string $data The data to write.
	 * @param string $mode Suggested mode 'a' for writing to the end of the
	 *        file.
	 * @return boolean
	 */
	public static function writeData($path, $data, $mode = 'a')
	{
		$fp = fopen($path, $mode);
		$retries = 0;
		$max_retries = 100;

		if (! $fp)
		{
			// failure
			return false;
		}

		// keep trying to get a lock as long as possible
		do
		{
			if ($retries > 0)
			{
				usleep(rand(1, 10000));
			}
			$retries += 1;
		}
		while (! flock($fp, LOCK_EX) and $retries <= $max_retries);

		// couldn't get the lock, give up
		if ($retries == $max_retries)
		{
			// failure
			return false;
		}

		// got the lock, write the data
		fwrite($fp, "$data" . PHP_EOL);

		// release the lock
		flock($fp, LOCK_UN);
		fclose($fp);

		// success
		return true;
	}

}

//
// example usage
//

SafeWriter::writeData('temp.txt', 'hello');

?>