1.微信开发文档 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
2.微信支付sdk下载:https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1
3.Thinkphp5.0下载:http://www.thinkphp.cn/down.html
4.注意在微信平台配置好域名等参数
1.获取openid需要前端给一个code,通过code获取open_id
2.php封装一个http请求函数
/**
* 发送HTTP请求方法
* @param string $url 请求URL
* @param array $params 请求参数
* @param string $method 请求方法GET/POST
* @return array $data 响应数据
*/
function httpCurl($url, $params, $method = 'POST', $header = array(), $multi = false){
date_default_timezone_set('PRC');
$opts = array(
CURLOPT_TIMEOUT => 30,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_HTTPHEADER => $header,
CURLOPT_COOKIESESSION => true,
CURLOPT_FOLLOWLOCATION => 1,
CURLOPT_COOKIE =>session_name().'='.session_id(),
);
/* 根据请求类型设置特定参数 */
switch(strtoupper($method)){
case 'GET':
// $opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
// 链接后拼接参数 & 非?
$opts[CURLOPT_URL] = $url . '?' . http_build_query($params);
break;
case 'POST':
//判断是否传输文件
$params = $multi ? $params : http_build_query($params);
$opts[CURLOPT_URL] = $url;
$opts[CURLOPT_POST] = 1;
$opts[CURLOPT_POSTFIELDS] = $params;
break;
default:
throw new Exception('不支持的请求方式!');
}
/* 初始化并执行curl请求 */
$ch = curl_init();
curl_setopt_array($ch, $opts);
$data = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if($error) throw new Exception('请求发生错误:' . $error);
return $data;
}
3.获取open_id
public function get_access_token($code)
{
$params['secret']=$this->appsecret;
$params['appid']=$this->appid;
$params['code']=$code;
$params['grant_type']="authorization_code";
$token_url = "https://api.weixin.qq.com/sns/oauth2/access_token";
$token_data = $this->httpCurl($token_url, $params, 'GET');
$token_data=json_decode($token_data);
$token_data = (array)$token_data;
return $token_data;
}
4.获取用户信息
public function get_user_info($access_token)
{
$params['secret']=$this->appsecret;
$params['appid']=$this->appid;
$params['access_token']=$access_token['access_token'];
$params['openid']=$access_token['openid'];
$params['lang']='zh_CN';
$url = "https://api.weixin.qq.com/sns/userinfo";
$token_data = $this->httpCurl($url, $params, 'GET');
$token_data=json_decode($token_data);
$token_data = (array)$token_data;
return $token_data;
}
1.微信支付类,引用于白俊遥博客中thinkphp3.2的写的支付类
附上源码
use think\Config;
error_reporting(E_ALL);
ini_set('display_errors', '1');
header("Content-Type: text/html;charset=utf-8");
// 定义时区
ini_set('date.timezone','Asia/Shanghai');
class Weixinpay {
// 定义配置项
private $config=array(
'APPID' => '', // 微信支付APPID
'MCHID' => '', // 微信支付MCHID 商户收款账号
'KEY' => '', // 微信支付KEY
'APPSECRET' => '', //公众帐号secert
'NOTIFY_URL' => 'http://paysdk.weixin.qq.com/notify.php', // 接收支付状态的连接 改成自己的域名
);
// 构造函数
public function __construct(){
// 如果不是在thinkphp框架中使用;那么注释掉下面一行代码;直接补全 private $config 即可
$this->config= Config::get('WEIPAY');
}
/**
* 统一下单
* @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
*/
public function unifiedOrder($order){
// 获取配置项
$weixinpay_config=$this->config;
$config=array(
'appid'=>$weixinpay_config['APPID'],
'mch_id'=>$weixinpay_config['MCHID'],
'nonce_str'=>'test',
'spbill_create_ip'=>'127.0.0.1',
'notify_url'=>$weixinpay_config['NOTIFY_URL']
);
// 合并配置数据和订单数据
$data=array_merge($order,$config);
// 生成签名
$sign=$this->makeSign($data);
$data['sign']=$sign;
$xml=$this->toXml($data);
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//接收xml数据的文件
$header[] = "Content-type: text/xml";//定义content-type为xml,注意是数组
$ch = curl_init ($url);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 兼容本地没有指定curl.cainfo路径的错误
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
$response = curl_exec($ch);
if(curl_errno($ch)){
// 显示报错信息;终止继续执行
curl_error($ch);
}
curl_close($ch);
$result=$this->toArray($response);
// 显示错误信息
if ($result['return_code']=='FAIL') {
die($result['return_msg']);
}
$result['sign']=$sign;
$result['nonce_str']='test';
return $result;
}
/**
* 验证
* @return array 返回数组格式的notify数据
*/
public function notify(){
// 获取xml
$xml=file_get_contents('php://input', 'r');
// 转成php数组
$data=$this->toArray($xml);
// 保存原sign
$data_sign=$data['sign'];
// sign不参与签名
unset($data['sign']);
$sign=$this->makeSign($data);
// 判断签名是否正确 判断支付状态
if ($sign===$data_sign && $data['return_code']=='SUCCESS' && $data['result_code']=='SUCCESS') {
$result=$data;
}else{
$result=false;
}
// 返回状态给微信服务器
if ($result) {
$str=' ';
}else{
$str=' ';
}
echo $str;
return $result;
}
/**
* 输出xml字符
* @throws WxPayException
**/
public function toXml($data){
if(!is_array($data) || count($data) <= 0){
throw new WxPayException("数组数据异常!");
}
$xml = "" ;
foreach ($data as $key=>$val){
if (is_numeric($val)){
$xml.="<".$key.">".$val."".$key.">";
}else{
$xml.="<".$key.">.$val."]]>".$key.">";
}
}
$xml.="";
return $xml;
}
/**
* 生成签名
* @return 签名,本函数不覆盖sign成员变量,如要设置签名需要调用SetSign方法赋值
*/
public function makeSign($data){
// 去空
$data=array_filter($data);
//签名步骤一:按字典序排序参数
ksort($data);
$string_a=http_build_query($data);
$string_a=urldecode($string_a);
//签名步骤二:在string后加入KEY
$config=$this->config;
$string_sign_temp=$string_a."&key=".$config['KEY'];
//签名步骤三:MD5加密
$sign = md5($string_sign_temp);
// 签名步骤四:所有字符转为大写
$result=strtoupper($sign);
return $result;
}
/**
* 将xml转为array
* @param string $xml xml字符串
* @return array 转换得到的数组
*/
public function toArray($xml){
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$result= json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $result;
}
/**
* 获取jssdk需要用到的数据
* @return array jssdk需要用到的数据
*/
public function getParameters($data){
// 获取配置项
$config=$this->config;
// 取出订单号
$out_trade_no=$data['out_trade_no'];
// 组合获取prepay_id的url
$openid=$data['openid'];
// 订单数据 请根据订单号out_trade_no 从数据库中查出实际的body、total_fee、out_trade_no、product_id
$order=array(
'body'=>'test',// 商品描述(需要根据自己的业务修改)
'total_fee'=>1,// 订单金额 以(分)为单位(需要根据自己的业务修改)
'out_trade_no'=>$out_trade_no,// 订单号(需要根据自己的业务修改)
'product_id'=>'1',// 商品id(需要根据自己的业务修改)
'trade_type'=>'JSAPI',// JSAPI公众号支付
'openid'=>$openid// 获取到的openid
);
// 统一下单 获取prepay_id
$unified_order=$this->unifiedOrder($order);
// 获取当前时间戳
$time=time();
// 组合jssdk需要用到的数据
$data=array(
'appId'=>$config['APPID'], //appid
'timeStamp'=>strval($time), //时间戳
'nonceStr'=>$unified_order['nonce_str'],// 随机字符串
'package'=>'prepay_id='.$unified_order['prepay_id'],// 预支付交易会话标识
'signType'=>'HMAC-SHA256'//加密方式
);
// 生成签名
$data['paySign']=$this->makeSign($data);
return $data;
}
/**
* 生成支付二维码
* @param array $order 订单 必须包含支付所需要的参数 body(产品描述)、total_fee(订单金额)、out_trade_no(订单号)、product_id(产品id)、trade_type(类型:JSAPI,NATIVE,APP)
*/
public function pay($order){
$result=$this->unifiedOrder($order);
$decodeurl=urldecode($result['code_url']);
qrcode($decodeurl);
}
/**
* curl 请求http
*/
public function curl_get_contents($url){
$ch=curl_init();
curl_setopt($ch, CURLOPT_URL, $url); //设置访问的url地址
// curl_setopt($ch,CURLOPT_HEADER,1); //是否显示头部信息
curl_setopt($ch, CURLOPT_TIMEOUT, 5); //设置超时
curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); //用户访问代理 User-Agent
curl_setopt($ch, CURLOPT_REFERER,$_SERVER['HTTP_HOST']); //设置 referer
curl_setopt($ch,CURLOPT_FOLLOWLOCATION,1); //跟踪301
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); //返回结果
$r=curl_exec($ch);
curl_close($ch);
return $r;
}
}
Vendor('Weixinpay.Weixinpay');
$wxpay=new \Weixinpay();
// 获取jssdk需要用到的数据
$paydata=['out_trade_no'=>time(),"openid"=>"test"];
$data=$wxpay->getParameters($paydata);
// 将数据分配到前台页面
$assign=array(
'data'=>($data)
);
return json($assign);
3.支付回调
Vendor('Weixinpay.Weixinpay');
$wxpay=new \Weixinpay();
$data=$wxpay->notify();
if (!$data) {
return 0;
}
注意获取jssdk的接口路径需要,要在微信平台配置
附件 https://pan.baidu.com/s/15E2miSrBp_AEYyUJNYizlw 提取码 vyzs
Vendor('weixin.JsSdk');
$jssdk = new \JsSdk("open_id", "key");
$r=Request::instance();
$url=$r->param("url");
if(empty($url)){
return json(['code'=>0,"msg"=>"url不可为空!"]);
}
$signPackage = $jssdk->GetSignPackage($url);
if($signPackage==0){
return json(['code'=>0,"data"=>"","msg"=>"获取失败"]);
}
return json(['code'=>1,"data"=>$signPackage,"msg"=>"获取成功"]);