diff --git a/composer.json b/composer.json index 875dcf4..d3f78b7 100644 --- a/composer.json +++ b/composer.json @@ -20,7 +20,8 @@ "ext-zip": "*", "ext-pdo": "*", "ext-iconv": "*", - "khanamiryan/qrcode-detector-decoder": "1.0.5.2" + "khanamiryan/qrcode-detector-decoder": "1.0.5.2", + "cccyun/php-whois": "^1.2" }, "require-dev": { "symfony/var-dumper": "^4.2", diff --git a/composer.lock b/composer.lock index 77537f0..280d584 100644 --- a/composer.lock +++ b/composer.lock @@ -4,8 +4,68 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "90b52d33a495d2606004dc98c6c983ae", + "content-hash": "cc447ea0a5a3bc2bf911a9ac53603245", "packages": [ + { + "name": "cccyun/php-whois", + "version": "1.2", + "source": { + "type": "git", + "url": "https://github.com/netcccyun/php-whois.git", + "reference": "c631f1c5e26e7150501a14cd25a2380f8a077ca1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/netcccyun/php-whois/zipball/c631f1c5e26e7150501a14cd25a2380f8a077ca1", + "reference": "c631f1c5e26e7150501a14cd25a2380f8a077ca1", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-json": "*", + "ext-mbstring": "*", + "php": ">=7.2", + "symfony/polyfill-intl-idn": "^1.27" + }, + "require-dev": { + "phpunit/phpunit": "^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Iodev\\": "src/Iodev/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "caihong", + "email": "admin@cccyun.cn" + } + ], + "description": "PHP WHOIS provides parsed and raw whois lookup of domains and ASN routes. PHP 5.4+ and 7+ compatible ", + "homepage": "https://github.com/netcccyun/php-whois", + "keywords": [ + "asn", + "domain", + "info", + "lookup", + "parser", + "php", + "query", + "routes", + "tld", + "whois", + "црщшы" + ], + "support": { + "source": "https://github.com/netcccyun/php-whois/tree/1.2" + }, + "time": "2025-06-25T06:54:23+00:00" + }, { "name": "cccyun/think-captcha", "version": "3.0.11", @@ -315,6 +375,178 @@ }, "time": "2017-10-23T01:57:42+00:00" }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-10T14:38:51+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.33.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, { "name": "topthink/framework", "version": "v6.1.5", @@ -382,16 +614,16 @@ }, { "name": "topthink/think-helper", - "version": "v3.1.11", + "version": "v3.1.12", "source": { "type": "git", "url": "https://github.com/top-think/think-helper.git", - "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c" + "reference": "fe277121112a8f1c872e169a733ca80bb11c4acb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/top-think/think-helper/zipball/1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", - "reference": "1d6ada9b9f3130046bf6922fe1bd159c8d88a33c", + "url": "https://api.github.com/repos/top-think/think-helper/zipball/fe277121112a8f1c872e169a733ca80bb11c4acb", + "reference": "fe277121112a8f1c872e169a733ca80bb11c4acb", "shasum": "" }, "require": { @@ -422,9 +654,9 @@ "description": "The ThinkPHP6 Helper Package", "support": { "issues": "https://github.com/top-think/think-helper/issues", - "source": "https://github.com/top-think/think-helper/tree/v3.1.11" + "source": "https://github.com/top-think/think-helper/tree/v3.1.12" }, - "time": "2025-04-07T06:55:59+00:00" + "time": "2025-12-26T09:58:29+00:00" }, { "name": "topthink/think-migration", diff --git a/plugin/web/icp/App.php b/plugin/web/icp/App.php index c1cec29..d1f3162 100644 --- a/plugin/web/icp/App.php +++ b/plugin/web/icp/App.php @@ -21,8 +21,9 @@ class App extends Plugin public function query(){ $domain = input('post.domain', null, 'trim'); + $type = input('post.type', 'web', 'trim'); if(!$domain) return msg('error','no domain'); - if(!checkdomain($domain)){ + if(strpos($domain,'.') && !checkdomain($domain)){ return msg('error', '域名格式不正确!'); } @@ -31,70 +32,148 @@ class App extends Plugin return msg('error', '验证失败,请重新验证'); } - $cache = Db::name('querycache')->where('type', 'icp')->where('key', $domain)->find(); + $cache = Db::name('querycache')->where('type', $type.'list')->where('key|subkey', $domain)->find(); if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){ $array = json_decode($cache['content'], true); - return msg('ok','success',$array); + $data = Db::name('querycache')->where('type', $type.'item')->whereIn('id', implode(',',$array['list']))->select(); + $list = []; + foreach($data as $row){ + $list[] = json_decode($row['content'], true); + } + return msg('ok','success',['total'=>$array['total'], 'list'=>$list]); + } + + $cache = Db::name('querycache')->where('type', $type.'item')->where('key|subkey', $domain)->find(); + if($cache && time() - strtotime($cache['uptime']) <= self::CACHE_TIME){ + $array = json_decode($cache['content'], true); + return msg('ok','success',['total'=>1, 'list'=>[$array]]); } try{ - $result = $this->queryapi($domain); - if(!$result){ - return msg('ok','success',null); - } + $result = $this->execapi($type, $domain); }catch(Exception $e){ return msg('error', $e->getMessage()); } - Db::name('querycache')->duplicate([ - 'type' => 'icp', - 'key' => $result['Domain'], - 'content' => json_encode($result), - 'uptime' => date('Y-m-d H:i:s') - ])->insert([ - 'type' => 'icp', - 'key' => $result['Domain'], - 'content' => json_encode($result), - 'uptime' => date('Y-m-d H:i:s') - ]); + if($result['total'] > 1 && count($result['data']) > 1){ + $i = 0; + foreach($result['data'] as $row){ + $id = Db::name('querycache')->duplicate([ + 'content' => json_encode($row), + 'uptime' => date('Y-m-d H:i:s') + ])->insertGetId([ + 'type' => $type.'item', + 'key' => $row['domain'], + 'subkey' => $row['webLicence'], + 'content' => json_encode($row), + 'uptime' => date('Y-m-d H:i:s') + ]); + $result['data'][$i++]['id'] = $id; + $ids[] = $id; + } + Db::name('querycache')->duplicate([ + 'content' => json_encode(['total'=>$result['total'], 'list'=>$ids]), + 'uptime' => date('Y-m-d H:i:s') + ])->insert([ + 'type' => $type.'list', + 'key' => $domain == $result['data'][0]['domain'] ? $result['data'][0]['domain'] : $result['data'][0]['unitName'], + 'subkey' => $domain == $result['data'][0]['domain'] ? $result['data'][0]['webLicence'] : $result['data'][0]['mainLicence'], + 'content' => json_encode(['total'=>$result['total'], 'list'=>$ids]), + 'uptime' => date('Y-m-d H:i:s') + ]); + }elseif($result['total'] == 1 && count($result['data']) > 0){ + $id = Db::name('querycache')->duplicate([ + 'content' => json_encode($result['data'][0]), + 'uptime' => date('Y-m-d H:i:s') + ])->insertGetId([ + 'type' => $type.'item', + 'key' => $result['data'][0]['domain'], + 'subkey' => $result['data'][0]['webLicence'], + 'content' => json_encode($result['data'][0]), + 'uptime' => date('Y-m-d H:i:s') + ]); + $result['data'][0]['id'] = $id; + } - return msg('ok','success',$result); + return msg('ok','success',['total'=>$result['total'], 'list'=>$result['data']]); } - private function queryapi($domain){ - if(config_get('qqapi_url')){ - $url = config_get('qqapi_url').'api.php?act=icpquery'; - $post = 'key='.config_get('qqapi_key').'&domain='.$domain; - $data = get_curl($url, $post); - $arr = json_decode($data, true); - if(isset($arr['code']) && $arr['code']==0){ - return $arr['data']; - }elseif(isset($arr['msg'])){ - throw new Exception($arr['msg']); - }else{ - throw new Exception('接口请求失败'); - } - }elseif(config_get('yapi_token')){ - $url = 'https://api.makuo.cc/api/get.other.icp?url='.urlencode($domain); - $header = ['Authorization: '.config_get('yapi_token')]; - $data = get_curl($url, 0, 0, 0, 0, 0, 0, $header); - $arr = json_decode($data, true); - if(isset($arr['code']) && $arr['code']==200){ - return [ - 'Domain' => $arr['data']['domain'], - 'DomainIcpNum' => $arr['data']['icp'], - 'CompanyName' => $arr['data']['unitName'], - 'CompanyType' => $arr['data']['natureName'], - 'AuditTime' => $arr['data']['updateRecordTime'], - ]; - }elseif(isset($arr['msg'])){ - throw new Exception('接口请求失败,'.$arr['msg']); - }else{ - throw new Exception('接口请求失败'); - } + public function item(){ + $id = input('post.id'); + if(!$id) return msg('error','no id'); + $cache = Db::name('querycache')->where('id', $id)->find(); + if($cache){ + $array = json_decode($cache['content'], true); + return msg('ok','success',['total'=>1, 'list'=>[$array]]); }else{ - throw new Exception('请先配置API接口参数'); + return msg('ok','success',['total'=>0, 'list'=>[]]); } } + /** + * https://github.com/HG-ha/ICP_Query + */ + private function execapi($type, $domain){ + $url = 'http://172.17.0.1:16181/query/'.$type.'?search='.urlencode($domain); + $response = get_curl($url); + $arr = json_decode($response, true); + if(isset($arr['code']) && $arr['code']==200){ + $list = []; + if(isset($arr['params']['list'])){ + foreach($arr['params']['list'] as $row){ + $list[] = ['domain'=>isset($row['domain'])?$row['domain']:$row['serviceName'], 'mainLicence'=>$row['mainLicence'], 'webLicence'=>$row['serviceLicence'], 'unitName'=>$row['unitName'], 'unitType'=>$row['natureName'], 'updateTime'=>$row['updateRecordTime'], 'contentTypeName'=>$row['contentTypeName']]; + } + } + return ['code'=>0, 'total'=>isset($arr['params']['total']) ? $arr['params']['total'] : 0, 'data'=>$list]; + }elseif(isset($arr['msg'])){ + throw new Exception($arr['msg']); + }else{ + throw new Exception('查询接口请求失败'); + } + } + + private function execapi2($domain){ + $timeStamp = time(); + $authKey = md5("testtest" . $timeStamp); + $referer = 'https://beian.miit.gov.cn/'; + $headers = ['Origin: https://beian.miit.gov.cn']; + $url = 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/auth'; + $post = 'authKey='.$authKey.'&timeStamp='.$timeStamp; + $response = get_curl($url, $post, $referer, 0, 1, 0, 0, $headers); + $body = substr($response, strpos($response, '{"')); + $arr = json_decode($body, true); + if(isset($arr['code']) && $arr['code']==200){ + $cookie = ''; + preg_match_all('/set-cookie: (.*?);/i', $response, $matchs); + foreach ($matchs[1] as $val) { + if(substr($val,-1)=='=')continue; + $cookie.=$val.'; '; + } + + $token = $arr['params']['bussiness']; + + $url = 'https://hlwicpfwc.miit.gov.cn/icpproject_query/api/icpAbbreviateInfo/queryByCondition'; + $post = json_encode(['pageNum'=>'','pageSize'=>'','unitName'=>$domain,'serviceType'=>1]); + $headers[] = 'Content-Type: application/json; charset=UTF-8'; + $headers[] = 'token: '.$token; + $response = get_curl($url, $post, $referer, $cookie, 0, 0, 0, $headers); + $arr = json_decode($response, true); + if(isset($arr['code']) && $arr['code']==200){ + $list = []; + foreach($arr['params']['list'] as $row){ + $list[] = ['domain'=>$row['domain'], 'mainLicence'=>$row['mainLicence'], 'webLicence'=>$row['serviceLicence'], 'unitName'=>$row['unitName'], 'unitType'=>$row['natureName'], 'updateTime'=>$row['updateRecordTime'], 'limitAccess'=>$row['limitAccess'], 'contentTypeName'=>$row['contentTypeName'], 'dataId'=>$row['dataId']]; + } + return ['code'=>0, 'total'=>$arr['params']['total'], 'data'=>$list]; + }elseif(isset($arr['msg'])){ + throw new Exception($arr['msg']); + }else{ + throw new Exception('查询接口(query)请求失败'); + } + + }elseif(isset($arr['msg'])){ + throw new Exception($arr['msg']); + }else{ + throw new Exception('查询接口(auth)请求失败'); + } + } } \ No newline at end of file diff --git a/plugin/web/icp/index.html b/plugin/web/icp/index.html index 50672bf..44b859e 100644 --- a/plugin/web/icp/index.html +++ b/plugin/web/icp/index.html @@ -2,19 +2,33 @@ {block name="title"}{$plugin.title} - {:config_get('title')}{/block} {block name="main"}
支持输入域名、程序名称、网站备案号、主体备案号、单位名称(个人姓名、企业名称)进行查询
+此ICP查询工具直接对接工信部官网,非第三方接口。采用开源项目ICP_Query
+| 域名 | {{whoisData.domainName}} |
| 域名所有者 | {{whoisData.owner || '-'}} |
| 注册商 | {{whoisData.registrar}} |
| Whois服务器 | {{whoisData.whoisServer}} |
| 注册时间 | {{whoisData.creationDate}} |
| 到期时间 | {{whoisData.expirationDate}} |
| 更新时间 | {{whoisData.updatedDate}} |
| 域名状态 | {{item.name}}({{item.value}}) |
| DNS服务器 | {{ns}} |
| 原始信息 | {{whoisData.rawData}} |