PHP接入海尔消费金融


海尔消费金融简称“嗨付”,公司要求接入海尔金融分期,第一次听说这种支付,官方只有java的demo,没有php的,所以下面会提供一些php实战用到的代码

介绍

海尔会拉一个微信群,给一个word文档,上面会写着测试环境地址,很简洁,没有在线的接口文档,效率极低,我一共收到了3个word文档了,他们给的接口实例每次都要少点什么。开发完后,发现要注册他们平台的账号、身份证认证、人脸识别、银行卡添加,各种隐私,而且又是贷款,给人一种很不安全的感觉。作为后端,要测试自己写的代码,只能注册了。只要能写出来php的demo,官方给的文档在标准一些,接入就比较方便了,这两样还得自己摸索。。。

实战代码

线上和测试配置切换需要修改url(接口地址)

公共配置文件

公钥私钥文件夹

  • hai_pay/ 海尔金融配置文件夹
  • hai_pay/config/ 公钥私钥
  • hai_pay/config/private.pem 私钥
  • hai_pay/config/public.pem 公钥
  • hai_pay/RSAUtils.php
  • hai_pay/SignUtil.php

文件名:private.pem

-----BEGIN PRIVATE KEY-----
***
-----END PRIVATE KEY-----

文件名:public.pem

-----BEGIN PUBLIC KEY-----
***
-----END PUBLIC KEY-----

文件名:RSAUtils.php

dir = 'config';

        $this->privateKey = openssl_pkey_get_private(file_get_contents(dirname(__FILE__).'/'.$this->dir.'/private.pem'));//私钥,用于加密
        $this->publicKey = openssl_pkey_get_public(file_get_contents(dirname(__FILE__).'/'.$this->dir.'/public.pem'));//公钥,用于解密
    }

    /**
     * 私钥加密
     * @param 原始数据 $data
     * @return 密文结果 string
     */
    public function encryptByPrivateKey($data) {
        openssl_private_encrypt($data,$encrypted,$this->privateKey,OPENSSL_PKCS1_PADDING);//私钥加密
        $encrypted = base64_encode($encrypted);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
        return $encrypted;
    }

    /**
     * 私钥解密
     * @param 密文数据 $data
     * @return 原文数据结果 string
     */
    public function decryptByPrivateKey($data){
        $data = base64_decode($data);
        openssl_private_decrypt($data,$encrypted,$this->privateKey,OPENSSL_PKCS1_PADDING);//私钥解密
        return $encrypted;
    }

    /**
     * 私钥签名
     * @param unknown $data
     */
    public function signByPrivateKey($data){
        openssl_sign($data, $signature, $this->privateKey);
        $encrypted = base64_encode($signature);//加密后的内容通常含有特殊字符,需要编码转换下,在网络间通过url传输时要注意base64编码是否是url安全的
        return $encrypted;
    }


    /**
     * 公钥加密
     * @param 原文数据 $data
     * @return 加密结果 string
     */
    public function encryptByPublicKey($data) {
        openssl_public_encrypt($data,$decrypted,$this->publicKey,OPENSSL_PKCS1_PADDING);//公钥加密
        return base64_encode($decrypted);
    }

    /**
     * 公钥解密
     * @param 密文数据 $data
     * @return 原文结果 string
     */
    public function decryptByPublicKey($data) {
        $data = base64_decode($data);
        openssl_public_decrypt($data,$decrypted,$this->publicKey,OPENSSL_PKCS1_PADDING);//公钥解密
        return $decrypted;
    }

    /**
     * 公钥验签
     * @param unknown $data
     * @param unknown $sign
     */
    public function verifyByPublicKey($data,$sign){
        $sign = base64_decode($sign);
        return openssl_verify($data, $sign, $this->publicKey);
    }

    public function __destruct(){
        openssl_free_key($this->privateKey);
        openssl_free_key($this->publicKey);
    }

    public function getPrivateKey(){

        return file_get_contents(dirname(__FILE__).'/'.$this->dir.'/private.pem');
    }
}

文件名:SignUtil.php

key = $key;
        $this->iv = $iv;
    }


    /**
     * 加密
     * @param boolean $status 是否加密
     * @return string 处理过的数据
     */
    public function encrypt($data,$status=false){
        if ($status){
            return base64_encode(openssl_encrypt($data, 'des-ede3-cbc', $this->key, OPENSSL_RAW_DATA,$this->iv));
        }
       return $data;
    }

    /**
     * 解密
     * @return string 加密的字符串不是完整的会返回空字符串值
     */
    public function decrypt($data,$miv,$status=false){
        if ($status){
            $k=substr($miv,0,8);
            $i=substr($miv,8,8);
            return openssl_decrypt(base64_decode($data), 'des-ede3-cbc', $k, OPENSSL_RAW_DATA, $i);
        }
        return $data;
    }
}

?>

控制器文件

