<?php namespace Api\Controller; use Think\Controller; //别的框架改改也可以用 //WeChatPayController.class.php 文件名 /** * * 微信APP 支付 + 回调 适用于TP3.2 * */ class WeChatPayController extends Controller { private $appid = '**';//appID private $mch_id = '**';//商户ID private $key = '***S';//key private $notify ='****';//回调地址 private $url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';//统一下请求地址 /** * 微信统一下单接口 * 请求类型 :POST * 所需参数 order 订单号 body 商品描述 total 金额 * @return json * * */ public function index() { //订单号 $order = I('post.order', time() . mt_rand('1000', '9999')); //内容 $body = I('post.body', '测试'); //金额默认为0.01 $total = ltrim(I('post.total', '0.01'),'-') * 100; $array = ['appid' => $this -> appid, 'mch_id' => $this -> mch_id, 'nonce_str' => $this -> randomCreateStr(), 'body' => $body, 'out_trade_no' => $order, 'total_fee' => $total, 'spbill_create_ip' => $this->getIp(), 'notify_url' => $this->notify, 'trade_type' => 'APP']; //生成签名 $sign = $this -> createSign($array); $array['sign'] = $sign; //生成xml $xml = $this -> createXml($array); //发送给微信服务器 $WeChatXml = $this -> postUrl($this -> url, $xml); //转为数组 $WeChatArray = $this -> XMLDataParse($WeChatXml); //进行判定 if ($WeChatArray['return_code'] != 'SUCCESS' || $WeChatArray['result_code'] != 'SUCCESS') { exit(json_encode(['error' => 1, 'message' => $WeChatArray], JSON_UNESCAPED_UNICODE)); } //对微信返回的签名进行验证是否正确 if (!$this -> verifySign($WeChatArray)) { exit(json_encode(['error' => 1, 'message' => '微信返回签名失败'], JSON_UNESCAPED_UNICODE)); } //组合要给APP 发送的数据 $AppArray = [ 'appid' => $this -> appid, 'partnerid' => $this -> mch_id, 'prepayid' =>$WeChatArray['prepay_id'], 'package' =>'Sign=WXPay', 'noncestr'=>$this->randomCreateStr(), 'timestamp'=>time() ]; //进行签名 $sign = $this -> createSign($AppArray); $AppArray['sign'] = $sign; //转换成JSON 返回给APP exit(json_encode($AppArray)); } /** *微信回调地址接口 * * * */ public function notify() { //接收微信xml格式信息 $xmlData = file_get_contents('php://input'); //转换为数组 $array = json_decode($xmlData,TRUE); $array = $this-> XMLDataParse($xmlData); //对微信返回的签名进行验证是否正确 if (!$this -> verifySign($array)) { exit('<xml><return_code><![CDATA[FAIL]]></return_code><return_msg><![CDATA[签名不正确]]></return_msg></xml>'); } /** * !!!注意: 下面的就是连接数据库了,做进一步处理 * * * */ //下面是处理完逻辑,返回给微信服务器的 //exit('<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>'); } private function postUrl($url, $paramsArray) { $curl = curl_init(); // 启动一个CURL会话 curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址 curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查 //curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查 //curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 1); // 从证书中检查SSL加密算法是否存在 //curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器 //curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转 curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求 curl_setopt($curl, CURLOPT_POSTFIELDS, $paramsArray); // Post提交的数据包 curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环 curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容 curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回 $tmpInfo = curl_exec($curl); // 执行操作 if (curl_errno($curl)) { echo 'Errno' . curl_error($curl); //捕抓异常 } curl_close($curl); // 关闭CURL会话 return $tmpInfo; // 返回数据,json格式 } /** * 获取IP 地址 * * */ private function getIp() { if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) $ip = getenv("HTTP_CLIENT_IP"); else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) $ip = getenv("HTTP_X_FORWARDED_FOR"); else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) $ip = getenv("REMOTE_ADDR"); else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) $ip = $_SERVER['REMOTE_ADDR']; else $ip = "unknown"; return ($ip); } /** * 验证签名 * * */ private function verifySign($array) { $sign = $array['sign']; unset($array['sign']); $s = $this -> createSign($array); return $s == $sign ? TRUE : FALSE; } /** * 生成签名 * @param $array array 参数 以关联数组 的形势 * * @return str 签名 */ private function createSign($array) { ksort($array); $stringA = ''; foreach ($array as $ke => $value) { $stringA .= $ke . '=' . $value . '&'; } //$stringA = http_build_query($array); $stringSignTemp = $stringA . "key=" . $this -> key; $sign = strtoupper(md5($stringSignTemp)); return $sign; } /** * 生成XML 格式文件 * @param $array array 参数 以关联数组 的形势 * * @return str xml字符串 */ private function createXml($array) { $xml = '<xml>'; foreach ($array as $key => $value) { $xml .= '<' . $key . '>' . $value . '</' . $key . '>'; } $xml .= '</xml>'; return $xml; } /** * 随机生成32位字符串 * @return str 32位字符串 */ private function randomCreateStr() { return strtoupper(md5(microtime(TRUE) . mt_rand(0, 9999))); } /** * xml格式数据解析函数 * @param $xml str 微信返回的xml格式字符串 * * @return array 数组 */ private function XMLDataParse($xml) { $array_data = json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true); return $array_data; }