"require": {
"php": ">=5.4.0",
"topthink/framework": "5.0.*",
"wechatpay/wechatpay": "^1.4",
"topthink/think-captcha": "^1.0",
"wechatpay/wechatpay-guzzle-middleware": "^0.2.0"
},
然后执行 composer update。但是安装完成后vendor/topthink/里面的think-captcha、think-helper等文件都被删除了。那么就使用cmd面板 composer require topthink/think-captha 逐个安装即可。<?php namespace app\common\controller; use think\Controller; use think\Db; use think\Request; use think\Loader; use think\Log; use WeChatPay\Builder; use WeChatPay\Crypto\Rsa; use WeChatPay\Util\PemUtil; use WeChatPay\Formatter; use WeChatPay\Crypto\AesGcm; /** * 微信支付类包含二维码链接、查询、退款 */ class Wechatpay extends Controller{ protected $instance = null;//支付对象 protected $appid='ww6220c7';//公众号的APPID protected $merchantId='84540';//直连商户号 protected $serial='407D62E09FDCA6557E9A3';//证书序列号 protected $apiv3key='NXq7SYRNPlO1uP';// 在商户平台上设置的APIv3密钥 protected $notifyUrl;//支付回调链接 protected $refundNotify;//退款回调链接 public function _initialize(){ $this->notifyUrl=request()->domain()."/common/wechatpay/notify"; $this->refundNotify=request()->domain()."/common/wechatpay/refundNotify"; // 商户号 $merchantId = $this->merchantId; // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名 $filekey='file://'.EXTEND_PATH.'php_sdk_v3/cert/apiclient_key.pem'; $merchantPrivateKeyFilePath = str_replace('\\','/',$filekey); $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE); // 「商户API证书」的「证书序列号」 $merchantCertificateSerial = $this->serial ; // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名 $filecert='file://'.ROOT_PATH.'wechatpay_7ECC4533801129683DE4FD04.pem'; $platformCertificateFilePath = str_replace('\\','/',$filecert); $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); // The `certs(49FDCA6557E9A3)` contains the merchant's certificate serial number(EB3862E09FDCA6557E9A3) which is not allowed here.微信支付平台证书需要下载 // 从「微信支付平台证书」中获取「证书序列号」 $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath); // 构造一个 APIv3 客户端实例 $instance = Builder::factory([ 'mchid' => $merchantId, 'serial' => $merchantCertificateSerial, 'privateKey' => $merchantPrivateKeyInstance, 'certs' => [ $platformCertificateSerial => $platformPublicKeyInstance, ], ]); return $this->instance=$instance; } //调用微信支付付款二维码链接 public function showQrcode($request){ $code=1000; $msg="下单成功"; $codeurl=""; try { $resp = $this->instance ->chain('v3/pay/transactions/native') ->post([ 'json' => [ 'mchid' => $this->merchantId, 'out_trade_no' => $request['out_trade_no'], 'appid' => $this->appid, 'description' => $request['trade_name'], 'notify_url' => $this->notifyUrl, 'amount' => [ 'total' => $request['total_amount'], 'currency' => 'CNY' ], ] ]); if($resp->getStatusCode()==200 && $resp->getReasonPhrase()=='OK'){ $codeurl=json_decode($resp->getBody(),true)['code_url']; } } catch (\Exception $e) { // 进行错误处理 $code=1001; $msg=$e->getMessage(); if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); } } return ['code'=>$code,'msg'=>$msg,'data'=>$codeurl]; } //将用户支付成功消息通知给商户,同样的通知可能会多次发送给商户系统。 public function notify(Request $request){ // 同样的通知可能会多次发送给商户系统 //1,从请求头部Headers,拿到Wechatpay-Signature、Wechatpay-Nonce、Wechatpay-Timestamp、Wechatpay-Serial及Request-ID, $inWechatpaySignature = $request->header('wechatpay-signature');// 签名值 $inWechatpayTimestamp = $request->header('wechatpay-timestamp');// 时间戳 $inWechatpaySerial =$request->header('wechatpay-serial');// 商户API证书序列号 $inWechatpayNonce = $request->header('wechatpay-nonce');// 请求随机串 //2,获取请求body体的JSON纯文本; $inBody = file_get_contents('php://input');// 请根据实际情况获取,例如: file_get_contents('php://input'); $apiv3Key = $this->apiv3key;// 在商户平台上设置的APIv3密钥 // 根据通知的平台证书序列号,查询本地平台证书文件, $platformPublicKeyInstance = Rsa::from('file://'.ROOT_PATH.'wechatpay_4533801129683DE4FD04.pem', Rsa::KEY_TYPE_PUBLIC); // 3,检查通知消息头标记的Wechatpay-Timestamp偏移量是否在5分钟之内; $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp); //4,调用SDK内置方法,构造验签名串然后经Rsa::verfify 验签; $verifiedStatus = Rsa::verify( // 构造验签名串 Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody), $inWechatpaySignature, $platformPublicKeyInstance ); if ($timeOffsetStatus && $verifiedStatus) { // 转换通知的JSON文本消息为PHP Array数组 $inBodyArray = (array)json_decode($inBody, true); $ciphertext=$inBodyArray['resource']['ciphertext']; $nonce=$inBodyArray['resource']['nonce']; $aad=$inBodyArray['resource']['associated_data']; // 使用PHP7的数据解构语法,从Array中解构并赋值变量 ['resource' => [ 'ciphertext' => $ciphertext, 'nonce' => $nonce, 'associated_data' => $aad ]] = $inBodyArray; // 加密文本消息解密 $inBodyResource = AesGcm::decrypt($ciphertext, $apiv3Key, $nonce, $aad); // 把解密后的文本转换为PHP Array数组 $inBodyResourceArray = (array)json_decode($inBodyResource, true); header('status:200'); $code='SUCCESS'; $message=''; }else{ header('status:400'); $code='FAIL'; $message='失败'; } return json_encode(['code'=>$code,'message'=>$message]); } //调用微信支付接口订单查询,返回订单详情数组 public function orderquery($inBodyResourceArray){ try { $resp = $this->instance->chain('v3/pay/transactions/out-trade-no/'.$inBodyResourceArray['out_trade_no'])->get([ // Query 参数 'query' => ['mchid' => $this->merchantId], ]); if($resp->getStatusCode()==200 && $resp->getReasonPhrase()=='OK'){ $inBodyArray=json_decode($resp->getBody(),true); return $inBodyArray; } } catch (\Exception $e) { Log::error('下单返回错误值:'); // 进行错误处理 Log::error($e->getMessage()); } } /*微信退款 *接收参数:商户订单号、总金额、退款金额、退款原因 *返回值: */ public function refund($out_refund_no,$out_trade_no,$total_fee,$refund_fee){ $total_fee=(int)($total_fee*100); $refund_fee=(int)($refund_fee*100); $data=array(); if(isset($out_trade_no) && $out_trade_no != ""){ $promise = $this->instance ->chain('v3/refund/domestic/refunds') ->postAsync([ 'json' => [ 'out_trade_no' => $out_trade_no, 'out_refund_no' => $out_refund_no, 'notify_url'=> $this->refundNotify, 'amount' => [ 'refund' => $refund_fee, 'total' => $total_fee, 'currency' => 'CNY', ], ], ])->then(static function($response) { // 正常逻辑回调处理 return $response;//这里不是该方法的返回值,注意避坑 })->otherwise(static function($e) {
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); }return $r;
}); // 同步等待 $res =$promise->wait();
if($res->getStatusCode()!=200 && $res->getReasonPhrase()!='OK'){ // 退款异常 $data['code']=$res->getStatusCode(); $data['msg']='退款失败'; return $data; }else{ $data['code']=$res->getStatusCode(); $data['msg']='退款成功'; return $data; }} } // 退款回调接口 public function refundNotify(Request $request){ $inBody = file_get_contents('php://input'); header('status:200'); $code='SUCCESS'; $message=''; return json_encode(['code'=>$code,'message'=>$message]); } // 关闭订单接口 // 1、商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付; // 2、系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。 public function closeOrder($out_trade_no){ try { $resp = $this->instance->chain('v3/pay/transactions/out-trade-no/'.$out_trade_no.'/close') ->post([ // Query 参数 'json' => ['mchid' => $this->merchantId], ]); if($resp->getStatusCode()==204){ return ['code'=>1000,'msg'=>'订单已关闭']; } } catch (\Exception $e) { Log::error('closeOrder关单返回错误值:'); // 进行错误处理 Log::error($e->getMessage()); return ['code'=>1001,'msg'=>$e->getMessage()]; } } } ?>
html页面使用ajax查询订单,setintevel()
上一篇:Call to undefined function think\finfo_open()
下一篇:微信支付cURL error 60: SSL certificate problem: unable to get lo