aliPay v1.0.12
使用模块,传递订单,获得支付str文本
<html>
<head>
<title>title>
<script src="../../../script/template/mobile/xianhua/static/js/jquery-3.1.1.min.js">script>
<script src="../../../script/api.js">script>
<script type="text/javascript"> //https://docs.apicloud.com/Client-API/Open-SDK/aliPay var orderInfo = ''; apiready = function() { aliPay = api.require('aliPay'); get_str(); if (orderInfo=='') { window.location.href="../order/order_list.html"; return; } alert(orderInfo); aliPay.payOrder({ orderInfo: orderInfo }, function(ret, err) { api.alert({ title: '支付结果', msg: ret.code, buttons: ['确定'] }); }); }; function get_str() { var pay_order_sn = window.localStorage.getItem("pay_order_sn"); if (pay_order_sn==null) { alert("请选择订单支付!"); window.location.href="../order/order_list.html"; return; } $.ajax({ type: "POST", url: "http://g421.com/apprun/Apppay/get_alipay_str", dataType: 'json', data:{ pay_order_sn:pay_order_sn }, async: false, success: function(e) { if (e.code == 1) { orderInfo = e.data; }else{ alert(e.msg); window.location.href="../order/order_list.html"; } } }) } script>
head>
<body>
body>
html>
namespace app\apprun\controller;
use think\Controller;
use think\Db;
/** * 支付 * 支付宝 * 私钥->获取订单支付->回调用公钥校验支付 * 注意: * 新版的app使用新的app支付接口(alipay.trade.app.pay)和RSA2校验,且只有一种签名结构(老版本有3种),老版本的支付是不支持RSA2的,只支持RSA1. * 详情:https://docs.open.alipay.com/204/105465/ * 验证:https://docs.open.alipay.com/200/106120 */
class Apppay extends Controller {
private $fileCharset = "UTF-8";
public $postCharset = "UTF-8";
public $rsaPrivateKeyFilePath = "";
public $rsaPublicKeyFilePath = "";
public $sign_type = "RSA2";
//商户私钥,您的原始格式RSA私钥
public $rsaPrivateKey = 'xxx';
//支付宝公钥
public $alipayrsaPublicKey = 'xxx';
/** * 获取支付宝支付字符串信息 * @return [type] [description] */
public function get_alipay_str() {
is_crossdomain_app(true);
$params['app_id'] = "2018062160408670";
$params['method'] = "alipay.trade.app.pay";
$params['format'] = "json";
$params['charset'] = "utf-8";
$params['timestamp'] = date("Y-m-d H:i:s");
$params['version'] = "1.0";
$params['notify_url'] = "http://m.luhong421.com/apprun/Apppay/notify_url"; // 异步通知地址
$params['sign_type'] = $this->sign_type;
$order_sn = input('pay_order_sn');
if (empty($order_sn)) {
return json(['code' => 0, 'msg' => '请选择订单!']);
}
$order_info = Db::name('order')->where('order_sn',$order_sn)->find();
if (empty($order_info)) {
return json(['code' => 0, 'msg' => '订单不存在!']);
}
if ($order_info['pay_status']==1) {
return json(['code' => 0, 'msg' => '订单已经支付!']);
}
$params['biz_content'] = json_encode([
'body' => '支付',
'subject' => '支付',
'out_trade_no' => $order_info['order_sn'],
'total_amount' => $order_info['order_amount'],
'product_code' => 'QUICK_MSECURITY_PAY',
'disable_pay_channels' => 'creditCard',
], JSON_UNESCAPED_UNICODE);
# 排序,签名,排序
$str = $this->getSignContent($params);
$params['sign'] = $this->sign($str, $params['sign_type']);
foreach ($params as $key => $value) {
if ($key != 'timestamp') {
$params[$key] = urlencode($value);
}
}
$str = $this->getSignContent($params);
return json(['code' => 1, 'msg' => '获取成功!', 'data' => $str]);
}
public function notify_url() {
$arr = $_POST;
//返回格式 {"gmt_create":"2018-09-08 13:03:08","charset":"utf-8","seller_email":"[email protected]","subject":"测试app支付","sign":"gZydvv7bOkzwnkVlsPKky5EDy3BS4OL1NLwnFn64jYCa3geDwAAKiBkpGNI87AVddodixTCz9Ll9hA6T8SYK8xTCFq4VTdbXrW6RGEqVdDfdu75RBSyEflCuf5jkIZXdIxe1C5idvbCthzS7ICvbDp7eYInKFOEgaewrXhs\/ddoaMxeK2etpOJiRi3\/ioSJKGYdvU+ReKXYvWX3dg5+zaQjKp8vLnKjag4XDhBO6yB1xzQYam8jHfJgn\/ZGCAVFOWEHuAHhM2qasWXKZei+gT3OnRHnvcJDhVp0NzLWRJtFiHy02yuaLS+TlLKRcvb4fN+S4e4JWL4lzzPrG6DLUWQ==","body":"测试app支付","buyer_id":"2088212942567899","invoice_amount":"0.01","notify_id":"2018090800222130309067890520057262","fund_bill_list":"[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]","notify_type":"trade_status_sync","trade_status":"TRADE_SUCCESS","receipt_amount":"0.01","app_id":"2018062160408670","buyer_pay_amount":"0.01","sign_type":"RSA2","seller_id":"2088411957695896","gmt_payment":"2018-09-08 13:03:08","notify_time":"2018-09-08 13:03:09","version":"1.0","out_trade_no":"20180621604086000000005","total_amount":"0.01","trade_no":"2018090822001467890528225092","auth_app_id":"2018062160408670","buyer_logon_id":"j.c***@foxmail.com","point_amount":"0.00","result_data":1}
$check = $this->check($arr);
if ($check) {
$out_trade_no = $_POST['out_trade_no'];
if (empty($out_trade_no)) {
Db::name('alipay_topay')->insert(['order_sn' => 'log:app订单不存在']);
exit(0);
}
Db::name('alipay_topay')->insert(['order_sn' => $out_trade_no.'app支付']);
//支付宝交易号
$trade_no = $_POST['trade_no'];
//交易状态
$trade_status = $_POST['trade_status'];
//交易金额
$total_amount = $_POST['total_amount'];
if ($_POST['trade_status'] == 'TRADE_SUCCESS') { // 支付成功
//判断该笔订单是否在商户网站中已经做过处理
//如果没有做过处理,根据订单号(out_trade_no)在商户网站的订单系统中查到该笔订单的详细,并执行商户的业务程序
//请务必判断请求时的total_amount与通知时获取的total_fee为一致的
//如果有做过处理,不执行商户的业务程序
//注意:
//退款日期超过可退款期限后(如三个月可退款),支付宝系统发送该交易状态通知
$data = [
'order_status' => 1,
'pay_status' => 1,
'pay_code' => 'alipay',
'pay_name' => 'app支付宝支付',
'pay_time' => time(), // $arr['time_end'] 表示非时间戳时间
];
# 判断是否支付,没有支付才进行支付
$pay_status = Db::name('order')->where('order_sn', $out_trade_no)->value('pay_status');
if ($pay_status != 1) {
$order_amount = Db::name('order')->where('order_sn', $out_trade_no)->value('order_amount');
$order_id = Db::name('order')->where('order_sn', $out_trade_no)->value('order_id');
if ($total_amount != $order_amount) {
Db::name('alipay_topay')->insert(['order_sn' => $out_trade_no . '支付金额不对:' . $total_amount . '/' . $order_amount]);
exit();
}
Db::name('order')->where('order_sn', $out_trade_no)->update($data);
$surplus = Db::name('order')->where('order_sn', $out_trade_no)->value('voucher_surplus');
$uid = Db::name('order')->where('order_sn', $out_trade_no)->value('user_id');
$voucher_surplus_before = Db::name('users')->where('user_id', $uid)->value('voucher_surplus');
Db::name('users')->where('user_id', $uid)->setDec('voucher_surplus', $surplus);
Db::name('users')->where('user_id', $uid)->setInc('consume_total', $order_amount);
// 支付成功通知
$templates = new \app\api\controller\TemplateMsg();
$templates->sendOrderTemplate($uid, "支付成功");
$templates->sendShareMsg($order_id);
$templates->AdminSendOrderTemplate($out_trade_no, "支付成功");
$data = [
'user_id' => $uid,
'money' => $surplus,
'money_before' => $voucher_surplus_before,
'money_last' => $voucher_surplus_before - $surplus,
'type' => "voucher_surplus",
'add_time' => time(),
'remark' => '抵扣券使用',
'ip' => request()->ip(),
'order_sn' => $out_trade_no,
];
Db::name('money_books')->insert($data);
}
}
echo "success";
} else {
echo "fail";
}
$str = json_encode($arr,JSON_UNESCAPED_UNICODE);
Db::name('atest')->insert(['info' => $str]);
}
public function check($arr) {
$result = $this->rsaCheckV1($arr, $this->rsaPublicKeyFilePath, $this->sign_type);
return $result;
}
/** rsaCheckV1 & rsaCheckV2 * 验证签名 * 在使用本方法前,必须初始化AopClient且传入公钥参数。 * 公钥是否是读取字符串还是读取文件,是根据初始化传入的值判断的。 **/
public function rsaCheckV1($params, $rsaPublicKeyFilePath, $signType = 'RSA') {
$sign = $params['sign'];
unset($params['sign']);
unset($params['sign_type']);
return $this->verify($this->getSignContent($params), $sign, $rsaPublicKeyFilePath, $signType);
}
public function verify($data, $sign, $rsaPublicKeyFilePath, $signType = 'RSA') {
if ($this->checkEmpty($this->rsaPublicKeyFilePath)) {
$pubKey = $this->alipayrsaPublicKey;
$res = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($pubKey, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
} else {
//读取公钥文件
$pubKey = file_get_contents($rsaPublicKeyFilePath);
//转换为openssl格式密钥
$res = openssl_get_publickey($pubKey);
}
($res) or die('支付宝RSA公钥错误。请检查公钥文件格式是否正确');
//调用openssl内置方法验签,返回bool值
if ("RSA2" == $signType) {
$result = (bool) openssl_verify($data, base64_decode($sign), $res, OPENSSL_ALGO_SHA256);
} else {
$result = (bool) openssl_verify($data, base64_decode($sign), $res);
}
if (!$this->checkEmpty($this->rsaPublicKeyFilePath)) {
//释放资源
openssl_free_key($res);
}
return $result;
}
public function make_sign($it_b_pay, $service, $body, $out_trade_no, $partner, $_input_charset, $notify_url, $subject, $payment_type, $seller_id, $total_fee, $sign_type) {
$params['it_b_pay'] = $it_b_pay;
$params['service'] = $service;
$params['body'] = $body;
$params['out_trade_no'] = $out_trade_no;
$params['partner'] = $partner;
$params['_input_charset'] = $_input_charset;
$params['notify_url'] = $notify_url;
$params['subject'] = $subject;
$params['payment_type'] = $payment_type;
$params['seller_id'] = $seller_id;
$params['total_fee'] = $total_fee;
ksort($params);
$sign = $this->generateSign($params, $sign_type);
return $sign;
}
public function generateSign($params, $signType = "RSA") {
return $this->sign($this->getSignContent($params), $signType);
}
protected function sign($data, $signType = "RSA") {
if ($this->checkEmpty($this->rsaPrivateKeyFilePath)) {
$priKey = $this->rsaPrivateKey;
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($priKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
} else {
$priKey = file_get_contents($this->rsaPrivateKeyFilePath);
$res = openssl_get_privatekey($priKey);
}
($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
if ("RSA2" == $signType) {
openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
} else {
openssl_sign($data, $sign, $res);
}
if (!$this->checkEmpty($this->rsaPrivateKeyFilePath)) {
openssl_free_key($res);
}
$sign = base64_encode($sign);
return $sign;
}
protected function getSignContent($params) {
ksort($params);
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = $this->characet($v, $this->postCharset);
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset($k, $v);
return $stringToBeSigned;
}
/** * 校验$value是否非空 * if not set ,return true; * if is null , return true; **/
protected function checkEmpty($value) {
if (!isset($value)) {
return true;
}
if ($value === null) {
return true;
}
if (trim($value) === "") {
return true;
}
return false;
}
/** * 转换字符集编码 * @param $data * @param $targetCharset * @return string */
public function characet($data, $targetCharset) {
if (!empty($data)) {
$fileType = $this->fileCharset;
if (strcasecmp($fileType, $targetCharset) != 0) {
$data = mb_convert_encoding($data, $targetCharset, $fileType);
// $data = iconv($fileType, $targetCharset.'//IGNORE', $data);
}
}
return $data;
}
}