简介这是一套开箱即用的域名WHOIS信息查询系统源码面向Web开发初学者与网络运维人员解决快速部署本地化域名注册信息查询服务的需求。资源包含19个文件以4个核心PHP脚本如index.php、whoishub.php、result.php、do.php为逻辑中枢辅以3个HTML页面、3个SVG图标及配套CSS、JS、字体文件ttf/eot/woff/svg和PNG/SVG/ICO等静态资源整体结构清晰、前后端分离明确压缩包仅290KB轻量易部署。已有278人学习下载适合用于课程实验、个人工具站搭建或网络安全信息收集场景。读者可直接运行获得完整域名查询界面含响应式布局、动态结果渲染、错误页处理及品牌标识同时通过源码深入理解WHOIS协议调用逻辑、表单提交流程与前端交互设计是实践Web全栈开发与网络信息服务集成的优质入门范例。1. 这不是个“查域名”的网页而是一套可部署、可审计、可二次开发的 WHOIS 查询服务骨架你手头那个「域名信息查询同款WHOIS源码.zip」别急着解压扔进 Apache 就跑——它根本不是个「点开 index.php 就能用」的傻瓜工具。这是一套完整落地的 PHP WHOIS 查询服务最小可行骨架前端有响应式 UI含 SVG logo、自定义字体、加载动画、后端有 do.php 承担核心查询调度、result.php 渲染结构化结果、whoishub.php 封装底层协议交互逻辑连 favicon.ico 和 404.html 都配齐了。它解决的不是「我想看看百度.com 谁注册的」这种一次性需求而是「我要在内网搭建一个受控的域名资产清查入口」「要给安全团队嵌入一个带审计日志的 WHOIS 接口」「得把 whois 查询能力集成进现有运维平台」这类真实工程场景。适合懂 PHP 基础、会配 Web 服务器、能读简单 socket 通信逻辑的运维工程师、安全研究员或中小项目后端开发者。如果你只想要一个在线查询网站直接搜「免费 WHOIS 查询」就行但如果你需要知道「谁在什么时候查了什么域名」「结果里哪些字段必须保留」「怎么防恶意高频探测」「如何对接内部 CMDB」——这套源码就是你拆解和改造的第一块砖。2. 从协议到 PHPWHOIS 查询不是 HTTP GET而是 TCP 纯文本握手WHOIS 协议本质是基于 TCP 的明文协议端口 43没有加密、没有状态、不走 HTTP。主流注册局如 VeriSign、CNNIC、EURid虽提供 Web 接口但其底层仍是 WHOIS 协议封装。这套源码没走第三方 API而是用 PHP 的fsockopen()直连目标 WHOIS 服务器这是可控性与合规性的分水岭——你清楚每一字节进出也承担全部解析责任。2.1 WHOIS 查询链路域名 → 注册局 → WHOIS 服务器 → 响应解析整个流程不是「发个请求等 JSON 回来」这么简单。以查询example.com为例先向根域名服务器或本地缓存查.com的权威 WHOIS 服务器通常是whois.verisign-grs.com再向该服务器发起 TCP 连接发送纯文本域名example.com\r\n服务器返回原始文本块含注册人、邮箱、创建时间、过期时间、DNS 服务器等字段最后由 PHP 解析这段非结构化文本提取关键字段并 HTML 渲染。源码中whoishub.php就干这事它不硬编码.com或.cn的 WHOIS 服务器而是通过get_whois_server()函数动态查 WHOIS 服务器地址原理是解析 IANA 的 WHOIS 服务器映射表或内置常见后缀规则再调用query_whois_server()建立 socket 连接并发送查询。2.2 核心查询函数query_whois_server()的三重校验逻辑function query_whois_server($domain, $server, $port 43) { $timeout 10; $fp fsockopen($server, $port, $errno, $errstr, $timeout); if (!$fp) { return 连接失败{$errstr} ({$errno}); } // 关键发送域名后必须换行且不能有多余空格 fputs($fp, trim($domain) . \r\n); // 读取响应WHOIS 响应无固定长度需循环读直到 EOF 或超时 $response ; stream_set_timeout($fp, $timeout); while (!feof($fp)) { $line fgets($fp, 4096); if ($line false) break; $response . $line; } fclose($fp); // 防止空响应或乱码检查是否含典型 WHOIS 字段标识 if (empty($response) || !preg_match(/(Domain Name|Registrant Name|Created Date)/i, $response)) { return WHOIS 响应异常未检测到有效字段; } return $response; }提示fputs($fp, trim($domain) . \r\n)这行看似简单却是翻车高发区。很多新手用file_get_contents(http://...)模拟结果被重定向或返回 HTML 页面还有人漏掉\r\n导致某些 WHOIS 服务器如日本 JPRS直接关闭连接。stream_set_timeout()也必不可少——WHOIS 服务器响应慢时PHP 默认会卡死 60 秒这里强制设为 10 秒避免页面假死。2.3 域名后缀智能路由为什么do.php要先查 WHOIS 服务器地址.cn域名走 CNNICwhois.cnnic.cn.jp走 JPRSwhois.jprs.jp.uk走 Nominetwhois.nic.uk。如果对所有域名都连whois.verisign-grs.com.cn类查询会返回「此域名不在本服务器管辖范围」再跳转成本高且不可靠。whoishub.php中的get_whois_server()函数采用两级 fallback一级查内置映射表如$whois_servers [cn whois.cnnic.cn, jp whois.jprs.jp]二级若后缀未定义向whois.iana.org查询该后缀的官方 WHOIS 服务器发送domain .cn\r\n三级兜底用whois.verisign-grs.com仅限通用顶级域。这个设计让do.php在收到?domainxxx.cn请求时能精准路由到 CNNIC而非盲目转发——这是响应速度和成功率的关键差异。3. 前端不是装饰CSS、字体、JS 如何协同支撑一次可信 WHOIS 查询这套源码的前端不是「凑合能看」而是为 WHOIS 查询场景量身定制的轻量级交互层。它规避了现代框架的臃肿用纯 CSS 原生 JS 实现响应式、防抖、结果折叠、复制按钮四大刚需功能且所有资源字体、图标、图片全部内联或本地化不依赖 CDN——这对内网部署和审计合规至关重要。3.1 自定义字体whoisfont.*为什么不用系统默认字体WHOIS 响应中常含非 ASCII 字符如中文注册人、日文地址、俄文字母系统默认字体如 Arial、Helvetica在 Linux 服务器上很可能缺失 CJK 字体支持导致result.php渲染出方块或问号。源码自带whoisfont.ttf等多格式字体包并在style.css中声明font-face { font-family: WhoisFont; src: url(font/whoisfont.eot); src: url(font/whoisfont.eot?#iefix) format(embedded-opentype), url(font/whoisfont.woff) format(woff), url(font/whoisfont.ttf) format(truetype), url(font/whoisfont.svg#WhoisFont) format(svg); font-weight: normal; font-style: normal; } body { font-family: WhoisFont, Microsoft YaHei, sans-serif; }注意font-face的多格式写法是为了兼容 IE8 和现代浏览器。.eot是 IE 专属.woff是主流压缩格式.ttf保底。若你部署在 Nginx 上需确认 MIME 类型已配置application/vnd.ms-fontobject对应.eotfont/woff对应.woff否则字体加载失败回退到系统字体中文仍会乱码。3.2domainPriceQuery.js它真在查价格还是个障眼法文件名domainPriceQuery.js容易让人误以为这是域名抢注价格查询模块但实际代码只有 37 行核心逻辑是// 防抖用户每敲一个字延迟 300ms 再触发查询避免频繁请求 let timeoutId; document.getElementById(domainInput).addEventListener(input, function() { clearTimeout(timeoutId); timeoutId setTimeout(() { const domain this.value.trim(); if (domain domain.includes(.)) { document.getElementById(submitBtn).disabled false; } else { document.getElementById(submitBtn).disabled true; } }, 300); }); // 复制按钮点击一键复制 WHOIS 结果文本 document.getElementById(copyBtn).addEventListener(click, function() { const resultDiv document.getElementById(resultContent); const text resultDiv.innerText || resultDiv.textContent; navigator.clipboard.writeText(text).then(() { this.textContent 已复制; setTimeout(() this.textContent 复制结果, 2000); }); });它不调任何价格 API纯粹是前端体验增强输入防抖防止do.php被刷、按钮状态联动、结果一键复制。这种「名字唬人功能务实」的设计在实战中很常见——开发者用业务术语命名 JS 文件方便后续扩展比如真要加价格查询只需在此文件追加 AJAX 调用。3.3wait.gif与bg.png加载态不是摆设而是用户信任锚点wait.gif是一个 16×16 像素的旋转圆圈 GIFbg.png是深蓝渐变背景图。它们的作用远超视觉美化wait.gif在index.php表单提交后立即显示result.php加载完成才隐藏。用户看到动效就知道「系统正在工作」而非「页面卡了」bg.png作为全屏背景配合style.css中的background-attachment: fixed营造专业感。更重要的是它让result.php的白色结果卡片在深色背景下具备强对比度便于长时间阅读 WHOIS 文本WHOIS 响应平均 500 字符易视觉疲劳。血泪经验我曾在一个金融客户内网部署时删掉了wait.gif改用 CSS 动画。结果部分老旧 IE 浏览器不支持animation加载时白屏 3 秒用户反复刷新误以为服务宕机。后来换回 GIF问题消失——不是技术落后而是兼容性即生产力。4. 部署不是复制粘贴Apache/Nginx 配置、PHP 版本、安全加固三道坎把源码丢进/var/www/html后访问index.php报 500 错空白页do.php返回「Connection refused」别怪源码先过这三关。这套 WHOIS 服务对运行环境有明确隐性要求跨不过就永远停在「能打开」而非「能查到」。4.1 PHP 版本与扩展7.4 是甜点8.2 需微调源码基于 PHP 7.2 编写核心依赖sockets扩展fsockopen、fgets等函数所在mbstring扩展WHOIS 响应含 UTF-8 中文时mb_convert_encoding()用于转码curl扩展备用方案当fsockopen被禁用时whoishub.php可切换为curl_exec()模拟但非首选。验证命令# 检查扩展是否启用 php -m | grep -E (sockets|mbstring|curl) # 检查 PHP 版本推荐 7.4–8.1 php -v # 检查 socket 函数是否可用 php -r echo function_exists(fsockopen) ? OK : FAIL;避坑 / 常见问题 / 排查 / 注意现象 1do.php返回「Warning: fsockopen(): unable to connect to ...」原因服务器防火墙如ufw或 SELinux 禁止 outbound TCP 43 端口或 PHPdisable_functions中禁用了fsockopen。解决sudo ufw allow out 43检查php.ini中disable_functions是否含fsockopen注释掉并重启 PHP-FPM。现象 2查询.cn域名返回乱码中文显示为??原因mbstring扩展未启用或result.php中mb_convert_encoding($response, UTF-8, GBK)的源编码判断错误CNNIC 响应实际是 GBK但部分新版服务器用 UTF-8。解决启用mbstring在whoishub.php的解析函数中增加编码探测逻辑$encoding mb_detect_encoding($response, [UTF-8, GBK, BIG5], true);。现象 3Nginx 下result.php404但index.php正常原因Nginx 未配置 PHP 解析规则或location ~ \.php$块未包含fastcgi_pass指向正确的 PHP-FPM socket。解决检查 Nginx 配置确保location ~ \.php$内有include fastcgi_params;和fastcgi_pass unix:/run/php/php7.4-fpm.sock;路径按实际版本调整。现象 4查询结果中Registrant Email字段为空但 WHOIS 原始响应里有原因隐私保护WHOIS Privacy导致注册邮箱被屏蔽或源码正则表达式/(Registrant Email|Admin Email):\s*(\S\S)/i未匹配新格式如Email: ******.***。解决更新正则为/(Email|Registrant\sEmail):\s*([^\r\n])/i并用trim()清理捕获组首尾空格。4.2 Web 服务器配置Apache 的.htaccess与 Nginx 的重写规则源码未提供.htaccess但index.php和result.php依赖 URL 参数如?domaingithub.com。Apache 默认允许.htaccessNginx 则需手动配置。Apache 方案启用 mod_rewrite在项目根目录新建.htaccessRewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L]这样用户访问/github.com会自动路由到index.php?domaingithub.com更简洁。Nginx 方案推荐在 server 块中添加location / { try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php7.4-fpm.sock; }提示Nginx 的try_files比 Apache 的mod_rewrite更高效且避免.htaccess被意外暴露曾有客户因.htaccess权限为 644被外部直接下载泄露数据库配置。4.3 安全加固为什么do.php必须加域名白名单与频率限制WHOIS 查询本身无害但do.php是开放接口若不做限制可能被滥用扫描大量域名如a.com,b.com…消耗服务器资源查询敏感域名如internal.company.com泄露内网资产作为代理发起 DDoS向 WHOIS 服务器发洪水请求。源码未内置防护需你手动加两层域名格式校验do.php开头$domain $_GET[domain] ?? ; if (!preg_match(/^[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)*\.[a-zA-Z]{2,}$/, $domain)) { die(非法域名格式); }IP 频率限制用 Redis 或文件锁$ip $_SERVER[REMOTE_ADDR]; $key whois_rate_limit:{$ip}; $count (int)file_get_contents(/tmp/{$key}) ?: 0; if ($count 5) { // 5次/分钟 die(请求过于频繁请稍后再试); } file_put_contents(/tmp/{$key}, $count 1); register_shutdown_function(function() use ($key) { // 1分钟后自动清理 unlink(/tmp/{$key}); });5. 解析不是正则完事从原始 WHOIS 文本到结构化数据的四步清洗法拿到fsockopen()返回的原始文本只是万里长征第一步。WHOIS 响应没有统一标准VeriSign 用Domain Name:CNNIC 用Domain Name............JPRS 用Domain Name :甚至同一注册局不同时间返回格式也会微调。硬写正则必然翻车。这套源码的whoishub.php采用「分层解析」策略比单纯preg_match_all()可靠得多。5.1 第一步按空行切分区块Block SegmentationWHOIS 响应天然按逻辑分块Domain Info、Registrar Info、Name Servers、Contact Details。源码用explode(\n\n, $response)切分得到数组$blocks。每个$block是一个语义单元例如Domain Name: EXAMPLE.COM Registry Domain ID: 2121212121_DOMAIN_COM-VRSN Registrar WHOIS Server: whois.godaddy.com ...为什么不用explode(\n, $response)因为单行解析会丢失上下文。比如Email:字段可能在 Contact 区块也可能在 Registrar 区块混在一起正则极易错配。按空行切分先定位「Contact Information」区块再在其中找Email准确率提升 80%。5.2 第二步区块内字段提取Key-Value Extraction对每个$block用以下逻辑提取键值对$lines explode(\n, $block); $pairs []; foreach ($lines as $line) { // 匹配 Key: Value 或 Key : Value 格式忽略空格差异 if (preg_match(/^([^:]):[[:space:]]*(.)$/, trim($line), $matches)) { $key trim($matches[1]); $value trim($matches[2]); // 归一化键名转小写、去空格、下划线替代空格 $normalized_key strtolower(str_replace([ , /], _, $key)); $pairs[$normalized_key] $value; } }这样Domain Name→domain_nameRegistrant Email→registrant_email为后续结构化打基础。5.3 第三步字段标准化Normalization原始字段名五花八门需映射到统一 SchemaWHOIS 原始字段名标准化字段名说明Domain Name/Domain Name............domain_name主域名Registrar WHOIS Server/Whois Serverwhois_server权威 WHOIS 服务器Creation Date/Created Datecreated_date创建时间需统一格式Y-m-d H:i:sRegistrar/Sponsoring Registrarregistrar注册商名称Name Server/DNSSECname_serversDNS 服务器列表需explode()分割源码在result.php渲染前会调用normalize_whois_data($pairs)函数做此映射并对时间字段用date(Y-m-d H:i:s, strtotime($value))标准化。5.4 第四步敏感字段脱敏Privacy Sanitization根据 GDPR 和 ICANN 规定个人注册人信息需脱敏。源码默认对以下字段做掩码处理registrant_email→r***e***.comregistrant_phone→86.138.****.****registrant_name→张***实现方式简单粗暴但有效function sanitize_field($field, $value) { switch ($field) { case registrant_email: return preg_replace(/^(.)(.*?)(?)/, $1***, $value); case registrant_phone: return preg_replace(/(\\d{2}\.\d{3}\.)\d{4}(\.\d{4})/, $1****$2, $value); case registrant_name: return mb_substr($value, 0, 1, UTF-8) . ***; default: return $value; } }玄学提醒WHOIS 解析没有银弹。我曾遇到.io域名返回的Registrant Organization字段含换行符导致explode(\n)切错行。最终解决方案是在Key-Value Extraction前先用str_replace([\r\n, \r], \n, $block)统一换行符再preg_replace(/\n\s\n/, \n\n, $block)合并多余空行。这些细节才是源码能稳定跑一年的关键。6. 进阶技巧把 WHOIS 查询变成资产测绘引擎的三个实战动作这套源码的价值从来不止于「查单个域名」。把它当作一个可插拔的组件嵌入你的资产测绘流水线才能释放最大效能。我过去三年在三个不同客户现场落地的实践总结出三个必做动作每个都能把查询效率提升 3 倍以上。6.1 动作一批量查询 结果归档 —— 用croncurl搭建每日资产快照不要手动查用脚本驱动。在服务器上新建daily_whois.sh#!/bin/bash DOMAINS_FILE/opt/whois/domains.txt # 每行一个域名 OUTPUT_DIR/opt/whois/archive/$(date %Y%m%d) mkdir -p $OUTPUT_DIR while IFS read -r domain; do [ -z $domain ] continue # 调用本地部署的 do.php保存原始响应 curl -s http://localhost/do.php?domain$domain $OUTPUT_DIR/${domain//./_}.txt # 提取关键字段生成 CSV 供 Excel 分析 php /opt/whois/parse_to_csv.php $OUTPUT_DIR/${domain//./_}.txt $OUTPUT_DIR/daily_report.csv done $DOMAINS_FILEparse_to_csv.php用源码的whoishub.php解析函数输出domain,registrar,created_date,expires_date,name_servers字段。每天凌晨 2 点执行自动归档半年后你就有完整的域名生命周期图谱。6.2 动作二对接 CMDB —— 用result.php的 JSON 输出模式替换 HTML源码默认输出 HTML但 CMDB 需要 JSON。修改result.php开头// 新增支持 ?formatjson 参数 if ($_GET[format] ?? json) { header(Content-Type: application/json; charsetutf-8); echo json_encode($parsed_data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT); exit; }然后你的 CMDB 同步脚本就能这样调用import requests resp requests.get(fhttp://whois.internal/result.php?domain{domain}formatjson) data resp.json() # 直接写入 CMDB 的 domain_asset 表后悔药某次客户 CMDB 升级要求所有接口返回 JSON。我们没改源码而是用 Nginxsub_filter模块把 HTML 响应中的div替换成{}结果字段错位、引号逃逸花了两天 debug。从那以后我每次对接新系统都强制走一遍「源码原生支持 JSON 输出」的改造哪怕只加三行代码。6.3 动作三构建变更告警 —— 监控expires_date和name_servers的波动WHOIS 最有价值的信息是变化。用 Python 脚本每日比对# compare_whois.py import sqlite3 conn sqlite3.connect(/opt/whois/whois.db) c conn.cursor() c.execute(SELECT domain, expires_date, name_servers FROM history WHERE date (SELECT MAX(date) FROM history WHERE domain ?), (domain,)) last c.fetchone() # 获取今日数据调用 result.php?formatjson today get_whois_json(domain) if last and (last[1] ! today[expires_date] or last[2] ! today[name_servers]): send_alert(f域名 {domain} WHOIS 关键字段变更\n过期时间{last[1]} → {today[expires_date]}\nDNS{last[2]} → {today[name_servers]})把expires_date提前 30 天告警能避免域名过期导致业务中断name_servers变更则可能是 DNS 劫持信号。这才是 WHOIS 查询真正的护城河价值。希望帮到你。本文还有配套的精品资源点击获取