银联支付笔记


银联支付相关笔记

	银联开放平台:
		https://open.unionpay.com

	商家中心:
		https://merchant.unionpay.com

	ping++ 聚合支付(看着不错):
		https://www.pingxx.com/

	参考文章:
		// 该文件非常不错,注册、测试整个流程都有,一步一步都有图文介绍
		https://blog.csdn.net/zyw_java/article/details/78167481

	关于银联支付要求的前、后台通知链接,要求是外网地址,我们自己可以搭建 ngrok,或使用网上免费或付费产品,搭建 ngork 也很简单,查看笔记

总结下:
	整个支付测试还是很简单的。

	官网下载下来 PHP-SDK,然后部署到本地,访问各个页面即可测试接口。

	需要注意的几点:
		1.sdk/acp_sdk.ini 配置文件里的:前、后台地址,证书文件,以及日志目录,需要替换成我们自己的本地路径

		2.接口的商户id号,需要替换成我们测试参数中的 "测试商户号"

		3.我测试过程中,一直报错:
			10报文格式错误[5500030]

			网上也找不到错误问题,有一篇文章提到了,好像是时区的问题。
			查看了下,本地因为新安装的 php,时区还真不对,修改 php 配置文件:
				php --ini		// 找到 php 配置文件
				vim /usr/local/etc/php/7.1/php.ini
				date.timezone = "Asia/Shanghai"		// 设置时区

测试完成了,项目代码中得实现整个银联支付,自己可能也能实现,但是不太优雅,在 composer 找有没有银联支付的包,找到一个:
	lokielse/omnipay-unionpay

github 上查找 payment 相关包:
	https://github.com/topics/payment?o=desc&s=stars

发现 laravel 学院,也有该包的一个教程:
	https://laravelacademy.org/post/1492.html
	https://laravelacademy.org/post/1475.html
	https://packagist.org/packages/ignited/laravel-omnipay

这里顺便过一下 omnipay-unionpay 笔记:
	github 地址:
		https://github.com/lokielse/omnipay-unionpay

		Omnipay 是一个独立于框架、多网关的支付类库,支持 PHP 7.1+。Omnipay-unionpay 为 Omnipay 实现了对银联支付的支持。

	Ominipay 地址:
		https://github.com/omnipay/omnipay

	安装:
		composer require lokielse/omnipay-unionpay dev-master

	基本用法:
		Ominipay-unionpay 提供了以下支付网关接口:
			Union_Wtz (Union No Redirect Payment) 银联无跳转支付(alpha)
			Union_Express (Union Express Payment) 银联全产品网关(PC,APP,WAP支付)
			Union_LegacyMobile (Union Legacy Mobile Payment) 银联老网关(APP)
			Union_LegacyQuickPay (Union Legacy QuickPay Payment) 银联老网关(PC)

	使用:
		测试参数可以在银联商户平台查看:
			https://open.unionpay.com/ajweb/account/testPara

	准备:
		如何获取 PrivateKey, PublicKey, Cert ID:
			1.准备好 cert.pfx、密码、verify_sign_acp.cer

			2.获取私钥
				openssl pkcs12 -in cert.pfx  -nocerts -nodes | openssl rsa -out private_key.pem

			3.公钥就是 verify_sign_acp.cer	

			4.获取 Cert ID
				openssl pkcs12 -in cert.pfx -clcerts -nokeys | openssl x509 -serial -noout // 得到 16 进制数
				visit https://lokielse.github.io/hex2dec // 将 16 进制数转换为 10 进制数

	接口:
		Consume
			$gateway = Omnipay::create('UnionPay_Express');
			$gateway->setMerId($config['merId']);
			$gateway->setCertId($config['certId']);
			$gateway->setPrivateKey($config['privateKey']); // path or content
			$gateway->setReturnUrl($config['returnUrl']);
			$gateway->setNotifyUrl($config['notifyUrl']);

			$order = [
			    'orderId'   => date('YmdHis'), //Your order ID
			    'txnTime'   => date('YmdHis'), //Should be format 'YmdHis'
			    'orderDesc' => 'My order title', //Order Title
			    'txnAmt'    => '100', //Order Total Fee
			];

			//For PC/Wap
			$response = $gateway->purchase($order)->send();
			$response->getRedirectHtml();

			//For APP
			$response = $gateway->createOrder($order)->send();
			$response->getTradeNo();

		Return/Notify
			$gateway = Omnipay::create('UnionPay_Express');
			$gateway->setMerId($config['merId']);
			$gateway->setPublicKey($config['publicKey']); // path or content

			$response = $gateway->completePurchase(['request_params'=>$_REQUEST])->send();

			if ($response->isPaid()) {
			    //pay success
			}else{
			    //pay fail
			}

		Query Order Status
			$response = $gateway->query([
			    'orderId' => '20150815121214', //Your site trade no, not union tn.
			    'txnTime' => '20150815121214', //Order trade time
			    'txnAmt'  => '200', //Order total fee
			])->send();

			var_dump($response->isSuccessful());
			var_dump($response->getData());

		Consume Undo
			$response = $gateway->consumeUndo([
			    'orderId' => '20150815121214', //Your site trade no, not union tn.
			    'txnTime' => date('YmdHis'), //Regenerate a new time
			    'txnAmt'  => '200', //Order total fee
			    'queryId' => 'xxxxxxxxx', //Order total fee
			])->send();

			var_dump($response->isSuccessful());
			var_dump($response->getData());

		Refund
			// 注意:
			1. 银联退款时,必须加上 queryId, 
			2. 作为商户生成的订单号orderId与退款时的订单号是不一样的。也就意味着退款时的订单号必须重新生成。
			3. txnAmt 这个参数银联是精确到分的。直接返回元为单位的值,将会出现报错信息。
			// get the queryId first
			$response = $gateway->query([
			    'orderId' => '20150815121214', //Your site trade no, not union tn.
			    'txnTime' => '20150815121214', //Order trade time
			    'txnAmt'  => 200 * 100, //Order total fee; notice that: you should multiply the txnAmt by 100 with the Unionpay gateway. Such as 200 * 100;
			])->send();
			$queryId = ($response->getData())['queryId'];
			$response = $gateway->refund([
			    'orderId' => '20150815121215', //Your site trade no, not union tn. notice: this orderId must not be the same with the order's created orderId.
			    'txnTime' => date('YmdHis'), //Order trade time
			    'txnAmt'  => 200 * 100, //Order total fee; notice that: you should multiply the txnAmt by 100 with the Unionpay gateway. Such as 200 * 100;
			    'queryId' => $queryId
			])->send();

			var_dump($response->isSuccessful());
			var_dump($response->getData());

		File Transfer
			$response = $gateway->fileTransfer([
			    'txnTime'    => '20150815121214', //Order trade time
			    'settleDate' => '0119', //Settle Date
			    'fileType'   => '00', //File Type
			])->send();

			var_dump($response->isSuccessful());
			var_dump($response->getData());


