一.注册微信公众号
微信公众号官方入口https://mp.weixin.qq.com注册公众号,注册过程中,类型选择可能是新手比较迷惑的地方.微信公众号分为订阅号和服务号(还有个企业号,似乎用的人不多),每种类型下面又分为公司,政府部门,社会组织,个人等不同性质.不同类型,不同性质的公众号,权限不同,申请资料也不同.
例如:公司(订阅号或服务号),你得提供工商注册号,银行对账号.注册成功后,也并不是所有权限都默认开通,需要手动开通.有些权限还得微信认证之后才能开通.关于这些细节,可参阅微信公众号官方文档https://mp.weixin.qq.com/wiki
可以申请测试号,它除了跟钱有关的权限(例如微信支付)没有,以及不能当正式公众号来发布(微信中似乎也搜索不到)之后,差不多所有权限都有,学习开发阶段,还是挺有用的.测试号申请办法:微信公众号官方管理平台->开发->开发者工具->公众平台测试账号.
二.配置
认证通过并且开通了微信支付的公众号,需要配置一些参数.以下为参数总集,不同类型的公众号权限不同,如果某个权限没有的话,则对应参数不用也无法设置.例如我的服务号(权限全都有了的)参数如下:
01.appid: wxfedef3857580f5a0
02.appsecret: d92dd8864ba5j5g4bd596cb9739ee423
03.EncodingAESKey: njo2Kau5pCtc9cR0TQcfGYhz8rGCwdP1n9Ju33yvQRz
04.微信支付商户号: 1391091002
05.API密钥(key): 3bf1114a986ba87ed28fcj5p3s93c2f8
06.token: weixin
07.服务器配置: http://szuzsq.tunnel.qydev.com/weixin/mp/index.php
08.JS接口安全域名: szuzsq.tunnel.qydev.com
09.业务域名: szuzsq.tunnel.qydev.com
10.网页授权域名: szuzsq.tunnel.qydev.com
11.检验文件: http://szuzsq.tunnel.qydev.com/MP_verify_BDLeQ3NxRqt1pZB3.txt
12.支付授权目录: szuzsq.tunnel.qydev.com/weixin/mp/
13.测试授权目录: szuzsq.tunnel.qydev.com/weixin/mp/test/
14.扫码支付回调URL: http://szuzsq.tunnel.qydev.com/weixin/mp/notify_native.php
15.预留信息: rene
16.API证书: cert.zip(apiclient_cert.p12,apiclient_cert.pem,apiclient_key.pem,rootca.pem)
1).微信公众号官方管理平台->开发->基本配置.如图:
2).微信公众号官方管理平台->右上角logo->功能配置.如图:
其中注意,设置业务域名,JS接口安全域名,网页授权域名这3个参数时,需要下载1个txt文件(例如,我的是MP_verify_BDLeQ3NxRqt1pZB3.txt),将文件上传至域名根目录或者项目路径下.
例如我的是http://szuzsq.tunnel.qydev.com/MP_verify_BDLeQ3NxRqt1pZB3.txt
是在按保存之前先上传,不然不能保存.只需下载1次,3个参数里的txt文件是一样的.
前2个参数,每个月只能修改3次.如图:

