<?php /** * Created by PhpStorm. * User: buhuan * Date: 14-4-18 * Time: 上午10:14 * 统计进程 * 广告留存 * 公式 * flag_id = channel_id*10000 + domain_id */ namespace Application\Process; use Application\Core\ProcessBase; use Application\Interfaces\IProcess; use Application\Core\Pusher; use \Ev; use \EvTimer; class Statistics extends ProcessBase implements IProcess{ /** * 子进程数目序号 => 执行的函数 */ private $procs = array( 0 => 'userOnline_daemon_handler', 1 => 'Retention_daemon_handler', 2 => 'AdRetention_daemon_handler' ); /** * 用户在线每5分钟执行一次 并且是在5的整数倍分钟时间点执行 */ const USER_ONLINE_DIFF = 5;//分钟 /** * 留存率每60分钟执行一次 */ const RETENTION_DIFF = 60;//分钟 /** * 广告留存率每60分钟执行一次 */ const AD_RETENTION_DIFF = 60;//分钟 /** * 在凌晨0点更新前N天的留存并写入前一天的留存 */ const RETENTION_PUSH_HOUR = 0;//整点 /** * 在凌晨0点更新前N天的广告留存并写入前一天的广告留存 */ const AD_RETENTION_PUSH_HOUR = 1;//整点 private $pids = array(); private $excutable = NULL; function onPreInit() { parent::onPreInit(); // TODO: Change the autogenerated stub foreach($this->procs as $function_name){ $this->excutable[$function_name] = TRUE; } } /** * 开始执行命令。 */ function execute() { // TODO: Implement execute() method. //创建子进程 $num = count($this->procs); $pid = pcntl_fork(); for($i =0 ; $i < $num ; $i++){ if($pid == -1){ print "不能创建子进程".chr(10); }else if($pid){ //父进程 print '子进程号:'.$pid.chr(10); $this->pids[$i] = $pid;//存入子进程序号和进程号 $pid = pcntl_fork(); }else{ if($this->excutable[$this->procs[$i]]) $this->daemon_dispatch($i); } } } /** * @param $i 进程序号 */ private function daemon_dispatch($i){ switch($i){ case 0: $timediff = self::USER_ONLINE_DIFF * 60; //确认分钟数为5的整数倍的时候开始执行 $minutes = intval(date('i')); $countdown = (5 - $minutes%5)*60;//倒计时开始毫秒数 break; case 1: //Retention $timediff = self::RETENTION_DIFF * 60; $countdown = 1; break; case 2: //ADRETENTION $timediff = self::AD_RETENTION_DIFF * 60; $countdown = 10; break; } print '启动进程['.$this->pids[$i].']'.$this->procs[$i].chr(10); $timer = new EvTimer($countdown,$timediff,array($this,$this->procs[$i])); $this->excutable[$this->procs[$i]] = FALSE; Ev::run(); } /** * 释放资源。 */ function dispose() { // TODO: Implement dispose() method. } function userOnline_daemon_handler(){ print "执行用户在线...".chr(10); $statistics_date = strtotime(date('Y-m-d')); $statistics_time = time(); //查找当前在线的玩家数量 $sql = "SELECT count(user_id) as num FROM user_online"; $d = $this->scope->db->fetch($sql); $num = $d['num']; $data = array( 'statistics_date' => $statistics_date, 'statistics_time' => $statistics_time, 'online' => $num ); Pusher::instance($this->scope)->doPushStat(107,$data); } function Retention_daemon_handler(){ $hour = intval(date('H')); print "执行留存率...".chr(10); if($hour == SELF::RETENTION_PUSH_HOUR){//如果是$push_hour点 则开始发送数据 $time = time(); $current_time = $time-24*60*60;//计算的基准时间 $start_datetime = date('Y-m-d',$current_time).' 00:00:00'; $end_datetime = date('Y-m-d',$current_time).' 23:59:59'; //查询当前前一天的注册人数 $sql = "SELECT COUNT(user_id) as reg_num FROM user_info_ext WHERE user_active_time > '$start_datetime' AND user_active_time < '$end_datetime'"; $d = $this->scope->db->fetch($sql); $reg_num = $d['reg_num']; //查询当前前一天登录的用户 $sql = "SELECT user_id FROM user_info_ext WHERE user_last_login_time > '$start_datetime' AND user_last_login_time < '$end_datetime' "; $d = $this->scope->db->fetchAll($sql); $login_users = $d; $reg_nums = array(); $reg_nums['day1'] = $this->nDayUsers(1,$current_time); $reg_nums['day3'] = $this->nDayUsers(3,$current_time); $reg_nums['day7'] = $this->nDayUsers(7,$current_time); $reg_nums['day15'] = $this->nDayUsers(15,$current_time); $reg_nums['day30'] = $this->nDayUsers(30,$current_time); $data = array( 'currentTime' => $time, 'reg_num' => $reg_num, 'reg_nums' => $reg_nums, 'login_users' => $login_users ); Pusher::instance($this->scope)->doPushStat(106,$data); } } function AdRetention_daemon_handler(){ $hour = intval(date('H')); print "执行广告留存率...".chr(10); if($hour == SELF::AD_RETENTION_PUSH_HOUR){//如果是$push_hour点 则开始发送数据 $time = time(); $current_time = $time-24*60*60;//计算的基准时间 $start_datetime = date('Y-m-d',$current_time).' 00:00:00'; $end_datetime = date('Y-m-d',$current_time).' 23:59:59'; //必须先知道哪些渠道ID 和 域名ID //查询当前前一天的注册人数集合 $sql = "SELECT COUNT(user_id) as reg_num,flag_id FROM user_info_ext WHERE flag_id <> 0 AND user_active_time > '$start_datetime' AND user_active_time < '$end_datetime' GROUP BY flag_id"; $d = $this->scope->db->fetchAll($sql); $reg_num = $d; //查询当前前一天登录的用户的不重复的flag_id $sql = "SELECT DISTINCT(flag_id) as flag_id FROM user_info_ext WHERE user_last_login_time > '$start_datetime' AND user_last_login_time < '$end_datetime' AND flag_id <> 0"; $flags = $this->scope->db->fetchAll($sql); //查询当前前一天登录的用户 $sql = "SELECT user_id,flag_id FROM user_info_ext WHERE user_last_login_time > '$start_datetime' AND user_last_login_time < '$end_datetime' AND flag_id <> 0"; $d = $this->scope->db->fetchAll($sql); $login_users = array(); //按channel_id,domain_id重组用户数据 if(count($d) > 0 && count($flags) > 0){ foreach($flags as $flag){ foreach($d as $user){ if($flag['flag_id'] == $user['flag_id']){ $login_users[$flag['flag_id']][] = $user['user_id']; } } } } unset($d); $reg_nums = array(); $reg_nums['day1'] = $this->nDayUsers_Ad(1,$current_time); $reg_nums['day2'] = $this->nDayUsers_Ad(2,$current_time); $reg_nums['day3'] = $this->nDayUsers_Ad(3,$current_time); $reg_nums['day4'] = $this->nDayUsers_Ad(4,$current_time); $reg_nums['day5'] = $this->nDayUsers_Ad(5,$current_time); $reg_nums['day6'] = $this->nDayUsers_Ad(6,$current_time); $reg_nums['day7'] = $this->nDayUsers_Ad(7,$current_time); $reg_nums['day8'] = $this->nDayUsers_Ad(8,$current_time); $data = array( 'currentTime' => $time, 'reg_num' => $reg_num, 'reg_nums' => $reg_nums, 'login_users' => $login_users ); Pusher::instance($this->scope)->doPushStat(108,$data); } } /** * @param int $n 1=1日 3=3日。。。 * @param int $current_time 基准时间 * @return array */ protected function nDayDate($n,$current_time){ $diff = 24*60*60; $start_datetime = date('Y-m-d',$current_time-$n*$diff).' 00:00:00'; $end_datetime = date('Y-m-d',$current_time-$n*$diff).' 23:59:59'; $date = array(); $date[0] = $start_datetime; $date[1] = $end_datetime; return $date; } /** * 得到基准日期前第n日的注册用户集合 * @param $n * @param $current_time * @return array */ protected function nDayUsers($n,$current_time){ $dates = $this->nDayDate($n,$current_time); //查询次日注册用户 $sql = "SELECT user_id FROM user_info_ext WHERE user_active_time > '{$dates[0]}' AND user_active_time < '{$dates[1]}'"; return $this->scope->db->fetchAll($sql); } /** * 得到基准日期前第n日的注册用户集合 * @param $n * @param $current_time * @return array */ function nDayUsers_Ad($n,$current_time){ $dates = $this->nDayDate($n,$current_time); //查询当前前一天注册的用户的不重复的flag_id $sql = "SELECT DISTINCT(flag_id) as flag_id FROM user_info_ext WHERE user_active_time > '{$dates[0]}' AND user_active_time < '{$dates[1]}' AND flag_id <> 0"; $flags = $this->scope->db->fetchAll($sql); //查询$n日注册用户 $sql = "SELECT user_id,flag_id FROM user_info_ext WHERE user_active_time > '{$dates[0]}' AND user_active_time < '{$dates[1]}' AND flag_id <> 0"; $d = $this->scope->db->fetchAll($sql); $reg_users = array(); if(count($d) > 0 && count($flags) > 0){ foreach($flags as $flag){ foreach($d as $user){ if($flag['flag_id'] == $user['flag_id']){ $reg_users[$flag['flag_id']][] = $user['user_id']; } } } } usleep(100000); return $reg_users; } }