1、前端调用后台生成的二维码
var wxcode = "/index.php/WebPay/thirdPaymentQrcode/user_id/52398/payType/weChat/fromType/3/price/";
var alipycode = "/index.php/WebPay/alipyCode?url=/index.php/WebPay/thirdPaymentQrcode/user_id/52398/payType/aliPay/fromType/3/price/";
2、用户扫码支付, 后端回调验证
class WebPayController extends WebController {
protected $pc_wechat_log;
protected $pc_alipay_log;
protected $base_url;
protected $wechat_notify_url;
protected $wechat_order_query;
protected $alipay_notify_url;
protected $alipay_return_url;
protected $pay_success_url;
protected $userModel;
//第三方支付,引入第三方支付库(微信,支付宝)
public function _initialize(){
//引入WxPayPubHelper
vendor('WxPayPubHelper.WxPayPubHelper');
// 引入支付宝类库
vendor('Alipay.Corefunction');
vendor('Alipay.Md5function');
vendor('Alipay.Notify');
vendor('Alipay.Submit');
//初始化模型
$this->userModel = D('User');
//log文件路径
$this->pc_wechat_log="/data/web/web/Public/pc_wechat_log.log";
$this->pc_alipay_log="/data/web/web/Public/pc_alipay_log.log";
//创建文件夹
if(!is_dir('/data/web/web/Public/')){
$res=mkdir('/data/web/web/Public/',0777,true);
}
//回调地址域名
$this->base_url = 'http://'.$_SERVER['HTTP_HOST'];
//订单来源(fromType):1某币,2微课,3积分
//微信回调地址
$this->wechat_notify_url = [
'1' => $this->base_url.'/index.php/Home/WebPay/wechatNotify',
'2' => $this->base_url.'/index.php/Home/WebPay/wechatNotifyCourse',
'3' => $this->base_url.'/index.php/Home/WebPay/wechatNotifyBean',
'5' => $this->base_url.'/index.php/Home/WebPay/wechatNotifyMaster',
];
//微信主动查询订单地址
$this->wechat_order_query = [
'1' => '',
'2' => '',
'3' => '',
'5' => '',
];
//支付宝回调地址
$this->alipay_notify_url = [
'1' => $this->base_url.'/index.php/Home/WebPay/alipayNotify',
'2' => $this->base_url.'/index.php/Home/WebPay/alipayNotifyCourse',
'3' => $this->base_url.'/index.php/Home/WebPay/alipayNotifyBean',
'5' => $this->base_url.'/index.php/Home/WebPay/alipayNotifyMaster',
];
//支付宝跳转地址
$this->alipay_return_url = [
'1' => '',
'2' => '',
'3' => '',
'5' => '',
];
//支付成功展示页地址
$this->pay_success_url = [
'1' => '',
'2' => '',
'3' => '',
'5' => '',
];
}
//第三方支付,将信息生成二维码(微信,支付宝)
public function thirdPaymentQrcode(){
// 接收参数
$user_id = I('user_id');
$user_id = decrypt(cookie('uid'));
$order_sn = I("order_sn",'');
$price = I("price",0);//均为实际金额
$payType = I("payType",'');// 支付类型,aliPay/weChat
$fromType = I("fromType",0);// 订单来源:1某币,2微课,3积分,4微课打赏,5大咖购买
$typeId = I("typeId",0);// 来源id
$is_usemoney = I('is_usemoney','1');//是否某币抵扣:1抵扣,0不抵扣
//生成订单号-- 商户网站唯一订单号out_trade_no
// $order_sn = $order_sn ? $order_sn : build_ruth_order_no('',$user_id);
// 判断是否登录
if(!$user_id){
$this->error('请先登录');
}
// 判断是否缺少参数
if(!$order_sn || !$payType || !$fromType || (($fromType==2 || $fromType==5) && !$typeId)){
$this->error('缺少参数');
}
//某币
$mymoney = $this->userModel->getMoneyCount($user_id);
$mymoney = $mymoney>0 ? $mymoney : '0';
//某币抵扣
if($is_usemoney && $fromType !='2' && $fromType !='5'){
//如果用户本身没有某币,则is_usermoney应为0
if($mymoney == 0){
$is_usemoney = 0;
}
$price = $price - $mymoney;
if($price <= 0){
$this->error('金额异常');
}
}else{
$price = $price;
}
// 订单金额
if($price < 1){
$this->error('金额不能小于1元');
}
// 判断是否为注册用户
$user_info = M('user') -> where(['id'=>$user_id]) -> find();
if(!$user_info){
$this->error('非法用户');
}
//获取参数值
switch ($fromType) {
case '1':#某币
$title = "PC端充值某币";
break;
case '2':#微课
$title = "PC端购买微课";
//微课信息
$course_info = M('course_courses')->field('price')->where(['id'=>$typeId])->find();
$course_price = $course_info['price'];
//某币抵扣
if($is_usemoney){
//如果用户本身没有某币,则is_usermoney应为0
if($mymoney == 0){
$is_usemoney = 0;
}
$price = $course_price - $mymoney;
if($price <= 0){
$this->error('金额异常');
}
}else{
$price = $course_price;
}
break;
case '3':#积分
$title = "PC端购买积分";
break;
case '5':#大咖
$title = "PC端购买大咖";
//微课信息
$course_info = M('course_courses')->field('price')->where(['id'=>$typeId])->find();
$course_price = $course_info['price'];
$price = $course_price;
break;
default:
# code...
break;
}
// 测试专用
if(in_array($user_id,[111111])){
$price = 0.01;
}
// 数据库生成订单
$cashOrders['sn'] = $order_sn;
$cashOrders['userId'] = $user_id;
$cashOrders['status'] = 'created';
$cashOrders['payment'] = $payType;
$cashOrders['fromType'] = $fromType;
$cashOrders['typeId'] = $typeId;
$cashOrders['amount'] = $price;
$cashOrders['title'] = $title;
$cashOrders['createdTime'] = time();
$cashOrders['is_usemoney'] = $is_usemoney;
$order_info = M('cash_orders')->where(['sn'=>$order_sn])->find();
if($order_info){
$res=M('cash_orders')->where(['sn'=>$order_sn])->save($cashOrders);
}else{
$res=M('cash_orders')->add($cashOrders);
}
$total_fee = $price;
if($res !== false){
//输出支付页面
if($payType == 'weChat') {
// 调用微信生成二维码
//使用统一支付接口
$unifiedOrder = new \UnifiedOrder_pub();
//设置统一支付接口参数
$unifiedOrder->setParameter("body","某某消费");//商品描述
$unifiedOrder->setParameter("out_trade_no","$order_sn");//商户订单号
$unifiedOrder->setParameter("total_fee",($total_fee * 100));//总金额
$unifiedOrder->setParameter("product_id",($total_fee * 100));//总金额
$unifiedOrder->setParameter("notify_url", $this->wechat_notify_url[$fromType]);//通知地址
$unifiedOrder->setParameter("trade_type","NATIVE");//交易类型
//获取统一支付接口结果
$unifiedOrderResult = $unifiedOrder->getResult();
//商户根据实际情况设置相应的处理流程
if ($unifiedOrderResult["return_code"] == "FAIL")
{
//商户自行增加处理流程
echo "通信出错:".$unifiedOrderResult['return_msg']."<br>";
}
elseif($unifiedOrderResult["result_code"] == "FAIL")
{
//商户自行增加处理流程
echo "错误代码:".$unifiedOrderResult['err_code']."<br>";
echo "错误代码描述:".$unifiedOrderResult['err_code_des']."<br>";
}
elseif($unifiedOrderResult["code_url"] != NULL)
{
//从统一支付接口获取到code_url
$code_url = $unifiedOrderResult["code_url"];
//商户自行增加处理流程
//......
}
$this->assign('out_trade_no',$order_sn);
$this->assign('code_url',$code_url);
$this->assign('wechat_order_query_url',$this->wechat_order_query[$fromType]);
$this->assign('pay_success_url',$this->pay_success_url[$fromType]);
$this->assign('unifiedOrderResult',$unifiedOrderResult);
$this->display('Web/Pay/qrcode');
} elseif($payType == 'aliPay') {
// 支付宝支付
//得到订单提交时的地址,区分不同各类订单
$alipay_config = C('alipay_config');
/**************************请求参数**************************/
$payment_type = "1"; //支付类型 //必填,不能修改
// $notify_url = C('alipay.notify_url'); //服务器异步通知页面路径
$notify_url = $this->alipay_notify_url[$fromType];
// $return_url = C('alipay.return_url'); //页面跳转同步通知页面路径
$return_url = $this->alipay_return_url[$fromType];
$seller_email = C('alipay.seller_email');//卖家支付宝帐户必填
$out_trade_no = $order_sn;//商户订单号 通过支付页面的表单进行传递,注意要唯一!
// $new_order =substr($out_trade_no,0,1);
//订单名称 //必填 通过支付页面的表单进行传递
$subject = '某某消费';
$body = "某某消费"; //订单描述 通过支付页面的表单进行传递
$show_url = $this->pay_success_url[$fromType]; //商品展示地址 通过支付页面的表单进行传递
//商品展示地址 通过支付页面的表单进行传递
$anti_phishing_key = "";//防钓鱼时间戳 //若要使用请调用类文件submit中的query_timestamp函数
$exter_invoke_ip = get_client_ip(); //客户端的IP地址*/
$qr_pay_mode = 3;//PC扫码支付的方式:0,1,2,3,4
//**********************************************************
//构造要请求的参数数组,无需改动
$parameter = array(
"service" => "create_direct_pay_by_user",
"partner" => trim($alipay_config['partner']),
"payment_type" => $payment_type,
"notify_url" => $notify_url,
"return_url" => $return_url,
"seller_email" => $seller_email,
"out_trade_no" => $out_trade_no,
"subject" => $subject,
"total_fee" => $total_fee,
"body" => $body,
"show_url" => $show_url,
"anti_phishing_key" => $anti_phishing_key,
"exter_invoke_ip" => $exter_invoke_ip,
"qr_pay_mode" => $qr_pay_mode,
"_input_charset" => trim(strtolower($alipay_config['input_charset']))
);
//建立请求
$alipaySubmit = new \AlipaySubmit($alipay_config);
$html_text = $alipaySubmit->buildRequestForm($parameter,"post", "确认");
echo($html_text);
}
}else{
$this->error('生成订单失败');
}
}
//对支付宝二维码进行包装显示
public function alipyCode(){
$url = I('url','');
$this->assign('url',$url);
$this->display('Web/Pay/alipycode');
}
//微信,异步通知,积分
public function wechatNotifyBean(){
//使用通用通知接口
$notify = new \Notify_pub();
//存储微信的回调
$xml = $GLOBALS['HTTP_RAW_POST_DATA'];
$notify->saveData($xml);
//将xml转为array
//验证签名,并回应微信。
//对后台通知交互时,如果微信收到商户的应答不是成功或超时,微信认为通知失败,
//微信会通过一定的策略(如30分钟共8次)定期重新发起通知,
//尽可能提高通知的成功率,但微信不保证通知最终能成功。
//商家交易单号
$out_trade_no = $notify->data['out_trade_no'];
//微信交易单号
$transaction_id = $notify->data['transaction_id'];
//交易金额,单位分
$price = $notify->data['total_fee']/100;
//==商户根据实际情况设置相应的处理流程,此处仅作举例=======
//以log文件形式记录回调信息
$log_name= $this->pc_wechat_log;//log文件路径
log_into_txt($log_name,"【微信】订单号:$out_trade_no",'head');
log_into_txt($log_name,"【接收到微信的notify通知】:\t".$xml."\t");
if($notify->checkSign() == TRUE) {
if($notify->data["return_code"] == "FAIL") {
//此处应该更新一下订单状态,商户自行增删操作
log_into_txt($log_name,"【通信出错】:\t",'foot');
$notify->setReturnParameter("return_code","FAIL");
}elseif($notify->data["result_code"] == "FAIL"){
//此处应该更新一下订单状态,商户自行增删操作
log_into_txt($log_name,"【业务出错】:\t",'foot');
$notify->setReturnParameter("return_code","FAIL");
}else{
//得到订单数据
$order_data=M('cash_orders')->where(['sn'=>$out_trade_no])->find();
log_into_txt($log_name,"【支付成功】:\t".json_encode($order_data)."\t");
//商户自行增加处理流程,
//支付成功信息是否已入库
if($order_data['status'] == 'paid'){
log_into_txt($log_name,"【查询已支付成功】",'foot');
$notify->setReturnParameter("return_code","SUCCESS");
}else{
//修改已支付状态
$save_res=M('cash_orders')->where(['sn'=>$out_trade_no])->save(['status'=>'paid','paidTime'=>time(),'note'=>$transaction_id]);
if($save_res === false){
log_into_txt($log_name,"【订单状态修改失败】:\t".M('cash_orders')->_sql()."\t",'foot');
$notify->setReturnParameter("return_code","FAIL");
}else{
//某币抵扣
if($order_data['is_usemoney']){
//某币
$mymoney = $this->userModel->getMoneyCount($order_data['userId']);
$money_count = $mymoney>0 ? $mymoney : '0';
//扣某币
$insert_data=[
'user_id' => $order_data['userId'],
'money_count' => -$money_count,
'money_time' => date('Y-m-d H:i:s'),
'money_detail' => 'PC端购买积分抵扣',
];
$money_res=M('user_money')->data($insert_data)->add();
}
$user_id = $order_data['userId'];
$bean_count = $order_data['amount']*10;
$bean_detail1 = "充值送积分";
$bean_type = 8;
// 购买积分
$bean_res = insert_user_been($user_id, $bean_count, $bean_detail1, $bean_type);;
if($bean_res === false){
log_into_txt($log_name,"【购买数据入库失败】:\t".M('user_bean')->_sql()."\t",'foot');
$notify->setReturnParameter("return_code","FAIL");
}else{
log_into_txt($log_name,"【购买成功】",'foot');
$notify->setReturnParameter("return_code","SUCCESS");
}
}
}
}
}else{
$notify->setReturnParameter("return_code","FAIL");//返回状态码
$notify->setReturnParameter("return_msg","签名失败");//返回信息
}
//返回通知
$returnXml = $notify->returnXml();
header("Access-Control-Allow-Origin:*" );/*星号表示所有的域都可以接受,*/
header("Access-Control-Allow-Methods:POST,GET" );
header('Access-Control-Allow-Headers:origin, x-requested-with,x-requested_with, content-type, accept');
echo $returnXml;
exit;
}
//支付宝,异步通知,积分
public function alipayNotifyBean(){
/*
同理去掉以下两句代码;
*/
//这里还是通过C函数来读取配置项,赋值给$alipay_config
$alipay_config=C('alipay_config');
//计算得出通知验证结果
$alipayNotify = new \AlipayNotify($alipay_config);
$verify_result = $alipayNotify->verifyNotify();
$log_name= $this->pc_alipay_log;//log文件路径
log_into_txt($log_name,"【支付宝】\t订单号:".$_POST['out_trade_no'],'head');
log_into_txt($log_name,"【接收到支付宝的notifyurl通知】:\t".json_encode($_POST));
if($verify_result) {
//验证成功
//获取支付宝的通知返回参数,可参考技术文档中服务器异步通知参数列表
$out_trade_no = $_POST['out_trade_no']; //商户订单号
$trade_no = $_POST['trade_no']; //支付宝交易号
$trade_status = $_POST['trade_status']; //交易状态
$total_fee = $_POST['total_fee']; //交易金额
$notify_id = $_POST['notify_id']; //通知校验ID。
$notify_time = $_POST['notify_time']; //通知的发送时间。格式为yyyy-MM-dd HH:mm:ss。
$buyer_email = $_POST['buyer_email']; //买家支付宝帐号;
$parameter = array(
"out_trade_no" => $out_trade_no, //商户订单编号;
"trade_no" => $trade_no, //支付宝交易号;
"total_fee" => $total_fee, //交易金额;
"trade_status" => $trade_status, //交易状态
"notify_id" => $notify_id, //通知校验ID。
"notify_time" => $notify_time, //通知的发送时间。
"buyer_email" => $buyer_email, //买家支付宝帐号;
);
if($_POST['trade_status'] == 'TRADE_FINISHED') {
//
}else if ($_POST['trade_status'] == 'TRADE_SUCCESS') {
//商户自行增加处理流程,
// 得到订单数据
$order_data=M('cash_orders')->where(['sn'=>$out_trade_no])->find();
log_into_txt($log_name,"【支付成功】:\t".json_encode($parameter)."\t");
//验证订单号和金额
if($out_trade_no == $order_data['sn'] && $total_fee == $order_data['amount']){
//支付成功信息是否已入库
if($order_data['status'] == 'paid'){
log_into_txt($log_name,"【查询已支付成功】",'foot');
echo "success";exit;
}else{
//修改已支付状态
$save_res=M('cash_orders')->where(['sn'=>$out_trade_no])->save(['status'=>'paid','paidTime'=>time(),'note'=>$trade_no]);
if($save_res === false){
log_into_txt($log_name,"【订单状态修改失败】:\t".M('cash_orders')->_sql()."\t",'foot');
echo "fail";exit;
}
//某币抵扣
if($order_data['is_usemoney']){
//某币
$mymoney = $this->userModel->getMoneyCount($order_data['userId']);
$money_count = $mymoney>0 ? $mymoney : '0';
//扣某币
$insert_data=[
'user_id' => $order_data['userId'],
'money_count' => -$money_count,
'money_time' => date('Y-m-d H:i:s'),
'money_detail' => 'PC端购买积分抵扣',
];
$money_res=M('user_money')->data($insert_data)->add();
}
$user_id = $order_data['userId'];
$bean_count = $order_data['amount']*10;
$bean_detail1 = "充值送积分";
$bean_type = 8;
// 购买积分
$bean_res = insert_user_been($user_id, $bean_count, $bean_detail1, $bean_type);;
if($bean_res === false){
log_into_txt($log_name,"【购买数据入库失败】:\t".M('user_bean')->_sql()."\t",'foot');
echo "fail";exit;
}else{
log_into_txt($log_name,"【购买成功】",'foot');
echo "success";exit;
}
}
}else{
log_into_txt($log_name,"【订单号或金额验证失败】:\t".json_encode($data)."\t",'foot');
echo "fail";exit;
}
}
echo "success"; //请不要修改或删除
}else {
//验证失败
echo "fail";
}
}