在开发之中经常会使用到支付的功能,现在常用的两种支付方式是支付宝和微信。相对而言,支付宝的文档较为健全,并且配置和调用方式方式比较简单,这里就不过多的描述。
首先去微信官网网站下去下载服务端的demo:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
这里虽然是官网提供的公众号支付的demo,虽然微信支付的预下单等都可以在前端进行实现,不过官方还是建议在服务端进行处理。下载后,将其中的demo引入你的项目就好,注意的是如果是公众号的支付用到的类文件WxPay.JsApiPay.php在文件中example目录下。
接下来我们就可以进行引用了并实现。以thinkphp框架下进行调用为例(以下案例包括移动端以及公众号支付以及公众号获取openid等功能)。以下代码为了能够更容易理解,将一些类中的方法提取了出来,写的有点乱,请见谅。
public function wxAppOrder(){
vendor('WxpayAPI.lib.WxPay','','.Api.php');
vendor('WxpayAPI.lib.WxPay','','.Data.php');
$order_info= new WxPayUnifiedOrder();
$order_info->SetOut_trade_no($user_order_info['orderNo']);
$body=$user_order_product_info['productName'];
$order_info->SetBody($body);
$order_info->SetTrade_type('CNY');
$order_info->SetTotal_fee(intval($user_order_info['sumPrice']*100));
$order_info->SetTrade_type('APP');
$order_info->SetAppid(C('wxAPPID'));
$order_info->SetMch_id(C('wxMCHID'));
$order_info->SetNotify_url('你的回调地址');
$order_info->SetSign();
$wxpay=new WxPayApi();
$order_result=$wxpay->unifiedOrder($order_info);
if ($order_result['return_code']=='FAIL') {
$arr=array(
'resultCode'=>'99',
'resultDesc'=>$order_result['return_msg'],
'resultObj'=>array(''=>''),
);
echo JSON($arr);
exit();
}
if ($order_result['result_code']=='SUCCESS') {
$wxpay_result=new WxPayResults();
$timestamp=time();
$wxpay_result->SetData('appid', $order_result['appid']);
$wxpay_result->SetData('partnerid', $order_result['mch_id']);
$wxpay_result->SetData('prepayid', $order_result['prepay_id']);
$wxpay_result->SetData('timestamp', $timestamp);
$wxpay_result->SetData('noncestr', $order_result['nonce_str']);
$wxpay_result->SetData('package', 'Sign=WXPay');
$resign_result=$wxpay_result->SetSign();
$result=array(
'appid'=>$order_result['appid'],
'partnerid'=>$order_result['mch_id'],
'prepayid'=>$order_result['prepay_id'],
'package'=>'Sign=WXPay',
'noncestr'=>$order_result['nonce_str'],
'timestamp'=>$timestamp,
'sign'=>$resign_result,
);
$arr=array(
'resultCode'=>'00',
'resultDesc'=>'成功',
'resultObj'=>$result,
);
echo JSON($arr);
exit();
}else{
$arr=array(
'resultCode'=>'99',
'resultDesc'=>'失败',
'resultObj'=>$order_result,
);
echo JSON($arr);
exit();
}
}
public function wxpayNotify(){
vendor('WxpayAPI.lib.Logwx','','.Log.php');
$handle=new CLogFileHandler('./Public/wxlog.txt');
$log=Logwx::Init($handle);
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
vendor('WxpayAPI.lib.WxPay','','.Api.php');
vendor('WxpayAPI.lib.WxPay','','.Data.php');
$wxpay=new WxPayApi();
$notify=new WxPayNotifyReply();
$result=WxPayResults::Init($xml);
if ($result['return_code']=='SUCCESS' && $result['result_code']=='SUCCESS') {
if ($res) {
$log->INFO('订单:'.$result['out_trade_no'].'支付成功');
$notify->SetReturn_code('SUCCESS');
$notify->SetReturn_msg('OK');
$notify->SetSign();
}else{
$log->ERROR('微信支付失败');
$notify->SetReturn_code('FAIL');
$notify->SetReturn_msg('客户服务器错误');
}
}else{
$log->ERROR('微信回调返回错误');
$notify->SetReturn_code('FAIL');
$notify->SetReturn_msg('微信支付失败');
}
$wxpay->replyNotify($notify->ToXml());
}
public function wxPubOrder(){
$orderId=$_GET['orderId'];
header('Location:https://open.weixin.qq.com/connect/oauth2/authorize?appid='.'*******'.'&redirect_uri='.urlencode('http://*****/Pay/getOpenid/orderId/'.$orderId).'&response_type=code&scope=snsapi_base&state=123#wechat_redirect');
exit();
}
public function getOpenid(){
$code=$_GET['code'];
$state=$_GET['state'];
$orderId=$_GET['orderId'];
$appid='******';
$appsecret='******';
$get_token_url = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid='.$appid.'&secret='.$appsecret.'&code='.$code.'&grant_type=authorization_code';
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,$get_token_url);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 10);
$res = curl_exec($ch);
curl_close($ch);
$json_obj = json_decode($res,true);
$openId=$json_obj['openid'];
$url='http://******/html5/#/pay/'.$orderId.'openid='.$openId;
header('Location:'.$url);
}
public function wxOrder(){
$orderId=$_GET['orderId'];
$openId=$_GET['openId'];
if (empty($orderId)||empty($openId)) {
$arr=array(
'resultCode'=>'66',
'resultDesc'=>'缺少参数',
'resultObj'=>array(),
);
echo JSON($arr);
exit();
}
if (empty($user_order_info)) {
$arr=array(
'resultCode'=>'99',
'resultDesc'=>'不存在该订单',
'resultObj'=>array(),
);
echo JSON($arr);
exit();
}
vendor('WxpayAPI.lib.WxPay','','.Api.php');
vendor('WxpayAPI.lib.WxPay','','.Data.php');
$order_info= new WxPayUnifiedOrder();
$wxpay=new WxPayApi();
$order_info->SetMch_id('***');
$order_info->SetAppid('****');
$order_info->SetOut_trade_no($user_order_info['orderNo']);
$order_info->SetBody($user_order_good_info['productName']);
$order_info->SetTrade_type('CNY');
$order_info->SetTotal_fee(intval($user_order_info['sumPrice']*100));
$order_info->SetTrade_type('JSAPI');
$order_info->SetNonce_str($wxpay->getNonceStr(32));
$order_info->SetSpbill_create_ip('1.1.1.1');
$order_info->SetOpenid($openId);
$order_info->SetNotify_url('http://****/Pay/wxpayNotify');
$order_info->SetSign();
$order_result=$wxpay->unifiedOrder($order_info);
if ($order_result['return_code']=='FAIL') {
$arr=array(
'resultCode'=>'99',
'resultDesc'=>$order_result['return_code'].':'.$order_result['return_msg'],
'resultObj'=>array(),
);
echo JSON($arr);
exit();
}
if ($order_result['result_code']=='SUCCESS') {
$jsapi = new WxPayJsApiPay();
$jsapi->SetAppid($order_result["appid"]);
$timeStamp = time();
$jsapi->SetTimeStamp("$timeStamp");
$jsapi->SetNonceStr(WxPayApi::getNonceStr());
$jsapi->SetPackage("prepay_id=" . $order_result['prepay_id']);
$jsapi->SetSignType("MD5");
$jsapi->SetPaySign($jsapi->MakeSign());
$order_result = $jsapi->GetValues();
$arr=array(
'resultCode'=>'00',
'resultDesc'=>'成功',
'resultObj'=>$order_result,
);
echo JSON($arr);
exit();
}else{
$arr=array(
'resultCode'=>'99',
'resultDesc'=>'失败',
'resultObj'=>$order_result,
);
echo JSON($arr);
exit();
}
}
这就是一个支付的流程,在这之中会遇到很多问题,在此给出一个大多数会遇到的问题的解决方法的大概思路:
1、APP统一下单后数据返回给前端,前端调用报签名错误:首先验证自己的秘钥信息是否正确,要注意移动端和公众号的是不同的,而类拿着key又去重新签名,可以将微信官方提供的demo中的直接内部调用配置文件那里注释掉
2、在公众号获取openid的时候,显示跨域:这个解决参考YII2框架中对于\yii::$app->response->header,中的remove方法,将报头去掉即可。
3、对于微信支付的配置,包括公众号支付配置白名单、测试目录啥的就不过多说了,请自行搜索资料
过程中肯定还遇到很多问题,这里不一一写了,如果还有问题可以在评论中留言,大家一起讨论学习,共同进步。