PHP版本微信支付开发----电脑网站扫码支付(native)(心得、总结)

PHP版本微信支付开发----电脑网站扫码支付(native)(心得、总结)

一、申请微信公众服务号并进行认证

二、下载微信支付demo,修改配置信息

1.开发文档

在这里插入图片描述
我做的项目是电脑网站,所以就选择了native支付

在这里插入图片描述
在这里可以下载demo,我下载了PHP的,这是目录结构
在这里插入图片描述
做过支付宝支付的人可能知道支付宝提供了异步回调和同步回调两种方式,而微信没有提供同步回调,只有异步回调(在此处理你的业务逻辑如数据库的更新)。

2.修改配置文件example/Wxpay.config.php

AppId 这是你的微信公众平台的APPID,去微信公众平台里面查看
MerchantId 这是你申请的商户号
NotifyUrl 这是异步回调地址,要求外网可以访问(不能写localhost域名)、不能带任何参数
Key 这是你的APIkey,在微信开发平台里,超级管理员可以修改
在这里插入图片描述

3.配置文件代码:

<?php
/**
*
* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
* 请勿直接直接使用样例对外提供服务
* 
**/
require_once "../lib/WxPay.Config.Interface.php";

/**
*
* 该类需要业务自己继承, 该类只是作为deamon使用
* 实际部署时,请务必保管自己的商户密钥,证书等
* 
*/

class WxPayConfig extends WxPayConfigInterface
{
	//=======【基本信息设置】=====================================
	/**
	 * TODO: 修改这里配置为您自己申请的商户信息
	 * 微信公众号信息配置
	 * 
	 * APPID:绑定支付的APPID(必须配置,开户邮件中可查看)
	 * 
	 * MCHID:商户号(必须配置,开户邮件中可查看)
	 * 
	 */
	public function GetAppId()
	{
		return 'xxxxxxxxxxxx';//jal
	}
	public function GetMerchantId()
	{
		return 'xxxxxxxxxxx';//jal
	}
	
	//=======【支付相关配置:支付成功回调地址/签名方式】===================================
	/**
	* TODO:支付回调url
	* 签名和验证签名方式, 支持md5和sha256方式
	**/
	public function GetNotifyUrl()
	{
		return "http://xxx.xxxxxx.com/JudgeOnline/wxpay/example/notify.php";
	}
	public function GetSignType()
	{
		return "HMAC-SHA256";
	}

	//=======【curl代理设置】===================================
	/**
	 * TODO:这里设置代理机器,只有需要代理的时候才设置,不需要代理,请设置为0.0.0.0和0
	 * 本例程通过curl使用HTTP POST方法,此处可修改代理服务器,
	 * 默认CURL_PROXY_HOST=0.0.0.0和CURL_PROXY_PORT=0,此时不开启代理(如有需要才设置)
	 * @var unknown_type
	 */
	public function GetProxy(&$proxyHost, &$proxyPort)
	{
		$proxyHost = "0.0.0.0";
		$proxyPort = 0;
	}
	

	//=======【上报信息配置】===================================
	/**
	 * TODO:接口调用上报等级,默认紧错误上报(注意:上报超时间为【1s】,上报无论成败【永不抛出异常】,
	 * 不会影响接口调用流程),开启上报之后,方便微信监控请求调用的质量,建议至少
	 * 开启错误上报。
	 * 上报等级,0.关闭上报; 1.仅错误出错上报; 2.全量上报
	 * @var int
	 */
	public function GetReportLevenl()
	{
		return 1;
	}


	//=======【商户密钥信息-需要业务方继承】===================================
	/*
	 * KEY:商户支付密钥,参考开户邮件设置(必须配置,登录商户平台自行设置), 请妥善保管, 避免密钥泄露
	 * 设置地址:https://pay.weixin.qq.com/index.php/account/api_cert
	 * 
	 * APPSECRET:公众帐号secert(仅JSAPI支付的时候需要配置, 登录公众平台,进入开发者中心可设置), 请妥善保管, 避免密钥泄露
	 * 获取地址:https://mp.weixin.qq.com/advanced/advanced?action=dev&t=advanced/dev&token=2005451881&lang=zh_CN
	 * @var string
	 */
	public function GetKey()
	{
		return 'xxxxxxxxxxxxxxxxxxxxxxxxxx';//jal
        //return '6f637dd7fe44a1e8ea19e4599fb2c7ff';//sandbox_sign_key这里有坑
	}
	public function GetAppSecret()
	{
		return '7813490da6f1265e4901ffb80afaa36f';//native不需要填
	}


