Skip to content

Commit 04a0536

Browse files
author
wangzhan
committed
添加支付宝国际模块
1 parent 81dfaef commit 04a0536

13 files changed

Lines changed: 4974 additions & 17 deletions

File tree

app/Components/AlipayNotify.php

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<?php
2+
3+
namespace App\Components;
4+
5+
class AlipayNotify {
6+
/**
7+
* HTTPS形式消息验证地址
8+
*/
9+
var $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
10+
/**
11+
* HTTP形式消息验证地址
12+
*/
13+
var $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';
14+
15+
16+
var $sign_type = "MD5";
17+
var $partner = "";
18+
var $md5_key = "";
19+
var $private_key = "";
20+
var $alipay_public_key = "";
21+
var $transport = "http";
22+
23+
/**
24+
* 构造函数
25+
* @param $sign_type 加密方式 MD5/RSA
26+
* return
27+
*/
28+
function __construct($sign_type, $partner, $md5_key, $private_key, $alipay_public_key, $transport){
29+
$this->sign_type = $sign_type;
30+
$this->partner = $partner;
31+
$this->md5_key = $md5_key;
32+
$this->private_key = $private_key;
33+
$this->alipay_public_key = $alipay_public_key;
34+
$this->transport = $transport;
35+
}
36+
37+
/**
38+
* 针对notify_url验证消息是否是支付宝发出的合法消息
39+
* @return 验证结果
40+
*/
41+
public function verifyNotify(){
42+
if(empty($_POST)) {//判断POST来的数组是否为空
43+
//Tools::Log("POST来的数组为空");
44+
return false;
45+
}
46+
else {
47+
//生成签名结果
48+
$isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
49+
//Tools::Log($isSign);
50+
$converted_res = ($isSign) ? 'true' : 'false';
51+
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
52+
$responseTxt = 'false';
53+
if (! empty($_POST["notify_id"])) {
54+
$responseTxt = $this->getResponse($_POST["notify_id"]);
55+
}
56+
//Tools::Log($responseTxt);
57+
//验证
58+
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
59+
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
60+
if (preg_match("/true$/i",$responseTxt) && $isSign) {
61+
return true;
62+
} else {
63+
return false;
64+
}
65+
}
66+
}
67+
68+
/**
69+
* 获取返回时的签名验证结果
70+
* @param $para_temp 通知返回来的参数数组
71+
* @param $sign 返回的签名结果
72+
* @return 签名验证结果
73+
*/
74+
function getSignVeryfy($para_temp, $sign) {
75+
//除去待签名参数数组中的空值和签名参数
76+
$para_filter = $this->paraFilter($para_temp);
77+
78+
//对待签名参数数组排序
79+
$para_sort = $this->argSort($para_filter);
80+
81+
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
82+
$prestr = $this->createLinkstring($para_sort);
83+
84+
$isSgin = false;
85+
switch (strtoupper(trim($this->sign_type))) {
86+
case "RSA" :
87+
$isSgin = $this->rsaVerify($prestr, trim($this->alipay_public_key), $sign);
88+
break;
89+
case "MD5" :
90+
$isSgin = $this->md5Verify($prestr, $sign, trim($this->md5_key));
91+
break;
92+
default :
93+
$isSgin = false;
94+
}
95+
return $isSgin;
96+
}
97+
98+
/**
99+
* 获取远程服务器ATN结果,验证返回URL
100+
* @param $notify_id 通知校验ID
101+
* @return 服务器ATN结果
102+
* 验证结果集:
103+
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
104+
* true 返回正确信息
105+
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
106+
*/
107+
function getResponse($notify_id) {
108+
$transport = strtolower(trim($this->transport));
109+
$partner = trim($this->partner);
110+
$veryfy_url = '';
111+
if($transport == 'https') {
112+
$veryfy_url = $this->https_verify_url;
113+
}
114+
else {
115+
$veryfy_url = $this->http_verify_url;
116+
}
117+
$veryfy_url = $veryfy_url."partner=" . $partner . "&notify_id=" . $notify_id;
118+
$responseTxt = $this->getHttpResponseGET($veryfy_url, base_path('ca/cacert_alipay.pem'));
119+
120+
return $responseTxt;
121+
}
122+
123+
/**
124+
* RSA验签
125+
* @param $data 待签名数据
126+
* @param $alipay_public_key 支付宝的公钥字符串
127+
* @param $sign 要校对的的签名结果
128+
* return 验证结果
129+
*/
130+
function rsaVerify($data, $alipay_public_key, $sign) {
131+
//以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
132+
$alipay_public_key=str_replace("-----BEGIN PUBLIC KEY-----","",$alipay_public_key);
133+
$alipay_public_key=str_replace("-----END PUBLIC KEY-----","",$alipay_public_key);
134+
$alipay_public_key=str_replace("\n","",$alipay_public_key);
135+
136+
$alipay_public_key='-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($alipay_public_key, 64, "\n", true) .PHP_EOL.'-----END PUBLIC KEY-----';
137+
$res=openssl_get_publickey($alipay_public_key);
138+
if($res)
139+
{
140+
$result = (bool)openssl_verify($data, base64_decode($sign), $res);
141+
}
142+
else {
143+
//Tools::Log("您的支付宝公钥格式不正确!"."<br/>"."The format of your alipay_public_key is incorrect!");
144+
exit();
145+
}
146+
openssl_free_key($res);
147+
return $result;
148+
}
149+
150+
/**
151+
* 验证签名 sign verify
152+
* @param $prestr 需要签名的字符串pre-sign string
153+
* @param $sign 签名结果
154+
* @param $key 私钥
155+
* return 签名结果sign generated
156+
*/
157+
function md5Verify($prestr, $sign, $key) {
158+
$prestr = $prestr . $key;
159+
$mysgin = md5($prestr);
160+
161+
if($mysgin == $sign) {
162+
return true;
163+
}
164+
else {
165+
return false;
166+
}
167+
}
168+
169+
/**
170+
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
171+
* @param $para 需要拼接的数组
172+
* return 拼接完成以后的字符串
173+
*/
174+
function createLinkstring($para) {
175+
$arg = "";
176+
while (list ($key, $val) = each ($para)) {
177+
$arg.=$key."=".$val."&";
178+
}
179+
//去掉最后一个&字符
180+
$arg = substr($arg,0,count($arg)-2);
181+
182+
//如果存在转义字符,那么去掉转义
183+
if(get_magic_quotes_gpc()){$arg = stripslashes($arg);}
184+
185+
return $arg;
186+
}
187+
188+
/**
189+
* 远程获取数据,GET模式
190+
* 注意:
191+
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
192+
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
193+
* @param $url 指定URL完整路径地址
194+
* @param $cacert_url 指定当前工作目录绝对路径
195+
* return 远程输出的数据
196+
*/
197+
function getHttpResponseGET($url,$cacert_url) {
198+
$curl = curl_init($url);
199+
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
200+
curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
201+
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
202+
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
203+
curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
204+
$responseText = curl_exec($curl);
205+
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
206+
curl_close($curl);
207+
208+
return $responseText;
209+
}
210+
211+
/**
212+
* 除去数组中的空值和签名参数
213+
* @param $para 签名参数组
214+
* return 去掉空值与签名参数后的新签名参数组
215+
*/
216+
function paraFilter($para) {
217+
$para_filter = array();
218+
while (list ($key, $val) = each ($para)) {
219+
if($key == "sign" || $key == "sign_type" || $val == "")continue;
220+
else $para_filter[$key] = $para[$key];
221+
}
222+
return $para_filter;
223+
}
224+
225+
/**
226+
* 对数组排序
227+
* @param $para 排序前的数组
228+
* return 排序后的数组
229+
*/
230+
function argSort($para) {
231+
ksort($para);
232+
reset($para);
233+
return $para;
234+
}
235+
}
236+
?>

0 commit comments

Comments
 (0)