VIVO小游戏支付以及服务端php支付流程

10 篇文章 2 订阅
VIVO小游戏支付流程如下:

1.前端拉起商品列表

用户登录app后,进入商品购买页面,前端请求app商品列表api接口,获取商品列表信息并展示

2.下单

用户点击'购买'操作,发送给服务端一条当前商品信息,服务端保存该商品的相关订单数据,并返回给前端vivo支付所需要的请求数据,前端调用vivo支付sdk,发起支付请求
    /**
     * vivo支付下单
     * @param array $params 订单信息
     * @return array
     */
    public static function Pay($params)
    {
        //获取商品内部订单号
        $innerOno = self::genInnerOno(date("Y-m-d H:i:s"), $params['user_id'], $paymentType);
        //生成订单
        $order = new Order();
        $order->order_id = $innerOno;  // 内部订单号
        $order->product_name = $params['name'];  // 商品名称
        $order->number = $params['num'];  // 购买商品个数
        $order->price = $params['price'];  // 商品单价, 1个商品价格
        $order->total_price = $params['total_price'];  // 总的价格
        $order->pay_amount = $params['pay_amount'];  // 应付总额:  实际应该支付的价格= 总金额 - 优惠金额
        $order->count = $params['count'];  // 购买后得到商品对应的产品数量
        $order->status = 0;  // 状态:0 待支付     
        $order->user_id = $params['user_id'];  // 用户游戏ID
        $order->expired_at = $params['expired_at'];  // 过期时间
        $order->created_by = $params['created_by'];  // 创建者
        $order->updated_by = $params['updated_by'];  // 创建者
 
        $result = $order->save();
        if (!$result) {
            $errors = '';
            if ($order->hasErrors()) {
                $tmp = $order->getErrors();
                foreach ($tmp as $rows) {
                    foreach ($rows as $row) {
                        $errors .= $row . '<br/>';
                    }
                }
            }
            throw new \Exception($errors);
        }
        $orderId = $order->id;
        
        //构建vivo支付所需要的数据
        $title = $order->product_name;
        //过滤掉特殊字符
        $title = replaceStr($title);
        $config = Yii::$app->params['vivo'];
        $price = $order->pay_amount;
 
         //构建向oppo发送的参数
        $data = [
            'appId' => $config['app_id'],   //appId:由开发者平台申请得到
            'cpOrderNumber' => $model->order_id, //商户订单号,务必保证唯一
            'productName' => $title,  //商品名(不能含有+号等特殊符号
            'productDesc' => $title,  //商品描述(不能含有+号等特殊符号)
            //消费总金额,单位为分,传整数,如商品价格为6元则要传“600”,  “600.0”则会报错,传“6”则会有不必要的损失
            'orderAmount' => $price,
            'extuid' => $user['wx'], // 用户的openId,登录后可以得到,必传
            'notifyUrl' => $config['notify_url'],  //回调地址
        ];
        $pay = new Pay();
        // 签名
        $data['vivoSignature'] = $pay->getSign($data, $config['secret']);

 
        return jsonFail($data);
    }
 
   /**
     * 生成本系统内部订单号, 在向第三方服务商发起支付时需要使用.
     *
     * 下单时的处理流程:
     *   1. 属性 ono 不要赋值, 成功插入(保存)订单.
     *   1. 支付前生成本系统内部订单号, 向第三方发起支付请求.
     *   1. 接收到支付成功回调通知时, 将第三方订单号保存到本次付款的订单的 ono 字段上.
     *
     * 格式: 下单时间+支付方式+ 4位数字修正值. 如 "20150930140041+1+1234".
     * 最大长度 32 个字符. 这也是 wx 可接受的订单号最大长度.
     *
     * @param int $createdAt 订单创建时间戳, 即 下单时间戳.
     * @param int $createdBy 订单创建人 ID, 即 下单会员 ID.
     * @return string
     * @throws \Exception
     */
 
    public static function genInnerOno($createdAt, $createdBy)
    {
        $createdAt = strtotime($createdAt);
        if (1 > $createdAt || 1 > $createdBy) {
            throw new \Exception('参数错误');
        }
 
        // 生成一个修正值, 一定程度上增加订单号的随机性.
        $tmp = intval(substr($createdAt, -4)) + intval(substr($createdBy, -2));
        if (4 < strlen($tmp)) {
            $tmp = substr($tmp, -4);
        }
 
        $tmp = date('YmdHis', $createdAt) . $tmp . rand(100, 900);
        return $tmp;
    }

3. 支付