	//=======【证书路径设置-需要业务方继承】=====================================
	/**
	 * TODO:设置商户证书路径
	 * 证书路径,注意应该填写绝对路径(仅退款、撤销订单时需要,可登录商户平台下载,
	 * API证书下载地址:https://pay.weixin.qq.com/index.php/account/api_cert,下载之前需要安装商户操作证书)
	 * 注意:
	 * 1.证书文件不能放在web服务器虚拟目录,应放在有访问权限控制的目录中,防止被他人下载;
	 * 2.建议将证书文件名改为复杂且不容易猜测的文件名;
	 * 3.商户服务器要做好病毒和木马防护工作,不被非法侵入者窃取证书文件。
	 * @var path
	 */
	public function GetSSLCertPath(&$sslCertPath, &$sslKeyPath)
	{
		$sslCertPath = '../cert/apiclient_cert.pem';
		$sslKeyPath = '../cert/apiclient_key.pem';
	}
}


四、 现在要正式进行编程了,首先是前台的支付页面完成后的跳转

由于微信没有给出同步回调地址,那什么时候完成支付进行页面跳转都需要看我们用js发送请求查询了。

在这里插入图片描述

微信的图片logo是在这个页面下载的,也可以点击点击直接下载


1.native.php代码如下:
<?php
/**
*
* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
* 请勿直接直接使用样例对外提供服务
* 
**/

require_once "../lib/WxPay.Api.php";
require_once "WxPay.NativePay.php";
require_once 'log.php';

//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);


$notify = new NativePay();
//模式二
/**
 * 流程:
 * 1、调用统一下单,取得code_url,生成二维码
 * 2、用户扫描二维码,进行支付
 * 3、支付完成之后,微信服务器会通知支付成功
 * 4、在支付成功通知中需要查单确认是否真正支付成功(见:notify.php)
 */

//jal
$amount = isset($_POST['WIDtotal_amount'])?$_POST['WIDtotal_amount']:"";
$body = isset($_POST['WIDsubject'])?$_POST['WIDsubject']:"";
$total_fee = intval(doubleval($amount)*100);
$product_id = isset($_POST['goods_id'])?$_POST['goods_id']:"";
$attach = isset($_POST['word'])?$_POST['word']:"test";
$out_trade_no = isset($_POST['WIDout_trade_no'])?$_POST['WIDout_trade_no']:"phpsdk".date("YmdHis");
$input = new WxPayUnifiedOrder();
$input->SetBody($body);
$input->SetAttach($attach);
$input->SetOut_trade_no($out_trade_no);
$input->SetTotal_fee($total_fee);
$input->SetTime_start(date("YmdHis"));
$input->SetTime_expire(date("YmdHis", time() + 600));
$input->SetGoods_tag("test");
//$input->SetNotify_url("http://paysdk.weixin.qq.com/notify.php");
$input->SetNotify_url("http://xxx.xxxxxxx.com/JudgeOnline/wxpay/example/notify.php");//这里写你的回调地址
$input->SetTrade_type("NATIVE");
$input->SetProduct_id($product_id);

$result = $notify->GetPayUrl($input);
$url2 = $result["code_url"];
?>

