php 微信支付V3 APP支付
前言:微信支付现在分为v2版和v3版,2014年9月10号之前申请的为v2版,之后申请的为v3版。V3版的微信支付没有paySignKey参数.
php 微信支付类
<?php
class Wechat {
protected $wechat_config;
//https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
public function __construct($wechat_config = [])
{
if(empty($wechat_config)){
$wechat_config = [
'appid'=>'',
'mch_id'=>'',
'api_key'=>'',
'appsecret'=>'',
'notify_url'=>'',
];
}
$this->wechat_config = $wechat_config;
}
//生成预支付订单
public function wx_pay($body,$total_fee,$out_trade_no,$attach = 'charge_order') {
$nonce_str = $this->rand_code(); //调用随机字符串生成方法获取随机字符串
$data['appid'] = $this->wechat_config['appid']; //appid
$data['mch_id'] = $this->wechat_config['mch_id'] ; //商户号
$data['body'] = $body;
$data['spbill_create_ip'] = $this->get_client_ip(); //ip地址
$data['total_fee'] = $total_fee; //金额
$data['out_trade_no'] = $out_trade_no; //商户订单号,不能重复
$data['nonce_str'] = $nonce_str; //随机字符串
$data['notify_url'] = $this->wechat_config['notify_url']; //回调地址,用户接收支付后的通知,必须为能直接访问的网址,不能跟参数
$data['trade_type'] = 'APP'; //支付方式
$data['attach'] = $attach; //商户携带订单的自定义数据
//将参与签名的数据保存到数组 注意:以上几个参数是追加到$data中的,$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
$data['sign'] = self::getSign($data,$this->wechat_config['api_key']); //获取签名
$xml = self::ToXml($data); //数组转xml
//curl 传递给微信方
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//header("Content-type:text/xml");
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
if(stripos($url,"https://")!==FALSE){
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
} else {
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
}
//设置header
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, TRUE);
//传输文件
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
//返回成功,将xml数据转换为数组.
$re = self::FromXml($data);
if($re['return_code'] != 'SUCCESS'){
return [
'code'=>'201',
'msg'=>$re['return_msg']
];
}
else{
//接收微信返回的数据,传给APP!
$arr =array(
'prepayid' =>$re['prepay_id'],
'appid' => $this->wechat_config['appid'],
'partnerid' => $this->wechat_config['mch_id'],
'package' => 'Sign=WXPay',
'noncestr' => $nonce_str,
'timestamp' =>strval(time()),
);
//第二次生成签名
$sign = self::getSign($arr,$this->wechat_config['api_key']);
$arr['sign'] = $sign;
$arr['code'] = '200';
$arr['msg'] = '签名成功';
return $arr;
}
} else {
$error = curl_errno($ch);
curl_close($ch);
return [
'code'=>'201',
'msg'=>"curl出错,错误码:$error"
];
}
}
//参数要组装成xml格式
public static function ToXml($data = array()){
if (!is_array($data) || count($data) <= 0) {
return '数组异常';
}
$xml = "<xml>";
foreach ($data as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
public static function FromXml($xml)
{
if(!$xml){
echo "xml数据异常!";
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
//生成随机字符串
private function rand_code(){
$str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
$str = str_shuffle($str);
$str = substr($str,0,32);
return $str;
}
/*
获取当前服务器的IP
*/
private function get_client_ip(){
if ($_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 = "unknown";
}
return $cip;
}
//生成签名
public static function getSign($params,$api_key) {
ksort($params); //将参数数组按照参数名ASCII码从小到大排序
foreach ($params as $key => $item) {
if (!empty($item)) { //剔除参数值为空的参数
$newArr[] = $key.'='.$item; // 整合新的参数数组
}
}
$stringA = implode("&", $newArr); //使用 & 符号连接参数
$stringSignTemp = $stringA."&key=".$api_key; //拼接key
// key是在商户平台API安全里自己设置的
$stringSignTemp = MD5($stringSignTemp); //将字符串进行MD5加密
$sign = strtoupper($stringSignTemp); //将所有字符转换为大写
return $sign;
}
}
调起微信支付
//生成微信支付预订单信息
$wechat_config = [
'appid'=>$this->config->openWeixin->appid,
'mch_id'=>$this->config->openWeixin->mch_id,
'api_key'=>$this->config->openWeixin->api_key,
'appsecret'=>$this->config->openWeixin->appsecret,
'notify_url'=>$this->config->openWeixin->notify_url,
];
$order_no = date('YmdHis').rand(1000,9999);
$money = 1;
$wechat = new Wechat($wechat_config);
$wechat_data = $wechat->wx_pay('test',$money,$order_no,'aid_order'); if($wechat_data['code'] != 200){
echo $wechat_data['msg'];die;
}
$result = [ 'order_no'=>$order_no , 'money'=>$money, 'wechat_data'=>$wechat_data, ];
print_r($result);die;
微信支付回调
// 微信支付回调
public function wx_notifyAction(){
defined('BASE_PATH') || define('BASE_PATH', getenv('BASE_PATH') ?: realpath(dirname(__FILE__) . '/../..'));
//接收微信返回的数据数据,返回的xml格式
$xmlData = file_get_contents('php://input');
//将xml格式转换为数组
$data = Wechat::FromXml($xmlData);
//用日志记录检查数据是否接受成功,验证成功一次之后,可删除。
$file_name = BASE_PATH.'/log'.date('Ymd').'.txt';
//$file = fopen($file_name, 'a+') or die("Unable to open file!");;
//fwrite($file,'test:'.json_encode($data));die;
//为了防止假数据,验证签名是否和返回的一样。
//记录一下,返回回来的签名,生成签名的时候,必须剔除sign字段。
$sign = $data['sign'];
unset($data['sign']);
if($sign == Wechat::getSign($data,$this->config->openWeixin->api_key)){
//签名验证成功后,判断返回微信返回的
if ($data['result_code'] == 'SUCCESS') {
//根据返回的订单号做业务逻辑
$res = false;
if($data['attach'] == 'aid_order'){
$model = new PetAidOrder();
//宠物援助
$PetAidOrderData = $model::findFirst([
'order_no = :out_trade_no: AND pay_type = 2 AND status = 2',
'bind'=>[
'out_trade_no'=>$data['out_trade_no'],
]
]);
$getPetAidData = PetAid::findFirst([
'id = :pet_aid_id:',
'bind'=>[
'pet_aid_id'=>$PetAidOrderData->pet_aid_id
]
]);
if($PetAidOrderData && $getPetAidData){
/*===================事务开启================================*/
$connection = $model->getWriteConnection();
$connection->begin();
//更新订单数据
$PetAidOrderData->status = 1;
$PetAidOrderData->pay_time = time();
//更新项目数据
$getPetAidData->get_money += $PetAidOrderData->money;
if($PetAidOrderData->update() && $a = $getPetAidData->update()){$connection->commit();
$res = true;
} } }elseif($data['attach'] == 'rescue_order'){
$model = new UserRescueOrder();
//爱心捐献
$UserRescueOrderData = $model::findFirst([
'order_no = :out_trade_no: AND pay_type = 2 AND status = 2',
'bind'=>[
'out_trade_no'=>$data['out_trade_no'],
]
]); $getUserRescueAuthData = UserRescueAuth::findFirst([
'id = :user_resuce_auth_id:',
'bind'=>[
'user_resuce_auth_id'=>$UserRescueOrderData->user_resuce_auth_id
]
]); if($UserRescueOrderData && $getUserRescueAuthData){
/*===================事务开启================================*/
$connection = $model->getWriteConnection();
$connection->begin();
//更新订单数据
$UserRescueOrderData->status = 1;
$UserRescueOrderData->pay_time = time();
//更新救助中心数据
$getUserRescueAuthData->donation_money += $UserRescueOrderData->money; if($UserRescueOrderData->update() && $getUserRescueAuthData->update()){
$connection->commit();
$res = true;
}
} } //处理完成之后,告诉微信成功结果!
if($res == true){
echo '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
exit();
}else{
$file = fopen($file_name, 'a+');
fwrite($file,date("Y-m-d H:i:s")."错误信息:数据修改失败,".json_encode($data).PHP_EOL);
}
}
//支付失败,输出错误信息
else{
$file = fopen($file_name, 'a+');
fwrite($file,date("Y-m-d H:i:s")."错误信息:支付失败,".json_encode($data).PHP_EOL);
}
}
else{
$file = fopen($file_name, 'a+');
fwrite($file,date("Y-m-d H:i:s")."错误信息:签名验证失败,".json_encode($data).PHP_EOL);
} }
php 微信支付V3 APP支付的更多相关文章
- asp.net core 微信扫码支付(扫码支付,H5支付,公众号支付,app支付)之1
2018-08-13更新生成二维码的方法 在做微信支付前,首先要了解你需要什么方式的微信支付,目前本人做过的支付包含扫码支付.H5支付.公众号支付.App支付等,本人使用的是asp.net mvc c ...
- 微信支付(APP支付)-服务端开发(一)
微信支付,首先需要注册一个商户平台公众账号,(网址:https://pay.weixin.qq.com/index.php/home/d_login) 目前微信支付的接入方式有四种方式:公众号支付,A ...
- 微信、支付宝App支付-JPay0.0.2发布
JPay 对微信App支付.支付宝App支付的二次封装,对外提供一个相对简单的接口以及支付结果的回调 GitHub:https://github.com/Javen205/JPay OsChina:h ...
- 微信支付之App支付
项目接入微信支付的准备工作: 注册成为开发者,进行资质认证,这里是需要300元的审核费用的: 在微信商户平台创建应用,提交等待审核(大致需要5-7个工作日): 应用审核通过之后,进入应用,开通微信支付 ...
- asp.net core 微信APP支付(扫码支付,H5支付,公众号支付,app支付)之4
微信app支付需要以下参数,类封装如下 public class WxPayModel { /// <summary> /// 应用ID /// </summary> publ ...
- uni-app - 支付(app支付、小程序支付、h5(微信端)支付)
App支付.小程序支付.h5(微信端)支付 APP支付(内置) appPay.js /** * 5+App支付,仅支持支付宝以及微信支付 * * 支付宝Sdk集成,微信sdk未集成 * * @para ...
- 微信JSAPI 公众号支付 H5支付以及APP支付 WEBAPI接口开发测试
统一下单入口 调用该方法入口: public void WxPayAPI() { //string PayPrice ="99.9"; ////订单号 //string Payor ...
- ThinkPHP 5 整合支付宝微信支付(支付宝H5,微信H5、APP支付、公众号支付)
因项目没有PC站所以没有写电脑网站支付. Pay.php支付控制器 <?php // +----------------------------------------------------- ...
- php支付走过的坑(微信篇 包含h5支付和app支付 注册 秘钥 环境等等配置)
支付这东西,说容易也容易,说难也难 代码这玩意还比较好说 但是 如果没有demo 直接去看官方文档 十有八九一脸懵逼 今天就整理一下 支付这块走过的坑 涉及 微信h5支付 支付宝h5支付 (api文档 ...
随机推荐
- 2018-2019-1 20189221《Linux内核原理与分析》第三周作业
2018-2019-1 20189221<Linux内核原理与分析>第三周作业 实验二 完成一个简单的时间片轮转多道程序内核代码 实验过程 在实验楼中编译内核 编写mymain.c函数和m ...
- PHP处理大文件下载
<?php /** * Created by PhpStorm. * User: Kung * Date: 15-10-21 * Time: 下午8:00 */ set_time_limit(0 ...
- CentOS6.5下实现R绘图
1.首先安装R的绘图包Cairo 下载地址:http://www.rforge.net/Cairo/files/ [root@Hadoop-NN-01 mysofts]# R CMD INSTALL ...
- iOS 开发笔记-NSURLConnection的使用
通过NSURLConnection发送一个HTTP GET请求 //send a GET request to server with some params -(void)httpGetWithPa ...
- 【cocos2d-js官方文档】事件分发监听机制(摘录)
简介 游戏开发中一个很重要的功能就是交互,如果没有与用户的交互,那么游戏将变成动画,而处理用户交互就需要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件处理逻 ...
- Django Form(表单)
前台用 get 或 post 方法向后台提交一些数据. GET方法: html示例(保存在templates文件夹中): <!DOCTYPE html> <html> < ...
- java-Unicode与中文的转换
package utils; import org.apache.commons.lang3.StringUtils; public class UnicodeUtils { public stati ...
- UGUI之Scrollbar使用
这个效果主要用到了3个组件(对象): 1:Scrollbar对象 滚动条 2:Scroll Rect组件 让对象具有滑动效果 3:Mask组件 遮罩层.把多余的部分隐藏不显示 Scrollbar ...
- shell编程:for循环
有几个参数执行几次 do done取代了{} 这种用于 文件的个数,用户的个数等. (())里才可以进行加减乘除.
- webapp定位
<!doctype html> <html> <head> <meta charset="utf-8"> <meta http ...