首页文章相册图片搜索RSS 2.0

Drupal模块开发实例(2)

发表于 2008-08-25-11:52:13 编辑

这一部分需要实现的是统计数据显示,和访问明细的过滤。最终效果图:
自制drupal模块、主题截图
自制drupal模块、主题截图

接下来就是把统计数据显示出来。流量概况定义的url为admin/reports/tongji,调用的函数是tongji_view。现在就是完成它。

<?php
function tongji_view(){
//为了方便,我们使用表格来显示数据。根据数据表时的字段,定义一个表格头部信息。
   
$header = array('日期','总IP','总PV','来自谷歌','来自百度');
   
$sql = 'SELECT * FROM {tongji} ORDER BY time DESC'. tablesort_sql($header);//查询tongji表里的数据。
   
$result = pager_query($sql, 10, 0);//以分页形式输出,每页10条。
   
$rows = array();
    while (
$a = db_fetch_object($result)) {
       
$rows[] = array(
   
$a->time,$a->ip,l($a->pv,'admin/reports/tongji/hits',array('query'=>array('time'=>$a->time))),l($a->google,'admin/reports/tongji/hits',array('query'=>array('time'=>$a->time,'type'=>'google'))),l($a->baidu,'admin/reports/tongji/hits',array('query'=>array('time'=>$a->time,'type'=>'baidu')))
        );
//五个字段的数据,按日期读取出来。同时链接到访问明细页面,以查看每个项目的明细。
   
}
   
$a = db_fetch_object(db_query('SELECT SUM(ip) AS ip,SUM(pv) AS pv, SUM(google) AS google, SUM(baidu) AS baidu FROM {tongji}'));//计算每个项目的总数,并读取出来。
   
$row = array(
       
'总计',
       
$a->ip,
       
l($a->pv,'admin/reports/tongji/hits'),
       
l($a->google,'admin/reports/tongji/hits',array('query'=>array('type'=>'google'))),
       
l($a->baidu,'admin/reports/tongji/hits',array('query'=>array('type'=>'baidu')))
    );
    if (empty(
$rows)) {
       
$rows[] = array(array('data' => '没有数据。你必须开启', 'colspan' => 5));
    }else{
       
$rows[] = $row;
    }
   
$output = theme('table', $header, $rows,array('id'=>'tongji-view'));//输出为表格,调用theme_table
   
$output .= theme('pager', NULL, 10, 0);//输出分页链接,调用theme_pager
   
return $output;
}
?>

进入这个地址(admin/reports/tongji),如果你正确设置了cron,或者手动导入了数据,页面上就应该会按时间显示出每天的流量的概况了。

然后就是访问明细。访问明细我们直接使用accesslog数据表里的记录,稍做一些过滤,按不同条件列出来即可。每个项目所能显示的数据多少,取决于访问记录的保存时间设置。这儿稍微有些复杂,因为我们需要一些过滤条件。

<?php
//先定义一个表单用来选择过滤条件。
function _tongji_sel(& $form_state){
   
$form['sel'] = array(
       
'#type' => 'select',
       
'#title' => '选择条件',
       
'#options' => array('all'=>'全部来源','google'=>'来自谷歌','baidu'=>'来自百度'),//设定的条件,可以根据自己的需要设置。
       
'#default_value' => $_GET['type'],//从url上获取默认数据。
   
);
   
$form['tongji-date'] = array(
       
'#type' => 'textfield',
       
'#title' => '选择时间',
       
'#default_value' => $_GET['time'],//传递时间参数。
       
'#size' => 12
   
);
   
$form['submit'] = array(
       
'#type' => 'submit',
       
'#value' => '确认',
       
'#submit' => array('_tongji_sel_submit'),
    );
    return
$form;
}

