微信初步开发(测试用)

         其实这个很早就该写了,当时没动手,然后又有点事影响了心情(啊六年了居然突然就知道某人的一些信息),等玩了一天游戏复活了却又病了……(但其实不还是拖延害死人.

         插入一句吧,用了接口就代表什么都要代码实现了。

 

         首先,要有公众账号和有独立域名的网站(我选新浪云),这个就不说了。新浪云最好还是弄个认证吧,据说没认证的话它是会附带一些乱七八糟的HTML内容过来。哎还是直接讲开发过程吧。

         公众号申请成为开发者以后,会要求绑定URL和Token。Token即为口令,微信服务器和开发者的服务器相互确认身份正是利用你定义的Token,通过DSA这个加密算法来确认的。当确认后,微信服务器即向指定URL发送一个带有signature, timestamp, nonce, echostr四个参数的GET request,目的是让你确认你的URL能否正确处理微信服务器发送过去的用于核对身份的信息。其中,nonce为随机数,与timestamp一起是为了防replay_attack,这个可见http://www.cnblogs.com/bestzrz/archive/2011/09/03/2164620.html 。至于怎么核对,网上一搜一大堆,比如 ——  

    private function checkSignature()

    {

        $signature = $_GET["signature"];

        $timestamp = $_GET["timestamp"];

        $nonce = $_GET["nonce"];

 

        $token = TOKEN;

        $tmpArr = array($token, $timestamp, $nonce);

        sort($tmpArr, SORT_STRING);

        $tmpStr = implode( $tmpArr );

        $tmpStr = sha1( $tmpStr );

 

        if( $tmpStr == $signature ){

            return true;

        }else{

            return false;

        }

    }

 

         当核对无误后,即让它返回echostr就好。别图省事不经验证就直接返回echostr,不然别人知道URL的也能随便写个Token就通过验证了。除非有修改,不然这个echostr以后是不会出现的了,也不需要了,但这个checkSignature,好像网上好多贴出的代码以后都没用上了。signature、nonce、timestamp那三个参数以后还是会发送过来的 —— 上面说了,这是微信服务器用来表明自己的身份的,个人建议checkSignature这个检查还是继续用吧。

 

         过几天开始要弄的只是一个订阅号,目前主要用于团队介绍,也用不上什么复杂功能,重点还是只是对别人发来的信息作个简单处理而已。所以我选择了PHP来作开发,尽管我写python比PHP多得多(但其实是用得都不多,大一我人太懒)。原因?主要还是微信的三个挺坑的地方(前两个也被人吐槽无数了) ——

1、  为了保密,微信和开发者的服务器之间都是POST通信的,然而它却把验证身份用的signature、timestamp、nonce三个参数附在URL上传过来,这个请看廖雪峰的说明http://www.liaoxuefeng.com/article/0013900476318564121d01facf844cba508396f95d9bb82000 。所以网上好多代码都不验证signature了?但出事的只会是自己= =

2、  微信服务器发过来的BODY不是JSON,而是一个CDATA(XML的一种变体). 好蛋疼啊我还记得上学期数据库期末考最后20分就是XML,然而我上课没留意 + 写Ajax时我只接触过JSON,结果……恩简单对CDATA作个介绍吧,就是为了应对’<’和’&’会在XML中出错而作的一个XML变体,但它不能包含字符串“]]>”(  因为它出现的形式就是<! [CDATA[ data ]]>  ),所以测试的时候我也能知道我发这个字符串会怎样。PHP有专门的函数处理,而Python的就不了解了。

3、  对于我而言 —— 微信官方的开发文档整理得比较混乱,我想找的信息总是不在我预想的地方,因而我只能靠百度/谷歌了。而可参考代码中,还是PHP占大多数(PHP是世界上最好的语言~)

 

被动回复消息

那么我的目标就好明确了,就是从URL上扒下来三个参数,进行身份验证,然后从POST发送过来的CDATA中抽出我想要的数据,再把我要回复的内容放进新构建的CDATA中就可以了。微信开发容易入手的地方就在于,它的消息格式较为固定,让开发者接收/发送消息更为方便。

首先,上面也说了,微信发送过来的BODY就直接是消息,所以用 $GLOBALS[“HTTP_RAW_POST_DATA”] 接收。注意别用$_POST,这两个是不同的,前者未经处理,后者是根据一定规则将POST的内容拆成 Key - Value 对。比如,前者可能为 key1=value1&key2=value2 ,而后者则直接是 array( “key1” => “value1”, “key2” => “value2”, )

然后,对于CDATA数据,可用simplexml_load_string函数读取,只需要记得加上LIBXML_NOCDATA这个参数,说明这是个CDATA型的XML数据。有其他函数,但我不太了解。然后直接从读取后的数据里再根据key_name进一步读取就能得到相应数据了。至于key_name是什么,则只需要了解微信定义的消息类型。这里我只说我在意的。其实可以直接参考http://www.cnblogs.com/logoove/p/3413641.html

