【PHP】PHP接入微信官方支付(native·APIv3)
CrazyPanda发表于:2023-12-01 21:51:12浏览:1293次
一、项目介绍
两个文件实现微信官方支付(native·APIv3)的发起支付和回调应答功能
二、准备资料
商户号:需要使用到营业执照注册商户
appid:小程序或者订阅号的appid
APIv3秘钥:32位秘钥,APIv2秘钥为16位,不要混淆
证书序号:apiclient_key.pem文件中的秘钥,需要将该文件改为txt后缀,然后获取其中的秘钥
三、支付代码
1.index.php文件
<?php //支付配置 $mchid = '';//微信支付商户号 PartnerID $appid = '';//公众号APPID $apiKey = '';//APIv3密钥 $serialNumber = ''; //证书序列号 $privateKey = ''; //apiclient_key.pem的文件内容,可以先将后缀名改为txt,然后获取里面内容//商品信息,可以由前端获取 $payAmount = ''; //付款金额,单位:元 $orderName = ''; //订单标题//默认配置 $outTradeNo = date('YmdHis').uniqid(); //订单号,采用时间加微秒计ID $notifyUrl = 'https://***/notify.php'; //付款成功后的通知地址,需要用https协议//这里可以填写预下单业务逻辑//发起支付 $wxPay = new IndexService($mchid, $appid, $apiKey,$privateKey,$serialNumber); $wxPay->setTotalFee($payAmount); $wxPay->setOutTradeNo($outTradeNo); $wxPay->setOrderName($orderName); $wxPay->setNotifyUrl($notifyUrl); $result = $wxPay->doPay(); $url = 'https://wenhairu.com/static/api/qr/?size=300&text=' . $result['code_url']; echo "<img src='{$url}' style='width:100px;'><br>";echo '二维码内容:' . $result['code_url']; //IndexService类 class IndexService { protected $mchid; protected $appid; protected $apiKey; protected $privateKey; protected $serialNumber; protected $totalFee; protected $outTradeNo; protected $orderName; protected $notifyUrl; protected $auth; protected $gateWay='https://api.mch.weixin.qq.com/v3'; public function __construct($mchid, $appid, $apikey, $privateKey, $serialNumber) { $this->mchid = $mchid; $this->appid = $appid; $this->apiKey = $apikey; $this->privateKey = $privateKey; $this->serialNumber = $serialNumber; } public function setTotalFee($totalFee) { $this->totalFee = floatval($totalFee); } public function setOutTradeNo($outTradeNo) { $this->outTradeNo = $outTradeNo; } public function setOrderName($orderName) { $this->orderName = $orderName; } public function setNotifyUrl($notifyUrl) { $this->notifyUrl = $notifyUrl; } /** * 发起支付 */ public function doPay() { $reqParams = array( 'appid' => $this->appid, //公众号或移动应用appid 'mchid' => $this->mchid, //商户号 'description' => $this->orderName, //商品描述 'attach' => 'pay', //附加数据,在查询API和支付通知中原样返回,可作为自定义参数使用 'notify_url' => $this->notifyUrl, //通知URL必须为直接可访问的URL,不允许携带查询串。 'out_trade_no' => $this->outTradeNo, //商户系统内部订单号,只能是数字、大小写字母_-*且在同一个商户号下唯一,详见【商户订单号】。特殊规则:最小字符长度为6 'amount'=>array( 'total'=> floatval($this->totalFee) * 100, //订单总金额,单位为分 'currency'=> 'CNY', //CNY:人民币,境内商户号仅支持人民币 ), 'scene_info'=>array( //支付场景描述 'payer_client_ip'=>'127.0.0.1' //调用微信支付API的机器IP ) ); $reqUrl = $this->gateWay.'/pay/transactions/native'; $this->getAuthStr($reqUrl,$reqParams); $response = $this->curlPost($reqUrl,$reqParams); return json_decode($response,true); } public function curlPost($url = '', $postData = array(), $options = array()) { if (is_array($postData)) { $postData = json_encode($postData); } $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt($ch, CURLOPT_HTTPHEADER, array( 'Authorization:'.$this->auth, 'Content-Type:application/json', 'Accept:application/json', 'User-Agent:'.$_SERVER['HTTP_USER_AGENT'] ) ); curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数 if (!empty($options)) { curl_setopt_array($ch, $options); } //https请求 不验证证书和host curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($ch); curl_close($ch); return $data; } private function getSchema(): string { return 'WECHATPAY2-SHA256-RSA2048'; } public function getAuthStr($requestUrl,$reqParams=array()): string { $schema = $this->getSchema(); $token = $this->getToken($requestUrl,$reqParams); $this->auth = $schema.' '.$token;return $this->auth; } private function getNonce() { static $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; $charactersLength = strlen($characters); $randomString = ''; for ($i = 0; $i < 32; $i++) { $randomString .= $characters[rand(0, $charactersLength - 1)]; } return $randomString; } public function getToken($requestUrl,$reqParams=array()): string { $body = $reqParams ? json_encode($reqParams) : ''; $nonce = $this->getNonce(); $timestamp = time(); $message = $this->buildMessage($nonce, $timestamp, $requestUrl,$body); $sign = $this->sign($message); $serialNo = $this->serialNumber; return sprintf('mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"',$this->mchid, $nonce, $timestamp, $serialNo, $sign); } private function buildMessage($nonce, $timestamp, $requestUrl, $body = ''): string { $method = 'POST'; $urlParts = parse_url($requestUrl); $canonicalUrl = ($urlParts['path'] . (!empty($urlParts['query']) ? "?{$urlParts['query']}" : "")); return strtoupper($method) . "\n" .$canonicalUrl . "\n" .$timestamp . "\n" .$nonce . "\n" .$body . "\n"; } private function sign($message): string { if (!in_array('sha256WithRSAEncryption', openssl_get_md_methods(true))) { throw new \RuntimeException("当前PHP环境不支持SHA256withRSA"); } $res = $this->privateKey; if (!openssl_sign($message, $sign, $res, 'sha256WithRSAEncryption')) { throw new \UnexpectedValueException("签名验证过程发生了错误"); } return base64_encode($sign); } }
说明:
该微信支付属于native的APIv3版本,需要用到商户证书的相关内内容,不要和微信的其他支付方式或者APIv2相混淆
index.php中的支付成功通知地址需要用https协议,该文件内容,下面会给出
仅需要填写IndexService类上边的配置即可,IndexService类的内容不需要修改
2.notify.php
<?php //获取返回json数据 $getCallBackJson = file_get_contents('php://input'); //转化为关联数组 $getCallBackArray = json_decode($getCallBackJson, true); //获取需要解密字段 $associatedData = $getCallBackArray['resource']['associated_data']; $nonceStr = $getCallBackArray['resource']['nonce']; $ciphertext = $getCallBackArray['resource']['ciphertext']; //执行解密 $apiKey = ''; //这里需要填写APIv3秘钥 $getData = new NotifyService($apiKey); $resultJson = $getData->decryptToString($associatedData, $nonceStr, $ciphertext); //解密结果,为关联数组格式$resultArray = json_decode($resultJson, true); //交易成功 if ($resultArray['trade_state'] === 'SUCCESS') { //这里填写交易成功的相关业务,如更新账单状态,其中可能需要用到的参数如下 //$resultArray['out_trade_no'] 商户订单号 //$resultArray['transaction_id'] 订单号 //$resultArray['amount']['total'] 订单金额 } //NotifyService类 class NotifyService { protected $apiKey; const AUTH_TAG_LENGTH_BYTE = 16; public function __construct($apiKey) { $this->apiKey = $apiKey; } /** * Decrypt AEAD_AES_256_GCM ciphertext * * @param string $associatedData AES GCM additional authentication data * @param string $nonceStr AES GCM nonce * @param string $ciphertext AES GCM cipher text * * @return string|bool Decrypted string on success or FALSE on failure */ public function decryptToString(string $associatedData, string $nonceStr, string $ciphertext) { $ciphertext = \base64_decode($ciphertext); if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) { return false; } $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE); $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE); return \openssl_decrypt($ctext, 'aes-256-gcm', $this->apiKey, \OPENSSL_RAW_DATA, $nonceStr,$authTag, $associatedData); } }
注意:
notify.php中需要再次填写你的APIv3秘钥
在交易成功的if语句中,填写最终支付成功的相关业务逻辑
猜你喜欢
- 【PHP】php 判断是否是数组
- 在PHP中,判断一个变量是否是数组可以使用多种方式。以下将介绍四种判断方法:1. is_array()函数is_array()函数是PHP中判断变量是否是数组的最常用方法。该函数接受一个变量作为参数,如果参数是一个数组,则返回true;反之,返回false。下面是一个使用is_array()函数的例子:$arr = array("apple","banana","cherry"); if(is_array(
- 【PHP】ThinkPHP 集成 jwt 技术 token 验证
- ThinkPHP 集成 jwt 技术 token 验证一、思路流程二、安装 firebase/php-jwt三、封装token类四、创建中间件,检验Token校验时效性五、配置路由中间件六、写几个测试方法,通过postman去验证一、思路流程客户端使用用户名和密码请求登录服务端收到请求,验证用户名和密码验证成功后,服务端会签发一个token,再把这个token返回给客户端客户端收到token后可以把它存储起来,比如放到cookie中客户端每次向服务端请求资源时需要携带服务端签发的token,可以
- 【PHP】CI,ThinkPHP,YII,Laravel框架比较
- 用过其中的yii TP CI框架。大概整理了这些框架的优点和缺点,有些错误的地方还希望大家指正。各个框架各有所长,针对的应用场景不同。一、Ci框架推崇简单就是美这一原则,没有花哨的设计模式,没有华丽的对象结构,一切就是那么简单。优点:框架的入门槛很低,极易学,极易用,框架很小,静态化非常容易配置简单,全部的配置使用php脚本来配置,执行效率高缺点:架构略简单,只能满足小型应用,略微不太能够满足中型应用需要大型项目扩展能力差,有些功能需要自己写扩展数据库类的扩展 ci给用户提供了一个名为call_
- 【PHP】9个适用于PHP的最佳自动化测试框架
- 您是否花了很长时间调试您PHP代码? 好吧,对于大多数程序员来说,这可能不是最迷人的挑战,但是有一种解决方案可以帮助我们缩短这项繁琐的任务。 自动化测试通过允许预先编写的测试来驱动开发过程,可以显着改善PHP开发的工作流程 。在这篇文章中,我们将尝试了解为什么自动化测试如此酷 ,它如何工作以及您可以从中开始的最佳测试框架是什么。为什么测试很重要新手PHP开发人员倾向于不为他们的代码编写测试。 我们大多数人的职业生涯都是通过逐一测试刚在浏览器窗口中编写的新特性和功能开始的,当出现问题时,我们一无所
- 【PHP】从零搭建php8环境
- 从零搭建php环境-php8一、下载1、https://www.php.net/distributions/php-8.0.0.tar.gz下载到本地,文件传输上传到 /usr/local/src/2、wget -P /usr/local/src/ https://www.php.net/distributions/php-8.0.0.tar.gz二、解压、编译、安装1、解压缩> cd /usr/local/src/ > tar xzf&nbs
- 【PHP】thinkphp5.1+workman+jsonRpc
- 1.下载jsonRpc包放到vendor目录下 2.启动文件 3.启动效果:启动命令php allserver.php start 4.RpcClient Rpc客户端+RpcClient Rpc服务端 访问:http://localhost/product/public/index/RpcTest/rpctest 报错:stream_socket_client(): unable to connect to tcp://127.0.0.1:2015 (由于目标计算机积极拒绝,无法连接。
- 【PHP】php如何将utf8转gbk编码
- 随着互联网的发展,跨语言交流和国际化成为了越来越普遍的需求。由于不同的编码方式,网站之间的数据传输和处理也变得越来越复杂。在这个过程中,一些老旧的编码方式依然在使用,比如GBK编码。为了兼容各种编码方式,php提供了一些内置函数来进行编码转换,本文将介绍如何将utf8编码转换成GBK编码。一、了解编码首先,我们需要了解utf8和GBK编码分别是什么。utf8是一种可变长度的字符编码,是国际标准化组织ISO的一部分,也是Unicode字符集的一种实现方式。utf8编码可以容纳所有Unic
- 【PHP】PHP 框架在大型项目中微服务的最佳实践
- 微服务在 php 框架中的优点包括模块化、可扩展性和容错性。实战案例展示了使用 laravel 创建微服务架构,包括创建用户、产品和订单微服务。与微服务的集成最佳实践建议使用消息队列实现异步通信、采用 api 网关处理身份验证和流量管理,以及运用 devops 实践简化开发和部署流程。PHP 框架在大型项目中微服务的最佳实践近年来,微服务已成为大型项目架构的流行选择。微服务架构在 PHP 框架中可以带来诸多好处,包括:模块化: 微服务允许您将项目分解成较小的、独立的组件,便于维护和迭代。可扩展性
栏目分类全部>