编写一卡通的PHP版SDK

作者: 乘风御上者 分类: PHP 发布时间: 2020-09-19 09:32

如今社会中的支付已形成支付宝老大、微信老二的趋势,各种老式的支付方式已被冲淡到角落,新兴的其他支付方式对支付宝和微信来说也形成不了威胁。

就比如今天的主角一卡通,也只能龟缩在某一特定小区域中瑟瑟发抖。 这些特定环境有学校或某个企业,因各种利益和其他因素的牵扯,暂时还在顽强的挣扎。

所以当我们PHPer服务于这些特定区域时,就不得不低头的去对接这些支付方式。

当对接一卡通的时候,我们摇身一变成了某个学校或者企业的内部商户,比如卖盒饭的小老板。 学生或职工持有的一卡通的卡,只要输入卡号和密码即可扣除其中的金额。

这其中有几点明确之后就非常简单了:

url: 一卡通对接的服务器地址(http://ip:端口/webservice.asmx)
foreign: 商户的账号,也就是扣除消费者的钱后进入的账户。(在接口中无实际作用,但业务上最好标记)
sno: 消费者(学生或职工)的一卡通卡号
pwd: 一卡通卡的密码
paySn: 每次交易自定义的唯一支付单号
amount: 交易金额(单位:元)

使用SDK前记得要先开启PHP的SOAP扩展和OpenSSL扩展

class ECard
{
    // 错误信息
    public $errMsg = '';
    private $url = '';
    private $foreign = '';
    private $payInfo = [];


    /**
     * 配置信息$config = ['url' => '一卡通服务器地址', 'foreign' => '收钱商户号']
     * 支付信息$payInfo = ['sno' => '消费者卡号', 'pwd' => '密码', 'paySn' => '自定义一个唯一的支付单号', 'amount' => '消费金额(元)']
     */
    public function __construct($config, $payInfo = [])
    {
        $this->url = trim($config['url'], '?wsdl') . '?wsdl';
        $this->foreign = $config['foreign'];
        $this->payInfo = $payInfo;
    }


    /**
     * 充值
     * @return bool
     * @throws Exception
     * @throws \SoapFault
     * @author AJie
     * @date 2020/8/27 11:19
     */
    public function doRecharge()
    {
        $payInfo = $this->payInfo;
        $params = [
            'Sno' => $payInfo['sno'],
            'Passwd' => $payInfo['pwd'],
            'foreigno' => $payInfo['paySn'],
            'tranamt' => $payInfo['amount'] * 100,
        ];
        $jsonRes = $this->getSoapResult('usertran', $params);
        $result = json_decode($jsonRes, true);
        if (!isset($result['result']) || $result['result'] != '00') {
            throw new Exception($this->errMsg. $jsonRes);
        }

        return $result['tranflowno'];
    }


    /**
     * 用户一卡通认证
     * @param $uid 用户ID
     * @return false|int
     * @throws Exception
     * @throws \SoapFault
     * @author AJie
     * @date 2020/8/22 15:09
     */
    public function checkCard($uid)
    {
        // 接口检验
        $params = [
            'Sno' => $this->payInfo['sno'],
            'Passwd' => $this->payInfo['pwd'],
        ];
        $result = $this->getSoapResult('CheckUserPid', $params);
        if ($result !== '00') {
            throw new Exception($this->errMsg.$result);
        }

        return true;
    }


    // 获取用户信息
    public function getUserInfo()
    {
        $params = [
            'Sno' => $this->payInfo['sno'],
            'Passwd' => $this->payInfo['pwd'],
        ];
        $jsonRes = $this->getSoapResult('usercardbalance', $params);
        $result = json_decode($jsonRes, true);
        if(!isset($result['err']) || $result['err'] != '00'){
            throw new Exception($this->errMsg.$jsonRes);
        }

        return $result;
    }


    /**
     * 检查充值记录
     * @param $no 交易时创建的流水号
     * @return bool
     * @throws Exception
     * @throws \SoapFault
     * @author AJie
     * @date 2020/8/22 17:32
     */
    public function checkLog($no)
    {
        $params = ['forgeinsn' => $no];
        $result = $this->getSoapResult('checkforeign', $params, false);
        if ($result !== '00') {
            throw new Exception($this->errMsg.$result);
        }
        return true;
    }


    /**
     * 请求服务器并获取结果
     * @param $action 请求方法(区分大小写)
     * @param array $params 请求数组参数(区分大小写)
     * @param bool $isNeedMd5 是否需要md5加密参数
     * @return bool|string 全等false则异常
     * @throws \SoapFault
     * @author AJie
     * @date 2020/8/22 9:15
     */
    protected function getSoapResult($action, $params = [], $isNeedMd5 = true)
    {
        try {
            $params = $isNeedMd5 ? $this->getEncryptData($params) : $params;
            $soap = new \SoapClient($this->url);
            $response = $soap->$action($params);
            $property = $action . 'Result';
            $result = trim($response->$property, '"');
        } catch (Exception $e) {
            $result = false;
            $this->errMsg = $e->getMessage();
        }

        return $result;
    }


    /**
     * 生成加密信息
     * @param array $params 加密数组
     * @return array
     * @author AJie
     * @date 2020/8/22 11:15
     */
    protected function getEncryptData($params = [])
    {
        if (!$params) {
            return $params;
        }

        if (!empty($params['Passwd'])) {
            $params['Passwd'] = openssl_encrypt($params['Passwd'], 'des-ecb', '秘钥');
        }

        $data = array_change_key_case($params);
        ksort($data);

        $str = implode('', $data);

        $params['Md5string'] = strtoupper(md5($str . '盐值'));
        return $params;
    }
}

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表回复