|
|
@@ -1,424 +0,0 @@
|
|
|
-<?php
|
|
|
-/**
|
|
|
- * 微信支付
|
|
|
- * Created by PhpStorm.
|
|
|
- * User: phperstar
|
|
|
- * Date: 2019/11/28
|
|
|
- * Time: 2:12 PM
|
|
|
- */
|
|
|
-namespace Util\WeiXin;
|
|
|
-
|
|
|
-
|
|
|
-class QnWxPay
|
|
|
-{
|
|
|
- /**
|
|
|
- * 小程序 appId
|
|
|
- * @var string $appid
|
|
|
- */
|
|
|
- private $appid;
|
|
|
- /**
|
|
|
- * 商户号
|
|
|
- * @var string $mch_id
|
|
|
- */
|
|
|
- private $mch_id;
|
|
|
-
|
|
|
- /**
|
|
|
- * 商户支付密钥
|
|
|
- */
|
|
|
- private $partnerKey;
|
|
|
-
|
|
|
- /**
|
|
|
- * 微信支付异步通知地址
|
|
|
- */
|
|
|
- private $notifyUrl = PAY_NOTIFY_URL.'/common/WeiXinPayNotify/notify';
|
|
|
-
|
|
|
- /**
|
|
|
- * 公共的接口请求地址
|
|
|
- * @var string
|
|
|
- */
|
|
|
- private $apiUrl = 'https://api.mch.weixin.qq.com/pay/';
|
|
|
-
|
|
|
- /**
|
|
|
- * 基础得请求地址
|
|
|
- */
|
|
|
- private $baseUrl = 'https://api.mch.weixin.qq.com/';
|
|
|
-
|
|
|
-
|
|
|
- private $config;
|
|
|
-
|
|
|
- /**
|
|
|
- * Pay constructor.
|
|
|
- * @param string $appid
|
|
|
- * @param $mch_id
|
|
|
- * @param $partnerKey
|
|
|
- */
|
|
|
- public function __construct($appid='', $mch_id, $partnerKey)
|
|
|
- {
|
|
|
- $this->appid = $appid;
|
|
|
- $this->mch_id = $mch_id;
|
|
|
- $this->partnerKey = $partnerKey;
|
|
|
- if(empty($config)) $config = config('wxpay');
|
|
|
- $this->config = $config;
|
|
|
- }
|
|
|
-
|
|
|
- public function wxmpPay($post=[]){
|
|
|
- $url = $this->apiUrl.'unifiedorder';
|
|
|
- $params = [
|
|
|
- 'appid' => $this->config["APPID"], // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->config["MCHID"], // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().randString(10))), // 32位随机字符串
|
|
|
- 'out_trade_no' => $post["out_trade_no"], // 商户订单号
|
|
|
- 'total_fee' => (int)(floatval($post["total"])*100), // 订单总金额,单位分
|
|
|
- 'spbill_create_ip' => empty($post["payer_client_ip"])?"127.0.0.1":$post["payer_client_ip"], // 终端ip
|
|
|
- 'trade_type' => "JSAPI", // 交易类型
|
|
|
- 'notify_url' => $this->config["NOTIFY_URL"], // 通知地址
|
|
|
- 'body' => empty($post["body"]) ?"微信小程序支付":$post["body"],
|
|
|
- 'attach' => empty($post["attach"])?"微信小程序支付":$post["attach"],
|
|
|
- 'openid' => $post["openid"],
|
|
|
- ];
|
|
|
- $params["sign"] = self::getSign($params);
|
|
|
-// $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 统一下单接口
|
|
|
- */
|
|
|
- public function unifiedorder($orderNo, $total_fee, $ip, $source, $shopName, $openid = '', $attach = '')
|
|
|
- {
|
|
|
- $url = $this->apiUrl.'unifiedorder';
|
|
|
-
|
|
|
- switch ($source){
|
|
|
- case 'H5':
|
|
|
- $trade_type = 'MWEB';
|
|
|
- break;
|
|
|
- case 'APP':
|
|
|
- $trade_type = 'APP';
|
|
|
- break;
|
|
|
- default:
|
|
|
- $trade_type = 'JSAPI';
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid, // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->mch_id, // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'out_trade_no' => $orderNo, // 商户订单号
|
|
|
- 'total_fee' => yuanToFen($total_fee), // 订单总金额,单位分
|
|
|
- 'spbill_create_ip' => $ip, // 终端ip
|
|
|
- 'trade_type' => $trade_type, // 交易类型
|
|
|
- 'notify_url' => $this->notifyUrl, // 通知地址
|
|
|
- 'body' => $shopName.'-'.'线上商城',
|
|
|
- 'attach' => $attach, // 附加数据
|
|
|
- ];
|
|
|
- if($trade_type == 'JSAPI'){
|
|
|
- $params['openid'] = $openid;
|
|
|
- }
|
|
|
-
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml);
|
|
|
-
|
|
|
- $result = $this->commonResult($curl_content);
|
|
|
- if(!$result->isSuccess()){
|
|
|
- return ResultWrapper::fail($result->getData(), $result->getErrorCode());
|
|
|
- }
|
|
|
- $response_content = $result->getData();
|
|
|
-
|
|
|
- //获取统一下单返回的id
|
|
|
- $prepay_id = $response_content['prepay_id'];
|
|
|
-
|
|
|
- // H5支付返回的支付跳转链接
|
|
|
- $mweb_url = isset($response_content['mweb_url']) ? $response_content['mweb_url'] : '';
|
|
|
-
|
|
|
- switch ($source){
|
|
|
- case 'byteDanceH5':
|
|
|
- $payParams = $mweb_url; // 字节跳动小程序调用微信H5支付获取支付链接
|
|
|
- break;
|
|
|
- case 'H5':
|
|
|
- $payParams = self::payment($prepay_id);
|
|
|
- break;
|
|
|
- case 'APP':
|
|
|
- $payParams = self::payment($prepay_id);
|
|
|
- break;
|
|
|
- default:
|
|
|
- $payParams = self::paymentToMinprogram($prepay_id);
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return ResultWrapper::success($payParams);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * 小程序调起支付用到的参数
|
|
|
- * 官方接口地址: https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
|
|
|
- */
|
|
|
- public function paymentToMinprogram($prepay_id)
|
|
|
- {
|
|
|
- unset($params);
|
|
|
- $params = [
|
|
|
- 'appId' => $this->appid, // 小程序ID
|
|
|
- 'timeStamp' => (string)time(), //时间戳
|
|
|
- 'nonceStr' => md5(md5(time().'qianniao.vip')), //32位随机字符串
|
|
|
- 'package' => 'prepay_id='.$prepay_id, // 数据包
|
|
|
- 'signType' => 'MD5', // 签名方式
|
|
|
- ];
|
|
|
- $params['paySign'] = self::getSign($params);
|
|
|
- return $params;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 调起支付用到的参数
|
|
|
- * 官方接口地址: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12
|
|
|
- * @param $prepay_id
|
|
|
- */
|
|
|
- public function payment($prepay_id)
|
|
|
- {
|
|
|
- unset($parm);
|
|
|
- $parm = array(
|
|
|
- 'appid' => $this->appid,
|
|
|
- 'partnerid' => $this->mch_id,
|
|
|
- 'timestamp' => (string)time(), //时间戳
|
|
|
- 'noncestr' => md5(md5(time().'qianniao.vip')), //32位随机字符串
|
|
|
- 'prepayid' => $prepay_id, //统一下单接口返回的prepay_id 参数值
|
|
|
- 'package' => 'Sign=WXPay',
|
|
|
- );
|
|
|
- $parm['sign'] = self::getSign($parm);
|
|
|
- return $parm;
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 付款码支付
|
|
|
- * 官方文档地址: https://pay.weixin.qq.com/wiki/doc/api/micropay.php?chapter=9_10&index=1
|
|
|
- */
|
|
|
- public function micropay($orderNo, $total_fee, $ip, $shopName, $auth_code)
|
|
|
- {
|
|
|
- $url = $this->apiUrl.'micropay';
|
|
|
-
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid, // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->mch_id, // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'body' => $shopName.'-'.'线上商城',
|
|
|
- 'out_trade_no' => $orderNo, // 商户订单号
|
|
|
- 'total_fee' => yuanToFen($total_fee), // 订单总金额,单位分
|
|
|
- 'spbill_create_ip' => $ip, // 终端ip
|
|
|
- 'auth_code' => $auth_code,
|
|
|
- ];
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml);
|
|
|
-
|
|
|
- if($curl_content['httpcode'] != '200'){
|
|
|
- return ResultWrapper::fail($curl_content['errorMsg'], ErrorCode::$apiNotResult);
|
|
|
- }
|
|
|
-
|
|
|
- $response_content = (array)simplexml_load_string($curl_content['content'], 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
|
- if($response_content['return_code'] != 'SUCCESS'){
|
|
|
- return ResultWrapper::fail($response_content['return_msg'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- if($response_content['result_code'] != 'SUCCESS' && $response_content['err_code'] != 'USERPAYING' ){
|
|
|
- return ResultWrapper::fail($response_content['err_code_des'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- // 20s内查询支付状态,如果有明确错误直接返回错误,其他情况继续查询。如果成功直接返回成功
|
|
|
- for($i=1; $i<=10; $i++)
|
|
|
- {
|
|
|
- $url = $this->apiUrl.'orderquery';
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid, // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->mch_id, // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'out_trade_no' => $orderNo, // 商户订单号
|
|
|
- ];
|
|
|
-
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml);
|
|
|
-
|
|
|
- if($curl_content['httpcode'] != '200'){
|
|
|
- return ResultWrapper::fail($curl_content['errorMsg'], ErrorCode::$apiNotResult);
|
|
|
- }
|
|
|
-
|
|
|
- $response_content = (array)simplexml_load_string($curl_content['content'], 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
|
- if($response_content['return_code'] != 'SUCCESS'){
|
|
|
- return ResultWrapper::fail($response_content['return_msg'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- if($response_content['result_code'] != 'SUCCESS' && $response_content['err_code'] == 'ORDERNOTEXIST'){
|
|
|
- return ResultWrapper::fail($response_content['err_code_des'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- if($response_content['return_code'] == 'SUCCESS' && $response_content['result_code'] == 'SUCCESS' && $response_content['trade_state'] == 'SUCCESS'){
|
|
|
- return ResultWrapper::success($response_content['trade_state']);
|
|
|
- }
|
|
|
-
|
|
|
- sleep(2);
|
|
|
- }
|
|
|
-
|
|
|
- // 20s内没有支付则撤销订单
|
|
|
- for($i=1; $i<=10; $i++){
|
|
|
- $url = $this->baseUrl.'secapi/pay/reverse';
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid, // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->mch_id, // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'out_trade_no' => $orderNo, // 商户订单号
|
|
|
- ];
|
|
|
-
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml, 10, false, [], true);
|
|
|
-
|
|
|
- if($curl_content['httpcode'] != '200'){
|
|
|
- return ResultWrapper::fail($curl_content['errorMsg'], ErrorCode::$apiNotResult);
|
|
|
- }
|
|
|
- $response_content = (array)simplexml_load_string($curl_content['content'], 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
|
- if($response_content['return_code'] != 'SUCCESS'){
|
|
|
- return ResultWrapper::fail($response_content['return_msg'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- if($response_content['result_code'] != 'SUCCESS' && $response_content['recall'] == 'N'){
|
|
|
- return ResultWrapper::fail($response_content['err_code_des'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
-
|
|
|
- if($response_content['return_code'] == 'SUCCESS' && $response_content['result_code'] == 'SUCCESS' && $response_content['recall'] == 'N'){
|
|
|
- return ResultWrapper::success($response_content['result_code']);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- /**
|
|
|
- * H5查询支付状态接口
|
|
|
- */
|
|
|
- public function orderquery($orderNo)
|
|
|
- {
|
|
|
- $url = $this->apiUrl.'orderquery';
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid, // 小程序ID/微信开放平台审核通过的应用APPID
|
|
|
- 'mch_id' => $this->mch_id, // 商户号
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'out_trade_no' => $orderNo, // 商户订单号
|
|
|
- ];
|
|
|
-
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml);
|
|
|
-
|
|
|
- $result = $this->commonResult($curl_content);
|
|
|
- if(!$result->isSuccess()){
|
|
|
- return ResultWrapper::fail($result->getData(), $result->getErrorCode());
|
|
|
- }
|
|
|
- $response_content = $result->getData();
|
|
|
-
|
|
|
- $trade_state = $response_content['trade_state'];
|
|
|
-
|
|
|
- return ResultWrapper::success($trade_state);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 申请退款API
|
|
|
- * 官方文档地址:https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_4
|
|
|
- */
|
|
|
- public function transfers($outerTradeNo, $out_refund_no, $refundMoney, $orderMoney, $sslData)
|
|
|
- {
|
|
|
- $url = $this->baseUrl.'secapi/pay/refund';
|
|
|
- $params = [
|
|
|
- 'appid' => $this->appid,
|
|
|
- 'mch_id' => $this->mch_id,
|
|
|
- 'nonce_str' => md5(md5(time().'qianniao.vip')), // 32位随机字符串
|
|
|
- 'transaction_id' => $outerTradeNo, // 微信交易号
|
|
|
- 'out_refund_no' => $out_refund_no, // 商户退款单号
|
|
|
- 'refund_fee' => yuanToFen($refundMoney), // 退款金额
|
|
|
- 'total_fee' => yuanToFen($orderMoney), // 订单总金额
|
|
|
- ];
|
|
|
-
|
|
|
- $params['sign'] = self::getSign($params);
|
|
|
- $post_xml = $this->arrayToWeiXinXml($params);
|
|
|
- $curl_content = request($url, $post_xml, 10, false, [], true, $sslData);
|
|
|
-
|
|
|
- $result = $this->commonResult($curl_content);
|
|
|
- if(!$result->isSuccess()){
|
|
|
- return ResultWrapper::fail($result->getData(), $result->getErrorCode());
|
|
|
- }
|
|
|
- $response_content = $result->getData();
|
|
|
-
|
|
|
- return ResultWrapper::success($response_content['refund_id']);
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 公共处理返回结果方法
|
|
|
- */
|
|
|
- public function commonResult($curl_content)
|
|
|
- {
|
|
|
- if($curl_content['httpcode'] == '200'){
|
|
|
- $response_content = (array)simplexml_load_string($curl_content['content'], 'SimpleXMLElement', LIBXML_NOCDATA);
|
|
|
- if($response_content['return_code'] == 'SUCCESS'){
|
|
|
- if($response_content['result_code'] == 'SUCCESS'){
|
|
|
- return ResultWrapper::success($response_content);
|
|
|
- }else{
|
|
|
- return ResultWrapper::fail($response_content['err_code_des'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
- }else{
|
|
|
- return ResultWrapper::fail($response_content['return_msg'], ErrorCode::$weixinPayError);
|
|
|
- }
|
|
|
- }else{
|
|
|
- return ResultWrapper::fail($curl_content['errorMsg'], ErrorCode::$apiNotResult);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 生成签名方法
|
|
|
- * 官方接口地址: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=4_3
|
|
|
- * 官方签名测试地址: https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1
|
|
|
- * @param $parm
|
|
|
- * @return string
|
|
|
- */
|
|
|
- public function getSign($parm)
|
|
|
- {
|
|
|
- //非空参数值的参数按照参数名ASCII码从小到大排序(字典序)
|
|
|
- if(ksort($parm)){
|
|
|
- $stringA = '';
|
|
|
- //使用URL键值对的格式拼接成字符串stringA
|
|
|
- foreach($parm as $key => $value){
|
|
|
- if($value == 0 || !empty($value)){
|
|
|
- $stringA .=$key.'='.$value.'&';
|
|
|
- }
|
|
|
- }
|
|
|
- }else{
|
|
|
- echo "对参数排序出错";
|
|
|
- exit();
|
|
|
- }
|
|
|
-
|
|
|
- //在stringA最后拼接上key=商户支付密钥
|
|
|
- $stringSignTemp = $stringA.'key='.$this->config["ApiV2Key"];
|
|
|
-
|
|
|
- //对stringSignTemp进行MD5运算,再将得到的字符串所有字符转换为大写
|
|
|
- $signValue = strtoupper(md5($stringSignTemp));
|
|
|
- return $signValue;
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- //数组转xml
|
|
|
- public function arrayToWeiXinXml($arr)
|
|
|
- {
|
|
|
- $xml = '<xml>';
|
|
|
- foreach($arr as $key => $value){
|
|
|
- if (is_string($value)) {
|
|
|
- $xml .= '<' . $key . '><![CDATA[' . $value . ']]></' . $key . '>';
|
|
|
- } else {
|
|
|
- $xml .= '<' . $key . '>' . $value . '</' . $key . '>';
|
|
|
- }
|
|
|
- }
|
|
|
- $xml .='</xml>';
|
|
|
- return $xml;
|
|
|
- }
|
|
|
-
|
|
|
-}
|