php银联网页支付实现方法
本文实例讲述了php银联网页支付实现方法。分享给大家供大家参考。具体分析如下:
这里介绍的银联WAP支付功能,仅限消费功能。
1.PHP代码如下:
<?php
namespacecommon\services;
classUnionPay
{
/**
*支付配置
*@vararray
*/
public$config=[];
/**
*支付参数,提交到银联对应接口的所有参数
*@vararray
*/
public$params=[];
/**
*自动提交表单模板
*@varstring
*/
private$formTemplate=<<<'HTML'
<!DOCTYPEHTML>
<html>
<head>
<metacharset="utf-8">
<title>支付</title>
</head>
<body>
<divstyle="text-align:center">跳转中...</div>
<formid="pay_form"name="pay_form"action="%s"method="post">
%s
</form>
<scripttype="text/javascript">
document.onreadystatechange=function(){
if(document.readyState=="complete"){
document.pay_form.submit();
}
};
</script>
</body>
</html>
HTML;
/**
*构建自动提交HTML表单
*@returnstring
*/
publicfunctioncreatePostForm()
{
$this->params['signature']=$this->sign();
$input='';
foreach($this->paramsas$key=>$item){
$input.="\t\t<inputtype=\"hidden\"name=\"{$key}\"value=\"{$item}\">\n";
}
returnsprintf($this->formTemplate,$this->config['frontUrl'],$input);
}
/**
*验证签名
*验签规则:
*除signature域之外的所有项目都必须参加验签
*根据key值按照字典排序,然后用&拼接key=value形式待验签字符串;
*然后对待验签字符串使用sha1算法做摘要;
*用银联公钥对摘要和签名信息做验签操作
*
*@throws\Exception
*@returnbool
*/
publicfunctionverifySign()
{
$publicKey=$this->getVerifyPublicKey();
$verifyArr=$this->filterBeforSign();
ksort($verifyArr);
$verifyStr=$this->arrayToString($verifyArr);
$verifySha1=sha1($verifyStr);
$signature=base64_decode($this->params['signature']);
$result=openssl_verify($verifySha1,$signature,$publicKey);
if($result===-1){
thrownew\Exception('VerifyError:'.openssl_error_string());
}
return$result===1?true:false;
}
/**
*取签名证书ID(SN)
*@returnstring
*/
publicfunctiongetSignCertId()
{
return$this->getCertIdPfx($this->config['signCertPath']);
}
/**
*签名数据
*签名规则:
*除signature域之外的所有项目都必须参加签名
*根据key值按照字典排序,然后用&拼接key=value形式待签名字符串;
*然后对待签名字符串使用sha1算法做摘要;
*用银联颁发的私钥对摘要做RSA签名操作
*签名结果用base64编码后放在signature域
*
*@throws\InvalidArgumentException
*@returnmultitype|string
*/
privatefunctionsign(){
$signData=$this->filterBeforSign();
ksort($signData);
$signQueryString=$this->arrayToString($signData);
if($this->params['signMethod']==01){
//签名之前先用sha1处理
//echo$signQueryString;exit;
$datasha1=sha1($signQueryString);
$signed=$this->rsaSign($datasha1);
}else{
thrownew\InvalidArgumentException('NonsupportSignMethod');
}
return$signed;
}
/**
*数组转换成字符串
*@paramarray$arr
*@returnstring
*/
privatefunctionarrayToString($arr)
{
$str='';
foreach($arras$key=>$value){
$str.=$key.'='.$value.'&';
}
returnsubstr($str,0,strlen($str)-1);
}
/**
*过滤待签名数据
*signature域不参加签名
*
*@returnarray
*/
privatefunctionfilterBeforSign()
{
$tmp=$this->params;
unset($tmp['signature']);
return$tmp;
}
/**
*RSA签名数据,并base64编码
*@paramstring$data待签名数据
*@returnmixed
*/
privatefunctionrsaSign($data)
{
$privatekey=$this->getSignPrivateKey();
$result=openssl_sign($data,$signature,$privatekey);
if($result){
returnbase64_encode($signature);
}
returnfalse;
}
/**
*取.pfx格式证书ID(SN)
*@returnstring
*/
privatefunctiongetCertIdPfx($path)
{
$pkcs12certdata=file_get_contents($path);
openssl_pkcs12_read($pkcs12certdata,$certs,$this->config['signCertPwd']);
$x509data=$certs['cert'];
openssl_x509_read($x509data);
$certdata=openssl_x509_parse($x509data);
return$certdata['serialNumber'];
}
/**
*取.cer格式证书ID(SN)
*@returnstring
*/
privatefunctiongetCertIdCer($path)
{
$x509data=file_get_contents($path);
openssl_x509_read($x509data);
$certdata=openssl_x509_parse($x509data);
return$certdata['serialNumber'];
}
/**
*取签名证书私钥
*@returnresource
*/
privatefunctiongetSignPrivateKey()
{
$pkcs12=file_get_contents($this->config['signCertPath']);
openssl_pkcs12_read($pkcs12,$certs,$this->config['signCertPwd']);
return$certs['pkey'];
}
/**
*取验证签名证书
*@throws\InvalidArgumentException
*@returnstring
*/
privatefunctiongetVerifyPublicKey()
{
//先判断配置的验签证书是否银联返回指定的证书是否一致
if($this->getCertIdCer($this->config['verifyCertPath'])!=$this->params['certId']){
thrownew\InvalidArgumentException('Verifysigncertisincorrect');
}
returnfile_get_contents($this->config['verifyCertPath']);
}
}2.配置示例
//银联支付设置
'unionpay'=>[
//测试环境参数
'frontUrl'=>'https://101.231.204.80:5000/gateway/api/frontTransReq.do',//前台交易请求地址
//'singleQueryUrl'=>'https://101.231.204.80:5000/gateway/api/queryTrans.do',//单笔查询请求地址
'signCertPath'=>__DIR__.'/../keys/unionpay/test/sign/700000000000001_acp.pfx',//签名证书路径
'signCertPwd'=>'000000',//签名证书密码
'verifyCertPath'=>__DIR__.'/../keys/unionpay/test/verify/verify_sign_acp.cer',//验签证书路径
'merId'=>'xxxxxxx',
//正式环境参数
//'frontUrl'=>'https://101.231.204.80:5000/gateway/api/frontTransReq.do',//前台交易请求地址
//'singleQueryUrl'=>'https://101.231.204.80:5000/gateway/api/queryTrans.do',//单笔查询请求地址
//'signCertPath'=>__DIR__.'/../keys/unionpay/test/sign/PM_700000000000001_acp.pfx',//签名证书路径
//'signCertPwd'=>'000000',//签名证书密码
//'verifyCertPath'=>__DIR__.'/../keys/unionpay/test/verify/verify_sign_acp.cer',//验签证书路径
//'merId'=>'xxxxxxxxx',//商户代码
],3.支付示例
$unionPay=newUnionPay();
$unionPay->config=Yii::$app->params['unionpay'];//上面的配置
$unionPay->params=[
'version'=>'5.0.0',//版本号
'encoding'=>'UTF-8',//编码方式
'certId'=>$unionPay->getSignCertId(),//证书ID
'signature'=>'',//签名
'signMethod'=>'01',//签名方式
'txnType'=>'01',//交易类型
'txnSubType'=>'01',//交易子类
'bizType'=>'000201',//产品类型
'channelType'=>'08',//渠道类型
'frontUrl'=>Url::toRoute(['payment/unionpayreturn'],true),//前台通知地址
'backUrl'=>Url::toRoute(['payment/unionpaynotify'],true),//后台通知地址
//'frontFailUrl'=>Url::toRoute(['payment/unionpayfail'],true),//失败交易前台跳转地址
'accessType'=>'0',//接入类型
'merId'=>Yii::$app->params['unionpay']['merId'],//商户代码
'orderId'=>$orderNo,//商户订单号
'txnTime'=>date('YmdHis'),//订单发送时间
'txnAmt'=>$sum*100,//交易金额,单位分
'currencyCode'=>'156',//交易币种
];
$html=$unionPay->createPostForm();4.异步通知示例
$unionPay=newUnionPay();
$unionPay->config=Yii::$app->params['unionpay'];
$unionPay->params=Yii::$app->request->post();//银联提交的参数
if(empty($unionPay->params)){
return'fail!';
}
if($unionPay->verifySign()&&$unionPay->params['respCode']=='00'){
//.......
}
希望本文所述对大家的php程序设计有所帮助。