laravel 还有一个 Ominipay 的封装包,是将 Ominipay 集成到 Laravel,并提供了一个简单的配置。
	ignited/laravel-omnipay

	github地址:
		https://github.com/ignited/laravel-omnipay

	安装:
		composer require ignited/laravel-omnipay

		config/app.php 添加 provider 和 facade
			'providers' => [
				Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider::class
			]

			'Omnipay' => Ignited\LaravelOmnipay\Facades\OmnipayFacade::class

		发布配置文件:
			php artisan vendor:publish --provider="Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider" --tag=config

	配置:
		config/laravel-ominipay.php

			return [

				// 支付使用的默认网关
				'default' => 'unionpay',

				// 各个支付网关
				'gateways' => [

			        // PayPal支付
					'paypal' => [
						'driver'  => 'PayPal_Express',
						'options' => [
							'solutionType'   => '',
							'landingPage'    => '',
							'headerImageUrl' => ''
						]
					],
				]
			];

	使用:
		1.支付

	        // 订单
	        $order = array(
	            'orderId' => '订单号',
	            'txnTime' => date('YmdHis'),
	            'title'   => '测试订单',
	            'txnAmt'  => '订单价格',
	        );

	        // 调用支付(purchase - 查看 omnipay-unionpay 用法)
	        $response = Omnipay::purchase($order)->send();

	        // 触发银联支付跳转
	        $response->redirect();

	    2.同步/异步通知

	        // 调用支付完成
	        $response = Omnipay::completePurchase(['request_params' => $_REQUEST])->send();

	        // 支付成功
	        if($response->isPaid()){

	        // 支付失败
	        }else{

	        }

	        /*
	        	注意,这里有个小坑:
	        		我在测试支付回调时,异步签名认证成功!但是同步签名认证失败!

	        	排查了半天,觉得程序没啥问题,后来在 github 上提问了作者:
	        		https://github.com/lokielse/omnipay-unionpay/issues/27

	        		将 $_REQUEST 改为 $_POST 即可($_REQUEST 可能包含了的内容)
	         */

	    3.切换其他网关
	    	Omnipay::setGateway('unionpay');

	    4.实例化网关
	    	$gateway = Omnipay::gateway('paypal');
	    	$gateway = Omnipay::gateway('unionpay');


