diff --git a/Access_Core.php b/Access_Core.php index 1b36d08..adfb551 100644 --- a/Access_Core.php +++ b/Access_Core.php @@ -9,6 +9,7 @@ class Access_Core protected $prefix; protected $table; public $config; + protected $response; protected $request; protected $pageSize; protected $isDrop; @@ -25,6 +26,7 @@ class Access_Core $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; @@ -176,4 +178,48 @@ class Access_Core } } + public function getReferer() + { + $referer = Typecho_Cookie::get('__typecho_access_referer'); + if ($referer == null) { + $referer = $this->request->getReferer(); + if (strpos($referer, rtrim(Helper::options()->siteUrl, '/')) !== false) { + $referer = null; + } + if ($referer != null) { + Typecho_Cookie::set('__typecho_access_referer', $referer); + } + } + return $referer; + } + + public function writeLogs($url = null) + { + if ($this->isAdmin()) { + return; + } + $ip = $this->request->getIp(); + if ($url == null) { + $url = $this->request->getServer('REQUEST_URI'); + } + if ($ip == null) { + $ip = 'UnKnown'; + } + + $timeStamp = Helper::options()->gmtTime; + $offset = Helper::options()->timezone - Helper::options()->serverTimezone; + $gtime = $timeStamp + $offset; + $referer = $this->getReferer(); + $rows = array( + 'ua' => $this->request->getAgent(), + 'url' => $url, + 'ip' => $ip, + 'referer' => $referer, + 'referer_domain' => parse_url($this->request->getReferer(), PHP_URL_HOST), + 'date' => $gtime, + ); + + $this->db->query($this->db->insert('table.access')->rows($rows)); + } + } diff --git a/Access_Ip.php b/Access_Ip.php new file mode 100644 index 0000000..ec064f9 --- /dev/null +++ b/Access_Ip.php @@ -0,0 +1,89 @@ + 255 || count($ipdot) !== 4) { + return 'N/A'; + } + + if (isset(self::$cached[$nip]) === true) { + return self::$cached[$nip]; + } + + if (self::$fp === null) { + self::init(); + } + + $nip2 = pack('N', ip2long($nip)); + + $tmp_offset = (int) $ipdot[0] * 4; + $start = unpack('Vlen', self::$index[$tmp_offset] . self::$index[$tmp_offset + 1] . self::$index[$tmp_offset + 2] . self::$index[$tmp_offset + 3]); + + $index_offset = $index_length = null; + $max_comp_len = self::$offset['len'] - 1024 - 4; + for ($start = $start['len'] * 8 + 1024; $start < $max_comp_len; $start += 8) { + if (self::$index{$start} . self::$index{$start + 1} . self::$index{$start + 2} . self::$index{$start + 3} >= $nip2) { + $index_offset = unpack('Vlen', self::$index{$start + 4} . self::$index{$start + 5} . self::$index{$start + 6} . "\x0"); + $index_length = unpack('Clen', self::$index{$start + 7}); + + break; + } + } + + if ($index_offset === null) { + return 'N/A'; + } + + fseek(self::$fp, self::$offset['len'] + $index_offset['len'] - 1024); + + self::$cached[$nip] = explode("\t", fread(self::$fp, $index_length['len'])); + + return self::$cached[$nip]; + } + + private static function init() + { + if (self::$fp === null) { + self::$ip = new self(); + + self::$fp = fopen(__ACCESS_PLUGIN_ROOT__ . '/lib/17monipdb.dat', 'rb'); + if (self::$fp === false) { + throw new Exception('Invalid 17monipdb.dat file!'); + } + + self::$offset = unpack('Nlen', fread(self::$fp, 4)); + if (self::$offset['len'] < 4) { + throw new Exception('Invalid 17monipdb.dat file!'); + } + + self::$index = fread(self::$fp, self::$offset['len'] - 4); + } + } + + public function __destruct() + { + if (self::$fp !== null) { + fclose(self::$fp); + } + } +} diff --git a/Action.php b/Action.php index d80481f..afe6996 100644 --- a/Action.php +++ b/Action.php @@ -22,17 +22,32 @@ class Access_Action implements Widget_Interface_Do { } + public function writeLogs() + { + $this->access->writeLogs($this->request->u); + $this->response->setStatus(206); + exit; + } + public function ip() { $this->response->setContentType('application/json'); try { $this->checkAuth(); $ip = $this->request->get('ip'); - $response = file_get_contents('http://ip.taobao.com/service/getIpInfo.php?ip=' . $ip); - if (!$response) { - throw new Exception('HTTP request failed'); + $response = Access_Ip::find($ip); + if (is_array($response)) { + $response = array( + 'code' => 0, + 'data' => implode(' ', $response), + ); + } else { + $response = array( + 'code' => 100, + 'message' => '解析ip失败', + ); } - exit($response); + exit(Json::encode($response)); } catch (Exception $e) { exit(Json::encode(array( 'code' => 100, diff --git a/Plugin.php b/Plugin.php index 06b7c60..cde7e26 100644 --- a/Plugin.php +++ b/Plugin.php @@ -4,7 +4,7 @@ * * @package Access * @author Kokororin - * @version 1.5 + * @version 1.6 * @link https://kotori.love */ class Access_Plugin implements Typecho_Plugin_Interface @@ -14,9 +14,11 @@ class Access_Plugin implements Typecho_Plugin_Interface { $msg = Access_Plugin::install(); Helper::addPanel(1, self::$panel, 'Access控制台', '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", "Access_Action", 'deleteLogs'); - Typecho_Plugin::factory('Widget_Archive')->beforeRender = array('Access_Plugin', 'start'); + Helper::addRoute("access_delete_logs", "/access/log/delete.json", "Access_Action", 'deleteLogs'); + Typecho_Plugin::factory('Widget_Archive')->beforeRender = array('Access_Plugin', 'backend'); + Typecho_Plugin::factory('Widget_Archive')->footer = array('Access_Plugin', 'frontend'); Typecho_Plugin::factory('admin/footer.php')->end = array('Access_Plugin', 'adminFooter'); return _t($msg); } @@ -31,6 +33,7 @@ class Access_Plugin implements Typecho_Plugin_Interface $db->query("DROP TABLE `" . $prefix . "access`", Typecho_Db::WRITE); } Helper::removePanel(1, self::$panel); + Helper::removeRoute("access_write_logs"); Helper::removeRoute("access_ip"); Helper::removeRoute("access_delete_logs"); } @@ -45,6 +48,11 @@ class Access_Plugin implements Typecho_Plugin_Interface '0' => '删除', '1' => '不删除', ), '1', '删除数据表:', '请选择是否在禁用插件时,删除日志数据表'); + $writeType = new Typecho_Widget_Helper_Form_Element_Radio( + 'writeType', array( + '0' => '后端', + '1' => '前端', + ), '0', '日志写入类型:', '请选择日志写入类型,数据量大时(几万以上),后端写入可能会拖慢博客访问速度'); $canAnalytize = new Typecho_Widget_Helper_Form_Element_Radio( 'canAnalytize', array( '0' => '不允许', @@ -52,6 +60,7 @@ class Access_Plugin implements Typecho_Plugin_Interface ), '1', '允许统计使用情况:', '请选择是否允许插件作者统计使用情况'); $form->addInput($pageSize); $form->addInput($isDrop); + $form->addInput($writeType); $form->addInput($canAnalytize); } @@ -92,7 +101,10 @@ class Access_Plugin implements Typecho_Plugin_Interface return '成功创建数据表,插件启用成功,' . $configLink; } catch (Typecho_Db_Exception $e) { $code = $e->getCode(); - if (('Mysql' == $type && $code == (1050 || '42S01'))) { + 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')))) { @@ -103,50 +115,29 @@ class Access_Plugin implements Typecho_Plugin_Interface } else { throw new Typecho_Plugin_Exception('数据表建立失败,插件启用失败。错误号:' . $code); } + } catch (Exception $e) { + throw new Typecho_Plugin_Exception($e->getMessage()); } } - public static function start($archive) + public static function backend($archive) { require_once __DIR__ . '/Access_Bootstrap.php'; $access = new Access_Core(); - if ($access->isAdmin()) { - return; - } + $access->getReferer(); $config = Typecho_Widget::widget('Widget_Options')->plugin('Access'); - $request = Typecho_Request::getInstance(); - $ip = $request->getIp(); - $url = $request->getServer('REQUEST_URI'); - if ($ip == null) { - $ip = 'UnKnown'; + if ($config->writeType == 0) { + $access->writeLogs(); } - $options = Typecho_Widget::widget('Widget_Options'); - $timeStamp = $options->gmtTime; - $offset = $options->timezone - $options->serverTimezone; - $gtime = $timeStamp + $offset; - $db = Typecho_Db::get(); - $referer = Typecho_Cookie::get('__typecho_access_referer'); - if ($referer == null) { - $referer = $request->getReferer(); - if (strpos($referer, rtrim(Helper::options()->siteUrl, '/')) !== false) { - $referer = null; - } - if ($referer != null) { - Typecho_Cookie::set('__typecho_access_referer', $referer); - } + } + + public static function frontend() + { + $config = Typecho_Widget::widget('Widget_Options')->plugin('Access'); + if ($config->writeType == 1) { + echo ''; } - - $rows = array( - 'ua' => $request->getAgent(), - 'url' => $url, - 'ip' => $ip, - 'referer' => $referer, - 'referer_domain' => parse_url($request->getReferer(), PHP_URL_HOST), - 'date' => $gtime, - ); - $db->query($db->insert('table.access')->rows($rows)); - } public static function adminFooter() diff --git a/lib/17monipdb.dat b/lib/17monipdb.dat new file mode 100755 index 0000000..a24080b Binary files /dev/null and b/lib/17monipdb.dat differ diff --git a/page/console.php b/page/console.php index f158032..9937f83 100644 --- a/page/console.php +++ b/page/console.php @@ -254,7 +254,7 @@ $(document).ready(function() { $('a[data-action="ip"]').click(function() { swal({ title: "IP查询中...", - text: '正在请求Taobao API...', + text: '正在查询...', type: "info", confirmButtonText: "OK" }); @@ -267,7 +267,7 @@ $(document).ready(function() { if (data.code == 0) { swal({ title: "IP查询成功", - text: data.data.country + data.data.area + data.data.city + data.data.country + data.data.isp, + text: data.data, type: "success", confirmButtonText: "OK" }); @@ -314,7 +314,7 @@ $(document).ready(function() { return swal("错误", "你并没有勾选任何内容", "warning"); } $.ajax({ - url: 'index, '/').'/access/log/delete';?>', + url: 'index, '/').'/access/log/delete.json';?>', method: 'post', dataType: 'json', contentType: 'application/json',