0

0

PHP银联在线支付接口的开发实例

小云云

小云云

发布时间:2018-03-01 13:48:12

|

13101人浏览过

|

来源于php中文网

原创

本文主要和大家分享php银联在线支付接口的开发实例,希望能帮助到大家。

1、 登录银联自助化测试平台(登陆地址:open.unionpay.com),登录后,点击我的产品,如下:点击右方需要测试的接口,本例以 手机网页支付(WAP支付)为例。

这里写图片描述 
这里写图片描述 
2、 点击左侧菜单 测试参数,即可看到测试过程所需要的参数,如下图:点击测试证书,下载两个证书,一个是以后缀 .pfx 的私钥证书,一个是后缀 .cer 的公钥证书,将其下载后,私钥证书文件名称修改为 acp_test_sign.pfx 。或者你不下载的话,直接用本例子的也可以。TP3.2例子 里面 Public/cer 里面已有所有证书文件。 
这里写图片描述

3、 TP3.2例子里面已有相关代码可以用来测试,测试的时候请使用测试环境的参数,代码中均有注释。在开始之前要确保你的环境PHP版本基于5.3,需开启curl、openssl功能,还有测试要放在线上测试,本地的虚拟域名是不行的。如遇到什么问题,可以参考官方的说明,本文件夹里面有个 PHP Version SDK 是官方的文档,参考里面的说明就好了,他们那个例子我测试的时候也跑不起来,不知道什么鬼原因。 
4、 切换到生产环境,注意以下问题: 
4.1 首先根据你收到的商户开通邮件里面的指示,访问网站 http://cs.cfca.com.cn/ 
下载生产证书文件: 
这里写图片描述 
点击下载后,完成下载操作后,页面会出现下载成功的提示。下载的证书自动存放在IE中,下一步就要进行证书的导出。 
这里写图片描述 
4.2 导出证书文件:打开IE浏览器,点击右上角的齿轮,打开工具=》Internet选项=》内容=》证书,如图: 
这里写图片描述

点击证书后,找到刚刚下载的那个证书,你可以根据名称去辨别,商户邮件中有标注: 
这里写图片描述 
上图中红色标注的名称应该跟你下载的那个名称一样。 
这里写图片描述 
找到它,然后点击导出:一路的下一步,在以下几步需要注意

立即学习PHP免费学习笔记(深入)”;

这里写图片描述

这里写图片描述

这里写图片描述

以上密码就是 config.php 里面生产环境要设置的那个密码,请设置为六位数字(仅限数字,请勿设置字母及符号)

指定导出证书的文件名,名称就设置为:acp_prod_sign,并选择目录存放证书,点击下一步,设置导出到桌面,完成后将在桌面看到一个 acp_prod_sign.pfx 的文件。这个就是生产环境要用到的私钥文件,将它复制一份到证书目录 /Public/cer 。下一步就要上传这个证书到商户服务网站。

4.2 上传证书到商户服务网站。登录 https://merchant.unionpay.com/portal/login.jsp 
这里写图片描述 
上传刚刚导出的那个 acp_prod_sign.pfx 文件,点击上传。

聚彩手机网店系统 免费版
聚彩手机网店系统 免费版

聚彩手机商城系统,是一款专业于手机销售的独立手机网店系统,他拥有众多的手机参数选项,以及傻瓜式的设置选项,让您可以在5分钟内建立起专业而强大的手机销售网站。他拥有多套模版可以实时切换,前台拥有新闻中心、手机中心、配件中心、软件下载、手机报价、发货查询、保修查询、分店查询、产品的对比功能,代理与加盟的申请等功能,他拥有完善的会员中心,会员等级设置等,集成在线支付接口,超强SEO,可以设置所有页面的t

下载

下一步,启用证书,点击安全证书管理,启用即可。 
这里写图片描述

下一步,下载银联公钥 
这里写图片描述 
解压文件,把里面的两个证书同样放到 /Public/cer 里面。然后就去 config.php 里面根据文件注释切换到生产环境即可。

这里写图片描述

