iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > PHP编程 >PHP 实现微信支付 JSAPI
  • 724
分享到

PHP 实现微信支付 JSAPI

php微信微信公众平台 2023-09-12 18:09:44 724人浏览 独家记忆
摘要

目录 一、首先我们来填个坑 1:支付验签失败 二、代码示例 1.请求参数配置 2.统一下单API 3.MakeSign 签名 4.ToXml 数组参数转xml 5.postXmlCurl 发送请求 6.FromXml 结果xml参数转数组

目录

一、首先我们来填个坑

1:支付验签失败

二、代码示例

1.请求参数配置

2.统一下单API

3.MakeSign 签名

4.ToXml 数组参数转xml

5.postXmlCurl 发送请求

6.FromXml 结果xml参数转数组

总结


一、首先我们来填个坑

1:支付验签失败

这个问题折磨了我两天,官方文档比较含糊不清。各种百度下来的方法试过之后也不尽人意,最后发现问题是没有二次签名

二次签名需要参数(代码会展示在哪里二次签名):

appId:        商户申请的公众号对应的appid(I大写)

nonceStr:   随机字符串(注意是jsapi下单接口中返回的 nonce_str、不是重新生成)

package:    统一下单接口返回的prepay_id参数值 ,(注意格式prepay_id=wx.....)

signType:   签名类型、(官方文档)仅支持RSA。

                (我的签名类型是 HMac-SHA256 也是可以的,必须和下单使用的签名类型保持一致)

timeStamp:时间戳(这里要把 time() 转成字符串类型)

