1.支付,退款,回调 函数
<?php
// 微信公众号AppId
define("APPID", "");
// 微信公众号AppSecret
define("APPSECRET", "");
// <微信支付> 公众号支付商户ID(partnerId)
define("PARTNER", "");
// <微信支付> 商户通加密串(partnerKey)
define("PARTNERKEY", "");
include('./weixinUtils/Util.php');
class wxAppUtils{
/**
* 微信退货处理
* 退货前提是必须支付成功
* @param type $orderId
* @return bool
*/
public function wxRefund($transaction_id,$out_trade_no, $totalFee,$refund_fee) {
$utils=new Util();
$curl=new Curl();
//微信退款
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$out_refund_no = date("Ymdhis") . mt_rand(10, 99);
$postData = array(
"appid" => APPID,
"mch_id" => PARTNER,
"transaction_id" => $transaction_id,
"out_trade_no" => $out_trade_no,
"out_refund_no" =>$out_refund_no,
"total_fee" => $totalFee,
"refund_fee" => $refund_fee,
"op_user_id" => PARTNER,
"nonce_str" => $utils->createNoncestr(),
);
$postData["sign"] = $utils->paySign($postData);
$reqPar =$utils->toXML($postData);
$r = $curl->postXmlCurl($url, $reqPar, 50);
return $r;
}
/**
* 统一下单
* @param unknown $openid
* @return boolean|string[]|unknown[]
*/
public function weinXinPay($openid) {
$utils=new Util();
$curl=new Curl();
$notify_url="http://www.weixin.qq.com/wxpay/pay.php";
$serial_number = date("Ymdhis") . mt_rand(10, 99);
// 随机字符串
$nonceStr = $utils->createNoncestr();
// 时间戳
$timeStamp = strval(time());
// 订单总额 = (金额 - 余额支付金额)
$totalFee = 1;
$pack = array(
'appid' => APPID,
'body' => "测试",
'mch_id' => PARTNER,
'nonce_str' => $nonceStr,
'notify_url' => $notify_url,
'spbill_create_ip' => $utils->getIps(),
'openid' => $openid,
'out_trade_no' => $serial_number,
'total_fee' => $totalFee,
'trade_type' => 'JSAPI'
);
$pack['sign'] = $utils->paySign($pack);
$xml = $utils->toXML($pack);
$ret = $curl->post('https://api.mch.weixin.qq.com/pay/unifiedorder', $xml);
$postObj = json_decode(json_encode(simplexml_load_string($ret, 'SimpleXMLElement', LIBXML_NOCDATA)));
if (empty($postObj->prepay_id) || $postObj->return_code == "FAIL") {
echo '生成签名失败:' . $postObj->return_msg . ' ' . $xml.$ret;
return false;
} else {
$packJs = array(
'appId' => APPID,
'timeStamp' => $timeStamp,
'nonceStr' => $nonceStr,
'package' => "prepay_id=" . $postObj->prepay_id,
'signType' => 'MD5'
);
$JsSign = $utils->paySign($packJs);
unset($packJs['timeStamp']);
$packJs['timestamp'] = $timeStamp;
$packJs['paySign'] = $JsSign;
return $packJs;
}
}
2.支付类
// 微信app支付回调页面
public function app_payment_notify(){
$utils=new Util();
$curl=new Curl();
//解决$GLOBAL限制导致无法获取xml数据
$this->sourceStr = file_get_contents('php://input');
// 读取数据
$postObj = simplexml_load_string($this->sourceStr, 'SimpleXMLElement', LIBXML_NOCDATA);
// 数据参考 systemtest/payment_notify.xml
if (!$postObj) {
echo "支付回调处理失败,数据包解析失败";
} else {
// 对数据包进行签名验证
$postArr = (array)$postObj;
$sign = $utils->AppPaySign($postArr);
if ($sign == $postObj->sign) {
$this->app_order_callback($postObj);
}
}
}
/**
* app支付回调
* @param $postObj
*/
public function app_order_callback($postObj) {
$serial = $postObj->out_trade_no;
// 微信交易单号
$transaction_id = $postObj->transaction_id;
if (!empty($transaction_id)) {
//这里写你需要的逻辑
echo "<xml><return_code><![CDATA[SUCCESS]]></return_code></xml>";
}
}
/**
* 输出成功JSON消息
*/
final public function echoSuccess($msg = 'success') {
$this->echoMsg(0, $msg);
exit();
}
/**
* 输出JSON消息
* @param mixed $code
* @param mixed $msg
*/
final public function echoMsg($code, $msg = '', $options = JSON_UNESCAPED_UNICODE) {
return $this->echoJson(array(
'ret_code' => $code,
'ret_msg' => $msg
), $options);
}
/**
* 输出JSON
* @param mixed $arr
*/
final public function echoJson($arr, $options = JSON_UNESCAPED_UNICODE) {
header('Content-Type: application/json; charset=utf-8');
if (strpos(PHP_VERSION, '5.3') > -1) {
// php 5.3-
echo json_encode($arr);
} else {
// php 5.4+
echo json_encode($arr, $options);
}
return true;
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<title>微信支付测试</title>
<style type="text/css">
body {margin:0px; background:#efefef; font-family:'微软雅黑'; -moz-appearance:none;}
.weixinpay {height:44px; margin:14px 5px; background:#31cd00; border-radius:4px; text-align:center; font-size:16px; line-height:44px; color:#fff;}
</style>
</head>
<body>
<?php
include('./wxAppUtils.php');
$wxPay =new wxAppUtils();
$openid="oLkSDv7tdOWxBHXvj1Tuz_xa4W-I";
$result=$wxPay->weinXinPay($openid);
?>
appId:<input type="text" id="appId" value="<?php echo $result['appId'];?>"><br />
timeStamp:<input type="text" id="timeStamp" value="<?php echo $result['timestamp'];?>"><br />
nonceStr:<input type="text" id="nonceStr" value="<?php echo $result['nonceStr'];?>"><br />
package:<input type="text" id="package" value="<?php echo $result['package'];?>"><br />
signType:<input type="text" id="signType" value="<?php echo $result['signType'];?>"><br />
paySign:<input type="text" id="paySign" value="<?php echo $result['paySign'];?>"><br />
<div class="weixinpay">微信支付</div>
</body>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$(function(){
$(".weixinpay").click(function(){
WeixinJSBridge.invoke('getBrandWCPayRequest',{
'appId':$("#appId").val(),
'timeStamp':$("#timeStamp").val(),
'nonceStr':$("#nonceStr").val(),
'package':$("#package").val(),
'signType':$("#signType").val(),
'paySign':$("#paySign").val(),
},
function(res){
//支付成功或失败前台判断
if(res.err_msg=='get_brand_wcpay_request:ok'){
alert('恭喜您,支付成功!');
}else if(res.err_msg=='get_brand_wcpay_request:cancel') {
alert('取消支付');
}else{
alert(res.err_msg);
}
});
});
});
</script>
</html>
3退款测试类
<?php
include('./wxAppUtils.php');
$wxPay =new wxAppUtils();
$out_trade_no=""; //订单号
$wepay_serial=""; //唯一订单号
$totalFee=1; //订单金额
$refund_fee=1; //退款金额
$result=$wxPay->wxRefund($wepay_serial, $out_trade_no, $totalFee, $refund_fee);//退款
if($result['errcode']==0){
var_dump($result);
}else{
echo $result['errcode'];
}
4.工具类
<?php
include_once 'Curl.php';
/**
* @description Hope You Do Good But Not Evil
* @copyright Copyright 2014-2015 <ycchen@iwshop.cn>
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
* @author Chenyong Cai <ycchen@iwshop.cn>
* @package Wshop
* @link http://www.iwshop.cn
*/
class Util
{
private $DigCrypt;
/**
* getIPaddress
* @return type
*/
public function getIp() {
$cIP = getenv('REMOTE_ADDR');
$cIP1 = getenv('HTTP_X_FORWARDED_FOR');
$cIP2 = getenv('HTTP_CLIENT_IP');
$cIP1 ? $cIP = $cIP1 : null;
$cIP2 ? $cIP = $cIP2 : null;
return $cIP;
}
/**
* getIPaddress
* @return type
*/
public static function getIps() {
$cIP = getenv('REMOTE_ADDR');
$cIP1 = getenv('HTTP_X_FORWARDED_FOR');
$cIP2 = getenv('HTTP_CLIENT_IP');
$cIP1 ? $cIP = $cIP1 : null;
$cIP2 ? $cIP = $cIP2 : null;
return $cIP;
}
/**
* xssFilter
* @todo function
* @param type $str
* @return type
*/
public function xssFilter($str) {
return addslashes($str);
}
public function getServerIP() {
return gethostbyname($_SERVER["SERVER_NAME"]);
}
/**
*
* @param type $timestamp
* @return string
*/
public function dateTimeFormat($timestamp) {
$timestamp = strtotime($timestamp);
$curTime = time();
$space = $curTime - $timestamp;
//1分钟
if ($space < 60) {
$string = "刚刚";
return $string;
} elseif ($space < 3600) { //一小时前
$string = floor($space / 60) . "分钟前";
return $string;
}
$curtimeArray = getdate($curTime);
$timeArray = getDate($timestamp);
if ($curtimeArray['year'] == $timeArray['year']) {
if ($curtimeArray['yday'] == $timeArray['yday']) {
$format = "%H:%M";
$string = strftime($format, $timestamp);
return "今天 {$string}";
} elseif (($curtimeArray['yday'] - 1) == $timeArray['yday']) {
$format = "%H:%M";
$string = strftime($format, $timestamp);
return "昨天 {$string}";
} else {
$string = sprintf("%d月%d日 %02d:%02d", $timeArray['mon'], $timeArray['mday'], $timeArray['hours'], $timeArray['minutes']);
return $string;
}
}
$string = sprintf("%d-%d-%d %d:%d", $timeArray['year'], $timeArray['mon'], $timeArray['mday'], $timeArray['hours'], $timeArray['minutes']);
return $string;
}
/**
* ip转换地址
* @param string $ip
* @return array
*/
public function ipConvAddress($ip) {
$json = file_get_contents('http://ip.taobao.com/service/getIpInfo.php?ip=' . $ip);
$arr = json_decode($json);
return $arr->data;
}
public function digEncrypt($nums) {
return $this->DigCrypt->en($nums);
}
public function digDecrypt($code) {
return $this->DigCrypt->de($code);
}
/**
* 性别eng转换
* @param string $sex
* @return string
*/
public function sexConv($sex) {
$s = array(
'f' => '女',
'm' => '男'
);
if (array_key_exists($sex, $s)) {
return $s[$sex];
} else {
return '未知';
}
}
/**
* digitDefault
* @param string $input
* @param int $default
* @return string
*/
public static function digitDefault($input, $default = 0) {
return (is_numeric($input) && $input > 0) ? intval($input) : $default;
}
/**
* digitDefaultZero
* @param string $input
* @param int $default
* @return int
*/
public static function digitDefaultZero($input, $default = 0) {
return (is_numeric($input) && $input > -1) ? intval($input) : $default;
}
/**
* strDefault
* @param string $input
* @param string $default
* @return string
*/
public static function strDefault($input, $default = '') {
return !empty($input) ? trim(addslashes($input)) : $default;
}
/**
* 删除目录文件
* @param string $dir
* @return bool
*/
public function delDirFiles($dir) {
$dirs = dir($dir);
if ($dirs && is_readable($dirs)) {
try {
while ($file = $dirs->read()) {
$file = $dir . $file;
if (is_file($file)) {
unlink($file);
}
}
return true;
} catch (Exception $ex) {
return false;
}
}
return false;
}
/**
* 数组转换XML
* @param array $arr
* @return string
*/
public function toXML($arr) {
$xml = "<xml>";
foreach ($arr as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
/**
* 格式化参数格式化成url参数
*/
public function ToUrlParams($arr) {
$buff = "";
foreach ($arr as $k => $v) {
if ($k != "sign" && $v != "" && !is_array($v)) {
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
/**
* 生成签名
* @param array $pack
* @return string
*/
public function paySign($pack) {
ksort($pack);
$string = $this->ToUrlParams($pack);
$string = $string . "&key=" . PARTNERKEY;
$string = md5($string);
$result = strtoupper($string);
return $result;
}
/**
* 生成随机字符串
* @param int $length
* @return string
*/
public function createNoncestr($length = 32) {
$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
$str = "";
for ($i = 0; $i < $length; $i++) {
$str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
//$str .= $chars[ mt_rand(0, strlen($chars) - 1) ];
}
return $str;
}
/**
* 检查是否登陆
* @return bool
*/
public function isLogin() {
if (isset($_COOKIE['uopenid']) && isset($_COOKIE['uid'])) {
return $this->User->checkUserExt($_COOKIE['uopenid']);
} else {
return false;
}
}
/**
* 组合数组key
* @param $array
*/
public static function combineArrayKey($array) {
$tmp = [];
foreach ($array as $key => $a) {
$tmp[] = $key;
}
return $tmp;
}
/**
* 组合数组值
* @param $array
*/
public static function combineArrayValue($array) {
$tmp = [];
foreach ($array as $key => $a) {
$tmp[] = $a;
}
return $tmp;
}
/**
* 获取完整根域名
* @return string
*/
public static function getHOST() {
return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://" . $_SERVER['HTTP_HOST'];
}
/**
* 获取请求完整路径
* @return string
*/
public static function getURI() {
return self::getHOST() . $_SERVER['REQUEST_URI'];
}
/**
* 获取根路径
* @return string
*/
public static function getROOT() {
global $config;
return self::getHOST() . $config->shoproot;
}
/**
* @return bool|string
*/
public static function getNOW() {
return date('Y-m-d H:i:s');
}
/**
* 打包商品图片地址数据
* @param $name
*/
public static function packProductImgURI($name) {
global $config;
if (isset($config->oss) && $config->oss['on']) {
// 兼容oss
return $name;
} else {
return Util::getHOST() . $config->productPicLink . $name;
}
}
/**
* 转换回调地址
* @param string $url
* @return string
*/
public static function convURI($url) {
$url = preg_replace("/(\?|\&)from=(timeline|singlemessage|groupmessage)&isappinstalled=0/", "", $url);
$tmp = parse_url($url);
parse_str($tmp[query], $t);
if ($t[code] || $t[state]) {
$a = array('code' => $t[code], 'state' => $t[state]);
$s = http_build_query($a);
$r = preg_replace("/(\?|\&)" . $s . "/", "", $url);
} else {
$r = $url;
}
return $r;
}
/**
* 获取今天星期几
*/
public function getTodayStr() {
$weekarray = array(
"日",
"一",
"二",
"三",
"四",
"五",
"六"
);
return $weekarray[date('w')];
}
/**
* 充值订单序列号
* @return string
*/
public function createDepositSerial(){
return "D_" . time() . mt_rand(100, 999);
}
}
5.请求类
<?php
/**
* Curl模型
* @description Hope You Do Good But Not Evil
* @copyright Copyright 2014-2015 <ycchen@iwshop.cn>
* @license LGPL (http://www.gnu.org/licenses/lgpl.html)
* @author Chenyong Cai <ycchen@iwshop.cn>
* @package Wshop
* @link http://www.iwshop.cn
*/
class Curl {
/**
* @param $url
* @return mixed
*/
public static function get($url) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97'); // 模拟用户使用的浏览器
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
/**
* @param $url
* @param $postData
* @param bool|false $raw
* @return mixed
*/
public static function post($url, $postData, $raw = false) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
#curl_setopt($curl, CURLOPT_REFERER, 'https://mp.weixin.qq.com/');
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97'); // 模拟用户使用的浏览器
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
// post数据
curl_setopt($curl, CURLOPT_POST, 1);
//
//关于微信报错media data missing的解决方案
//php5.6及旧版本curl传文件差异
if (phpversion() < 5.6){
if (is_array($postData) && !$raw) {
$data = http_build_query($postData);
}
else{
$data = $postData;
}
}
else{
if (is_array($postData)) {
foreach ($postData as $key => $value){
//如果是上传文件,以@开头
if (substr($value,0,1) == '@'){
$data[$key] = new CURLFile(substr($value,1));
}
else{
$data[$key] = $value;
}
}
}
else{
$data = $postData;
}
}
curl_setopt($curl, CURLOPT_POSTFIELDS,$data);
$output = curl_exec($curl);
curl_close($curl);
return $output;
}
/**
* @param type $url
* @param type $head
* @return type
*/
public static function getWithHeader($url, $head = false) {
$curl = curl_init();
$header[0] = "Accept: text/xml,application/xml,application/xhtml+xml,";
$header[0] .= "text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5";
$header[] = "Cache-Control: max-age=0";
$header[] = "Connection: keep-alive";
$header[] = "Keep-Alive: 300";
$header[] = "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7";
$header[] = "Accept-Language: en-us,en;q=0.5";
$header[] = "Pragma: "; // browsers keep this blank.
if ($header) {
$header[] = $head;
}
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.97'); // 模拟用户使用的浏览器
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
$res = curl_exec($curl);
curl_close($curl);
return $res;
}
/**
* curl POST
*
* @param string url
* @param array 数据
* @param int 请求超时时间
* @param bool HTTPS时是否进行严格认证
* @return string
*/
function postXmlCurl($url,$xmldata, $second = 6) {
// 证书验证与否
$ch = curl_init();
// 设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, $second);
curl_setopt($ch,CURLOPT_URL, $url);
curl_setopt($ch,CURLOPT_SSL_VERIFYPEER,TRUE);
curl_setopt($ch,CURLOPT_SSL_VERIFYHOST,2);//严格校验
// 设置header
curl_setopt($ch, CURLOPT_HEADER, FALSE);
// 要求结果为字符串且输出到屏幕上
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
// 退款严格使用证书,必须是公众号所对应的商户平台下的证书才可以,安全不的外泄
// 设置证书
// 使用证书:cert 与 key 分别属于两个.pem文件
curl_setopt($ch,CURLOPT_SSLCERTTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLCERT,"./weixinUtils/cert/apiclient_cert.pem");
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY,"./weixinUtils/cert/apiclient_key.pem");
// post提交方式
curl_setopt($ch, CURLOPT_POST, TRUE);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmldata);
// 运行curl
$xml = curl_exec($ch);
$error = curl_errno($ch);
curl_close($ch);
// 返回结果0的时候能只能表明程序是正常返回不一定说明退款成功而已
if($xml){
// 把xml转化成数组
$xmlstring =simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
$result['errcode'] = 0;
$result['result'] =$xmlstring;
return $result;
}else{
// 错误的时候返回错误码。
$result['errcode'] = $error;
return $result;
}
}
}
百度云下载地址
http://pan.baidu.com/s/1dET2rEL
密码:iot1