以下是TP3.2的代码资料: 
/App/Home/Conf/config.php

'配置值'

    'UNIONPAY' => array(// 银联配置
                //测试环境参数
                'frontUrl' => 'https://101.231.204.80:5000/gateway/api/frontTransReq.do', //测试环境前台交易请求地址
                //'frontUrl' => 'https://gateway.95516.com/gateway/api/frontTransReq.do', //生产环境前台交易请求地址

                'singleQueryUrl' => 'https://101.231.204.80:5000/gateway/api/backTransReq.do', //测试环境单笔查询请求地址
                //'singleQueryUrl' => 'https://gateway.95516.com/gateway/api/queryTrans.do', //生产环境单笔查询请求地址

                'signCertPath' =>getcwd().'/Public/cer/acp_test_sign.pfx', //签名证书路径 这个证书就是你在https://open.unionpay.com/ajweb/account/testPara 上面下载的那个商户私钥证书 供你测试使用 
                //'signCertPath' =>getcwd().'/Public/cer/acp_prod_sign.pfx', //签名证书路径 这个证书就是你在 商户开通邮件里面叫你去 http://cs.cfca.com.cn/ 下载并把私钥上传至商户服务网站并启用的那个私钥文件

                'signCertPwd' => '000000', //测试环境签名证书密码
                //'signCertPwd' => '135246', //生产环境证书签名证书密码 这个密码是你在IE导出上述私钥文件时候你自己定义的6位数字密码 

                //'verifyCertPath' => getcwd().'/Public/cer/verify_sign_acp.cer', //测试环境验签证书路径
                'verifyCertPath' => getcwd().'/Public/cer/acp_prod_verify_sign.cer', //验签证书路径

                'merId' => '777290058138754', //测试商户代码
                //'merId' => '8024400481****', //生产环境商户代码 从你的商户开通邮件里面有


        ),        'UNIONPAY_CONFIG'=>array(// 银联配置
                'version' => '5.0.0', //版本号
                'encoding' => 'GBK', //编码方式
                'signMethod' => '01', //签名方式
                'txnType' => '01', //交易类型
                'txnSubType' => '01', //交易子类
                'bizType' => '000201', //产品类型
                'channelType' => '07',//渠道类型
                'frontUrl' => "http://win2.qbt8.com/ase_admin/index.php/Home/ypay/pay_success", //前台通知地址
                'backUrl' => "http://win2.qbt8.com/ase_admin/index.php/Home/ypay/notify", //后台通知地址
                'frontFailUrl' => "http://win2.qbt8.com/ase_admin/index.php/Home/ypay/pay_fail", //失败交易前台跳转地址
                'accessType' => '0', //接入类型
                'merId' => '777290058138754', //测试商户代码
                //'merId' => '8024400481*****', //生产环境商户代码
                'txnTime' => date('YmdHis'), //订单发送时间
                'currencyCode' => '156', //交易币种
        ),
);?>

控制器代码如下:


        
        
                
                支付
        
        
                

跳转中...

