微信支付之公众号支付开发:遇到的坑及解决办法

公众号支付是用户在微信中打开商户的H5页面,商户在H5页面通过调用微信支付提供的JSAPI接口调起微信支付模块完成支付。 但是,微信官方的SDK “WxpayAPI_php_v3” V3版存在诸多问题,现从微信支付的接口原则和逻辑说说怎么解决。

官方文档中接口调用规则:

1、认证方式:HTTPS 认证,退款和冲正接口调用需要商户证书;
2、请求采用 POST 方式;
3、提交和返回结果采用 XML 格式;
4、字符集默认使用 UTF-8,请勿使用其它字符集;
5、商户与微信之间的交互(特别是 Native 回调和支付通知回调),都需验证签名;
6、处理返回时先判断协议返回错误码,再判断业务返回错误码,最后判断交易状态。

微信支付的流程与逻辑:

1、授权,抓取openid;
2、订单信息+openid得到支付页面;
3、支付,程序结束;
4、异步,腾讯服务器执行回调;回调目的是腾讯告诉我们订单是否支付成功。

问题一:curl错误码6

	/**
* 
* 通过code从工作平台获取openid机器access_token
* @param string $code 微信跳转回来带上的code
* 
* @return openid
*/
public function GetOpenidFromMp($code)
{
$url = $this->__CreateOauthUrlForOpenid($code);
//初始化curl
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $this->curl_timeout);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if(WxPayConfig::CURL_PROXY_HOST != "0.0.0.0" 
&& WxPayConfig::CURL_PROXY_PORT != 0){
curl_setopt($ch,CURLOPT_PROXY, WxPayConfig::CURL_PROXY_HOST);
curl_setopt($ch,CURLOPT_PROXYPORT, WxPayConfig::CURL_PROXY_PORT);
}
//运行curl,结果以jason形式返回
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res,true);
$this->data = $data;
$openid = $data['openid'];
return $openid;
}

问题原因:

如果开启了IPv6,curl默认会优先解析 IPv6,在对应域名没有 IPv6 的情况下,会等待 IPv6 dns解析失败 timeout 之后才按以前的正常流程去找 IPv4。在程序中我对curl获取内容都作了较为严格的超时限制,所以就会造成无法获取内容的问题。

解决办法: 强制curl走ipv4;或者centos系统中禁用ipv6; 或者添加微信相关域名解析。

curl_setopt($ch, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
修改/etc/sysctl.conf文件:
net.ipv6.conf.default.disable_ipv6 = 1
net.ipv6.conf.all.disable_ipv6 = 1
# /sbin/sysctl -p 使禁用IPv6生效
vi  etc/hosts
添加以下内容:
101.227.143.34 open.weixin.qq.com
101.226.90.149 api.mch.weixin.qq.com
101.226.90.58 api.weixin.qq.com

问题二:PHP7 接入微信支付存在的错误

 	/**
* 
* 支付结果通用通知
* @param function $callback
* 直接回调函数使用方法: notify(you_function);
* 回调类成员函数方法:notify(array($this, you_function));
* $callback  原型为:function function_name($data){}
*/
public static function notify($callback, &$msg)
{
//获取通知的数据
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
//如果返回成功则验证签名
try {
$result = WxPayResults::Init($xml);
} catch (WxPayException $e){
$msg = $e->errorMessage();
return false;
}
 
return call_user_func($callback, $result);
}

问题原因:

PHP7 不支持 $GLOBALS[‘HTTP_RAW_POST_DATA’]; 已移除该全局变量。

解决办法:

$xml = $GLOBALS['HTTP_RAW_POST_DATA'];  修改成: $xml = file_get_contents("php://input");