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

公众号支付是用户在微信中打开商户的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");