PHP 实现微信Native扫码支付
短信预约 -IT技能 免费直播动态提醒
目录
一、安装微信SDK
composer require wechatpay/wechatpay
二、准备请求资料
appid:开放平台
mchid:商户平台
商户API证书:商户平台-账户中心-api安全(申请)
商户API秘钥:商户平台-账户中心-api安全(申请)
商户证书序列号:开放平台-API管理
apiv3_key:商户平台-api安全
微信支付平台证书:(在项目根目录执行命令,保证sdk已安装 证书保存文件夹已经创建 outputFilePath 保存地址是项目地址中的文件夹)
php vendor/bin/CertificateDownloader.php -k ${apiV3key} -m ${mchId} -f ${mchPrivateKeyFilePath} -s ${mchSerialNo} -o ${outputFilePath}
${apiV3key} 替换成apiV3key秘钥
${mchId} 替换成商户号
${mchPrivateKeyFilePath} 替换成商户私钥路径
${mchSerialNo} 替换成商户证书序列号
${outputFilePath} 替换成微信支付证书要保存的路径
三、引入和定义
use WeChatPay\Builder;use WeChatPay\Crypto\AesGcm;use WeChatPay\Crypto\Rsa;use WeChatPay\Formatter;use WeChatPay\Util\PemUtil; private const APPID = ''; //appid private const MCHID = ''; //商户号 private const CERT_NUM = ''; //商户证书序列号 private const APIV3_KEY = ''; //apiv3秘钥
四、Native下单
返回一个code_url 后端生成二维码显示给前端
//Native下单 public function paymentCode($out_trade_no, $description, $notify_url, $total) { // 微信配置 $merchantId = self::MCHID; // 商户号 $appid = self::APPID; // appid // 从本地文件中加载「商户API私钥」,「商户API私钥」会用来生成请求的签名 $merchantPrivateKeyFilePath = 'file://' . ROOT_PATH . '\app\...私钥路径..\apiclient_key.pem'; $merchantPrivateKeyInstance = Rsa::from($merchantPrivateKeyFilePath, Rsa::KEY_TYPE_PRIVATE); // 「商户API证书」的「证书序列号」 $merchantCertificateSerial = self::CERT_NUM; // 从本地文件中加载「微信支付平台证书」,用来验证微信支付应答的签名 $platformCertificateFilePath = 'file://' . ROOT_PATH . '\app\...支付证书路径...\wechatpay_123456.pem'; $platformPublicKeyInstance = Rsa::from($platformCertificateFilePath, Rsa::KEY_TYPE_PUBLIC); // 从「微信支付平台证书」中获取「证书序列号」 $platformCertificateSerial = PemUtil::parseCertificateSerialNo($platformCertificateFilePath); // 构造一个 APIv3 客户端实例 $instance = Builder::factory([ 'mchid' => $merchantId, 'serial' => $merchantCertificateSerial, 'privateKey' => $merchantPrivateKeyInstance, 'certs' => [ $platformCertificateSerial => $platformPublicKeyInstance, ], ]); try { $resp = $instance ->chain('v3/pay/transactions/native') ->post(['json' => [ 'mchid' => $merchantId, 'out_trade_no' => $out_trade_no, 'appid' => $appid, 'description' => $description, 'notify_url' => $notify_url, 'amount' => [ 'total' => $total * 100, 'currency' => 'CNY' ], ]]); echo $resp->getStatusCode(), PHP_EOL; echo $resp->getBody(), PHP_EOL; //返回的code_url } catch (\Exception $e) { // 进行错误处理 echo $e->getMessage(), PHP_EOL; if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) { $r = $e->getResponse(); echo $r->getStatusCode() . ' ' . $r->getReasonPhrase(), PHP_EOL; echo $r->getBody(), PHP_EOL, PHP_EOL, PHP_EOL; } echo $e->getTraceAsString(), PHP_EOL; } }
五、Native调起支付
用户扫码即调起
六、Native异步通知
// 异步通知 public function wxPayNotify() { $headers = $this->request->header(); $inWechatpaySignature = $headers['wechatpay-signature']; // 应答heade中对应数据:应答签名 $inWechatpayTimestamp = $headers['wechatpay-timestamp']; // 应答heade中对应数据:应答时间戳 $inWechatpaySerial = $headers['wechatpay-serial']; // 应答heade中对应数据:应答平台证书序列号 $inWechatpayNonce = $headers['wechatpay-nonce']; // 应答heade中对应数据:应答随机字符串 $inBody = file_get_contents('php://input'); // 应答主体:请根据实际情况获取,例如: file_get_contents('php://input'); $apiv3Key = self::APIV3_KEY; // 在商户平台上设置的APIv3密钥 // 根据通知的平台证书序列号,查询本地平台证书文件, $platformPublicKeyInstance = Rsa::from('file://' . ROOT_PATH . '\app\..路径..\wxpay_cert\wechatpay_1234563.pem', Rsa::KEY_TYPE_PUBLIC); // 检查通知时间偏移量,允许5分钟之内的偏移 $timeOffsetStatus = 300 >= abs(Formatter::timestamp() - (int)$inWechatpayTimestamp); $verifiedStatus = Rsa::verify( // 构造验签名串 Formatter::joinedByLineFeed($inWechatpayTimestamp, $inWechatpayNonce, $inBody), $inWechatpaySignature, $platformPublicKeyInstance ); if ($timeOffsetStatus && $verifiedStatus) { // 转换通知的JSON文本消息为PHP Array数组 $inBodyArray = (array)json_decode($inBody, true); // 使用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); // print_r($inBodyResourceArray); // 打印解密后的结果 $out_trade_no = $inBodyResourceArray['out_trade_no']; $trade_state = $inBodyResourceArray['trade_state']; $total = $inBodyResourceArray['amount']['total']; if (Db::name('记录表')->where('out_trade_no', $out_trade_no)->find()) { http_response_code(200); $data = [ 'code' => 'SUCCESS', 'message' => '成功' ]; return json_encode($data); } else { //订单处理业务 http_response_code(200); $data = [ 'code' => 'SUCCESS', 'message' => '成功' ]; return json_encode($data); } } else { // 调用微信查询订单API } }}
来源地址:https://blog.csdn.net/arlene12345/article/details/130883343
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341