编写一卡通的PHP版SDK
如今社会中的支付已形成支付宝老大、微信老二的趋势,各种老式的支付方式已被冲淡到角落,新兴的其他支付方式对支付宝和微信来说也形成不了威胁。
就比如今天的主角一卡通,也只能龟缩在某一特定小区域中瑟瑟发抖。 这些特定环境有学校或某个企业,因各种利益和其他因素的牵扯,暂时还在顽强的挣扎。
所以当我们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;
}
}