重构封装微信服务号支付接口
微信支付支付接口提供sdk太多,太复杂,修改很不方便,于是自已重新封装,支付测试成功!
1 微信支付数据配置
2 unifiedorder() 支付方法 ,notify() 微信支付结果通知回调
微信支付,有太多的坑,需要技术支持联系我QQ2420355482
<?php
namespace app\index\controller;
class WxPay extends Common
{
private $config;
//前置操作
public function _initialize()
{
$this->config = $this->config();
}
//微信支付数据配置
private function config()
{
$config = array();
$config['appid']= '请填写'; //微信分配的公众账号ID
$config['MerchantId'] = '请填写'; //商户号
$config['key'] = '请填写'; //商户支付密钥
$config['notify_url'] = '请填写'; //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
return $config;
}
public function unifiedorder($orderData=array())
{
$input = array();
//自定义订单数据
$input['attach'] = '支付测试'; //附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
$input['body'] = '支付测试'; //商品简单描述
$input['openid'] = 'onXiXv-af8He2UkIqovTBwWfAmF8'; //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
$input['out_trade_no'] = '14156599995568'; //商户系统内部的订单号,32个字符内、可包含字母,
$input['total_fee'] = 1; //订单总金额,单位为分
//配置数据
$input['appid'] = $this->config['appid']; //微信分配的公众账号ID 支付测试
$input['mch_id'] = $this->config['MerchantId']; //微信支付分配的商户号
$input['notify_url'] = $this->config['notify_url']; //接收微信支付异步通知回调地址,通知url必须为直接可访问的url,不能携带参数。
//预置数据
$input['spbill_create_ip'] = $_SERVER['REMOTE_ADDR']; //终端ip
$input['nonce_str'] = $this->getNonceStr(); //随机字符串
$input['trade_type'] = 'JSAPI'; //JSAPI支付的交易类型为MWEB
$input['time_start']= date("YmdHis"); //设置订单生成时间,格式为yyyyMMddHHmmss,如2009年12月25日9点10分10秒表示为20091225091010。
$input['time_expire']= date("YmdHis", time() + 600); //设置订单失效时间,格式为yyyyMMddHHmmss,如2009年12月27日9点10分10秒表示为20091227091010。//
$input['sign'] = $this->sign($input); //获取签名
$data = $this->ToXml($input); //提交的xml格式数据
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //统一下单接口
$res = $this->postXmlCurl($data,$url); //psot提交
$jsApiParameters = $this->GetJsApiParameters($res); //获取jsapi支付的参数
$this->assign('jsApiParameters',$jsApiParameters);
return view();
}
//微信支付结果通知回调
public function notify()
{
if(request()->isPost()){
$xml = file_get_contents("php://input");
//将xml转化为json格式
$xml = json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA));
//转成数组
$result = json_decode($xml, true);
if($result){
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
//支付成功操作
return true;
}else{
//支付失败操作
return false;
}
}
}
}
//签名
private function sign($value){
//签名步骤一:按字典序排序参数
ksort($value);
//--格式化参数格式化成url参数
$buff = "";
foreach ($value as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
$string = $buff;
//签名步骤二:在string后加入KEY
$string = $string . "&key=".$this->config['key'];
//签名步骤三:MD5加密或者HMAC-SHA256
//$string =hash_hmac("sha256",$string,$key);
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
//将据转换为xml格式
// $value['sign'] = $result;
// $xmlData = $this->ToXml($value);
// dump($xmlData);
return $result;
}
/**
* 输出xml字符
* @throws WxPayException
**/
public function ToXml($value)
{
if(!is_array($value) || count($value) <= 0)
{
throw new WxPayException("数组数据异常!");
}
$xml = "<xml>";
foreach ($value as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
/*
* 以post方式提交xml到对应的接口url
*
* @param string $xml 需要post的xml数据
* @param string $url url 提交的接口地址
* @param int $second url执行超时时间,默认30s
* @throws WxPayException
*/
private static function postXmlCurl($xml, $url, $second = 30)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_TIMEOUT, $second);//设置超时
curl_setopt($ch,CURLOPT_URL, $url); //指定URL
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE); //忽略证书
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,false);//忽略证书
curl_setopt($ch, CURLOPT_HEADER, FALSE); //忽略header头信息
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); //设定请求后返回结果
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出错,错误码:$error");
}
}
/**
*
* 产生随机字符串,不长于32位
* @param int $length
* @return 产生的随机字符串
*/
public static function getNonceStr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
/**
* 获取毫秒级别的时间戳
*/
private static function getMillisecond()
{
//获取毫秒的时间戳
$time = explode ( " ", microtime () );
$time = $time[1] . ($time[0] * 1000);
$time2 = explode( ".", $time );
$time = $time2[0];
return $time;
}
//获取jsapi支付的参数,将xml数据转为json
public function GetJsApiParameters($xml){
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
//dump($arr);
$data = array();
$data['appId'] = $arr['appid'];
$data['nonceStr'] = $this->getMillisecond();
$data['package'] = 'prepay_id='.$arr['prepay_id'];
$data['signType'] = 'MD5';
$data['timeStamp'] =$this->getMillisecond();
$data['paySign'] = $this->sign($data); //二次签名
return json_encode($data);
}
}前端js发起支付
<script type="text/javascript">
// //调用微信JS api 支付
function jsApiCall()
{
WeixinJSBridge.invoke(
'getBrandWCPayRequest',
{$jsApiParameters},
function(res){
if(res.err_msg == "get_brand_wcpay_request:ok"){
paySuccess();
}else{
payFail();
}
}
);
}
function callpay()
{
if (typeof WeixinJSBridge == "undefined"){
if( document.addEventListener ){
document.addEventListener('WeixinJSBridgeReady', jsApiCall, false);
}else if (document.attachEvent){
document.attachEvent('WeixinJSBridgeReady', jsApiCall);
document.attachEvent('onWeixinJSBridgeReady', jsApiCall);
}
}else{
jsApiCall();
}
}
//支付成功
function paySuccess() {
//进行操作
}
//支付失败
function payFail() {
//进行操作
}
//获取get参数
function getQueryVariable(variable){
var query = window.location.search.substring(1);
var vars = query.split("&");
for (var i=0;i<vars.length;i++) {
var pair = vars[i].split("=");
if(pair[0] == variable){return pair[1];}
}
return(false);
}
callpay(); //发起支付
</script>