uniapp 百度小程序收银台支付开发(php)

开通支付功能(对着文档看就行,无雷点)

OpenSSL下载地址:Win32/Win64 OpenSSL Installer for Windows - Shining Light Productions

生成的pem文件有3个,复制公钥时只需要复制字符串!

申请审核通过后就能看到支付配置信息,红框内的参数在发起支付时会用到:

前端代码:

//请使用自己的请求函数
request({
				url: `pay.php`,
				data: {
					"order_id": id.value,
				},
				method: 'POST',
				needLoading: true
			}).then(v => {
				swan.requestPolymerPayment({
					orderInfo:v.orderInfo,
					success: function() {
                        console.log('支付成功')
					},
					fail: function(res) {
						console.log(res)
						console.log('支付失败')
					}
				})
			}).catch(e => {
				console.log(e)
				onsole.log('支付失败')
			})

后端代码:(非拷贝即用!只提供正确的代码传参及调用格式供避坑)

applet_info.php

<?php

//小程序的配置,在小程序管理中心,基本设置里有
$app_id = "1xxxxxxx";

$app_key = "fxxxxxxxxxxxxxxx";

$app_secret = "Mxxxxxxxxxxxxxxxxxxxxxx";

//支付配置,在小程序管理中心,功能管理-支付管理里有
$dealId = "3xxxxx";

$app_id_pay = "6xxxxxxxx";

$app_key_pay = "Mxxxxxxxxx";

$platform_public_key = "xxxxxxxxxxxxxxxxx";

//自己的公钥,在上面生成的文件里有,复制下来,只要字符串!
$public_key = "Mxxxxxxxxxxxxxxxxxxxxx";

//自己的私钥,在上面生成的文件里有,复制下来,只要字符串!
$private_key = "Mxxxxxxxxxxxxxxxxx";



?>

sign.php(就是拷贝的官方的)

<?php

// 通用签名工具,基于openssl扩展,提供使用私钥生成签名和使用公钥验证签名的接口
class RSASign
{

    /**
     * @desc 使用私钥生成签名字符串
     * @param array $assocArr 入参数组
     * @param string $rsaPriKeyStr 私钥原始字符串,不含PEM格式前后缀
     * @return string 签名结果字符串
     * @throws Exception
     */
    public static function sign(array $assocArr, $rsaPriKeyStr)
    {
        $sign = '';

        // var_dump($assocArr);
        // echo $rsaPriKeyStr;

        // exit;

        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);
    }

    /**
     * @desc 使用公钥校验签名
     * @param array $assocArr 入参数据,签名属性名固定为rsaSign
     * @param string $rsaPubKeyStr 公钥原始字符串,不含PEM格式前后缀
     * @return bool true 验签通过|false 验签不通过
     * @throws Exception
     */
    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;
    }


    /**
     * @desc 将密钥由字符串(不换行)转为PEM格式
     * @param string $rsaKeyStr 原始密钥字符串
     * @param int $keyType 0 公钥|1 私钥,默认0
     * @return string PEM格式密钥
     * @throws Exception
     */
    public static function convertRSAKeyStr2Pem($rsaKeyStr, $keyType = 0)
    {

        $pemWidth = 64;
        $rsaKeyPem = '';

        $begin = '-----BEGIN ';
        $end = '-----END ';
        $key = ' KEY-----';
        $type = $keyType ? '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;
    }

}

pay.php

<?php
date_default_timezone_set('prc');
$price = 0;

//自行获取前端上传的数据
$pay_type = $_POST['pay_type '];


$rootPath = $_SERVER['DOCUMENT_ROOT'];

//自行获取price价格
$price = (float)$price;


include  'applet_info.php';

include 'sign.php';

if($price === 0){
    $json = json_encode(array(
        "resultCode"=>500,
        "message"=>'价格错误',
    ),256);
    exit($json);
}

//以分为单位
$totalAmount = $price * 100;

//自行上传参数
$rsaSign = RSASign::sign(
    array(
        "dealId"=>$dealId,
        "appKey"=>$app_key_pay,
        "totalAmount"=>$totalAmount,
        "tpOrderId"=>$trade_no,
    ), $private_key
);

if(!$rsaSign){
    echo json_encode(array("resultCode"=>800,"message"=>"签名失败"));
    exit;
}

//自行上传参数
$bizInfo = array(
    "tpData"=>array(
        "returnData"=>array(
            "order_id"=>$order_id,
            "user_id"=>$user_id,
        )
    )
);

$bizInfo = json_encode($bizInfo,256);

