不知不觉微信支付也更新了,接口版本也升级到了V3,跟着微信的升级,将个人使用微信支付类也进行了升级,V3微信支付文档:https://pay.weixin.qq.com/wiki/doc/apiv3/index.shtml。
使用方法还和之前的一样(V2微信支付),直接传递参数就可使用:
新版新增了composer
安装,便于集成框架使用(Github地址):
composer require fengkui/pay
首先把配置文件填写完整(细心不要填错,否则会导致签名错误):
# 微信支付配置 $wechatCOnfig= [ 'xcxid' => '', // 小程序 appid 'appid' => '', // 微信支付 appid 'mchid' => '', // 微信支付 mch_id 商户收款账号 'key' => '', // 微信支付 apiV3key(尽量包含大小写字母,否则验签不通过) 'appsecret' => '', // 公众帐号 secert (公众号支付获取 code 和 openid 使用) 'notify_url' => '', // 接收支付状态的连接 改成自己的回调地址 'redirect_url' => '', // 公众号支付,调起支付页面 'serial_no' => '', // 证书序列号 'cert_client' => './cert/apiclient_cert.pem', // 证书(退款,红包时使用) 'cert_key' => './cert/apiclient_key.pem', // 商户私钥(Api安全中下载) 'public_key' => './cert/public_key.pem', // 平台公钥(调动证书列表,自动生成) ];
支付类封装相关方法:
method | 描述 |
---|---|
js | JSAPI下单 |
app | APP支付 |
h5 | H5支付 |
scan | Navicat支付 |
xcx | 小程序支付 |
query | 查询订单 |
close | 关闭订单 |
refund | 申请退款 |
notify | 支付结果通知 |
使用方法(这里已小程序支付为示例):
time(), // 订单编号 'total_amount' => 1, // 订单金额(分) 'body' => '测试商品', // 商品名称 'openid' => '', // 用户openid // 'type' => 'Wap', ]; $wechat = new fengkuiPayWechat($config); $re = $wechat->xcx($order); die(json_encode($re)); // JSON化直接返回小程序客户端
如下代码是封装好的完整支付类文件(Wechat.php),
可以根据自己需求随意修改,详细的使用方法后期会有文档:
* @Date: 2019-09-06 09:50:30 * @Last Modified by: [FENG] <1161634940@qq.com> * @Last Modified time: 2021-07-12 18:24:18 */ namespace fengkuiPay; use Exception; use RuntimeException; use fengkuiSupportsHttp; /** * Wechat 微信支付 * 新版(V3)接口(更新中) */ class Wechat { const AUTH_TAG_LENGTH_BYTE = 16; // 新版相关接口 // GET 获取平台证书列表 private static $certificatesUrl = &#39;https://api.mch.weixin.qq.com/v3/certificates&#39;; // 统一下订单管理 private static $transactiOnsUrl= &#39;https://api.mch.weixin.qq.com/v3/pay/transactions/&#39;; // 申请退款 private static $refundUrl = &#39;https://api.mch.weixin.qq.com/v3/refund/domestic/refunds&#39;; // 静默授权,获取code private static $authorizeUrl = &#39;https://open.weixin.qq.com/connect/oauth2/authorize&#39;; // 通过code获取access_token以及openid private static $accessTokenUrl = &#39;https://api.weixin.qq.com/sns/oauth2/access_token&#39;; // 支付完整配置 private static $cOnfig= array( &#39;xcxid&#39; => &#39;&#39;, // 小程序appid &#39;appid&#39; => &#39;&#39;, // 微信支付appid &#39;mchid&#39; => &#39;&#39;, // 微信支付 mch_id 商户收款账号 &#39;key&#39; => &#39;&#39;, // 微信支付 apiV3key(尽量包含大小写字母,否则验签不通过) &#39;appsecret&#39; => &#39;&#39;, // 公众帐号 secert (公众号支付获取code 和 openid使用) &#39;notify_url&#39; => &#39;&#39;, // 接收支付状态的连接 改成自己的回调地址 &#39;redirect_url&#39; => &#39;&#39;, // 公众号支付,调起支付页面 &#39;serial_no&#39; => &#39;&#39;, // 证书序列号 &#39;cert_client&#39; => &#39;./cert/apiclient_cert.pem&#39;, // 证书(退款,红包时使用) &#39;cert_key&#39; => &#39;./cert/apiclient_key.pem&#39;, // 商户私钥(Api安全中下载) &#39;public_key&#39; => &#39;./cert/public_key.pem&#39;, // 平台公钥(调动证书列表,自动生成) ); /** * [__construct 构造函数] * @param [type] $config [传递微信支付相关配置] */ public function __construct($cOnfig=NULL, $referer=NULL){ $config && self::$cOnfig= array_merge(self::$config, $config); } /** * [unifiedOrder 统一下单] * @param [type] $order [订单信息(必须包含支付所需要的参数)] * @param boolean $type [区分是否是小程序,是则传 true] * @return [type] [description] * $order = array( * &#39;body&#39; => &#39;&#39;, // 产品描述 * &#39;order_sn&#39; => &#39;&#39;, // 订单编号 * &#39;total_amount&#39; => &#39;&#39;, // 订单金额(分) * ); */ public static function unifiedOrder($order, $type=false) { $cOnfig= array_filter(self::$config); // 获取配置项 $params = array( &#39;appid&#39; => $type ? $config[&#39;xcxid&#39;] : $config[&#39;appid&#39;], // 由微信生成的应用ID &#39;mchid&#39; => $config[&#39;mchid&#39;], // 直连商户的商户号 &#39;description&#39; => $order[&#39;body&#39;], // 商品描述 &#39;out_trade_no&#39; => (string)$order[&#39;order_sn&#39;], // 商户系统内部订单号 &#39;notify_url&#39; => $config[&#39;notify_url&#39;], // 通知URL必须为直接可访问的URL &#39;amount&#39; => [&#39;total&#39; => (int)$order[&#39;total_amount&#39;], &#39;currency&#39; => &#39;CNY&#39;], // 订单金额信息 ); !empty($order[&#39;attach&#39;]) && $params[&#39;attach&#39;] = $order[&#39;attach&#39;]; // 附加数据 if (!empty($order[&#39;time_expire&#39;])) { // 订单失效时间 preg_match(&#39;/[年/-]/&#39;, $order[&#39;time_expire&#39;]) && $order[&#39;time_expire&#39;] = strtotime($order[&#39;time_expire&#39;]); $time = $order[&#39;time_expire&#39;] > time() ? $order[&#39;time_expire&#39;] : $order[&#39;time_expire&#39;] + time(); $params[&#39;time_expire&#39;] = date(DATE_ATOM, $time); } if (!in_array($order[&#39;type&#39;], [&#39;native&#39;])) { !empty($order[&#39;openid&#39;]) && $params[&#39;payer&#39;] = [&#39;openid&#39; => $order[&#39;openid&#39;]]; $params[&#39;scene_info&#39;] = [&#39;payer_client_ip&#39; => self::get_ip()]; } if (in_array($order[&#39;type&#39;], [&#39;iOS&#39;, &#39;Android&#39;, &#39;Wap&#39;])) { $params[&#39;scene_info&#39;][&#39;h5_info&#39;] = [&#39;type&#39; => $order[&#39;type&#39;]]; $url = self::$transactionsUrl . &#39;h5&#39;; // 拼接请求地址 } else { $url = self::$transactionsUrl . strtolower($order[&#39;type&#39;]); // 拼接请求地址 } $header = self::createAuthorization($url, $params, &#39;POST&#39;); $respOnse= Http::post($url, json_encode($params, JSON_UNESCAPED_UNICODE), $header); $result = json_decode($response, true); if (isset($result[&#39;code&#39;]) && isset($result[&#39;message&#39;])) { throw new Exception("[" . $result[&#39;code&#39;] . "] " . $result[&#39;message&#39;]); } return $result; } /** * [query 查询订单] * @param [type] $orderSn [订单编号] * @param boolean $type [微信支付订单编号,是否是微信支付订单号] * @return [type] [description] */ public static function query($orderSn, $type = false) { $cOnfig= self::$config; $url = self::$transactionsUrl . ($type ? &#39;id/&#39; : &#39;out-trade-no/&#39;) . $orderSn . &#39;?mchid=&#39; . $config[&#39;mchid&#39;]; $params = &#39;&#39;; $header = self::createAuthorization($url, $params, &#39;GET&#39;); $respOnse= Http::get($url, $params, $header); $result = json_decode($response, true); return $result; } /** * [close 关闭订单] * @param [type] $orderSn [微信支付订单编号] * @return [type] [description] */ public static function close($orderSn) { $cOnfig= self::$config; $url = self::$transactionsUrl . &#39;out-trade-no/&#39; . $orderSn . &#39;/close&#39;; $params[&#39;mchid&#39;] = $config[&#39;mchid&#39;]; $header = self::createAuthorization($url, $params, &#39;POST&#39;); $respOnse= Http::post($url, json_encode($params, JSON_UNESCAPED_UNICODE), $header); $result = json_decode($response, true); return true; } /** * [js 获取jssdk需要用到的数据] * @param [type] $order [订单信息数组] * @return [type] [description] */ public static function js($order=[]){ $cOnfig= self::$config; if (!is_array($order) || count($order) <3) die("订单数组信息缺失!"); if (count($order) == 4 && !empty($order[&#39;openid&#39;])) { $data = self::xcx($order, false, false); // 获取支付相关信息(获取非小程序信息) return $data; } $code = !empty($order[&#39;code&#39;]) ? $order[&#39;code&#39;] : ($_GET[&#39;code&#39;] ?? &#39;&#39;); $redirectUri = $_SERVER[&#39;REQUEST_SCHEME&#39;] . &#39;://&#39; . $_SERVER[&#39;HTTP_HOST&#39;] . rtrim($_SERVER[&#39;REQUEST_URI&#39;], &#39;/&#39;) . &#39;/&#39;; // 重定向地址 $params = [&#39;appid&#39; => $config[&#39;appid&#39;]]; // 如果没有get参数没有code;则重定向去获取code; if (empty($code)) { $params[&#39;redirect_uri&#39;] = $redirectUri; // 返回的url $params[&#39;response_type&#39;] = &#39;code&#39;; $params[&#39;scope&#39;] = &#39;snsapi_base&#39;; $params[&#39;state&#39;] = $order[&#39;order_sn&#39;]; // 获取订单号 $url = self::$authorizeUrl . &#39;?&#39;. http_build_query($params) .&#39;#wechat_redirect&#39;; } else { $params[&#39;secret&#39;] = $config[&#39;appsecret&#39;]; $params[&#39;code&#39;] = $code; $params[&#39;grant_type&#39;] = &#39;authorization_code&#39;; $respOnse= Http::get(self::$accessTokenUrl, $params); // 进行GET请求 $result = json_decode($response, true); $order[&#39;openid&#39;] = $result[&#39;openid&#39;]; // 获取到的openid $data = self::xcx($order, false, false); // 获取支付相关信息(获取非小程序信息) if (!empty($order[&#39;code&#39;])) { return $data; } $url = $config[&#39;redirect_url&#39;] ?? $redirectUri; $url .= &#39;?data=&#39; . json_encode($data, JSON_UNESCAPED_UNICODE); } header(&#39;Location: &#39;. $url); die; } /** * [app 获取APP支付需要用到的数据] * @param [type] $order [订单信息数组] * @return [type] [description] */ public static function app($order=[], $log=false) { if(empty($order[&#39;order_sn&#39;]) || empty($order[&#39;total_amount&#39;]) || empty($order[&#39;body&#39;])){ die("订单数组信息缺失!"); } $order[&#39;type&#39;] = &#39;app&#39;; // 获取订单类型,用户拼接请求地址 $result = self::unifiedOrder($order, true); if (!empty($result[&#39;prepay_id&#39;])) { $data = array ( &#39;appId&#39; => self::$config[&#39;appid&#39;], // 微信开放平台审核通过的移动应用appid &#39;timeStamp&#39; => (string)time(), &#39;nonceStr&#39; => self::get_rand_str(32, 0, 1), // 随机32位字符串 &#39;prepayid&#39; => $result[&#39;prepay_id&#39;], ); $data[&#39;paySign&#39;] = self::makeSign($data); $data[&#39;partnerid&#39;] = $config[&#39;mchid&#39;]; $data[&#39;package&#39;] = &#39;Sign=WXPay&#39;; return $data; // 数据小程序客户端 } else { return $log ? $result : false; } } /** * [h5 微信H5支付] * @param [type] $order [订单信息数组] * @return [type] [description] */ public static function h5($order=[], $log=false) { if(empty($order[&#39;order_sn&#39;]) || empty($order[&#39;total_amount&#39;]) || empty($order[&#39;body&#39;]) || empty($order[&#39;type&#39;]) || !in_array(strtolower($order[&#39;type&#39;]), [&#39;ios&#39;, &#39;android&#39;, &#39;wap&#39;])){ die("订单数组信息缺失!"); } $result = self::unifiedOrder($order); if (!empty($result[&#39;h5_url&#39;])) { return $result[&#39;h5_url&#39;]; // 返回链接让用户点击跳转 } else { return $log ? $result : false; } } /** * [xcx 获取jssdk需要用到的数据] * @param [type] $order [订单信息数组] * @param boolean $log [description] * @param boolean $type [区分是否是小程序,默认 true] * @return [type] [description] */ public static function xcx($order=[], $log=false, $type=true) { if(empty($order[&#39;order_sn&#39;]) || empty($order[&#39;total_amount&#39;]) || empty($order[&#39;body&#39;]) || empty($order[&#39;openid&#39;])){ die("订单数组信息缺失!"); } $order[&#39;type&#39;] = &#39;jsapi&#39;; // 获取订单类型,用户拼接请求地址 $cOnfig= self::$config; $result = self::unifiedOrder($order, $type); if (!empty($result[&#39;prepay_id&#39;])) { $data = array ( &#39;appId&#39; => $type ? $config[&#39;xcxid&#39;] : $config[&#39;appid&#39;], // 由微信生成的应用ID &#39;timeStamp&#39; => (string)time(), &#39;nonceStr&#39; => self::get_rand_str(32, 0, 1), // 随机32位字符串 &#39;package&#39; => &#39;prepay_id=&#39;.$result[&#39;prepay_id&#39;], ); $data[&#39;paySign&#39;] = self::makeSign($data); $data[&#39;signType&#39;] = &#39;RSA&#39;; return $data; // 数据小程序客户端 } else { return $log ? $result : false; } } /** * [scan 微信扫码支付] * @param [type] $order [订单信息数组] * @return [type] [description] */ public static function scan($order=[], $log=false) { if(empty($order[&#39;order_sn&#39;]) || empty($order[&#39;total_amount&#39;]) || empty($order[&#39;body&#39;])){ die("订单数组信息缺失!"); } $order[&#39;type&#39;] = &#39;native&#39;; // Native支付 $result = self::unifiedOrder($order); if (!empty($result[&#39;code_url&#39;])) { return urldecode($result[&#39;code_url&#39;]); // 返回链接让用户点击跳转 } else { return $log ? $result : false; } } /** * [notify 回调验证] * @return [array] [返回数组格式的notify数据] */ public static function notify($server = [], $respOnse= []) { $cOnfig= self::$config; $server = $server ?? $_SERVER; $respOnse= $response ?? file_get_contents(&#39;php://input&#39;, &#39;r&#39;); if (empty($response) || empty($server[&#39;HTTP_WECHATPAY_SIGNATURE&#39;])) { return false; } $body = [ &#39;timestamp&#39; => $server[&#39;HTTP_WECHATPAY_TIMESTAMP&#39;], &#39;nonce&#39; => $server[&#39;HTTP_WECHATPAY_NONCE&#39;], &#39;data&#39; => $response, ]; // 验证应答签名 $verifySign = self::verifySign($body, trim($server[&#39;HTTP_WECHATPAY_SIGNATURE&#39;]), trim($server[&#39;HTTP_WECHATPAY_SERIAL&#39;])); if (!$verifySign) { die("签名验证失败!"); } $result = json_decode($response, true); if (empty($result) || $result[&#39;event_type&#39;] != &#39;TRANSACTION.SUCCESS&#39; || $result[&#39;summary&#39;] != &#39;支付成功&#39;) { return false; } // 加密信息 $associatedData = $result[&#39;resource&#39;][&#39;associated_data&#39;]; $nOnceStr= $result[&#39;resource&#39;][&#39;nonce&#39;]; $ciphertext = $result[&#39;resource&#39;][&#39;ciphertext&#39;]; $data = $result[&#39;resource&#39;][&#39;ciphertext&#39;] = self::decryptToString($associatedData, $nonceStr, $ciphertext); return json_decode($data, true); } /** * [refund 微信支付退款] * @param [type] $order [订单信息] * @param [type] $type [是否是小程序] */ public static function refund($order) { $cOnfig= self::$config; if(empty($order[&#39;refund_sn&#39;]) || empty($order[&#39;refund_amount&#39;]) || (empty($order[&#39;order_sn&#39;]) && empty($order[&#39;transaction_id&#39;]))){ die("订单数组信息缺失!"); } $params = array( &#39;out_refund_no&#39; => (string)$order[&#39;refund_sn&#39;], // 商户退款单号 &#39;funds_account&#39; => &#39;AVAILABLE&#39;, // 退款资金来源 &#39;amount&#39; => [ &#39;refund&#39; => $order[&#39;refund_amount&#39;], &#39;currency&#39; => &#39;CNY&#39;, ] ); if (!empty($order[&#39;transaction_id&#39;])) { $params[&#39;transaction_id&#39;] = $order[&#39;transaction_id&#39;]; $orderDetail = self::query($order[&#39;transaction_id&#39;], true); } else { $params[&#39;out_trade_no&#39;] = $order[&#39;order_sn&#39;]; $orderDetail = self::query($order[&#39;order_sn&#39;]); } $params[&#39;amount&#39;][&#39;total&#39;] = $orderDetail[&#39;amount&#39;][&#39;total&#39;]; !empty($order[&#39;reason&#39;]) && $params[&#39;reason&#39;] = $order[&#39;reason&#39;]; $url = self::$refundUrl; $header = self::createAuthorization($url, $params, &#39;POST&#39;); $respOnse= Http::post($url, json_encode($params, JSON_UNESCAPED_UNICODE), $header); $result = json_decode($response, true); return $result; } /** * [queryRefund 查询退款] * @param [type] $refundSn [退款单号] * @return [type] [description] */ public static function queryRefund($refundSn, $type = false) { $url = self::$refundUrl . &#39;/&#39; . $refundSn; $params = &#39;&#39;; $header = self::createAuthorization($url, $params, &#39;GET&#39;); $respOnse= Http::get($url, $params, $header); $result = json_decode($response, true); return $result; } /** * [success 通知支付状态] */ public static function success() { $str = [&#39;code&#39;=>&#39;SUCCESS&#39;, &#39;message&#39;=>&#39;成功&#39;]; die(json_encode($str, JSON_UNESCAPED_UNICODE)); } /** * [createAuthorization 获取接口授权header头信息] * @param [type] $url [请求地址] * @param array $data [请求参数] * @param string $method [请求方式] * @return [type] [description] */ //生成v3 Authorization protected static function createAuthorization($url, $data=[], $method=&#39;POST&#39;){ $cOnfig= self::$config; //商户号 $mchid = $config[&#39;mchid&#39;]; // 证书序列号 if (empty($config[&#39;serial_no&#39;])) { $certFile = @file_get_contents($config[&#39;cert_client&#39;]); $certArr = openssl_x509_parse($publicStr); $serial_no = $certArr[&#39;serialNumberHex&#39;]; } else { $serial_no = $config[&#39;serial_no&#39;]; } // 解析url地址 $url_parts = parse_url($url); //生成签名 $body = [ &#39;method&#39; => $method, &#39;url&#39; => ($url_parts[&#39;path&#39;] . (!empty($url_parts[&#39;query&#39;]) ? "?${url_parts[&#39;query&#39;]}" : "")), &#39;time&#39; => time(), // 当前时间戳 &#39;nonce&#39; => self::get_rand_str(32, 0, 1), // 随机32位字符串 &#39;data&#39; => (strtolower($method) == &#39;post&#39; ? json_encode($data, JSON_UNESCAPED_UNICODE) : $data), // POST请求时 需要 转JSON字符串 ]; $sign = self::makeSign($body); //Authorization 类型 $schema = &#39;WECHATPAY2-SHA256-RSA2048&#39;; //生成token $token = sprintf(&#39;mchid="%s",nonce_str="%s",timestamp="%d",serial_no="%s",signature="%s"&#39;, $mchid, $body[&#39;nonce&#39;], $body[&#39;time&#39;], $serial_no, $sign); $header = [ &#39;Content-Type:application/json&#39;, &#39;Accept:application/json&#39;, &#39;User-Agent:*/*&#39;, &#39;Authorization: &#39;. $schema . &#39; &#39; . $token ]; return $header; } /** * [makeSign 生成签名] * @param [type] $data [加密数据] * @return [type] [description] */ public static function makeSign($data) { $cOnfig= self::$config; if (!in_array(&#39;sha256WithRSAEncryption&#39;, openssl_get_md_methods(true))) { throw new RuntimeException("当前PHP环境不支持SHA256withRSA"); } // 拼接生成签名所需的字符串 $message = &#39;&#39;; foreach ($data as $value) { $message .= $value . " "; } // 商户私钥 $private_key = self::getPrivateKey($config[&#39;cert_key&#39;]); // 生成签名 openssl_sign($message, $sign, $private_key, &#39;sha256WithRSAEncryption&#39;); $sign = base64_encode($sign); return $sign; } /** * [verifySign 验证签名] * @param [type] $data [description] * @param [type] $sign [description] * @param [type] $serial [description] * @return [type] [description] */ public static function verifySign($data, $sign, $serial) { $cOnfig= self::$config; if (!in_array(&#39;sha256WithRSAEncryption&#39;, openssl_get_md_methods(true))) { throw new RuntimeException("当前PHP环境不支持SHA256withRSA"); } $sign = ase64_decode($sign); // 拼接生成签名所需的字符串 $message = &#39;&#39;; foreach ($data as $value) { $message .= $value . " "; } // 获取证书相关信息 self::certificates($serial); // 平台公钥 $public_key = self::getPublicKey($config[&#39;public_key&#39;]); //平台公钥 // 验证签名 $recode = openssl_verify($message, $sign, $public_key, &#39;sha256WithRSAEncryption&#39;); return $recode == 1 ? true : false; } //获取私钥 public static function getPrivateKey($filepath) { return openssl_pkey_get_private(file_get_contents($filepath)); } //获取公钥 public static function getPublicKey($filepath) { return openssl_pkey_get_public(file_get_contents($filepath)); } /** * [certificates 获取证书] * @return [type] [description] */ public static function certificates($serial) { $cOnfig= self::$config; $publicStr = @file_get_contents($config[&#39;public_key&#39;]); if ($publicStr) { // 判断证书是否存在 $openssl = openssl_x509_parse($publicStr); if ($openssl[&#39;serialNumberHex&#39;] == $serial) { // 是否是所需证书 // return self::getPublicKey($config[&#39;public_key&#39;]); //平台公钥 return &#39;&#39;; } } $url = self::$certificatesUrl; $params = &#39;&#39;; $header = self::createAuthorization($url, $params, &#39;GET&#39;); $respOnse= Http::get($url, $params, $header); $result = json_decode($response, true); if (empty($result[&#39;data&#39;])) { throw new RuntimeException("[" . $result[&#39;code&#39;] . "] " . $result[&#39;message&#39;]); } foreach ($result[&#39;data&#39;] as $key => $certificate) { if ($certificate[&#39;serial_no&#39;] == $serial) { $publicKey = self::decryptToString( $certificate[&#39;encrypt_certificate&#39;][&#39;associated_data&#39;], $certificate[&#39;encrypt_certificate&#39;][&#39;nonce&#39;], $certificate[&#39;encrypt_certificate&#39;][&#39;ciphertext&#39;] ); file_put_contents($config[&#39;public_key&#39;], $publicKey); break; // 终止循环 } // self::$publicKey[$certificate[&#39;serial_no&#39;]] = $publicKey; } // return self::getPublicKey($config[&#39;public_key&#39;]); //平台公钥 } /** * [decryptToString 证书和回调报文解密] * @param [type] $associatedData [附加数据包(可能为空)] * @param [type] $nonceStr [加密使用的随机串初始化向量] * @param [type] $ciphertext [Base64编码后的密文] * @return [type] [description] */ public static function decryptToString($associatedData, $nonceStr, $ciphertext) { $cOnfig= self::$config; $ciphertext = base64_decode($ciphertext); if (strlen($ciphertext) <= self::AUTH_TAG_LENGTH_BYTE) { return false; } // ext-sodium (default installed on >= PHP 7.2) if (function_exists(&#39;sodium_crypto_aead_aes256gcm_is_available&#39;) && sodium_crypto_aead_aes256gcm_is_available()) { return sodium_crypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $config[&#39;key&#39;]); } // ext-libsodium (need install libsodium-php 1.x via pecl) if (function_exists(&#39;Sodiumcrypto_aead_aes256gcm_is_available&#39;) && Sodiumcrypto_aead_aes256gcm_is_available()) { return Sodiumcrypto_aead_aes256gcm_decrypt($ciphertext, $associatedData, $nonceStr, $config[&#39;key&#39;]); } // openssl (PHP >= 7.1 support AEAD) if (PHP_VERSION_ID >= 70100 && in_array(&#39;aes-256-gcm&#39;, openssl_get_cipher_methods())) { $ctext = substr($ciphertext, 0, -self::AUTH_TAG_LENGTH_BYTE); $authTag = substr($ciphertext, -self::AUTH_TAG_LENGTH_BYTE); return openssl_decrypt($ctext, &#39;aes-256-gcm&#39;, $config[&#39;key&#39;], OPENSSL_RAW_DATA, $nonceStr, $authTag, $associatedData); } throw new RuntimeException(&#39;AEAD_AES_256_GCM需要PHP 7.1以上或者安装libsodium-php&#39;); } /** fengkui.net * [get_rand_str 获取随机字符串] * @param integer $randLength [长度] * @param integer $addtime [是否加入当前时间戳] * @param integer $includenumber [是否包含数字] * @return [type] [description] */ public static function get_rand_str($randLength=6, $addtime=0, $includenumber=1) { if ($includenumber) $chars=&#39;abcdefghijklmnopqrstuvwxyzABCDEFGHJKLMNPQEST123456789&#39;; $chars=&#39;abcdefghijklmnopqrstuvwxyz&#39;; $len = strlen($chars); $randStr = &#39;&#39;; for ($i=0; $i<$randLength; $i++){ $randStr .= $chars[rand(0, $len-1)]; } $tokenvalue = $randStr; $addtime && $tokenvalue = $randStr . time(); return $tokenvalue; } /** fengkui.net * [get_ip 定义一个函数get_ip() 客户端IP] * @return [type] [description] */ public static function get_ip() { if (getenv("HTTP_CLIENT_IP")) $ip = getenv("HTTP_CLIENT_IP"); else if(getenv("HTTP_X_FORWARDED_FOR")) $ip = getenv("HTTP_X_FORWARDED_FOR"); else if(getenv("REMOTE_ADDR")) $ip = getenv("REMOTE_ADDR"); else $ip = "Unknow"; if(preg_match(&#39;/^((?:(?:25[0-5]|2[0-4]d|((1d{2})|([1-9]?d))).){3}(?:25[0-5]|2[0-4]d|((1d{2})|([1 -9]?d))))$/&#39;, $ip)) return $ip; else return &#39;&#39;; } }
本文参考文档:
1、微信支付 小程序 (v3)- PHP 完整后端代码
2、PHP 微信小程序 微信支付 v3
3、微信支付V3版本小程序支付 php签名,验签,数据解密代码分享(完整方法主参考)
4、微信支付 API v3 回调通知 签名验证 PHPdemo有嘛?
推荐:《PHP视频教程》