简介海风域名查询工具v1.0是一款基于PHP开发的轻量级域名查询系统面向需要在Linux主机上快速搭建域名信息查询服务的站长与开发者尤其适合具备基础PHP环境配置能力的技术人员使用。资源包为rar压缩格式整体约372KB体积小巧便于部署与迁移。安装前需将sitemap.xml、inc/config.php、install/data.sql等文件权限设置为777随后运行/install/index.php完成安装后台入口为/acp/默认账号与密码均为admin便于快速上手调试。该工具可帮助读者获得一套可直接运行的域名查询脚本省去从零开发的时间成本同时通过后台管理界面灵活维护查询数据与站点配置适合用于个人站点功能扩展或学习PHP项目部署流程。目前已有118人学习关注可作为入门级PHP建站与域名工具实践的参考素材。1. 海风域名查询工具 v1.0一个能塞进任何 PHP 项目的轻量查询模块手里有个 PHP 老项目后台需要加一个「查域名是否被注册」的小功能你会怎么做调第三方 API 要配额、要密钥还怕哪天服务停了自己写 whois 查询又得处理各种后缀的返回格式烦得很。海风域名查询工具 v1.0 就是冲着这个场景来的——它是一套纯 PHP 实现的域名查询源码不依赖外部接口丢进现有项目就能跑。适合谁手上维护着 PHP 站点、需要批量或单次查询域名状态的后端开发者以及想拿一个完整小项目练手 PHP 网络编程的新手。整套代码结构不复杂但把「查询—解析—返回」这条链路走通了拿来当二次开发的底座正合适。2. 技术选型与目录结构为什么用原生 PHP 而不是框架2.1 选型逻辑轻量优先拒绝框架绑架这个项目最核心的选型判断是不引入任何框架。原因很直接——域名查询本身是一个工具型功能它需要的是「能被嵌入」而不是「自成体系」。如果用了某个 MVC 框架使用者就得先装框架、配路由、改入口文件接入成本反而比功能本身还高。原生 PHP 的好处是你可以在任何入口文件里require一下就开始调用不需要改项目的整体架构。从技术栈上看这套源码依赖的东西很少依赖项用途是否必须PHP 7.0运行环境必须cURL 扩展发起 whois / HTTP 查询必须sockets 扩展部分后缀走 socket 直连可选mbstring 扩展处理多编码返回内容推荐常见做法是在入口文件里先做一个环境检查把缺失的扩展直接报出来避免使用者跑起来才发现某个函数不存在。我一般会在项目根目录放一个check_env.php浏览器访问一下就能看到当前环境是否满足要求。2.2 目录结构每个文件干什么源码包的目录结构大致是这样的haifeng-domain/ ├── index.php # 演示入口可直接访问测试 ├── config.php # 全局配置超时、后缀列表、缓存开关 ├── core/ │ ├── Query.php # 查询调度器根据后缀选择查询方式 │ ├── WhoisQuery.php # whois 协议查询实现 │ ├── HttpQuery.php # HTTP 接口查询实现备用通道 │ └── Parser.php # 返回内容解析器提取关键字段 ├── lib/ │ ├── Cache.php # 文件缓存避免重复查询 │ └── Helper.php # 公共函数后缀提取、编码转换 └── data/ └── cache/ # 缓存文件存放目录需可写这个结构里core/Query.php是调度中心它不关心具体怎么查只负责根据域名后缀决定走 whois 还是 HTTP。Parser.php是另一个关键点——不同后缀的 whois 返回格式差异很大解析器要做的是从一堆文本里把「注册状态」「到期时间」「注册商」这几个字段抠出来。2.3 配置项怎么改config.php里几个参数值得单独说?php return [ // 查询超时时间单位秒。whois 服务器响应慢时可适当调大 timeout 10, // 是否开启文件缓存。批量查询同一域名时建议开启 cache_enable true, // 缓存有效期单位秒。默认 1 小时 cache_ttl 3600, // 支持查询的后缀列表不在列表内的后缀会直接返回不支持 suffix_list [com, net, cn, org, io, com.cn], // whois 服务器映射可自行补充 whois_server [ com whois.verisign-grs.com, cn whois.cnnic.cn, io whois.nic.io, ], ];timeout这个值别设太小有些 whois 服务器在高峰期响应会超过 5 秒设成 10 秒是比较稳妥的。cache_enable在批量查询场景下一定要开否则同一个域名查两次就是两次网络请求既慢又容易被限流。suffix_list决定了哪些后缀会被处理不在列表里的直接返回「不支持」避免程序去查一个根本没有 whois 服务器的后缀。3. 核心查询链路从域名输入到结果返回3.1 查询调度器一个入口分流两种通道Query.php是整个项目的调度入口它的逻辑不复杂但决定了后续走哪条路?php class Query { private $config; public function __construct($config) { $this-config $config; } /** * 查询域名状态 * param string $domain 完整域名如 example.com * return array 包含 status/expire/registrar 的数组 */ public function check($domain) { // 提取后缀判断是否在支持列表内 $suffix Helper::getSuffix($domain); if (!in_array($suffix, $this-config[suffix_list])) { return [status unsupported, msg 后缀暂不支持]; } // 缓存命中则直接返回不走网络 if ($this-config[cache_enable]) { $cached Cache::get($domain); if ($cached ! false) { return $cached; } } // 根据后缀选择查询通道 if (isset($this-config[whois_server][$suffix])) { $query new WhoisQuery($this-config); } else { $query new HttpQuery($this-config); } $raw $query-fetch($domain); $result Parser::parse($raw, $suffix); // 写入缓存 if ($this-config[cache_enable]) { Cache::set($domain, $result, $this-config[cache_ttl]); } return $result; } }这段代码里几个关键点Helper::getSuffix()负责从完整域名里把后缀抠出来比如example.com.cn要返回com.cn而不是cn这里需要做一次后缀匹配。缓存判断放在网络请求之前命中就直接返回这是批量查询场景下最省时间的优化。通道选择依据是whois_server映射表里有没有这个后缀有就走 whois没有就走 HTTP 备用通道。3.2 whois 查询实现socket 直连与超时控制WhoisQuery.php负责和 whois 服务器建立连接并读取返回内容?php class WhoisQuery { private $config; public function __construct($config) { $this-config $config; } /** * 向 whois 服务器发起查询 * param string $domain 完整域名 * return string 原始返回文本 */ public function fetch($domain) { $suffix Helper::getSuffix($domain); $server $this-config[whois_server][$suffix]; // 建立 socket 连接超时时间从配置读取 $fp fsockopen($server, 43, $errno, $errstr, $this-config[timeout]); if (!$fp) { return ; // 连接失败返回空由上层决定如何处理 } // 设置读取超时避免服务器不返回时一直卡住 stream_set_timeout($fp, $this-config[timeout]); // whois 协议规定查询内容以换行结尾 fwrite($fp, $domain . \r\n); $result ; while (!feof($fp)) { $result . fgets($fp, 1024); } fclose($fp); return $result; } }fsockopen的第五个参数是连接超时这里直接用了配置里的timeout。stream_set_timeout是读取超时两个都要设否则连接上了但服务器不返回数据程序会一直卡在fgets上。whois 协议默认走 43 端口查询内容以\r\n结尾这是协议规定不能省。返回的原始文本不做任何处理直接交给Parser去解析这样职责分离得更干净。3.3 解析器从一堆文本里抠出关键字段Parser.php是这个项目里最需要耐心写的部分因为不同后缀的 whois 返回格式差异很大?php class Parser { /** * 解析 whois 原始返回 * param string $raw 原始文本 * param string $suffix 域名后缀 * return array 结构化结果 */ public static function parse($raw, $suffix) { $result [ status unknown, expire , registrar , ]; if (empty($raw)) { $result[status] error; return $result; } // 统一转小写避免大小写导致匹配失败 $text strtolower($raw); // 判断是否已注册不同后缀的关键词不一样 if (strpos($text, no match) ! false || strpos($text, not found) ! false || strpos($text, no data found) ! false) { $result[status] available; return $result; } // 已注册提取到期时间和注册商 if (preg_match(/expir(y|ation) date:\s*(.)/i, $raw, $m)) { $result[expire] trim($m[2]); } if (preg_match(/registrar:\s*(.)/i, $raw, $m)) { $result[registrar] trim($m[1]); } $result[status] registered; return $result; } }解析逻辑分两步先判断是否可注册再提取已注册域名的附加信息。判断可注册的关键词用了no match、not found、no data found三个覆盖了大部分 whois 服务器的返回习惯。到期时间和注册商用正则提取expir(y|ation) date这个写法是为了兼容expiry date和expiration date两种写法。注意这里没有做编码转换如果返回内容不是 UTF-8需要在Helper里先转码再解析。4. 避坑与常见问题跑起来之后容易卡在哪4.1 查询超时但没有任何报错现象是页面一直转圈最后返回空白或者超时提示但日志里看不到具体错误。原因通常是fsockopen连接失败后返回了空字符串上层没有区分「连接失败」和「域名可注册」两种情况。解决方式是在WhoisQuery::fetch()里把连接失败的状态单独标记出来比如返回false而不是空字符串然后在Query::check()里判断$raw false时直接返回status error不要继续走解析流程。4.2 某些后缀查询结果始终是 unknown现象是.cn或.io域名查出来状态永远是unknown。原因是这些后缀的 whois 返回格式和.com不一样Parser里的关键词没匹配上。解决方式是先把原始返回打印出来看一眼确认它的「可注册」提示词是什么然后往Parser的判断条件里补。我一般会在Parser里加一个调试开关打开后把原始文本写到日志文件方便对照。4.3 批量查询时被 whois 服务器限流现象是查了十几个域名之后后续全部返回空或超时。原因是 whois 服务器对同一 IP 的请求频率有限制短时间大量请求会被临时封禁。解决方式有两个一是开启缓存同一个域名短时间内不重复查二是在批量查询的循环里加sleep(1)每次查询间隔一秒。如果量确实大建议把查询任务拆到多个时间段执行不要一次性跑完。4.4 缓存文件越来越多磁盘占用上涨现象是data/cache/目录下文件数量持续增长几个月后占了几百 MB。原因是缓存文件只写不删过期文件没有被清理。解决方式是加一个清理逻辑在每次写入缓存时以一定概率触发过期文件扫描把修改时间超过cache_ttl的文件删掉。或者更简单一点用 cron 定时任务每天清理一次。4.5 中文域名查询返回乱码现象是查询中文域名时返回内容里出现乱码。原因是中文域名需要先转成 punycode 再查询直接传中文给 whois 服务器会返回错误内容。解决方式是在Query::check()入口处加一个判断如果域名包含非 ASCII 字符先用idn_to_ascii()转成 punycode 再走后续流程。这个函数需要intl扩展支持环境检查里要加上。5. 二次开发把查询模块改造成自己的工具5.1 扩展后缀支持加一个后缀要改哪几个地方假设你要加.xyz后缀的支持需要动三个地方。第一在config.php的suffix_list里加上xyz。第二在whois_server映射里加上xyz whois.nic.xyz。第三如果.xyz的返回格式和现有解析逻辑不兼容需要在Parser::parse()里补充对应的关键词判断。改完之后用index.php测试一下确认返回状态正确。5.2 接入自己的项目三种调用方式最直接的调用方式是在你的入口文件里引入核心类?php require_once haifeng-domain/core/Query.php; require_once haifeng-domain/core/WhoisQuery.php; require_once haifeng-domain/core/HttpQuery.php; require_once haifeng-domain/core/Parser.php; require_once haifeng-domain/lib/Cache.php; require_once haifeng-domain/lib/Helper.php; $config require haifeng-domain/config.php; $query new Query($config); $result $query-check(example.com); // 输出[status registered, expire 2025-..., registrar ...] print_r($result);如果你用的是 Composer可以把core/和lib/目录加到autoload的classmap里省去手动require。另一种方式是把整个工具包作为一个独立目录放进项目通过命名空间隔离避免类名冲突。我一般会在项目里建一个tools/目录专门放这类小工具每个工具一个子目录互不干扰。5.3 改造为 API 接口返回 JSON 而不是数组如果你想把查询功能暴露成 HTTP 接口可以在index.php基础上改?php header(Content-Type: application/json; charsetutf-8); $domain isset($_GET[domain]) ? trim($_GET[domain]) : ; if (empty($domain)) { echo json_encode([code 400, msg 缺少 domain 参数]); exit; } // 简单校验域名格式避免传入非法字符 if (!preg_match(/^[a-z0-9\-\.]\.[a-z]{2,}$/i, $domain)) { echo json_encode([code 400, msg 域名格式不正确]); exit; } $config require config.php; $query new Query($config); $result $query-check($domain); echo json_encode([code 0, data $result]);这个接口改造的关键点是加了参数校验避免用户传入奇怪的内容导致查询异常。返回格式统一成code data的结构方便前端处理。如果你要对外提供服务建议再加一层频率限制比如同一个 IP 每分钟最多查 10 次防止被滥用。5.4 一个我踩过的坑缓存 key 的命名最开始写缓存的时候我直接用域名做文件名比如example.com.cache。跑了一段时间发现有些域名带特殊字符比如xn--开头的 punycode 域名文件名里带-没问题但有些后缀带点号比如example.com.cn文件名里有两个点在某些文件系统上会有问题。后来改成用md5($domain)做文件名彻底避开了特殊字符的问题。从那以后我每次写文件缓存都强制走一遍md5命名不再直接用原始字符串做文件名。希望这个习惯能帮到你。本文还有配套的精品资源点击获取