host = 'https://testpm.haiercash.com:9002';
        $this->loanType = 0;
        if(env('APP_ENV') == 'production'){
            $this->loanType = 0; // todo 线上地址待完善
            $this->host = ''; // todo 线上地址待完善
        }
        $this->tools = new Tools();
        $this->http_clinet = new Client();
        require_once  dirname(dirname(dirname(__FILE__))) . '/Tools/hai_pay/SignUtil.php';
        require_once  dirname(dirname(dirname(__FILE__))) . '/Tools/hai_pay/RSAUtils.php';

    }

    /**
     * 贷款申请
     * @return \Illuminate\Http\JsonResponse
     * @throws LogicException
     * @throws \GuzzleHttp\Exception\GuzzleException
     * User: https://github.com/WXiangQian
     */
    public function hai_consume()
    {
        $key = rand(10000000, 99999999);
        $iv  = rand(10000000, 99999999);
        $order_id = $this->request->input('order_id',0);
        $model = $this->request->input('model','');
        // 期数。3、6、9、12
        $applyTnr = $this->request->input('applyTnr',0);
        if (!in_array($applyTnr,[3,6,9,12])) {
            return $this->response->tag('PARAM_ERROR')->response();
        }
        // 根据订单号查询数据库的实付金额
        $payAmt = 0;
        if (!isset($payAmt)) {
            return $this->response->tag('ORDER_NOT_EXIST')->response();
        }
        // 小于1w的课程不允许使用海尔金融
        if ($payAmt < 10000) {
            return $this->response->tag('PARAM_ERROR')->response();
        }

        $post_data = array(
            'uuid' => '交易流水号',
            'body' => array(
                'orderSn' => '订单号',
                'loanType' => '贷款品种编码',
                'payAmt' => '贷款金额',
                'orderDate' => '下单时间Y-m-d',
                'applyTnr' => '期数',
                'orderMessage' => array(
                    'cOrderSn' => time(),
                    'topLevel' => '',
                    'model' => '',
                    'sku' => 0,
                    'price' => '价格',
                    'num' => 1,
                    'cOrderAmt' => '价格',
                    'cOrderPayAmt' => '价格'
                ),
            )
        );

        $sign = new SignUtil($key, $iv);
        $desData = $sign->encrypt(json_encode($post_data), true);

        $rsa = new RSAUtils();
        $password_ = $rsa->encryptByPublicKey($key . $iv);

        $data = [
            'applyNo' => $order_id,
            'channelNo' => '',    // todo 文档里的渠道编号
            'tradeCode' => '', // todo 内部系统使用,文档里有标识
            'data' => $desData,
            'privatekey' => $rsa->getPrivateKey(),
            'key' => $password_
        ];
        $data_string = json_encode($data);
        $clinet_data = [
            'body' => $data_string,
        ];
        // 这里使用到了guzzle扩展包,可以更换为curl去请求
        $result = $this->http_clinet->request('post', $this->host.'/api/payment/gmorder/loanApplication', $clinet_data);

        if ($result->getStatusCode() != 200) {
            return $this->response->tag('PARAM_ERROR')->response();
        }
        $result = json_decode($result->getBody(),true);
        // 00000为申请成功
        if ($result['head']['retFlag'] != '00000') {
            throw new LogicException($result['head']['retMsg'],400);
        }

        $resData = $result['body']['data'];
        $resKey = $result['body']['key'];
        $decryptByPublicKey = $rsa->decryptByPrivateKey($resKey);

        $r = $sign->decrypt($resData, $decryptByPublicKey, true);
        $url = '';
        if ($r) {
            $r = json_decode($r, true);
            if (!empty($r['url'])) {
                $url = $r['url'];
            }
        }
        return $this->response->data(['url'=>$url])->response();
    }

    /**
     * 贷款回调
     * User: https://github.com/WXiangQian
     */
    public function hai_callback()
    {
        $post = file_get_contents('php://input');
        $rs = json_decode(stripslashes($post),true);
        if(empty($rs['key']) || empty($rs['data'])){
            echo json_encode(array('status'=>1,'msg'=>'key值或data值为空'),JSON_UNESCAPED_UNICODE); die;
        }
        $sign = new SignUtil();
        $rsa  = new RSAUtils();
        $decryptByPublicKey=$rsa->decryptByPrivateKey($rs['key']);
        $r = $sign->decrypt($rs['data'],$decryptByPublicKey,true);
        if(!$r){
            echo json_encode(array('status'=>1,'msg'=>'解密失败'),JSON_UNESCAPED_UNICODE); die;
        }
        $r = json_decode($r,true);
        if(!$r['ordersn']){
            echo json_encode(array('status'=>1,'msg'=>'没有订单编号'),JSON_UNESCAPED_UNICODE); die;
        }
        $out_trade_no   = $r['ordersn']; //订单号
        $transStatus    = $r['body']['outSts']; //订单状态 01审批中02审批通过03审批拒绝04 贷款已取消05 客人以确认提交(订单保存)06 审批退回(客人
        $trade_no       = $r['body']['orderNo']; //流水号
       // $notify_time    = time();       //通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。

        if($transStatus == '02') {
            // 调用支付回调回调地址


            echo json_encode(array('status'=>1,'msg'=>'02处理成功'),JSON_UNESCAPED_UNICODE); die;
        }
        echo json_encode(array('status'=>1,'msg'=>'处理成功'),JSON_UNESCAPED_UNICODE); die;

    }
}

实战demo地址

https://github.com/WXiangQian/laravel-api

操作流程

结束语

真枪实战php接入海尔消费金融,希望可以得到一个👍哦


文章作者: WXiangQian
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 WXiangQian !
 上一篇
《吊打面试官》系列之GIT面试篇 《吊打面试官》系列之GIT面试篇
为什么要编写这个系列?git不熟悉的面试者很难表现出自己熟悉git工作流,那么教大家如何在面试官面前大展雄风!!! 介绍git是一款代码版本控制软件,目前已被广泛的使用。因此优雅的使用git已经成了开发者的必备技能。 区别于SVN,gi
2020-04-15
下一篇 
识破laravel+groupBy+count中那些隐藏着的秘密 识破laravel+groupBy+count中那些隐藏着的秘密
谈一谈那些隐藏着的秘密吧!!! laravel框架中写统计用户的领取数量,打算用 groupBy + count来实现(去重+统计),加了groupBy之后再count,统计出来不的数量不对。查询资料+反复测试终于得到了解决方案。
2020-04-01
  目录