【PHP】PHP接入微信官方支付(native·APIv3)
CrazyPanda发表于:2023-12-01 21:51:12浏览:1271次
一、项目介绍
两个文件实现微信官方支付(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滑动验证码的实现原理。一、滑动验证码的定义与应用滑动验证码是一种人机交互的验证码形式,它的基本原理是在界面上展示一张包含某些图片或图形的滑块,用户需要按住滑块进行拖动,直到把滑块拼接到验证码图形相应位置,以此进行验证。该类型的验证码多用于广告、登录、注册和评论等需要用户身份识别的场景。二、php滑动验证码的实现原理ph
- 【PHP】PHP Websocket开发指南,实现实时交通信息查询功能
- PHP Websocket开发指南,实现实时交通信息查询功能前言Websocket是一种在Web上实现双向通信的技术,它能够实现实时更新数据,适用于需要实时交互的场景。本篇文章将介绍如何使用PHP开发一个实时交通信息查询的功能,并提供相应的代码示例。准备工作在开始开发之前,需要准备以下工作:一台安装了PHP和Apache服务器的主机,具备基础的PHP编程知识一个支持Websocket的浏览器,如Chrome、Firefox等安装Composer,用于安装相关依赖库开始开发3.1 安装W
- 【PHP】在vscode中要用php需安装什么
- 在Vscode中使用Php需安装什么?随着Php的使用范围逐渐扩大,越来越多的人开始在Vscode中使用Php进行开发。但是,要在Vscode中使用Php需要安装一些必要的扩展和插件。本篇文章将为大家讲解在Vscode中使用Php需要安装的扩展和插件。PHP Extension PackPHP Extension Pack是由Microsoft开发的一个扩展包,其中包括了一些必要的Php扩展,比如Php Debug、Php IntelliSense、Php DocBlocker等。使用
- 【PHP】linux系统php怎么安装curl扩展
- 有时候安装好php后,后面需要一些扩展需要添加进来,又不能影响当前php的工作,我们就只能通过动态添加扩展来实现。php安装curl扩展的方法:一.首先明确一些目录1.源码包目录,就是放从网上下载的源码包文件的目录,里面有下载的php,mysql,http等源码例如:/usr/local/src/ 2.PHP扩展包路径,就是PHP用来支持扩展服务的软件包,一般在php源码包的ext目录例如:/usr/local/src/php-7.0.12/ext/二. 开始动手安装1.安装curl
- 【PHP】Composer配置中国全量镜像
- 查看当前的镜像源:composer config -g -l repo.packagist切换国内镜像阿里云 composer config -g repos.packagist composer https://mirrors.aliyun.com/composer/腾讯云 composer config -g repos.packagist composer https://mirrors.c
- 【PHP】Composer创建一个library
- 1、首先创建一个空的项目文件夹mkdir mylibrary & cd mylibrary2、执行composer命令//开始创建composer 包 sh-4.2# composer init &nbs
- 【PHP】PHP 框架中大型项目代码维护挑战与解决方法
- 在大型 php 项目中,代码维护面临主要挑战,包括依赖管理、代码重构、代码风格和文档。解决方法包括:使用依赖项管理器管理版本冲突。使用unittest框架在重构时保持代码完整性。建立并强制执行代码风格指南。建立文档策略并使用phpdoc生成文档。PHP 框架中大型项目代码维护挑战与解决方法在大型 PHP 项目中,代码维护可能是一个艰巨的任务。随着项目规模的增长,代码库会变得庞大且复杂,从而难以管理和更新。以下是 PHP 框架中代码维护面临的主要挑战以及解决这些挑战的一些方法:挑战 1:依赖管理依
- 【PHP】php在数组后面增加一列
- 在 PHP 中,要在数组后面增加一列,我们可以采用 array_push() 函数或直接赋值的方式来实现。下面我们来介绍一下这两种方法。方法一:使用 array_push() 函数array_push() 函数可将一个或多个元素添加到数组末尾,我们可以利用此函数在数组后面增加一列。具体实现的方式如下:<?php // 定义一个数组 $oldArr = array( array('name&#39
栏目分类全部>