微信支付
app\common\service\WxPay.php
<?php
/**
* Created by PhpStorm.
* Date: 2020/6/17
* Time: 0:01
*/
namespace app\common\service;
use app\common\model\LogModel;
class Wxpay extends WxpayCommon {
protected $log;
/**
* desc:测试app支付
*/
public function test(){
$params['appid'] = 'wx85ad1ecf7ebce37a';
$params['attach'] = 'test';
$params['body'] = 'test2';
$params['mch_id'] = '1587922861';
$params['notify_url'] = '2323';
$params['out_trade_no'] = time();
$params['total_fee'] = 100;
$response = $this->appPay($params);
echo json_encode($response);
}
/**
* desc:APP支付
*/
public function appPay($config)
{
$this->log=[];
$this->log['title']='微信APP支付';
$this->log['content']['config']= $config;
$params = [];
$params['appid'] = $config['appid'];
$params['attach'] = $config['attach'];
$params['body'] = $config['body'];
$params['mch_id'] = $config['mch_id'];
$params['nonce_str'] = $this->getNonceStr();
$params['notify_url'] = $config['notify_url'];
$params['out_trade_no'] = $config['out_trade_no'];
$params['spbill_create_ip'] = $_SERVER['SERVER_ADDR'];
$params['total_fee'] = $config['total_fee'];
$params['trade_type'] = "APP";
$this->log['flag'] = $config['out_trade_no'];
$this->log['content']['params']= $params;
//获取签名
$sign = $this->makeSign($params);
$this->log['content']['sign']= $sign;
$params['sign'] = $sign;
$xml = $this->ToXml($params);
$api = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$curlData = $this->curlXml($api, $xml);
$this->log['content']['curlDataXML']= $curlData;
$curlData = simplexml_load_string($curlData, 'SimpleXMLElement', LIBXML_NOCDATA);
$curlData = json_decode(json_encode($curlData), true);
$this->log['content']['curlData']= $curlData;
//返回
$response=[];
$response['appid'] = !empty($curlData['appid'])?$curlData['appid']:'';
$response['partnerid'] = !empty($curlData['mch_id'])?$curlData['mch_id']:'';
$response['prepayid'] = !empty($curlData['prepay_id'])?$curlData['prepay_id']:'';
$response['package'] = 'Sign=WXPay';
$response['noncestr'] = $this->getNonceStr();
$response['timestamp'] = time();
$sign2 = $this->makeSign($response);
$response['sign'] = $sign2;
$this->log['content']['response']= $response;
LogModel::add($this->log);
return $response;
}
}
app\common\service\WxpayCommon.php
<?php
/**
* Created by PhpStorm.
* Date: 2020/6/17
* Time: 0:01
*/
namespace app\common\service;
use think\Config;
use think\Controller;
class WxpayCommon extends Controller {
protected $log;
/**
* desc:测试签名,与https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=20_1进行对比
*/
public function testSign(){
$response=[];
$response['appid'] = 'wx85ad1ecf7ebce37a';
$response['partnerid'] = '1587922861';
$response['prepayid'] = 'wx2318424232767470837925821975240400';
$response['package'] ='Sign=WXPay';
$response['noncestr'] = 't0ym9r9qjoji6b8r9yloksymxxzcge5q';
$response['timestamp'] = 1592908962;
$sign = $this->makeSign($response);
echo $sign;
}
/**
* desc:推送xml
*/
public function curlXml($api,$xml){
$header[] = "Content-type: text/xml"; //定义content-type为xml,注意是数组
$ch = curl_init ($api);
curl_setopt($ch, CURLOPT_URL, $api);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
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)){
print curl_error($ch);
exit();
}
curl_close($ch);
return $response;
}
/**
* auth:chenliang
* desc:获取签名
*/
public function makeSign($params){
//第一步
ksort($params);
$str = $this->ToUrlParams($params);
//第二部
$str.="&key=".Config::get("wxapp.key");
//第三步
$sign= strtoupper(MD5($str));
return $sign;
}
/**
* desc:字符串拼接
*/
public function ToUrlParams($params)
{
$buff = "";
foreach ($params as $k => $v)
{
if($k != "sign" && $v != "" && !is_array($v)){
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
/**
* desc:数组转成xml
*/
public function ToXml($values)
{
if(!is_array($values) || count($values) <= 0)
{
throw new WxPayException("数组数据异常!");
}
$xml = "<xml>";
foreach ($values as $key=>$val)
{
if (is_numeric($val)){
$xml.="<".$key.">".$val."</".$key.">";
}else{
$xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
}
}
$xml.="</xml>";
return $xml;
}
/**
* desc:生成随机字符串
*/
public function getNonceStr($length = 32)
{
$chars = "abcdefghijklmnopqrstuvwxyz0123456789";
$str ="";
for ( $i = 0; $i < $length; $i++ ) {
$str .= substr($chars, mt_rand(0, strlen($chars)-1), 1);
}
return $str;
}
}
控制器方法
protected function makeToken($uid, $money)
{
$k = $uid . md5($money) . $uid;
$k = md5(sha1($k));
return $k;
}
function num_random($length = 6) {
$pool = '0123456789';
return substr(str_shuffle(str_repeat($pool, 5)), 0, $length);
}
$token = $this->makeToken($model->id, $money);
$data = ['id' => $model->id, 'money' => $money, 'app_token' => $token, 'notify_type' => 'device_notify'];
$data['type'] = 'appwx';
$wxset = config('wxapp');
$sign = base64_encode(json_encode($data));
$order = ['out_trade_no' => $user_info['id'] . time() . num_random(4),
'body' => '商品支付',
'total_fee' => $money * 100,
'notify_url' => $app_host . 'scan_doctor_app/notify_service/device_notify/' . $sign,
'appid' => $wxset['appid'],
'mch_id' => $wxset['mch_id'],
'attach' => '商品支付'
];
$Wxpay = new Wxpay();
$pay = $Wxpay->appPay($order);
支付回调(微信及支付宝支付通用型回调,处理后续业务逻辑)
支付回调接口的请求格式必须是restful风格的:Route::any(‘/scan_doctor_app/notify_service/device_notify/:sign’, ‘scan_doctor_app/v1.notify_service/device_notify’);
// 成功回调
public function device_notify($sign)
{
try {
//$sign = input('sign');
$log = [];
$log['title'] = '支付回调';
$log['content']['request'] = $_REQUEST;
$log['content']['msg'] = '';
$log['content']['sign'] = empty($sign) ? '未传参' : $sign;
$signData = json_decode(base64_decode($sign), true);
$token = $this->makeToken($signData['id'], $signData['money']);
$log['content']['signData'] = $signData;
if ($token != $signData['app_token']) {
throw new Exception('token错误');
}
// 获取商品信息
/*$orderModel = DeviceBuy::get(function ($query) use($signData) {
$query->where('id', $signData['id']);
});*/
$orderModel = DeviceBuy::where('id', $signData['id'])->find();
if (!in_array($orderModel->getData('status'), [0, 1])) {
throw new Exception('错误_非待支付');
}
$payment_account = '';
//获取医生信息
// $diagDoctorWechatModel = ScanDoctorWechat::where('scan_doctor_id', $orderModel['scan_doctor_id'])->find();
$diagDoctorModel = ScanDoctor::where('id', $orderModel['scan_doctor_id'])->find();
if ($diagDoctorModel) {
$payment_account = $diagDoctorModel['name'];
}
$payment_flow = '';
$out_trade_no = '';
$content = '';
if ($signData['type'] == 'alipay') {
$payment_flow = input('trade_no');
$out_trade_no = input('out_trade_no');
$content = json_encode($_REQUEST);
$orderModel->pay_type = 2;
$orderModel->payment_flow = input('trade_no');
// $alipayRes = $orderModel->save();
// $log['content']['alipayRes'] = $alipayRes;
}else{
//微信支付,
$input_value = !empty( file_get_contents('php://input') ) ? file_get_contents('php://input') : '';
$curlData = simplexml_load_string($input_value, 'SimpleXMLElement', LIBXML_NOCDATA);
$curlData = json_decode(json_encode($curlData), true);
$log['content']['input'] = $curlData;
// $curlData['wxBackData']['transaction_id'];
if( !empty($curlData) ){
$payment_flow = $curlData['transaction_id'];
$out_trade_no = $curlData['out_trade_no'];
$content = json_encode($curlData);
$orderModel->payment_flow = $payment_flow;
}
}
//支付信息记录表 关联DeviceBuy
if( !empty($payment_flow) ){
$payment_lsit = PaymentList::where('data_id', $signData['id'])->where('out_trade_no', $out_trade_no)->find();
if( !$payment_lsit ){
$payment_lsit = new PaymentList;
//数据库不存在的情况新增数据
$payment_lsit->out_trade_no = $out_trade_no;
$payment_lsit->payment_flow = $payment_flow;
$payment_lsit->data_id = $signData['id'];
$payment_lsit->content = $content;
$payment_lsit->type = 1;
$payment_lsit->save();
}
}
$orderModel->payment_account = $payment_account;
/*$orderData = DeviceBuy::where('id', $orderModel['id'])->find();
if ($orderData) {
$orderData->payment_account = $payment_account;
$orderData->save();
}*/
if ($orderModel->scale == 0) {
// 不分期
$orderModel->money = $signData['money'];
$orderModel->pay = $signData['money'];
$orderModel->status = 2;
} else {
if ($orderModel->getData('status') == 0) {
// 付第一期
$orderModel->money = $signData['money'];
$orderModel->pay = $signData['money'];
$orderModel->status = 1;
} else {
// 付第二期
if ( empty( $signData['erqi'] ) || $signData['erqi'] != true) {
throw new Exception('非二期请求');
}
$orderModel->money += $signData['money'];
$orderModel->pay += $signData['money'];
$orderModel->status = 2;
}
}
$log['content']['DeviceBuyStatus'] = $orderModel->status;
$deviceBuyRes = $orderModel->save();
$log['content']['deviceBuyRes'] = $deviceBuyRes;
$streamModel = new DeviceStream();
$streamModel->scan_doctor_id = $orderModel->scan_doctor_id;
$streamModel->device_buy_id = $orderModel->id;
$streamModel->type = 0;
$streamModel->money = $signData['money'];
$streamModel->content = '购买设备';
$deviceStreamRes = $streamModel->save();
$log['content']['money'] = $signData['money'];
$log['content']['deviceStreamRes'] = $deviceStreamRes;
//$checkStatusRes = Check::where('order_id',$orderModel->id)->update(['status' => 1]);
//$log['content']['check_status_res'] = $checkStatusRes;
$log['content']['msg'] = 'success';
LogModel::add($log);
$response = \wxpay\Wxpay::success();
return $response;
} catch (Exception $e) {
$log['content']['msg'] = $e->getMessage();
LogModel::add($log);
return errorResponse($e->getMessage());
}
}
// 生成充值token
protected function makeToken($uid, $money)
{
$k = $uid . md5($money) . $uid;
$k = md5(sha1($k));
return $k;
}