总结下项目步骤:
	1.安装 laravel-omnipay
		composer require ignited/laravel-omnipay

		config/app.php 添加 provider 和 facade
			'providers' => [
				Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider::class
			]

			'Omnipay' => Ignited\LaravelOmnipay\Facades\OmnipayFacade::class

		发布配置文件:
			php artisan vendor:publish --provider="Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider" --tag=config

	2.安装 ominipay-unionpay
		composer require lokielse/omnipay-unionpay dev-master

	3.配置银联支付
		1>获取私钥、公钥、证书ID 配置
			1)准备好 证书(cert.pfx)、证书密码(000000)、verify_sign_acp.cer

			2)获取私钥
				openssl pkcs12 -in cert.pfx  -nocerts -nodes | openssl rsa -out private_key.pem

			3)获取公钥
				公钥就是 verify_sign_acp.cer

			4)获取证书ID
				openssl pkcs12 -in cert.pfx -clcerts -nokeys | openssl x509 -serial -noout 		// 得到16进制

				访问:https://lokielse.github.io/hex2dec,将16进制转换为10进制

		2>创建银联支付证书目录:
			mkdir -p config/unionpay-cart/test/ 		// 测试环境证书配置目录
				private_key.pem 			// 私钥
				verify_sign_acp.cer 		// 公钥
				cert.pfx 					// 证书

			mkdir -p config/unionpay-cart/production/	// 生产环境证书配置目录

		3>配置 config/laravel-ominipay.php,银联支付:

			return [

				// 支付使用的默认网关
				'default' => 'unionpay',

				// 各个支付网关
				'gateways' => [

			        // PayPal支付
					'paypal' => [
						'driver'  => 'PayPal_Express',
						'options' => [
							'solutionType'   => '',
							'landingPage'    => '',
							'headerImageUrl' => ''
						]
					],

			        // 银联支付
			        'unionpay' => [
			            'driver' => 'UnionPay_Express',
			            'options' => [
			                'merId' => 'xxx',
			                'certId' => 'xxx',
			                'privateKey' => 'private_key.pem',
			                'publicKey' => 'verify_sign_acp.cer',
			                'certPath' => '700000000000001_acp.pfx',
			                'certPassword' => '000000',
			                'certDir' => 'xxx',
			                'returnUrl' => url('payment/unionpay/return'),
			                'notifyUrl' => url('payment/unionpay/notify'),
			            ]
			        ],
				]
			];

	4.调用
		路由:
			web/wap端支付
			    Route::get('payment/unionpay/web-pay', 'PaymentUnionpayController@webPay');
			    Route::get('payment/unionpay/wap-pay', 'PaymentUnionpayController@wapPay');
			同步/异步通知
			    // 注意:银联的同步通知也是 POST 提交
			    Route::post('payment/unionpay/return', 'PaymentUnionpayController@return');
			    Route::post('payment/unionpay/notify', 'PaymentUnionpayController@notify');
			/*
				这里注意下 "同步通知":
					不同于一般的同步通知,是 'get' 请求,银联的是 'post' 请求
			 */

		中间件:
			VerifyCsrfToken 也得配置 '同步/异步通知' 排除 csrf token 认证

			    protected $except = [
			    	...
			        'payment/unionpay/return',      // 同步通知(银联的同步通知,也是 post 提交)
			        'payment/unionpay/notify',      // 异步通知
			    ];

		控制器:
		    public function webPay()
		    &&
		    public function wapPay()
		    {
		        $order = array(
		            'orderId' => '订单号',
		            'txnTime' => date('YmdHis'),
		            'title'   => '测试订单',
		            'txnAmt'  => '100',
		        );

		        $response = Omnipay::purchase($order)->send();
		        $response->redirect();
		    }


		    public function return()
		    &&
		    public function notify()
		    {

		        // 调用支付完成
		        $response = Omnipay::completePurchase(['request_params' => $_REQUEST])->send();

		        // 支付成功
		        if($response->isPaid()){

		        // 支付失败
		        }else{

		        }
		    }

	5.其他
		1>目前 ominipay-unionpay 只支持 5.0.0 版本,想要使用 5.0.1 版本,需要我们自己来扩展

		2>看的几篇教程、还有官方文档,以及银联自身的 5.0.1 SDK,看的相当混乱,包括银联支付里该设置哪些配置,都很乱。
			需要我们来查看 ominipay-unionpay 源码,才能大概了解到底是怎么使用!

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值