相比于最常用的短信和邮件的通知方式,微信有着无可比拟的优势:快速、免费,特别适合用在报警通知类应用上。
但是微信并没有提供现成的api接口来给好友发送信息,公众平台也只能被动回复。那么如何才能主动发信息呢?答案就在微信网页版。
仔细观察微信网页版和服务器请求的记录,发现完全就是以oauth授权方式运行,完全不用考虑cookie。据此,分析请求记录,就能模拟网页版登录微信,从而实现主动向用户发送消息的功能。
以下是用到的请求:
1. 获取uuid,从返回的数据中,找到uuid
https://login.weixin.qq.com/jslogin?appid=wx782c26e4c19acffb&redirect_uri=https%3A%2F%2Fwx.qq.com%2Fcgi-bin%2Fmmwebwx-bin%2Fwebwxnewloginpage&fun=new&lang=zh_CN
2. 获取二维码图片,然后使用微信扫描
https://login.weixin.qq.com/qrcode/$this->uuid?t=webwx
3. 获取令牌,轮询,直到从返回的数据中找到window.redirect_uri=xxxx的代码,xxx就是令牌url
https://login.weixin.qq.com/cgi-bin/mmwebwx-bin/login?uuid=$this->uuid&tip=1
4. 访问令牌url,获取sid。从返回的头信息中,分析出Uin,sid和uuid,保存起来
xxxxxx
5. 初始化微信,从返回的数据中读取UserName
$data = array( "BaseRequest"=>array( "DeviceID" => 'e538770852445779', "Sid" => $this->sid, "Skey" => "", "Uin" => $this->Uin, ) ); $this->post_contents('https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxinit', $this->encode($data));
6. 获取Skey
$this->post_contents('https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=' . urlencode($this->sid), '{"BaseRequest":{"Uin":'.$this->Uin.',"Sid":"'.$this->sid.'"},"SyncKey":{"Count":0,"List":[]}}');
7. 发送消息,POST方式,
$data = array( "BaseRequest" => array( "Uin"=> $this->Uin, "Sid"=> $this->sid, "Skey"=> $this->Skey, "DeviceID"=> $this->DeviceID, ), "Msg" => array( "FromUserName" => $this->FromUserName, "ToUserName" => $name, "Type" => 1, "Content" => $content, "ClientMsgId" => $this->ClientMsgId, "LocalID" => $this->ClientMsgId, ), ); $str = $this->encode($data); son_decode($this->post_contents('https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg?sid=' . urlencode($this->sid) . '&r=' .$this->ClientMsgId, $str), true);
发送消息的经典过程为:
- 初始化对象,设置Uin,sid,uuid
- 更新Skey
- 发送信息
但是微信网页版长时间不登录会失效,所以还需要写个任务去ping
$data = '{"BaseRequest":{"Uin":'.$this->Uin.',"Sid":"'.$this->sid.'"},"SyncKey":{"Count":0,"List":[]}}'; $ret = json_decode($this->post_contents('https://wx.qq.com/cgi-bin/mmwebwx-bin/webwxsync?sid=' . urlencode($this->sid), $data, 30), true);
微信的数据都是以json格式传输的,但是他这个json比较特殊,还需要用特别的函数来实现
protected function encode($data){ if(!is_array($data)){ return $this->encode_str($data); } $ds = array(); foreach($data as $k => $v){ $ds [] = "\"$k\":" . $this->encode($v); } return '{' . join(',', $ds) . '}'; } protected function encode_str($str){ if(preg_match('|^\d+$|', $str)){ return $str; } return '"' . str_replace('"', '\"', iconv('GBK', 'UTF-8', $str)) . '"'; }
请问大侠能分享分析方式吗
post_contents 这个方法怎么写呢?二维数组怎么传呢?麻烦大神可以粘贴出来啊
有个想请教一下,deviceid 从哪来的?在哪个URL获取的?
需要手动扫描二维码么 ?
需要。理论上只需要扫描一次。实际运行中会经常掉线,需要多次扫描二维码。
高手。。