ThinkPHP 3.2 支付宝即时到账接口开发
前言:

一、支付流程
- 构造请求参数
- 向支付宝网关发送请求
- 生成支付宝页面
- 支付宝交易结果
二、构建支付类
1.官方即时到账文档地址:
https://doc.open.alipay.com/doc2/detail?treeId=62&articleId=103740&docType=1
2.支付类:
<?php
/**
* Created by PhpStorm.
* User: Tinywan
* Date: 2016/9/16
* Time: 10:44
*/
namespace Common\Model; use Think\Model; class PayModel
{
public $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?';
public $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&';
public $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?';
private $keys = 'k2zu8i7h9enbkafsvtfrgdcuy1n273qn';
private $partner = '2088802807619823';
private $cacert = 'http://www.19981.com/cert/cacert.pem'; public function alipay($data)
{
$param = array(
'service' => 'create_direct_pay_by_user',
'partner' => $this->partner,
'_input_charset' => 'utf-8',
'notify_url' => 'http://wechatu.xd107.com/pay/notify/notify_url', //异步通知
//'return_url' => 'http://wechatu.xd107.com/pay/notify/return_url', //同步通知
'out_trade_no' => $data['out_trade_no'],
'subject' => $data['subject'],
'payment_type' => '1',
'total_fee' => $data['total_fee'],
'seller_email' => 'mzhsoft@126.com',
);
//构造请求参数
$res = $this->buildRequestPara($param);
$form = $this->buildRequestForm($res, 'get', '提交');
return $form;
//echo($form);
} /**
* 针对notify_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
public function verifyNotify()
{
if (empty($_POST)) {//判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'false';
if (!empty($_POST["notify_id"])) {
$responseTxt = $this->getResponse($_POST["notify_id"]);
} //写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n notify_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_POST);
//logResult($log_text); //验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i", $responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
} /**
* 针对return_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
public function verifyReturn()
{ if (empty($_GET)) {//判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'false';
if (!empty($_GET["notify_id"])) {
$responseTxt = $this->getResponse($_GET["notify_id"]);
} //写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_GET);
//logResult($log_text); //验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i", $responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
} /**
* 获取返回时的签名验证结果
* @param $para_temp 通知返回来的参数数组
* @param $sign 返回的签名结果
* @return 签名验证结果
*/
function getSignVeryfy($para_temp, $sign)
{
//除去待签名参数数组中的空值和签名参数
$para_filter = $this->paraFilter($para_temp); //对待签名参数数组排序
$para_sort = $this->argSort($para_filter); //把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $this->createLinkstring($para_sort); $isSgin = false;
switch (strtoupper(trim('MD5'))) {
case "MD5" :
$isSgin = $this->md5Verify($prestr, $sign, $this->keys);
break;
default :
$isSgin = false;
} return $isSgin;
} /**
* 获取远程服务器ATN结果,验证返回URL
* @param $notify_id 通知校验ID
* @return 服务器ATN结果
* 验证结果集:
* invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
* true 返回正确信息
* false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
*/
function getResponse($notify_id)
{
$transport = strtolower(trim('http'));
$partner = trim($this->partner);
$veryfy_url = '';
if ($transport == 'https') {
$veryfy_url = $this->https_verify_url;
} else {
$veryfy_url = $this->http_verify_url;
}
$veryfy_url = $veryfy_url . "partner=" . $partner . "¬ify_id=" . $notify_id;
$responseTxt = $this->getHttpResponseGET($veryfy_url, $this->cacert); return $responseTxt;
} /**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @param $method 提交方式。两个值可选:post、get
* @param $button_name 确认按钮显示文字
* @return 提交表单HTML文本
*/
function buildRequestForm($para_temp, $method, $button_name)
{
//待请求参数数组
$para = $this->buildRequestPara($para_temp); $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=" . trim(strtolower('utf-8')) . "' method='" . $method . "'>";
while (list ($key, $val) = each($para)) {
$sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
} //submit按钮控件请不要含有name属性
$sHtml = $sHtml . "<input type='submit' value='" . $button_name . "' style='display:none;'></form>"; $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>"; return $sHtml;
} /**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组
*/
function buildRequestPara($para_temp)
{
//除去待签名参数数组中的空值和签名参数
$para_filter = $this->paraFilter($para_temp); //对待签名参数数组排序
$para_sort = $this->argSort($para_filter); //生成签名结果
$mysign = $this->buildRequestMysign($para_sort); //签名结果与签名方式加入请求提交参数组中
$para_sort['sign'] = $mysign;
$para_sort['sign_type'] = strtoupper(trim('MD5')); return $para_sort;
} /**
* 除去数组中的空值和签名参数
* @param $para 签名参数组
* return 去掉空值与签名参数后的新签名参数组
*/
function paraFilter($para)
{
$para_filter = array();
while (list ($key, $val) = each($para)) {
if ($key == "sign" || $key == "sign_type" || $val == "") continue;
else $para_filter[$key] = $para[$key];
}
return $para_filter;
} /**
* 对数组排序
* @param $para 排序前的数组
* return 排序后的数组
*/
function argSort($para)
{
ksort($para);
reset($para);
return $para;
} /**
* 生成签名结果
* @param $para_sort 已排序要签名的数组
* return 签名结果字符串
*/
function buildRequestMysign($para_sort)
{
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $this->createLinkstring($para_sort); $mysign = "";
switch (strtoupper(trim('MD5'))) {
case "MD5" :
$mysign = $this->md5Sign($prestr, $this->keys);
break;
default :
$mysign = "";
} return $mysign;
} /**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstring($para)
{
$arg = "";
while (list ($key, $val) = each($para)) {
$arg .= $key . "=" . $val . "&";
}
//去掉最后一个&字符
$arg = substr($arg, 0, count($arg) - 2); //如果存在转义字符,那么去掉转义
if (get_magic_quotes_gpc()) {
$arg = stripslashes($arg);
} return $arg;
} /**
* 签名字符串
* @param $prestr 需要签名的字符串
* @param $key 私钥
* return 签名结果
*/
function md5Sign($prestr, $key)
{
$prestr = $prestr . $key;
return md5($prestr);
} /**
* 验证签名
* @param $prestr 需要签名的字符串
* @param $sign 签名结果
* @param $key 私钥
* return 签名结果
*/
function md5Verify($prestr, $sign, $key)
{
$prestr = $prestr . $key;
$mysgin = md5($prestr); if ($mysgin == $sign) {
return true;
} else {
return false;
}
} /**
* 远程获取数据,GET模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* return 远程输出的数据
*/
function getHttpResponseGET($url, $cacert_url)
{
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO, $cacert_url);//证书地址
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl); return $responseText;
} }
三、订单支付
(1)订单显示和异步处理代码:
<?php
/**
* Created by PhpStorm.
* User: Tinywan
* Date: 2016/9/16
* Time: 10:44
*/
namespace Pay\Controller; use Think\Controller; class IndexController extends Controller
{
public function index()
{
$map['id'] = 7;
$info = M('alipay')->where($map)->find();
$this->assign('info', $info);
$this->display();
//echo($form);
} public function payTo()
{
$data['subject'] = $_POST['subject'];
$data['out_trade_no'] = $_POST['out_trade_no'];
$data['total_fee'] = $_POST['total_fee'];
$res = D('Common/Pay')->alipay($data);
$this->ajaxReturn($res);
} }
(2)订单显示和异步请求代码:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>购物车</title>
<script src="http://apps.bdimg.com/libs/jquery/1.6.4/jquery.min.js" type="text/javascript"></script>
</head>
<body>
<style type="text/css">
*{margin:0px;padding:0px;border:0px; font-size:12px;color:#333; font-family:微软雅黑;}
ul li{ list-style:none}
a{ text-decoration:none;}
a:hover{ color:#e46432;}
body{margin:auto;;overflow-x:hidden;} /*****购物车*********/
.gwc{ width:950px;overflow:hidden;}
.gwc_tb1{ width:100%; border-top:5px solid #48b9e5; background:#d0e7fa; height:38px; margin-top:20px; overflow:hidden;}
.tb1_td1{ width:35px; text-align:center;}
.tb1_td3{ width:290px; text-align:center;}
.tb1_td4{ width:260px; text-align:center;}
.tb1_td5{ width:115px; text-align:center;}
.tb1_td6{ width:135px; text-align:center;}
.tb1_td7{ text-align:center;} .gwc_tb2{ width:100%; margin-top:20px; background:#eef6ff; border:1px solid #e5e5e5; padding-top:20px; padding-bottom:20px;}
.tb2_td1{ width:60px; text-align:center;}
.tb2_td2{ width:100px; text-align:center;}
.tb2_td2 img{ width:96px; height:96px; border:2px solid #c9c6c7;}
.tb2_td3{ width:170px; padding-left:12px; padding-right:18px;}
.tb2_td3 a{ font-size:14px; line-height:22px;} .gwc_tb3{ width:100%; border:1px solid #d2d2d2; background:#e7e7e7; height:46px; margin-top:20px; }
.gwc_tb3 tr td{font-size:14px;}
.tb3_td2{ width:100px;text-align:center;}
.tb3_td2 span{ color:#ff5500;font-size:14px; font-weight:bold; padding-left:5px; padding-right:5px; }
.tb3_td3{ width:220px;text-align:center;}
.tb3_td3 span{ font-size:18px; font-weight:bold;}
.tb3_td4{ width:110px;text-align:center;}
.jz2{ width:100px; height:46px; line-height:46px; text-align:center; font-size:18px; color:#fff; background:#ee0000; display:block; float:right;}
#jz1{font-size:18px;}
</style>
<div class="gwc" style=" margin:auto;">
<table cellpadding="0" cellspacing="0" class="gwc_tb1">
<tr>
<td class="tb1_td3">商品</td>
<td class="tb1_td4">商品信息</td>
<td class="tb1_td5">数量</td>
<td class="tb1_td6">单价</td>
<td class="tb1_td7">操作</td>
</tr>
</table> <table cellpadding="0" cellspacing="0" class="gwc_tb2">
<tr>
<td class="tb2_td2"></td>
<td class="tb2_td3"><a href="#">苹果手机</a></td>
<td class="tb1_td4">{$info.subject}</td>
<td class="tb1_td5">
<input id="min1" name="" style=" width:20px; height:18px;border:1px solid #ccc;" type="button" value="-" />
<input id="text_box1" name="" type="text" value="1" style=" width:30px; text-align:center; border:1px solid #ccc;" />
<input id="add1" name="" style=" width:20px; height:18px;border:1px solid #ccc;" type="button" value="+" />
</td>
<td class="tb1_td6"><label id="total1" class="tot" style="color:#ff5500;font-size:14px; font-weight:bold;">{$info.total_fee}</label></td>
<td class="tb1_td7"><a href="#">删除</a></td>
</tr>
</table>
<table cellpadding="0" cellspacing="0" class="gwc_tb3">
<tr>
<td id="subject" style="display:none">{$info.subject}</td>
<td id="out_trade_no" style="display:none">{$info.out_trade_no}</td>
<td class="tb3_td3">合计(不含运费):<span>¥</span><span id="total_fee">{$info.total_fee}</span></td>
<td class="tb3_td4"><a href="#" style=" display:block;" onclick="payto()" class="jz2" id="jz2">结算</a></td>
</tr>
</table> </div>
<div id="form" style="display:none"></div>
<script type='text/javascript'>
var $URL = "__ROOT__/Pay/Index/";
function payto(){
$.ajax({
type: "post",
url: $URL+'payTo',
data: {subject:$("#subject").html(), out_trade_no:$("#out_trade_no").html(),total_fee:$("#total_fee").html()},
dataType: "json",
success: function(data){
$('#form').html(data);
}
});
}
</script>
</body>
</html>
四、同步通知和异步通知(已经做了是否支付宝发送过来的信息)
(1)notify_url()方法:【异步方法】
说明:应该是每3秒异步请求或说刷新一次。里面主要做:比如更改订单状态(如果验证成功,几把本地订单设置为已支付,包括发送短信等操作)
(2)return_url()方法:【同步方法】
说明:支付成功提示后跳转回去的页面,就是finish页面。建议这里只做提示用,因为如果想在这里做业务逻辑的话做法不当,因为如果这个页面跳转是有个时间段的,需要几秒钟,如果支付成功后客户在还没有跳转前把页面关闭了,那么对应的业务逻辑就没法实现。业务逻辑应该都是放在notify_url()方法中实现比较好的(*^__^*) 嘻嘻……。
<?php
/**
* Created by PhpStorm.
* User: Tinywan
* Date: 2016/9/16
* Time: 10:44
*/
namespace Pay\Controller;
use Think\Controller;
class NotifyController extends Controller {
//同步通知
public function return_url(){
$verify = D('Common/Pay')->verifyReturn();
if($verify){
$out_trade_no = $_GET['out_trade_no'];
$trade_no = $_GET['trade_no'];
$trade_status = $_GET['trade_status'];
if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
$map['out_trade_no'] = $out_trade_no;
$data['trade_no'] = $trade_no;
$res = M('alipay')->where($map)->save($data);
if($res !== false){
echo 'success,return_url'.$res;
}
}
} } //异步通知
public function notify_url(){
$verify = D('Common/Pay')->verifyNotify();
if($verify){
$out_trade_no = $_POST['out_trade_no'];
$trade_no = $_POST['trade_no'];
$trade_status = $_POST['trade_status'];
if($trade_status == 'TRADE_FINISHED' || $trade_status == 'TRADE_SUCCESS') {
$map['out_trade_no'] = $out_trade_no;
$data['trade_no'] = $trade_no;
$res = M('alipay')->where($map)->save($data);
if($res !== false){
echo 'success notify_url--$res';
}
}
}
}
}
五、验证是否是支付宝发来的通知
$verify = D('Common/Pay')->verifyNotify(); // 返回值:true 正确,false:错误
/**
* 针对return_url验证消息是否是支付宝发出的合法消息
* @return 验证结果
*/
public function verifyReturn()
{ if (empty($_GET)) {//判断POST来的数组是否为空
return false;
} else {
//生成签名结果
$isSign = $this->getSignVeryfy($_GET, $_GET["sign"]);
//获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
$responseTxt = 'false';
if (!empty($_GET["notify_id"])) {
$responseTxt = $this->getResponse($_GET["notify_id"]);
} //写日志记录
//if ($isSign) {
// $isSignStr = 'true';
//}
//else {
// $isSignStr = 'false';
//}
//$log_text = "responseTxt=".$responseTxt."\n return_url_log:isSign=".$isSignStr.",";
//$log_text = $log_text.createLinkString($_GET);
//logResult($log_text); //验证
//$responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
//isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
if (preg_match("/true$/i", $responseTxt) && $isSign) {
return true;
} else {
return false;
}
}
}
六、支付宝有密批量退款
处理类:
<?php
namespace Common\Model;
use Think\Model;
class RefundModel{
public $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?';
private $keys = 'k2zu8i7h9enbkafsvtfrgdcuy1n273qn';
private $partner = '2088802807619823';
private $cacert = './cert/cacert.pem';
private $private_key_path = './cert/rsa_private_key.pem'; //退款请求
function refund($data){
//构造要请求的参数数组,无需改动
$parameter = array(
"service" => 'refund_fastpay_by_platform_pwd',
"partner" => $this->partner,
"seller_email" => 'mzhsoft@126.com',
"refund_date" => date('Y-m-d H:i:s',time()),
"batch_no" => $data['batch_no'],
"batch_num" => $data['batch_num'],
"detail_data" => $data['detail_data'],
"_input_charset" => trim(strtolower('utf-8')) );
$res = $this->buildRequestForm($parameter, 'get', '确认');
return $res ;
}
/**
* 生成签名结果
* @param $para_sort 已排序要签名的数组
* return 签名结果字符串
*/
function buildRequestMysign($para_sort) {
//把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
$prestr = $this->createLinkstring($para_sort); $mysign = "";
switch (strtoupper(trim('RSA'))) {
case "RSA" :
$mysign = $this->rsaSign($prestr, $this->private_key_path);
break;
default :
$mysign = "";
} return $mysign;
} /**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组
*/
function buildRequestPara($para_temp) {
//除去待签名参数数组中的空值和签名参数
$para_filter = $this->paraFilter($para_temp); //对待签名参数数组排序
$para_sort = $this->argSort($para_filter); //生成签名结果
$mysign = $this->buildRequestMysign($para_sort); //签名结果与签名方式加入请求提交参数组中
$para_sort['sign'] = $mysign;
$para_sort['sign_type'] = strtoupper(trim('RSA')); return $para_sort;
} /**
* 生成要请求给支付宝的参数数组
* @param $para_temp 请求前的参数数组
* @return 要请求的参数数组字符串
*/
function buildRequestParaToString($para_temp) {
//待请求参数数组
$para = $this->buildRequestPara($para_temp); //把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
$request_data = $this->createLinkstringUrlencode($para); return $request_data;
} /**
* 建立请求,以表单HTML形式构造(默认)
* @param $para_temp 请求参数数组
* @param $method 提交方式。两个值可选:post、get
* @param $button_name 确认按钮显示文字
* @return 提交表单HTML文本
*/
function buildRequestForm($para_temp, $method, $button_name) {
//待请求参数数组
$para = $this->buildRequestPara($para_temp); $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->alipay_gateway_new."_input_charset=".trim(strtolower('utf-8'))."' method='".$method."'>";
while (list ($key, $val) = each ($para)) {
$sHtml.= "<input type='hidden' name='".$key."' value='".$val."'/>";
} //submit按钮控件请不要含有name属性
$sHtml = $sHtml."<input type='submit' value='".$button_name."'></form>"; $sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>"; return $sHtml;
} /**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果
* @param $para_temp 请求参数数组
* @return 支付宝处理结果
*/
function buildRequestHttp($para_temp) {
$sResult = ''; //待请求参数数组字符串
$request_data = $this->buildRequestPara($para_temp); //远程获取数据
$sResult = $this->getHttpResponsePOST($this->alipay_gateway_new, $this->cacert,$request_data,trim(strtolower('utf-8'))); return $sResult;
} /**
* 建立请求,以模拟远程HTTP的POST请求方式构造并获取支付宝的处理结果,带文件上传功能
* @param $para_temp 请求参数数组
* @param $file_para_name 文件类型的参数名
* @param $file_name 文件完整绝对路径
* @return 支付宝返回处理结果
*/
function buildRequestHttpInFile($para_temp, $file_para_name, $file_name) { //待请求参数数组
$para = $this->buildRequestPara($para_temp);
$para[$file_para_name] = "@".$file_name; //远程获取数据
$sResult = $this->getHttpResponsePOST($this->alipay_gateway_new, $this->cacert,$para,trim(strtolower('utf-8'))); return $sResult;
} /**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstring($para) {
$arg = "";
while (list ($key, $val) = each ($para)) {
$arg.=$key."=".$val."&";
}
//去掉最后一个&字符
$arg = substr($arg,0,count($arg)-2); //如果存在转义字符,那么去掉转义
if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} return $arg;
}
/**
* 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
* @param $para 需要拼接的数组
* return 拼接完成以后的字符串
*/
function createLinkstringUrlencode($para) {
$arg = "";
while (list ($key, $val) = each ($para)) {
$arg.=$key."=".urlencode($val)."&";
}
//去掉最后一个&字符
$arg = substr($arg,0,count($arg)-2); //如果存在转义字符,那么去掉转义
if(get_magic_quotes_gpc()){$arg = stripslashes($arg);} return $arg;
}
/**
* 除去数组中的空值和签名参数
* @param $para 签名参数组
* return 去掉空值与签名参数后的新签名参数组
*/
function paraFilter($para) {
$para_filter = array();
while (list ($key, $val) = each ($para)) {
if($key == "sign" || $key == "sign_type" || $val == "")continue;
else $para_filter[$key] = $para[$key];
}
return $para_filter;
}
/**
* 对数组排序
* @param $para 排序前的数组
* return 排序后的数组
*/
function argSort($para) {
ksort($para);
reset($para);
return $para;
}
/**
* 写日志,方便测试(看网站需求,也可以改成把记录存入数据库)
* 注意:服务器需要开通fopen配置
* @param $word 要写入日志里的文本内容 默认值:空值
*/
function logResult($word='') {
$fp = fopen("log.txt","a");
flock($fp, LOCK_EX) ;
fwrite($fp,"执行日期:".strftime("%Y%m%d%H%M%S",time())."\n".$word."\n");
flock($fp, LOCK_UN);
fclose($fp);
} /**
* 远程获取数据,POST模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* @param $para 请求的数据
* @param $input_charset 编码格式。默认值:空值
* return 远程输出的数据
*/
function getHttpResponsePOST($url, $cacert_url, $para, $input_charset = '') { if (trim($input_charset) != '') {
$url = $url."_input_charset=".$input_charset;
}
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl,CURLOPT_POST,true); // post传输数据
curl_setopt($curl,CURLOPT_POSTFIELDS,$para);// post传输数据
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl); return $responseText;
} /**
* 远程获取数据,GET模式
* 注意:
* 1.使用Crul需要修改服务器中php.ini文件的设置,找到php_curl.dll去掉前面的";"就行了
* 2.文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
* @param $url 指定URL完整路径地址
* @param $cacert_url 指定当前工作目录绝对路径
* return 远程输出的数据
*/
function getHttpResponseGET($url,$cacert_url) {
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_HEADER, 0 ); // 过滤HTTP头
curl_setopt($curl,CURLOPT_RETURNTRANSFER, 1);// 显示输出结果
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true);//SSL证书认证
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2);//严格认证
curl_setopt($curl, CURLOPT_CAINFO,$cacert_url);//证书地址
$responseText = curl_exec($curl);
//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
curl_close($curl); return $responseText;
} /**
* 实现多种字符编码方式
* @param $input 需要编码的字符串
* @param $_output_charset 输出的编码格式
* @param $_input_charset 输入的编码格式
* return 编码后的字符串
*/
function charsetEncode($input,$_output_charset ,$_input_charset) {
$output = "";
if(!isset($_output_charset) )$_output_charset = $_input_charset;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset change.");
return $output;
}
/**
* 实现多种字符解码方式
* @param $input 需要解码的字符串
* @param $_output_charset 输出的解码格式
* @param $_input_charset 输入的解码格式
* return 解码后的字符串
*/
function charsetDecode($input,$_input_charset ,$_output_charset) {
$output = "";
if(!isset($_input_charset) )$_input_charset = $_input_charset ;
if($_input_charset == $_output_charset || $input ==null ) {
$output = $input;
} elseif (function_exists("mb_convert_encoding")) {
$output = mb_convert_encoding($input,$_output_charset,$_input_charset);
} elseif(function_exists("iconv")) {
$output = iconv($_input_charset,$_output_charset,$input);
} else die("sorry, you have no libs support for charset changes.");
return $output;
} /**
* RSA签名
* @param $data 待签名数据
* @param $private_key_path 商户私钥文件路径
* return 签名结果
*/
function rsaSign($data, $private_key_path) {
$priKey = file_get_contents($private_key_path);
$res = openssl_get_privatekey($priKey);
openssl_sign($data, $sign, $res);
openssl_free_key($res);
//base64编码
$sign = base64_encode($sign);
return $sign;
} /**
* RSA验签
* @param $data 待签名数据
* @param $ali_public_key_path 支付宝的公钥文件路径
* @param $sign 要校对的的签名结果
* return 验证结果
*/
function rsaVerify($data, $ali_public_key_path, $sign) {
$pubKey = file_get_contents($ali_public_key_path);
$res = openssl_get_publickey($pubKey);
$result = (bool)openssl_verify($data, base64_decode($sign), $res);
openssl_free_key($res);
return $result;
} /**
* RSA解密
* @param $content 需要解密的内容,密文
* @param $private_key_path 商户私钥文件路径
* return 解密后内容,明文
*/
function rsaDecrypt($content, $private_key_path) {
$priKey = file_get_contents($private_key_path);
$res = openssl_get_privatekey($priKey);
//用base64将内容还原成二进制
$content = base64_decode($content);
//把需要解密的内容,按128位拆开解密
$result = '';
for($i = 0; $i < strlen($content)/128; $i++ ) {
$data = substr($content, $i * 128, 128);
openssl_private_decrypt($data, $decrypt, $res);
$result .= $decrypt;
}
openssl_free_key($res);
return $result;
} }
具体方法:
//退款
public function refund(){
header("Content-type:text/html;charset=utf-8");
$data['batch_no'] = date('YmdHis').'MZ01';
$data['batch_num'] = 1;
$data['detail_data'] = '2016091621001004480242264394^0.01^协商退款01';
$res = D('Common/Refund')->refund($data);
//var_dump($res); 这个用在测试的时候,如果打印的是一个表单的话表示错误
echo($res);
}
六、RSA商户公钥与支付宝公钥(待定....)
具体详细代码和说明文档见Github:https://github.com/Tinywan/ThinkPhpStudy
ThinkPHP 3.2 支付宝即时到账接口开发的更多相关文章
- PHP九大接口视频教程( 支付宝,QQ,短信接口,微信接口开发, 支付宝即时到账接口开发三级分销全套)
PHP九大接口视频教程( 支付宝,QQ,短信接口,微信接口开发, 支付宝即时到账接口开发三级分销全套) 需要的联系我:QQ: 1844912514 PHP九大接口视频教程( 支付宝,QQ,短信接口 ...
- thinkphp框架对接支付宝即时到账接口回调的代码
关于支付宝即时收款接口的对接过程,很简单,也有很多人发过,我这里就不在啰嗦了,对接完成后,在线支付成功后的回调,相对来说,是个难点,,我重点分享下我的经验. 我在开发二代旅游CMS(http://ww ...
- 支付宝即时到账接口开发 - DEMO讲解
支付宝即时到帐接口 环境要求 PHP5.0以上,且需要开启curl.openssl. 文档地址: https://doc.open.alipay.com/doc2/detail?treeId=62&a ...
- ThinkPHP整合支付宝即时到账接口调用
首先是在支付宝的蚂蚁金服开放平台下载PHP的demo: https://doc.open.alipay.com/doc2/detail?treeId=62&articleId=103566&a ...
- 支付宝即时到账DEMO配置与使用
支付宝网页即时到账功能,可让用户在线向开发者的支付宝账号支付资金,交易资金即时到账,帮助开发者快速回笼资金. 当用户进行支付操作时候可以直接跳转到支付宝支付页面进行支付 1. 准备 关于支付宝签约即时 ...
- PHP实现支付宝即时到账功能
本文实例为大家分享了PHP支付宝即时到账功能的实现代码,供大家参考,具体内容如下 首先需要下载即时到账交易接口,传送门https://doc.open.alipay.com/doc2/detail?t ...
- PHP 接入支付宝即时到账功能
首先请到支付宝那边申请一个及时到账的接口账户,需要提交相关材料申请.然后根据即时到账的API文档进行接入.API文档提供了各种语言版本的demo,我这里是下的php版demo,然后再进行相关修改操作. ...
- php支付宝在线支付接口开发教程【转】
php支付宝在线支付接口开发教程 这篇文章主要为大家详细介绍了php支付宝在线支付接口开发教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 1.什么是第三方支付 所谓第三方支付,就是一些和各 ...
- 支付宝WAP支付接口开发
支付宝WAP支付接口开发 因项目需要,要增加支付宝手机网站支付功能,找了支付宝的样例代码和接口说明,折腾两天搞定,谨以此文作为这两天摸索的总结.由于公司有自己的支付接口,并不直接使用这个接口,所以晚些 ...
随机推荐
- JavaScript封装方法,兼容参数类型为Number和String
/** * 依据Kind确定跳转到目标列表页面. * @param kind */ function gobackByKind(kind) { var kindStr = String(kind); ...
- Difference between prop and attr in different version of jquery
jQuery <1.9$('#inputId').attr('readonly', true); jQuery 1.9+$('#inputId').prop('readonly', true); ...
- 使用nodejs去做一个验证码
let express = require('express'); let captchapng = require('captchapng'); let app = express(); app.g ...
- B树,B+树,红黑树应用场景AVL树,红黑树,B树,B+树,Trie树
B B+运用在file system database这类持续存储结构,同样能保持lon(n)的插入与查询,也需要额外的平衡调节.像mysql的数据库定义是可以指定B+ 索引还是hash索引. C++ ...
- [转帖]浅析Servlet执行原理
浅析Servlet执行原理 原贴地址: https://www.cnblogs.com/wangjiming/p/10360327.html 原作者画的图挺好. 自己之前看过iis的一些配置文档 但是 ...
- Linux基础学习(7)--用户和用户组管理
第七章——用户和用户组管理 一.用户配置文件 1.用户信息文件/etc/passwd: (1)用户管理简介:所以越是对服务器安全性要求高的服务器,越需要建立合理的用户权限等级制度和服务器操作规范. ...
- ADOTable的CancelUpdate和CancelBatch的区别?(100分)
出差新疆,修改别人的代码,请教CancelUpdate和CancelBatch的区别! 如果希望取消对当前记录所做的任何更改或者放弃新添加的记录,则必须调用CancelUpdate 方法CancelB ...
- jquery Ajax get()/post()
get()/post()是通過http get/post向服務器請求數據的. http get vs post: get:向指定資源獲取數據 post項指定資源提交數據. get是向遠程服務器的獲取數 ...
- 如果filename的value有值 说明支持存储
如果filename的value有值 说明支持存储
- sorted 返回字典的所有键