数据分析脚本如下:
//error_reporting(0);
date_default_timezone_set("PRC");
$environment = get_cfg_var('app_flow_develop') ? get_cfg_var('app_flow_develop') : 3;
define('BASEPATH',dirname(dirname(__FILE__)));
switch($environment){
case 1 :
require BASEPATH . DIRECTORY_SEPARATOR . 'conf' . DIRECTORY_SEPARATOR . 'config.product.php';
break;
case 2 :
require BASEPATH . DIRECTORY_SEPARATOR . 'conf' . DIRECTORY_SEPARATOR . 'config.product.php';
break;
default:
require BASEPATH . DIRECTORY_SEPARATOR . 'conf' . DIRECTORY_SEPARATOR . 'config.develop.php';
break;
}
//删除其他的配置项
unset($tjdomain);unset($config);unset($interval);unset($replace_a);
require BASEPATH . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'logger.class.php';
//0//cc : 是否支持写数据到浏览器(cookie,sessionStorage,localStorage,userData)
//1//ck : 是否支持cookie
//2//cl : 浏览器颜色位数
//3//ds : 浏览器分辨率
//4//fl : flash版本
//5//ja : 是否支持java
//6//ln : 浏览器语言
//7//si : 统计id,站点标示
//8//su : 来源url,只取了域名
//9//kd : 关键词
//10//tt : 站点title
//11//cf : m点 1,站点0
//12//uid : 会员id
//13//pt : 平台
//14//ocu : 操作系统
//15//ua : 浏览器类型
//16//tm : 请求时间
//17//ip : 请求ip
//18//u : 站点url
//19//uuid:唯一用户标识
//20//basesu:原始su
//21//baseu:原始u
//22//basekd:原始关键词
//23//u1:一级连接
//24//u2:二级连接
//25//u3:三级连接
//26//u4:四级连接
//获得时间节点
$time = time();
$Ymd = date("Ymd",$time);
$H = date("G",$time);
$i = floor(date("i",$time)/5);
//处理昨天的最后一个五分钟区间
if(0 == $i && 0 == $H){
$Ymd = date("Ymd",strtotime('-1 days'));
$H = 23;
$i = 11;
}
//处理今天上一个小时的最后一个五分钟区间
elseif(0 == $i && 0 != $H){
$H--;
$i = 11;
}
//处理上一个五分钟区间
else{
$i--;
}
//手动控制脚本的执行目录
if(isset($_SERVER['argv'][1]) && $_SERVER['argv'][1]){
if(isset($_SERVER['argv'][2]) && isset($_SERVER['argv'][3]) &&
$_SERVER['argv'][2] >=0 &&
$_SERVER['argv'][2] < 24 &&
$_SERVER['argv'][3] >=0 &&
$_SERVER['argv'][3] <12)
{
$Ymd = strval($_SERVER['argv'][1]);
$H = strval($_SERVER['argv'][2]);
$i = strval($_SERVER['argv'][3]);
$handd0 = true;
}else{
echo 'parma error';
}
}
//设置redis的key与操作目录地址
$LOG_PATH = $LOG_BASE . DIRECTORY_SEPARATOR . $Ymd . DIRECTORY_SEPARATOR . $H . DIRECTORY_SEPARATOR . $i;
$HOUR_PATH = dirname($LOG_PATH);
$REDIS_DAY_KEY = $Ymd;
$REDIS_HOUR_KEY = "{$Ymd}:{$H}";
$log_base = new Logger($LOG_BASE . DIRECTORY_SEPARATOR . 'error.log');
//小时路径下的记录句柄,先检查有没有小时目录,没有的话报错
if(file_exists($HOUR_PATH)){
$log_hour = new Logger($HOUR_PATH . DIRECTORY_SEPARATOR . 'error.log');
}else{
if(isset($handd0) && true === $handd0){
echo $HOUR_PATH . ' is not exists please check the dir and retry';
$log_base -> error($HOUR_PATH . ' is not exists by hand');
}else{
$log_base -> error($HOUR_PATH . ' is not exists ');
}
exit;
}
//如果有日志
//这里的代码可以封装成一个类,当做一种对最小单元的一个处理方法,或者可以换成其他语言的脚本的调用,也方便单独手动处理数据
//优化可以使用popen,proc_open,pcntl等方法多进程来处理
if(file_exists($LOG_PATH)){
//分钟路径下的记录句柄
$log_do = new Logger($LOG_PATH . DIRECTORY_SEPARATOR . 'do.txt');
//切换目录,不然window下报错
chdir($LOG_PATH);
//判断是否完成这个区间
if(!file_exists($LOG_PATH . '/done.txt')){
//生成合并文件
if(!file_exists($LOG_PATH . '/all.log')){
$log_do -> notice(" combine files starts ");
if(PHP_OS == 'WINNT'){
system("copy *.log all.log");
} else {
system("cat *.log >> all.log");
}
//再次判断
if(!file_exists($LOG_PATH . '/all.log')){
$log_hour -> error(" No.{$i} all log combine error");
exit;
}
$log_do -> notice(" combine files ends ");
}
//读取文件写redis缓存
$log_do -> notice(" read all_log starts ");
if($fp = fopen ($LOG_PATH . '/all.log', "r")){
if(flock($fp , LOCK_SH )) {
//初始化
$redis = new Redis();
$re = $redis->pconnect($REDIS_IP,$REDIS_PORT);
if(!$re){
$REDIS_FLAG = FALSE;
}else{
$REDIS_FLAG = TRUE;
//全站新的ip,uv,uid
$uv_new = $uid_new = $ip_new = array();
//u的新uv,su的新uv,kw的新uv
$u_uv = $su_uv = $kw_uv = array();
}
$ii=1;
//记录这段时间的pv
$si_array = $uv_array = $uid_array = $ip_array = $u_array = $su_array = $kw_array = array();
//读取文件,填充数组
while($str = fgets($fp)){
//移除回车符
$str = trim($str,PHP_EOL);
$a = explode('~^~',$str);
if(27 != count($a)){
$log_do -> notice(" No.{$ii} data is bad type ");
continue;
}
//填充数组
if($a[7]){
//处理si,根据si再次初始化数组
//记录每个站点这段时间的pv总数
/*
$si_array(
'站点一'=>10,
'站点二'=>'20'
);
*/
if(isset($si_array[$a[7]])) {
$si_array[$a[7]] += 1;
} else {
$si_array[$a[7]] = 1;
$uv_new[$a[7]] = $uid_new[$a[7]] = $ip_new[$a[7]] = array();
$u_uv[$a[7]] = $su_uv[$a[7]] = $kw_uv[$a[7]] = array();
$uv_array[$a[7]] = $uid_array[$a[7]] = $ip_array[$a[7]] = $kw_array[$a[7]] = $su_array[$a[7]] = $u_array[$a[7]] = array();
$si_array[$a[7]] = 1;
}
//处理uv
if($a[19]){
//记录uv,记录后得到每个站点,每个uuid这段时间的pv数量
/*
$uv_array = array(
'站点一'=>array(
'uuid1'=>10,
'uuid2'=>20,
)
)
*/
isset($uv_array[$a[7]][$a[19]]) ? $uv_array[$a[7]][$a[19]] += 1 : $uv_array[$a[7]][$a[19]] = 1;
//记录每个站点,这段时间的新的uv数量
/*
$uv_new = array(
'站点一'=>array(
'uuid1','uuid2'
)
)
*/
if($REDIS_FLAG){
//不在这个时间段记录的数据里
if(!in_array($a[19],$uv_new[$a[7]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:UV:HASH",$a[19]);
//不在今天的历史数据里(即新的uuid)
if(!$exist){
$uv_new[$a[7]][]= $a[19];
}
}
}
}
//处理uid
if($a[12]){
//记录uid,记录后得到每个站点,每个uid这段时间的pv数量
/*
$uid_array = array(
'站点一'=>array(
'uid1'=>10,
'uid2'=>20,
)
)
*/
isset($uid_array[$a[7]][$a[12]]) ? $uid_array[$a[7]][$a[12]] += 1 : $uid_array[$a[7]][$a[12]] = 1;
//记录每个站点,这段时间的新的uid数量
/*
$uid_new = array(
'站点一'=>array(
'uid1','uid2'
)
)
*/
if($REDIS_FLAG){
if(!in_array($a[12],$uid_new[$a[7]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:UID:HASH",$a[12]);
if(!$exist){
$uid_new[$a[7]][]= $a[12];
}
}
}
}
//处理ip
if($a[17]){
//记录ip,记录后得到每个站点,每个ip这段时间的pv数量
/*
$ip_array = array(
'站点一'=>array(
'ip1'=>10,
'ip2'=>20,
)
)
*/
isset($ip_array[$a[7]][$a[17]]) ? $ip_array[$a[7]][$a[17]] += 1 : $ip_array[$a[7]][$a[17]] = 1;
//记录每个站点,这段时间的新的ip数量
/*
$ip_new = array(
'站点一'=>array(
'ip1','ip2'
)
)
*/
if($REDIS_FLAG){
if(!in_array($a[17],$ip_new[$a[7]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:IP:HASH",$a[17]);
if(!$exist){
$ip_new[$a[7]][]= $a[17];
}
}
}
}
//特殊处理的项
//处理u
if($a[18]){
//处理一级Url
reg_u_common_op(23);
//处理二级Url
reg_u_common_op(24);
//处理三级Url
reg_u_common_op(25);
//处理四级Url
reg_u_common_op(26);
}
//处理kw
if($a[9]){
//记录kw,记录后得到每个站点,每个kw这段时间的pv数量
/*
$kw_array = array(
'站点一'=>array(
'kw1'=>10,
'kw2'=>20,
)
)
*/
isset($kw_array[$a[7]][$a[9]]) ? $kw_array[$a[7]][$a[9]] += 1 : $kw_array[$a[7]][$a[9]] = 1;
//记录每个站点,这段时间kw的新的uv数量
/*
$kw_new = array(
'站点一'=>array(
'kw1'=>array(
'uuid1','uuid2'
)
)
)
*/
if($REDIS_FLAG){
if(!isset($kw_uv[$a[7]][$a[9]]) || !in_array($a[19],$kw_uv[$a[7]][$a[9]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:{$a[9]}:KW:UV:HASH",$a[19]);
if(!$exist){
$kw_uv[$a[7]][$a[9]][]= $a[19];
}
}
}
}
//处理su
if($a[8]){
//记录su,记录后得到每个站点,每个su这段时间的pv数量
/*
$su_array = array(
'站点一'=>array(
'su1'=>10,
'su2'=>20,
)
)
*/
isset($su_array[$a[7]][$a[8]]) ? $su_array[$a[7]][$a[8]] += 1 : $su_array[$a[7]][$a[8]] = 1;
//记录每个站点,这段时间su的新的uv数量
/*
$kw_new = array(
'站点一'=>array(
'kw1'=>array(
'uuid1','uuid2'
)
)
)
*/
if($REDIS_FLAG){
if(!isset($su_uv[$a[7]][$a[8]]) || !in_array($a[19],$su_uv[$a[7]][$a[8]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:{$a[8]}:SU:UV:HASH",$a[19]);
if(!$exist){
$su_uv[$a[7]][$a[8]][]= $a[19];
}
}
}
}
}else{
$log_do -> notice(" No.{$ii} data empty si ");
continue;
}
$ii++;
unset($a);
}
$log_do -> notice(" read all_log is complete ");
//填充redis
//记录redis记录开始
if($REDIS_FLAG){
$log_do -> notice(" set redis start ");
//记录站点的pv总数
foreach($si_array as $k => $v){
$redis->HINCRBY("{$REDIS_DAY_KEY}:{$k}:QZ:HASH","PV",$v);
$redis->HINCRBY("{$REDIS_HOUR_KEY}:{$k}:QZ:HASH","PV",$v);
}
//记录站点的uv总数
foreach($uv_new as $k => $v){
$uv_num = count($v);
$redis->HINCRBY("{$REDIS_DAY_KEY}:{$k}:QZ:HASH","UV",$uv_num);
$redis->HINCRBY("{$REDIS_HOUR_KEY}:{$k}:QZ:HASH","UV",$uv_num);
//插入当天的uv唯一hash
$flip_uv = array_flip($v);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:UV:HASH",$flip_uv);
}
//记录站点的uid总数
foreach($uid_new as $k => $v){
$uid_num = count($v);
$redis->HINCRBY("{$REDIS_DAY_KEY}:{$k}:QZ:HASH","UID",$uid_num);
$redis->HINCRBY("{$REDIS_HOUR_KEY}:{$k}:QZ:HASH","UID",$uid_num);
//插入当天的uv唯一hash
$flip_uid = array_flip($v);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:UID:HASH",$flip_uid);
}
//记录站点的ip总数
foreach($ip_new as $k => $v){
$ip_num = count($v);
$redis->HINCRBY("{$REDIS_DAY_KEY}:{$k}:QZ:HASH","IP",$ip_num);
$redis->HINCRBY("{$REDIS_HOUR_KEY}:{$k}:QZ:HASH","IP",$ip_num);
//插入当天的uv唯一hash
$flip_ip = array_flip($v);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:IP:HASH",$flip_ip);
}
//记录站点u的pv,uv
foreach($u_uv as $k => $v){
foreach($v as $kk => $vv){
$u_uv_num = count($vv);
$u_pv_num = $u_array[$k][$kk];
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:U:PV:ZSET",$u_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:U:PV:ZSET",$u_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:U:UV:ZSET",$u_uv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:U:UV:ZSET",$u_uv_num,$kk);
//插入当天的uv唯一hash
$flip_u_uv = array_flip($vv);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:{$kk}:U:UV:HASH",$flip_u_uv);
}
}
//记录站点kw的pv,uv
foreach($kw_uv as $k => $v){
foreach($v as $kk => $vv){
$kw_uv_num = count($vv);
$kw_pv_num = $kw_array[$k][$kk];
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:KW:PV:ZSET",$kw_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:KW:PV:ZSET",$kw_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:KW:UV:ZSET",$kw_uv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:KW:UV:ZSET",$kw_uv_num,$kk);
//插入当天的uv唯一hash
$flip_kw_uv = array_flip($vv);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:{$kk}:KW:UV:HASH",$flip_kw_uv);
}
}
//记录站点su的pv,uv
foreach($su_uv as $k => $v){
foreach($v as $kk => $vv){
$su_uv_num = count($vv);
$su_pv_num = $su_array[$k][$kk];
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:SU:PV:ZSET",$su_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:SU:PV:ZSET",$su_pv_num,$kk);
$redis->ZINCRBY("{$REDIS_DAY_KEY}:{$k}:SU:UV:ZSET",$su_uv_num,$kk);
$redis->ZINCRBY("{$REDIS_HOUR_KEY}:{$k}:SU:UV:ZSET",$su_uv_num,$kk);
//插入当天的uv唯一hash
$flip_su_uv = array_flip($vv);
$redis->HMSET("{$REDIS_DAY_KEY}:{$k}:{$kk}:SU:UV:HASH",$flip_su_uv);
}
}
$log_do -> notice(" set redis is complete ");
}
//记录redis记录结束
//记录统计数据
//记录统计记录开始
$log_do -> notice(" write analyse data starts ");
if($REDIS_FLAG){
file_put_contents($LOG_PATH . '/uv_new.log', var_export(json_encode($uv_new),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/uid_new.log', var_export(json_encode($uid_new),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/ip_new.log', var_export(json_encode($ip_new),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/u_uv.log', var_export(json_encode($u_uv),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/su_uv.log', var_export(json_encode($su_uv),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/kw_uv.log', var_export(json_encode($kw_uv),true), FILE_APPEND);
}
file_put_contents($LOG_PATH . '/uv_array.log', var_export(json_encode($uv_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/uid_array.log', var_export(json_encode($uid_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/ip_array.log', var_export(json_encode($ip_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/kw_array.log', var_export(json_encode($kw_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/su_array.log', var_export(json_encode($su_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/u_array.log', var_export(json_encode($u_array),true), FILE_APPEND);
file_put_contents($LOG_PATH . '/si_array.log', var_export(json_encode($si_array),true), FILE_APPEND);
//记录统计记录完毕
$log_do -> notice(" write analyse data is complete ");
//释放变量
if($REDIS_FLAG){
unset($ip_new);
unset($uv_new);
unset($uid_new);
unset($u_uv);
unset($su_uv);
unset($kw_uv);
}
unset($uv_array);
unset($uid_array);
unset($ip_array);
unset($kw_array);
unset($su_array);
unset($u_array);
$log_do -> notice(" release var is complete ");
flock ( $fp , LOCK_UN);
} else {
$log_do -> notice(" all.log flock failed ");
}
fclose ( $fp );
}else{
$log_hour -> error(" No.{$i} all.log fopen error ");
exit;
}
//记录完成
$now = date("Y-m-d H:i:s");
$log_do -> notice(" No.{$i} job done at {$now} ");
file_put_contents($LOG_PATH . DIRECTORY_SEPARATOR . 'done.txt', $now . " No.{$i} job is done" . PHP_EOL, FILE_APPEND);
$log_hour -> notice(" No.{$i} job done at {$now} ");
if(isset($handd0) && true === $handd0){
echo " No.{$i} job done at {$now} ";
}
}else{
$log_hour -> notice(" No.{$i} alread done ");
}
}else{
$log_hour -> error(" No.{$i} dir not exist ");
}
//处理各级url的通用方法
function reg_u_common_op($u_no){
//引入全局变量
global $a,$u_array,$REDIS_DAY_KEY,$redis,$REDIS_FLAG,$u_uv;
if($a[$u_no]){
//记录u,记录后得到每个站点,每个url这段时间的pv数量
/*
$u_array = array(
'站点一'=>array(
'u1'=>10,
'u2'=>20,
)
)
*/
isset($u_array[$a[7]][$a[$u_no]]) ? $u_array[$a[7]][$a[$u_no]] += 1 : $u_array[$a[7]][$a[$u_no]] = 1;
//记录每个站点,这段时间的u新的uv数量
/*
$u_uv = array(
'站点一'=>array(
'URL一'=>array(
'uuid1','uuid2'
)
)
)
*/
if($REDIS_FLAG){
if(!isset($u_uv[$a[7]][$a[$u_no]]) || !in_array($a[19],$u_uv[$a[7]][$a[$u_no]])){
$exist = $redis->HEXISTS("{$REDIS_DAY_KEY}:{$a[7]}:{$a[$u_no]}:U:UV:HASH",$a[19]);
if(!$exist){
$u_uv[$a[7]][$a[$u_no]][]= $a[19];
}
}
}
}
}
exit;
附上nginx的server配置:
server { listen 80; server_name 18touch.tongji.com; index index.php index.html index.htm; root /home/tongji/webroot; rewrite ^/h.js$ /js.php last; rewrite ^/m.gif$ /hm.php last; include global/restrictions.conf; location ~ .php$ { fastcgi_pass php78; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /home/tongji/webroot$fastcgi_script_name; include fastcgi_params; } location ~ /888/$ { empty_gif; fastcgi_pass php78; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME /home/tongji/webroot/hm.php; include fastcgi_params; } }
剩下从redis每日获取昨天的统计数据,然后存储到文本或者mysql。
PS:对目录的操作在win与linux下的函数效果不同,注意文件夹的权限,写文本也有不同。
统计数据从文本返回到php的脚本:
$fp = fopen ('uv_array.log', "r"); while($str = fgets($fp)){ $str = "$str = " . trim($str,PHP_EOL) .";"; eval($str); $a = json_decode($str,true); var_dump($a);exit; }