Wscats / articles

🔖My Learning Notes and Memories - 分享我的学习片段和与你的回忆
https://github.com/Wscats/articles
3.17k stars 735 forks source link

微信公众号开发 #50

Closed Wscats closed 5 years ago

Wscats commented 8 years ago

首先去微信公众号官网 注册订阅号 微信接入官方文档 这里写图片描述 这里写图片描述 在新浪服务器下新建一个SAE应用 这里写图片描述 配置服务器,并把地址带到公众号的 这里演示的是用新浪SAE云服务器 新浪云

这里写图片描述 在新浪云的代码管理中把链接粘贴到微信的基本配置中的URL输入框可参考官方token的设置方法 或者用下面的代码

<?php
/**
 * wechat php wsscat test
 */

//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (isset($_GET['echostr'])) {
    $wechatObj -> valid();
} else {
    $wechatObj -> responseMsg();
}

class wechatCallbackapiTest {
    public function valid() {
        $echoStr = $_GET["echostr"];

        //valid signature , option
        if ($this -> checkSignature()) {
            echo $echoStr;
            exit ;
        }
    }

    public function responseMsg() {
        //get post data, May be due to the different environments
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

        //extract post data
        if (!empty($postStr)) {
            /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
             the best way is to check the validity of xml by yourself */
            libxml_disable_entity_loader(true);
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $fromUsername = $postObj -> FromUserName;
            $toUsername = $postObj -> ToUserName;
            $keyword = trim($postObj -> Content);
            $time = time();
            $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";

            if (!empty($keyword)) {
                $msgType = "text";
                $contentStr = "Welcome to wechat world! I'am wsscat,nice to meet you";
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                echo $resultStr;
            } else {
                echo "Input something...";
            }

        } else {
            echo "";
            exit ;
        }
    }

    private function checkSignature() {
        // you must define TOKEN by yourself
        if (!defined("TOKEN")) {
            throw new Exception('TOKEN is not defined!');
        }

        $signature = $_GET["signature"];
        $timestamp = $_GET["timestamp"];
        $nonce = $_GET["nonce"];

        $token = TOKEN;
        $tmpArr = array($token, $timestamp, $nonce);
        // use SORT_STRING rule
        sort($tmpArr, SORT_STRING);
        $tmpStr = implode($tmpArr);
        $tmpStr = sha1($tmpStr);

        if ($tmpStr == $signature) {
            return true;
        } else {
            return false;
        }
    }

}
?>

token可以自行更改,现在这里我用的是weixin

设置成功后微信的服务器配置项会变成如下

这里写图片描述 配置成功后按启动

如果是官方的示例代码,再启动成功后记得再更改服务器上面的这部分代码为下面,让它接受信息后调用responseMsg()函数

//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
if (isset($_GET['echostr'])) {
    $wechatObj -> valid();
} else {
    $wechatObj -> responseMsg();
}

在微信搜索或者扫描二维码并关注公众号即可看到以下回复 这里写图片描述

来到这一步我们可以接入图灵测试的接口来测试 图灵机器人接口

public function responseMsg() {
        //get post data, May be due to the different environments
        $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];

        //extract post data
        if (!empty($postStr)) {
            /* libxml_disable_entity_loader is to prevent XML eXternal Entity Injection,
             the best way is to check the validity of xml by yourself */
            libxml_disable_entity_loader(true);
            $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
            $fromUsername = $postObj -> FromUserName;
            $toUsername = $postObj -> ToUserName;
            $keyword = trim($postObj -> Content);
            $time = time();
            $textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Content><![CDATA[%s]]></Content>
                            <FuncFlag>0</FuncFlag>
                            </xml>";

            if (!empty($keyword)) {
                $apiKey = "输入自己的apiKey";
                $apiURL = "http://www.tuling123.com/openapi/api?key=KEY&info=INFO";
                $reqInfo = $keyword;
                $url = str_replace("INFO", $reqInfo, str_replace("KEY", $apiKey, $apiURL));
                $res = file_get_contents($url);
                $resObj = json_decode($res);
                $contentStr = $resObj->text;
                $msgType = "text";
                //$contentStr = "Welcome to wechat world! I'am wsscat,nice to meet you";
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                echo $resultStr;
            } else {
                echo "Input something...";
            }

        } else {
            echo "";
            exit ;
        }
    }

这里如果要回复非文本的消息我们就要更改回复的XML格式 首先我们先在代码中打印后台接受微信的$postObj数据,里面包括ToUserName,FromUserName,CreateTime,MsgType,Content和MsgId这几个重要信息,后面我们封装回复的消息体时候就会用到 $contentStr = json_encode($postObj) 然后包装返回的信息格式,格式是XML的格式 被动回复用户消息 比如图文的模版

$textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <ArticleCount>2</ArticleCount>
                            <Articles>
                            <item>
                            <Title><![CDATA[你好,我是Wsscat]]></Title> 
                            <Description><![CDATA[谢谢您的关注]]></Description>
                            <PicUrl><![CDATA[http://avatar.csdn.net/1/E/E/2_qq_27080247.jpg]]></PicUrl>
                            <Url><![CDATA[http://blog.csdn.net/qq_27080247]]></Url>
                            </item>
                            <item>
                            <Title><![CDATA[Wsscat是一只猫]]></Title>
                            <Description><![CDATA[这是我第一条发布的信息]]></Description>
                            <PicUrl><![CDATA[http://avatar.csdn.net/1/E/E/2_qq_27080247.jpg]]></PicUrl>
                            <Url><![CDATA[http://blog.csdn.net/qq_27080247]]></Url>
                            </item>
                            </Articles>
                            </xml>";

                $msgType = "news";
//              $contentStr = json_encode($postObj);
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType);
                echo $resultStr;

图片的模版

$textTpl = "<xml>
                            <ToUserName><![CDATA[%s]]></ToUserName>
                            <FromUserName><![CDATA[%s]]></FromUserName>
                            <CreateTime>%s</CreateTime>
                            <MsgType><![CDATA[%s]]></MsgType>
                            <Image>
                            <MediaId><![CDATA[IIljTxbQ7VV7HhXWZrmR361nqd9dpyncq23YewYb6NkgQdMdytYsOD3ewKmZWARN]]></MediaId>
                            </Image>
                            </xml>";
                $msgType = "image";

                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType);
                echo $resultStr;

常见问题: 部署新浪云token验证失败

header("Content-Type:text/html; charset=utf-8");//添加这行
/**
  * wechat php test
  */

//define your token
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
$wechatObj->valid();
if ($this -> checkSignature()) {
            header('content-type:text');//再添加这行
            echo $echoStr;
            exit ;
        }
Wscats commented 8 years ago

微信JS-SDK

微信JS-SDK官方说明文档 jweixin-1.0.0.js JS-SDK官方DEMO

首先绑定域名 先登录微信公众平台左边设置进入公众号设置功能设置里填写“JS接口安全域名” 这里写图片描述

然后,如果要JSSDK开动,必须满足下面三个条件:

第一二步我们前面都配置好了,现在我们缺的是第三步 我们下载后台生成签名的代码官网JSSDK后台服务代码DEMO并替换里面的AppIDAppSecret 打开上传的后端代码测试,新浪SAE有可能会报以下的错误,原因是没有权限读写,JSSDK要把access_token和expire_time写到本地被SAE拒绝了 这里写图片描述

这里可以参考这两篇文章来解决 解决新浪SAE无法写入jssdk.php的问题 http://www.henkuai.com/thread-1404-1-1.html

当然也可以用我的方法来解决 在SAE上用Storage的Bucket管理管理,把需要的文件放上去,这里我放了主要产生问题的access_token.phpjsapi_ticket.php 这里写图片描述 然后获取这些文件的路径,并把他替换到jssdk.php对应的地方,如下 这里写图片描述 那么我们就可以打开微信访问我们服务器上的这个测试文件来检测是否可以调用微信的接口了 这里提醒下,分享功能必须要通过验证才可以使用,参考segmentfault的这个问答 最新的微信JSSDK分享接口的问题

Wscats commented 8 years ago

微信WEB开发者工具

微信web开发者工具官方文档 首先绑定自己的微信号,并下载开发者工具 Windows64位 这里写图片描述 下载完安装并且连接上手机代理,手机和电脑必须在同一个局域网内 这里写图片描述 这里写图片描述 在微信打开的网页都能在PC端的开发者工具看到页面结构(DOM)和JS调试的输出,对手机端开发调试有很好的帮助,也可以像在Chrome一样用console.log输出参数方便查看,也可以在侧边栏打内链的样式实时看到页面的变化

Wscats commented 8 years ago

微信支付

微信支付DEMO下载 打开demo的index.php会看到以下的测试页面 这里写图片描述 这是一个重要的配置文件,在lib目录下的WxPay.Config.php

/**
     * TODO: 修改这里配置为您自己申请的商户信息
     * 微信公众号信息配置
     * 
     * APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
     * 
     * MCHID:商户号(必须配置,开户邮件中可查看)
     * 
     * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置)
     * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
     * 
     * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置),
     * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
     * @var string
     */
    const APPID = 'wx426b3015555a46be';
    const MCHID = '1900009851';
    const KEY = '8934e7d15453e97507ef794cf7b0519d';
    const APPSECRET = '7813490da6f1265e4901ffb80afaa36f';

其中APPIDAPPSECRECT在公众号的开发配置信息中能获取,上面是微信提供的测试帐号 而MCHIDKEY为支付接入后邮件中的商户号和支付密钥

mongofeng commented 7 years ago

把测试的PHP文件丢到腾讯云的服务器(可以运行PHP),在公众号URL和tooken里面配置成功,但是公众号发送消息没有任何回复,新浪云的就可以,怎么解决