700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > php微信jsapi支付小结 ThinkPHP接入微信支付 - JSAPI支付

php微信jsapi支付小结 ThinkPHP接入微信支付 - JSAPI支付

时间:2018-12-05 21:28:03

相关推荐

php微信jsapi支付小结 ThinkPHP接入微信支付 - JSAPI支付

一、支付准备

二、获取用户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,项目地址:/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./connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_base&state=STATE#wechat_redirect';

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

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

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

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

//获取token

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

//获取用户信息

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

//获取jsapi_tocket

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

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

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

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

const ATTEND_PUBLIC = 'https://api./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支付的流程,其中还包含了获取用户信息。

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

不足之处,望不吝指出~

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。