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程序设计有所帮助。