<?php
public function order_pay(){
$Pay=new Pay();
$pay_data['body']='掌上索比支付';
$pay_data['system_order_num']=$system_order_num;
$pay_data['total_price']=$insert_data['total_price'];
$pay_data['notify_url']='https://test.api.com/wechat/callback';// 这个根据自己的回调地址修改
$pay_data['openid']=$data['openid'];
return $Pay->wxPays_return_arr($pay_data);
}
控制器内容:
<?php
public function callback(){
$message=file_get_contents("php://input");
if(!empty($message)){
$Domain_Orders = new BookPay();
$res=$Domain_Orders->callback($message);
return $res;
}else{
return '参数错误';
}
}
?callback方法:
<?php
use think\facade\Db;
class BookPay extends Common
{
// 回调
public function callback($message){
$message=json_encode(simplexml_load_string($message, 'SimpleXMLElement', LIBXML_NOCDATA));
$message = json_decode($message, true);
// 通信失败,通知微信稍后重新通知
if ($message['return_code'] != 'SUCCESS') {
return false;
}
// 支付失败,不处理
if ($message['result_code'] != 'SUCCESS') {
return false;
}
$orders=Db::connect('system')->name('goods_order')->field('id,system_order_num,goods_id,goods_num,total_price,order_status,user_id')->where(['system_order_num'=>$message['out_trade_no']])->order('id desc')->limit(1)->find();
if(!empty($orders) && $orders['order_status'] != 2){
// 修改订单状态
$update_orders=Db::connect('system')->name('goods_order')->where(['system_order_num'=>$message['out_trade_no']])->update(['order_status'=>2,'wechat_order_num'=>$message['transaction_id'],'pay_time'=>time()]);
// 减商品库存
$book_stock=Book::where(['id'=>$orders['goods_id']])->field('stock')->find()->toArray();
$dec_stock=Db::connect('system')->name('book_goods')->where(['id'=>$orders['goods_id']])->update(['stock'=>($book_stock['stock']-$orders['goods_num'])]);
if($update_orders && $dec_stock){
return '<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>';
}
}else{
return 'error';
}
}
}
<?php
// $data 中的数据 goods_number是自己系统生成的,支付传的订单号
// refund_price是退款总额, pay_price是支付总额
public function orderRefund($data){
// 查询订单时间
$wxClass = $this->wxConfig();
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$time = time();
$out_refund_no = 'wxtk' . $time;//退款单
$parameters = array(
'appid' => "{$wxClass['appid']}", //应用ID,固定
'mch_id' => "{$wxClass['mch_id']}", //商户号,固定
'nonce_str' => $this->createNoncestr(), //随机字符串
'out_refund_no' => $out_refund_no, //商户内部唯一退款单号
'out_trade_no' => $data['goods_number'], //商户订单号,pay_sn码 1.1二选一,微信生成的订单号,在支付通知中有返回
// 'transaction_id'=>'1',//微信订单号 1.2二选一,商户侧传给微信的订单号
'refund_fee' => floatval($data['refund_price'] * 100), //退款金额
'total_fee' => floatval($data['pay_price'] * 100), //总金额
);
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$path_cert = $wxClass['cert_path'];
$path_key = $wxClass['key_path'];
$useCert = true;
$return = $this->xmlToArray($this->postXmlCurls($xmlData, $url, $useCert, 60, $path_cert, $path_key));
return $return;
}
<?php
namespace app\orderbuy\domain;
use app\telecast\controller\Common;
class Pay extends Common
{
// 微信支付返回数组
public function wxPays_return_arr($request)
{
$data = $request;//这里是前端传的值
//订单编号
try{
$reponse_data = $this->wechat_pay($data);
return (['code'=>0,'data'=>$reponse_data,'msg'=>'下单成功']);
} catch (\Exception $exception)
{
return (['code'=>2,'msg' => $exception->getMessage()]);
}
}
//统一下单接口
public function unifiedorder($data) {
$config=$this->wxConfig();
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$parameters = array(
'appid' => $config['appid'], //小程序ID
'mch_id' => $config['mch_id'], //商户号
'nonce_str' => $this->createNoncestr(), //随机字符串
'body' => $data['body'], //商品描述
'out_trade_no' => $data['system_order_num'], //商户订单号
'total_fee' => floatval($data['total_price'] * 100), //总金额 单位 分
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'], //终端IP
'notify_url' => $data['notify_url'], //通知地址 确保外网能正常访问
'openid' => $data['openid'], //用户openid
'trade_type' => 'JSAPI'//交易类型
);
//统一下单签名
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$return = $this->xmlToArray($this->postXmlCurl($xmlData, $url, 60));
if($return['return_code'] == 'FAIL'){
return json(['code'=>-1,'msg'=>$return['return_msg']]);
}
return $return;
}
/**
* 配置信息
* */
public function wxConfig(){
$data['appid'] = \think\facade\Config::get('wechat.wechatConfig.app_id');//商户appid
$data['mch_id'] = \think\facade\Config::get('wechat.wechatConfig.mch_id');//商户(商户号)
$data['key'] = \think\facade\Config::get('wechat.wechatConfig.key');//商户密匙
$data['cert_path'] = \think\facade\Config::get('wechat.wechatConfig.cert_path');//证书路径.cert
$data['key_path'] = \think\facade\Config::get('wechat.wechatConfig.key_path');//证书路径.key
$data['spbill_create_ip'] = \think\facade\Config::get('wechat.wechatConfig.spbill_create_ip');//允许请求的ip,访问没有用这个
return $data;
}
//签名(调起数据签名)
private function wechat_pay($data) {
$config=$this->wxConfig();
//统一下单接口
$unifiedorder = $this->unifiedorder($data);
$parameters = array(
'appId' => $config['appid'], //小程序ID
'timeStamp' => '' . time() . '', //时间戳
'nonceStr' => $this->createNoncestr(), //随机串
'package' => 'prepay_id=' . $unifiedorder['prepay_id'], //数据包
'signType' => 'MD5'//签名方式
);
//签名
$parameters['paySign'] = $this->getSign($parameters);
return $parameters;
}
//产生随机字符串,不长于32位
private function createNoncestr($length = 32) {
$chars = "ABCDEFGHIJKIMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
}
return $str;
}
//生成签名
private function getSign($Obj) {
$config=$this->wxConfig();
foreach ($Obj as $k => $v) {
$Parameters[$k] = $v;
}
//签名步骤一:按字典序排序参数
ksort($Parameters);
$String = $this->formatBizQueryParaMap($Parameters, false);
//签名步骤二:在string后加入KEY
// $String = $String . "&key=" . $this->key;
$String = $String . "&key=".$config['key'];;
//签名步骤三:MD5加密
$String = md5($String);
//签名步骤四:所有字符转为大写
$result_ = strtoupper($String);
return $result_;
}
//格式化参数,签名过程需要使用
private function formatBizQueryParaMap($paraMap, $urlencode) {
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if ($urlencode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
//数组转换成xml
private function arrayToXml($arr) {
$xml = "<root>";
foreach ($arr as $key => $val) {
if (is_array($val)) {
$xml .= "<" . $key . ">" . arrayToXml($val) . "</" . $key . ">";
} else {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
}
}
$xml .= "</root>";
return $xml;
}
//xml转换成数组
private function xmlToArray($xml) {
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring), true);
return $val;
}
// 微信支付使用
private static function postXmlCurl($xml, $url, $second = 30)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE); //严格校验
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
curl_setopt($ch, CURLOPT_TIMEOUT, 40);
set_time_limit(0);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
throw new WxPayException("curl出错,错误码:$error");
}
}
/**
* 申请退款
*/
public function orderRefund($data){
// 查询订单时间
$wxClass = $this->wxConfig();
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$time = time();
$out_refund_no = 'wxtk' . $time;//退款单
$parameters = array(
'appid' => "{$wxClass['appid']}", //应用ID,固定
'mch_id' => "{$wxClass['mch_id']}", //商户号,固定
'nonce_str' => $this->createNoncestr(), //随机字符串
'out_refund_no' => $out_refund_no, //商户内部唯一退款单号
'out_trade_no' => $data['goods_number'], //商户订单号,pay_sn码 1.1二选一,微信生成的订单号,在支付通知中有返回
// 'transaction_id'=>'1',//微信订单号 1.2二选一,商户侧传给微信的订单号
'refund_fee' => floatval($data['refund_price'] * 100), //退款金额
'total_fee' => floatval($data['pay_price'] * 100), //总金额
);
$parameters['sign'] = $this->getSign($parameters);
$xmlData = $this->arrayToXml($parameters);
$path_cert = $wxClass['cert_path'];
$path_key = $wxClass['key_path'];
$useCert = true;
$return = $this->xmlToArray($this->postXmlCurls($xmlData, $url, $useCert, 60, $path_cert, $path_key));
return $return;
}
// 退款使用
private function postXmlCurls($xml, $url, $useCert, $second = 30,$path_cert,$path_key)
{
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);//严格校验
//设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
if ($useCert == true) {
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLCERT, $path_cert);
curl_setopt($ch, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($ch, CURLOPT_SSLKEY, $path_key);
}
//post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if ($data) {
curl_close($ch);
return $data;
} else {
$error = curl_errno($ch);
curl_close($ch);
return ['code' => 201, 'error' => $error];
//message("退款失败,CURL出错,错误码:".$error);exit;
}
}
}
上面是总的方法
时间紧张,只是用了其中的简单方法实现,大家可以借鉴使用