**
PHP微信APP端支付流程(已通)
**
关于微信支付,看了很多遍tx的文档。不得不说,很辣鸡,遇到过很多坑,我在这里总结一下,希望能给大家有所帮助。话不多说,上代码!!!
1、首先调用微信统一下单接口
// 实际参数可以根据业务写入
$data = [
'appid' => 'APP应用id’,
'mch_id' => '商户号id',
// 随机字符串
'nonce_str' => $this->actionRandomString(),
'body' => '商品描述’,
'out_trade_no' => '订单号’,
// 金额要乘100,因为微信是以分为单位,而且不能有小数点
'total_fee' => '金额',
// IP地址
'spbill_create_ip' => $this->actionClientIp();
'notify_url' => '回调地址(很重要)',
// 支付方式
'trade_type' => ‘APP’,
];
// 签名验证
$data['sign'] = $this->actionSign($data);
// 将数组转为xml格式
$datas = $this->arrayToXml($data);
// 请求微信的url地址
$response = $this->httpRequest($url, $datas);
这里用到了几个方法:
获取随机字符串
// 生成32位随机字符串
public function actionRandomString() {
$str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; //62个字符
$str = str_shuffle($str);
$strimg = substr($str, 0, 32);
return $strimg;
}
获取IP地址
// 获取当前IP地址
public function actionClientIp() {
if (isset($_SERVER['REMOTE_ADDR'])) {
$cip = $_SERVER['REMOTE_ADDR'];
} elseif (getenv("REMOTE_ADDR")) {
$cip = getenv("REMOTE_ADDR");
} elseif (getenv("HTTP_CLIENT_IP")) {
$cip = getenv("HTTP_CLIENT_IP");
} else {
$cip = "127.0.0.1";
}
return $cip;
}
签名的生成
// 微信签名生成
public function actionSign($params) {
// 将参数数组按照参数名ASCII码从小到大排序
ksort($params);
foreach ($params as $key => $item) {
if (!empty($item)) {
// 剔除参数值为空的参数并整合为新的数组
$newArr[] = $key . '=' . $item;
}
}
$stringA = implode("&", $newArr);
// 使用 & 符号连接参数
$stringSignTemp = $stringA . "&key=" . "自己的key值(32位)";
// 将字符串进行MD5加密
$stringSignTemp = MD5($stringSignTemp);
// 将所有字符转换为大写
$sign = strtoupper($stringSignTemp);
return $sign;
}
将数组转为xml格式
// 有些数组转xml格式会出现CDATA字符,在微信平台校验的时候会出现错误,把代码中CDATA删除即可
public function arrayToXml($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 . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
请求url地址
// http请求
public function httpRequest($url, $data = null) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
到这里可以打印下输出的内容,到微信签名校验平台校验一下,看一下是否出现问题
然后在第一段代码中接着往下写,进行二次签名校验
// 请求微信接口后会下发xml格式,这里要把xml格式转为数组进行判断
$responseArr = $this->xmlToArray($response);
if ($responseArr["return_code"] == 'SUCCESS' && $responseArr["return_code"] == 'SUCCESS') {
// 进行二次签名验证
$two_data['appid'] = '同上',
$two_data['partnerid'] = '同上',
// 预支付id是微信下发的
$two_data['prepayid'] = $responseArr['prepay_id'];
// 32位随机字符串
$two_data['noncestr'] = $this->actionRandomString();
// 时间,可以直接获取为int类型,这里我处理为字符串格式(前端需要)
$two_data['timestamp'] = '' . time() . '';
$two_data['package'] = "Sign=WXPay";
// 再次进行签名验证
$two_data['sign'] = $this->actionSign($two_data);
return $two_data;
} else {
return '错误';
}
这里用到一个方法,将xml格式转为数组
public static function xmlToArray($xml) {
$array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $array_data;
}
到此为止,可以让前端把输出$two_data数组的内容去请求微信支付,查看是否能支付
2、回调
回调地址是统一下单接口中的notify_url字段,是支付成功后,处理自己业务逻辑的一个步骤
// 微信下发的依旧是xml格式,需要进行转换
public function actionWxCallBack() {
// 获取返回的xml
$testxml = file_get_contents("php://input");
// 将xml转化为数组
$result = $this->xmlToArray($testxml);
if ($result) {
if ($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS') {
// 微信会下发订单号$result['out_trade_no']
echo '处理自己的业务逻辑';
}else{
echo '错误';
}
}else{
echo '错误';
}
}
微信支付到这里已经完成了,希望可以帮助到您! ! !
小白一名
不足之处
多多担待
共同进步