一、支付准备

二、获取用户openid

首先,到微信公众平台后台 - 设置 - 网页授权域名(别忘了添加开发者)

// 在头部引入WechatPubService.php文件,见附录一

use app\api\service\WechatPubService;

/**

* 获取code

*/

public function getInfo(){

//前端传code过来

$code = $this->request->param('code');

// dump($code);die;

if (isset($code)) {

$wechat_public = config('wechat_public');

try {

$wechatService = new WechatPubService($wechat_public);

$token = file_get_contents($wechatService->getToken($code));

$token = json_decode($token, true);

// dump($token);

} catch (\Exception $e) {

return $this->json_error('系统错误');

}

if (!isset($token['errcode'])) {

$useInfo = $wechatService->getUserInfo($token['access_token'], $token['openid']);

$useInfo = json_decode($useInfo, true);

// dump($useInfo);

return $this->json_success('获取用户信息成功', $useInfo);

} else {

return $this->json_error('获取用户token失败');

}

} else {

return $this->json_error('code能不能为空');

}

}

三、项目安装Payment

安装Payment的前提条件为PHP版本 大于7.0,项目下命令行运行:composer require "riverslei/payment:*",即可安装成功。

Payment为第三方支付SDK,项目地址:https://github.com/helei112g/payment,可以去了解更多的支付接入。

四、接入支付

服务端,创建支付订单,获取支付参数并传给客户端

// 头部引入

use Payment\Common\PayException;

use Payment\Client\Charge;

use Payment\Config;

use Payment\Client\Notify;

use Payment\Notify\PayNotifyInterface;

/**

* 创建订单,并调起支付

*/

public function create_order()

{

if (IS_POST) {

//

//---------- 获取订单参数 ----------

//$openid = $this->request->param('openid');

//

//---------- 获取订单参数结束 ----------

//---------- 验证订单参数 ----------

//if (!$openid) {

// return $this->json_error('openid不能为空');

//}

//

//---------- 验证订单参数结束 ----------

// 生成订单号

$orderNo = date('ymdHi') . rand(1000, 9999);

Db::startTrans();

try {

//

//---------- 以下为处理具体业务,并进行数据库操作 ----------

//

//

//---------- 处理具体业务结束 ----------

//---------- 以下为发起微信支付 ----------

// 支付订单信息,即传递给微信的参数

$payData = [

'body' => '校友捐赠', //商品描述 用户支付后看不到此项

'subject' => '校友捐赠', //商品详情

'order_no' => $orderNo,

'timeout_express' => time() + 600,// 表示必须 600s 内付款

'amount' => 0.01,// 微信沙箱模式,需要金额固定为3.01 单位:元

'return_param' => 'JSAPI', // 支付回调值

'client_ip' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '127.0.0.1',// 客户地址

'openid' => $openid,

'product_id' => '123',

];

// 获取微信配置

$channel = 'wx_pub';// wx_app wx_pub wx_qr wx_bar wx_lite wx_wap

$wxConfig = config('wechat.wx_pay'); // 这里的配置文件见附录二

$ret = Charge::run($channel, $wxConfig, $payData);

Db::commit();

} catch (Exception $e) {

Db::rollback();

return $this->json_error('调取支付失败'.$e->getMessage() );

}

if (!empty($ret)) {

return $this->json_success('调取支付成功', $ret);

} else {

return $this->json_error('调取支付失败');

}

}

}

客户端,调起支付,若成功支付则进入下一步

服务端,到支付回调方法下查看回调结果 (这里需要注意后台拿到回调结果后,需要进行签名验证提高安全性)

/**

* 支付回调方法

*/