前端获取服务端返回的支付所需要的请求数据后,拼接支付请求参数,调用vivo支付sdk,发起支付请求

4. 回调操作

前端支付成功后,vivo会请求服务端的回调方法,对支付订单进行校验验签操作,根据验签结果,处理订单业务逻辑
php以yii2框架为参考
    /**
     * vivo支付回调
     */
    public function actionNotify()
    {
        //获取回调通知数据
        $notifyData = $_POST;  

        //判断通知请求
        $trans = Yii::$app->db->beginTransaction();
        try {
            //签名校验
            $config = Yii::$app->params['vivo'];
            // 检查回调参数是否正确
            if (empty($notifyData['signature']) || $notifyData['respCode'] != 200
                || $notifyData['tradeStatus'] != '0000') { //回调参数错误
                return "fail";
            }

            // 对回调数据进行验签
            $pay = new Pay();
            $sign = $pay->getSign($notifyData, $config['secret']);
            if ($notifyData['signature'] != $sign) { //回调数据验签失败
                return "fail";
            }

            $order_id = $notifyData["cpOrderNumber"]; //商户自定义的订单号
            $order_number = $notifyData['orderNumber'];//交易流水号:vivo生成的交易单号
            $paid_at = strtotime($notifyData['payTime']);//交易时间
            // 订单状态
            $status = UserOrder::STATUS_BUY;
            
            //处理订单业务逻辑
            //判断订单状态是否已经支付
            $userOrder = UserOrder::find()
                        ->where([
                            'status' => $status,
                            'order_id' => $order_id
                         ])
                        ->exists();
            if ($userOrder) {
                throw new \Exception('订单已支付');
            }
            // 变更订单属性
            UserOrder::changeAttribute(
                ['order_id' => $order_id],
                [
                    'status' => $status,
                    'paid_at' => $paid_at,
                    'order_number' => $order_number,
                ]
            );

            $trans->commit();

            return "success"; // 通知vivo回调成功
        } catch (\Exception $e) {
            $trans->rollBack();
        }
    }

5.上面需要使用到的公共方法

/**
 * 操作成功
 * @example1 jsonSuccess();
 */
function jsonSuccess($data = NULL, $message = '操作成功')
{
    header("Content-Type:application/json");
    $json = array();
    $json['code'] = 0;
    $json['data'] = $data;
    $json['message'] = $message;
    $json['request_time'] = now();
    echo Json::encode($json);
    exit();
}

/**
 * 错误信息
 * @example1 jsonFail();
 * @example1 jsonFail("删除失败!");
 * @example2 jsonFail($model->getErrors());
 */
function jsonFail($message = '请求失败', $code = 1, $data = null)
{
    header("Content-Type:application/json");
    $json = array();
    $json['code'] = $code;
    $json['data'] = $data;
    $json['message'] = $message;
    $json['request_time'] = now();
    echo Json::encode($json);
    exit();
}

/**
 * 过滤掉特殊的字符
 * @param $str
 * @param string $replacement
 * @return string|string[]|null
 */
function replaceStr($str, $replacement = '')
{
    $regex = "/\/|\~|\,|\。|\!|\?|\“|\”|\【|\】|\『|\』|\:|\;|\《|\》|\’|\‘|\ |\·|\~|\!|\@|\#|\\$|\%|\^|\&|\*|\(|\)|\_|\+|\{|\}|\:|\<|\>|\?|\[|\]|\,|\.|\/|\;|\'|\`|\-|\=|\\\|\|/";
    $result = preg_replace($regex, $replacement, $str);

    return $result;
}
Yii2 VIVO相关配置:params-local.php
<?php

return [
    //vivo配置
    'vivo' => [
        'app_id' => '', //应用ID
        //异步通知地址
        'notify_url' => "https://xxx/notify",
        'pay_test' => 1,  //是否支付测试
        'is_screen_pay' => 0, //是否屏蔽支付
    ],
];
VIVO支付签名校验
<?php
/**
 * vivo支付签名校验
 */
namespace common\vivo;

/**
 * Class Pay
 * @package common\vivo
 */
class Pay
{
    /**
     * 对数据进行签名
     *
     * @param $data    array  需要签名的数据
     * @param $secret string 小游戏支付密钥
     *
     * @return string
     */
    public function getSign($data, $secret)
    {
        unset($data['signature'], $data['signMethod'], $data['extuid']); // 不参与签名字段

        ksort($data);
        $signStr = urldecode(http_build_query(array_filter($data, 'strlen'))).'&'.md5($secret);
        return md5($signStr);
    }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值