杉德全支付平台
注意:
需要的资料:
1.商户公钥 获取方式:先安装证书(注意:证书在收到邮件后14天内下载,并且只能下载一次),然后用IE打开https://cs.cfca.com.cn/cgi-bin/userCertDownload/v_input.do?displayAgreement=true 点击“工具—Internet选项”,查看证书,注意查看证书中的商户号是否与邮箱中发送的商户号一致,然后导出公钥
2.商户私钥 跟上边公钥导出方式一样
3.私钥证书密码 此密码是公钥导出时设置的密码
开始步骤
1.根据收到的开通邮件,找到登陆CFCA官网数字证书下载平台https://cs.cfca.com.cn/cgi-bin/userCertDownload/v_input.do?displayAgreement=true,使用本邮件提供的证书序列号和授权码,下载加密证书安装,然后再按流程导出商户公钥(后缀为 .cer)和商户私钥(文件后缀为.pfx)文件 公钥私钥导出手册:https://open.sandpay.com.cn/developmentAccess/guide?msg=6684
2.使用邮箱中的商户号去开放平台注册账号,然后在开放平台-参数设置中上传该公钥,完成编辑后请刷新页面查看审核状态。状态显示为“已审核”后1小时左右生效,请耐心等待。(需要注册并登录,注册时使用开户邮件中的商户号注册)
3.找到开发文档 https://open.sandpay.com.cn//developmentAccess/moredoc?openpage=demo 接口文档中提供有demo 然后下载对应的demo 文件
4.将之前的 公钥,私钥,私钥密码,商户号配置好,将下载好的公钥,私钥文件放到项目cert文件下,然后配置好,获取私钥路径
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/11/15
* Time: 15:21
*/
namespace app\v1\controller;
use app\common\controller\Checking;
use app\common\controller\Factory;
use merchants\Configs;
use merchants\WithdrawBank;
use think\Controller;
use think\Db;
use think\Exception;
class UnionPay extends Controller
{
protected $mid='';//商户号 100211701160001
protected $notifyUrl='';//异步回调地址
protected $frontUrl='http://api.yfr2018.com/v1/notify/check_bank?order_id=';//同步回调地址
public function webPay(){
$out_trade_no = $_GET['orderId']; //商户网站唯一订单号
$orders=$this->query($out_trade_no);
if ($orders['head']['respCode']=='000000'){
if ($orders['body']['orderStatus']!='00'){
#订单支付失败修改订单号
$orderModel = Factory::createModel( 'orders' );
$out_trade_no=Checking::ordeSnByUnique( 'pay_order_num', $orderModel );
Db::name('orders')->where(['pay_order_num'=>$_GET['orderId']])->update(['pay_order_num'=>$out_trade_no,'last_order_num'=>$_GET['orderId']]);
}
}
$order=Db::name('orders')->where(['pay_order_num'=>$out_trade_no])->find();
$money=$order['real_price']*100;
$data = array(
'head' => array(
'version' => '1.0',
'method' => 'sandPay.fastPay.quickPay.index',
'productId' => '00000016',
'accessType' => '1',
'mid' => $this->mid,
'channelType' => '07',
'reqTime' => date('YmdHis', time())
),
'body' => array(
'userId' => $order['user_id'],
'orderCode' => $order['pay_order_num'],//商户订单号
'orderTime' => date('YmdHis',strtotime($order['create_time'])+86400),
'totalAmount' => str_pad($money,'12',0,STR_PAD_LEFT),
'subject' => '悦芙蓉',//订单标题
'body' =>'悦芙蓉',//订单描述
'currencyCode' => '156',//币种
'notifyUrl' => $this->notifyUrl,
'frontUrl' => $this->frontUrl.$out_trade_no,
'clearCycle' => '0',
'extend' => ''
)
);
// step2: 私钥签名
$prikey = loadPk12Cert(PRI_KEY_PATH, CERT_PWD);
$sign = sign($data, $prikey);
// step3: 拼接post数据
$post = array(
'charset' => 'utf-8',
'signType' => '01',
'data' => json_encode($data),
'sign' => urlencode($sign)
);
// step4: post请求
$url = 'https://cashier.sandpay.com.cn/fastPay/quickPay/index';
$html_form = createAutoFormHtml( $post, $url );
return $html_form;
}
/**
* 订单查询
*/
public function query($order_id){
$data = array(
'head' => array(
'version' => '1.0',
'method' => 'sandpay.trade.query',
'productId' => '00000016',
'accessType' => '1',
'mid' => $this->mid,
'channelType' => '07',
'reqTime' => date('YmdHis', time())
),
'body' => array(
'orderCode' => $order_id,//商户订单号
'extend' => ''
)
);
// step2: 私钥签名
$prikey = loadPk12Cert(PRI_KEY_PATH, CERT_PWD);
$sign = sign($data, $prikey);
// step3: 拼接post数据
$post = array(
'charset' => 'utf-8',
'signType' => '01',
'data' => json_encode($data),
'sign' => urlencode($sign)
);
// step4: post请求
$result = http_post_json('https://cashier.sandpay.com.cn/gateway/api/order/query', $post);
$arr = parse_result($result);
//step5: 公钥验签
// $pubkey = loadX509Cert(PUB_KEY_PATH);
// try {
// verify($arr['data'], $arr['sign'], $pubkey);
// } catch (Exception $e) {
// echo $e->getMessage();
// exit;
// }
// step6: 获取credential
$data = json_decode($arr['data'], true);
// if ($data['orderStatus']){
//
// }
return $data;
}
/**
* 实时代收
*/
public function agentpay(){
dump(11);
$getConfig=Config::getConfig();
halt($getConfig);
$config=Config::Config();
$info=$getConfig['agentpay'];
// step1: 拼接报文及配置
$transCode = $info['transCode']; // 交易码
$accessType = '0'; // 接入类型 0-商户接入,默认;1-平台接入
$merId = $info['merId']; // 此处更换商户号
$path = $info['url']; // 服务地址
$pt = $info['pt']; // 报文
// step2: 生成AESKey并使用公钥加密
$with=new WithdrawBank();
$AESKey = aes_generate(16);
$encryptKey = $with->RSAEncryptByPub($AESKey, $config['pubKey']);
// step3: 使用AESKey加密报文
$encryptData = $with->AESEncrypt($pt, $AESKey);
// step4: 使用私钥签名报文
$sign = $with->sign($pt, $config['priKey']);
// step5: 拼接post数据
$post = array(
'transCode' => $transCode,
'accessType' => $accessType,
'merId' => $merId,
'encryptKey' => $encryptKey,
'encryptData' => $encryptData,
'sign' => $sign
);
// step6: post请求
$result = $with->http_post_json(API_HOST . $path, $post);
parse_str($result, $arr);
try {
// step7: 使用私钥解密AESKey
$decryptAESKey = $with->RSADecryptByPri($arr['encryptKey'], $config['priKey']);
// step8: 使用解密后的AESKey解密报文
$decryptPlainText =$with->AESDecrypt($arr['encryptData'], $decryptAESKey);
// step9: 使用公钥验签报文
$with->verify($decryptPlainText, $arr['sign'], $config['pubKey']);
} catch (Exception $e) {
echo $e->getMessage();
exit;
}
print_r($decryptPlainText);
}
}
下边是用到的方法,代码没有整理
function createAutoFormHtml($params, $reqUrl) {
$encodeType = isset ( $params ['encoding'] ) ? $params ['encoding'] : 'UTF-8';
$html = <<<eot
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset={$encodeType}" />
</head>
<body onload="javascript:document.sandpay.submit();">
<form id="sandpay" name="sandpay" action="{$reqUrl}" method="post">
eot;
foreach ( $params as $key => $value ) {
$html .= " <textarea name=\"{$key}\" hidden='hidden' id=\"{$key}\">{$value}</textarea>\n";
}
$html .= <<<eot
</form>
</body>
</html>
eot;
return $html;
}
/**
* 获取私钥
* @param $path
* @param $pwd
* @return mixed
* @throws Exception
*/
function loadPk12Cert($path, $pwd)
{
try {
$file = file_get_contents($path);
if (!$file) {
throw new \Exception('loadPk12Cert::file
_get_contents');
}
if (!openssl_pkcs12_read($file, $cert, $pwd)) {
throw new \Exception('loadPk12Cert::openssl_pkcs12_read ERROR');
}
return $cert['pkey'];
} catch (\Exception $e) {
throw $e;
}
}
/**
* 获取公钥
* @param $path
* @return mixed
* @throws Exception
*/
function loadX509Cert($path)
{
try {
$file = file_get_contents($path);
if (!$file) {
throw new \Exception('loadx509Cert::file_get_contents ERROR');
}
$cert = chunk_split(base64_encode($file), 64, "\n");
$cert = "-----BEGIN CERTIFICATE-----\n" . $cert . "-----END CERTIFICATE-----\n";
$res = openssl_pkey_get_public($cert);
$detail = openssl_pkey_get_details($res);
openssl_free_key($res);
if (!$detail) {
throw new \Exception('loadX509Cert::openssl_pkey_get_details ERROR');
}
return $detail['key'];
} catch (\Exception $e) {
throw $e;
}
}
/**
* 私钥签名
* @param $plainText
* @param $path
* @return string
* @throws Exception
*/
function sign($plainText, $path)
{
$plainText = json_encode($plainText);
try {
$resource = openssl_pkey_get_private($path);
$result = openssl_sign($plainText, $sign, $resource);
openssl_free_key($resource);
if (!$result) {
throw new \Exception('签名出错' . $plainText);
}
return base64_encode($sign);
} catch (\Exception $e) {
throw $e;
}
}
/**
* 公钥验签
* @param $plainText
* @param $sign
* @param $path
* @return int
* @throws Exception
*/
function verify($plainText, $sign, $path)
{
$resource = openssl_pkey_get_public($path);
$result = openssl_verify($plainText, base64_decode($sign), $resource);
openssl_free_key($resource);
if (!$result) {
throw new \Exception('签名验证未通过,plainText:' . $plainText . '。sign:' . $sign, '02002');
}
return $result;
}
/**
* 发送请求
* @param $url
* @param $param
* @return bool|mixed
* @throws Exception
*/
function http_post_json($url, $param)
{
if (empty($url) || empty($param)) {
return false;
}
$param = http_build_query($param);
try {
$ch = curl_init();//初始化curl
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//正式环境时解开注释
// curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
// curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$data = curl_exec($ch);//运行curl
curl_close($ch);
// halt($data);
if (!$data) {
throw new \Exception('请求出错');
}
return $data;
} catch (\Exception $e) {
throw $e;
}
}
function parse_result($result)
{
$arr = array();
$response = urldecode($result);
$arrStr = explode('&', $response);
foreach ($arrStr as $str) {
$p = strpos($str, "=");
$key = substr($str, 0, $p);
$value = substr($str, $p + 1);
$arr[$key] = $value;
}
return $arr;
}