public function notify(){

// file_put_contents('upload/1.txt' , '进入了回调');

// 获取回调值

$xmlData = file_get_contents('php://input');

// 解析回调值

//XML格式转换

$xmlObj = simplexml_load_string($xmlData, 'SimpleXMLElement', LIBXML_NOCDATA);

$xmlObj = json_decode(json_encode($xmlObj),true);

// 当支付通知返回支付成功时

if ($xmlObj['return_code'] == "SUCCESS" && $xmlObj['result_code'] == "SUCCESS") {

//回调签名验证;

foreach( $xmlObj as $k=>$v) {

if($k == 'sign') {

$xmlSign = $xmlObj[$k];

unset($xmlObj[$k]);

};

}

$sign = http_build_query($xmlObj);

// file_put_contents('upload/1.txt' , $sign);

//md5处理

$sign = md5($sign.'&key='.'fb84170d5baeaf8a9a96c286821ad781');

//转大写

$sign = strtoupper($sign);

//验签名。默认支持MD5

//验证加密后的32位值和 微信返回的sign 是否一致!!!

if ( $sign === $xmlSign) {

// 订单号

$trade_no = $xmlObj['out_trade_no'];

//---------- 以下为处理具体业务 ----------

$edit['is_pay'] = 1;

$edit['pay_time'] = date('Y-m-d H:i:s');

$model = new OrderModel();

$order = $model->where(['order_no'=>$trade_no])->update($edit);

//---------- 处理具体业务结束 ----------

if($order){

return $this->json_success('支付成功,感谢您的捐赠');

}else{

return $this->json_error('支付失败');

}

}

}

}

附录:

附录一:(这里有多种微信相关方法,需要什么就可以调用什么)

namespace app\api\service;

use \Exception;

use think\facade\Cache;

class WechatPubService

{

//获取微信授权cod地址

const CODE_URL_BASE = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';

const CODE_URL_USER = 'https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect';

const TOKEN_URL = 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code';

const TOKEN = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';

const APPQRCODE = 'https://api.weixin.qq.com/wxa/getwxacodeunlimit?access_token=%s';

//获取token

const ACCESS_TOKEN = 'https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code';

//获取用户信息

const USER_INFO = 'https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN';

//获取jsapi_tocket

const JSAPI_TICKET = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=%s&type=jsapi';

//获取公众号的全局唯一接口调用凭据

const PUBLIC_ACCESS_TOKEN = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s';

//判断用户是否关注了公众号

const ATTEND_PUBLIC = 'https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid=%s&lang=zh_CN';

private static $instance;

//配置

private $_config = [

'AppID' => 'wx**********************99',

'AppSecret' => '21**********************7c',

];

//access_token和ticket的有效时间,最好小于7200秒

const TOKEN_EXPIRE = 7000;

/**

* WechatPubService 初始化方法.

* @param array $conf_option

* @throws Exception

*/

public function __construct($conf_option = [])

{

$this->_config = array_merge($this->_config, $conf_option);

if (!isset($this->_config['AppID']) || empty($this->_config['AppID'])) {

throw new Exception('微信AppID不能为空');

} else if (!isset($this->_config['AppSecret']) || empty($this->_config['AppSecret'])) {

throw new Exception('微信AppSecret不能为空');

}

}

/**

* @param array $conf_option

* @return WechatPubService

* @throws Exception

*/

public static function instance($conf_option = [])

{

if (is_null(self::$instance)) {

self::$instance = new self($conf_option);

}

return self::$instance;

}

/**

* 生成获取用户code的请求链接

* @param $uri string 用户同意授权以后的跳转链接(当前项目的链接,不要有任何登录检查和权限检查)

* @return string 获得授权地址,使用header进行跳转

*/

public function getCode($uri = '')

{

$uri = urlencode($uri);

$url = sprintf(self::CODE_URL_USER, $this->_config['AppID'], $uri);

return $url;

}

/**

* 根据用户的授权code获取用户的access_token

* @param string $code

* @return string 获得请求地址,使用curl或者file_get_contents获取结果

*/

public function getToken($code = '')

{

$url = sprintf(self::ACCESS_TOKEN, $this->_config['AppID'], $this->_config['AppSecret'], $code);

return $url;

}

/**

* 拉取用户信息 scope为 snsapi_userinfo才可以调用

* @param string $access_token

* @param string $openid

* @return false|string

*/

public function getUserInfo($access_token = '', $openid = '')

{

$url = sprintf(self::USER_INFO, $access_token, $openid);

$result = file_get_contents($url);

return $result;

}

/**

* 获取公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token

* @param string $app_id

* @param string $app_secret

* @return mixed

*/

public function getAccessToken($app_id = '', $app_secret = '')

{

$url = sprintf(self::PUBLIC_ACCESS_TOKEN, $app_id, $app_secret);

$result = file_get_contents($url);

return json_decode($result, true);

}

/**

* 获取公众号accessTOken

* @param string $app_id

* @param string $app_secret

* @return mixed

* @throws Exception

*/

public function getPublicAccessToken($app_id = '', $app_secret = '')

{

$cache_key = 'wechat_public_access_token_cache_' . $app_id;

// Cache::rm($cache_key);

if (Cache::has($cache_key)) {

return Cache::get($cache_key);

} else {

$result = $this->getAccessToken($app_id, $app_secret);

if (isset($result['errcode'])) {

throw new Exception($result['errmsg']);

} else {

Cache::set($cache_key, $result['access_token'], self::TOKEN_EXPIRE);

return $result['access_token'];

}

}

}

/**

* 获取JSAPI_TICKET接口

* @throws Exception

*/

public function getJsApiTicket()

{

$cache_key = 'wechat_public_js_api_ticket_prefix_' . $this->_config['AppID'];

// Cache::rm($cache_key);

if (Cache::has($cache_key) && 1 ==2) {

return Cache::get($cache_key);

} else {

//抓取错误,不然缓存会缓存错误的结果

try {

$access_token = $this->getPublicAccessToken($this->_config['AppID'], $this->_config['AppSecret']);

} catch (Exception $e) {

throw new Exception($e->getMessage());

}

$url = sprintf(self::JSAPI_TICKET, $access_token);

$result = file_get_contents($url);

$result = json_decode($result, true);

Cache::set($cache_key, $result, self::TOKEN_EXPIRE);

return $result;

}

}

//获取随机字符串

public static function getRandCode($num = 16)

{

$array = array('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',

't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',

'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'

);

$tmp_str = '';

$max = count($array);

for ($i = 1; $i <= $num; $i++) {

$tmp_str .= $array[rand(0, $max - 1)];

}

return $tmp_str;

}

/**

* 判断用户是否关注了公众号

* @param $access_token

* @param $open_id

*/

public function hasAttendPub($open_id)

{

$access_token = $this->getPublicAccessToken($this->_config['AppID'], $this->_config['AppSecret']);

$url = sprintf(self::ATTEND_PUBLIC, $access_token, $open_id);

$result = file_get_contents($url);

return json_decode($result, true);

}

}

