经常逛博客的朋友一定注意到,我关掉了评论头像的功能有一段时间了。因为它!会!暴!露!号!码!
这可不行啊,所以我就把它关掉了。
前几天更新后端平台的时候,把网站主题也更新了下,看见这个主题项目的Issue里,有人提到了这个问题,并且给了一个不错的解决方案。(但是主题作者没有去完善相关代码)
接下来我们就按照这个网友的思路去解决一下这个问题吧。
我们在主题根目录下找到functions.php文件,查看主题作者本身的实现逻辑是什么样的。
function get_avatar_by_qqnumber($avatar){
global $comment;
if (!isset($comment) || !isset($comment -> comment_ID)){
return $avatar;
}
$qqnumber = get_comment_meta($comment -> comment_ID, 'qq_number', true);
if (!empty($qqnumber)){
preg_match_all('/width=\'(.*?)\'/', $avatar, $preg_res);
$size = $preg_res[1][0];
return "<img src='https://q1.qlogo.cn/g?b=qq&s=640&nk=" . $qqnumber ."' class='avatar avatar-" . $size . " photo' width='" . $size . "' height='" . $size . "'>";
}
return $avatar;
}
可以看见,作者是直接获取QQ号码填入到这个地址以获取头像的,现在我们按照这个网友的思路去进行改造。
首先,我们先确认一下,这个网友给的链接,如果我们填入参数,会获取到一个什么样的信息。
果然,我们获取到了一个json地址,里面包含了QQ号和一个链接,我们来访问这个链接看看:
根据这个链接的结果,我们成功获取了头像,接下来我们按照这个博主的方法去实现相关的代码逻辑吧。
//QQ Avatar 获取
function get_avatar_by_qqnumber($avatar){
global $comment;
if (!isset($comment) || !isset($comment -> comment_ID)){
return $avatar;
}
$qqnumber = get_comment_meta($comment -> comment_ID, 'qq_number', true);
if (!empty($qqnumber)){
preg_match_all('/width=\'(.*?)\'/', $avatar, $preg_res);
$size = $preg_res[1][0];
$linkqq = 'http://ptlogin2.qq.com/getface?&imgtype=1&uin='.$qqnumber;
$json_v = json_encode(file_get_contents($linkqq),true); //抓json
$k_v = explode("&k=",$json_v)[1]; //去读这个json,获取k之后的值
return "<img src='https://q1.qlogo.cn/g?b=qq&s=640&k=" . $k_v ."' class='avatar avatar-" . $size . " photo' width='" . $size . "' height='" . $size . "'>";
}
return $avatar;
}
实际上,这不是一个效率很高的方式,我们知道 file_get_contents() 会读入每一个链接去获取参数,这会大大影响网页加载,但我们有没有什么更好的方法去处理这个逻辑呢?例如json里的地址能不能直接跳转这些?然而不管怎么样,只要涉及到操作这个json,网页效率就一定会影响。
本来感觉很棘手打算就这样的时候,我看着这些链接地址,总感觉腾讯是不是留了其它的接口。因此我在网上找了下如何在网页获取QQ头像的方法。
有一篇文章(链接可以点)里,涉及到了一个新的地址:
https://s.p.qq.com/pub/get_face?img_type=3&uin=(qq_number)
然后我把参数填入这个地址里,发现网址自动跳转成了跟json一样的地址,并且直接加载出来了图片。
这就好操作了,我们可以直接读取这个页面的header,将跳转后的地址抓下来,直接对这个地址进行分析不就好了嘛!
因此我又改了下:
function get_avatar_by_qqnumber($avatar){
global $comment;
if (!isset($comment) || !isset($comment -> comment_ID)){
return $avatar;
}
$qqnumber = get_comment_meta($comment -> comment_ID, 'qq_number', true);
if (!empty($qqnumber)){
preg_match_all('/width=\'(.*?)\'/', $avatar, $preg_res);
$size = $preg_res[1][0];
$linkqq = 'https://s.p.qq.com/pub/get_face?img_type=3&uin='.$qqnumber;
$url = get_headers($linkqq, true)['Location']; //抓跳转后的链接
$k_v = explode("&k=",$url)[1]; //去读链接里k后面的值
return "<img src='https://q1.qlogo.cn/g?b=qq&s=640&k=" . $k_v ."' class='avatar avatar-" . $size . " photo' width='" . $size . "' height='" . $size . "'>";
}
return $avatar;
}
经过测试,完美实现,终于不用担心隐私泄露的问题了。
2024.4.13 更新:
站长在日常维护网站的时候,发现部分页面无法显示,通过开启 Debug 模式,检查到所有显示 QQ 头像的地方出了问题:
对应的代码部分如下:
一开始以为是代码出错了(因为有升级 PHP),但是警告和弃用标志是不会导致 500 的故障发生的,于是尝试访问获取头像的地址:
网上查询资料后,发现鹅厂封禁了大部分获取头像的方式,目前只有主题作者采用的显式获取的方法,也就是需要暴露 QQ 号。这不行啊,这样的话我可能就要把这个功能关掉了。。
突然想起来,既然通过 QQ 号获取直接是一张图片,不如把图片用 Base64 加密后再在网页上显示如何?于是就有了如下改动:
function get_avatar_by_qqnumber($avatar){
global $comment;
if (!isset($comment) || !isset($comment -> comment_ID)){
return $avatar;
}
$qqnumber = get_comment_meta($comment -> comment_ID, 'qq_number', true);
if (!empty($qqnumber)){
preg_match_all('/width=\'(.*?)\'/', $avatar, $preg_res);
$size = $preg_res[1][0];
$avatarqq = 'https://q1.qlogo.cn/g?b=qq&s=640&nk='.$qqnumber;
$avatarqq_data = file_get_contents($avatarqq);
$avatarqq_base64 = base64_encode($avatarqq_data); //Base64 加密
return "<img src='data:image/png;base64," . $avatarqq_base64 ."' class='avatar avatar-" . $size . " photo' width='" . $size . "' height='" . $size . "'>";
}
return $avatar;
}
问题得到解决,可以继续保持不泄露 QQ 的情况下显示头像了。