PHP扫码⽀付DEMO,thinkphp5+⽀付PS:⽀付基础条件
1.⼀个认证的服务号
2.在服务号后台申请⽀付,成功后获得⼀个商户号
3.在商户号⾥⾯选择native⽀付,这个就是扫码⽀付,按照提⽰开通这项。
4.按照⽀付⽂档的说法,扫码⽀付分两种模式
模式⼀:⽣成的⼆维码没有失效性,但是操作⽐较复杂,中间步骤⽐较多,容易出现很多问题。
模式⼆:⽣成的⼆维码有两⼩时时间限制,但是我感觉也⼗分够⽤了,这个步骤⽐较简单,很容易实现。
按照时序图,⼤概也就分两步
代码结构:
配置⽂件:
⽀付类:
<?php
/*
* To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
namespace tools;
use think\Config;
/**
* Description of WxPay
*
* @author admin
*/
class WxPay {
/**
* 获取签名
* @param type $arr
* @return type
*/
public function getSign($arr)
//去除数组的空值
array_filter($arr);
if(isset($arr['sign'])){
unset($arr['sign']);
}
//排序
ksort($arr);
//组装字符
$str = $this->arrToUrl($arr) . '&key=' . Config::get('wx_pay')['key'];
//使⽤md5 加密转换成⼤写
return strtoupper(md5($str));
}
/**
* 校验签名
* @param type $arr
* @return boolean
*/
public function checkSign($arr){
//⽣成新签名
$sign = $this->getSign($arr);
//和数组中原始签名⽐较
if($sign == $arr['sign']){
return true;
}else{
return false;
}
}
/**
* 获取带签名的数组
* @param array $arr
* @return type
*/
public function setSign($arr)
{
$arr['sign'] = $this->getSign($arr);
return $arr;
}
/**
* 数组转URL字符串不带key
* @param type $arr
* @return type
*/
public function arrToUrl($arr)
{
return urldecode(http_build_query($arr));
}
/**
* 记录到⽂件
* @param type $file
* @param type $data
*/
public function logs($file,$data)
{
$data = is_array($data) ? print_r($data,true) : $data;
file_put_contents('./public/paylogs/' .$file, $data);
}
/**
* 接收POST推送
* @return type
*/
public function getPost()
{
return file_get_contents('php://input');
}
/**
* Xml ⽂件转数组
* @param type $xml
* @return string
*/
public function XmlToArr($xml)
{
if($xml == '') return'';
libxml_disable_entity_loader(true);
$arr = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $arr;
}
/**
* 数组转XML
* @param type $arr
* @return string
*/
public function ArrToXml($arr)
{
if(!is_array($arr) || count($arr) == 0) return'';
$xml = "<xml>";
foreach ($arr as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
代码转换/**
* 发送POST请求
* @param type $url
* @param type $postfields
* @return type
public function postStr($url,$postfields)
{
$ch = curl_init();
$params[CURLOPT_URL] = $url;    //请求url地址
$params[CURLOPT_HEADER] = false; //是否返回响应头信息
$params[CURLOPT_RETURNTRANSFER] = true; //是否将结果返回
$params[CURLOPT_FOLLOWLOCATION] = true; //是否重定向
$params[CURLOPT_POST] = true;
$params[CURLOPT_SSL_VERIFYPEER] = false;//禁⽤证书校验
$params[CURLOPT_SSL_VERIFYHOST] = false;
$params[CURLOPT_POSTFIELDS] = $postfields;
curl_setopt_array($ch, $params); //传⼊curl参数
$content = curl_exec($ch); //执⾏
curl_close($ch); //关闭连接
return $content;
}
/**
* 统⼀下单
* @param type $params
* @return boolean
*/
public function unifiedorder($params)
{
//获取到带签名的数组
$params = $this->setSign($params);
//数组转xml
$xml = $this->ArrToXml($params);
//发送数据到统⼀下单API地址
$data = $this->postStr(Config::get('wx_pay')['uourl'], $xml);
$arr = $this->XmlToArr($data);
if($arr['result_code'] == 'SUCCESS' && $arr['return_code'] == 'SUCCESS'){
return $arr;
}else{
$this->logs('', $data);
return false;
}
}
}
index控制器演⽰代码
<?php
namespace app\index\controller;
use app\common\controller\HomeBase;
use tools\WxPay;
use think\Config;
use phpqrcode\ApiQrcode;
use think\Request;
use think\Cache;
use tools\RetJosn;
class Index extends HomeBase {
/**
* ⾸页
* @param WxPay $wxpay
* @return mixed
*/
public function index(WxPay $wxpay) {
//$wxpay->logs('',['213123','123123123']);
echo 'index';
}
/**
* 扫码⽀付-模式⼆
* @param WxPay $wxpay
*/
public function index2(Request $request, WxPay $wxpay) {
if ($request->isGet()) {
return $this->fetch();
}
}
/**
* 统⼀下单,⽣成⼆维码
*/
public function getQrUrl(Request $request) {
$pid = $request->get('id');
//调⽤统⼀下单API
$params = [
'appid' => Config::get('wx_pay')['appid'],
'mch_id' => Config::get('wx_pay')['mchid'],
'nonce_str' => md5(time()),
'body' => '订单号:'.$pid,
'out_trade_no' => $pid,
'total_fee' => 2,
'spbill_create_ip' => $_SERVER['SERVER_ADDR'],
'notify_url' => Config::get('wx_pay')['notify'],
'trade_type' => 'NATIVE',
'product_id' => $pid
];
$wxpay = new WxPay();
$arr = $wxpay->unifiedorder($params);
if (!empty($arr['code_url'])) {
Cache::set('send' . $params['out_trade_no'], $params['total_fee'], 3600);            ApiQrcode::png($arr['code_url']);
} else {
return'下单失败!';
}
}
/**
* 接收腾讯推送⽀付通知
* @param WxPay $wxpay
*/
public function backOrder(WxPay $wxpay) {
try {
// 获取腾讯传回来的通知数据
$xml = $wxpay->getPost();
// 将XML格式的数据转换为数组
$arr = $wxpay->XmlToArr($xml);
$wxpay->logs('', '1');
// 验证签名
if ($wxpay->checkSign($arr)) {
Cache::set('back'.$arr['out_trade_no'],$arr['total_fee'],3600);
}
$wxpay->logs('', '2');
$params = [
'return_code' => 'SUCCESS',
'return_msg' => 'OK'
];
echo $wxpay->ArrToXml($params);
} catch (\Exception $e) {
$wxpay->logs('', $e->getMessage());
exit();
}
}
/**
* 查询⽀付状态
* @param Request $request
* @return type
*/
public function checkSuccess(Request $request){
$pid = $request->get('id');
if (Cache::get('send'.$pid) == Cache::get('back'.$pid)) {
return RetJosn::successJson('⽀付成功');
} else {
return RetJosn::errorJson(Cache::get('send'.$pid).'|'.Cache::get('back'.$pid));        }
}
}
⼆维码页⾯代码:
<!DOCTYPE html>
<!--
To change this license header, choose License Headers in Project Properties.
To change this template file, choose Tools | Templates
and open the template in the editor.
-->
<html>
<head>
<title>TODO supply a title</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<body>
<div class="btn-box">
<button onclick="getQrcode()">刷新⼆维码</button>
</div>
<div class="qrcode-box">
<img id="qrimg" src="">
</div>
<div class="status-box">
<h2 id="status"></h2>
</div>
</body>
<script src="__STATIC__/default/js/jquery-1.9.1.min.js"></script>
<script>
(function () {
getQrcode();//⼆维码⽣成
})();
/*验证码⽣成*/
function getQrcode() {
var id = getId(10);
var url = "{:url('Index/getQrUrl')}" + "?id=" + id;
$("#qrimg").attr("src", url);
sessionStorage.setItem('id',id);
checkSuccess();//轮询⽀付状态
}
/
*⽣成唯⼀Id*/
function getId(length){
var tmp = Date.parse( new Date() ).toString();
tmp = tmp.substr(0,length);
return tmp;
}
/*轮询⽀付状态*/
function checkSuccess(){
var interval = window.setInterval(function(){
var id = Item('id');
$.ajax({
url:"{:url('Index/checkSuccess')}?id=" + id,
dataType:'json',
success:function(res) {
if (de == 200) {
$('#status').html('订单号:'+id+','+res.msg);
                clearInterval(interval);
}
}
})
},2000)
}
</script>
</html>
效果演⽰:
⽣成⼆维码,并开始启动轮询

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。