对于text类型,有 ToUserName  FromUserName(可得到用户的OpenID。OpenID是每个用户在关注时针对每个公众号生成的)  CreateTime  MsgType  Content(文本内容)  MsgId(我不太清楚应用场合,据说主要是用于排重)

然后判断他发信息来干嘛啊,接着继续按这样的格式去构建我们要回复的信息就好。最简便的

 

<xml>

<ToUserName><! [CDATA[%s] ]></ToUserName>

<FromUserName><! [CDATA[%s] ]></FromUserName>

<CreateTime> %s </ CreateTime>

<MsgType><! [CDATA[“test”] ]></ MsgType>

<Content><! [CDATA[%s] ]></ Content>

</xml>

 

接着用sprintf函数写入,注意CreateTime处对应的是time()函数。这段也是一搜一大堆的啦。


自定义菜单

在创建菜单的时候就需要用到access_token来调用微信服务器的接口了。access_token看英文就能猜到用途,表明了一种公众号有权限调用微信的接口的一个口令,它的有效时间为7200秒,这段时间内重复获取则会使上个token失效。

那么,我们就先获取这个access_token吧。用https协议,通过GET方式(这个又有点想吐槽…),传递grant_type、appid、secret到api.weixin.qq.com/cgi-bin/token,其实grant_type直接写client_credential(哎为什么就不要管啦),后面两个在公众号平台那可以查到。写完整的话就是https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET 如无意外的话,它会返回一个JSON数据包给你。直接json_decode然后获取access_token值就好。其实要是嫌麻烦的话,可以直接用网上的那个调试接口弄。接着就贴一个来自方倍工作室的源码 ——

$appid = "";
$appsecret = "";
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appid&secret=$appsecret";
 
$ch = curl_init();  // PHP函数,初始化一个curl会话
curl_setopt($ch, CURLOPT_URL, $url);  // 设置目标URL
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);   // 不检测服务器的证书是否由正规浏览器认证过的授权CA颁发
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);   // 不检测服务器的域名是否与证书上的一致
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);   // TRUE to return the transfer as a string if the return value of curl_exec() instead of outputting it out directly.
$output = curl_exec($ch);
curl_close($ch);  // 关闭curl会话
$jsoninfo = json_decode($output, true);
$access_token = $jsoninfo["access_token"];

         这里在文章最后就顺带说下点CURL吧。这个我也不懂,印象中有在Ubuntu那边用过,但忘了当时是干嘛。

         接着就构造一个JSON数据包,再附加个access_token,也按CURL发回给服务器就好,即https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN 。至于JSON数据包格式,还是直接看代码号。以下代码也是来自方倍工作室 ——

$jsonmenu = ‘{
      "button":[
      {
            "name":"天气预报",
           "sub_button":[
            {
               "type":"click",
               "name":"北京天气",
               "key":"天气北京"
            },
            {
               "type":"click",
               "name":"上海天气",
               "key":"天气上海"
            },
            {
               "type":"click",
               "name":"广州天气",
               "key":"天气广州"
            },
            {
               "type":"click",
               "name":"深圳天气",
               "key":"天气深圳"
            },
            {
                "type":"view",
                "name":"本地天气",
                "url":"http://m.hao123.com/a/tianqi"
            }]
      
 
       },
       {
           "name":"方倍工作室",
           "sub_button":[
            {
               "type":"click",
               "name":"公司简介",
               "key":"company"
            },
            {
               "type":"click",
               "name":"趣味游戏",
               "key":"游戏"
            },
            {
                "type":"click",
                "name":"讲个笑话",
                "key":"笑话"
            }]
       
 
       }]
 }‘;

恩,注意分清PHP还是JSON形式就好。真的说实用点的代码的话可以看cloudbbs.org/forum.php?mod=viewthread&tid=27191,主要是看一个封装的就好。至于想修改菜单?没见到开发文档有说明,只好删除和创建。

 

用户分组管理

直接看开发文档http://mp.weixin.qq.com/wiki/0/56d992c605a97245eb7e617854b169fc.html ,注意点有:name用UTF8编码;每组id由微信服务器分配,你只能get并记下,用户的open_id同理

 

素材管理

首先是临时素材,发送到微信服务器3天后会删除,上传说明则按文档上的

http请求方式: POST/FORM,需使用https
https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE
调用示例(使用curl命令,用FORM表单方式上传一个多媒体文件):
curl -F media=@test.jpg "https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE"

成功的话会返回JSON数据包

{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}

其中created_at为文件上传时间戳。还有其他限制细节就不写了。下载则

http请求方式: GET,https调用  // 视频文件不支持https下载
https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID
请求示例(示例为通过curl命令获取多媒体文件)
curl -I -G "https://api.weixin.qq.com/cgi-bin/media/get?access_token=ACCESS_TOKEN&media_id=MEDIA_ID"

永久素材的话,直接看文档吧…

 

群发消息

         图文消息 :