其中注意,似乎新版没有测试授权目录了.
4).微信支付商户平台->账户中心->个人信息
5).微信支付商户平台->账户中心->API安全
其中注意,证书下载下来为打包的cert.zip.其apiclient_cert.p12用于java版本等的微信支付.apiclient_cert.pem,apiclient_key.pem用于php版本的微信支付.例如.我使用php语言,则将文件上传到:
http://szuzsq.tunnel.qydev.com/weixin/lib/wxlib/wxpay/cert/apiclient_cert.pem
http://szuzsq.tunnel.qydev.com/weixin/lib/wxlib/wxpay/cert/apiclient_key.pem
在我以后的代码中,使用curl退款时,会用到这些证书.
四.搭建本地开发环境
我使用php作为开发语言(所有的例子都是基于php+ html5 + css3 + javascript),大家可选用自己熟悉的语言(只要是http服务器语言并且会搭建环境就行).我的环境为:windows7 + wampserver3 + eclipse..其中mysql默认编码以及排序均设置为utf8;php打开了xdebug调试;eclipse上集成web,javascript,php插件.如果有同样使用php又不会的配置的,可联系我...关于断点调试,我的eclipse可调试普通网站的php代码,浏览器可调试普通网站的javascript代码.但是,怎么在微信公众号开发时断点调试php和javascript,我还不会,有会的同学,请指教.
wampserver3(wampserver3.0.4_x86_apache2.4.18_mysql5.7.11_php5.6.19-7.0.4.exe)下载地址: https://sourceforge.net/projects/wampserver/files
wampserver3自运安装了apache,mysql和php.
要运行eclipse,请先安装java(我的是java6).然后解压.
然后从菜单Help->Install New Software->Add.进入Add Respository界面,在Name处填写Indigo,在Location处填写: http://download.eclipse.org/releases/indigo.如果上一级Install界面的Work with里面直接有Indigo - http://download.eclipse.org/releases/indigo,也可以直接选中这一项...
解析完之后,会有一项"Web,XML,Java EE and OSGi Enterprise Development",不用全部安装,我只安装了"JavaScript Development Tools", "PHP Development Tools(PDT) SDK Feature"和"Web Page Editor"
五.响应微信服务器配置以及响应微信转发回复消息:
<?php
//文件名: http://szuzsq.tunnel.qydev.com/weixin/mp/index.php
define("TOKEN", "weixin");
$wechatObj = new wechatCallbackapiTest();
//转发xml消息也有signature,timestamp,nonce参数.只有验证消息才有echostr参数.
if(!isset($_GET["echostr"]) /*|| !isset($_GET["signature"]) || !isset($_GET["timestamp"]) || !isset($_GET["nonce"])*/)
$wechatObj->responseMsg();
else
$wechatObj->valid();
class wechatCallbackapiTest {
private function checkSignature() {
if(!defined("TOKEN"))
throw new Exception('TOKEN is not defined!');
$signature = $_GET["signature"];
$timestamp = $_GET["timestamp"];
$nonce = $_GET["nonce"];
$token = TOKEN;
if(!isset($signature) && !isset($timestamp) && !isset($nonce))
return false;
//将所有参数的值进行字符串的字典序排序,拼接成一个字符串进行sha1加密.
$data = array($token, $timestamp, $nonce);
sort($data, SORT_STRING);
return (sha1(implode($data)) == $signature) ? true : false;
}
public function valid() {
$echostr = $_GET["echostr"];
if($this->checkSignature()) {
echo $echostr;
exit;
}
}
public function responseMsg() {
//注:微信官方demo是使用$GLOBALS,而我使用的是file_get_contents的形式,来获取转发过来的xml内容.具体php配置不同,应采用不同的形式,请大家注意下,不然后可能粉丝收不到你的公众号回复的消息.
//$str = $GLOBALS["HTTP_RAW_POST_DATA"];
$str = file_get_contents("php://input");
if(!isset($str) || empty($str))
exit("");
//error_log($str, 3, "err.log");
libxml_disable_entity_loader(true);
$xml = simplexml_load_string($str, 'SimpleXMLElement', LIBXML_NOCDATA);
//各种消息的处理,请自己具体实现^_^
switch($xml->MsgType) {
case "text": { //文本消息
$fmt = "<xml>";
$fmt .= "<ToUserName><![CDATA[%s]]></ToUserName>";
$fmt .= "<FromUserName><![CDATA[%s]]></FromUserName>";
$fmt .= "<CreateTime>%s</CreateTime>";
$fmt .= "<MsgType><![CDATA[%s]]></MsgType>";
$fmt .= "<Content><![CDATA[%s]]></Content>";
$fmt .= "</xml>";
$toUserName = $xml->FromUserName;
$fromUserName = $xml->ToUserName;
$createTime = time();
$msgType = "text";
$content = "接收方:$xml->ToUserName";
$content .= "\n发送方:$xml->FromUserName";
$content .= "\n创建时间:$xml->CreateTime";
$content .= "\n类型:$xml->MsgType";
$content .= "\n内容:$xml->Content";
$content .= "\n消息ID:$xml->MsgId";
$rs = sprintf($fmt, $toUserName, $fromUserName, $createTime, $msgType, $content);
echo $rs;
break;
}
case "image": //图片消息
case "voice": //语音消息
case "video": //视频消息
case "shortvideo": //小视频消息
case "location": //地理位置消息
case "link": //链接消息
case "event": { //事件消息
echo "";
break;
}
}
}
}
?>