=&=... All parameters are optional. List of the parameters: pass= - password to invoke program in hostmaster's mode domain= - aquire certain virtual domain log file cut_limit= - lower limit to cut log file cut_unit= - what units used to count cutting limit strip_query= - strip off queries in hit statistics rep_ref= - include referrers in statistics ref_domain_only= - show only referrers' domains rep_vis= - include visits in statistics rep_topvis= - how many most active visitors to show rep_brs= - include browser in statistics brs_brief= - show brief names of browsers brs_ver= - show versions in brief names of broswers stat_hits= - what "hits" are: hits to pages (more accurate) or hits to any file (WebTrend's style) cmp_pix= - compress removing pictures and other non-html hits cmp_dup= - compress removing duplications op= - operation to do panel= - show control panel or not batch_mode= - batch mode suppres any output (but errors if any). Useful with cron report_time=
- date of report (other from current) log_dir= - directory where logs are (other from default) log_file= - name of the log file (other from default "virtual-domain.com.log") If you want avoid client to do anything with a log but get statistics only, create page something like: http://www.virtual-domain.com/stat.shtml where you can put line similar to this one: Feel free to use this program at your own risk. No responsibilities taken on damages claimed to be done by this program. Modification of this file is allowed with any one of the following conditions: 1. Changes clearly noted in this introduction or 2. Any referenses from this file to 19colors removed */ ########################################################## # # Correct values in this section according to your configuration # if (!isset($log_dir)) $log_dir='/usr/local/apache/var/log/cust-logs'; //directory where log files are define('_log_file', '*.log'); //filename definition of the log define('_hostmaster_pass','hostmaster'); //hostmaster's password define('_hostmaster_limit','2000K'); //warning limit size of log define('_dir_restriction','.+/cust-logs'); //restriction to dir names for sequrity reasons # # Avoid changes below this line unless you feel confidence # ########################################################## set_time_limit(100); if (!isset($domain)) $domain=''; if (substr($domain,0,4)=='www.') $domain=substr($domain,4); // cut www... if (substr($domain,-1)==')') $domain=substr($domain,0,strpos($domain,' ')); // cut ...(xxxK) if (!isset($op)) $op=''; if (!isset($pass)) $pass=''; if (!isset($rep_ref)) $rep_ref='off'; if (!isset($rep_vis)) $rep_vis='off'; if (!isset($rep_topvis)) $rep_topvis=10; else $rep_topvis=(int)$rep_topvis; if (!isset($rep_brs)) $rep_brs='off'; if (!isset($strip_query)) $strip_query='off'; if (!isset($ref_domain_only)) $ref_domain_only='off'; if (!isset($brs_brief)) $brs_brief='off'; if (!isset($brs_ver)) $brs_ver='off'; if (!isset($stat_hits)) $stat_hits='Pages'; if (!isset($cmp_pix)) $cmp_pix='off'; if (!isset($cmp_dup)) $cmp_dup='off'; if (!isset($cut_limit)) $cut_limit='0'; if (!isset($cut_unit)) $cut_unit='Kb'; if (!isset($panel)) $panel='on'; if (!isset($batch_mode)) $batch_mode='off'; $batch_mode= $batch_mode=='on'; if ($batch_mode) { $panel='off'; } ?> Statistics and Log Operations Looking log in a wrong directory "'.$log_dir.'"'; if ($batch_mode) error_log('logop.php: Looking log in a wrong directory "'.$log_dir.'" at '.$path_log_file,0); } if (!empty($domain) && !file_exists($path_log_file)) { $op=''; $msg='No log found for domain "'.$domain.'"'; if ($batch_mode) error_log('logop.php: No log found for domain "'.$domain.'" at '.$path_log_file,0); } if (empty($domain) && !empty($op)) { $op=''; $msg='Domain not set'; if ($batch_mode) error_log('logop.php: Domain not set',0); } if ($op=='Cut' && $cut_unit=='Kb' && (int)$cut_limit*1024>=filesize($path_log_file)) { $op=''; $msg='Cut limit is over file size'; } $time_now= isset($report_time)?strtotime($report_time):time(); $is_compress= $op=='Compress' && ($cmp_pix=='on'||$cmp_dup=='on'); $is_statistics= $op=='Statistics'; $is_cut= $op=='Cut'; $is_compress_dup= $cmp_dup=='on'; $is_cut_by_size= $cut_unit=='Kb'; $is_cut_by_date= !$is_cut_by_size; $conv_cut_limit= $is_cut_by_size?(int)$cut_limit*1024:_midnight-_24h*(int)$cut_limit; $uniq_hit=false; $prev_line= array('','','','','','','','','','','',''); $got_cut_point=false; define('_ip',0); define('_time',3); define('_gmt',4); define('_meth',5); define('_url',6); define('_prot',7); define('_n1',8); define('_n2',9); define('_ref',10); define('_brs',11); define('_ip_last',0); define('_ip_visits',1); define('_24h', 60*60*24); define('_hostmaster_mode',$pass==_hostmaster_pass); define('_midnight', strtotime(date('d F Y 0:0:0',$time_now))); //last midnight define('_hits', $stat_hits); define('_hits_off', ($stat_hits=='Pages')?'Requests':'Pages'); if ($is_statistics || $is_compress || ($is_cut && $conv_cut_limit>0)) { $time_begin_log=0; if ($is_statistics) { $list_ip= array(); $list_url= array(); $list_brs= array(); $list_ref= array(); $total['Requests']= array(0,0,0,0); $total['Pages']= array(0,0,0,0); $total['Visits']= array(0,0,0,0); $last_week[_midnight-6*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight-5*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight-4*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight-3*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight-2*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight-1*_24h]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); $last_week[_midnight ]= array('Requests'=>0,'Pages'=>0,'Visits'=>0); } ################################################ parse log file $line_no=0; $bytes_left= filesize($path_log_file); $fp = fopen($path_log_file, "r"); if ($is_compress) { $tmp_filename= tempnam('',$domain); $out= fopen($tmp_filename, "w"); } $line= array(_time=>0); while ($fp && !feof($fp)) { $significant_hit=true; $buff= fgets($fp, 1000); if (strlen($buff)<=2) continue; $line= explode(' ',$buff, 12); $line_no++; $line[_brs]= str_replace("\n",'',$line[_brs]); //cut <\n> $line[_brs]= str_replace("\r",'',$line[_brs]); //cut <\r> //---------------- detect non-html files by filename extension // BUG --- queries are not considered if (substr($line[_url],-1)!='/') { $ext= strrchr($line[_url],'.'); if ($ext) $ext= substr($ext,1); else $ext=''; if (stristr(',gif,jpg,bmp,jpeg,exe,zip,,',','.$ext.',')) { $significant_hit=false; if ($is_compress && $cmp_pix=='on') { continue; } } } if ($is_compress) { if ($is_compress_dup) { if ($line[_ip] ==$prev_line[_ip]) $line[_ip]='^'; else $prev_line[_ip] =$line[_ip]; if ($line[_gmt] ==$prev_line[_gmt]) $line[_gmt]='^'; else $prev_line[_gmt] =$line[_gmt]; if ($line[_meth]==$prev_line[_meth]) $line[_meth]='^'; else $prev_line[_meth] =$line[_meth]; if ($line[_url] ==$prev_line[_url]) $line[_url]='^'; else $prev_line[_url] =$line[_url]; if ($line[_prot]==$prev_line[_prot]) $line[_prot]='^'; else $prev_line[_prot] =$line[_prot]; if ($line[_n1] ==$prev_line[_n1]) $line[_n1]='^'; else $prev_line[_n1] =$line[_n1]; if ($line[_n2] ==$prev_line[_n2]) $line[_n2]='^'; else $prev_line[_n2] =$line[_n2]; if ($line[_ref] ==$prev_line[_ref]) $line[_ref]='^'; else $prev_line[_ref] =$line[_ref]; if ($line[_brs] ==$prev_line[_brs]) $line[_brs]='^'; else $prev_line[_brs] =$line[_brs]; if ($line[_time][0]!='^' && substr($line[_time],0,13)==$prev_line[_time]) $line[_time]='^'.substr($line[_time],13); else $prev_line[_time]= substr($line[_time],0,13); $buff= implode(' ',$line)."\n"; } fwrite($out, $buff); continue; } if ($line[_ip][0]=='^') $line[_ip]= $prev_line[_ip]; else $prev_line[_ip] =$line[_ip]; if ($line[_gmt][0]=='^') $line[_gmt]= $prev_line[_gmt]; else $prev_line[_gmt] =$line[_gmt]; if ($line[_meth][0]=='^') $line[_meth]=$prev_line[_meth]; else $prev_line[_meth] =$line[_meth]; if ($line[_url][0]=='^') $line[_url]= $prev_line[_url]; else $prev_line[_url] =$line[_url]; if ($line[_prot][0]=='^') $line[_prot]=$prev_line[_prot]; else $prev_line[_prot] =$line[_prot]; if ($line[_n1][0]=='^') $line[_n1]= $prev_line[_n1]; else $prev_line[_n1] =$line[_n1]; if ($line[_n2][0]=='^') $line[_n2]= $prev_line[_n2]; else $prev_line[_n2] =$line[_n2]; if ($line[_ref][0]=='^') $line[_ref]= $prev_line[_ref]; else $prev_line[_ref] =$line[_ref]; if ($line[_brs][0]=='^') $line[_brs]= $prev_line[_brs]; else $prev_line[_brs] =$line[_brs]; if ($line[_time][0]=='^') $line[_time]=$prev_line[_time].substr($line[_time],1); else $prev_line[_time]= substr($line[_time],0,13); $line_time= log_to_time(substr($line[_time],1)/*cutting first '['*/); if ($is_cut) { if ($is_cut_by_size && $bytes_left<$conv_cut_limit) {$got_cut_point=true; break;} $bytes_left-= strlen($buff); if ($is_cut_by_date && $line_time>$conv_cut_limit) {$got_cut_point=true; break;} } if ($is_statistics) { if ($line_no==1) $time_begin_log=$line_time; ################################################### removing extra characters from data $line[_ref]= substr($line[_ref],1,strlen($line[_ref])-2); //cut <"> if ($strip_query=='on') {$n= strpos($line[_ref],'?'); if (!($n===false)) $line[_ref]=substr($line[_ref],0,$n);} //cut ?... $n= strpos($line[_ref],'#'); if (!($n===false)) $line[_ref]=substr($line[_ref],0,$n); //cut #... $n= strpos($line[_ref],'://'); if (!($n===false)) $line[_ref]=substr($line[_ref],$n+3); //cut http://... if ($ref_domain_only=='on') {$n= strpos($line[_ref],'/'); if (!($n===false)) $line[_ref]=substr($line[_ref],0,$n);} //cut /... $line[_brs]= str_replace('"','',$line[_brs]); //cut <"> if ($strip_query=='on') {$n= strpos($line[_url],'?'); if (!($n===false)) $line[_url]=substr($line[_url],0,$n);} //cut ?... $n= strpos($line[_url],'#'); if (!($n===false)) $line[_url]=substr($line[_url],0,$n); //cut #... ################################################### accumulating data $uniq_hit= add_ip($list_ip,$line[_ip],$line_time); add_hit($list_url,$line[_url],$line_time,1,$uniq_hit,$significant_hit); if ($rep_brs=='on' and $uniq_hit) add_brs($list_brs,$line[_brs],$line_time,$brs_brief=='on',$brs_ver=='on'); if ($rep_ref=='on') add_ref($list_ref,$line[_ref],$line_time); ################################################### } } if (!$is_cut) fclose($fp); } if ($is_compress) { fclose($out); copy($tmp_filename,$path_log_file); unlink($tmp_filename); $msg='Log has been compressed'; } if ($is_statistics) { echo '

'.$domain.'

'; echo '
Generated on '.date('d F Y, H:i',$time_now).'
'; $list_sum=''; report_total('Total',$total); report_week('Last Week Statistics',$last_week); if (count($list_url)<40) report_generic('Clicks on Pages',$list_url); else { report_generic('10 Most Clicked Pages',$list_url,10); report_generic('10 Least Clicked Pages',$list_url,-10); } if ($rep_ref=='on') if (count($list_ref)<30) report_generic('Referrers',$list_ref); else report_generic('20 Most Active Referrers',$list_ref,30); if ($rep_vis=='on') report_visits('Number of Visits',$list_ip); if ($rep_vis=='on' && $rep_topvis>0) report_topvisits('Top Visitors',$list_ip); if ($rep_brs=='on') report_generic('Used Browsers',$list_brs); echo '

*Note: Requests shows number of all requests from the web server (html`s, pictures, downloads, etc.). Currently may show not an accurate figure due to compression of the protocol files which removes unsignificant requests (e.g. pictures).

'; echo '

end

'; } if ($is_cut) { if ($conv_cut_limit==0 || !$got_cut_point) { $fp = fopen($path_log_file, 'w'); fclose($fp); $msg='Log has been zeroed'; } elseif ($is_cut_by_size) { $tmp_filename= tempnam('',$domain); $out= fopen($tmp_filename, 'w'); // write last read line with actualizied fields $buff= implode(' ',$line)."\n"; fwrite($out, $buff); // write rest of the log while (!feof($fp)) fwrite($out,fgets($fp,1000)); fclose($out); fclose($fp); copy($tmp_filename,$path_log_file); unlink($tmp_filename); $msg='Log has been cut'; } elseif ($is_cut_by_date) { if ($line_no>1) { $tmp_filename= tempnam('',$domain); $out= fopen($tmp_filename, 'w'); // write last read line with actualizied fields $buff= implode(' ',$line)."\n"; fwrite($out, $buff); // write rest of the log while (!feof($fp)) fwrite($out,fgets($fp,1000)); fclose($out); copy($tmp_filename,$path_log_file); unlink($tmp_filename); $msg='Log has been cut on '.date('d F Y',$conv_cut_limit).''; } else $msg='No cut has been done by date'; fclose($fp); } } ?>
'; ?> '; ?> '; ?>
Select domain:
Log size: K (Limit:)
No log file for this domain
Domain:


> Strip queries
> Report referrers (> Domains only)
> Report visits and size=3> top visitors
> Report browsers (> Brief, > Versions)
"Hits" considered as:
> Pages (more accurate)
> Requests (WebTrend`s manner)

> Remove non-html hits
> Squeeze more

Down to: size=3> >Kb >days

Description

- LogOperator 1.3 created by 19colors -
"Everything is possible" 0) return; ################################################ function get_log_list($log_dir, $sizes=false) { $list= array(); $dir= dir($log_dir); while($entry=$dir->read()) { if (substr($entry,-4)=='.log') { $item= substr($entry,0,strlen($entry)-4); if ($sizes) $item.= ' ('.(int)(filesize($log_dir.'/'.$entry)/1024).'K)'; $list[]= $item; } } $dir->close(); if (count($list)==0) $list[]="-no logs in this directory-"; else sort($list); return $list; } ################################################ function write_array($fp, $name, &$list) { for ($i=0; $i14400) {$list[$ip][_ip_visits]++; $unique=TRUE;} $list[$ip][_ip_last]= $time; } return $unique; } ################################################ function add_ref(&$list,$item,$time) { global $domain; if (substr($item,0,strlen($domain))==$domain) return; //self referrence if (substr($item,0,4+strlen($domain))=='www.'.$domain) return; //self referrence add_generic($list,$item,$time); } ################################################ function add_hit(&$list,$item,$time,$hit=0,$visit=0,$page=0) { global $total, $time_now; if (!isset($list[$item])) $list[$item]= array(0,0,0,0); $time_passed= $time_now-$time; $list[$item][3]++; $total['Requests'][3]+=$hit; $total['Pages'][3]+=$page; $total['Visits'][3]+=$visit; if ($time_passed<2592000) {$list[$item][2]++; $total['Requests'][2]+=$hit; $total['Pages'][2]+=$page; $total['Visits'][2]+=$visit;} //month if ($time_passed<604800) {$list[$item][1]++; $total['Requests'][1]+=$hit; $total['Pages'][1]+=$page; $total['Visits'][1]+=$visit;} //week if ($time_passed<86400) {$list[$item][0]++; $total['Requests'][0]+=$hit; $total['Pages'][0]+=$page; $total['Visits'][0]+=$visit;} //day if ($hit|$visit) { global $last_week; if ($time<_midnight-7*_24h); elseif ($time<_midnight-6*_24h) {$last_week[_midnight-6*_24h]['Requests']+=$hit; $last_week[_midnight-6*_24h]['Pages']+=$page; $last_week[_midnight-6*_24h]['Visits']+=$visit;} elseif ($time<_midnight-5*_24h) {$last_week[_midnight-5*_24h]['Requests']+=$hit; $last_week[_midnight-5*_24h]['Pages']+=$page; $last_week[_midnight-5*_24h]['Visits']+=$visit;} elseif ($time<_midnight-4*_24h) {$last_week[_midnight-4*_24h]['Requests']+=$hit; $last_week[_midnight-4*_24h]['Pages']+=$page; $last_week[_midnight-4*_24h]['Visits']+=$visit;} elseif ($time<_midnight-3*_24h) {$last_week[_midnight-3*_24h]['Requests']+=$hit; $last_week[_midnight-3*_24h]['Pages']+=$page; $last_week[_midnight-3*_24h]['Visits']+=$visit;} elseif ($time<_midnight-2*_24h) {$last_week[_midnight-2*_24h]['Requests']+=$hit; $last_week[_midnight-2*_24h]['Pages']+=$page; $last_week[_midnight-2*_24h]['Visits']+=$visit;} elseif ($time<_midnight-1*_24h) {$last_week[_midnight-1*_24h]['Requests']+=$hit; $last_week[_midnight-1*_24h]['Pages']+=$page; $last_week[_midnight-1*_24h]['Visits']+=$visit;} elseif ($time<_midnight ) {$last_week[_midnight ]['Requests']+=$hit; $last_week[_midnight ]['Pages']+=$page; $last_week[_midnight ]['Visits']+=$visit;} } } ################################################ function add_brs(&$list,$item,$time,$brief,$ver) { if ($brief && $ver) { $res=''; if (ereg('(MSIE|Opera) ([0-9.]+)',$item,$res)) $item= $res[0]; elseif (ereg('(Mozilla)/([0-9.]+)',$item,$res)) $item= 'Netscape '.$res[2]; } elseif ($brief) { $res=''; if (ereg('(MSIE|Opera) ([0-9.]+)',$item,$res)) $item= $res[1]; elseif (ereg('(Mozilla)/([0-9.]+)',$item,$res)) $item= 'Netscape'; else $item= 'Others'; } add_generic($list,$item,$time); } ################################################ function add_generic(&$list,$item,$time) { global $time_now; $time_passed= $time_now-$time; if (!isset($list[$item])) $list[$item]= array(0,0,0,0); $list[$item][3]++; if ($time_passed<2592000) {$list[$item][2]++;} //month if ($time_passed<604800) {$list[$item][1]++;} //week if ($time_passed<86400) {$list[$item][0]++;} //day } ################################################ function cmp_1($a,$b) {return ($a[1]>$b[1])?-1:1;} function clear_time(&$val) {$val[0]=0;} ################################################ function max_week(&$val,$key,&$max) { if ($val[_hits]>$max) $max= $val[_hits]; if ($val['Visits']==0 and $val[_hits]!=0) $val['Visits']=1; } ################################################ function sum_generic($val) { global $list_sum; $list_sum[0]+= $val[0]; $list_sum[1]+= $val[1]; $list_sum[2]+= $val[2]; $list_sum[3]+= $val[3]; } ################################################ function sum_visits($val) { global $list_sum; if (!isset($list_sum[$val[_ip_visits]])) $list_sum[$val[_ip_visits]]=0; $list_sum[$val[_ip_visits]]++; } ################################################ function log_to_time($time) { $time[2]=' '; $time[6]=' '; $time[11]=' '; return strtotime($time); } ################################################ function report_total($name,&$total) { global $time_begin_log; $total[_hits.' per visit'][0]= round($total[_hits][0]/($total['Visits'][0]?$total['Visits'][0]:1),1); $total[_hits.' per visit'][1]= round($total[_hits][1]/($total['Visits'][1]?$total['Visits'][1]:1),1); $total[_hits.' per visit'][2]= round($total[_hits][2]/($total['Visits'][2]?$total['Visits'][2]:1),1); $total[_hits.' per visit'][3]= round($total[_hits][3]/($total['Visits'][3]?$total['Visits'][3]:1),1); table_begin($name,' |Last 24 Hours|Last 7 Days|Last 30 Days|From '.date('d F Y',$time_begin_log)); reset($total); while (list($key,$val)=each($total)) { if (_hits=='Pages' && $key=='Requests') continue; table_line($key,$val); } table_end(); } ################################################ function report_week($name,&$week) { table_begin($name,'Day|'._hits.'|Visits|'.str_pad('Graph',2*6*20+5," ",STR_PAD_BOTH)); $max=0; reset($week); array_walk($week,'max_week',&$max); $max= round($max*1.1); reset($week); while (list($key,$val)=each($week)) { $key= date('D, d F',$key-1); unset($val[_hits_off]); $val[]= create_graph_bar($val[_hits],$max); table_line($key,$val); } table_end(); } ################################################ function report_generic($name,&$list,$quantity=0) { global $list_sum; global $time_begin_log; if ($quantity>=0) /*otherwise already sorted*/ arsort($list); // asort compares only first elements in subarrays $list_sum= array(0,0,0,0); array_walk($list,'sum_generic'); table_begin($name,' |Last 24 Hours|Last 7 Days|Last 30 Days|From '.date('d F Y',$time_begin_log).'|%%'); if ($quantity>=0) reset($list); else {end($list); for ($i=$quantity+1; $i!=0; $i++) prev($list);} while (list($key,$val)=each($list)) { $val[]=sprintf('%3.1f',round($val[3]/$list_sum[3]*100,1)); table_line($key,$val); $quantity--; if ($quantity==0) break; } table_end(); } ################################################ function report_visits($name,&$list) { global $list_sum; $list_sum= array(); array_walk($list,'sum_visits'); krsort($list_sum); table_begin($name,'Number of Visits|Number of Visitors'); reset($list_sum); while (list($key,$val)=each($list_sum)) { $val=array($val); table_line($key,$val); } table_end(); } ################################################ function report_topvisits($name,&$list) { global $rep_topvis; array_walk($list,'clear_time'); arsort($list,'cmp_1'); // asort compares only first elements in subarrays table_begin($name,'Address|Number of Visits'); reset($list); $i=0; while (list($key,$val)=each($list) and $i++<$rep_topvis) { $val= array($val[_ip_visits]); table_line($key,$val); } table_end(); } ################################################ function create_graph_bar($this,$max) { static $color=array('#FF0000','#FFFF00','#00FF00','#00FFFF','#0000FF','#FF00FF','#FFFFFF'); $code=''; if ($this!=0) { $code.= ''; $code.= '
 
'; } else $code.= ' '; array_shift($color); return $code; } ################################################ function table_begin($name,$head) { echo '

'.$name.'

'; echo ''; echo ''; echo ''; echo ''; } ################################################ function table_end() { echo '
'.str_replace('|','',$head).'
'; } ################################################ function table_line($item,&$data) { echo ''; echo ''.$item.''; reset($data); while (list($key,$val)=each($data)) { echo ''.$val.''; } echo ''; } ?>