附录二:

return [

'appid' => 'wx*****************99', // 公众号或小程序的appid

'secret' => '21*****************7c', // 公众号或小程序的secret

'wx_pay' => [

'use_sandbox' => false,// 是否使用 微信支付仿真测试系统 开启使用沙箱模式。金额固定

'app_id' => 'wx***************99', // 公众账号ID

'mch_id' => '14******02',// 商户id

'md5_key' => 'fb*******************81',// md5 秘钥(商户的秘钥)

// (前面第一步下载的证书文件放到指定位置,在这里设置路径)

'app_cert_pem' => env('CONFIG_PATH').'cert/' . 'apiclient_cert.pem',

'app_key_pem' => env('CONFIG_PATH').'cert/' . 'apiclient_key.pem',

'sign_type' => 'MD5',// MD5 HMAC-SHA256

'limit_pay' => [

//'no_credit',

],// 指定不能使用信用卡支付 不传入,则均可使用

'fee_type' => 'CNY',// 货币类型 当前仅支持该字段

'notify_url' => 'http://***.com/api/v1/Payment/notify', // 回调返回的方法,到此方法下接收支付回调

// 'redirect_url' => 'https://helei112g.github.io/',// 如果是h5支付,可以设置该值,返回到指定页面

'return_raw' => false,// 在处理回调时,是否直接返回原始数据,默认为true

],

];

结束,这是我目前总结的最简单的实现微信JSAPI支付的流程,其中还包含了获取用户信息。

如果仅仅是需要获取用户微信信息可以直接使用第二步,简单便捷。

不足之处,望不吝指出~