function
_tongji_sel_submit($form, &$form_state) {
   
$s = $form_state['values']['sel'];
   
$d = $form_state['values']['tongji-date'];
    if(
$d){
       
drupal_goto('admin/reports/tongji/hits',array('type' => $s,'time'=>$d));
    }else{
       
drupal_goto('admin/reports/tongji/hits',array('type' => $s));
    }
//提交后的处理,我们把过滤条件的值(项目和时间)传附加到url上,另一个函数从url上获取参数。
}
function
tongji_hits(){
   
$header = array(
        array(
'data' => t('Timestamp'), 'field' => 'a.timestamp', 'sort' => 'desc'),
        array(
'data' => t('Page'), 'field' => 'a.path'),
        array(
'data' => t('User'), 'field' => 'u.name'),
        array(
'data' => t('Referrer')),
        array(
'data' => t('IP address'))
    );
//同样以表格方式输出。
   
if($_GET['time']) {//接收url传递来的时间参数。因为这是管理员使用的,就不必验证参数的合法性了。
       
$timesql = ' AND to_days(from_unixtime(timestamp)) = to_days('.$_GET['time'].') ';
       
$allsql = ' WHERE to_days(from_unixtime(timestamp)) = to_days('.$_GET['time'].') ';
       
$allsql1 = ' WHERE time = '.$_GET['time'];
    }
   
$sql = 'SELECT a.aid, a.path, a.title, a.hostname, a.uid, u.name, a.timestamp,a.url FROM {accesslog} a LEFT JOIN {users} u ON u.uid = a.uid WHERE';
    switch (
$_GET['type']){//判断url传递来的项目值。根据上面的项目,在这儿使用不同的数据库查询来过滤访问记录。我们上面只定义了三个:全部、百度、谷歌,所以这里也就是三个。
       
case '':
        case
'all':
           
$result = pager_query('SELECT a.aid, a.path, a.title, a.hostname, a.uid, u.name, a.timestamp,a.url FROM {accesslog} a LEFT JOIN {users} u ON u.uid = a.uid'.$allsql. tablesort_sql($header),30);
        break;
        case
'google':
           
$result = pager_query($sql.' a.url LIKE "%%.google.%" '.$timesql. tablesort_sql($header),30);
           
$title = db_fetch_object(db_query('SELECT SUM(google) AS ip FROM {tongji} '.$allsql1));
        break;
        case
'baidu':
           
$result = pager_query($sql.' a.url LIKE "%%.baidu.%" '.$timesql. tablesort_sql($header),30);
           
$title = db_fetch_object(db_query('SELECT SUM(baidu) AS ip FROM {tongji} '.$allsql1));
        break;
        case
'yahoo':
           
$result = pager_query($sql.' a.url LIKE "%%.yahoo.%" '.$timesql. tablesort_sql($header),30);
        break;
    }
   
$rows = array();
    while (
$log = db_fetch_object($result)) {
   
$rows[] = array(
      array(
'data' => format_date($log->timestamp, 'small'), 'class' => 'nowrap'),
     
_tongji_format_item($log->title, $log->path),
     
theme('username', $log),
        ((
$log->url) ? _tongji_keyword($log->url, 40):NULL),
       
$log->hostname.'<br>'._tongji_getip($log->hostname));
    }
//读取各字段的数据。这里有两个转换,一个是从来源url中提取搜索关键字,一个是利用QQ纯真IP库来转换ip地址。需要把纯真IP库下载保存到模块文件夹中。

   
if (empty($rows)) {
       
$rows[] = array(array('data' => t('No statistics available.'), 'colspan' => 5));
    }
drupal_add_js(<<<EOT
    $(document).ready(function () {
        var type = $("select[@name='sel'] option[@selected]").text();
        $('.tj-sels').text(type);
    });
EOT
,
'inline');
   
$output = drupal_get_form('_tongji_sel');
   
$tm = ($_GET['time'] ? $_GET['time']:'所有时间');
   
$pv = ($title->pv ? ',总 PV:'.$title->pv:NULL);
   
$output .= '<h2 class="tj-title">时间段:'.$tm.',<span class="tj-sels"></span> 的总 IP 共:'.$title->ip.$pv.'</h2>';
   
$output .= theme('table', $header, $rows,array('id'=>'tj-hits'));
   
$output .= theme('pager', NULL, 30, 0);
    return
$output;
}

//搜索引擎关键字截取
function _tongji_keyword($v,$w = 35){
   
$b = urldecode($v);
   
$x = 1;
    if(
strpos($v,'.baidu.')){
       
$q = '/wd=(.*?)&|wd=(.*)/i';
       
$b = iconv("GBK", "UTF-8", $b);
    }elseif(
strpos($v,'.google.')){
       
$q = /[&|
?>
q=(.*?)&|[&|\?]q=(.*)/i';
}elseif(strpos($v,'.yahoo.')){
$q = '/p=(.*?)&/i';
}elseif(strpos($v,'.live.')){
$q = '/q=(.*?)&/i';
}elseif(strpos($v,'.soso.')){
$q = '/[&|\?]w=(.*?)&|[&|\?]w=(.*)/i';
$b = iconv("GBK", "UTF-8", $b);
}elseif(strpos($v,'.yodao.')){
$q = '/q=(.*?)&/i';
}elseif(strpos($v,'.sogou.')){
$q = '/query=(.*?)&/i';
$b = iconv("GBK", "UTF-8", $b);
}else{
$x = 0;
}
if($x && preg_match($q, $b, $value)) {
$t = '关键字:'.($value[1] ? $value[1]:$value[2]).'';
}
$title = truncate_utf8($v, $w, FALSE, TRUE);
$t .= l($title,$v,array('attributes'=>array('target'=>'_blank')));
return $t;
}
//ip查询,纯真IP库的查询代码基本上是使用dz论坛的方法。
function _tongji_getip($ip) {

$return = '';

if(preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip)) {

$iparray = explode('.', $ip);

if($iparray[0] == 10 || $iparray[0] == 127 || ($iparray[0] == 192 && $iparray[1] == 168) || ($iparray[0] == 172 && ($iparray[1] >= 16 && $iparray[1] <= 31))) {
$t = '本机地址';
} elseif($iparray[0] > 255 || $iparray[1] > 255 || $iparray[2] > 255 || $iparray[3] > 255) {
$t = '- Invalid IP Address';
} else {
$t = _tongji_dataip($ip, drupal_get_path(module,tongji).'/QQWry.Dat');
}
}else{
$t = 'IP地址不合法。';
}

return $t;

}

