|
|
作者:Hackfan
' X* W' ~1 w+ \5 A日期:2005.8.21凌晨
0 c! [+ I/ U( a* \联系:QQ:106814 Email:hackfan@vip.sina.com # ~+ B; |6 s$ L$ n% L, g
/ s9 E! {* t E! N: l1、研究说明 7 ~+ y: f I: b7 o" P
5 T$ ~: |3 i/ D. x ?+ }" T# n T Tencent在tqq.tencent.com的8000有一个使用HTTP的QQ接口,通过这个接口,可以进行一些基本的操作,如:登陆、登出、改变登陆状态(上线、忙碌、离线、隐身)、添加删除好友、查看好友信息、发送验证信息(接受被加为好友、申请加对方为好友、拒绝被加为好友)、收发用户消息、系统信息。 2 l6 @9 O5 S! u" u* [
* s1 C* k( l/ z: c
目前我研究的是1.1版本的HTTP QQ协议,研究是微程在的成果上进行的,不敢说有什么超越,只不过更为详细和准确。
* g. _1 h. K9 H$ {" q/ |+ c# l8 `5 V d$ r1 x
2、接口说明: / Z. R7 ?4 y1 m9 j" H1 ~+ v
* R" h" Q) {: F
接口位置:tqq.tencent.com:8000 ( M) h3 _* e$ z8 Z% A1 k
通信协议:HTTP / s& x c; I1 v: N2 ~
数据传输方法:POST ( f; R9 V$ A2 C" i L3 j6 ]
HTTP请求格式:
. Q) e2 x+ f F' I- Z& q$ I: i
5 X# V; s7 l& P5 \" v6 F% VPOST HTTP/1.1 ! N! t0 ~" r. Z
Host: tqq.tencent.com:8000 7 a8 ]% d7 C4 N- Q7 @9 s0 k" E
Content-Type: text/plain; charset=UTF-8
0 y; Z4 a- M/ C# _; a2 `Content-length: 长度
. `6 |- l' ^9 ~- o( M$ C9 B; nConnection: close
1 c& O1 s- J0 A1 a+ M+ l' O( I. T+ |) a k+ s' D; }6 R& r# M n! t
数据 4 n/ }- Y5 g% M$ Q8 h$ y" J, l
' ]4 i* M; q% O' @5 D 其中长度为 数据 的长度,数据的格式: : ~4 L. f6 E9 ]/ |$ O1 z) F9 M" g
VER=1.1&CMD=命令&SEQ=标记&UIN=QQ号&....
( k# y! u9 Y. l5 O/ U6 h3 N, q- `1 X7 h- I
以上4个参数是每个请求都必有的。其中,VER表示协议的版本,目前为1.1,据说1.2已经出来了,这个乱写的话,服务器返回NULL; CMD为操作的指令,有Login、List、Query_Stat、GetInfo、AddToList、Ack_AddToList、 DelFromList、Change_Stat、GetMsgEx、CLTMSG、Logout;SEQ为当前请求的标记,防止重复发送,可以用当前时间,也可以用随机数;UIN是当前执行操作的QQ号。不过不同的CMD还需要不同的参数,下面我就公布我的研究成果。 4 ~0 f; Y0 K) g; w
$ F5 i; S+ e4 y! K) O7 ]! R# D
3、研究方法: , B6 c2 _9 k& g i: [! F: w
; L- K: _& Q5 a- u6 {
我对目前网上的资料不够满意,就自己写程序,发送多条相同CMD不同参数的请求,根据服务器的返回,来做判断。感兴趣的朋友可以参考一下,此处可以跳过。 : k" m2 N4 B7 H# {# W3 x* G
下面我公布我探测的代码(PHP):- <?
2 m* b( G. R) a, s+ ^ - $uin = "QQ号";
0 Q0 O0 a4 h; w9 ] l - $pwd = md5("QQ密码");
8 a$ n+ j9 r9 a/ j+ p% g1 K# l - 4 u# X9 ^& U Z4 N0 A) f9 B
- //登陆测试
1 S1 }9 l9 ?- X4 P: k. }: C - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235"; ' K8 |& T" [2 d0 ^9 t/ {* C# g
- //注意:登陆测试不能同时进行,必须等到服务器认为QQ断开了,才能够测试,不然结果不可信 ' F+ A. P( x. v
- /*******
% U' a$ x4 \) r" I8 { - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=0&LC=9326B87B234E7235";
0 D( a# u# Y4 y) n+ ^9 i1 {- o - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=1&LC=9326B87B234E7235";
' s. d' z$ o/ U+ X; | - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=2&LC=9326B87B234E7235";
% r6 |0 D0 o! ?+ ]" q; e. n) \ - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M5=3&LC=9326B87B234E7235";
& \' @. J7 O% E( J- R" f - $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=9326B87B234E7235"; . @. a3 [1 w+ u( N
- $poststring[] = "VER=1.1&CMD=Login&SEQ=".rand(1000,9000)."&UIN=".$uin."&PS=".$pwd."&M6=1&LC=1223423545756679";
7 x. Q6 m- f! T1 R( c* Y' C - *******/ 6 ]2 v$ E0 V$ O5 m5 e9 ~
. l' p7 v& S5 F7 ^
0 I* c" H3 _5 J! Z+ I- //得到好友列表 % g1 g F( l7 c P# F3 e2 N% l7 ]
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin;
, L" `3 i8 S( `- P* f8 m - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0";
0 C+ g( s# r4 e* N' E5 P7 R# s! p - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160";
- a" F# `& _; l+ E9 ?; e5 u - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0";
2 s% r. |3 L* M* u% k - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10); 5 k; r: g K p- W5 Q" H# @$ Y
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0"; 8 z! L3 R* |* x% V0 g7 U
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; - N C3 j* `5 ?( E% J2 `- u
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; ) a7 v: a/ t1 ], s. K4 w
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
/ B/ I/ J; Q- Z - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; 9 \& b/ n- }, \: I+ g( e
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; + o% G* M0 p. f2 X1 b$ X
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
2 c+ g. a) b* o6 P) s, l C; K6 @ - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10);
5 [" N5 V. H$ Q! O - $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); + ]% H- W2 \% |- J# N9 v) Y
- $poststring[] = "VER=1.1&CMD=List&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814";
, k: r/ P% w6 X! ] a- @* I% |
- S# M' h3 Z& t$ m4 T$ c- //得到在线列表
$ V7 l$ m, v4 @* f3 d, p5 L, ^ - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin; 1 R, W& X! @. S1 O4 i6 r
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0";
# L* M7 h- P& W( I - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160";
, ]( E' Z$ f' q8 B! a - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=0"; 4 n; J# J! ?# j
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=".rand(1,10);
$ j! J3 F; F0 P/ W9 k/ H8 D. H - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=0"; ) e& `! O. E) P" a( W5 T
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; , Y; q3 I9 u1 i! \) b2 Q
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=160&UN=0"; 5 V* \ e6 o0 v
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
' n' [' X& A+ d# { - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0"; 2 l5 X) E7 P6 s0 e }$ W/ x" Z
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=".rand(1,200)."&UN=0";
! S6 e- {( I2 i - $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); ; S( ^/ n4 H, Q' q) O! f6 \
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); ) H5 L& p# @0 q+ L) }
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=".rand(1,10); 4 W9 M' W+ T4 w6 K! L
- $poststring[] = "VER=1.1&CMD=Query_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&TN=0&UN=106814"; ! E: U2 G2 T+ e9 d2 B* Y
- 7 Q) }8 M ~2 f( C' X; Z
- //查看好友信息 . D2 @4 e5 m- }4 Z) Y
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=0&UN=106814"; 0 z' }) [9 `0 V2 V# h
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=1&UN=106814";
. H0 J! e3 n5 O# I: T - $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=2&UN=106814";
7 X+ R5 U5 K1 G" T' q$ A( L - $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=3&UN=106814"; - X' b. l2 g7 N- v
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=4&UN=106814"; 9 o; [! g: i1 U; k- {$ s
- $poststring[] = "VER=1.1&CMD=GetInfo&SEQ=".rand(1000,9000)."&UIN=".$uin."&LV=5&UN=106814";
% A* k' q3 c4 ~" W. f
: G7 c% L" l3 M$ W& j$ g) t; o- //增加好友 : o. u0 s; [- _* H4 y, |7 \
- $poststring[] = "VER=1.1&CMD=AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814";
: d& M$ L- @0 V2 D: v - ) |6 V; c" q3 ?, x% q7 ?% k0 K2 Q4 W
- //发送验证 ) S, e- g* A( F+ l% H- S7 H
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=0&RS=TEST"; 6 X4 p5 n) `: c
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=1&RS=TEST"; 9 c9 [* D: V0 D- Y$ E& v
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=2&RS=TEST";
% M& u9 k2 m2 Q& J7 x; H. b6 y - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=3&RS=TEST";
" `6 d! c7 l0 ?) W - $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=4&RS=TEST"; # f) G# w# U8 p5 ?2 \! Y( H8 a* u
- $poststring[] = "VER=1.1&CMD=Ack_AddToList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&CD=5&RS=TEST";
& Q8 B' |) ^% P8 }* k
* r6 h$ Z% \& g- //删除好友
4 u0 N7 Q, d8 D4 a' d* j - $poststring[] = "VER=1.1&CMD=DelFromList&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814"; , Z7 g& ~' W9 f! S" H1 R* s
- 9 }6 i0 d! K) O: Y1 X
- //改变状态
- S! g9 ~% ]6 U/ J& D- N5 ` n4 I - for($i=0;$i<=60;$i=$i+5) + R- r# ^4 D, @* ~2 \. V
- {
! ^9 e2 U! ?8 m( U8 h - $poststring[] = "VER=1.1&CMD=Change_Stat&SEQ=".rand(1000,9000)."&UIN=".$uin."&ST=".$i; 8 _ d8 }: b2 u1 t
- }
* O# A' v& j$ o" |2 c7 L. y& B
9 z# _8 u5 S. ?9 E' H- //获得消息 # A' S! d4 E" l4 h* ^
- $poststring[] = "VER=1.1&CMD=GetMsgEx&SEQ=".rand(1000,9000)."&UIN=".$uin."";
2 ^$ _3 f+ P5 O - ) W3 ]6 t9 \- ~. I0 x/ m1 W* t- y
- //发送消息
8 l8 ^# B8 B6 e+ T& a' s - $poststring[] = "VER=1.1&CMD=CLTMSG&SEQ=".rand(1000,9000)."&UIN=".$uin."&UN=106814&MG=TEST"; # Z, s5 e2 p4 B* }( T4 [* N0 v! g/ b
0 L9 e( R0 `5 e. v- S- //登出 0 c0 \: d# r# e1 ~+ L+ d# {
- $poststring[] = "VER=1.1&CMD=Logout&SEQ=".rand(1000,9000)."&UIN=".$uin.""; / P4 A" J' S5 I9 K" U& u1 R5 F
9 E7 t$ g9 }) h7 B- $file = fopen("p.txt","w");
3 p; I* Q8 ]8 K `( `! m4 z% P
, Q+ O9 {! K5 m: ~1 m( j- foreach($poststring as $k=>$v) : ^ C0 I, C* { n7 N9 T0 c
- { & L' z" _. k$ @$ O
- ss_timing_start();
" }: C( ]% Y+ P - $fp = fsockopen('tqq.tencent.com', '8000', $errno, $errstr, $timeout = 10);
, J! v+ X/ @) ?5 Z' y - % k5 {: w! R) _' a9 A
- if(!$fp){ % g9 o3 \) t$ {7 t0 C
- //error tell us
% G8 q9 i A8 V - $content = $k.chr(13).chr(10)."ERROR:$errstr ($errno)"; 2 g/ e% G c( T: o
-
c( `$ H; Y- B2 s - }else{
8 X1 G: }) F5 \. R$ r O" U. T( G
4 _& M, i! b- n' U- //send the server request ' f L2 H4 ]. B
- fputs($fp, "POST HTTP/1.1\r\n"); 1 m4 {' ?$ _5 g. V. k* l( G
- // fputs($fp, "Host: $host\r\n"); 2 o3 I" B9 q5 i5 E% ^1 K" k1 T
- // fputs($fp, "Content-type: application/x-www-form-urlencoded\r\n");
5 F0 Y) K1 Y0 C5 m d5 s - fputs($fp, "Content-length: ".strlen($v)."\r\n"); : n- Y8 D3 K& [9 p! \6 C
- fputs($fp, "Connection: close\r\n\r\n"); 7 B6 I! {2 n2 R; D0 `
- fputs($fp, $v . "\r\n\r\n");
) v- i1 ?6 ]% W+ p' J$ \ - 7 X. e, ^% d9 s2 `' Y3 L4 }
- //loop through the response from the server 4 c* `! Y& M3 I
- $res = "";
{7 \: I9 I( s1 O; d5 H' F - while(!feof($fp)) { h4 k6 R( k* C) l! l
- $res .= fgets($fp, 4096); + ~; {2 n m2 \
- } & K3 c( W. [5 z' f' Z/ {$ z
- //close fp - we are done with it ! R" V; u) Y# R2 i
- fclose($fp); , `$ S: Z& H! }3 i
( x9 N" n( B: X: R- $content = $v.chr(13).chr(10).$res;
2 O2 G9 x( n3 j' C6 u% { - } " H& H% q& A5 V1 H3 [7 Y# G" N
- ss_timing_stop(); $ d# U; Y9 n. [* D' c
- $content .= chr(13).chr(10)."Time: ".ss_timing_current().chr(13).chr(10)."--------------------------------------".chr(13).chr(10); 4 m# b* m8 D8 T4 p9 u# S
- fputs($file,$content);
0 m+ a. ~, R6 r4 f* t9 K( E6 \ - }
/ ]5 H3 x8 v$ c5 c; q - fclose($file); * {6 W9 y. a8 |8 l
- ?>
, _) Q1 D: x) Q+ L, j8 D - <? 5 L& `2 m3 _$ B4 V( u) }& H/ d
- function ss_timing_start ($name = "default") { 5 [$ H& `4 C& F! ^/ |8 ^
- global $ss_timing_start_times; - L' |, L4 j$ _8 n% l) f# k
- $ss_timing_start_times[$name] = explode(' ', microtime());
5 q0 c, }1 j$ Z( b - }
2 Q0 Z9 d8 J4 g - function ss_timing_stop ($name = "default") {
N! W5 P; R" [1 a - global $ss_timing_stop_times;
1 a$ Q/ p$ I/ u8 F! Y2 r - $ss_timing_stop_times[$name] = explode(' ', microtime()); 4 \1 @% C# m- _4 z; W+ Q# d1 I; D: I3 G |
- } $ @% ]9 T2 c* V/ s, l7 z! f6 M3 m
- function ss_timing_current ($name = "default") { 8 m' u6 |+ g- I5 C& m/ z
- global $ss_timing_start_times, $ss_timing_stop_times; 1 I8 m, k+ U: G5 ]2 R0 d, `
- if (!isset($ss_timing_start_times[$name])) {
* Q2 B2 q7 J3 X/ x - return 0; 7 W* Q! O" Z+ X i1 Q/ M
- } / C/ s" f& U: r$ i* D3 d' R
- if (!isset($ss_timing_stop_times[$name])) { 4 [2 V" k, S) c c z0 K T X( g
- $stop_time = explode(' ', microtime());
6 c; Z( i1 B" K. f. d a. Q5 | - }
2 `( f; p+ Z- X. E+ Z2 K - else {
/ h. Z/ W; U; i, q; w1 [ - $stop_time = $ss_timing_stop_times[$name]; . i$ H% }+ x9 T3 i/ o. y" l G, z
- }
, c1 b* i2 }% ^& [5 L1 W - $current = $stop_time[1]-$ss_timing_start_times[$name][1];
9 `+ E% e2 E" q! I5 E7 ~& S - $current += $stop_time[0]-$ss_timing_start_times[$name][0];
: O, Z3 {, Q5 j4 P3 w1 K9 p - return $current;
% P) a3 n6 a6 B - }
4 Y, |+ p& P4 y* k - ?>
复制代码
' C6 l$ K6 O4 ]! x7 y# [; E4、研究成果: 2 w+ }; E# B+ e: K/ M
' a6 G, _! T3 |* [5 e- n(1).登陆 ; q8 c j; ]( b8 [ i$ Q7 ?
说明:在你做任何其他操作以前,你必须登陆。只有在登陆以后,你的其他指令才有可能被正确执行(返回RES=0),不然服务器会返回RES= 20,不过有个例外,就是logout。当你成功登陆以后,服务器就会根据你的IP*和参数中的UIN来验证身份。一台电脑可以同时登陆多个QQ,互不影响,就是因为有参数UIN。
* T/ r, \; I# v. F l" J *至于我能够确定服务器是通过IP来验证的,是因为服务器不可能通过我的请求获得其他信息了^_^
0 b! X# D A& x0 C% S( [) U$ l4 y, F( ~- y& I2 z; }& S
提交数据:VER=1.1&CMD=Login&SEQ=标记&UIN=QQ号&PS=QQ密码&M5=1&LC=9326B87B234E7235
: f$ p% F6 W5 G% j0 | 说明:QQ密码是通过md5加密的字符串,在PHP中可以直接用md5()进行加密; . ~/ o' N* B% ~$ f/ m! S
M5这个参数的作用还不清楚,但最好为1。
+ Q. C. I* ?1 y' z$ G* _ LC这个参数有点神秘,不能有丝毫改动,不然服务器就没有响应(没有响应就是返回NULL)。 4 m5 P" _: E, i# B
4 d" V8 W9 O. e: g9 ?8 R3 L
返回:VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=0&HI=60&LI=300(成功) * r+ G7 h+ U9 i, L
VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=0&RS=1&RA=密码错误(密码错误) 1 C' H1 |; y# G: a7 d7 a) I' y/ R
VER=1.1&CMD=LOGIN&SEQ=标记&UIN=QQ号&RES=5(QQ号非法,如100)
/ I) \5 ?+ s" s) A3 t1 ] NULL(UIN为字符、PS为空、LC错误) : D/ R3 a1 A$ i! U) |# B
- ^8 }( f1 a6 K q( e. u
(2).得到好友列表
+ _2 Q1 b+ s' v0 u* f7 t9 u 提交数据:VER=1.1&CMD=List&SEQ=标记&UIN=QQ号&TN=160&UN=0 2 U( Y5 a2 J4 S
说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响
. u" k: ]6 s5 `( ~8 U7 K
2 c1 R9 v. z+ o4 _+ v 返回:VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN=9(当TN=0或没有TN参数时,FN表示好友数) 9 H$ G% T( {5 Q, n# e
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=0&FN= 1&SN=9&UN=3814526,...,(当TN存在且非0时,FN=1,SN表示好友数,UN为好友列表,用","分割) 8 A1 M( E7 L5 T& c+ d" I0 M( d
VER=1.1&CMD=LIST&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
6 S4 w! \* E8 c2 e& B+ l2 a NULL(UIN、TN、UN为字符)
* X+ w1 x8 f% h
; d5 {6 |) V* ?; g* }* Y4 V(3).得到在线好友列表
- N2 T" c+ P+ | 提交数据:VER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号&TN=50&UN=0 : ?1 Y1 I/ P8 ?: Z' i2 S; Y7 S
说明:TN、UN还不清楚具体表示什么,但是TN的值会影响返回的结果,有没有UN对结果没有影响
% R( H$ R T. [' ?0 A1 f \5 D
* F, k3 h* @ s8 e 返回:VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES= 0&FC=0,&FN=1&SN=1&ST=10,&UN=106814,&NK=Hackfan 好,(当TN存在且非0时,FN=1,SN表示在线好友数,FC、ST、UN、NK的值用','分割,分别表示头像、状态、号码、昵称) % B5 _0 o$ f e0 ~
VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
8 k7 ?- m' r+ r( i' E NULL(UIN、TN、UN为字符)
1 q& C* n) S+ g0 Y 说明:FC为QQ头像的的ID,如的头像ID为270,那么其头使用的图片为91.bmp,其算法为ID/3+1;
; x& q9 D& z. k ST为QQ用户的状态,10为上线,20为离线(或隐身),30为忙碌;
1 L* E- |5 Q" m. @) Y( \4 k, }
) W' c, s" S" j4 a3 b1 K( a 特别说明:当参数TN=0或不存在时,服务器返回:
& R l! i+ e& K) b2 j! MVER=1.1&CMD=Query_Stat&SEQ=标记&UIN=QQ号
9 W" V$ H9 B7 A* a4 z) G3 _% sHTTP/1.1 200 OK
4 ], e" p3 R$ _7 T& uServer: tencent imserver/1.0.0
& F4 B$ h, G( c6 f8 Q( S+ `Content-Type: text/plain; charset=UTF-8
* N+ [. U* }9 b+ x6 b5 \2 g( C" G: PContent-Length: 56
; X, G2 E9 H3 `4 a( W
) S9 o, r. i( L, {VER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FN=1
) F/ ]( x3 J" J/ H& iHTTP/1.1 200 OK
4 [- L4 j* X; G2 u4 sServer: tencent imserver/1.0.0
% u( i5 k/ L6 k7 F, kContent-Type: text/plain; charset=UTF-8
2 F, @ {! [+ y( ^' kContent-Length: 77 - k% a9 f4 J1 I6 R' G m6 s8 e1 p
5 r( v& i6 P6 C- O. AVER=1.1&CMD=QUERY_STAT&SEQ=标记&UIN=QQ号&RES=0&FC=&FN=1&SN=0&ST=&UN=&NK= : I: }. J( f8 k/ n% Z! R
返回了2次,第一次的结果中,FN为在线好友数,第二次返回的数据基本没用。 ' L& ]- A* M; ?, d% n; s. H& ]
" {9 I/ x( b9 g/ h9 v; V- L8 j1 A7 r/ {
(4).查看好友信息
7 Q, S9 ]- g$ U# s! W" b+ ? 提交数据:VER=1.1&CMD=GetInfo&SEQ=标记&UIN=QQ号&LV=查询类型&UN=被查询QQ号码 - x0 |4 f K7 Y. |5 @
说明:LV=0,1为精简查询,LV=2为普通查询,LV>=3为详细查询 9 r6 f% v" j. W# { ~
% z- ?+ g0 V0 C1 k, m
返回:VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&LV=0&UN=106814&NK=Hackfan 好(精简查询)
" o, T! ?7 F; C) \! m, a$ x! ` VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD =地址&AG=19&EM=hackfan@qq.com&FC=0&HP=http: //blog.hackfan.net&JB=学生
: a4 h& X, H- F) x2 [- t&LV=2&PC=邮编&PH=电话&PR= The guy is updating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC= 毕业院校&SX=0&UN=106814&NK=Hackfan 8 Y# v4 f6 o' C; ^" p
好(普通查询) + s% ^6 \* w2 j) R2 X# T1 W
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=0&AD =地址&AG=19&BT=2&CO=6&CT=苏州&CV=%01&CY=中华人民共和国
2 m1 V3 O- {5 K9 f% ?&EM=hackfan@qq.com&FC=0&HP=http://blog.hackfan.net&ID =-&JB=学生&LV=3&MO=136********&MT=0&MV=&PC=邮编& PH=电话&PR=The guy is
0 _/ P* G+ J0 Q$ y$ Y1 Q, zupdating to .NET Frameword......&PV=江苏&RN=胡吉阳&SC=毕业院校&SH=3&SX=0&UN=106814&NK=Hackfan 好(详细查询) 6 D6 k9 }% I, w3 v. X4 }3 y
VER=1.1&CMD=GETINFO&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
# L; ^$ z( h9 ]. W NULL(UIN、LV、UN为字符)
, }& U3 d7 j. a) g5 V5 y9 f+ |# W7 L. R- Y, B: _. u3 S. `
说明:AD为联系地址 8 B$ X+ i) A$ j5 N+ |
AG为年龄 % b) U l; q4 _& l7 _
BT为血型 $ z4 J; B' R: B: C, z3 M
CO为星座
5 o, c. {5 A/ M+ r* t CT为城市
8 w( W3 v% `2 f# C/ v CV为未知*
9 C. D, `' w( V# M! f CY为国家
9 ^) w9 }0 `% c' t* ^4 D EM为Email
1 l8 m6 m9 z) l! C: h FC为头像
6 m2 Z W9 g/ R/ r. E) z0 P HP为网站
0 h8 M n2 C. i- g ID为未知 ( d. I/ k' L: A# C
JB为职业 , _3 [5 H) t& X0 t: o+ G$ t
LV为查询代码(就是发送的LV)
2 q+ k- k( T" Q MO为移动电话 : {: A. J, w4 G6 V! b6 K2 @! ^
MT为未知 / n& F) j6 Q6 } v$ Y
MV为未知
* O! T/ K( Y1 X1 Y. Q# _# G PC为邮编
1 W! M+ ~$ f9 b" U PH为联系电话 5 g# ^( Q2 P/ l" b3 Y/ q: f2 [
PR为简介 ; W) h+ _4 I* {& Y4 O+ G
PV为省 ; ~. ?3 W* p/ U* Z: M
RN为真实姓名
P) `% S+ k7 @4 J( T/ Q" K) C SC为毕业院校 & [& r+ U' S# s, d- x( O# _% C
SH为生肖
) T, T0 o* Y/ Q& z SX为性别
! U( k, f4 z! V7 Z% P3 E, l UN为QQ号 6 b, ?' c2 l& k( g% P. g1 y: }1 f9 b
NK为昵称
: l6 J" T( [8 z8 q5 k4 n
+ l" }8 {/ b' c' f* [ 血型:0 => '', * N' X ]. G' j+ a& @2 c6 m9 ^9 F
1 => 'A型', ( n* b V& i. B: u
2 => 'B型',
: S* x+ W, Y) P7 |2 Y! v O6 u2 Y& ? 3 => 'O型',
) M0 D& r$ ?# a/ o& U 4 => 'AB型', . w1 T4 Z/ Y5 U; a& h
5 => '其他'
/ \9 q% n$ p }; H A; x% I1 V4 H: G4 _7 V& B5 S, X9 P }
* f! J1 r c8 |" W 星座:0 => '',
/ W+ O( R1 F& y! z, ] 1 => '水瓶座',
3 o" F/ R! O1 k8 o) F" ?( | 2 => '双鱼座',
9 I2 p7 \3 e% C! B 3 => '牡羊座',
6 n0 C" {" h, ?1 x$ }. G% d& Q 4 => '金牛座',
1 ]. P) Y* O* ^1 f2 g 5 => '双子座',
3 ^! [3 {! F" K/ w6 x 6 => '巨蟹座',
; E- S6 H; y! K 7 => '狮子座', 7 n; F3 `0 d. f
8 => '座', # k1 D2 |: H; w2 k- t* R+ b* y$ I
9 => '天秤座',
8 \( a& i& j$ J 10 => '天蝎座', 0 n1 a6 F( Y. \0 N
11 => '射手座',
3 T, B: v, f3 o0 l6 a9 \ 12 => '摩羯座'
9 E: F J. i1 Y
( Z/ ~5 H" K# J' }/ t* B 生肖:0 => '',
" B5 h1 H# k2 v5 T 1 => '鼠', 0 j* p$ T2 B: N. k6 ]
2 => '牛', 8 c. s) ^3 Q. i' i& G/ ^; o( _+ E- V
3 => '虎', 4 r# K! \' F7 a6 t6 g, B/ A
4 => '兔',
. W, o8 L6 ?5 ~' S4 m( d4 I/ ~ 5 => '龙', # u( s; C9 H" j0 y
6 => '蛇', ) j2 b3 y) _5 |& C0 ] p
7 => '马', 3 C4 [' _& I# t% i0 @# x
8 => '羊', + _' |- D* k( y
9 => '猴',
% l/ i% v! h7 v9 f7 f2 |& M 10 => '鸡', 3 v1 l5 L& z0 G m0 h
11 => '狗',
$ n5 P+ c+ J. K H+ {9 E9 t( l 12 => '猪' , E6 \- Z) w+ n- o
+ K" E! i' z+ A
性别:0 => '男', , P4 d9 @" G9 x+ x, U$ |) F
1 => '女'
0 m) Q b3 f) I9 ~( D6 I# _: H( H
: l |) u+ c5 z- z' V1 O7 M(5).增加好友 4 Y4 K) A& T' U5 ~+ c: U
提交数据:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号 0 k% {5 H& q, G' M; V9 l& h
6 K* f- n+ j. `/ p" S0 X+ t" J
返回:VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=0&UN=对方QQ号(允许被加为好友,此时他已经是你的好友)
# H8 l/ o+ U3 x4 ~4 W* @ VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=1&UN=对方QQ号(需要验证)
! U4 p1 z# H- ~1 T4 E7 _ VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=0&CD=2&UN=对方QQ号(决绝被加为好友)
1 i9 m& e" Q2 i/ K: E VER=1.1&CMD=AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
0 h8 D- ^" K" l t NULL(UIN、UN为字符)
# C: ?7 e0 @# I# Y. l! r8 d9 i
(5).发送验证 $ e( A" _) u1 B% ?, B0 v
说明:1、如果你加对方为好友,你需要发送验证 / C5 p9 `4 m4 a' W4 A" ^
2、对方加你为好友,发送了验证,你要通过或者拒绝 ; ^/ z, |) Y: r% z$ U
这2种情况需要发送验证消息
* x: c3 ^( w' t1 L* |* b3 {/ ~0 D0 I- l7 `, n* o
提交数据:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&UN=对方QQ号&CD=验证类型&RS=理由
' C6 S7 \1 `* t! @- h- }) a 说明:CD为0表示“通过验证”,CD为1表示“拒决加为对方为好友”,CD为2表示“为请求对方加为好友”。
2 r$ _( c2 Q3 M/ u/ _$ i: |8 A1 D: V2 L, ?
返回:VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=0(成功)
/ \+ T1 ^# h( t( g7 f$ n' T; ]+ n VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=3(*) % i8 N/ ]: q8 Q2 B5 B, W
VER=1.1&CMD=Ack_AddToList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) 1 J0 d( [% ?: R- v# E
NULL(UIN、UN、CD为字符,RS为非UTF-8字符) 4 M- S( I3 P& y1 I( b$ M
*如果服务器返回RES=3,那么这次对话的响应时间在20s。当发送验证请求的时候,必须连发2次(请求内容不必一样),其中一条RES=3,对方收不到,一条RES=0,对方能够收到。当CD>=3时,RES=3,响应时间20s。
9 T& B' b" V6 h/ i5 C: m
& `8 |% c" i4 u1 a- C8 x& U' ^(6).删除好友 . J( h G* ]/ x# ?# C7 l
提交数据:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&UN=删除的QQ号
$ {6 |2 ~! h7 C9 c' w3 U
( _6 m5 p8 _6 t7 i& b* l2 t- d4 p 返回:VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=0&(成功)
! p! \ P) i- ^0 i VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=3(响应时间30s,重复发送的后果) ( I) w6 u- r7 F9 h5 V) N: B8 o
VER=1.1&CMD=DelFromList&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) + j$ F" H3 P6 \
NULL(UIN、UN为字符)
. _: m7 A* ~0 K# O3 Q
# Z0 i2 D' _# z0 \. y- b( r(7).改变状态 % o( j5 L4 p7 P8 d% I8 R: d
提交数据:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&ST=状态代码
5 [( ~5 ]% @. \. \ 说明:状态代码:10为上线,20为离线,30为忙碌,40为隐身,其他视为非法 ; N0 E1 u* x( D+ u$ B) v
# B* | Z0 c0 |# e# D
返回:VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=0&(成功)
/ Z8 }# l$ S0 y3 M8 _) @3 p VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=3(失败,原因不明,响应时间20s,可能是过于频繁的改变状态引起的) - u% H% f2 K# Y( ^
VER=1.1&CMD=Change_Stat&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆)
, a! o* g! o0 ~, e( C NULL(UIN为字符,ST非法) 8 C* t# |/ ]4 r* e0 w3 Z( R
/ p* E1 H \& f6 j, s* b0 Z6 S 特别说明:如果你改变好友,将会给所有好友发送一条系统信息,内容就是状态代码;如果隐身,发送的状态代码为20,表示离线。 + U1 H* ~/ x& E% r
同理,当你的好友改变状态,你也会收到一条系统信息。 6 w7 d: f0 M" {$ q ?3 V
$ o0 v0 q$ U$ X4 T! d
(9).获得消息
2 j* F- ?& k `. {, M) z' b | 提交数据:VER=1.1&CMD=GetMsgEx&SEQ=标记&UIN=QQ号 Q: C" p( R; L1 o; i
- S+ `9 O, }) J+ q) j8 o 返回:VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0& MN=4&MT=99,99,99,9,&UN=36791785,99833581,99833581,106814,&MG= 20,30,10,hi ,(MN表示信息数量,MT、UN、MG的值用","分割,分别表示消息类型、发送人号码、消息内容) * \+ C) y6 K. K# H* v6 _
VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=0&MN=0&MT=&UN=&MG=(表示没有信息) # |4 b' u9 u9 [- m/ p" _2 l
VER=1.1&CMD=GETMSGEX&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) - N( F7 E7 r7 U* z* \
NULL(UIN为字符)
9 i% h9 a/ e3 j 说明:关于MT: ( n& M4 E- C3 f; A
9为用户消息,99为系统消息,2为请求信息,3为通过验证,4为拒绝被加好友 1 C. h9 s' y* Z6 m& B; i8 b8 w: }
关于MG: / B. Q4 o; n M- g$ E3 C3 l
当MT=9时,MG为用户发送的消息内容
$ p8 c3 _# g5 u3 ~* @: z 当MT=99时, " F5 S+ n' F" G; c8 _: B( V4 T
MG=10(QQ_STATUS_ONLINE)表示对方上线
! o1 l! ?' ?( Z" D: d5 e/ V MG=20(QQ_STATUS_OFFLINE)表示对方下线
- t3 A# Z6 p; W3 I6 C- c! i MG=30(QQ_STATUS_BUSY)表示对方进入忙碌状态 8 b# b. ]: |; F' G, s
当MT=2时,MG为对方请求你验证的信息
9 g2 k! w# Y* C# [ ?- G* K 当MT=3时,表示对方通过你的验证
) a2 B4 E+ k9 o, e7 S9 V5 t4 C 当MT=4时,MG为对方拒绝你理由
- F; T5 B$ w3 r6 D: y9 X) r: @7 |" G3 O- B4 y0 R+ {) O1 g; t
(10).发送消息
( Q4 ]5 s+ }$ f+ d( W0 ^2 a 提交数据:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&UN=对方QQ号&MG=发送内容
# k% a$ J6 Y5 ~8 K. U+ A
6 E; O# }% N. j% E 返回:VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=0&(成功发送,对方不一定能收到哦)
8 J, p: V6 c0 U5 p8 B VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=3(发送过快)
" F- C) N1 \& {* }5 D I VER=1.1&CMD=CLTMSG&SEQ=标记&UIN=QQ号&RES=20(没有正确登陆) / \* E# X% u3 _* ]6 B- c0 K
NULL(UIN、UN为字符,MG含非UTF-8字符)
- p$ @ F) U( P7 p# H 说明:1、当你发消息时,以下情形对方可能看不到(其实是收到了,QQ不提示)你发送的消息:
; U8 V6 u, m) Y/ n l7 |+ C4 M 你俩互为陌生人,且对方没有和你说过话
3 m' p9 b: \, U 你在他的陌生人列表里,并且他没有和你说过话(没有验证)
# a$ m. `% N4 f5 |+ @6 g6 A 2、当你过快发送消息时,系统会给你一个惩罚,RES=3,相应时间20s
4 \. w, ?% g5 Y5 B- f8 K$ o 3、当我发送含有小写字母h的信息时,服务器有可能返回NULL
6 d4 c; _* l) J) w6 s3 v$ }8 W% t8 _; z$ }, i( U
(11).登出 ) d0 X! }) r) h% W$ T/ P
提交数据:VER=1.1&CMD=Logout&SEQ=标记&UIN=QQ号 0 z& x; q/ I1 `: j5 c3 l! U
$ P0 ]# Y+ s/ o( v
返回:VER=1.1&CMD=LOGOUT&SEQ=标记&UIN=QQ号&RES=0(成功,好像永远成功的,不管你是否登陆) 6 t. I. Z4 {4 l; l/ t; T+ W* e
NULL(UIN为字符)
4 Y7 z% I8 v7 A* T% |+ w3 o* Y4 x3 K2 J% g
5、总结
7 D# Z o. N' K" w- a1 i7 X, E, u" w: d, x p
通过对照以上的接口说明,我开发出了能够实现基本QQ功能的PHP类,它整合了以上所有的接口,使用更方便,可以开发QQ机器人、群发广告程序等。免费获得类的代码请到 4 a* U k& [. A$ A; z
http://blog.hackfan.net/index.ph ... d=a_20050819_223558
6 z( C+ m! E- t- c$ F$ { 本文撰写时间仓促,难免有误,希望各位不吝赐教
, b2 K" F' J5 F. Q4 i
/ q) j6 q) `# q. f$ D
. m( P6 G# f- S. H+ YTrackback: http://tb.donews.net/TrackBack.aspx?PostId=520301 |
|