服务热线
1888888888
作者:文煞发布时间:2024-06-06分类:PHP笔记浏览:5219
最近开发了一款Zblog插件,文煞网站日志统计分析工具。在开发的时候遇到一个很有意思的事情,统计页面需要获取多种数据,比如蜘蛛、游客或登录用户的PV和IP数量,由于需要统计的数据比较多,而且还需要按照指定的字段进行排序展示,如果全部从mysql进行查询的话,那么该页面就需要对数据库进行十至二十次的查询,明显增加了服务器压力。在我巧妙的构思下,找到了一个比较好的方法,那就是先取出所有日志数据,然后再用取出的数据来获取我想要的内容!这样我只需要查询一次数据库!
因为我们已经取出了网站日志的所有数据,现在需要展示一个IP请求榜,按照同IP请求的次数进行排序,展示到页面,我们可以直观的看到访问频率最高的IP,然后就可以对该IP的访问行为进行一些判断和识别。
function ips($array) { if($array != null) { $ipss = array(); foreach ($array as $v) { $ips[] = $v['ip']; } // 创建一个计数数组 $ipCounts = array_count_values($ips); foreach ($ipCounts as $ip => $count) { $ipss[] = array('ip'=>$ip,'num'=>$count); } $ips[]=array(); usort($ipss, function($a, $b) { return $b['num'] - $a['num']; } ); return $ipss; } else { return array(); } }
代码注释:因为我们想从数组$array中对不同IP的出现次数进行排序,那么我们首先需要一个计数数组,本代码是构造了一个新的数组,里面只包含了IP字段和num字段,num字段对应的值是IP出现次数。然后我们直接用foreach输出ips($array)就可以了。
接着上面的代码进行介绍,这里我们还通过以下代码按照num字段的值进行了降序排序,就是上面代码中的以下部分代码:
$ips[]=array(); usort($ipss, function($a, $b) { return $b['num'] - $a['num']; } );
function de404logs($array){ global $zbp; $groups_404 = array(); foreach ($array as $item) { if ($item['code'] == 404) { $groups_404[] = $item; } } $newArray = []; // 删除符合条件的数组 $newArray = array_map(function ($item) { $item['code'] = 200; //这里 return $item; }, $groups_404); foreach ($newArray as $value) { if (($key = array_search($value, $array)) !== false) { unset($array[$key]); } } $array = array_merge($array, $newArray); // 重新合并数组 return $array; }
代码注释:这里我们先找到符合条件的数据(代码中是code字段为404的数据),并存入了新的数组$groups_404,然后通过循环$groups_404,把$groups_404中的code从404改为200并存入入新数组$newArray,然后通过array_merge($array, $newArray)合并数组,并把两个数组交集的部分(就是符合其他字段的值与$groups_404相同,但是code字段已经修改为200的newArray数组)进行删除。
由于我还要通过$groups_404修改数据库,中间删掉了操作数据库的代码。所以没有直接使用$groups_404数组。
function wenshaweblogs_time($data, $timePeriod) { // 定义时间常量 $todayStart = strtotime('today 00:00:00'); $todayEnd = strtotime('today 23:59:59'); $weekStart = strtotime('this week Monday'); $weekEnd = strtotime('this week Sunday 23:59:59'); $monthStart = strtotime('first day of this month'); $monthEnd = strtotime('last day of this month 23:59:59'); // 定义时间段 switch ($timePeriod) { case 0: // 本日 $mintime = $todayStart; $maxtime = $todayEnd; break; case 1: // 本周 $mintime = $weekStart; $maxtime = $weekEnd; break; case 2: // 本月 $mintime = $monthStart; $maxtime = $monthEnd; break; case 3: // 上周 $mintime = strtotime('last week Monday'); $maxtime = strtotime('last week Sunday 23:59:59'); break; case 4: // 上个月 $mintime = strtotime('first day of last month'); $maxtime = strtotime('last day of last month 23:59:59'); break; case 5: // 本年 $mintime = strtotime("first day of January " . date('Y')); $maxtime = $todayEnd; break; case 6: // 上一年 $mintime = strtotime("first day of January " . date('Y', strtotime('-1 year'))); $maxtime = strtotime("last day of December " . date('Y', strtotime('-1 year')) . " 23:59:59"); break; default: throw new Exception("Invalid time period: " . $timePeriod); } // 过滤数组并返回结果数组 if ($data != null) { return array_filter($data, function ($item) use ($mintime, $maxtime) { return $item['time'] >= $mintime && $item['time'] <= $maxtime; }); } else { return array(); } }
代码注释:wenshaweblogs_time($data, $timePeriod)通过传入$data和$timePeriod对$data进行数据提取,代码中可以看出我们是通过time字段进行范围匹配,从而返回符合时间范围的新的数据!
以上代码都需要在一个页面进行处理,而且还有很多类似处理的数据的地方,本来我们可以直接通过条件查询数据库,而无需像我这样通过处理数组来达到自己的目的。但是由于我们需要查询全部数据来进行总数的统计和区分,既然已经获取了全部数据,我下面的数据就不需要再去查询数据库了,而是直接在前面查询到的总数数据中进行各式各样的处理。虽然我没测试过哪种方法效果更好,但是少查询数据库总是没毛病的,尤其是数据库和脚本不再同一个服务器的情况下,少查询数据库应该更佳!
本文只是部分代码片段分享,希望对你有所帮助!
分享:
支付宝
微信