'GET', 'migrate' => 'POST', ]; private $config; private $db; private $request; public function __construct($request) { $this->db = Typecho_Db::get(); $this->request = $request; $this->config = Typecho_Widget::widget('Widget_Options')->plugin('Access'); } /** * 显示是否存在旧版数据 * * @access public * @return bool * @throws Exception */ public function exists() { $prefix = $this->db->getPrefix(); if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access';", Typecho_Db::READ))) { return true; } if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access_log';", Typecho_Db::READ))) { return true; } return false; } /** * 显示旧版本数据数量 * * @access private * @return ?array * @throws Exception */ private function overview() { $resp = [ 'total' => 0 ]; $prefix = $this->db->getPrefix(); // 统计 v1 版本数据 if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access';", Typecho_Db::READ))) { $resp['v1'] = $this->db->fetchRow($this->db->select('COUNT(1) AS cnt')->from('table.access'))['cnt']; $resp['total'] += $resp['v1']; } // 统计 v2 版本数据 if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access_log';", Typecho_Db::READ))) { $resp['v2'] = intval($this->db->fetchRow($this->db->select('COUNT(1) AS cnt')->from('table.access_log'))['cnt']); $resp['total'] += $resp['v2']; } return $resp; } /** * 迁移旧版本数据,单次1000条 * * @access private * @return ?array * @throws Exception */ private function migrate() { $resp = [ 'count' => 0, 'remain' => 0 ]; $step = 1000; $prefix = $this->db->getPrefix(); // 迁移 v1 版本数据 if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access';", Typecho_Db::READ))) { $remain = intval($this->db->fetchRow($this->db->select('COUNT(1) AS cnt')->from('table.access'))['cnt']); if ($resp['count'] === 0) { $rows = $this->db->fetchAll($this->db->select()->from('table.access')->limit($step)); foreach ($rows as $row) { $id = $row['id']; unset($row['id']); $ua = new Access_UA($row['ua']); $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' ] = $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']); $this->db->query($this->db->insert('table.access_logs')->rows($row)); $resp['count'] += 1; $this->db->query($this->db->delete('table.access')->where('id = ?', $id)); $remain -= 1; } } if ($remain === 0) { $this->db->query("DROP TABLE `{$prefix}access`;", Typecho_Db::WRITE); } $resp['remain'] += $remain; } // 迁移 v2 版本数据 if ($this->db->fetchRow($this->db->query("SHOW TABLES LIKE '{$prefix}access_log';", Typecho_Db::READ))) { $remain = intval($this->db->fetchRow($this->db->select('COUNT(1) AS cnt')->from('table.access_log'))['cnt']); if ($resp['count'] === 0) { $rows = $this->db->fetchAll($this->db->select()->from('table.access_log')->limit($step)); foreach ($rows as $row) { $id = $row['id']; unset($row['id']); $row['ip'] = long2ip($row['ip']); $this->db->query($this->db->insert('table.access_logs')->rows($row)); $resp['count'] += 1; $this->db->query($this->db->delete('table.access_log')->where('id = ?', $id)); $remain -= 1; } } if ($remain === 0) { $this->db->query("DROP TABLE `{$prefix}access_log`;", Typecho_Db::WRITE); } $resp['remain'] += $remain; } return $resp; } /** * 业务调度入口 * * @access public * @param string rpcType 调用过程类型 * @return ?array * @throws Exception */ public function invoke(string $rpcType): ?array { if(!method_exists($this, $rpcType) || !array_key_exists($rpcType, Access_Migration::$rpcTypes)) throw new Exception('Bad Request', 400); $method = Access_Migration::$rpcTypes[$rpcType]; if ( ($method === 'GET' && !$this->request->isGet()) || ($method === 'POST' && !$this->request->isPost()) || ($method === 'PUT' && !$this->request->isPut()) ) { throw new Exception('Method Not Allowed', 405); } return $this->$rpcType(); } }