当面付 (原理场景使用范例)
https://blog.csdn.net/weixin_34111790/article/details/86344681
当面付 和 手机网站支付 在同一个文件中
https://blog.csdn.net/qq_21761149/article/details/84502416
我参考第2个
<?php
namespace app\admin\controller;
use think\Controller;
use app\index\controller\Commen;
use think\Session;
use think\Db;
use think\Request;
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 10:43:44
* 支付宝支付类
*/
class Alipay extends Commen
{
//是否沙盒环境
public $is_sandbox = false;
//沙盒地址
private $sandurl = 'https://openapi.alipaydev.com/gateway.do';
//正式地址
private $url = 'https://openapi.alipay.com/gateway.do';
// private $url = 'https://openapi.alipaydev.com/gateway.do';
//appid
private $appid ;
//商户应用私钥
private $rsaPrivateKey = '';
//支付宝公钥 验签使用
private $alipayPublicKey= '';
private $payment_id;
private $charset = 'utf-8';
public function __construct(){
// $payment = Db::name('payment')->where('code', 'alipay')->find();
// $json = json_decode($payment['json'], true);
// $this->appid = $json['appid'];
$this->appid = '';
// $this->payment_id = $payment['id'];
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 10:57:51
* 发起支付
*/
public function pay($order_id){
$time = time();
// 判断是否是沙箱环境
if($this->is_sandbox){
$url = $this->sandurl;
$this->appid = '';
$this->rsaPrivateKey = '';
$this->alipayPublicKey = '';
echo '111';
}else {
$url = $this->url;
// echo '222';
}
// die;
$notify_url = '异步回调';
// $order = Db::name('order')->where('id', $order_id)->find();
//请求参数的集合 json_encode
$biz_content = [
// 'out_trade_no' => $order['order_unique'],
'out_trade_no' => '111111',
//'seller_id' => ''
// 'total_amount' => $order['real_total_fee'],
'total_amount' => '666',
//'discountable_amount' => '',
'subject' => '标题',
//'goods_detail' => '',
//'body' => $order['body'],
//'operator_id' => '',
//'store_id' => '',
//'disable_pay_channels' => '',
//'enable_pay_channels' => '',
//'terminal_id'=> '',
//'extend_params' => '',
//'timeout_express' => '',
//'settle_info' => '',
//'business_params' => '',
//'qr_code_timeout_express' => '',
];
//参数
$param = [
'app_id' => $this->appid, //支付宝分配给开发者的应用ID
'method' => 'alipay.trade.precreate', //接口名称
//'format' => 'JSON', //紧支持JSON
'charset' => 'utf-8', //请求使用的编码格式
'sign_type' => 'RSA2', //商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2
'sign' => 'RSA2', //商户请求参数的签名串
'timestamp' => date('Y-m-d H:i:s', $time), //发送请求的时间,格式"yyyy-MM-dd HH:mm:ss"
'version' => '1.0', //调用的接口版本,固定为1.0
'notify_url' => $notify_url, //支付宝服务器主动通知商户服务器里指定的页面http/https路径
//'app_auth_token' => '', //app_auth_token
'biz_content' => json_encode($biz_content), //请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档
];
//组合生成签名参数
$signdata = [];
$signdata['app_id'] = $param['app_id'];
$signdata['method'] = $param['method'];
$signdata['charset'] = $param['charset'];
$signdata['sign_type'] = $param['sign_type'];
$signdata['timestamp'] = $param['timestamp'];
$signdata['version'] = $param['version'];
$signdata['notify_url'] = $param['notify_url'];
$signdata['biz_content'] = $param['biz_content'];
//生成签名
$sign = $this->generateSign($signdata, 'RSA2');
$param['sign'] = $sign;
// 第1种
$content = $this->curlPost($url,$param);
$return = json_decode($content, true);
// echo '<pre>';
// var_dump($content);
// var_dump($return);
// die;
// 第2种
// $url = 'https://openapi.alipaydev.com/gateway.do?' . http_build_query($param);
// $return = file_get_contents($url); //打开支付请求连接 获取二维码地址
// $return = json_decode($return, true); //将返回的字符串转换为数组
// echo '<pre>';
// var_dump($return);
// die;
//file_put_contents('alipay.log', $content, FILE_APPEND);
$return = $return['alipay_trade_precreate_response'];
echo '<pre>';
var_dump($return);
die;
if($return['code'] == 10000){
$out_trade_no = $return['out_trade_no'];
if($out_trade_no != $order['order_unique']){
return ['code' => -1, 'msg' => '返回订单号错误'];
}
//生成成功
$qr_code = $return['qr_code'];
$data = [];
$data['order_id'] = $order_id;
$data['code_url'] = $qr_code;
return ['code' => 1 , 'msg' => '成功' , 'data' => $data];
}else {
file_put_contents('alipay.log', 'err code:' . $return['code'] . ', err msg:' . $return['msg'] . '\r\n', FILE_APPEND);
return ['code' => -1 , 'msg' => 'err_code:' . $return['code'] . ',err_msg:' . $return['msg']];
}
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 13:36:17 { function_description }
* 支付宝支付通知
*
* @param <type> $data The data
*/
public function notify($data){
//验签
//组合验签数据
$param = $data;
unset($param['sign']);
unset($param['sign_type']);
$rst = $this->rsaCheck($param, $data['sign'] , $data['sign_type']);
if($rst){
//查询订单状态
$order = Db::name("order")->where('order_unique', $data['out_trade_no'])->where('status', -1)->find();
if(!empty($order)){
//$rst = $this->orderquery($order, 'TRADE_SUCCESS');
$rst = true;
if($rst){
$time = time();
Db::startTrans();
try {
//修改订单状态
$order_data = [];
$order_data['status'] =1;
$order_data['pay_time'] = $time;
$order_data['trade_no'] = $data['trade_no'];
$order_data['payment_id'] = $this->payment_id;
$rst = Db::name('order')->where('id', $order['id'])->update($order_data);
if($order['type'] == 1){
}else if ($order['type'] == 2){
//添加订单记录
$log_order = [];
$log_order['order_id'] = $order['id'];
$log_order['content'] = '[代金券]购买代金券:' . $coupon['title'] . ', 已支付' ;
$log_order['create_time'] = $time;
$rst = Db::name('log_order')->insertGetId($log_order);
}
Db::commit();
}catch(\Exception $e){
Db::rollback();
file_put_contents('alipaynotify.log', '支付通知数据库操作错误:' . $e->getMessage() . '\r\n', FILE_APPEND);
exit;
}
if($order['type'] ==1 ){
//发送成功短信通知
$yunxin = new Yunxin;
$arr = [];
$arr[] = $match_member['name'];
$arr[] = $match['title'];
$arr[] = date("Y年m月d日H:i", $match['mhstart']);
$arr[] = $match_member['idno'];
$yunxin->sendSMSTemplate( 9294589, [$match_member['telephone']], $arr);
}
echo "success";exit;
}else {
file_put_contents('alipaynotify.log', '查询订单状态错误\r\n', FILE_APPEND);
}
}else {
file_put_contents('alipaynotify.log', '未找到相应订单\r\n' , FILE_APPEND );
exit;
}
}else {
file_put_contents('alipaynotify.log', '验签失败\r\n' , FILE_APPEND );
exit;
}
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 13:39:15
* 支付查询接口
*
* @param order
* @param status 要验证的状态 WAIT_BUYER_PAY-交易创建等待买家付款 TRADE_CLOSED-未付款交易超时关闭或支付完成后全额退款 TRADE_SUCCESS-交易支付成功 TRADE_FINISHED-交易结束不可退款
*/
public function orderquery($order , $status){
$time = time();
$url = '';
$biz_content = [
'out_trade_no' => $order['order_unique'],
'trade_no' => $order['trade_no'],
//'org_pid' => '',
];
$param = [
'app_id' => $this->appid,
'method' => 'alipay.trade.query',
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'sign' => '',
'timestamp' => date('Y-m-d H:i:s', $time),
'version' => '1.0',
'biz_content' => json_encode($biz_content),
];
//组合签名数组
$signdata = [];
$signdata['app_id'] = $param['app_id'];
$signdata['method'] = $param['method'];
$signdata['charset'] = $param['charset'];
$signdata['sign_type'] = $param['sign_type'];
$signdata['timestamp'] = $param['timestamp'];
$signdata['version'] = $param['version'];
$signdata['biz_content'] = $param['biz_content'];
//生成签名
$sign = $this->generateSign($signdata, 'RSA2');
$param['sign'] = $sign;
$content = $this->curlPost($url,$param);
$return = json_decode($content, true);
if($return['code'] == 10000){
if($return['trade_status'] == $status){
return true;
}else {
return false;
}
}else {
return false;
}
}
public function generateSign($params, $signType = "RSA") {
return $this->sign($this->getSignContent($params), $signType);
}
public 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->charset);
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
unset ($k, $v);
return $stringToBeSigned;
}
/**
* 转换字符集编码
* @param $data
* @param $targetCharset
* @return string
*/
function characet($data, $targetCharset) {
if (!empty($data)) {
$fileType = $this->charset;
if (strcasecmp($fileType, $targetCharset) != 0) {
$data = mb_convert_encoding($data, $targetCharset, $fileType);
//$data = iconv($fileType, $targetCharset.'//IGNORE', $data);
}
}
return $data;
}
/**
* 校验$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;
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 12:05:26
* 签名函数
*
* @param <type> $data The data
* @param string $signType The sign type
*
* @return <type> ( description_of_the_return_value )
*/
protected function sign($data, $signType = "RSA") {
$priKey=$this->rsaPrivateKey;
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($priKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
($res) or die('您使用的私钥格式错误,请检查RSA私钥配置');
if ("RSA2" == $signType) {
openssl_sign($data, $sign, $res, version_compare(PHP_VERSION,'5.4.0', '<') ? SHA256 : OPENSSL_ALGO_SHA256); //OPENSSL_ALGO_SHA256是php5.4.8以上版本才支持
} else {
openssl_sign($data, $sign, $res);
}
$sign = base64_encode($sign);
return $sign;
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-16 12:06:12
* 验签函数
*
* @param <type> $data The data 带签名数据
* @param <type> $sign The sign 要校对的签名结果
* @param string $type The type
*
* @return <type> ( description_of_the_return_value )
*/
public function rsaCheck($data, $sign,$type = 'RSA'){
$public_key = $this->alipayPublicKey;
$search = [
"-----BEGIN PUBLIC KEY-----",
"-----END PUBLIC KEY-----",
"\n",
"\r",
"\r\n"
];
$public_key=str_replace($search,"",$public_key);
$public_key=$search[0] . PHP_EOL . wordwrap($public_key, 64, "\n", true) . PHP_EOL . $search[1];
$res=openssl_get_publickey($public_key);
if($res)
{
if($type == 'RSA'){
$result = (bool)openssl_verify($this->getSignContent($data), base64_decode($sign), $res);
}elseif($type == 'RSA2'){
$result = (bool)openssl_verify($this->getSignContent($data), base64_decode($sign), $res,OPENSSL_ALGO_SHA256);
}
openssl_free_key($res);
}else{
return false;
}
return true;
}
public function curlPost($url = '', $postData = '', $options = array())
{
if (is_array($postData)) {
$postData = http_build_query($postData);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
if (!empty($options)) {
curl_setopt_array($ch, $options);
}
//https请求 不验证证书和host
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
/**
* @author mselect <445712421@qq.com>
*
* @DateTime 2018-11-19 15:03:28
* PC网站支付
*/
public function pagepay($order_id){
if($this->is_sandbox){
$url = $this->sandurl;
$this->appid = '';
$this->rsaPrivateKey = ''; // 商户私钥
$this->alipayPublicKey = '';
}else {
$url = $this->url;
}
// $order = Db::name('order')->where('id' , $order_id)->find();
// if($order['type'] ==1 ){
// $return_url = cmf_url('user/match/mindex', '', true, true);
// }elseif($order['type'] ==2 ) {
// $return_url = cmf_url('user/order/index', '', true, true);
$return_url = '';
// }
$notify_url = '异步回调地址';
$time = time();
$biz_content = [
// 'out_trade_no' => $order['order_unique'],
'out_trade_no' => '111111',
'product_code' => 'FAST_INSTANT_TRADE_PAY',
// 'total_amount' => $order['real_total_fee'],
'total_amount' => '666',
// 'subject' => $order['body'],
'subject' => 'en',
//'body' => '',
//'goods_detail' => '',
//'passback_params' => '',
//'extend_params' => '',
//'goods_type' => '',
//'timeout_express' => '',
//'enable_pay_channels' => '',
//'disable_pay_channels' => '',
//'auth_token' => '',
//'qr_pay_mode' => '',
//'qrcode_width' => '',
];
//生成参数
$param = [
'app_id' => $this->appid,
'method' => 'alipay.trade.page.pay',
//'format' => 'JSON',
'return_url' => $return_url,
'charset' => 'utf-8',
'sign_type' => 'RSA2',
'sign' => '',
'timestamp' => date('Y-m-d H:i:s', $time),
'version' => '1.0',
'notify_url' => $notify_url,
'biz_content' => json_encode($biz_content),
];
//组合签名数组
$signdata = [];
$signdata['app_id'] = $param['app_id'];
$signdata['method'] = $param['method'];
$signdata['return_url'] = $param['return_url'];
$signdata['charset'] = $param['charset'];
$signdata['sign_type'] = $param['sign_type'];
$signdata['timestamp'] = $param['timestamp'];
$signdata['version'] = $param['version'];
$signdata['notify_url'] = $param['notify_url'];
$signdata['biz_content'] = $param['biz_content'];
$sign = $this->generateSign($signdata, 'RSA2');
$param['sign'] = $sign;
$data = [];
$data['param'] = $param;
$data['url'] = $url;
echo '<pre>';
var_dump($data);
die;
return ['code' => 1 , 'msg' => '成功', 'data' => $data];
}
}
?>