<html>
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <script src="../../template/bs3/jquery.min.js"></script>
    <link rel="icon" href="img/logo.png">
    <title>微信支付</title>

    <script src="https://cdn.bootcss.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div style="padding: 10px 30px">
        <img src="img/logo.png" alt="" style="height: 35px;vertical-align:middle"><span style="font-size: large; font-weight: 600">微信收银台</span>
        </div>
    </div>

    <div class="row" style="background-color: lightgrey; padding: 10px 30px;">
        <div style="display: inline-block;">
            <div>订单编号:<span><?php echo $out_trade_no?></span></div>
            <div>订单名称:<span><?php echo $body?></span></div>
        </div>
        <div style="float: right; display: inline-block;padding: 10px">应付金额:¥<span><?php echo $amount?></span></div>
    </div>
    <div class="row" style="margin: 20px 30px; padding: 10px 20px; border-color: orange; border-style: solid;border-width: medium">
        <div style="display: inline-block">
            <img src="img/WePayLogo.png" alt="" style="height: 50px;vertical-align: middle">
            <img src="img/right.png" alt="" style="height: 30px; vertical-align: middle">
            <span style="color: lightgrey">亿万用户的选择,更快更安全</span>
        </div>
        <div style="float: right; display: inline-block; padding: 10px">
            支付<span style="color: orange"><?php echo $amount?></span></div>
    </div>
    <div class="row" style="text-align: center">
        <img alt="扫码支付" src="qrcode.php?data=<?php echo urlencode($url2);?>" style="width:250px;height:250px;"/><div>
            支付提示:<span id="query_result" style="color: red">WAITING...</span>
        </div>
        <input id="out_trade_no" type="hidden"  value="<?php echo $out_trade_no;?>">
        <img src="img/scan.png" alt="" style="width: 250px; height: 90px">
    </div>
</div>
<script>
    var t1;
    var sum=0;
    $(document).ready(function () {
        t1=setInterval("ajaxstatus()", 3000);//三秒查询一次
    });
    function ajaxstatus() {
        sum++;
        if(sum>600){ window.clearInterval(t1);return false;}//如果查询次数过多就放弃
        if(sum>180){
            m=sum % 10;
            if(m!=0){return false;}
        }
        if ($("#out_trade_no").val() != 0) {
        //此处很关键,用ajax异步查询orderqueryajax.php页面,看看这笔订单是否已完成支付
            $.post("orderqueryajax.php", { out_trade_no:$("#out_trade_no").val() }, function (data) {
                data = $.trim(data);
                $("#query_result").html(data);//一直更新查询结果
                if (data=="SUCCESS") {
                    $("#query_result").html("支付成功,即将跳转...");//如果查询到的结果是成功支付,就进行页面跳转
                    <?php
                    if (isset($_POST['history_go']) && $_POST['history_go'] == 3){
                        echo 'window.setTimeout("history.go(-3);",2000);';//此处只是为了判断是页面返回两页还是三页
                    }else
                    echo 'window.setTimeout("history.go(-2);",2000);';
                    ?>
                }
            });
        }
    }

</script>
</body>
</html>

3. 后台orderqueryajax.php页面,其实这个页面是我仿照已有的example/orderquery.php抄的啦,嘿嘿

<?php
/**
*
* ajax异步查询订单是否完成
* 
**/
require_once "../lib/WxPay.Api.php";
require_once 'log.php';
require_once "WxPay.Config.php";

//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);

$v = $_POST["out_trade_no"];
if(isset($v) && $v != ""){
    $out_trade_no = $v;
    $input = new WxPayOrderQuery();
    $input->SetOut_trade_no($out_trade_no);
    $config = new WxPayConfig();
    $result = WxPayApi::orderQuery($config, $input);
    if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){//返回查询结果
        echo $result['trade_state'];
    }else{
        echo "FAIL";
    }
}
?>

这些写好后,就可以提交到服务器上跑一下啦

哦对了,如果你的代码在服务器上跑不起来的话,连最初demo里面的二维码都无法显示的话,那应该是你的php.ini里面的curl扩展功能没有开,我当时就是因为curl没开,导致在服务器上打开就是500错误,或者检查白名单是否添加;iis话在服务器上打开错误提示信息,根据提示找解决办法就行了

五、支付完成后异步回调,处理业务逻辑如:更新数据库

这一部分功能我是在example/notify.php中处理的

<?php
/**
*
* example目录下为简单的支付样例,仅能用于搭建快速体验微信支付使用
* 样例的作用仅限于指导如何使用sdk,在安全上面仅做了简单处理, 复制使用样例代码时请慎重
* 请勿直接直接使用样例对外提供服务
* 
**/

require_once "../lib/WxPay.Api.php";
require_once '../lib/WxPay.Notify.php';
require_once "WxPay.Config.php";
require_once 'log.php';
require_once("../../include/memcache.php");
//初始化日志
$logHandler= new CLogFileHandler("../logs/".date('Y-m-d').'.log');
$log = Log::Init($logHandler, 15);