//自行上传参数
$orderInfo = array(
    "dealId"=>$dealId,
    "appKey"=>$app_key_pay,
    "totalAmount"=>$totalAmount,
    "tpOrderId"=>$trade_no,
    "dealTitle"=>$title,
    "signFieldsRange"=>"1",
    "rsaSign"=>$rsaSign,
    "payResultUrl"=>"/pages/index/index",
    "bizInfo"=>"$bizInfo"
);

$array = array(
    "resultCode"=>200,
    "message"=>'ok',
    "orderInfo"=> $orderInfo,
    "trade_no"=>$trade_no
);
echo json_encode($array,256);

?>

生成orderInfo成功,前端就会打开百度收银台:

支付通知回调:

notify.php

<?php
date_default_timezone_set('prc');

// 日志记录函数
function logMessage($message) {
    $logFile = __DIR__ . '/callback.log';
    file_put_contents($logFile, date('Y-m-d H:i:s') . " - $message\n", FILE_APPEND);
}

$rootPath = $_SERVER['DOCUMENT_ROOT'];

include 'sign.php';
include 'applet_info.php';

$out_trade_no = null;


// 更新订单状态函数
function updateOrderStatus($responseArr) {
    $time = date('Y-m-d H:i:s');

    $out_trade_no = $responseArr['tpOrderId'];
    $root = $_SERVER['DOCUMENT_ROOT'];

    $msg_json = json_encode($responseArr);

    $returnData = json_decode($responseArr['returnData'],true);
    $order_id = $returnData['order_id'];

    $userId = $responseArr['userId'];
    $orderId = $responseArr['orderId'];
    $timestamp = $responseArr['payTime'];

        if($responseArr['status'] == 2){ //已支付
            echo json_encode(["errno" => 0, "msg" => "success","data"=>["isConsumed"=>2]]);
            //订单金额
            $price = (float)$responseArr['totalMoney'] / 100; 
            //实际支付金额
            $pay_price = (float)$responseArr['payMoney'] / 100;
            

            //你的支付成功逻辑
            //你的支付成功逻辑

            //请注意把orderId,userId等参数保存起来,(怎么实现都行)退款时会用到
            
            $sql_bd = "insert into xxxxxxxxxxxxxxxx";
            mysqli_query($sql_bd);
            // }
        }else{
            logMessage('订单支付失败:'. $out_trade_no . " - order_id: $order_id" . " - orderId: $orderId");
            echo json_encode(["errno" => 0, "msg" => "fail:not paid","data"=>["isConsumed"=>1]]);
        }
}

// 主逻辑

if (!$_POST || empty($_POST)) {
    echo "Invalid request";
    logMessage('Invalid request:'. json_encode($_POST));
    exit;
}

$checkSignResult = RSASign::checkSign($_POST,$platform_public_key);

if(!$checkSignResult){
    echo "Invalid sign";
    logMessage('订单支付回调签名验证失败:'. json_encode($_POST));
    exit;
}

$root = $_SERVER['DOCUMENT_ROOT'];
//连接数据库省略
//连接数据库省略

header('Content-Type: application/json');
updateOrderStatus($_POST);
?>

发起退款

发起请求要以表单形式,非json,加上这一句:curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); 

refund.php

<?php
date_default_timezone_set("Asia/Shanghai");

$rootPath = $_SERVER['DOCUMENT_ROOT'];

include 'applet_info.php';

function logMessage($message) {
    $logFile = __DIR__ . '/callback_refund.log';
    file_put_contents($logFile, date('Y-m-d H:i:s') . " - $message\n", FILE_APPEND);
}

$ch = curl_init();

$url = "https://openapi.baidu.com/oauth/2.0/token?grant_type=client_credentials&client_id=$app_key&client_secret=$app_secret&scope=smartapp_snsapi_base";
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);

$response = json_decode($response,true);
$access_token = $response['access_token'];


// 设置请求的 URL
$url = 'https://openapi.baidu.com/rest/2.0/smartapp/pay/paymentservice/applyOrderRefund';


if(!$myRefundPrice){
    $json = json_encode(array(
        "resultCode"=>925,
        "message"=>'退款金额不正确',
    ),256);
    exit($json);
}


if($id){
    $id = $id;
}else if($order_id){
    $id = $order_id;
}

//取出保存的userId,orderId(每个人实现方式不同,都行,反正这里要用到userId,orderId)
$sql_bd = "select userId,orderId,price from xxxxxx where xxxxxxxx";

$rs_bd = mysql_query($sql_bd);

if(!$rs_bd){
    $array = array(
        "resultCode"=>926,
        "message"=>'错误:检索订单支付信息超时,请联系客服',
    );
    $json = json_encode($array,256);
    echo $json;
    logMessage("退款失败:$id 检索订单支付信息超时");
    exit;
}