php微信jsapi支付小结,ThinkPHP接入微信支付 - JSAPI支付相关推荐

  1. php验证是否是微信支付,利用thinkphp判断微信中的支付还是微信扫码支付还是手...

    进行判断,根不同的客户端,显示不同的内容,如果不是手机,则只显示扫码微信支付,如果是微信公众号中,则只显示公众号支付 阿里西西web开发网为大家整理了这篇利用thinkphp判断微信中的支付还是微信扫 ...

  2. 微信无法连接支付服务器,App接入微信H5支付常见错误及原因

    在App上接入微信H5支付一般都会遇到一些错误.本文讨论了这些错误的解决方案和背后的原因,希望能让读者能少踩些坑. 错误可以分为两类:一是H5支付域名设置错误,二是URL Scheme跳转App错误. ...

  3. Java微信公众平台开发(一)--接入微信公众平台

    转载自崔用志博客:http://www.cuiyongzhi.com/ 前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我 ...

  4. Java微信公众平台开发(一)——接入微信公众平台

    前面几篇文章一直都在说微信公众平台的开发准备工作,那么从这篇开始我们就将正式的进入JAVA微信公众平台开发的整个流程,那么这篇我们开始聊聊如何将我们的服务端和微信公众平台对接! (一)接入流程解析 在 ...

  5. 微信公众号 - H5 网页接入微信支付(JSAPI)

    前言 假设您已经申请成为微信商户(认证)且各项配置弄好了,并且开通 JSAPI 支付等,只差代码(前端)编写. 如果你之前不了解,强烈建议 先看一遍如下标注的文档: [官方文档]网页客户端(H5),需 ...

  6. php微信支付使用ajax,接入微信公众号支付,选择支付方式后,只弹出“error’”(php)...

    这个怎么感觉不用ajax去请求什么啊?WeixinJSBridge不是已经封装好公众号支付的方法了吗?如果你已经在php里面完成统一下单过程了,那直接调用WeixinJSBridge的支付方法就行了: ...

  7. 企业微信接收服务器php代码,企业微信通知机器人 - 利用ThinkPHP+企业微信随时随地接受业务提醒、日报表等,个人亦可接入 – 基于ThinkPHP和Bootstrap的快速后台开发框架...

    此插件基于FastAdmin+企业微信机器人进行二次开发,用于管理员.开发者等接受实时.免费的通知服务,配置简单,个人亦可接入zrOiJ4E2dpaDH/3I+1YljA== 功能特性一行代码即可向您 ...

  8. Taro-RN使用 react-native-wechat-lib 集成微信支付-IOS(从微信注册应用到应用接入微信支付)全*

    组件库版本 "@tarojs/taro": "3.3.9", "@tarojs/taro-rn": "^3.3.9", ...

  9. 微信公众号一、接入微信并实现机器人自动回复功能

    一.说明 微信公众平台 https://mp.weixin.qq.com/cgi-bin/loginpage?t=wxm2-login&lang=zh_CN 测试平台 https://mp.w ...

最新文章

  1. 目前学什么专业的人在搞SLAM?各有什么优势?
  2. 服务器群装系统,手把手教你安装及配置服务器集群系统
  3. 程序员语言也有鄙视链!某美团程序员爆料:筛选简历时,用go语言的基本不看!网友:当韭菜还当出优越感了!...
  4. 深度学习核心技术精讲100篇(十四)-一文带你看懂GPflow的前世今生
  5. 数据中心机房工程建设需要注意的重大问题
  6. 邻值查找—算法进阶指南
  7. 为何setRequestMethod(GET)不生效
  8. SQLServer获取最后插入生成的ID 不同方法
  9. keras embedding层_初识TextCNN及keras实现
  10. 关于Navicat 连接mysql报11001错误
  11. 智能优化算法应用:基于麻雀搜索算法与非完全beta函数的自适应图像增强算法 - 附代码
  12. MySQL Workbench 如何连接 Amazon EC2 上的MySQL服务器?
  13. notes for 电子技术技术(模拟部分) 康华光
  14. access查询设计sol视图_access查询类型分哪几种?
  15. 电脑突然无法连接网络,如何处理(主要是针对QQ、微信可以登录,网页无法进入)
  16. 10.8 SNK中国一面面经
  17. asp.net914-自驾游网站的设计与实现
  18. 地球物理及空间物理相关数据下载
  19. 数字电路 时序逻辑电路
  20. java -jar .jar_Java_JAR命令JAR包闲谈;

热门文章

  1. Mysql学习总结(76)——MySQL执行计划(explain)结果含义总结
  2. Java设计模式学习总结(1)——设计模式简介
  3. Maven学习总结(42)——Maven多模块构建中常用的参数
  4. Maven学习总结(39)——Maven私服的搭建及使用deploy命令部署构建问题汇总
  5. linux手动安装unzip_怎样在Linux下搭建接口自动化测试平台?
  6. springboot忽略证书_SpringBoot中通过java代码实现忽略SSL证书
  7. java线程轮询_基于springboot实现轮询线程自动执行任务
  8. mysql_fetch_array 失败_mysql_fetch_array错误
  9. 自动备份 SourceSafe
  10. Java提高班(五)深入理解BIO、NIO、AIO