mirror of
https://github.com/kokororin/typecho-plugin-Access.git
synced 2025-02-22 01:30:46 +08:00
commit
06cd5fd799
364
Access_Core.php
364
Access_Core.php
@ -6,89 +6,107 @@ if (!defined('__ACCESS_PLUGIN_ROOT__')) {
|
||||
class Access_Core
|
||||
{
|
||||
protected $db;
|
||||
protected $prefix;
|
||||
protected $table;
|
||||
public $config;
|
||||
protected $response;
|
||||
protected $request;
|
||||
protected $pageSize;
|
||||
protected $isDrop;
|
||||
public $parser;
|
||||
protected $response;
|
||||
|
||||
public $ua;
|
||||
public $config;
|
||||
public $action;
|
||||
public $title;
|
||||
public $logs = array();
|
||||
public $overview = array();
|
||||
public $referer = array();
|
||||
|
||||
/**
|
||||
* 构造函数,根据不同类型的请求,计算不同的数据并渲染输出
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->db = Typecho_Db::get();
|
||||
$this->prefix = $this->db->getPrefix();
|
||||
$this->table = $this->prefix . 'access';
|
||||
$this->config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
$this->response = Typecho_Response::getInstance();
|
||||
$this->request = Typecho_Request::getInstance();
|
||||
$this->pageSize = $this->config->pageSize;
|
||||
$this->isDrop = $this->config->isDrop;
|
||||
if ($this->pageSize == null || $this->isDrop == null) {
|
||||
throw new Typecho_Plugin_Exception('请先设置插件!');
|
||||
# Load language pack
|
||||
if (Typecho_I18n::getLang() != 'zh_CN') {
|
||||
$file = __TYPECHO_ROOT_DIR__ . __TYPECHO_PLUGIN_DIR__ .
|
||||
'/Access/lang/' . Typecho_I18n::getLang() . '.mo';
|
||||
file_exists($file) && Typecho_I18n::addLang($file);
|
||||
}
|
||||
$this->parser = new Access_Parser();
|
||||
# Init variables
|
||||
$this->db = Typecho_Db::get();
|
||||
$this->config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
$this->request = Typecho_Request::getInstance();
|
||||
$this->response = Typecho_Response::getInstance();
|
||||
if ($this->config->pageSize == null || $this->config->isDrop == null) {
|
||||
throw new Typecho_Plugin_Exception(_t('请先设置插件!'));
|
||||
}
|
||||
$this->ua = new Access_UA($this->request->getAgent());
|
||||
switch ($this->request->get('action')) {
|
||||
case 'logs':
|
||||
default:
|
||||
$this->action = 'logs';
|
||||
$this->title = '访问日志';
|
||||
$this->parseLogs();
|
||||
break;
|
||||
case 'overview':
|
||||
$this->action = 'overview';
|
||||
$this->title = '访问概览';
|
||||
$this->title = _t('访问概览');
|
||||
$this->parseOverview();
|
||||
$this->parseReferer();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getWhere($type)
|
||||
{
|
||||
$where_str = '';
|
||||
foreach ($this->parser->bots as $value) {
|
||||
$where_str .= "replace(LOWER(`ua`), ' ', '') {1} LIKE " . "'%{$this->parser->filter($value)}%' {2} ";
|
||||
}
|
||||
$where_str = rtrim($where_str, '{2} ');
|
||||
switch ($type) {
|
||||
case 1:
|
||||
$where = str_replace('{1}', 'NOT', $where_str);
|
||||
$where = str_replace('{2}', 'and', $where);
|
||||
break;
|
||||
case 2:
|
||||
$where = str_replace('{1}', '', $where_str);
|
||||
$where = str_replace('{2}', 'or', $where);
|
||||
break;
|
||||
case 3:
|
||||
$where = '1=1';
|
||||
break;
|
||||
case 'logs':
|
||||
default:
|
||||
throw new Typecho_Plugin_Exception('参数不正确!');
|
||||
$this->action = 'logs';
|
||||
$this->title = _t('访问日志');
|
||||
$this->parseLogs();
|
||||
break;
|
||||
}
|
||||
return 'WHERE ' . $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成详细访问日志数据,提供给页面渲染使用
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
protected function parseLogs()
|
||||
{
|
||||
$type = $this->request->get('type', 1);
|
||||
$p = $this->request->get('page', 1);
|
||||
$offset = (max(intval($p), 1) - 1) * $this->pageSize;
|
||||
$where = $this->getWhere($type);
|
||||
$pagenum = $this->request->get('page', 1);
|
||||
$offset = (max(intval($pagenum), 1) - 1) * $this->config->pageSize;
|
||||
$query = $this->db->select()->from('table.access_log')
|
||||
->order('time', Typecho_Db::SORT_DESC)
|
||||
->offset($offset)->limit($this->config->pageSize);
|
||||
$qcount = $this->db->select('count(1) AS count')->from('table.access_log');
|
||||
switch ($type) {
|
||||
case 1:
|
||||
$query->where('robot = ?', 0);
|
||||
$qcount->where('robot = ?', 0);
|
||||
break;
|
||||
case 2:
|
||||
$query->where('robot = ?', 1);
|
||||
$qcount->where('robot = ?', 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$this->logs['list'] = $this->db->fetchAll($query);
|
||||
foreach ($this->logs['list'] as &$row) {
|
||||
$ua = new Access_UA($row['ua']);
|
||||
if ($ua->isRobot()) {
|
||||
$name = $ua->getRobotID();
|
||||
$version = $ua->getRobotVersion();
|
||||
} else {
|
||||
$name = $ua->getBrowserName();
|
||||
$version = $ua->getBrowserVersion();
|
||||
}
|
||||
if ($name == '') {
|
||||
$row['display_name'] = _t('未知');
|
||||
} elseif ($version == '') {
|
||||
$row['display_name'] = $name;
|
||||
} else {
|
||||
$row['display_name'] = $name . ' / ' . $version;
|
||||
}
|
||||
}
|
||||
|
||||
$this->logs['list'] = $this->db->fetchAll("SELECT * FROM {$this->table} {$where} ORDER BY id DESC LIMIT {$this->pageSize} OFFSET {$offset}");
|
||||
$this->htmlEncode($this->logs['list']);
|
||||
|
||||
$this->cleanArray($this->logs['list']);
|
||||
|
||||
$this->logs['rows'] = count($this->db->fetchAll("SELECT * FROM {$this->table} {$where}"));
|
||||
|
||||
$page = new Access_Page($this->pageSize, $this->logs['rows'], $p, 10, array(
|
||||
$this->logs['rows'] = $this->db->fetchAll($qcount)[0]['count'];
|
||||
|
||||
$page = new Access_Page($this->config->pageSize, $this->logs['rows'], $pagenum, 10, array(
|
||||
'panel' => Access_Plugin::$panel,
|
||||
'action' => 'logs',
|
||||
'type' => $type,
|
||||
@ -96,85 +114,105 @@ class Access_Core
|
||||
$this->logs['page'] = $page->show();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成来源统计数据,提供给页面渲染使用
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
protected function parseReferer()
|
||||
{
|
||||
$this->referer['url'] = $this->db->fetchAll("SELECT DISTINCT referer, COUNT(*) as count FROM {$this->table} WHERE referer <> '' GROUP BY referer ORDER BY count DESC LIMIT {$this->pageSize}");
|
||||
$this->referer['domain'] = $this->db->fetchAll("SELECT DISTINCT referer_domain, COUNT(*) as count FROM {$this->table} WHERE referer_domain <> '' GROUP BY referer_domain ORDER BY count DESC LIMIT {$this->pageSize}");
|
||||
$this->cleanArray($this->referer);
|
||||
$this->referer['url'] = $this->db->fetchAll($this->db->select('DISTINCT entrypoint AS value, COUNT(1) as count')
|
||||
->from('table.access_log')->where("entrypoint <> ''")->group('entrypoint')
|
||||
->order('count', Typecho_Db::SORT_DESC)->limit($this->config->pageSize));
|
||||
$this->referer['domain'] = $this->db->fetchAll($this->db->select('DISTINCT entrypoint_domain AS value, COUNT(1) as count')
|
||||
->from('table.access_log')->where("entrypoint_domain <> ''")->group('entrypoint_domain')
|
||||
->order('count', Typecho_Db::SORT_DESC)->limit($this->config->pageSize));
|
||||
$this->htmlEncode($this->referer);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成总览数据,提供给页面渲染使用
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
protected function parseOverview()
|
||||
{
|
||||
|
||||
$where = 'WHERE 1=1';
|
||||
|
||||
$this->overview['ip']['today']['total'] = 0;
|
||||
$this->overview['uv']['today']['total'] = 0;
|
||||
$this->overview['pv']['today']['total'] = 0;
|
||||
$this->overview['ip']['yesterday']['total'] = 0;
|
||||
$this->overview['uv']['yesterday']['total'] = 0;
|
||||
$this->overview['pv']['yesterday']['total'] = 0;
|
||||
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$today = date("Y-m-d");
|
||||
$start = strtotime(date("{$today} {$i}:00:00"));
|
||||
$end = strtotime(date("{$today} {$i}:59:59"));
|
||||
$this->overview['ip']['today']['hours'][] = count($this->db->fetchAll("SELECT DISTINCT ip FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['ip']['today']['total'] += $this->overview['ip']['today']['hours'][$i];
|
||||
$this->overview['uv']['today']['hours'][] = count($this->db->fetchAll("SELECT DISTINCT ip,ua FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['uv']['today']['total'] += $this->overview['uv']['today']['hours'][$i];
|
||||
$this->overview['pv']['today']['hours'][] = count($this->db->fetchAll("SELECT ip FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['pv']['today']['total'] += $this->overview['pv']['today']['hours'][$i];
|
||||
}
|
||||
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$yesterday = date("Y-m-d", time() - 24 * 60 * 60);
|
||||
$start = strtotime(date("{$yesterday} {$i}:00:00"));
|
||||
$end = strtotime(date("{$yesterday} {$i}:59:59"));
|
||||
$this->overview['ip']['yesterday']['hours'][] = count($this->db->fetchAll("SELECT DISTINCT ip FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['ip']['yesterday']['total'] += $this->overview['ip']['yesterday']['hours'][$i];
|
||||
$this->overview['uv']['yesterday']['hours'][] = count($this->db->fetchAll("SELECT DISTINCT ip,ua FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['uv']['yesterday']['total'] += $this->overview['uv']['yesterday']['hours'][$i];
|
||||
$this->overview['pv']['yesterday']['hours'][] = count($this->db->fetchAll("SELECT ip FROM {$this->table} {$where} AND date BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['pv']['yesterday']['total'] += $this->overview['pv']['yesterday']['hours'][$i];
|
||||
}
|
||||
|
||||
$this->overview['ip']['all']['total'] = count($this->db->fetchAll("SELECT DISTINCT ip FROM {$this->table} {$where}"));
|
||||
$this->overview['uv']['all']['total'] = count($this->db->fetchAll("SELECT DISTINCT ip,ua FROM {$this->table} {$where}"));
|
||||
$this->overview['pv']['all']['total'] = count($this->db->fetchAll("SELECT ip FROM {$this->table} {$where}"));
|
||||
|
||||
$this->overview['chart']['title']['text'] = date("Y-m-d 统计");
|
||||
$this->overview['chart']['xAxis']['categories'] = $this->buildObject(array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23), true);
|
||||
$this->overview['chart']['series']['pv'] = $this->buildObject($this->overview['pv']['today']['hours'], false);
|
||||
$this->overview['chart']['series']['uv'] = $this->buildObject($this->overview['uv']['today']['hours'], false);
|
||||
$this->overview['chart']['series']['ip'] = $this->buildObject($this->overview['ip']['today']['hours'], false);
|
||||
|
||||
}
|
||||
|
||||
protected function cleanArray(&$array)
|
||||
{
|
||||
if (is_array($array)) {
|
||||
foreach ($array as &$value) {
|
||||
if (!is_array($value)) {
|
||||
$value = htmlspecialchars(urldecode($value));
|
||||
} else {
|
||||
$this->cleanArray($value);
|
||||
}
|
||||
# 初始化统计数组
|
||||
foreach (['ip', 'uv', 'pv'] as $type) {
|
||||
foreach (['today', 'yesterday'] as $day) {
|
||||
$this->overview[$type][$day]['total'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
# 分类分时段统计数据
|
||||
foreach (['today' => date("Y-m-d"), 'yesterday'=> date("Y-m-d", time() - 24 * 60 * 60)] as $day => $time) {
|
||||
for ($i = 0; $i < 24; $i++) {
|
||||
$time = date("Y-m-d");
|
||||
$start = strtotime(date("{$time} {$i}:00:00"));
|
||||
$end = strtotime(date("{$time} {$i}:59:59"));
|
||||
// "SELECT DISTINCT ip FROM {$this->table} {$where} AND `time` BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['ip'][$day]['hours'][$i] = intval($this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('(' . $this->db->select('DISTINCT ip')->from('table.access_log')
|
||||
->where('time >= ? AND time <= ?', $start, $end) . ') AS tmp'))[0]['count']);
|
||||
$this->overview['ip'][$day]['total'] += $this->overview['ip'][$day]['hours'][$i];
|
||||
// "SELECT DISTINCT ip,ua FROM {$this->table} {$where} AND `time` BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['uv'][$day]['hours'][$i] = intval($this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('(' . $this->db->select('DISTINCT ip,ua')->from('table.access_log')
|
||||
->where('time >= ? AND time <= ?', $start, $end) . ') AS tmp'))[0]['count']);
|
||||
$this->overview['uv'][$day]['total'] += $this->overview['uv'][$day]['hours'][$i];
|
||||
// "SELECT ip FROM {$this->table} {$where} AND `time` BETWEEN {$start} AND {$end}"));
|
||||
$this->overview['pv'][$day]['hours'][$i] = intval($this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('table.access_log')->where('time >= ? AND time <= ?', $start, $end))[0]['count']);
|
||||
$this->overview['pv'][$day]['total'] += $this->overview['pv'][$day]['hours'][$i];
|
||||
}
|
||||
}
|
||||
|
||||
# 总统计数据
|
||||
// "SELECT DISTINCT ip FROM {$this->table} {$where}"));
|
||||
$this->overview['ip']['all']['total'] = $this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('(' . $this->db->select('DISTINCT ip')->from('table.access_log') . ') AS tmp'))[0]['count'];
|
||||
// "SELECT DISTINCT ip,ua FROM {$this->table} {$where}"));
|
||||
$this->overview['uv']['all']['total'] = $this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('(' . $this->db->select('DISTINCT ip,ua')->from('table.access_log') . ') AS tmp'))[0]['count'];
|
||||
// "SELECT ip FROM {$this->table} {$where}"));
|
||||
$this->overview['pv']['all']['total'] = $this->db->fetchAll($this->db->select('COUNT(1) AS count')
|
||||
->from('table.access_log'))[0]['count'];
|
||||
|
||||
# 分类型绘制24小时访问图
|
||||
$this->overview['chart']['xAxis']['categories'] = json_encode([
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23
|
||||
]);
|
||||
foreach (['ip', 'uv', 'pv'] as $type) {
|
||||
$this->overview['chart']['series'][$type] = json_encode($this->overview[$type]['today']['hours']);
|
||||
}
|
||||
$this->overview['chart']['title']['text'] = _t('%s 统计', date("Y-m-d"));
|
||||
}
|
||||
|
||||
protected function buildObject($array, $quote)
|
||||
/**
|
||||
* 转义特殊字符,防止XSS等攻击
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
protected function htmlEncode(&$variable)
|
||||
{
|
||||
$obj = Json::encode($array);
|
||||
$obj = str_replace("\"", "'", $obj);
|
||||
if ($quote) {
|
||||
return $obj;
|
||||
} else {
|
||||
return str_replace("'", '', $obj);
|
||||
if (is_array($variable)) {
|
||||
foreach ($variable as &$value) {
|
||||
$this->htmlEncode($value);
|
||||
}
|
||||
} elseif (is_string($variable)) {
|
||||
$variable = htmlspecialchars(urldecode($variable));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否是管理员登录状态
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isAdmin()
|
||||
{
|
||||
$hasLogin = Typecho_Widget::widget('Widget_User')->hasLogin();
|
||||
@ -185,58 +223,88 @@ class Access_Core
|
||||
return $isAdmin;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除记录
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function deleteLogs($ids)
|
||||
{
|
||||
foreach ($ids as $id) {
|
||||
$this->db->query($this->db->delete($this->table)
|
||||
->where('id = ?', $id)
|
||||
$this->db->query($this->db->delete('table.access_log')
|
||||
->where('id = ?', $id)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function getReferer()
|
||||
/**
|
||||
* 获取首次进入网站时的来源
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getEntryPoint()
|
||||
{
|
||||
$referer = Typecho_Cookie::get('__typecho_access_referer');
|
||||
if ($referer == null) {
|
||||
$referer = $this->request->getReferer();
|
||||
if (strpos($referer, rtrim(Helper::options()->siteUrl, '/')) !== false) {
|
||||
$referer = null;
|
||||
$entrypoint = Typecho_Cookie::get('__typecho_access_entrypoint');
|
||||
if ($entrypoint == null) {
|
||||
$entrypoint = $this->request->getReferer();
|
||||
if (strpos($entrypoint, rtrim(Helper::options()->siteUrl, '/')) !== false) {
|
||||
$entrypoint = null;
|
||||
}
|
||||
if ($referer != null) {
|
||||
Typecho_Cookie::set('__typecho_access_referer', $referer);
|
||||
if ($entrypoint != null) {
|
||||
Typecho_Cookie::set('__typecho_access_entrypoint', $entrypoint);
|
||||
}
|
||||
}
|
||||
return $referer;
|
||||
return $entrypoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* 记录当前访问(管理员登录不会记录)
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function writeLogs($url = null)
|
||||
{
|
||||
if ($this->isAdmin()) {
|
||||
return;
|
||||
}
|
||||
$ip = $this->request->getIp();
|
||||
if ($url == null) {
|
||||
$url = $this->request->getServer('REQUEST_URI');
|
||||
}
|
||||
$ip = $this->request->getIp();
|
||||
if ($ip == null) {
|
||||
$ip = 'UnKnown';
|
||||
$ip = '0.0.0.0';
|
||||
}
|
||||
|
||||
$timeStamp = Helper::options()->gmtTime;
|
||||
$offset = Helper::options()->timezone - Helper::options()->serverTimezone;
|
||||
$gtime = $timeStamp + $offset;
|
||||
$referer = $this->getReferer();
|
||||
$ip = bindec(decbin(ip2long($ip)));
|
||||
|
||||
$entrypoint = $this->getEntryPoint();
|
||||
$referer = $this->request->getReferer();
|
||||
$time = Helper::options()->gmtTime + (Helper::options()->timezone - Helper::options()->serverTimezone);
|
||||
$rows = array(
|
||||
'ua' => $this->request->getAgent(),
|
||||
'url' => $url,
|
||||
'ip' => $ip,
|
||||
'referer' => $referer,
|
||||
'referer_domain' => parse_url($referer, PHP_URL_HOST),
|
||||
'date' => $gtime,
|
||||
'ua' => $this->ua->getUA(),
|
||||
'browser_id' => $this->ua->getBrowserID(),
|
||||
'browser_version' => $this->ua->getBrowserVersion(),
|
||||
'os_id' => $this->ua->getOSID(),
|
||||
'os_version' => $this->ua->getOSVersion(),
|
||||
'url' => $url,
|
||||
'path' => parse_url($url, PHP_URL_PATH),
|
||||
'query_string' => parse_url($url, PHP_URL_QUERY),
|
||||
'ip' => $ip,
|
||||
'referer' => $referer,
|
||||
'referer_domain' => parse_url($referer, PHP_URL_HOST),
|
||||
'entrypoint' => $entrypoint,
|
||||
'entrypoint_domain' => parse_url($entrypoint, PHP_URL_HOST),
|
||||
'time' => $time,
|
||||
// 'content_id' => ,
|
||||
'robot' => $this->ua->isRobot() ? 1 : 0,
|
||||
'robot_id' => $this->ua->getRobotID(),
|
||||
'robot_version' => $this->ua->getRobotVersion(),
|
||||
);
|
||||
|
||||
try {
|
||||
$this->db->query($this->db->insert('table.access')->rows($rows));
|
||||
$this->db->query($this->db->insert('table.access_log')->rows($rows));
|
||||
} catch (Exception $e) {} catch (Typecho_Db_Query_Exception $e) {}
|
||||
}
|
||||
|
||||
|
@ -1,163 +0,0 @@
|
||||
<?php
|
||||
if (!defined('__ACCESS_PLUGIN_ROOT__')) {
|
||||
throw new Exception('Boostrap file not found');
|
||||
}
|
||||
|
||||
class Access_Parser
|
||||
{
|
||||
public $bots = array(
|
||||
'TencentTraveler',
|
||||
'Baiduspider',
|
||||
'BaiduGame',
|
||||
'Googlebot',
|
||||
'msnbot',
|
||||
'Sosospider+',
|
||||
'Sogou web spider',
|
||||
'ia_archiver',
|
||||
'Yahoo! Slurp',
|
||||
'YoudaoBot',
|
||||
'Yahoo Slurp',
|
||||
'MSNBot',
|
||||
'Java (Often spam bot)',
|
||||
'BaiDuSpider',
|
||||
'Voila',
|
||||
'Yandex bot',
|
||||
'BSpider',
|
||||
'twiceler',
|
||||
'Sogou Spider',
|
||||
'Speedy Spider',
|
||||
'Google AdSense',
|
||||
'Heritrix',
|
||||
'Python-urllib',
|
||||
'Alexa (IA Archiver)',
|
||||
'Ask',
|
||||
'Exabot',
|
||||
'Custo',
|
||||
'OutfoxBot/YodaoBot',
|
||||
'yacy',
|
||||
'SurveyBot',
|
||||
'legs',
|
||||
'lwp-trivial',
|
||||
'Nutch',
|
||||
'StackRambler',
|
||||
'The web archive (IA Archiver)',
|
||||
'Perl tool',
|
||||
'MJ12bot',
|
||||
'Netcraft',
|
||||
'MSIECrawler',
|
||||
'WGet tools',
|
||||
'larbin',
|
||||
'Fish search',
|
||||
'crawler',
|
||||
'bingbot',
|
||||
'YisouSpider',
|
||||
'Bot',
|
||||
'Spider',
|
||||
);
|
||||
|
||||
protected $currentBot = null;
|
||||
|
||||
public function getBrowser($ua)
|
||||
{
|
||||
$os = null;
|
||||
if ($this->isBot($ua)) {
|
||||
return $this->currentBot;
|
||||
} elseif (preg_match('/Windows NT 6.0/i', $ua)) {
|
||||
$os = 'Windows Vista';
|
||||
} elseif (preg_match('/Windows NT 6.1/i', $ua)) {
|
||||
$os = 'Windows 7';
|
||||
} elseif (preg_match('/Windows NT 6.2/i', $ua)) {
|
||||
$os = 'Windows 8';
|
||||
} elseif (preg_match('/Windows NT 6.3/i', $ua)) {
|
||||
$os = 'Windows 8.1';
|
||||
} elseif (preg_match('/Windows NT 10.0/i', $ua)) {
|
||||
$os = 'Windows 10';
|
||||
} elseif (preg_match('/Windows NT 5.1/i', $ua)) {
|
||||
$os = 'Windows XP';
|
||||
} elseif (preg_match('/Windows NT 5.2/i', $ua) && preg_match('/Win64/i', $ua)) {
|
||||
$os = 'Windows XP 64 bit';
|
||||
} elseif (preg_match('/Android ([0-9.]+)/i', $ua, $matches)) {
|
||||
$os = 'Android ' . $matches[1];
|
||||
} elseif (preg_match('/iPhone OS ([_0-9]+)/i', $ua, $matches)) {
|
||||
$os = 'iPhone ' . $matches[1];
|
||||
} elseif (preg_match('/Ubuntu/i', $ua, $matches)) {
|
||||
$os = 'Ubuntu ';
|
||||
} elseif (preg_match('/Mac OS X ([0-9_]+)/i', $ua, $matches)) {
|
||||
$os = 'Mac OS X ' . $matches[1];
|
||||
} elseif (preg_match('/Linux/i', $ua, $matches)) {
|
||||
$os = 'Linux';
|
||||
} else {
|
||||
$os = '未知';
|
||||
}
|
||||
|
||||
if ($this->isBot($ua)) {
|
||||
return $this->currentBot;
|
||||
} elseif (preg_match('#(Camino|Chimera)[ /]([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Camino ' . $matches[2];
|
||||
} elseif (preg_match('#SE 2([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = '搜狗浏览器 2' . $matches[1];
|
||||
} elseif (preg_match('#360([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = '360浏览器 ' . $matches[1];
|
||||
} elseif (preg_match('#Maxthon( |\/)([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Maxthon ' . $matches[2];
|
||||
} elseif (preg_match('#Edge/([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
//Win10中Microsoft Edge浏览器
|
||||
$browser = 'Edge ' . $matches[1];
|
||||
} elseif (preg_match('#Chrome/([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Chrome ' . $matches[1];
|
||||
} elseif (preg_match('#XiaoMi/MiuiBrowser/([0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = '小米浏览器 ' . $matches[1];
|
||||
} elseif (preg_match('#Safari/([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Safari ' . $matches[1];
|
||||
} elseif (preg_match('#opera mini#i', $ua)) {
|
||||
preg_match('#Opera/([a-zA-Z0-9.]+)#i', $ua, $matches);
|
||||
$browser = 'Opera Mini ' . $matches[1];
|
||||
} elseif (preg_match('#Opera.([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Opera ' . $matches[1];
|
||||
} elseif (preg_match('#TencentTraveler ([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = '腾讯TT浏览器 ' . $matches[1];
|
||||
} elseif (preg_match('#UCWEB([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'UCWEB ' . $matches[1];
|
||||
} elseif (preg_match('#MSIE ([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Internet Explorer ' . $matches[1];
|
||||
} elseif (preg_match('#Trident#', $ua, $matches)) {
|
||||
$browser = 'Internet Explorer 11';
|
||||
} elseif (preg_match('#(Firefox|Phoenix|Firebird|BonEcho|GranParadiso|Minefield|Iceweasel)/([a-zA-Z0-9.]+)#i', $ua, $matches)) {
|
||||
$browser = 'Firefox ' . $matches[2];
|
||||
} else {
|
||||
$browser = '未知';
|
||||
}
|
||||
return $os . ' / ' . $browser;
|
||||
}
|
||||
|
||||
public function isBot($ua)
|
||||
{
|
||||
$ua = $this->filter($ua);
|
||||
if (!empty($ua)) {
|
||||
foreach ($this->bots as $val) {
|
||||
if (($val == 'Bot' || $val == 'Spider')
|
||||
&& (preg_match('#([a-zA-Z0-9]+(bot|spider))[ /]*([0-9.]*)#i', $ua, $matches))) {
|
||||
$this->currentBot = $matches[1] . ' ' . $matches[3];
|
||||
return true;
|
||||
}
|
||||
$str = $this->filter($val);
|
||||
if (strpos($ua, $str) !== false) {
|
||||
$this->currentBot = $str;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function filter($str)
|
||||
{
|
||||
return $this->removeSpace(strtolower($str));
|
||||
}
|
||||
|
||||
protected function removeSpace($str)
|
||||
{
|
||||
return preg_replace('/\s+/', '', $str);
|
||||
}
|
||||
}
|
324
Access_UA.php
Normal file
324
Access_UA.php
Normal file
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
if (!defined('__ACCESS_PLUGIN_ROOT__')) {
|
||||
throw new Exception('Boostrap file not found');
|
||||
}
|
||||
|
||||
class Access_UA
|
||||
{
|
||||
private static $robots = array(
|
||||
'TencentTraveler',
|
||||
'Baiduspider',
|
||||
'BaiduGame',
|
||||
'Googlebot',
|
||||
'msnbot',
|
||||
'Sosospider+',
|
||||
'Sogou web spider',
|
||||
'ia_archiver',
|
||||
'Yahoo! Slurp',
|
||||
'YoudaoBot',
|
||||
'Yahoo Slurp',
|
||||
'MSNBot',
|
||||
'Java (Often spam bot)',
|
||||
'BaiDuSpider',
|
||||
'Voila',
|
||||
'Yandex bot',
|
||||
'BSpider',
|
||||
'twiceler',
|
||||
'Sogou Spider',
|
||||
'Speedy Spider',
|
||||
'Google AdSense',
|
||||
'Heritrix',
|
||||
'Python-urllib',
|
||||
'Alexa (IA Archiver)',
|
||||
'Ask',
|
||||
'Exabot',
|
||||
'Custo',
|
||||
'OutfoxBot/YodaoBot',
|
||||
'yacy',
|
||||
'SurveyBot',
|
||||
'legs',
|
||||
'lwp-trivial',
|
||||
'Nutch',
|
||||
'StackRambler',
|
||||
'The web archive (IA Archiver)',
|
||||
'Perl tool',
|
||||
'MJ12bot',
|
||||
'Netcraft',
|
||||
'MSIECrawler',
|
||||
'WGet tools',
|
||||
'larbin',
|
||||
'Fish search',
|
||||
'crawler',
|
||||
'bingbot',
|
||||
'YisouSpider',
|
||||
);
|
||||
private $ua;
|
||||
private $ual;
|
||||
|
||||
private $osID = null;
|
||||
private $osName = null;
|
||||
private $osVersion = null;
|
||||
|
||||
private $robotID = null;
|
||||
private $robotName = null;
|
||||
private $robotVersion = null;
|
||||
|
||||
private $browserID = null;
|
||||
private $browserName = null;
|
||||
private $browserVersion = null;
|
||||
|
||||
function __construct($ua) {
|
||||
$this->ua = $ua;
|
||||
$this->ual = $this->filter($ua);
|
||||
}
|
||||
|
||||
public static function filter($str)
|
||||
{
|
||||
return self::removeSpace(strtolower($str));
|
||||
}
|
||||
|
||||
protected static function removeSpace($str)
|
||||
{
|
||||
return preg_replace('/\s+/', '', $str);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整UA信息
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getUA() {
|
||||
return $this->ua;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否是爬虫
|
||||
*
|
||||
* @access public
|
||||
* @return bool
|
||||
*/
|
||||
public function isRobot()
|
||||
{
|
||||
if ($this->robotID === null) {
|
||||
if (!empty($this->ua)) {
|
||||
if (preg_match('#([a-zA-Z0-9]+\s*(?:bot|spider))[ /]*([0-9.]*)#i', $this->ua, $matches)) {
|
||||
$this->robotID = $this->robotName = $matches[1];
|
||||
$this->robotVersion = $matches[2];
|
||||
}
|
||||
foreach (self::$robots as $val) {
|
||||
if (strpos($this->ual, $this->filter($val)) !== false) {
|
||||
$this->robotID = $this->robotName = $val;
|
||||
$this->robotVersion = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($this->robotID == null) $this->robotID = '';
|
||||
if ($this->robotName == null) $this->robotName = '';
|
||||
if ($this->robotVersion == null) $this->robotVersion = '';
|
||||
}
|
||||
return $this->robotID !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取爬虫ID
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRobotID()
|
||||
{
|
||||
return $this->isRobot() ? $this->robotID : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取爬虫版本
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getRobotVersion()
|
||||
{
|
||||
return $this->isRobot() ? $this->robotVersion : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析操作系统信息
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function parseOS()
|
||||
{
|
||||
if ($this->osID === null) {
|
||||
if (preg_match('/Windows NT 6.0/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = 'Vista';
|
||||
} elseif (preg_match('/Windows NT 6.1/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = '7';
|
||||
} elseif (preg_match('/Windows NT 6.2/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = '8';
|
||||
} elseif (preg_match('/Windows NT 6.3/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = '8.1';
|
||||
} elseif (preg_match('/Windows NT 10.0/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = '10';
|
||||
} elseif (preg_match('/Windows NT 5.1/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = 'XP';
|
||||
} elseif (preg_match('/Windows NT 5.2/i', $this->ua) && preg_match('/Win64/i', $this->ua)) {
|
||||
$this->osID = $this->osName = 'Windows';
|
||||
$this->osVersion = 'XP (64 bit)';
|
||||
} elseif (preg_match('/Android ([0-9.]+)/i', $this->ua, $matches)) {
|
||||
$this->osID = $this->osName = 'Android';
|
||||
$this->osVersion = $matches[1];
|
||||
} elseif (preg_match('/iPhone OS ([_0-9]+)/i', $this->ua, $matches)) {
|
||||
$this->osID = $this->osName = 'iPhone OS';
|
||||
$this->osVersion = $matches[1];
|
||||
} elseif (preg_match('/Ubuntu/i', $this->ua, $matches)) {
|
||||
$this->osID = $this->osName = 'Ubuntu';
|
||||
$this->osVersion = '';
|
||||
} elseif (preg_match('/Mac OS X ([0-9_]+)/i', $this->ua, $matches)) {
|
||||
$this->osID = $this->osName = 'Mac OS X';
|
||||
$this->osVersion = $matches[1];
|
||||
} elseif (preg_match('/Linux/i', $this->ua, $matches)) {
|
||||
$this->osID = $this->osName = 'Linux';
|
||||
$this->osVersion = '';
|
||||
} else {
|
||||
$this->osID = '';
|
||||
$this->osName = '';
|
||||
$this->osVersion = '';
|
||||
}
|
||||
}
|
||||
return $this->osID !== '' || $this->osName !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统ID
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getOSID() {
|
||||
return $this->parseOS() ? $this->osID : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统名字
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getOSName() {
|
||||
return $this->parseOS() ? $this->osName : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取操作系统版本号
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getOSVersion() {
|
||||
return $this->parseOS() ? $this->osVersion : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析浏览器信息
|
||||
*
|
||||
* @access private
|
||||
* @return bool
|
||||
*/
|
||||
private function parseBrowser() {
|
||||
if ($this->browserName === null) {
|
||||
if (preg_match('#(Camino|Chimera)[ /]([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Camino';
|
||||
$this->browserVersion = $matches[2];
|
||||
} elseif (preg_match('#SE 2([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = 'SE 2';
|
||||
$this->browserName = '搜狗浏览器 2';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#360([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = '360';
|
||||
$this->browserName = '360浏览器';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#Maxthon( |\/)([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Maxthon';
|
||||
$this->browserVersion = $matches[2];
|
||||
} elseif (preg_match('#Edge/([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Edge';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#Chrome/([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Chrome';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#XiaoMi/MiuiBrowser/([0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = '小米浏览器';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#Safari/([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Safari';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#opera mini#i', $this->ua)) {
|
||||
preg_match('#Opera/([a-zA-Z0-9.]+)#i', $this->ua, $matches);
|
||||
$this->browserID = $this->browserName = 'Opera Mini';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#Opera.([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Opera';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#TencentTraveler ([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = 'TencentTraveler';
|
||||
$this->browserName = '腾讯TT浏览器';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#UCWEB([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'UCWEB';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#MSIE ([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Internet Explorer';
|
||||
$this->browserVersion = $matches[1];
|
||||
} elseif (preg_match('#Trident#', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Internet Explorer';
|
||||
$this->browserVersion = '11';
|
||||
} elseif (preg_match('#(Firefox|Phoenix|Firebird|BonEcho|GranParadiso|Minefield|Iceweasel)/([a-zA-Z0-9.]+)#i', $this->ua, $matches)) {
|
||||
$this->browserID = $this->browserName = 'Firefox';
|
||||
$this->browserVersion = $matches[2];
|
||||
} else {
|
||||
$this->browserID = '';
|
||||
$this->browserName = '';
|
||||
$this->browserVersion = '';
|
||||
}
|
||||
}
|
||||
return $this->browserID !== '' || $this->browserName !== '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器ID
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getBrowserID() {
|
||||
return $this->parseBrowser() ? $this->browserID : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器名字
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getBrowserName() {
|
||||
return $this->parseBrowser() ? $this->browserName : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取浏览器版本号
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
*/
|
||||
public function getBrowserVersion() {
|
||||
return $this->parseBrowser() ? $this->browserVersion : '';
|
||||
}
|
||||
}
|
162
Plugin.php
162
Plugin.php
@ -1,19 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* 获取访客信息
|
||||
* 获取访客信息,生成统计图表,由<a href="https://zhaiyiming.com/">@一名宅</a> 部分优化重构。
|
||||
*
|
||||
* @package Access
|
||||
* @author Kokororin
|
||||
* @version 1.6
|
||||
* @version 2.0.0
|
||||
* @link https://kotori.love
|
||||
*/
|
||||
class Access_Plugin implements Typecho_Plugin_Interface
|
||||
{
|
||||
public const VERSION = 2;
|
||||
public static $panel = 'Access/page/console.php';
|
||||
|
||||
/**
|
||||
* 激活插件方法,如果激活失败,直接抛出异常
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function activate()
|
||||
{
|
||||
$msg = Access_Plugin::install();
|
||||
Helper::addPanel(1, self::$panel, 'Access控制台', 'Access插件控制台', 'subscriber');
|
||||
Helper::addPanel(1, self::$panel, _t('Access控制台'), _t('Access插件控制台'), 'subscriber');
|
||||
Helper::addRoute("access_write_logs", "/access/log/write.json", "Access_Action", 'writeLogs');
|
||||
Helper::addRoute("access_ip", "/access/ip.json", "Access_Action", 'ip');
|
||||
Helper::addRoute("access_delete_logs", "/access/log/delete.json", "Access_Action", 'deleteLogs');
|
||||
@ -23,14 +32,20 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
return _t($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 禁用插件方法,如果禁用失败,直接抛出异常
|
||||
*
|
||||
* @static
|
||||
* @access public
|
||||
* @return void
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function deactivate()
|
||||
{
|
||||
$config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
$isDrop = $config->isDrop;
|
||||
if ($isDrop == 0) {
|
||||
if ($config->isDrop == 0) {
|
||||
$db = Typecho_Db::get();
|
||||
$prefix = $db->getPrefix();
|
||||
$db->query("DROP TABLE `" . $prefix . "access`", Typecho_Db::WRITE);
|
||||
$db->query("DROP TABLE `{$db->getPrefix()}access_log`", Typecho_Db::WRITE);
|
||||
}
|
||||
Helper::removePanel(1, self::$panel);
|
||||
Helper::removeRoute("access_write_logs");
|
||||
@ -38,6 +53,13 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
Helper::removeRoute("access_delete_logs");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取插件配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form 配置面板
|
||||
* @return void
|
||||
*/
|
||||
public static function config(Typecho_Widget_Helper_Form $form)
|
||||
{
|
||||
$pageSize = new Typecho_Widget_Helper_Form_Element_Text(
|
||||
@ -64,67 +86,99 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
$form->addInput($canAnalytize);
|
||||
}
|
||||
|
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* 个人用户的配置面板
|
||||
*
|
||||
* @access public
|
||||
* @param Typecho_Widget_Helper_Form $form
|
||||
* @return void
|
||||
*/
|
||||
public static function personalConfig(Typecho_Widget_Helper_Form $form) { }
|
||||
|
||||
/**
|
||||
* 初始化以及升级插件数据库,如初始化失败,直接抛出异常
|
||||
*
|
||||
* @access public
|
||||
* @return string
|
||||
* @throws Typecho_Plugin_Exception
|
||||
*/
|
||||
public static function install()
|
||||
{
|
||||
$configLink = '<a href="' . Helper::options()->adminUrl . 'options-plugin.php?config=Access' . '">请设置</a>';
|
||||
if (substr(trim(dirname(__FILE__), '/'), -6) != 'Access') {
|
||||
throw new Typecho_Plugin_Exception('插件目录名必须为Access');
|
||||
throw new Typecho_Plugin_Exception(_t('插件目录名必须为Access'));
|
||||
}
|
||||
$installDb = Typecho_Db::get();
|
||||
$type = explode('_', $installDb->getAdapterName());
|
||||
$type = array_pop($type);
|
||||
$prefix = $installDb->getPrefix();
|
||||
$scripts = "CREATE TABLE `typecho_access` (
|
||||
`id` int(10) unsigned NOT NULL auto_increment,
|
||||
`ua` varchar(255) default NULL,
|
||||
`url` varchar(64) default NULL,
|
||||
`ip` varchar(48) default NULL,
|
||||
`referer` varchar(255) default NULL,
|
||||
`referer_domain` varchar(100) default NULL,
|
||||
`date` int(10) unsigned default '0',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=MYISAM DEFAULT CHARSET=%charset%;";
|
||||
$db = Typecho_Db::get();
|
||||
$adapterName = $db->getAdapterName();
|
||||
if (false === strpos($adapterName, 'Mysql')) {
|
||||
throw new Typecho_Plugin_Exception(_t('你的适配器为%s,目前只支持Mysql', $adapterName));
|
||||
}
|
||||
|
||||
$prefix = $db->getPrefix();
|
||||
$scripts = file_get_contents('usr/plugins/Access/sql/Mysql.sql');
|
||||
$scripts = str_replace('typecho_', $prefix, $scripts);
|
||||
$scripts = str_replace('%charset%', 'utf8', $scripts);
|
||||
$scripts = explode(';', $scripts);
|
||||
try {
|
||||
foreach ($scripts as $script) {
|
||||
$script = trim($script);
|
||||
if ($script) {
|
||||
$installDb->query($script, Typecho_Db::WRITE);
|
||||
$configLink = '<a href="' . Helper::options()->adminUrl . 'options-plugin.php?config=Access">' . _t('前往设置') . '</a>';
|
||||
# 初始化数据库如果不存在
|
||||
if (!$db->fetchRow($db->query("SHOW TABLES LIKE '{$prefix}access_log';", Typecho_Db::READ))) {
|
||||
foreach ($scripts as $script) {
|
||||
$script = trim($script);
|
||||
if ($script) {
|
||||
$db->query($script, Typecho_Db::WRITE);
|
||||
}
|
||||
}
|
||||
$msg = _t('成功创建数据表,插件启用成功,') . $configLink;
|
||||
}
|
||||
return '成功创建数据表,插件启用成功,' . $configLink;
|
||||
# 处理旧版本数据
|
||||
if ($db->fetchRow($db->query("SHOW TABLES LIKE '{$prefix}access';", Typecho_Db::READ))) {
|
||||
require_once __DIR__ . '/Access_Bootstrap.php';
|
||||
$rows = $db->fetchAll($db->select()->from('table.access'));
|
||||
foreach ($rows as $row) {
|
||||
$ua = new Access_UA($row['ua']);
|
||||
$time = Helper::options()->gmtTime + (Helper::options()->timezone - Helper::options()->serverTimezone);
|
||||
$row['browser_id' ] = $ua->getBrowserID();
|
||||
$row['browser_version' ] = $ua->getBrowserVersion();
|
||||
$row['os_id' ] = $ua->getOSID();
|
||||
$row['os_version' ] = $ua->getOSVersion();
|
||||
$row['path' ] = parse_url($row['url'], PHP_URL_PATH);
|
||||
$row['query_string' ] = parse_url($row['url'], PHP_URL_QUERY);
|
||||
$row['ip' ] = bindec(decbin(ip2long($row['ip'])));
|
||||
$row['entrypoint' ] = $row['referer'];
|
||||
$row['entrypoint_domain'] = $row['referer_domain'];
|
||||
$row['time' ] = $row['date'];
|
||||
$row['robot' ] = $ua->isRobot() ? 1 : 0;
|
||||
$row['robot_id' ] = $ua->getRobotID();
|
||||
$row['robot_version' ] = $ua->getRobotVersion();
|
||||
unset($row['date']);
|
||||
try {
|
||||
$db->query($db->insert('table.access_log')->rows($row));
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
if ($e->getCode() != 23000)
|
||||
throw new Typecho_Plugin_Exception(_t('导入旧版数据失败,插件启用失败,错误信息:%s。', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
$db->query("DROP TABLE `{$prefix}access`;", Typecho_Db::WRITE);
|
||||
$msg = _t('成功创建数据表并更新数据,插件启用成功,') . $configLink;
|
||||
}
|
||||
return $msg;
|
||||
} catch (Typecho_Db_Exception $e) {
|
||||
$code = $e->getCode();
|
||||
if ($type != 'Mysql') {
|
||||
throw new Typecho_Plugin_Exception('你的适配器为' . $type . ',目前只支持Mysql');
|
||||
}
|
||||
if ($code == (1050 || '42S01')) {
|
||||
$script = 'SELECT * from `' . $prefix . 'access`';
|
||||
$installDb->query($script, Typecho_Db::READ);
|
||||
if (!array_key_exists('referer', $installDb->fetchRow($installDb->select()->from('table.access')))) {
|
||||
$installDb->query('ALTER TABLE `' . $prefix . 'access` ADD `referer` varchar(255) NULL AFTER `ip`, ADD `referer_domain` varchar(100) NULL AFTER `referer`;');
|
||||
return '数据表结构已更新,插件启用成功,' . $configLink;
|
||||
}
|
||||
return '数据表已存在,插件启用成功,' . $configLink;
|
||||
} else {
|
||||
throw new Typecho_Plugin_Exception('数据表建立失败,插件启用失败。错误号:' . $code);
|
||||
}
|
||||
throw new Typecho_Plugin_Exception(_t('数据表建立失败,插件启用失败,错误信息:%s。', $e->getMessage()));
|
||||
} catch (Exception $e) {
|
||||
throw new Typecho_Plugin_Exception($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取后端统计,该统计方法可以统计到一切访问
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public static function backend($archive)
|
||||
{
|
||||
require_once __DIR__ . '/Access_Bootstrap.php';
|
||||
$access = new Access_Core();
|
||||
$access->getReferer();
|
||||
$config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
|
||||
if ($config->writeType == 0) {
|
||||
@ -132,11 +186,19 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取前端统计,该方法要求客户端必须渲染网页,所以不能统计RSS等直接抓取PHP页面的方式
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public static function frontend()
|
||||
{
|
||||
$config = Typecho_Widget::widget('Widget_Options')->plugin('Access');
|
||||
if ($config->writeType == 1) {
|
||||
echo '<script type="text/javascript">(function(){var xhr=new XMLHttpRequest();xhr.open("GET","' . rtrim(Helper::options()->index, '/') . '/access/log/write.json?u="+location.pathname+location.search+location.hash' . ',true);xhr.send();})();</script>';
|
||||
$index = rtrim(Helper::options()->index, '/');
|
||||
echo '<script type="text/javascript">(function(){var xhr=new XMLHttpRequest();xhr.open("GET","' .
|
||||
"{$index}/access/log/write.json?u=\"+location.pathname+location.search+location.hash,true);xhr.send();})();</script>";
|
||||
}
|
||||
}
|
||||
|
||||
@ -148,8 +210,8 @@ class Access_Plugin implements Typecho_Plugin_Interface
|
||||
echo '<script>
|
||||
$(document).ready(function() {
|
||||
$("#start-link").append("<li><a href=\"';
|
||||
Helper::options()->adminUrl('extending.php?panel=' . Access_Plugin::$panel);
|
||||
echo '\">Access控制台</a></li>");
|
||||
Helper::options()->adminUrl('extending.php?panel=' . self::$panel);
|
||||
echo '\">'. _t('Access控制台') . '</a></li>");
|
||||
});
|
||||
</script>';
|
||||
}
|
||||
|
@ -77,10 +77,10 @@ $access = new Access_Core();
|
||||
<tr id="<?php echo $log['id']; ?>" data-id="<?php echo $log['id']; ?>">
|
||||
<td><input type="checkbox" data-id="<?php echo $log['id']; ?>" value="<?php echo $log['id']; ?>" name="id[]"/></td>
|
||||
<td><a target="_blank" href="<?php echo str_replace("%23", "#", $log['url']); ?>"><?php echo urldecode(str_replace("%23", "#", $log['url'])); ?></a></td>
|
||||
<td><a data-action="ua" href="#" title="<?php echo $log['ua'];?>"><?php echo $access->parser->getBrowser($log['ua']); ?></a></td>
|
||||
<td><a data-action="ip" data-ip="<?php echo $log['ip']; ?>" href="#"><?php echo $log['ip']; ?></a></td>
|
||||
<td><a data-action="ua" href="#" title="<?php echo $log['ua'];?>"><?php echo $log['display_name']; ?></a></td>
|
||||
<td><a data-action="ip" data-ip="<?php echo long2ip($log['ip']); ?>" href="#"><?php echo long2ip($log['ip']); ?></a></td>
|
||||
<td><a target="_blank" data-action="referer" href="<?php echo $log['referer']; ?>"><?php echo $log['referer']; ?></a></td>
|
||||
<td><?php echo date('Y-m-d H:i:s',$log['date']); ?></td>
|
||||
<td><?php echo date('Y-m-d H:i:s',$log['time']); ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
@ -184,7 +184,7 @@ $access = new Access_Core();
|
||||
<tr>
|
||||
<td><?php echo $key +1 ?></td>
|
||||
<td><?php echo $value['count']?></td>
|
||||
<td><?php echo $value['referer_domain']?></td>
|
||||
<td><?php echo $value['value']?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
@ -212,7 +212,7 @@ $access = new Access_Core();
|
||||
<tr>
|
||||
<td><?php echo $key +1 ?></td>
|
||||
<td><?php echo $value['count']?></td>
|
||||
<td><?php echo $value['referer']?></td>
|
||||
<td><?php echo $value['value']?></td>
|
||||
</tr>
|
||||
<?php endforeach;?>
|
||||
</tbody>
|
||||
@ -416,4 +416,4 @@ $(document).ready(function() {
|
||||
<?php endif;?>
|
||||
<?php
|
||||
include 'footer.php';
|
||||
?>
|
||||
?>
|
||||
|
38
sql/Mysql.sql
Normal file
38
sql/Mysql.sql
Normal file
@ -0,0 +1,38 @@
|
||||
CREATE TABLE `typecho_access_log` (
|
||||
`id` int(10) unsigned NOT NULL auto_increment,
|
||||
`ua` varchar(255) default '' ,
|
||||
`browser_id` varchar(32) default '' ,
|
||||
`browser_version` varchar(32) default '' ,
|
||||
`os_id` varchar(32) default '' ,
|
||||
`os_version` varchar(32) default '' ,
|
||||
`url` varchar(255) default '' ,
|
||||
`path` varchar(255) default '' ,
|
||||
`query_string` varchar(255) default '' ,
|
||||
`ip` int(32) unsigned default '0' ,
|
||||
`entrypoint` varchar(255) default '' ,
|
||||
`entrypoint_domain` varchar(100) default '' ,
|
||||
`referer` varchar(255) default '' ,
|
||||
`referer_domain` varchar(100) default '' ,
|
||||
`time` int(32) unsigned default '0' ,
|
||||
`content_id` int(10) unsigned default NULL,
|
||||
`meta_id` int(10) unsigned default NULL,
|
||||
`robot` tinyint(1) default '0' ,
|
||||
`robot_id` varchar(32) default '' ,
|
||||
`robot_version` varchar(32) default '' ,
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_time` (`time` ),
|
||||
KEY `idx_path` (`path` ),
|
||||
KEY `idx_ip_ua` (`ip`,`ua` ),
|
||||
KEY `idx_robot` (`robot`, `time` ),
|
||||
KEY `idx_os_id` (`os_id` ),
|
||||
KEY `idx_robot_id` (`robot_id` ),
|
||||
KEY `idx_browser_id` (`browser_id` ),
|
||||
KEY `idx_content_id` (`content_id` ),
|
||||
KEY `idx_meta_id` (`meta_id` ),
|
||||
KEY `idx_entrypoint` (`entrypoint` ),
|
||||
KEY `idx_entrypoint_domain` (`entrypoint_domain`),
|
||||
KEY `idx_referer` (`referer` ),
|
||||
KEY `idx_referer_domain` (`referer_domain` ),
|
||||
CONSTRAINT `typecho_access_log_ibfk_cid` FOREIGN KEY (`content_id`) REFERENCES `typecho_contents` (`cid`) ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT `typecho_access_log_ibfk_mid` FOREIGN KEY (`meta_id` ) REFERENCES `typecho_metas` (`mid`) ON DELETE SET NULL ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=%charset%;
|
Loading…
Reference in New Issue
Block a user