注明:使用这五个参数生成的 paySign 签名才是需要返给前端的(

官方文档实例要计算签名也给我整的蒙圈,最后发现直接将五个必须参数生成的签名返给前端就可以直接调取API了

二、代码示例

1.控制层

$oInput    = ['body'         => '测试商品',          // 商品说明                    'attach'       => '测试场景',          // 自定义参数:可以用来做回调后场景区分                 'out_trade_no' => '测试单号' . time(), // 自定义订单号           'total_fee'    => 1 * 100,           // 付款金额:记得*100 微信官方是以分为单位               'goods_tag'    => '',                // 优惠券相关参数       'notify_url'   => 'http://...',     // 回调通知地址'trade_type'   => 'JSAPI',          // 支付方式            'openid'       => $openid,          // 付款用户openid           ];$res = $this->unifiedOrder($oInput);     // 这里我调用的统一下单return $res; // 返给前端带APPID等参数给前端去调用支付

2.微信服务层

const SSLCERT_PATH = 'Cert证书路径';    const SSLKEY_PATH  = 'Key证书路径';    const MCHID        = '商户号';    const APPID        = 'APPID';    const KEY          = '商户支付密钥(必须配置,登录商户平台自行设置)';        public function unifiedOrder($inputObj, $timeOut = 6){$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";// 首次签名参数$oValues = ['body' => $inputObj['body'],// 设置商品或支付单简要描述'attach' => $inputObj['attach'],// 设置附加数据,用于商户携带订单的自定义数据'out_trade_no' => $inputObj['out_trade_no'], // 设置商户系统内部的订单号,transaction_id、out_trade_no二选一,如果同时存在优先级:transaction_id> out_trade_no'total_fee' => $inputObj['total_fee'], // 设置订单总金额,只能为整数,单位:分'time_start' => date("YmdHis"), // 设置订单生成时间'time_expire' => date("YmdHis", time() + 600), // 设置订单失效时间'goods_tag' => $inputObj['goods_tag'], // 设置商品标记,代金券或立减优惠功能的参数'notify_url' => $inputObj['notify_url'], // 获取接收微信支付异步通知回调地址的值'trade_type' => $inputObj['trade_type'], // JSAPI,NATIVE,APP'openid' => $inputObj['openid'], // 用户在商户appid下的唯一标识'appid' => self::APPID,         // 顶部定义'mch_id' => self::MCHID,         // 顶部定义'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], // 终端ip'nonce_str' => $this->getNonceStr(), // 随机32位字符串'sign_type' => 'HMAC-SHA256', // 签名类型,自行替换];// 首次签名ksort($oValues);$oValues['sign'] = $this->MakeSign($oValues); // 调用签名$xml = $this->ToXml($oValues);                      // 数字转xml类型$response = self::postXmlCurl($xml, $url, false, $timeOut); // 请求$result   = $this->FromXml($response);              // 请求结果从xml转成数组类型        // 二次签名参数$oResult    = ['appId'     => $result['appid'],                   // 首次请求中的appid'nonceStr'  => $result['nonce_str'],               // 首次请求中的nonce_str'package'   => 'prepay_id=' . $result['prepay_id'],// 首次请求中的prepay_id'signType'  => 'HMAC-SHA256',   // 跟首次签名中的签名类型参数保持一致'timeStamp' => (string)(time()),// 时间戳转字符串类型];        // 二次签名$oResult['paySign'] = $this->MakeSign($oResult);    // 调用签名$result = json_encode($oResult); // encode数组return $result;                  // 直接返回}public function MakeSign($values, $needSignType = true){if ($needSignType) {$sSignType = 'HMAC-SHA256'; // 可以在文档开头用枚举定义: 所有签名类型必须一致}$sKey = self:KEY;             // KEY:商户支付密钥(必须配置,登录商户平台自行设置)// 签名步骤一:按字典序排序参数ksort($values);$string = $this->ToUrlParams($values);// 签名步骤二:在string后加入KEY$string = $string . "&key=" . $sKey;// 签名步骤三:MD5加密或者HMAC-SHA256if ($sSignType == "MD5") {$string = md5($string);} else if ($sSignType == "HMAC-SHA256") {$string = hash_hmac("sha256", $string, $sKey);} else {return "签名类型不支持!";}// 签名步骤四:所有字符转为大写$result = strtoupper($string);return $result;}        public function ToXml($values){if (!is_array($values) || count($values) <= 0) {return "数组数据异常!";}$xml = "";foreach ($values as $key => $val) {if (is_numeric($val)) {$xml .= "<" . $key . ">" . $val . "";} else {$xml .= "<" . $key . ">";}}$xml .= "";return $xml;}private function postXmlCurl($xml, $url, $useCert = false, $second = 30){$ch = curl_init();$curlVersion = curl_version();$ua = "WXPaySDK/" . self::VERSION . " (" . PHP_OS . ") php/" . PHP_VERSION . " CURL/" . $curlVersion['version'] . " " . $aWxpayParam['mchid'];//设置超时curl_setopt($ch, CURLOPT_TIMEOUT, $second);$proxyHost = "0.0.0.0";$proxyPort = 0;// 如果有配置代理这里就设置代理if ($proxyHost != "0.0.0.0" && $proxyPort != 0) {curl_setopt($ch, CURLOPT_PROXY, $proxyHost);curl_setopt($ch, CURLOPT_PROXYPORT, $proxyPort);}curl_setopt($ch, CURLOPT_URL, $url);// curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);// curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验curl_setopt($ch, CURLOPT_USERAGENT, $ua);// 设置headercurl_setopt($ch, CURLOPT_HEADER, FALSE);// 要求结果为字符串且输出到屏幕上curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);if ($useCert == true) {// 设置证书// 使用证书:cert 与 key 分别属于两个.pem文件// 证书文件请放入服务器的非WEB目录下$sslCertPath = self::SSLCERT_PATH ;    // Cert证书路径:文档顶部自定义参数名$sslKeyPath = self::SSLKEY_PATH  ;    // Key证书路径:文档顶部自定义参数名curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');curl_setopt($ch, CURLOPT_SSLCERT, $sslCertPath);curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');curl_setopt($ch, CURLOPT_SSLKEY, $sslKeyPath);}// post提交方式curl_setopt($ch, CURLOPT_POST, TRUE);curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);// 运行curl$data = curl_exec($ch);// 返回结果if ($data) {curl_close($ch);return $data;} else {$error = curl_errno($ch);curl_close($ch);throw new WxPayException("curl出错,错误码:$error");}}public function FromXml($xml){if (!$xml) {return "xml数据异常!";}//将XML转为array//禁止引用外部xml实体libxml_disable_entity_loader(true);$res = JSON_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);return $res;}public function getNonceStr($length = 32){$chars = "abcdefghijklmnopqrstuvwxyz0123456789";$str = "";for ($i = 0; $i < $length; $i++) {$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);}return $str;}public function ToUrlParams($urlObj){$buff = "";foreach ($urlObj as $k => $v) {if ($k != "sign" && $v != "" && !is_array($v)) {$buff .= $k . "=" . $v . "&";}}$buff = trim($buff, "&");return $buff;}

来源地址:https://blog.csdn.net/arlene12345/article/details/127831004

--结束END--

本文标题: PHP 实现微信支付 JSAPI

本文链接: https://www.lsjlt.com/news/404950.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作