简介:这是一份PHP版QQ空间最近访客查看器的工具源码,定位为轻量级网站查询小工具,适合PHP初学者、毕业设计及课程设计人群借鉴。它围绕“最近访客查询”功能提供了一套可运行的PHP实现,配套txt说明文件详细介绍部署与使用方式,便于快速上手。资源包整体非常小巧,共2个文件,其中1个php文件为核心功能代码,另1个txt文件为使用说明,压缩包大小仅3KB,携带和部署都很方便。目前已有93人学习下载,适合用于理解PHP网页请求、数据交互及简单工具开发的完整思路。代码经过基础验证可直接运行,学习者可以将其直接用作QQ空间访客查看工具,也可以在原有逻辑上修改扩展,改造成其他网站查询或管理模板,进一步巩固项目开发能力。同时,该资源也常被用作课程设计、大作业或工程实训的初期项目样本,帮助初学者快速进入网站开发实战。
1. 先说结论:这份PHP访客查看器,本质是一个能跑的「数据接口+展示页」模板
QQ空间最近访客查看器PHP版,拆开压缩包看到的是一整套可以直接部署的查询工具:PHP端负责往QQ空间的访客接口发请求、拿JSON、解析数据,HTML端负责把访客头像、昵称、访问时间渲染成一个像样的页面。它不是什么黑科技,也没有碰任何违规的东西,就是利用了QQ空间网页版自己的访客接口,前提是你自己账号的cookie和登录态有效。
这工具最适合两类人:一是拿它当毕业设计选题的学生,二是想快速搭一个「查询类工具站」的开发者。你不需要懂太多前端,把PHP文件放进去、改几个参数,页面就能出数据。但如果你想本地跑起来、再改造成自己的东西,有几个点必须先搞清楚——比如cookie怎么来的、g_tk怎么算、接口返回的字段怎么对上。下面直接从拆包开始讲。
2. 拆开压缩包:项目结构与本地环境搭建
2.1 压缩包里到底有什么:五个文件各自的职责
拿到qqvisitorphp这个压缩包,先别急着往服务器上传。先解压,把文件列出来,看清每个文件是干嘛的。我解压后看到的典型结构是这样:
qqvisitorphp/ ├── index.php # 入口文件,负责组装页面和处理请求 ├── qq_visitor.php # 核心类库,封装访客接口请求与解析 ├── config.php # 配置文件,填QQ号和cookie的地方 ├── html/ │ ├── index.html # 静态模板,展示访客列表 │ └── assets/ │ ├── style.css # 页面样式 │ └── script.js # 前端交互 └── 使用说明.txt # 作者写的部署说明这个结构很典型:入口文件负责调度,核心类库负责业务逻辑,配置文件负责参数,HTML目录负责展示。你在index.php里引入qq_visitor.php,调用它的方法拿到数据,然后输出HTML。如果只看index.php,你会发现它逻辑很薄——基本就是「读配置 → 调类库 → 输出页面」三步。
这里有个常见的坑:使用说明.txt里写的部署步骤往往很简略,只告诉你「修改config.php,放到服务器,访问index.php」。但实际跑的时候,光改config是不够的,你还要确认PHP开了curl扩展和json扩展。后面踩坑章节会专门讲。
2.2 本地跑起来:用phpstudy或宝塔三分钟启动
本地调试我一般推荐用 phpstudy(Windows下最省事)。下载安装后选一个PHP版本,我建议用 PHP 7.4 或 8.0,太老或太新都可能遇到扩展不兼容的问题。你把解压后的整个文件夹丢到phpstudy_pro\WWW目录下,然后启动Apache和MySQL(其实这个项目用不到MySQL,纯文件型,但phpstudy默认一起启动没问题)。
启动后浏览器访问:
http://localhost/qqvisitorphp/index.php如果你看到了页面框架但没有数据,多半是config.php里的cookie没填或者已经过期。这项目不依赖数据库,数据全从QQ空间接口实时拉取,所以本地跑通的关键就一个:让PHP发出的请求,看起来像是一个正常用户在浏览器里访问QQ空间。
2.3 参数说明:访客接口的URL结构与必填参数
访客数据的获取,本质是向QQ空间的一个接口发HTTP请求。这个接口的域名是h5.qzone.qq.com,路径是/proxy/domain/visitor2.cgi/visitor_list_get。在实际代码里,核心类库会把参数拼成一个URL再发请求。典型的参数表如下:
| 参数名 | 含义 | 示例值 |
|---|---|---|
uin | 目标QQ号,查谁就填谁 | 10001 |
proxy_uin | 代理查询的QQ号,一般同uin | 10001 |
g_tk | 登录态校验值,由cookie里的p_skey算出来 | 1941324059 |
qzonetoken | 空间令牌,登录后从页面或cookie里取 | 一串随机字符 |
format | 返回格式,固定写json | json |
count | 每页返回条数,建议10 | 10 |
order | 排序,1表示按访问时间倒序 | 1 |
g_tk不是凭空来的,它是由cookie里的p_skey经过一个固定算法算出来的。这个算法是腾讯公开的,很多开源项目里都有,后面章节会贴代码。qzonetoken则是登录空间后在页面源码里能搜到的一个token字段。如果你是自己登录的账号,这两个值能在浏览器开发者工具里直接复制出来。
提示:当你发现接口返回code: -3000时,基本就是g_tk跟cookie不匹配或者token过期了。先去浏览器重新登录一次,再复制新的值。这算是这个工具最常见的问题,没有之一。
3. 核心代码拆解:PHP怎么拿到访客JSON并解析
3.1 请求流程:Cookie、Referer与UA三个头缺一不可
要让QQ空间的接口把数据吐给你,光有URL是不够的。服务端会校验三个东西:请求头里的Cookie、Referer和User-Agent。Cookie用来确认你的登录身份;Referer必须指向https://user.qzone.qq.com/<你的QQ号>,让服务端觉得你是在空间页面里发起的请求;User-Agent则要伪装成一个完整的Chrome浏览器。
我见过有人只填了Cookie没设Referer,结果接口返回一堆-3000错误码。这三个头信息在PHP里是通过curl_setopt设置的:
curl_setopt($ch, CURLOPT_COOKIE, $cookie); // 登录态 curl_setopt($ch, CURLOPT_REFERER, $referer); // 来源页面 curl_setopt($ch, CURLOPT_USERAGENT, $userAgent); // 浏览器标识如果你用浏览器的复制Cookie功能,注意别漏掉p_skey这一段。p_skey一般是登录后种在Cookie里的,长度在几十到一百多字符之间,它直接决定g_tk的值对不对。很多人复制Cookie时习惯只复制一段,结果漏了p_skey,接口就报错。
3.2 PHP代码逐段拆读:从curl请求到数组解析
核心类库qq_visitor.php的逻辑可以拆成三段:计算g_tk、发请求、解析JSON。下面我贴出典型实现并逐段说明。
先看g_tk的计算函数,这是整个工具的地基:
<?php // 计算g_tk,p_skey为cookie中取到的值 function getGTK($p_skey) { $hash = 5381; $len = strlen($p_skey); for ($i = 0; $i < $len; $i++) { // 左移5位相当于乘32,再加字符ASCII码 $hash += ($hash << 5) + ord($p_skey[$i]); } // 转成32位有符号整数,等价于JS里的 & 0x7fffffff return $hash & 0x7fffffff; }这个算法的charm点在于它和前端JS版的结果必须完全一致。因为g_tk是前端登录后算出来再随请求发出去的,PHP这边如果运算顺序或位运算处理不对,算出来的值三五天就变一次,接口就间歇性失效。我调试时发现,$hash初始值必须是5381,不能改成别的,否则永远签不上。
接下来是发送请求并解析的核心函数:
<?php function getVisitors($uin, $gtk, $qzonetoken, $cookie) { $url = "https://h5.qzone.qq.com/proxy/domain/visitor2.cgi/visitor_list_get"; $params = [ 'uin' => $uin, 'proxy_uin' => $uin, 'g_tk' => $gtk, 'qzonetoken' => $qzonetoken, 'format' => 'json', 'count' => 10, 'order' => 1 ]; // 把参数拼接到URL后面 $url .= '?' . http_build_query($params); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_TIMEOUT, 15); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 本地调试跳过SSL证书验证 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_COOKIE, $cookie); curl_setopt($ch, CURLOPT_REFERER, "https://user.qzone.qq.com/{$uin}"); curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36"); $response = curl_exec($ch); curl_close($ch); // 接口返回的是JSON字符串,转成数组 $data = json_decode($response, true); return $data; }参数说明:http_build_query会自动做URL编码,比手拼字符串安全;CURLOPT_TIMEOUT设15秒是因为访客接口偶尔响应慢,不设超时的话PHP进程会一直挂在那;SSL_VERIFYPEER和SSL_VERIFYHOST在本地调试时设false省事,部署到公网建议改为true并配上证书路径,否则容易被安全扫描器标记。
拿到返回值后,我们真正关心的是data.visitors数组。这个接口返回的结构大致是:
Array ( [code] => 0 [message] => ok [data] => Array ( [visitors] => Array ( [0] => Array ( [uin] => 123456789 [nickname] => 某某 [avatar] => https://q1.qlogo.cn/... [visitTime] => 1716163200 ) ) [total] => 86 ) )注意visitTime是Unix时间戳,展示到页面上时要转成日期格式。有些改版把昵称字段写成nick而不是nickname,解析的时候建议用isset判断一下,别直接取,否则PHP会报未定义索引的警告。
3.3 数据校验:返回为空时先看code再查请求
很多人改完参数刷新页面,看到的是空列表,于是怀疑接口被封了。实际上大部分情况是请求参数没拼对。我自己的调试顺序是:先var_dump($data)打印整个返回数组,看code字段。code=0表示请求成功,这时候问题在解析层——比如字段名不匹配。code=-3000则说明登录态失效,需要重新抓cookie。code=-100往往是参数缺失,检查g_tk是否为空。
这里有一个容易翻车的细节:如果你在服务器上调试,服务器的IP可能触发QQ空间的异地登录校验。前台表现为接口返回正常,但data.visitors为空数组。我遇到过一次,后来在config.php里把请求超时调大到30秒,问题消失——大概率是服务端延迟导致旧接口提前返回空数据。这个经验不一定适用于所有账号,但值得先试。
4. 把数据变成页面:HTML模板与前端渲染
4.1 HTML模板的数据绑定方式:PHP直接嵌入还是JS异步
压缩包里自带的html/index.html是一份静态模板,但真正输出页面时,index.php会把PHP解析好的访客数组循环渲染成HTML片段。最早这个模板用的是纯PHP嵌入方式,也就是在HTML里写<?php foreach ($visitors as $v): ?>的写法。好处是简单、不需要跨域,坏处是页面和逻辑耦合,改样式得在PHP文件里改。
如果你要改造成前后端分离,常见做法是让PHP只输出JSON,前端用fetch异步拉取。比如访问api.php?uin=123456时返回JSON,script.js里再渲染卡片。这样做的好处是同一个接口可以给多个页面复用,做毕业设计时也更好跟老师讲「前后端数据交互」。
我拿到这套模板后,更推荐改成异步方案。原因很现实:访客接口的响应时延不稳定,如果PHP端同步渲染,用户打开页面可能要等两秒才看到完整内容;改成异步后,可以先渲染页面框架,数据到了再填充列表,体感快很多。
4.2 头像加载与时间格式化的两个小坑
访客头像字段返回的是QQ头像的URL,域名叫q1.qlogo.cn。这个域名在浏览器里直接访问没问题,但如果你把页面部署到自己的服务器,且设置了严格防盗链,头像可能一张都出不来。解决方案是在<img>标签里加referrerpolicy="no-referrer"属性,或者干脆在PHP端把头像URL换成https://q1.qlogo.cn/g?b=qq&nk=<对方QQ号>&s=140这种规范化格式。
时间格式化我一般这样处理:
<?php // visitTime是Unix时间戳,转成"刚刚 / x分钟前 / yyyy-MM-dd HH:mm"格式 function formatVisitTime($timestamp) { $diff = time() - $timestamp; if ($diff < 60) return '刚刚'; if ($diff < 3600) return floor($diff / 60) . '分钟前'; if ($diff < 86400) return floor($diff / 3600) . '小时前'; return date('Y-m-d H:i', $timestamp); }这个函数的边界就是$timestamp有可能是空的,比如旧数据里没存访问时间。调用前加一个empty($timestamp)判断,否则date()会告警。
4.3 分页与下拉加载:count参数和翻页机制
访客接口的单次返回条数由count参数控制,实测这个接口单次最多返回20条,设大了也不会多给。所以要看全部访客,就必须做翻页。目前接口没有直接给「页码」参数,而是用last_visit_time来做游标:第一页请求不带这个参数,拿到数据后记住最后一条的visitTime,下一页把它作为last_visit_time传进去,接口就会返回更早的访客。
前端下拉加载的逻辑我封装成这样一个函数:
// 加载下一页访客数据 function loadMore() { fetch('/api.php?uin=' + qqNumber + '&last_visit_time=' + lastVisitTime) .then(res => res.json()) .then(data => { if (data.data.visitors.length === 0) { document.getElementById('no-more').style.display = 'block'; return; } // 追加渲染... lastVisitTime = data.data.visitors[data.data.visitors.length - 1].visitTime; }); }注意最后一条lastVisitTime一定要往旧时间方向移动,否则接口会一直返回同样的数据,表现为列表无限重复。我在第一次写时就翻过车,原因就是把时间传反了,让接口以为要看最新的数据。
5. 避坑实录:访客查看器最容易翻车的五个问题
5.1 接口返回code: -3000,页面一只访客都没有
现象:填写好config.php后访问index.php,页面框架正常,但列表区空白,抓包看到接口返回{"code":-3000,"message":"..."}。
原因:这是登录态失效或g_tk计算错误。-3000在QQ空间的接口体系里就是「请重新登录」的意思。Cookie过期、p_skey被顶掉、qzonetoken没填对,都会触发这个错误。
解决:打开浏览器重新登录QQ空间,在开发者工具里复制最新的Cookie和qzonetoken,替换到config.php。同时用前面贴的getGTK函数重新算一遍g_tk。我建议写一个小脚本专门输出g_tk,方便随时核对。
5.2 有时候能出数据,有时候空列表
现象:同一个配置,早上访问有数据,下午刷新就空了,但接口返回的code仍然是0。
原因:大概率是触发了QQ空间的频率限制或风控。访客接口对短时间内的请求次数很敏感,如果页面每次刷新都实时拉取,很容易被临时限制。
解决:加一层缓存。把访客数据缓存到本地文件或Redis,比如设置5分钟有效期。5分钟内的请求直接从缓存读,不重复打接口。缓存有效期不宜太长,否则访客数据就不「最近」了。
5.3 部署到Linux服务器后,页面空白
现象:本地phpstudy一切正常,传到服务器上后访问index.php,页面空白,浏览器控制台显示500错误,查看日志看到curl相关报错。
原因:大概率是服务器上的PHP没有安装或启用curl扩展。Windows版的phpstudy默认带curl,但Linux上很多精简安装没有。
解决:执行下面命令安装扩展,然后重启PHP服务。
sudo apt install php-curl sudo systemctl restart php7.4-fpm如果是宝塔面板,直接在「软件商店」里找到PHP,点「安装扩展」,勾选curl,保存后自动重载。装完再刷新页面,基本就能跑通。
5.4 访客头像全部显示为默认图或裂图
现象:昵称和时间都正常,但头像全部显示成QQ默认头像,或者干脆不显示。
原因:头像URL被防盗链拦截。QQ头像的CDN会校验Referer,如果你的页面域名不是QQ自家的,图片请求会被拒绝。
解决:给所有头像<img>标签加referrerpolicy="no-referrer"属性。如果还不行,就在PHP端把头像URL里的域名替换为q1.qlogo.cn的标准格式,这个域名对Referer的校验最宽松。
5.5 本地访问正常,手机浏览器打开布局全乱
现象:电脑上页面很整齐,手机上访问排版错乱,头像一张张竖着排,间距也怪。
原因:模板里的CSS用的是固定宽度,没有加响应式布局。手机浏览器屏幕窄,固定宽度直接被截断或缩放。
解决:在style.css里补一段媒体查询,让列表在窄屏下变为单列、头像缩小。常见做法是给列表容器加max-width: 100%,再用@media (max-width: 600px)调整卡片内边距和头像尺寸。改完记得清一下浏览器缓存再测。
6. 拿去做毕业设计或工具站:上线前的三个加分改动
做到这步,你的访客查看器已经能跑起来了。但如果是为了毕业设计答辩或者日后的工具站维护,我再推荐三个改动方向。
第一,把访客查询封装成独立API。改一个api.php,接收uin参数,返回JSON,前端用fetch拉取。这样答辩时你就能清晰说出「前端展示层与后端数据层分离」的架构设计。同时,把config.php里的cookie配置改成从环境变量读取,避免把敏感信息直接写在文件里。
第二,给数据加缓存。用文件缓存就够,访客数据存到cache/目录下,以QQ号+日期做文件名,有效期5分钟。这能显著降低接口被限流的概率,也让你在演示时弱网环境下页面依然秒开。
第三,做一个「历史访客记录」页面。把每次拉取到的访客数据按时间戳存下来,用简单表格展示。虽然原始模板没这个功能,但加个history.php并不复杂,而且特别契合「最近访客查看器」这个主题——访客来了、走了、哪天来的,全都有迹可循。
从那以后,我每次部署类似的项目,都会强制走一遍检查清单:curl扩展是否启用、cookie是否最新、缓存是否开启、防盗链是否处理。这套流程虽然简单,但帮我省掉了无数次「明明代码没动却突然不能访问」的血泪排查。希望这套拆解和踩坑记录能帮到你,尤其是第一次接触QQ空间接口的人,按着这篇的顺序走,比对着原文摸索要省力得多。
本文还有配套的精品资源,点击获取