随着移动支付的普及,微信成为了国内使用最广泛的支付方式之一。微信支付提供了多种支付方式,二维码支付也受到了越来越多用户的欢迎。本文将介绍如何使用PHP实现微信二维码支付。
一、前置条件
在开始之前,需要准备以下几个条件:
- 微信开发者账号
- 微信支付功能申请通过
- PHP开发环境的搭建
- 微信支付SDK
二、微信支付流程
微信支付的流程可以简单概括为以下几步:
- 用户打开商户的支付页面并选择支付方式
- 商户将用户的订单信息发送给微信支付
- 微信支付生成二维码并返回给商户
- 商户将二维码展示给用户
- 用户使用微信扫描二维码并完成支付
- 微信支付向商户发送支付结果通知
为了实现微信二维码支付,我们需要按照上述流程实现功能。
<?php
namespace common;
use app\common\controller\Common;
use app\common\model\LibWechatConfig;
/**
* 提供微信支付服务管理服务
* @name WxCodePay.php
* @package jypp
* @category model
* @link http://www.chanekeji.com
* @author mengchen
* @version 1.0
* @copyright CHANGE INC
* @since 2023-02-15
*/
class WxPay
{
public $key; //支付秘钥需要更改成自己的
public $appId; //APPID需要更改为自己的
public $mchId; //商户号需要更改成自己的
public $secret; //开发者密码需要更改为自己的
public $uoUrl = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //无需更改 统一下单API地址
public $notifyURL; //支付通知地址需要更改成你自己服务器的地址
public function __construct()
{
$LibWechatConfig = new LibWechatConfig();
$config = $LibWechatConfig->findConfigKeyValue('wechat');
$this->appId = $config['wx_appid'];
$this->mchId = $config['wx_mchid'];
$this->secret = $config['wx_secret'];
$this->key = $config['wx_pay_key'];
$this->notifyURL = $config['wx_notify_url'];
}
//获取签名
public function getSign($arr)
{
//去除数组的空值
array_filter($arr);
if (isset($arr['sign'])) {
unset($arr['sign']);
}
//排序
ksort($arr);
//组装字符
$str = $this->arrToUrl($arr) . '&key=' . $this->key;
//使用md5 加密 转换成大写
return strtoupper(md5($str));
}
//获取带签名的数组
public function setSign($arr)
{
$arr['sign'] = $this->getSign($arr);
return $arr;
}
//校验签名
public function checkSign($arr)
{
//生成新签名
$sign = $this->getSign($arr);
//和数组中原始签名比较
if ($sign == $arr['sign']) {
return true;
} else {
return false;
}
}
//数组转URL字符串 不带key
public function arrToUrl($arr)
{
return urldecode(http_build_query($arr));
}
//记录到文件
public function logs($file, $data)
{
$data = is_array($data) ? print_r($data, true) : $data;
file_put_contents('./logs/' . $file, $data);
}
public function getPost()
{
return file_get_contents('php://input');
}
//Xml 文件转数组
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
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 字符串到接口
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;
}
//统一下单
public function unifiedorder($params)
{
//获取到带签名的数组
$params = $this->setSign($params);
//数组转xml
$xml = $this->ArrToXml($params);
//发送数据到统一下单API地址
$data = $this->postStr($this->uoUrl, $xml);
$arr = $this->XmlToArr($data);
if ($arr['result_code'] == 'SUCCESS' && $arr['return_code'] == 'SUCCESS') {
return $arr;
} else {
$this->logs('error.txt', $data);
return false;
}
}
}
/**
* 生成微信支付二维码
*/
public function getWxpay($orderNum, $total, $body, $isH5 = false)
{
$pay = new WxPay();
$tradeType = 'NATIVE';
if ($isH5) {
$tradeType = 'MWEB';
}
$params = [
'appid' => $pay->appId,
'mch_id' => $pay->mchId,
'nonce_str' => md5(time()),
'body' => $body,
'out_trade_no' => $orderNum,
'total_fee' => $total * 100,
'spbill_create_ip' => $_SERVER['SERVER_ADDR'],
'notify_url' => $pay->notifyURL,
'trade_type' => $tradeType,
'product_id' => $orderNum
];
$result = $pay->unifiedorder($params);
return $result['code_url'];
}