首页 > QQ技巧 > 正文

QQ空间别人的图片中显示我的QQ和昵称是怎么实现的

时间:2014-07-27 12:10 作者:QQ地带 我要评论

鉴于这个问题在网上反复出现,我还是写一篇文章从技术角度解释一下这个问题,也希望这篇文章能让外行人能看懂。
 
很多人都在QQ空间的动态流中见过这样的日志,正文有一张图片,查看的时候可以显示自己(不是发日志的好友,是你自己)的头像和QQ号码、昵称,再配上“您的QQ号已被盗”之类恶搞的措辞,引起恶作剧式的转发。
 
据我所知,这样的图片最早是空间营销的人发明的,因为这样可以让读者主动转发日志,顺便传播日志中的营销信息。因为QQ空间的缓存图片功能,一开始需要读者转载后到自己的空间才能查看。后来经过升级换代,可以直接显示了。
 
图片最核心的手法就是Referer(来源网址)检测。
 
我们每天上网都会接触一个叫做HTTP协议的东西,正是有了HTTP协议,我们才能畅快地浏览网页、刷微博、上知乎。HTTP协议里有很多参数,在你浏览网页或者查看图片的时候会发送给服务器端,如cookie(记录登录状态)和UserAgent(包含用户浏览器版本、操作系统等信息)。其中有一个叫做Referer的字段,作用是标明来源网址。
 
什么是来源网址呢?
 
如你正在浏览知乎,而答案里有一个链接指向新浪微博。在你点开这个链接的时候,为了告诉新浪微博你『从哪儿来』,浏览器会把知乎帖子的网址(整个地址栏的完整文本,不光是域名)作为参数传递给新浪微博的服务器,方便新浪微博做流量统计等工作。
 
还有一种情况是,你在知乎上引用了优酷的一段视频,在加载这个视频的时候,知乎帖子的网址同样会发送给优酷的服务器,这个过程不需要你点击。
 
早在几年前BBS还在流行的时候,很多人设置的签名图具有天气预报、客户端信息(浏览器、操作系统、IP所在地之类)、随机笑话、倒计时等五花八门的功能,就是通过客户端信息和服务器动态生成图片的方法实现的。
 
现在把注意力放到QQ空间。浏览好友动态的时候,你的地址栏应该是这个样子:
 
http://user.qzone.qq.com/574201314
 
574201314部分是你的QQ号。这样只要取到这个号码,自然就可以显示在图片里了。大伙不要纠结那个QZFL了,只是QQ前端为了调整图片大小的一个工具,跟这个恶作剧式的图片无关。
 
不过直接取似乎还有问题。
 
QQ空间有一个缓存图片的功能。凡是发表到QQ空间的日志,正文都会把引用到的所有第三方图片资源缓存到腾讯的云端上。所以正常情况下直接在日志正文中引用的图片,是不会提交REFER到我们的服务器脚本上的。但是有人发现只要服务器端响应HTTP请求的时候输出状态200(HTTP协议里成功的代码),但不输出任何内容,腾讯就不会缓存这张图。
 
这是我在去年3月份编写的代码,可以根据用户端的QQ号码,显示对应的用户昵称、头像、IP所在地。为了减少后端的流量,对下载的头像做了缓存处理。现在是否能用,我没有测试。
 
<?php
error_reporting(0);
ob_start();
header('Content-Type: image/png');
 
define('IMG_NO', "no.png"); #刚开始显示的提示信息
define('IMG_BACKGROUND', "background.png");
define('IMG_WIDTH', 400);
define('IMG_HEIGHT', 128);
define('FONT_NAME', "AdobeHeitiStd-Regular.otf"); #字体文件名,替换成你自己的
define('CACHE_PATH', rtrim(realpath("./cache"), '/').'/'); #缓存目录
define('CACHE_EXPIRE', 60*60); #缓存时间,单位秒
 
#(!is_dir(CACHE_PATH) && is_writable(CACHE_PATH)) || die;
 
/*
 $remote: 远程URL
 $local: 本地缓存路径
 $expire: 过期时间。为-1时,永久不更新缓存
*/
function load_from_cache($remote, $local, $expire = CACHE_EXPIRE, $as_path = false) {
 //过滤潜在的危险字符
 $local = preg_replace("/[.\/\\\?\*\'\"\|\:\<\>]/", "_", $local);
 $cache = CACHE_PATH.$local;
 //查找缓存
 if(file_exists($cache) && ($expire = -1 || filemtime($cache) - time() < $expire))
 return $as_path ? $cache : file_get_contents($cache);
 
 //文件不存在或缓存过期,重新下载
 $content = file_get_contents($remote);
 file_put_contents($cache, $content);
 return $as_path ? $cache : $content;
}
 
/*
 返回客户端信息。
*/
function client_info() {
 $url = "http://ip.taobao.com/service/getIpInfo.php?ip=";
 $ip = ($_SERVER["HTTP_VIA"] && $_SERVER["HTTP_X_FORWARDED_FOR"] ?
 $_SERVER["HTTP_X_FORWARDED_FOR"] : $_SERVER["REMOTE_ADDR"]);
 $info = explode('"', load_from_cache($url.$ip, $ip, -1));
 $string = $info[7].$info[23].$info[31].$info[47];
 return json_decode('"'.$string.'"');
}
 
$referer = $_SERVER['HTTP_REFERER'];
//$referer = "QQ空间";
 
$pattern = "/http:\/\/user.qzone.qq.com\/(\d+)\/infocenter/";
if(preg_match($pattern, $referer, $matches)) {
 //获取QQ号码
 $uin = $matches[1];
 $info = explode('"', load_from_cache(
 "http://base.qzone.qq.com/fcg-bin/cgi_get_portrait.fcg?uins=".$uin, $uin));
 $avatar = $info[3];
 $nickname = iconv("GBK", "UTF-8//IGNORE", $info[5]);
 $client = client_info();
 
//重点来了,生成图片
 try{
 $im = imagecreatefrompng(IMG_BACKGROUND);
 
//绘制头像
 $avatar_file = load_from_cache($avatar, $uin.".jpg", 60*60*24, true);
 $im_avatar = imagecreatefromjpeg($avatar_file);
 imagecopymerge($im, $im_avatar, 14, 14, 0, 0, 100, 100, 100);
 imagedestroy($im_avatar);
 
//绘制文字
 $blue = imagecolorallocate($im, 0, 0x99, 0xFF);
 
$white = imagecolorallocate($im, 0xFF, 0xFF, 0xFF);
 
$texts = array(
 array(12, 148, 40, $white, $uin),
 array(18, 125, 70, $blue, $nickname),
 array(16, 125, 100, $blue, $client)
 );
 
foreach($texts as $key=>$value) {
 imagettftext($im, $value[0], 0, $value[1], $value[2], $value[3], FONT_NAME,
 mb_convert_encoding($value[4], "html-entities", "utf-8")); //解决乱码问题
 }
 
imagepng($im);
 imagedestroy($im);
 
header("Content-Length: ".ob_get_length());
 ob_end_flush();
 } catch (Exception $e) {
 
//die($e->getMessage());
 $error = true;
 }
} else {
 $error = true;
}
 
//在这里直接停止输出即可防止图片被缓存
die();
 
 
代码打包了:http://pan.baidu.com/s/1qW6WSn6

标签: QQ空间
顶一下
(3)
100%
踩一下
(0)
0%

Google提供的广告