{
   "filter":{
      "is_to_all":false
      "group_id":"2"
   },
   "mpnews":{
      "media_id":"123dsdajkasd231jhksad"
   },
    "msgtype":"mpnews"
}

         文本 :

{
   "filter":{
      "is_to_all":false
      "group_id":"2"
   },
   "text":{
      "content":"CONTENT"
   },
    "msgtype":"text"
}

         要注意的是:订阅号每天只可以用一次群发接口;如果多次群发发送的是同一个图文信息,那么删除其中一次群发,就会删掉这个图文信息,也会导致所有群发都失效  // 开发文档原话有点醉

4、如果多次群发发送的是一个图文消息,那么删除其中一次群发,就会删除掉这个图文消息也,导致所有群发都失效

         另,有个预览接口,

图文消息 :

{
   "touser":"OPENID", 
   "mpnews":{              
            "media_id":"123dsdajkasd231jhksad"               
             },
   "msgtype":"mpnews" 
}

文本 :

{     
    "touser":"OPENID",
    "text":{           
           "content":"CONTENT"            
           },     
    "msgtype":"text"
}

注意以上CONTENT的JS代码皆作废,而HTML会可能得到支持,分清楚点吧。

 

JS – SDK  // 这个是拿来给网页以JS方式调用微信的一些内置接口用的

这个直接看文档吧http://mp.weixin.qq.com/wiki/7/aaa137b55fb2e0456bf8dd9148dd613f.html

 

另,有个接口小结 ——

http://www.360doc.com/content/14/0123/22/10675863_347454840.shtml

 

总结 ——

1、如果想实现什么功能,想干点特别些的事情,还是写个网页,然后自定义菜单上button(view) 跳进去,接着JS(含JS - SDK) + 后台实现吧

2、网上靠谱的综合点的教程算是没有,但好在微信开发易上手(然而开发文档的内容说明顺序在我看来好谜啊o(╯□╰)o

 

 

CURL ——

curl is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, ......). The command is designed to work without user interaction.
    curl offers a busload of useful tricks like proxy support, user authentication FTP upload, HTTP post, SSL connections, cookies, file transfer resume, Metalink, and more.
    其涉及范围之广,从仿写cookie,分析页面到使用代理,自己构造数据包(包括要利用证书的)。感觉就像百科上说的,虽说是without user interaction,但没点基础没法好好用(暂时还是用urllib.py吧,再低级点的就python的requests包)。下面列一些用法就好。
    curl "URL"  直接访问
    curl -d "post-data" "URL"  将POST数据提交到指定URL
    curl -F upload=@localfilename URL  将本地文件作upload参数上传到指定URL(微信里上传多媒体文件的sample就是curl -F media=@test.jpg  “https://api.weixin.qq.com/cgi-bin/media/uploadimg?access_token=ACCESS_TOKEN
    curl -u name:password URL  这个不用介绍了吧
    curl -e URL1 URL2  伪造referer(想到盗链就呵呵了,感觉能玩
    curl -A user-agent URL  伪造浏览器 + 系统信息(666

至于上面的微信处curl代码,不验证证书一些内容的一块,我也不懂。证书这些,我只听说过些术语,但整个流程我还是毫无了解的,也并不知道上面这样写会有什么好处/问题。

 

具体实现的问题

真正写的时候遇到的坑就多咯。首先说下,我是用新浪上的git来管理代码的,而我不愿用Windows来操作git;但是我Ubuntu上又没有apache来帮忙测试代码是否有语法错误,所以我是现在Win下跑一趟,没问题了再放回Ubuntu那git add .和git commit –am “xxx”以及git push https:xxxx master:1操作(提醒下master那个可重复推)。这个就导致了我后来的一个难以发觉的错误,以致我的token验证始终不对。可我自己模拟了一遍签名生成的过程,感到这正确啊,没有什么错误啊。后来终于找到原因的,BOM的问题,被Windows坑了一回。BOM具体的介绍请看www.cnblogs.com/findumars/p/3620078.html. 这还是第一回见到的。

后来想用新浪云上的MySQL存储access_token,发现那个太长没法好好存储,于是转用Memcache(也是那个时候发觉这玩意更好更适合)。跑的时候观察到有请求但没弄输出测试,就删掉先不管了,留给队友写让他熟悉下。

      弄到申请自定义菜单的时候发觉没反应。就又开始debug,结果发现是两个问题:1、自己变量写得太乱,没有统一,导致url变量名搞混了,token都获取错误了  2、自己测试用的订阅号没权限,但我没输出,告诉自己这回事。这件事告诉我们,在规划代码块的时候就该考虑,要构造怎样的代码块,在哪里嵌入输出错误信息才好。

      暂时就这样吧。测试可以说已经完成了。前后四百多行代码,耗费了自己三天,也是效率蛮低的。多媒体文件那些我就暂时没管,以后要了再弄吧。

微信初步开发(测试用)

上一篇:9.10,,,实现new instanceof apply call 高阶函数,偏函数,柯里化


下一篇:微信web开发的上传图片js接口