<?
$_SERVER['HTTP_USER_AGENT'] = "googlebot 2.1 (Mozilla)";
$system = array(
'temp_folder' => '_bots_temp/',
'bots_folder' => '_bots_by_names/',
'bots_folder1' => '_bots_by_hosts/',
'notbot_browsers' => 'msie;netscape;opera;firefox;gecko;windows;microso ft;konqueror;lynx;libwww;win98',
'bots_min_visits_to_log'=> 1,
'log_bot_visits' => 1,
'domain' => 'your_domain.com',
);
if(rand(1, 100 < 80)){
bots_log();
}else{
bots_log(404);
}
function bots_log($response_code = 200){
global $system, $_SERVER;
if($system['log_bot_visits'] && $_SERVER['HTTP_USER_AGENT']){
$bot_name = '';
$found = false;
$bots = explode(';', $system['notbot_browsers']);
$ua = strtolower($_SERVER['HTTP_USER_AGENT']);
for($i = 0; $i < count($bots); $i++){
if(strpos(' ' . $ua, $bots[$i]) > 0){
$found = true;
break;
}
}
if(!$found){
file_exists($system['temp_folder']) ? 'nil' : mkdir($system['temp_folder']);
$today_dir1 = $system['bots_folder'] . date("d.m.y", mktime());
$today_dir2 = $system['bots_folder1'] . date("d.m.y", mktime());
$bot_name = trim(preg_replace("!http:\/\/.+[\s)$]!si", "", $ua));
$bot_name = preg_replace("!mozilla.*compatible!si", "", $bot_name);
$bot_name = preg_replace("![^\w\d]+!si", " ", $bot_name);
$bot_name = preg_replace("/(\d+)\s+(\d+)/", "$1.$2", $bot_name);
$log_visit = false;
if(file_exists($system['temp_folder'] . 'real_' . $bot_name)){
$log_visit = true;
}else{
if(file_exists($system['temp_folder'] . $bot_name) && $test_lines = file($system['temp_folder'] . $bot_name)){
if(count($test_lines) >= $system['bots_min_visits_to_log']){
file_exists($system['bots_folder']) ? 'nil' : mkdir($system['bots_folder']);
file_exists($system['bots_folder1']) ? 'nil' : mkdir($system['bots_folder1']);
file_exists($system['bots_folder'] . date("d.m.y", mktime())) ? 'nil' : mkdir($today_dir1);
file_exists($system['bots_folder1'] . date("d.m.y", mktime())) ? 'nil' : mkdir($today_dir2);
copy($system['temp_folder'] . $bot_name, $today_dir1 . '/' . $bot_name);
text_log('', $system['temp_folder'] . 'real_' . $bot_name);
unlink($system['temp_folder'] . $bot_name);
$log_visit = true;
}else{
text_log('[' . $_SERVER['REMOTE_ADDR'] . ' r: ' . trim($_SERVER['HTTP_REFERER']) . "] $response_code: " . $system['domain'] . $_SERVER['REQUEST_URI'], $system['temp_folder'] . $bot_name);
}
}else{
text_log('[' . $_SERVER['REMOTE_ADDR'] . ' r: ' . trim($_SERVER['HTTP_REFERER']) . "] $response_code: " . $system['domain'] . $_SERVER['REQUEST_URI'], $system['temp_folder'] . $bot_name);
}
}
if($log_visit){
text_log('[' . $_SERVER['REMOTE_ADDR'] . ' r: ' . trim($_SERVER['HTTP_REFERER']) . "] $response_code: " . $system['domain'] . $_SERVER['REQUEST_URI'], $today_dir1 . '/' . $bot_name);
text_log('[' . $_SERVER['REMOTE_ADDR'] . ' r: ' . trim($_SERVER['HTTP_REFERER']) . "] $response_code: " . $system['domain'] . $_SERVER['REQUEST_URI'], $today_dir2 . '/' . $system['domain'] . "-$bot_name"

;
}
}
}
}
function text_log($log_string, $filename = '_main_log'){
$file = fopen($filename, "a"

;
fwrite ($file, date("d.m.y H:i:s ", mktime()) . ": " . $log_string . "\n"

;
fflush($file);
while(!fclose($file)){
usleep(10);
if(!$file){
break;
}
}
echo"log to $filename: $log_string<br>";
}
?>
складывает всех ботов по папкам и соотв датам в 2-х вариантах отчетов
1. каждый бот за сутки все хосты
2. каждый хост за суски всеми ботами (если нужно вести логи для нескольких доменов одновременно)
фильтрует мусорных ботов с рандомными именами (см параметр bots_min_visits_to_log). Бот должен зайти как минимум bots_min_visits_to_log на любой адрес на сервере, чтобы писать о нем в чистые логи. Под юниху придется добавить обработку разрешений на папки. Кому надо - дописывайте.
Думаю многим пригодится. Настроение хорошее, решил выложить.