class PayNotifyCallBack extends WxPayNotify
{
	//查询订单
	public function Queryorder($transaction_id)
	{
		$input = new WxPayOrderQuery();
		$input->SetTransaction_id($transaction_id);

		$config = new WxPayConfig();
		$result = WxPayApi::orderQuery($config, $input);
		Log::DEBUG("query:" . json_encode($result));
		if(array_key_exists("return_code", $result)
			&& array_key_exists("result_code", $result)
			&& $result["return_code"] == "SUCCESS"
			&& $result["result_code"] == "SUCCESS")
		{
			return true;
		}
		return false;
	}

	/**
	*
	* 回包前的回调方法
	* 业务可以继承该方法,打印日志方便定位
	* @param string $xmlData 返回的xml参数
	*
	**/
	public function LogAfterProcess($xmlData)
	{
		Log::DEBUG("call back, return xml:" . $xmlData);
		return;
	}
	
	//重写回调处理函数
	/**
	 * @param WxPayNotifyResults $data 回调解释出的参数
	 * @param WxPayConfigInterface $config
	 * @param string $msg 如果回调处理失败,可以将错误信息输出到该方法
	 * @return true回调出来完成不需要继续回调,false回调处理未完成需要继续回调
	 */
	public function NotifyProcess($objData, $config, &$msg)
	{
		$data = $objData->GetValues();
		//TODO 1、进行参数校验
		if(!array_key_exists("return_code", $data) 
			||(array_key_exists("return_code", $data) && $data['return_code'] != "SUCCESS")) {
			//TODO失败,不是支付成功的通知
			//如果有需要可以做失败时候的一些清理处理,并且做一些监控
			$msg = "异常异常";
			return false;
		}
		if(!array_key_exists("transaction_id", $data)){
			$msg = "输入参数不正确";
			return false;
		}

		//TODO 2、进行签名验证
		try {
			$checkResult = $objData->CheckSign($config);
			if($checkResult == false){
				//签名错误
				Log::ERROR("签名错误...");
				return false;
			}
		} catch(Exception $e) {
			Log::ERROR(json_encode($e));
		}

		//TODO 3、处理业务逻辑
		Log::DEBUG("call back:" . json_encode($data));
		$notfiyOutput = array();
		
		
		//查询订单,判断订单真实性
		if(!$this->Queryorder($data["transaction_id"])){
			$msg = "订单查询失败";
			return false;
		}

        //可以在此处写入数据库
        $trade_no = $data['transaction_id'];
		$trade_status = $data['result_code'];
		$receipt_amount = $data['total_fee'];
		$gmt_payment = date("Y-m-d H:i:s");
		$buyer_logon_id = "";
		$buyer_user_id = "";
		$total_amount = $data['total_fee'];
		$out_trade_no = $data['out_trade_no'];
		$body = "";
		$subject= pdo_query("select subject from trade WHERE out_trade_no = ?", $out_trade_no)[0][0];
        $sql = "update trade set trade_no = ?,
  trade_status = ?,valid=1,
  receipt_amount = ?, gmt_payment = ?,
  buyer_logon_id = ?, buyer_user_id = ? where out_trade_no = ? limit 1; 
";
        $res =  pdo_query($sql,$trade_no, $trade_status,
            $receipt_amount,
            $gmt_payment, $buyer_logon_id, $buyer_user_id,$out_trade_no);
        $sql = "update goods set goods_number = goods_number-1, goods_trade_number = goods_trade_number+1 where goods_name=?";
        pdo_query($sql, $subject);

		return true;
	}
}

$config = new WxPayConfig();
Log::DEBUG("begin notify");
$notify = new PayNotifyCallBack();
$notify->Handle($config, false);

如果你的回调中的代码没有生效,但你的回调地址又没有写错的话,估计你是和我遇着同样的坑了,且不得不填。极有可能是因为微信给你发的支付通知信息你没收到,解决方法我写在这篇文里面了,微信支付开发中的坑---- php废弃$GLOBALS[‘HTTP_RAW_POST_DATA’]
————————————————
版权声明:本文为CSDN博主「爱玲姐姐」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/jal517486222/article/details/84928429

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值