### [重新对百度支付进行编写封装(百度智能小程序支付)](https://www.prosaas.cn/article/16393) **Published:** 2021-07-17T07:38:44 **Author:** 5201314 **Excerpt:** 最近因为项目重构的原因,对百度支付重新进行了编写封装,本次重写,添加了对签名的处理、添加用户退款,方便之后开发… 最近因为项目重构的原因,对百度支付重新进行了编写封装,本次重写,添加了对签名的处理、添加用户退款,方便之后开发的使用。 因为百度电商开放平台的升级,支付功能已移至智能小程序内部,具体申请流程:百度收银台支付开通指引,(https://smartprogram.baidu.com/docs/operations/transform/pay/) (注:在支付服务中,服务电话应填写银行预留手机号,如填写错误报【银行预留手机号码格式校验不通过】) 百度支付文档:百度收银台接口2.0(https://smartprogram.baidu.com/docs/develop/function/tune\_up\_2.0/) 一、申请通过后,填写百度支付相关配置: $config = array( 'deal\_id' => '', // 百度收银台的财务结算凭证 'app\_key' => '', // 表示应用身份的唯一ID 'private\_key' => '', // 私钥原始字符串 'public\_key' => '', // 平台公钥 'notify\_url' => '', // 支付回调地址 ); 二、调用封装的支付方法,将返回信息,传递到百度小程序 '测试商品', // 产品描述 'total\_amount' => '1', // 订单金额(分) 'order\_sn' => $order\_sn, // 订单编号 ); $re = $baidupay->xcxPay($order); die(json\_encode($re)); // JSON化直接返回小程序客户端 PHP 小程序支付类 xcxPay: /\*\* \* \[xcxPay 百度小程序支付\] \* @param \[type\] $order \[订单信息数组\] \* @return \[type\] \[description\] \* $order = array( \* 'body' => '', // 产品描述 \* 'total\_amount' => '', // 订单金额(分) \* 'order\_sn' => '', // 订单编号 \* ); \*/ public static function xcxPay($order) { if(!is\_array($order) || count($order) < 3) die("数组数据信息缺失!"); $config = self::$config; $requestParamsArr = array( 'appKey' => $config\['app\_key'\], 'dealId' => $config\['deal\_id'\], 'tpOrderId' => $order\['order\_sn'\], 'totalAmount' => $order\['total\_amount'\], ); $rsaSign = self::makeSign($requestParamsArr, $config\['private\_key'\]); // 声称百度支付签名 $bizInfo = array( 'tpData' => array( "appKey" => $config\['app\_key'\], "dealId" => $config\['deal\_id'\], "tpOrderId" => $order\['order\_sn'\], "rsaSign" => $rsaSign, "totalAmount" => $order\['total\_amount'\], "returnData" => '', "displayData" => array( "cashierTopBlock" => array( array( \[ "leftCol" => "订单名称", "rightCol" => $order\['body'\] \], \[ "leftCol" => "数量", "rightCol" => "1" \], \[ "leftCol" => "订单金额", "rightCol" => $order\['total\_amount'\] \] ), array( \[ "leftCol" => "服务地址", "rightCol" => "北京市海淀区上地十街10号百度大厦" \], \[ "leftCol" => "服务时间", "rightCol" => "2018/10/29 14:51" \], \[ "leftCol" => "服务人员", "rightCol" => "百度App" \] ) ) ), "dealTitle" => $order\['body'\], "dealSubTitle" => $order\['body'\], "dealThumbView" => "https://b.bdstatic.com/searchbox/icms/searchbox/img/swan-logo.png", ), "orderDetailData" => '' ); $bdOrder = array( 'dealId' => $config\['deal\_id'\], 'appKey' => $config\['app\_key'\], 'totalAmount' => $order\['total\_amount'\], 'tpOrderId' => $order\['order\_sn'\], 'dealTitle' => $order\['body'\], 'signFieldsRange' => 1, 'rsaSign' => $rsaSign, 'bizInfo' => json\_encode($bizInfo), ); return $bdOrder; } 三、百度智能小程序端的使用 SWAN HTML JS Page({ requestPolymerPayment(e) { swan.request({ url: 'https://mbd.baidu.com/xxx', // 仅为示例,并非真实的接口地址,开发者从真实接口获取orderInfo的值 success: res => { res.data.data.dealTitle = '百度小程序Demo支付测试'; let data = res.data; if (data.errno !== 0) { console.log('create order err', data); return; } swan.requestPolymerPayment({ orderInfo: data.data, success: res => { swan.showToast({ title: '支付成功', icon: 'success' }); console.log('pay success', res); }, fail: err => { swan.showToast({ title: err.errMsg, icon: 'none' }); console.log('pay fail', err); } }); }, fail: err => { swan.showToast({ title: '订单创建失败', icon: 'none' }); console.log('create order fail', err); } }); } }); 四、支付回调 notify(); if ($re) { // 这里回调处理订单操作 // 以验证返回支付成功后的信息,可直接对订单进行操作,已通知微信支付成功 $baidupay->success(); // 支付返还成功,通知结果 } else { // 支付失败 $baidupay->error(); // 支付失败,返回状态(无论支付成功与否都需要通知百度) } 百度完整支付类(BaiduPay.php),包含小程序支付、验签、回调、退款: \* @Date: 2020-09-27T16:28:31+08:00 \* @Last Modified by: \[FENG\] <1161634940@qq.com> \* @Last Modified time: 2020-10-15T10:23:07+08:00 \*/ namespace feng; class BaiduPay { private static $config = array( 'deal\_id' => '', // 百度收银台的财务结算凭证 'app\_key' => '', // 表示应用身份的唯一ID 'private\_key' => '', // 私钥原始字符串 'public\_key' => '', // 平台公钥 'notify\_url' => '', // 支付回调地址 ); /\*\* \* \[\_\_construct 构造函数\] \* @param \[type\] $config \[传递支付相关配置\] \*/ public function \_\_construct($config=NULL){ $config && self::$config = $config; } /\*\* \* \[xcxPay 百度小程序支付\] \* @param \[type\] $order \[订单信息数组\] \* @return \[type\] \[description\] \* $order = array( \* 'body' => '', // 产品描述 \* 'total\_amount' => '', // 订单金额(分) \* 'order\_sn' => '', // 订单编号 \* ); \*/ public static function xcxPay($order) { if(!is\_array($order) || count($order) < 3) die("数组数据信息缺失!"); $config = self::$config; $requestParamsArr = array( 'appKey' => $config\['app\_key'\], 'dealId' => $config\['deal\_id'\], 'tpOrderId' => $order\['order\_sn'\], 'totalAmount' => $order\['total\_amount'\], ); $rsaSign = self::makeSign($requestParamsArr, $config\['private\_key'\]); // 声称百度支付签名 $bizInfo = array( 'tpData' => array( "appKey" => $config\['app\_key'\], "dealId" => $config\['deal\_id'\], "tpOrderId" => $order\['order\_sn'\], "rsaSign" => $rsaSign, "totalAmount" => $order\['total\_amount'\], "returnData" => '', "displayData" => array( "cashierTopBlock" => array( array( \[ "leftCol" => "订单名称", "rightCol" => $order\['body'\] \], \[ "leftCol" => "数量", "rightCol" => "1" \], \[ "leftCol" => "订单金额", "rightCol" => $order\['total\_amount'\] \] ), array( \[ "leftCol" => "服务地址", "rightCol" => "北京市海淀区上地十街10号百度大厦" \], \[ "leftCol" => "服务时间", "rightCol" => "2018/10/29 14:51" \], \[ "leftCol" => "服务人员", "rightCol" => "百度App" \] ) ) ), "dealTitle" => $order\['body'\], "dealSubTitle" => $order\['body'\], "dealThumbView" => "https://b.bdstatic.com/searchbox/icms/searchbox/img/swan-logo.png", ), "orderDetailData" => '' ); $bdOrder = array( 'dealId' => $config\['deal\_id'\], 'appKey' => $config\['app\_key'\], 'totalAmount' => $order\['total\_amount'\], 'tpOrderId' => $order\['order\_sn'\], 'dealTitle' => $order\['body'\], 'signFieldsRange' => 1, 'rsaSign' => $rsaSign, 'bizInfo' => json\_encode($bizInfo), ); return $bdOrder; } /\*\* \* \[refund baidu支付退款\] \* @param \[type\] $order \[订单信息\] \* @param \[type\] $type \[退款类型\] \* $order = array( \* 'body' => '', // 退款原因 \* 'total\_amount' => '', // 退款金额(分) \* 'order\_sn' => '', // 订单编号 \* 'access\_token' => '', // 获取开发者服务权限说明 \* 'order\_id' => '', // 百度收银台订单 ID \* 'user\_id' => '', // 百度收银台用户 id \* ); \*/ public static function refund($order=\[\], $type=1) { $config = self::$config; $data = array( 'access\_token' => $order\['access\_token'\], // 获取开发者服务权限说明 'applyRefundMoney' => $order\['total\_amount'\], // 退款金额,单位:分。 'bizRefundBatchId' => $order\['order\_sn'\], // 开发者退款批次 'isSkipAudit' => 1, // 是否跳过审核,不需要百度请求开发者退款审核请传 1,默认为0; 0:不跳过开发者业务方审核;1:跳过开发者业务方审核。 'orderId' => $order\['order\_id'\], // 百度收银台订单 ID 'refundReason' => $order\['body'\], // 退款原因 'refundType' => $type, // 退款类型 1:用户发起退款;2:开发者业务方客服退款;3:开发者服务异常退款。 'tpOrderId' => $order\['order\_sn'\], // 开发者订单 ID 'userId' => $order\['user\_id'\], // 百度收银台用户 id ); $array = \['errno'=>0, 'msg'=>'success', 'data'=> \['isConsumed'=>2\] \]; $url = 'https://openapi.baidu.com/rest/2.0/smartapp/pay/paymentservice/applyOrderRefund'; $response = self::post\_curl($url, $data); $result = json\_decode($response, true); // // 显示错误信息 // if ($result\['msg'\]!='success') { // return false; // // die($result\['msg'\]); // } return $result; } /\*\* \* \[notify 回调验证\] \* @return \[array\] \[返回数组格式的notify数据\] \*/ public static function notify() { $data = $\_POST; // 获取xml $config = self::$config; if (!$data || empty($data\['rsaSign'\])) die('暂无回调信息'); $result = self::checkSign($data, $config\['public\_key'\]); // 进行签名验证 // 判断签名是否正确 判断支付状态 if ($result && $data\['status'\]==2) { return $data; } else { return false; } } /\*\* \* \[success 通知支付状态\] \*/ public static function success() { $array = \['errno'=>0, 'msg'=>'success', 'data'=> \['isConsumed'=>2\] \]; die(json\_encode($array)); } /\*\* \* \[error 通知支付状态\] \*/ public static function error() { $array = \['errno'=>0, 'msg'=>'success', 'data'=> \['isErrorOrder'=>1, 'isConsumed'=>2\] \]; die(json\_encode($array)); } /\*\* \* \[makeSign 使用私钥生成签名字符串\] \* @param array $assocArr \[入参数组\] \* @param \[type\] $rsaPriKeyStr \[私钥原始字符串,不含PEM格式前后缀\] \* @return \[type\] \[签名结果字符串\] \*/ public static function makeSign(array $assocArr, $rsaPriKeyStr) { $sign = ''; if (empty($rsaPriKeyStr) || empty($assocArr)) { return $sign; } if (!function\_exists('openssl\_pkey\_get\_private') || !function\_exists('openssl\_sign')) { throw new Exception("openssl扩展不存在"); } $rsaPriKeyPem = self::convertRSAKeyStr2Pem($rsaPriKeyStr, 1); $priKey = openssl\_pkey\_get\_private($rsaPriKeyPem); if (isset($assocArr\['sign'\])) { unset($assocArr\['sign'\]); } ksort($assocArr); // 参数按字典顺序排序 $parts = array(); foreach ($assocArr as $k => $v) { $parts\[\] = $k . '=' . $v; } $str = implode('&', $parts); openssl\_sign($str, $sign, $priKey); openssl\_free\_key($priKey); return base64\_encode($sign); } /\*\* \* \[checkSign 使用公钥校验签名\] \* @param array $assocArr \[入参数据,签名属性名固定为rsaSign\] \* @param \[type\] $rsaPubKeyStr \[公钥原始字符串,不含PEM格式前后缀\] \* @return \[type\] \[验签通过|false 验签不通过\] \*/ public static function checkSign(array $assocArr, $rsaPubKeyStr) { if (!isset($assocArr\['rsaSign'\]) || empty($assocArr) || empty($rsaPubKeyStr)) { return false; } if (!function\_exists('openssl\_pkey\_get\_public') || !function\_exists('openssl\_verify')) { throw new Exception("openssl扩展不存在"); } $sign = $assocArr\['rsaSign'\]; unset($assocArr\['rsaSign'\]); if (empty($assocArr)) { return false; } ksort($assocArr); // 参数按字典顺序排序 $parts = array(); foreach ($assocArr as $k => $v) { $parts\[\] = $k . '=' . $v; } $str = implode('&', $parts); $sign = base64\_decode($sign); $rsaPubKeyPem = self::convertRSAKeyStr2Pem($rsaPubKeyStr); $pubKey = openssl\_pkey\_get\_public($rsaPubKeyPem); $result = (bool)openssl\_verify($str, $sign, $pubKey); openssl\_free\_key($pubKey); return $result; } /\*\* \* \[convertRSAKeyStr2Pem 将密钥由字符串(不换行)转为PEM格式\] \* @param \[type\] $rsaKeyStr \[原始密钥字符串\] \* @param integer $keyType \[0 公钥|1 私钥,默认0\] \* @return \[type\] \[PEM格式密钥\] \*/ public static function convertRSAKeyStr2Pem($rsaKeyStr, $keyType = 0) { $pemWidth = 64; $rsaKeyPem = ''; $begin = '-----BEGIN '; $end = '-----END '; $key = ' KEY-----'; $type = $keyType ? 'RSA PRIVATE' : 'PUBLIC'; $keyPrefix = $begin . $type . $key; $keySuffix = $end . $type . $key; $rsaKeyPem .= $keyPrefix . "\\n"; $rsaKeyPem .= wordwrap($rsaKeyStr, $pemWidth, "\\n", true) . "\\n"; $rsaKeyPem .= $keySuffix; if (!function\_exists('openssl\_pkey\_get\_public') || !function\_exists('openssl\_pkey\_get\_private')) { return false; } if ($keyType == 0 && false == openssl\_pkey\_get\_public($rsaKeyPem)) { return false; } if ($keyType == 1 && false == openssl\_pkey\_get\_private($rsaKeyPem)) { return false; } return $rsaKeyPem; } /\*\* \* curl post请求 \* @param string $url 地址 \* @param string $postData 数据 \* @param array $header 头部 \* @return bool|string \* @Date 2020/9/17 17:12 \* @Author wzb \*/ public static function post\_curl($url='',$postData='',$header=\[\]){ $ch = curl\_init($url); curl\_setopt($ch, CURLOPT\_SSL\_VERIFYPEER, false); curl\_setopt($ch, CURLOPT\_POST, 1); curl\_setopt($ch, CURLOPT\_HEADER, false); curl\_setopt($ch, CURLOPT\_RETURNTRANSFER, true); curl\_setopt($ch, CURLOPT\_CONNECTTIMEOUT, 5000); curl\_setopt($ch, CURLOPT\_TIMEOUT, 5000); if($header){ curl\_setopt($ch, CURLOPT\_HTTPHEADER,$header); } curl\_setopt($ch, CURLOPT\_POSTFIELDS, $postData); $result = curl\_exec($ch); $httpCode = curl\_getinfo($ch, CURLINFO\_HTTP\_CODE); $curlErrNo = curl\_errno($ch); $curlErr = curl\_error($ch); curl\_close($ch); return $result; } } 以上就是重新对百度支付进行编写封装(百度智能小程序支付)的详细内容,更多请关注知企PROSAAS其它相关文章! **Tags:** function, https, php, transform, 封装, 接口, 重构 **Categories:** 后端开发 ---