function _tongji_dataip($ip, $ipdatafile) {

if(!$fd = @fopen($ipdatafile, 'rb')) {
return '- Invalid IP data file';
}

$ip = explode('.', $ip);
$ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];

if(!($DataBegin = fread($fd, 4)) || !($DataEnd = fread($fd, 4)) ) return;
@$ipbegin = implode('', unpack('L', $DataBegin));
if($ipbegin < 0) $ipbegin += pow(2, 32);
@$ipend = implode('', unpack('L', $DataEnd));
if($ipend < 0) $ipend += pow(2, 32);
$ipAllNum = ($ipend - $ipbegin) / 7 + 1;

$BeginNum = $ip2num = $ip1num = 0;
$ipAddr1 = $ipAddr2 = '';
$EndNum = $ipAllNum;

while($ip1num > $ipNum || $ip2num < $ipNum) {
$Middle= intval(($EndNum + $BeginNum) / 2);

fseek($fd, $ipbegin + 7 * $Middle);
$ipData1 = fread($fd, 4);
if(strlen($ipData1) < 4) {
fclose($fd);
return '- System Error';
}
$ip1num = implode('', unpack('L', $ipData1));
if($ip1num < 0) $ip1num += pow(2, 32);

if($ip1num > $ipNum) {
$EndNum = $Middle;
continue;
}

$DataSeek = fread($fd, 3);
if(strlen($DataSeek) < 3) {
fclose($fd);
return '- System Error';
}
$DataSeek = implode('', unpack('L', $DataSeek.chr(0)));
fseek($fd, $DataSeek);
$ipData2 = fread($fd, 4);
if(strlen($ipData2) < 4) {
fclose($fd);
return '- System Error';
}
$ip2num = implode('', unpack('L', $ipData2));
if($ip2num < 0) $ip2num += pow(2, 32);

if($ip2num < $ipNum) {
if($Middle == $BeginNum) {
fclose($fd);
return '- Unknown';
}
$BeginNum = $Middle;
}
}

$ipFlag = fread($fd, 1);
if($ipFlag == chr(1)) {
$ipSeek = fread($fd, 3);
if(strlen($ipSeek) < 3) {
fclose($fd);
return '- System Error';
}
$ipSeek = implode('', unpack('L', $ipSeek.chr(0)));
fseek($fd, $ipSeek);
$ipFlag = fread($fd, 1);
}

if($ipFlag == chr(2)) {
$AddrSeek = fread($fd, 3);
if(strlen($AddrSeek) < 3) {
fclose($fd);
return '- System Error';
}
$ipFlag = fread($fd, 1);
if($ipFlag == chr(2)) {
$AddrSeek2 = fread($fd, 3);
if(strlen($AddrSeek2) < 3) {
fclose($fd);
return '- System Error';
}
$AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
fseek($fd, $AddrSeek2);
} else {
fseek($fd, -1, SEEK_CUR);
}

while(($char = fread($fd, 1)) != chr(0))
$ipAddr2 .= $char;

$AddrSeek = implode('', unpack('L', $AddrSeek.chr(0)));
fseek($fd, $AddrSeek);

while(($char = fread($fd, 1)) != chr(0))
$ipAddr1 .= $char;
} else {
fseek($fd, -1, SEEK_CUR);
while(($char = fread($fd, 1)) != chr(0))
$ipAddr1 .= $char;

$ipFlag = fread($fd, 1);
if($ipFlag == chr(2)) {
$AddrSeek2 = fread($fd, 3);
if(strlen($AddrSeek2) < 3) {
fclose($fd);
return '- System Error';
}
$AddrSeek2 = implode('', unpack('L', $AddrSeek2.chr(0)));
fseek($fd, $AddrSeek2);
} else {
fseek($fd, -1, SEEK_CUR);
}
while(($char = fread($fd, 1)) != chr(0))
$ipAddr2 .= $char;
}
fclose($fd);

if(preg_match('/http/i', $ipAddr2)) {
$ipAddr2 = '';
}
$ipaddr = "$ipAddr1 $ipAddr2";
$ipaddr = preg_replace('/CZ88\.NET/is', '', $ipaddr);
$ipaddr = preg_replace('/^\s*/is', '', $ipaddr);
$ipaddr = preg_replace('/\s*$/is', '', $ipaddr);
if(preg_match('/http/i', $ipaddr) || $ipaddr == '') {
$ipaddr = '- Unknown';
}

return mb_convert_encoding($ipaddr,"utf-8","gb2312");

}
?>
这样,访问明细的功能就完成了。

AttachmentSize
Drupal模块开发实例(2).zip4.5 KB

谢谢提供这么详细的例子,另外,第二块php代码显示有点问题

谢谢提供这么详细的例子,另外,第二块php代码显示有点问题,好像多了一个?>

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <img> <span> <h1> <h2> <h3> <h4>
  • Lines and paragraphs break automatically.
  • You can use BBCode tags in the text. URLs will automatically be converted to links.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

同步内容