最近一直在搞微信开发,其中涉及的比较复杂,开发商户模式的微信支付,实现每个代理商家可以独立收款并且为为每个商家的公众号吸粉。这篇主要分享的是微信的授权,简单的授权,我就不记录了,这里要分享的一个授权域名去获取多个公众号的用户信息。
抛出问题:一个代理商A,这个代理商下面会有A1,A2, A3多个代理商,每个代理商都有独立的微信公众号,都要求独立收款,即用户付款之后要自动将金额转到每个商户中,目前业务服务器一台架设在www.a.com,用户购买都是在公众号中完成,排除了 h5支付和扫码支付,只能使用公众号支付。问怎么实现?
解决方法:开发过微信的朋友们可能知道,普通商户模式是无法实现以上需求,(如果有办法实现的朋友可以微信我,微信:13642245956),这里我们使用的是商户模式,就是一种代理模式。一个商户下面可以有很多子商户,每个子商户在后台配置上相应的appid,即时公众号ID,每个公众号的授权域名都是填www.a.com,后台会记录这些子商户的相关信息(appid等等),OK,这样就可以根据不同的子商户的公众号信息去获取对应公众号的用户信息。(这里会有个小插曲,后续)
以下是我对微信授权的代码封装实现(后续会不断去丰富这个类)这其中最主要的便是auth和snsapiUserinfoAuth这两个函数(这两个函数是本编的重点)
namespace App\Libs\Weixin;
class CommWeiXin
{
private $appId;
private $appSecret;
private $protocol;
private $code;
function __construct($appId, $appSecret, $protocol="http") {
$this->appId = $appId;
$this->appSecret = $appSecret;
$this->protocol = $protocol;
}
private function getCode($redirectUrl, $scope='snsapi_base') {
if(empty($this->appId)) {
throw new Exception("WeiXin AppId is NULL, Init Please");
}
$url = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=' . $this->appId;
$url .= '&redirect_uri=' . urlencode($redirectUrl);
$url .='&response_type=code&scope=' . $scope . '&state=STATE#wechat_redirect';
header('location:'.$url);
exit;
}
private function getUserInfo($code) {
if(empty($this->appId)) {
throw new Exception("WeiXin AppId is NULL, Init Please");
}
if(empty($this->appSecret)) {
throw new Exception("WeiXin AppSecret is NULL, Init Please");
}
$url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=' . $this->appId;
$url .= '&secret=' . $this->appSecret . '&code=' . $code . '&grant_type=authorization_code';
return $this->dataReq($url, 'GET');
}
//默认静默获取用户信息
public function auth($scope = 'snsapi_base') {
$redirectUrl = $this->protocol.'://'.$_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI'];
if(!isset($_GET['code'])) {
$this->getCode($redirectUrl, $scope);
} else {
$code = $_GET['code'];
$userinfo = $this->getUserInfo($code);
$userinfo = json_decode($userinfo);
if(isset($userinfo->errcode)) {
$this->getCode($redirectUrl);
$userinfo = json_decode($this->getUserInfo($code));
}
return $userinfo;
}
}
//非静默获取用户信息
public function snsapiUserinfoAuth() {
$ret = $this->auth('snsapi_userinfo');
$accessToken = $ret->access_token;
$url = 'https://api.weixin.qq.com/sns/userinfo?access_token='.$accessToken.'&openid=OPENID&lang=zh_CN';
return $this->dataReq($url, 'GET');
}
public function pay($postData) {
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$dataxml = $this->dataReq($url, 'POST', $postData);
return $dataxml;
}
public static function dataReq ($url, $method, $postfields = NULL, $header_array = array(), $userpwd = NULL) {
$ci = curl_init();
curl_setopt($ci, CURLOPT_USERAGENT, 'Mozilla/4.0');
curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, 30);
curl_setopt($ci, CURLOPT_TIMEOUT, 30);
curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ci, CURLOPT_HEADER, FALSE);
if ($userpwd) {
curl_setopt($ci, CURLOPT_USERPWD, $userpwd);
}
$method = strtoupper($method);
switch ($method) {
case 'GET':
if (! empty($postfields)) {
$url = $url . '?' . http_build_query($postfields);
}
break;
case 'POST':
curl_setopt($ci, CURLOPT_POST, TRUE);
if (! empty($postfields)) {
curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
}
break;
}
$header_array2 = array();
foreach ($header_array as $k => $v) {
array_push($header_array2, $k . ': ' . $v);
}
curl_setopt($ci, CURLOPT_HTTPHEADER, $header_array2);
curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($ci, CURLOPT_URL, $url);
$response = curl_exec($ci);
if(curl_errno($ci) != 0) {
error_log(curl_error($ci)."--".curl_errno($ci)."\n",3,DOCROOT.'demo1.log');
}
curl_close($ci);
return $response;
}
}
使用实例(其实微信有相应的SDK但是用起来不是很方便,至少对于我这个项目来说吧!使用起来也是相当简单吧)
//获取到A商户的公众号的用户的openid
public function getUserinfo_A() {
$commweixin = new CommWeiXin('appidA', 'appSecretA');
$userinfo = $commweixin->auth();
//使用该公众号的用户的openid,对应其子商户sub_appid和子商户sub_mch_id进行支付,那么用户支付的金额就到该子商户A中了(下一篇章再叙)
}
//获取到B商户的公众号的用户的openid
public function getUserinfo_B() {
$commweixin = new CommWeiXin('appidB', 'appSecretB');
$userinfo = $commweixin->auth();
//使用该公众号的用户的openid,对应其子商户sub_appid和子商户sub_mch_id进行支付,那么用户支付的金额就到该子商户B中了(下一篇章再叙)
}
划重点:1、都有的公众号都必须是服务号。2、所有公众号的授权域名都必须是同一个(这里都是www.a.com)。3、在填写域名时,要将验证文件上传到www.a.com项目的根目录之后,填写域名之后必须将这个文件删除(否则无法实现,这就是前面说到的那个小插曲)