《PHP開發微信聊天機器人之WEB版微信協議部分功能分析》要點:
本文介紹了PHP開發微信聊天機器人之WEB版微信協議部分功能分析,希望對您有用。如果有疑問,可以聯系我們。
相關主題:web微信和微信機器人
2016-09-20更新,以下按一個微信WEB登錄的全過程依次分析接口:
首先,我們打開瀏覽器端發起登陸請求,系統返回一個唯一的uid,并將uid的信息繪制成二維碼返回給用戶。
請求:
url | https://login.wx.qq.com/jslogin |
---|---|
method | GET |
Params | appid:wx782c26e4c19acffb,應用ID (固定值)redirect_uri: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage fun : new lang : en_US 或 zh_CN,瀏覽器的語言 _ : 1466394395577,時間戳(ms,js中的實現為new Date) |
%2F是’/ ‘的URL編碼
返回數據(String): window.QRLogin.code = 200;
window.QRLogin.uuid = "xxxxxxXxx=="
如下:
得到uuid之后,請求二維碼: https://login.weixin.qq.com/qrcode/wYGuImiikg==
返回的數據:
一張二維碼圖片
url | https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login |
---|---|
method | GET |
params | loginicon : true uuid : 獲取到的uuid tip : 1-未掃描 0-已掃描 r : 1698811404(時間戳取反,js中的實現:~new Date) _ : 時間戳 |
返回數據(String):
window.code=xxx; xxx值可以是: 408 登陸超時 201 掃描成功 200 確認登錄
如下:
(1)如果一直沒有掃描,則得到408返回碼
(2)掃描成功后,得到201返回碼:
掃描成功后網頁上會出現你的賬號頭像,userAvatar后面的字符串是將要登錄賬號的頭像(直接將userAvatar后面的字符串放入地址欄就可以得到你的頭像)
(3)登錄成功,得到200返回碼:
登錄成功后的返回數據(String):
window.code=200; window.redirect_uri="https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=AXMhC-q8hFm1YagQCIfejW0W@qrticket_0&uuid=wYGRJ91k7A==&lang=en_US&scan=1466408041";12
PS:scan值為時間戳(s),js中的實現為Date.now()
登錄成功之前,每隔27s左右就會重新確認狀態,如下:
請求: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage?ticket=ATB6rg04PsHA1mpklaCZd2Tu@qrticket_0&uuid=AaGxsJd1kQ==&lang=zh_CN&scan=1467183053&fun=new&version=v2
PS:其實這個請求是在window.redirect_uri最后拼接”&fun=new&version=v2”
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxnewloginpage |
---|---|
method | GET |
params | ticket:xxx uuid:xxx lang:xxx scan:掃碼成功后返回的時間戳(s) fun:new version:v2 |
返回數據(XML):
<error><ret>0</ret><message>OK</message><skey>xxx</skey><wxsid>xxx</wxsid><wxuin>xxx</wxuin><pass_ticket>xxx</pass_ticket><isgrayscale>1</isgrayscale></error>1
解析可以得到:skey
、sid
、uin
、pass_ticket
的值。
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit?r=xxx&pass_ticket=xxx |
---|---|
method | POST |
params | BaseRequest: { DeviceID:”xxx”, Sid: “xxx”, Skey: “xxx”, Uin: “xxx”, } |
PS:DeviceID值的由來:e+15位隨機數,JS中的實現如下:
getDeviceID: function() { return "e" + ("" + Math.random().toFixed(15)).substring(2, 17) },123
返回數據(JSON):
部分分析:
本次ContactList里只有10個好友or群組,應該是最近的10個活躍對象(個數不是固定的);
另外,可以通過UserName來區分好友or群組,一個”@”為好友,兩個”@”為群組。
MPSubscribeMsg為公眾號推送的閱讀文章
User其實就是自己賬號信息(用在頂部的頭像)
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxstatusnotify?lang=zh_CN&pass_ticket=xxx |
---|---|
method | POST |
data | JSON |
params | BaseRequest: { ClientMsgId:時間戳(ms) Code:3 FromUserName:”自己的ID” ToUserName:”自己的ID” } |
返回的數據(JSON):
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": "8219790123546360012" }12345678
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxgetcontact |
---|---|
method | GET |
params | lang=zh_CN pass_ticket=xxx r=xxx seq=0 skey=xxx |
返回數據(JSON):
PS:
這個列表中包含好友、群組、公眾號。
好友和公眾號是通過”ContactFlag”區分的,值為1是好友,值為3是公眾號。
關于NickName,可以帶表情之類,所以有的人昵稱是這樣的: "NickName": "<span class=\"emoji emoji270a\"></span>Wade"
部分字段說明:
"Uin": 0, "UserName": 用戶名稱,一個"@"為好友,兩個"@"為群組 "NickName": 昵稱 "HeadImgUrl":頭像圖片鏈接地址 "ContactFlag": 1-好友, 2-群組, 3-公眾號 "MemberCount": 成員數量,只有在群組信息中才有效, "MemberList": 成員列表, "RemarkName": 備注名稱 "HideInputBarFlag": 0, "Sex": 性別,0-未設置(公眾號、保密),1-男,2-女 "Signature": 公眾號的功能介紹 or 好友的個性簽名 "VerifyFlag": 0, "OwnerUin": 0, "PYInitial": 用戶名拼音縮寫 "PYQuanPin": 用戶名拼音全拼 "RemarkPYInitial":備注拼音縮寫 "RemarkPYQuanPin": 備注拼音全拼 "StarFriend": 是否為星標朋友 0-否 1-是 "AppAccountFlag": 0, "Statues": 0, "AttrStatus": 119911, "Province": 省 "City": 市 "Alias": "SnsFlag": 17, "UniFriend": 0, "DisplayName": "", "ChatRoomId": 0, "KeyWord": "EncryChatRoomId": ""123456789101112131415161718192021222324252627282930
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=xxx&lang=zh_CN&pass_ticket=xxx |
---|---|
method | POST |
params | BaseRequest: { DeviceID:”xxx” Sid:”xxx” Skey:”xxx” Uin:xxx } Count:4 List: [ 0:{UserName: “xxx”, EncryChatRoomId: “”} 1:{UserName: “xxx”, ChatRoomId: “”} … ] |
Q:EncryChatRoomId與ChatRoomId有什么區別?
(1) 第一次請求得到最近一段時間內活躍的群組(但不知道騰訊是怎么定義這段時間的):
POST表單提交的內容:
上面LIST的內容是從微信初始化時(webwxinit)返回的數據中得到的:
返回到結果如下:
里面有群組的名稱、群組成員等信息
(2) 第二次請求得到剩下的(最近沒有交流的)群組: https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxbatchgetcontact?type=ex&r=xxx&lang=zh_CN&pass_ticket=xxx
POST表單提交的內容:
PS:應該都是在獲取好友列表(webwxgetcontact)的返回數據中提取出來的(通過判斷”@@”即可)
返回到結果如下:
PS: 里面有群組的名稱、群組成員等信息
url | https://webpush2.weixin.qq.com/cgi-bin/mmwebwx-bin/synccheck |
---|---|
method | GET |
params | r=時間戳(ms) skey=xxx sid=xxx uin=xxx deviceid=xxx synckey=1_654585659%7C2_654585745%7C3_654585673%7C1000_1467162721 _=1467184052133 |
PS:%7C是’| ‘的URL編碼
返回數據(String):
window.synccheck={retcode:"xxx",selector:"xxx"}1
其中各個返回值的含義如下:
retcode: 0 正常 1100 失敗/退出微信 selector: 0 正常 2 新的消息 7 進入/離開聊天界面1234567
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=xxx&skey=xxx&lang=zh_CN&pass_ticket=xxx |
---|---|
method | POST |
params | BaseRequest: { DeviceID:”xxx” Sid:”xxx” Skey:”xxx” Uin:xxx } SyncKey: { Count: 8 List: [ 0:{Key: 1, Val: 654585659} … 7:{Key: 1001, Val: 1467198392} ] } rr:1678170712 |
rr: 時間戳取反
SyscKey值:
第一次更新時POST提交的SyncKey部分是從前面webwxinit請求的返回信息中得到的,如下圖;
之后的每次更新都會使用最新的SyncKey進行請求。
返回的數據(JSON):
請求:
url | https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?lang=zh_CN&pass_ticket=xxx |
---|---|
method | POST |
params | BaseRequest: { DeviceID:”xxx” Sid:”xxx” Skey:”xxx” Uin:xxx } Msg: { ClientMsgId:”14672041846800613” Content:”hello, myself.” FromUserName:”xxx” LocalID:”14672041846800613” ToUserName:”filehelper” Type:1 } Scene:0 |
可以看到我往<文件傳輸助手>發送了”hello,myself”
字段說明:
Type: 1 文字消息,3 圖片消息(先把圖片上傳得到MediaId再調用webwxsendmsg發送),其他消息類型沒試。 Content: 要發送的消息(發送圖片消息時該字段為MediaId) FromUserName: 自己的ID ToUserName: 好友的ID ClientMsgId: 時間戳左移4位隨后補上4位隨機數 LocalID: 與clientMsgId相同123456
返回的數據(JSON):
{ "BaseResponse": { "Ret": 0, "ErrMsg": "" } , "MsgID": "5897491620102102783", "LocalID": "14672043702850802" }123456789
以上這些就可以用代碼實現交互過程啦。