微信支付
微信支付,和我们支付宝支付大致都是一样的,只不过微信支付配置的时候很复杂,注意的细节:
开通商务号:
公众号,或者小程序,任意一个就可以,必须要有一个否则,无法申请支付,支付配置就要有appid如果公众号有,那么写公众号,有小程序就有小程序。
支付必备:
- 商务号:
小程序,或公众号任意一个即可。
- Appid
也就是商务号的id
上面两种情况我们如果都没有那么我们可以进行借权,但是借权
扫描二维码关注公众号,回复:
10884157 查看本文章
授权问题:
在登录小程序或者公众号的时候,有的会提示你,要获取你的账户信息,你是否允许,然后它提示你你点击允许,那么他可以获取你的头像和账户信息,有的不用你点击直接进去的,那么他就是静默授权,他获取不到你的头像,和名字,其他内容可以获取的到。
- 商务平台,连续交易90天
切忌不能刷单,不能用一个账号去刷,换着账号去刷,如果一天没有,从新开始
- 支付需要证书,证书两年过期,过期后不能使用,使用支付失败。
- 微信的支付单位是分
- 支付交易类型,有h5,小程序,公众号等。
-
- 支付的流程分析
先说一下支付的流程再说配置问题。
H5流程:
点击下单->后台将订单插入数据库->将订单号、商品名称、价钱(*100,因为他是一分)、appid、商户号、随机字符串、回调url、交易类型,传给微信支付->支付判断->支付成功->同步、异步返回信息->更改订单状态->给腾讯返回的信息(腾讯的订单信息)。
-
- 代码实例
<?php
// +----------------------------------------------------------------------
// | ******微信支付
// +----------------------------------------------------------------------
namespace app\api\controller;
use think\Controller;
use think\DB;
class Wxpay extends Common
{
//微信支付
public function index(){
//接收用户下单信息
$goodsname = input('goodsname');//商品名称
$data['goodsid']=input('goodsid');//商品id
$data['buy_number_count']=input('buy_number_count');//购买数量
$data['total_price']=input('total_price');//商品价格
$data['add_time']=time();//下单时间
$data['phone']=input('phone');//用户手机号
$data['username']=input('username');//用户姓名
$data['address']=input('address');//收货地址
$data['userid']=input('userid');//用户id
if(input('goodstype')){
$data['goodstype']=input('goodstype');//商品类型
}
$user = Db::name('user')->where(array('id' => $data['userid']))->field('openid')->find();//获取当前用户openID/这个我们登录的时候都存在了
//发起微信支付,调用统一下单支付接口
$fee = $data['total_price'];//支付金额
$appid = '****************';//appid.如果是公众号 就是公众号的appid
$body = $goodsname;
$mch_id = '*******************'; //商户号
$nonce_str = $this->nonce_str();//随机字符串
$notify_url = '域名/api/wxpay/notifyurl'; //回调的url
$openid = $user['openid'];
$time = time();
$year = date('Y',$time);
$rand = rand(000000000,999999999);
$out_trade_no = $year.$rand;//订单号
//$out_trade_no = $this->order_number($openid);//商户订单号
$spbill_create_ip = $_SERVER["REMOTE_ADDR"];//服务器的ip;
$total_fee = $fee*100;// 微信支付单位是分,所以这里需要*100
$trade_type = 'JSAPI';//交易类型 默认
$data['order_no']=$out_trade_no;
$order = Db::name('order')->insert($data);
//这里是按照顺序的 因为下面的签名是按照顺序 排序错误 肯定出错
$post['appid'] = $appid;
$post['body'] = $body;
$post['mch_id'] = $mch_id;
$post['nonce_str'] = $nonce_str;//随机字符串
$post['notify_url'] = $notify_url;
$post['openid'] = $openid;
$post['out_trade_no'] = $out_trade_no;
$post['spbill_create_ip'] = $spbill_create_ip;//用户终端的ip
$post['total_fee'] = $total_fee;//总金额
$post['trade_type'] = $trade_type;
$sign = $this->sign($post);//签名
$post_xml = '<xml>
<appid>'.$appid.'</appid>
<body>'.$body.'</body>
<mch_id>'.$mch_id.'</mch_id>
<nonce_str>'.$nonce_str.'</nonce_str>
<notify_url>'.$notify_url.'</notify_url>
<openid>'.$openid.'</openid>
<out_trade_no>'.$out_trade_no.'</out_trade_no>
<spbill_create_ip>'.$spbill_create_ip.'</spbill_create_ip>
<total_fee>'.$total_fee.'</total_fee>
<trade_type>'.$trade_type.'</trade_type>
<sign>'.$sign.'</sign>
</xml> ';
//print_r($post_xml);die;
//统一接口prepay_id
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//调用统一下单
$xml = $this->http_request($url,$post_xml);
$array = $this->xml($xml);//全要大写
//print_r($array);
//统一下单请求成功回调前端支付参数
if($array['RETURN_CODE'] == 'SUCCESS' && $array['RESULT_CODE'] == 'SUCCESS'){
$time = time();
$tmp='';//临时数组用于签名
$tmp['appId'] = $appid;
$tmp['nonceStr'] = $nonce_str;
$tmp['package'] = 'prepay_id='.$array['PREPAY_ID'];
$tmp['signType'] = 'MD5';
$tmp['timeStamp'] = $time;
$data['state'] = 200;
$data['timeStamp'] = $time;//时间戳
$data['nonceStr'] = $nonce_str;//随机字符串
$data['signType'] = 'MD5';//签名算法,暂支持 MD5
$data['package'] = 'prepay_id='.$array['PREPAY_ID'];//统一下单接口返回的 prepay_id 参数值
$data['paySign'] = $this->sign($tmp);//签名
$data['out_trade_no'] = $out_trade_no;
}else{
$data['state'] = 0;
$data['text'] = "错误";
$data['RETURN_CODE'] = $array['RETURN_CODE'];
$data['RETURN_MSG'] = $array['RETURN_MSG'];
}
echo json_encode($data);
}
//随机32位字符串
private function nonce_str(){
$result = '';
$str = 'QWERTYUIOPASDFGHJKLZXVBNMqwertyuioplkjhgfdsamnbvcxz';
for ($i=0;$i<32;$i++){
$result .= $str[rand(0,48)];
}
return $result;
}
//生成订单号
private function order_number($openid){
//date('Ymd',time()).time().rand(10,99);//18位
return md5($openid.time().rand(10,99));//32位
}
//签名 $data要先排好顺序
private function sign($data){
$stringA = '';
foreach ($data as $key=>$value){
if(!$value) continue;
if($stringA) $stringA .= '&'.$key."=".$value;
else $stringA = $key."=".$value;
}
$wx_key = '************************';//申请支付后有给予一个商户账号和密码,登陆后自己设置的key
$stringSignTemp = $stringA.'&key='.$wx_key;
return strtoupper(md5($stringSignTemp));
}
//curl请求
public function http_request($url,$data = null,$headers=array())
{
$curl = curl_init();
if( count($headers) >= 1 ){
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
}
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, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
//获取xml
private function xml($xml){
$p = xml_parser_create();
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
$data = "";
foreach ($index as $key=>$value) {
if($key == 'xml' || $key == 'XML') continue;
$tag = $vals[$value[0]]['tag'];
$value = $vals[$value[0]]['value'];
$data[$tag] = $value;
}
return $data;
}
//支付回调接口
public function notifyurl(){
$res_xml = file_get_contents("php://input");
libxml_disable_entity_loader(true);
$ret = json_decode(json_encode(simplexml_load_string($res_xml,'simpleXMLElement',LIBXML_NOCDATA)),true);
$data = array();
$data['order_sn'] = $ret['out_trade_no'];
$data['trade_no'] = $ret['transaction_id'];
$data['total_fee'] = $ret['total_fee'];
$check_info = DB::name('order')->where(array('order_no'=>$data['order_sn']))->find();
if (!$check_info) {
echo json_encode(array('state'=>1,'msg'=>'订单信息错误...'));
}
$up = array();
$up['status'] = 1;
$up['pay_time'] = time();
$res = DB::name('order')->where(array('order_no'=>$data['order_sn']))->update($up);//更新订单状态
//支付成功升级等级
if($user['status'] == 0){
$device = DB::name('terminus') ->where('userid',$check_info['userid'])->count();//查询用户名下终端机具
$where['status'] = 1;
$where['upd_time'] = time();
if($device >= 10){
$userdata = DB::name('user')->where(['id'=>$check_info['userid']])->update($where);//更新当前用户等级为VIP
if($userdata){
echo json_encode(array('state'=>1,'msg'=>'等级更新成功'));
exit;
}else{
echo json_encode(array('state'=>2,'msg'=>'等级更新失败'));
exit;
}
}
}
//$result = $this->orderhandle($data);
if ($res) {
//将信息返回给腾讯一次
$xml = "<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg>";
$xml.="</xml>";
echo $xml;
}
}
}