if(mysql_num_rows($rs_bd) == 0){
    $array = array(
        "resultCode"=>930,
        "message"=>'错误:订单支付信息不存在,请联系客服',
    );
    $json = json_encode($array,256);
    echo $json;
    logMessage("退款失败:$id 订单支付信息不存在");
    exit;
}

$row_bd = mysql_fetch_assoc($rs_bd);

$bd_orderId = $row_bd['orderId']; //百度收银台订单id
$bd_userId = $row_bd['userId'];

$bd_price = $row_bd['price'];

$refund_amount = $myRefundPrice;  //以分为单位

//有部分退款需求,所以这里做了区分
if($refund_amount < $bd_price){
    $refundType = 2;
}else{
    $refundType = 1;
}

$data = [
    "access_token" => $access_token,
    "applyRefundMoney" => $refund_amount,
    "bizRefundBatchId"=>$refund_no,
    "isSkipAudit" =>0,
    "orderId" => $bd_orderId, //百度收银台订单id
    "refundReason"=>"取消订单退款",
    "refundType"=>$refundType, //用户退款
    "refundNotifyUrl" => "https://xxxx/notify_refund.php",
    "tpOrderId"=> $myTradeNo,  //开发者订单id
    "userId"=> $bd_userId, //收银台用户ID
    "pmAppKey"=> $app_key_pay,
];

logMessage("data: ".json_encode($data,256));
// 将数组转换为 JSON 格式
// $jsonData = json_encode($data);

// 设置 cURL 选项
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
//请注意一定要用表单方式提交,百度不支持json格式
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data)); 

curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

// 执行 cURL 会话
$response = curl_exec($ch);

// 检查是否有错误发生
if (curl_errno($ch)) {
    $error_msg = curl_error($ch);
}

// 关闭 cURL 会话
curl_close($ch);

//你的逻辑
//插入退款记录等
//你的逻辑

logMessage("response: $response");


// 如果有错误,输出错误信息
if (isset($error_msg)) {
    echo 'Curl error: ' . $error_msg;
}
?>

退款审核(注意百度与其他支付不同点有一个退款审核机制)

notify_refund_check.php

<?php
date_default_timezone_set('prc');

// 日志记录函数
function logMessage($message) {
    $logFile = __DIR__ . '/callback_refund_check.log';
    file_put_contents($logFile, date('Y-m-d H:i:s') . " - $message\n", FILE_APPEND);
}

$rootPath = $_SERVER['DOCUMENT_ROOT'];
include 'applet_info.php';
include 'sign.php';

// 主逻辑

if (!$_POST || empty($_POST)) {
    echo "Invalid request";
    exit;
}

$checkSignResult = RSASign::checkSign($_POST,$platform_public_key);

if(!$checkSignResult){
    echo "Invalid sign";
    exit;
}

$applyRefundMoney = $_POST['applyRefundMoney'];

echo json_encode(["errno" => 0, "msg" => "success","data"=>[
    "auditStatus"=>1,
    "calculateRes"=>array(
        "refundPayMoney"=>$applyRefundMoney,
    )
]]);
?>

退款通知回调(和支付通知回调基本一致)

notify_refund.php

<?php
date_default_timezone_set('prc');

// 日志记录函数
function logMessage($message) {
    $logFile = __DIR__ . '/callback_refund.log';
    file_put_contents($logFile, date('Y-m-d H:i:s') . " - $message\n", FILE_APPEND);
}


$rootPath = $_SERVER['DOCUMENT_ROOT'];

include 'sign.php';
include 'applet_info.php';

$out_trade_no = null;

// 更新订单状态函数
function refund_notify($responseArr) {

    $time = date('Y-m-d H:i:s');

    $out_trade_no = $responseArr['tpOrderId'];
    $refund_no = $responseArr['refundBatchId'];
    $orderId = $responseArr['orderId'];

    $root = $_SERVER['DOCUMENT_ROOT'];

    $msg_json = json_encode($responseArr);

    if($responseArr['refundStatus'] != 1){
        //退款失败
        exit;
    }
    //退款成功更新状态
}

// 主逻辑

if (!$_POST || empty($_POST)) {
    echo "Invalid request";
    exit;
}

$checkSignResult = RSASign::checkSign($_POST,$platform_public_key);

if(!$checkSignResult){
    echo "Invalid sign";
    exit;
}

$root = $_SERVER['DOCUMENT_ROOT'];
//连接数据库
//连接数据库
header('Content-Type: application/json');
refund_notify($_POST);
echo json_encode(["errno" => 0, "msg" => "success","data"=>[]]);
?>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值