废话不多说,直接上干货,
<?php
// +----------------------------------------------------------------------
// | ThinkCMF [ WE CAN DO IT MORE SIMPLE ]
// +----------------------------------------------------------------------
// | Copyright (c) 2013-2017 http://www.thinkcmf.com All rights reserved.
// +----------------------------------------------------------------------
// | Author: pl125 <xskjs888@163.com>
// +----------------------------------------------------------------------
namespace api\yikao\controller;
use api\portal\service\PortalPostService;
use api\user\model\UserFavoriteModel;
use api\user\model\UserLikeModel;
use cmf\controller\RestBaseController;
use api\portal\model\PortalPostModel;
use think\Db;
use think\db\Query;
use think\facade\Cache;
use think\facade\Request;
/*
*
*/
class WpayController extends RestBaseController
{
protected $wechat_config;
//https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_1
public function __construct($wechat_config = [])
{
if(empty($wechat_config)){
$wechat_config = [
'appid'=>'w**2',//APPID
'mch_id'=>'1**',//商户号
'api_key'=>'CCW***gZ7',//支付秘钥
'appsecret'=>'b9&&***',//APP秘钥
'notify_url'=>'',//回调网址
];
}
$this->wechat_config = $wechat_config;
}
//支付陪练系统
public function wpay(){
//生成微信支付预订单信息
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: token, Origin, X-Requested-With, Content-Type, Accept, Authorization");
header('Access-Control-Allow-Methods: POST,GET,PUT,DELETE');
$data2 = Request::param();//过滤参数
// dump($data2);die;
$body = '商品';
$total_fee = '1';
$out_trade_no = 'PL'.date('YmdHis').rand(1000,9999);
$attach = 'charge_order';
$wechat_data = $this->wx_pay($body,$total_fee,$out_trade_no,$attach);
$data = [
'title'=>$body,
'money'=>$total_fee,
'order_no'=>$out_trade_no,
'attach'=>$attach,
'status'=>0,//未支付
];
// dump($data);die;
//写入数据库表信息
Db::table('f_*')->insert($data);
$this->relog('wxapp---'.json_encode($wechat_data));//日志
if($wechat_data['code'] != 200){
echo $wechat_data['msg'];die;
}
$result = [ 'order_no'=>$out_trade_no , 'money'=>$total_fee, 'wechat_data'=>$wechat_data];
return json_encode($result);
// print_r($result);die;
}
//生成预支付订单
public function wx_pay($body,$total_fee,$out_trade_no,$attach) {
$nonce_str = $this->rand_code(); //调用随机字符串生成方法获取随机字符串
$data['appid'] = $this->wechat_config['appid']; //appid
$data['mch_id'] = $this->wechat_config['mch_id'] ; //商户号
$data['body'] = $body;
$data['spbill_create_ip'] = $this->get_client_ip(); //ip地址
$data['total_fee'] = $total_fee; //金额
$data['out_trade_no'] = $out_trade_no; //商户订单号,不能重复
$data['nonce_str'] = $nonce_str; //随机字符串
$data['notify_url'] = $this->wechat_config['notify_url']; //回调地址,用户接收支付后的通知,必须为能直接访问的网址,不能跟参数
$data['trade_type'] = 'APP'; //支付方式
$data['attach'] = $attach; //商户携带订单的自定义数据
//将参与签名的数据保存到数组 注意:以上几个参数是追加到$data中的,$data中应该同时包含开发文档中要求必填的剔除sign以外的所有数据
$data['sign'] = self::getSign($data,$this->wechat_config['api_key']); //获取签名
$xml = self::ToXml($data); //数组转xml
//curl 传递给微信方
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
//header("Content-type:text/xml");
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL, $url);
if(stripos($url,"https://")!==FALSE){
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
} else {
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
}
//设置header
curl_setopt($ch, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
//要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, TRUE);
//传输文件
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml);
//运行curl
$data = curl_exec($ch);
//返回结果
if($data){
curl_close($ch);
//返回成功,将xml数据转换为数组.
$re = self::FromXml($data);
if($re['return_code'] != 'SUCCESS'){
return [
'code'=>'201',
'msg'=>$re['return_msg']
];
}
else{
//接收微信返回的数据,传给APP!
$arr =array(
'prepayid' =>$re['prepay_id'],
'appid' => $this->wechat_config['appid'],
'partnerid' => $this->wechat_config['mch_id'],
'package' => 'Sign=WXPay',
'noncestr' => $nonce_str,
'timestamp' =>strval(time()),
);
//第二次生成签名
$sign = self::getSign($arr,$this->wechat_config['api_key']);
$arr['sign'] = $sign;
$arr['code'] = '200';
$arr['msg'] = '签名成功';
return $arr;
}
} else {
$error = curl_errno($ch);
curl_close($ch);
return [
'code'=>'201',
'msg'=>"curl出错,错误码:$error"
];
}
}
//参数要组装成xml格式
public static function ToXml($data = array()){
if (!is_array($data) || count($data) <= 0) {
return '数组异常';
}
$xml = "<xml>";
foreach ($data as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
public static function FromXml($xml)
{
if(!$xml){
echo "xml数据异常!";
}
//将XML转为array
//禁止引用外部xml实体
libxml_disable_entity_loader(true);
$data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
return $data;
}
//生成随机字符串
private function rand_code(){
$str = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';//62个字符
$str = str_shuffle($str);
$str = substr($str,0,32);
return $str;
}
/*
获取当前服务器的IP
*/
private function get_client_ip(){
if ($_SERVER['REMOTE_ADDR']) {
$cip = $_SERVER['REMOTE_ADDR'];
} elseif (getenv("REMOTE_ADDR")) {
$cip = getenv("REMOTE_ADDR");
} elseif (getenv("HTTP_CLIENT_IP")) {
$cip = getenv("HTTP_CLIENT_IP");
} else {
$cip = "unknown";
}
return $cip;
}
//生成签名
public static function getSign($params,$api_key) {
ksort($params); //将参数数组按照参数名ASCII码从小到大排序
foreach ($params as $key => $item) {
if (!empty($item)) { //剔除参数值为空的参数
$newArr[] = $key.'='.$item; // 整合新的参数数组
}
}
$stringA = implode("&", $newArr); //使用 & 符号连接参数
$stringSignTemp = $stringA."&key=".$api_key; //拼接key
// key是在商户平台API安全里自己设置的
$stringSignTemp = MD5($stringSignTemp); //将字符串进行MD5加密
$sign = strtoupper($stringSignTemp); //将所有字符转换为大写
return $sign;
}
// 微信支付回调
public function wx_notifyAction(){
//接收微信返回的数据数据,返回的xml格式
$xmlData = file_get_contents('php://input');
//dump(json_encode($xmlData));die;
//将xml格式转换为数组
$data = $this->FromXml($xmlData);
//用日志记录检查数据是否接受成功,验证成功一次之后,可删除。
$this->relog('wx---'.$xmlData);
//为了防止假数据,验证签名是否和返回的一样。
//记录一下,返回回来的签名,生成签名的时候,必须剔除sign字段。
$sign = $data['sign'];
unset($data['sign']);
if($sign == $this->getSign($data,$this->wechat_config['api_key'])){
//签名验证成功后,判断返回微信返回的
$this->relog('wx---55'.$data['out_trade_no']);
Db::name("app_user")->insert($shuju);
echo '<xml>
<return_code><![CDATA[SUCCESS]]></return_code>
<return_msg><![CDATA[OK]]></return_msg>
</xml>';
exit();
// if($data['result_code'] == 'SUCCESS'){
// $this->relog('wxapp---44'.$data['result_code']);
// //根据返回的订单号做业务逻辑
// $res = false;
// if($data['attach'] == 'charge_order'){
// }
// //处理完成之后,告诉微信成功结果!
// if($res == true){
// echo '<xml>
// <return_code><![CDATA[SUCCESS]]></return_code>
// <return_msg><![CDATA[OK]]></return_msg>
// </xml>';
// exit();
// }else{
// $file = fopen($file_name, 'a+');
// fwrite($file,date("Y-m-d H:i:s")."错误信息:数据修改失败,".json_encode($data).PHP_EOL);
// }
// }
}
else{
$file = fopen($file_name, 'a+');
fwrite($file,date("Y-m-d H:i:s")."错误信息:签名验证失败,".json_encode($data).PHP_EOL);
}
}
public function relog($word = '')
{
$word = is_array($word) ? var_export($word, 1) : $word;
$fp = fopen( cmf_get_root().'temp/wx.txt', 'a+');
flock($fp, LOCK_EX);
fwrite($fp, '执行日期:' . strftime('%Y%m%d%H%M%S', time()) . "\n" . $word . "\n");
flock($fp, LOCK_UN);
fclose($fp);
}
}
是不是很简单呀!