diff --git a/comments.php b/comments.php
index 697001c..7ac3fbd 100644
--- a/comments.php
+++ b/comments.php
@@ -111,7 +111,12 @@ function threadedComments($comments, $options) {
- ip); ?>
+
+ ip; // Ensure this is the correct property for IP
+ $location = get_ip_location($ip);
+ echo htmlspecialchars($location['country']);
+ ?>
diff --git a/functions.php b/functions.php
index 09975bb..d43fef6 100644
--- a/functions.php
+++ b/functions.php
@@ -1,6 +1,6 @@
addInput($logoUrl);
@@ -477,155 +477,17 @@ function commentApprove($widget, $email = NULL)
/** 获取评论者地址 */
-function convertips($ip) {
- $ip1num = 0;
- $ip2num = 0;
- $ipAddr1 = "";
- $ipAddr2 = "";
- $dat_path = dirname(__FILE__) . '/dist/qqwry.dat';
-
- // 验证IP格式
- if (!preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/", $ip)) {
- return 'IPV6无法获取归宿地';
- }
-
- // 打开数据文件
- if (!$fd = @fopen($dat_path, 'rb')) {
- return 'IP 数据库路径不正确';
- }
-
- // 计算IP数值
- $ip = explode('.', $ip);
- $ipNum = $ip[0] * 16777216 + $ip[1] * 65536 + $ip[2] * 256 + $ip[3];
- $DataBegin = fread($fd, 4);
- $DataEnd = fread($fd, 4);
- $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 = 0;
- $EndNum = $ipAllNum;
-
- // 二分查找IP
- 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;
+function get_ip_location($ip) {
+ $qqwry = new QQWry(__DIR__ . '/dist/qqwry.dat');
+ $detail = $qqwry->getDetail($ip);
+ if ($detail) {
+ // Assuming dataA is country and dataB is province
+ return array(
+ 'country' => $detail['dataA']
+ );
} 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;
- }
+ return array(
+ 'country' => 'Unknown'
+ );
}
- fclose($fd);
-
- // 处理结果,去除城市和运营商信息
- $ipAddr1 = iconv('gbk', 'utf-8//IGNORE', trim($ipAddr1));
- $ipAddr2 = iconv('gbk', 'utf-8//IGNORE', trim($ipAddr2));
-
- // 只返回国家和省份
- $result = "$ipAddr1 $ipAddr2";
-
- // 清理多余信息
- $result = preg_replace('/(.*?)(?:–.*)?/', '$1', $result); // 只保留前面的部分
- $result = preg_replace('/CZ88.NET|http.*$/i', '', $result);
- $result = preg_replace('/\s+/', ' ', $result); // 合并多余空格
- $result = trim($result);
-
- if (empty($result)) {
- return '可能来自火星';
- }
-
- return $result;
-}
-
-function convertip($ip) {
- echo convertips($ip);
-}
+}
\ No newline at end of file
diff --git a/qqwry.php b/qqwry.php
new file mode 100644
index 0000000..9795aa0
--- /dev/null
+++ b/qqwry.php
@@ -0,0 +1,164 @@
+fp = fopen($fileName, 'rb');
+ $this->firstRecord = $this->read4byte();
+ $this->lastRecord = $this->read4byte();
+ $this->recordNum = ($this->lastRecord - $this->firstRecord) / 7; // 每条索引长度为7字节
+ }
+
+ public function __destruct() { // 析构函数
+ if ($this->fp) {
+ fclose($this->fp);
+ }
+ }
+
+ private function read4byte() { // 读取4字节并转为long
+ return unpack('Vlong', fread($this->fp, 4))['long'];
+ }
+
+ private function read3byte() { // 读取3字节并转为long
+ return unpack('Vlong', fread($this->fp, 3) . chr(0))['long'];
+ }
+
+ private function readString() { // 读取字符串
+ $str = '';
+ $char = fread($this->fp, 1);
+ while (ord($char) != 0) { // 读到二进制0结束
+ $str .= $char;
+ $char = fread($this->fp, 1);
+ }
+ return $str;
+ }
+
+ private function zipIP($ip) { // IP地址转为数字
+ $ip_arr = explode('.', $ip);
+ $tmp = (16777216 * intval($ip_arr[0])) + (65536 * intval($ip_arr[1])) + (256 * intval($ip_arr[2])) + intval($ip_arr[3]);
+ return pack('N', intval($tmp)); // 32位无符号大端序长整型
+ }
+
+ private function unzipIP($ip) { // 数字转为IP地址
+ return long2ip($ip);
+ }
+
+ public function getVersion() { // 获取当前数据库的版本
+ fseek($this->fp, $this->lastRecord + 4);
+ $tmp = $this->getRecord($this->read3byte())['B'];
+ return substr($tmp, 0, 4) . substr($tmp, 7, 2) . substr($tmp, 12, 2);
+ }
+
+ public function getDetail($ip) { // 获取IP地址区段及所在位置
+ if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) { // 判断是否为IPv4地址
+ return null;
+ }
+
+ fseek($this->fp, $this->searchRecord($ip)); // 跳转到对应IP记录的位置
+ $detail['beginIP'] = $this->unzipIP($this->read4byte()); // 目标IP所在网段的起始IP
+ $offset = $this->read3byte(); // 索引后3字节为对应记录的偏移量
+ fseek($this->fp, $offset);
+ $detail['endIP'] = $this->unzipIP($this->read4byte()); // 目标IP所在网段的结束IP
+
+ $tmp = $this->getRecord($offset); // 获取记录的dataA与dataB
+ $detail['dataA'] = $tmp['A'];
+ $detail['dataB'] = $tmp['B'];
+
+ if ($detail['beginIP'] == '255.255.255.0') { // 去除附加信息
+ $detail['dataA'] = 'IANA';
+ $detail['dataB'] = '保留地址';
+ }
+ if ($detail['dataA'] == ' CZ88.NET' || $detail['dataA'] == '纯真网络') {
+ $detail['dataA'] = '';
+ }
+ if ($detail['dataB'] == ' CZ88.NET') {
+ $detail['dataB'] = '';
+ }
+ return $detail;
+ }
+
+ private function searchRecord($ip) { // 根据IP地址获取索引的绝对偏移量
+ $ip = $this->zipIP($ip); // 转为数字以比较大小
+ $down = 0;
+ $up = $this->recordNum;
+ while ($down <= $up) { // 二分法查找
+ $mid = floor(($down + $up) / 2); // 计算二分点
+ fseek($this->fp, $this->firstRecord + $mid * 7);
+ $beginip = strrev(fread($this->fp, 4)); // 获取二分区域的下边界
+ if ($ip < $beginip) { // 目标IP在二分区域以下
+ $up = $mid - 1; // 缩小搜索的上边界
+ } else {
+ fseek($this->fp, $this->read3byte());
+ $endip = strrev(fread($this->fp, 4)); // 获取二分区域的上边界
+ if ($ip > $endip) { // 目标IP在二分区域以上
+ $down = $mid + 1; // 缩小搜索的下边界
+ } else { // 目标IP在二分区域内
+ return $this->firstRecord + $mid * 7; // 返回索引的偏移量
+ }
+ }
+ }
+ return $this->lastRecord; // 无法找到对应索引,返回最后一条记录的偏移量
+ }
+
+ private function getRecord($offset) { // 读取IP记录的数据
+ fseek($this->fp, $offset + 4);
+ $flag = ord(fread($this->fp, 1));
+ if ($flag == 1) { // dataA与dataB均重定向
+ $offset = $this->read3byte(); // 重定向偏移
+ fseek($this->fp, $offset);
+ if (ord(fread($this->fp, 1)) == 2) { // dataA再次重定向
+ fseek($this->fp, $this->read3byte());
+ $data['A'] = $this->readString();
+ fseek($this->fp, $offset + 4);
+ $data['B'] = $this->getDataB();
+ } else { // dataA无重定向
+ fseek($this->fp, -1, SEEK_CUR); // 文件指针回退1字节
+ $data['A'] = $this->readString();
+ $data['B'] = $this->getDataB();
+ }
+ } else if ($flag == 2) { // dataA重定向
+ fseek($this->fp, $this->read3byte());
+ $data['A'] = $this->readString();
+ fseek($this->fp, $offset + 8); // IP占4字节, 重定向标志占1字节, dataA指针占3字节
+ $data['B'] = $this->getDataB();
+ } else { // dataA无重定向
+ fseek($this->fp, -1, SEEK_CUR); // 文件指针回退1字节
+ $data['A'] = $this->readString();
+ $data['B'] = $this->getDataB();
+ }
+ $data['A'] = iconv("GBK", "UTF-8", $data['A']); // GBK -> UTF-8
+ $data['B'] = iconv("GBK", "UTF-8", $data['B']);
+ return $data;
+ }
+
+ private function getDataB() { // 从fp指定偏移获取dataB
+ $flag = ord(fread($this->fp, 1));
+ if ($flag == 0) { // dataB无信息
+ return '';
+ } else if ($flag == 1 || $flag == 2) { // dataB重定向
+ fseek($this->fp, $this->read3byte());
+ return $this->readString();
+ } else { // dataB无重定向
+ fseek($this->fp, -1, SEEK_CUR); // 文件指针回退1字节
+ return $this->readString();
+ }
+ }
+}
+?>
\ No newline at end of file