%s
HTML; public function index(){ //前台表单 $this->display(); } /*支付成功后 前台通知地址*/ public function pay_success(){ echo "

支付成功!

"; } /*失败交易前台跳转地址*/ public function pay_fail(){ echo "

支付失败!

"; } /*生产支付参数 提交支付 */ function usespay(){ $this->config = C('UNIONPAY');//从配置里读取 $config = C('UNIONPAY_CONFIG'); $config['certId'] = $this->getSignCertId(); //证书ID $config['orderId'] = mt_rand(111111111,999999999);//订单号 自定义 $config['txnAmt'] = I("post.money")*100; //交易金额,单位分 $this->params = $config; // $_SESSION['ceshi']=$config; /* 以下是自己的业务逻辑操作 生产支付记录到本地数据库 $money = I("post.money");; $user_id = $this->user_id; $OrderId = $config['orderId'];//生成随机订单号 $pay_type = "银联";//支付方式 1余额 2支付宝 $pay_fee = M('handfee')->find(2); if ($pay_fee['type'] == 1){ $fee=$pay_fee['rate']*$money; }else { $fee=$pay_fee['fee']; } //订单表数据 $order = array( "order_id"=>$OrderId, "uid"=>$user_id, "pay_mode"=>1, "pay_channels"=>2, "fee"=>$fee, "status"=>0,//待审核 "beizhu"=>"银联在线充值", "ent_money"=>$money-$fee, "time"=>time(), "sub_time"=>time(), "pay_money"=>$money, "pay_type"=>$pay_type,//1余额支付 2支付宝支付 //"type"=>2 );*/ //$Ord=M('pay'); //$Ord->add($order); $html = $this->createPostForm();//构建自动提交HTML表单 echo $html; } function ceshi(){ dump($_SESSION); } function usernotify(){// 付款后返回商家 } function notify(){//后台通知路径 /*付款后业务逻辑代码 */ $orderId = $_POST ['orderId']; //其他字段也可用类似方式获取 $respCode = $_POST ['respCode']; //判断respCode=00或A6即可认为交易成功 if ($respCode=='00'||$respCode=='A6'){ /*通过写入文件的方式记录返回的订单号等 */ $str = "--------- ".date('Y-m-d H:i:s')." ---------"; $str .= "orderId:".$orderId."\r\n"; $str .= "respCode:".$respCode."\r\n"; $str .= "--------- END -----------"."\r\n"; file_put_contents('unionpay_notify_log.log', $str); /* 以下是支付成功后的数据库操作 请根据需要自行操作 $order['status']=1; $order['check_time']=time(); M('pay')->where(array('order_id'=>$orderId))->save($order); $order_info = M('pay')->where(array('order_id'=>$orderId))->find(); $log['user_id']=$order_info['uid']; $log['user_money']=$order_info['pay_money']; $log['change_time']=time(); $log['desc']="银联在线充值"; M('account_log')->add($log); M('users')->where('user_id='.$order_info['uid'])->setInc('user_money',$order_info['ent_money']); */ } } function unionpayfail(){ } /* function orderPay($orderinfo,$state){ $filename = 'Log/yapy'; file_put_contents($filename.'/'.$orderinfo['orderId'].'.txt', json_encode($_POST), FILE_APPEND); //$order = D('order'); //$payment = D('payment'); //$where['order_sn'] = array('in', array($orderinfo['orderId'])); //$orinfo = $order->where($where)->find(); $rs = $payment->where($where)->find(); if (empty($rs) && $orinfo['order_state'] < 2 ) { $where1['udb_user.user_id'] = array('eq', session('id')); $userinfo1 = json_decode(req_api("api_key", C("API_KEY"), C('USER_API') ."user/api/GetSomeuser/", array('where' => json_encode($where1))), true); $data1['order_state'] = (int) $state; //$orderwhere['order_sn'] = array('in', array($orderinfo['orderId'])); //$order->where($orderwhere)->save($data1); if($orinfo['balance'] >0 && $orinfo['isblance'] == 1){ if($userinfo1[0]['balance']-$orinfo['balance']>=0){ $total1 = $total1-$data['balance']; $istrue = req_api("api_key", C("API_KEY"), C('USER_API') . "user/api/removeBalance/", array('user' =>session('id'),'count'=>$orinfo['balance'],'type'=>'d')); //$this->BanlanceRecord(2,$orinfo['balance'],'购物消费',session('id')); } } if ($orinfo['jindou'] >0 && $orinfo['isjindou'] == 1) { if($userinfo1[0]['user_wealth']-$orinfo['jindou']>=0){ $istrue = req_api("api_key", C("API_KEY"), C('USER_API') . "user/api/AddJindou/", array('user' =>session('id'),'count'=>$orinfo['jindou'],'type'=>'d')); $this->ChangeRecord(2,$orinfo['jindou'],'购物抵消',session('id')); $total1 = $total1-($orinfo['jindou']/100); } } $data['order_sn'] = $orderinfo['orderId']; $data['buyer_id'] = $orderinfo['certId']; $data['buyer_user'] = '银联支付'; $data['is_success'] = 'T'; $data['notify_time'] = substr($orderinfo['txnTime'],0,4)."-".substr($orderinfo['txnTime'],4,2).'-'.substr($orderinfo['txnTime'],6,2).' '.substr($orderinfo['txnTime'],8,2).':'.substr($orderinfo['txnTime'],10,2).':'.substr($orderinfo['txnTime'],12,2); $data['trade_no'] = $orderinfo['queryId']; $data['seller_id'] = $orderinfo['merId']; $data['total_fee'] = $orderinfo['txnAmt']*100; $data['sign'] = $orderinfo['signature']; $data['user_id'] = $orinfo['user_id']; $data['order_state'] = (int) $state; $data['status'] = 0; $payment->data($data)->filter('strip_tags')->add(); } $record = A('Shop/Orderrecord'); $shuju['order_state'] = (string) $state; $shuju['action_user_id'] = session('id'); $shuju['action_descrption'] = $type.'支付宝付款' . $orinfo['payable_total']; $record->ChangeOrderRecords($orinfo['_id'], $shuju); $orderrecord = A('Shop/Order'); $orderrecord->CashMoneyRecord(2, $orinfo['payable_total'], '购物消费--订单(' . $orderinfo['out_trade_no'] . ')', session('id')); layout(false); $this->assign('orderinfo', $orinfo); $this->display('Order:PaySuccess6'); } */ /** * 构建自动提交HTML表单 * @return string */ public function createPostForm() { $this->params['signature'] = $this->sign(); $input = ''; foreach($this->params as $key => $item) { $input .= "\t\t\n"; } return sprintf($this->formTemplate, $this->config['frontUrl'], $input); } /** * 验证签名 * 验签规则: * 除signature域之外的所有项目都必须参加验签 * 根据key值按照字典排序,然后用&拼接key=value形式待验签字符串; * 然后对待验签字符串使用sha1算法做摘要; * 用银联公钥对摘要和签名信息做验签操作 * * @throws \Exception * @return bool */ public function verifySign() { $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) { // throw new \Exception('Verify Error:'.openssl_error_string()); echo 'Verify Error:'.openssl_error_string(); } return $result === 1 ? true : false; } /** * 取签名证书ID(SN) * @return string */ public function getSignCertId() { return $this->getCertIdPfx($this->config['signCertPath']); } /** * 签名数据 * 签名规则: * 除signature域之外的所有项目都必须参加签名 * 根据key值按照字典排序,然后用&拼接key=value形式待签名字符串; * 然后对待签名字符串使用sha1算法做摘要; * 用银联颁发的私钥对摘要做RSA签名操作 * 签名结果用base64编码后放在signature域 * * @throws \InvalidArgumentException * @return multitype|string */ private function sign() { $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 { //throw new \InvalidArgumentException('Nonsupport Sign Method'); echo 'Nonsupport Sign Method'; } return $signed; } /** * 数组转换成字符串 * @param array $arr * @return string */ private function arrayToString($arr) { $str = ''; foreach($arr as $key => $value) { $str .= $key.'='.$value.'&'; } return substr($str, 0, strlen($str) - 1); } /** * 过滤待签名数据 * signature域不参加签名 * * @return array */ private function filterBeforSign() { $tmp = $this->params; unset($tmp['signature']); return $tmp; } /** * RSA签名数据,并base64编码 * @param string $data 待签名数据 * @return mixed */ private function rsaSign($data) { $privatekey = $this->getSignPrivateKey(); $result = openssl_sign($data, $signature, $privatekey); if($result) { return base64_encode($signature); } return false; } /** * 取.pfx格式证书ID(SN) * @return string */ private function getCertIdPfx($path) { $data = fopen($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) * @return string */ private function getCertIdCer($path) { $x509data = file_get_contents($path); openssl_x509_read($x509data); $certdata = openssl_x509_parse($x509data); return $certdata['serialNumber']; } /** * 取签名证书私钥 * @return resource */ private function getSignPrivateKey() { $pkcs12 = file_get_contents($this->config['signCertPath']); openssl_pkcs12_read($pkcs12, $certs, $this->config['signCertPwd']); return $certs['pkey']; } /** * 取验证签名证书 * @throws \InvalidArgumentException * @return string */ private function getVerifyPublicKey() { //先判断配置的验签证书是否银联返回指定的证书是否一致 if($this->getCertIdCer($this->config['verifyCertPath']) != $this->params['certId']) { // throw new \InvalidArgumentException('Verify sign cert is incorrect'); echo 'Verify sign cert is incorrect'; } return file_get_contents($this->config['verifyCertPath']); } }

视图文件内容如下:


    
    银联支付测试
    

银联支付测试

支付金额:

证书文件这里上传不了,放个截图好了,都可以自己去下载的: 
这里写图片描述

相关推荐:

PHP实现的交通银行网银在线支付接口ECSHOP插件和使用例子

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
curl_exec
curl_exec

curl_exec函数是PHP cURL函数列表中的一种,它的功能是执行一个cURL会话。给大家总结了一下php curl_exec函数的一些用法实例,这个函数应该在初始化一个cURL会话并且全部的选项都被设置后被调用。他的返回值成功时返回TRUE, 或者在失败时返回FALSE。

441

2023.06.14

linux常见下载安装工具
linux常见下载安装工具

linux常见下载安装工具有APT、YUM、DNF、Snapcraft、Flatpak、AppImage、Wget、Curl等。想了解更多linux常见下载安装工具相关内容,可以阅读本专题下面的文章。

178

2023.10.30

硬盘接口类型介绍
硬盘接口类型介绍

硬盘接口类型有IDE、SATA、SCSI、Fibre Channel、USB、eSATA、mSATA、PCIe等等。详细介绍:1、IDE接口是一种并行接口,主要用于连接硬盘和光驱等设备,它主要有两种类型:ATA和ATAPI,IDE接口已经逐渐被SATA接口;2、SATA接口是一种串行接口,相较于IDE接口,它具有更高的传输速度、更低的功耗和更小的体积;3、SCSI接口等等。

1155

2023.10.19

PHP接口编写教程
PHP接口编写教程

本专题整合了PHP接口编写教程,阅读专题下面的文章了解更多详细内容。

214

2025.10.17

php8.4实现接口限流的教程
php8.4实现接口限流的教程

PHP8.4本身不内置限流功能,需借助Redis(令牌桶)或Swoole(漏桶)实现;文件锁因I/O瓶颈、无跨机共享、秒级精度等缺陷不适用高并发场景。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

1947

2025.12.29

java接口相关教程
java接口相关教程

本专题整合了java接口相关内容,阅读专题下面的文章了解更多详细内容。

22

2026.01.19

http500解决方法
http500解决方法

http500解决方法有检查服务器日志、检查代码错误、检查服务器配置、检查文件和目录权限、检查资源不足、更新软件版本、重启服务器或寻求专业帮助等。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

432

2023.11.09

http请求415错误怎么解决
http请求415错误怎么解决

解决方法:1、检查请求头中的Content-Type;2、检查请求体中的数据格式;3、使用适当的编码格式;4、使用适当的请求方法;5、检查服务器端的支持情况。更多http请求415错误怎么解决的相关内容,可以阅读下面的文章。

419

2023.11.14

C++ 设计模式与软件架构
C++ 设计模式与软件架构

本专题深入讲解 C++ 中的常见设计模式与架构优化,包括单例模式、工厂模式、观察者模式、策略模式、命令模式等,结合实际案例展示如何在 C++ 项目中应用这些模式提升代码可维护性与扩展性。通过案例分析,帮助开发者掌握 如何运用设计模式构建高质量的软件架构,提升系统的灵活性与可扩展性。

14

2026.01.30

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Node.js 教程
Node.js 教程

共57课时 | 9.8万人学习

Rust 教程
Rust 教程

共28课时 | 5.1万人学习

Vue 教程
Vue 教程

共42课时 | 7.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号