Because:
1) flock() is not safe if multiple php sessions are simultaneously locking.
2) fopen( , 'a') is not safe if multiple php sessions are simultaneously appending.
3) usleep and sleep are known for having problems.
I wrote the Weblog function, it's purpose is to append a line to logging. This function handles the concurrency as follows:
- Try to create a lockfile named: $directory . date('Ymd') . $logfile . 1 . lock
- If this fails, try to create lockfile named: $directory . date('Ymd') . $logfile . 2 . lock
- etc. After 100 tries return false.
- When the lockfile is acquired the file named: $directory.date('Ymd').$logfile.1 (or .2 or .3 or .25) is opened or created.
- If created the a "extended log file" header is written.
- Write out the line.
- Close the flie and if created set the correct access rights. (I had some problems creating files on a webserver, I did not see them when I opened a FTP session to the webdirectory. The chmod did the trick for me).
- Remove the lockfile.
There is only one drawback, multiple logfiles are created.
e.g. (executed on 15 september 2010)
Weblog('./' , 'visit', 'Somebody requested the index page');
Could lead to 100 files, depending how many concurrent php sessions are simultaneously trying to append a logline:
./20100915visit.1
./20100915visit.2
./20100915visit.3
./20100915visit.4
...
./20100915visit.100
This function is donated to the public domain. Maybe you can give me some credit by leaving in the author comment, but it is not required. You may modify this as you wish.
(This function was inspired by the function m_lock_file presented by Kuzma dot Deretuke at gmail dot com)
<?php
function Weblog($directory, $logfile, $message)
{
$curtime = time();
$logfile = date('Ymd',$curtime) . $logfile;
if (!isset($directory) || $directory === false)
$directory = './';
if (substr($directory,-1) !== '/')
$directory = $directory . '/';
$count = 1;
while(1)
{
$logfilename = $directory . $logfile . '.' . $count;
$lockfile = $logfilename . '.lock';
$lockhandle = false;
if (!file_exists($lockfile) || @unlink($lockfile))
$lockhandle = @fopen($lockfile, 'xb');
if ($lockhandle !== false) break;
$count++;
if ($count > 100) return false;
}
if (file_exists($logfilename))
{
$created = false;
$loghandle = @fopen($logfilename, 'ab');
}
else
{
$loghandle = @fopen($logfilename, 'xb');
if ($loghandle !== false)
{
$created = true;
$str = '#version: 1.0' . "\r\n" .
'#Fields: date time c-ip x-msg' . "\r\n";
fwrite($loghandle,$str);
}
}
if ($loghandle !== false)
{
$str = date('Y-m-d',$curtime) . "\t" .
date('H:i:s', $curtime) . "\t" .
(isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '-') . "\t" .
'"' . str_replace('"', '""', $message) . '"' . "\r\n";
fwrite($loghandle,$str);
fclose($loghandle);
if ($created) chmod($logfilename,0644); $result = true;
}
else
{
$result = false;
}
fclose($lockhandle);
@unlink($lockfile);
return $result;
}
?>