8 Star 6 Fork 6

crazymus / WechatPay-for-ThinkPHP

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
WechatPay.class.php 13.70 KB
一键复制 编辑 原始数据 按行查看 历史
crazymus 提交于 2016-01-30 14:31 . 创建项目
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
<?php
/**
* @name 微信支付PHPSDK,实现了微信支付大部分接口
* @author crazymus < QQ:291445576 >
* @version 2.0.1
* @licensed apache2.0
* @updated 2016-01-19
* @link https://pay.weixin.qq.com/wiki/doc/api/index.html
*/
namespace Org\Util;
class WechatPay{
protected static $config = array(
//app id
'appid' => '',
//app key
'app_key' => '',
//商户号
'mch_id' => '',
//密钥
'appsecret' => '',
//证书放在非WEB目录中 保证安全
'SSLCERT_PATH' => '',
'SSLKEY_PATH' => ''
);
/**
* @name 动态配置
* @param array
*/
public function init($config){
self::$config = array_merge(self::$config, $config);
}
/**
* @name 读取配置信息
* @return array
*/
public function getConfig(){
return self::$config;
}
/**
* @name 统一下单
* @param array
* array(
'body' => '订单描述',
'out_trade_no' => '订单号',
'total_fee' => '金额 单位为分',
'notify_url' => '接收支付信息地址', //必须使用pathinfo,不可带query_string
'trade_type' => '支付类别 JSAPI--公众号支付、NATIVE--原生扫码支付、APP--app支付',
'openid' => '用户openid 支付类别为JSAPI必须提供'
)
* @return JSON 若交易类型为JSAPI,则返回
https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
需要的参数
若交易类型为APP,则返回
https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_12&index=2
需要的参数
*/
public static function UnifiedOrder($arr) {
$arr = array(
'appid' => self::$config['appid'],
'mch_id' => self::$config['mch_id'],
'nonce_str' => self::makeNonceStr(),
'body' => $arr['body'],
'out_trade_no' => $arr['out_trade_no'],
'total_fee' => $arr['total_fee'],
'spbill_create_ip' => $_SERVER['REMOTE_ADDR'],
'notify_url' => $arr['notify_url'],
'trade_type' => $arr['trade_type'],
'openid' => $arr['openid']
);
//生成签名
$arr['sign'] = self::makeSign($arr);
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
$result = self::post($url, $arr);
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ){
$output = array(
'success' => true,
'msg' => '成功获取prepay_id'
);
if($arr['trade_type'] == 'JSAPI'){
//网页调起微信支付的返回值
$params = array(
'appId' => self::$config['appid'],
'timeStamp' => time(),
'nonceStr' => self::makeNonceStr(),
//prepay_id
'package' => "prepay_id=".$result['prepay_id'],
//签名方式
'signType' => 'MD5'
);
//计算签名
$params['paySign'] = self::makeSign($params);
}else if($arr['trade_type'] == 'APP'){
//APP调起微信
$params = array(
'appid' => self::$config['appid'],
'partnerid' => self::$config['mch_id'],
'prepayid' => $result['prepay_id'],
'package' => 'Sign=WXPay',
'noncestr' => self::makeNonceStr(),
'timestamp' => time()
);
//计算签名
$params['sign'] = self::makeSign($params);
}else{
$params = '抱歉,当前仅支持JSAPI和APP支付';
}
$output['params'] = $params;
}else{
$output = array(
'success' => false,
'msg' => '获取prepay_id失败, 请重新尝试'
);
}
return $output;
}
/**
* @name 查询订单
* @param array 传入订单号(out_trade_no) 或微信订单号(transaction_id)
* @param callbackContext 回调类 实现WechatPayQuery接口
* @output JSON 查询及回调方法执行结果
*/
public static function queryOrder($array, WechatPayQuery $callbackContext){
//获取配置信息
$config = self::$config;
//获取appid和商户号
$array['appid'] = $config['appid'];
$array['mch_id'] = $config['mch_id'];
//生成随机字符串
$array['nonce_str'] = self::makeNonceStr();
//生成签名
$sign = self::makeSign($array);
$array['sign'] = $sign;
$url = 'https://api.mch.weixin.qq.com/pay/orderquery';
$result = self::post($url, $array);
//=========校验签名==========//
$sign = self::makeSign($result);
if($sign != $result['sign']){
echo json_encode(array(
'success' => false,
'msg' => '签名校验失败'
));
}
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ){
//订单支付成功 执行回调
$callback_result = $callbackContext->success($result);
if($callback_result){
$output = array(
'success' => true,
'msg' => '订单处理成功'
);
}else{
$output = array(
'success' => false,
'msg' => '订单处理失败'
);
}
}else{
//查询失败的返回值
$output = array(
'success' => false,
'msg' => '订单查询失败, 请重新尝试'
);
}
return $output;
}
/**
* @name 接收微信回传信息, 并完成业务逻辑
* @param $callbackContext 回调类,实现WechatPayNotify接口
* @output XML 参见https://pay.weixin.qq.com/wiki/doc/api/app.php?chapter=9_7&index=3
*/
public static function notify(WechatPayNotify $callbackContext){
//======获取原生的POST数据===========//
$xml = file_get_contents("php://input");
if(!$xml){
return null;
}
//转成数组
$array = self::toArray($xml);
//========生成签名===========//
$sign = self::makeSign($array);
//=========校验签名========//
if($sign != $array['sign']){
$result = array(
'return_code' => 'FAIL',
'return_msg' => '签名校验失败'
);
echo self::toXml($result);
exit;
}
if($array['result_code'] == 'SUCCESS'){
//表示支付成功 执行业务逻辑
$callback_result = $callbackContext->success($array);
if($callback_result){
$result = array(
'return_code' => 'SUCCESS',
'return_msg' => '订单处理成功'
);
echo self::toXml($result);
}
}
}
/**
* @name 申请退款
* @param array(
'out_trade_no' => '商户订单号',
'out_refund_no' => '退款订单号',
'total_fee' => '总费用',
'refund_fee' => '退款金额'
)
@param WechatPayRefund 申请退款成功后执行的回调
@return array
成功:
array(
'success' => true,
'msg' => '成功的提示'
)
失败:
array(
'success' => false,
'msg' => '失败的提示'
)
*/
public function refund($params, WechatPayRefund $callbackContext){
//退款地址
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
//获取配置信息
$config = self::$config;
$array['appid'] = $config['appid'];
$array['mch_id'] = $config['mch_id'];
$array['nonce_str'] = self::makeNonceStr();
$array['out_trade_no'] = $params['out_trade_no'];
$array['out_refund_no'] = $params['out_refund_no'];
//总费用
$array['total_fee'] = $params['total_fee'];
//退款金额
$array['refund_fee'] = $params['refund_fee'];
//操作员 默认为商户号
$array['op_user_id'] = $config['mch_id'];
//生成签名
$array['sign'] = self::makeSign($array);
$result = self::postSSL($url, $array);
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS'){
$callback_result = $callbackContext->success($result);
if($callback_result){
$output = array(
'success' => true,
'msg' => '申请退款成功, 请稍后查询退款结果'
);
}else{
$output = array(
'success' => false,
'msg' => '申请退款失败, 请重新尝试'
);
}
}else{
$output = array(
'success' => false,
'msg' => '申请退款失败, 请重新尝试'
);
}
return $output;
}
/**
* @name 查询退款结果
* @param string 商户订单号
* @param WechatPayRefundQuery 退款成功后的回调
* @return array
成功:array(
'success' => true,
'msg' => '成功提示'
)
失败:array(
'success' => false,
'msg' => '失败提示'
)
*/
public function refundQuery($out_trade_no, WechatPayRefundQuery $callbackContext){
$url = 'https://api.mch.weixin.qq.com/pay/refundquery';
$config = self::$config;
$array['appid'] = $config['appid'];
$array['mch_id'] = $config['mch_id'];
$array['nonce_str'] = self::makeNonceStr();
$array['out_trade_no'] = $out_trade_no;
$array['sign'] = self::makeSign($array);
$result = self::post($url, $array);
if($result['return_code'] == 'SUCCESS' && $result['result_code'] == 'SUCCESS' ){
if($result['refund_status_$n'] == 'SUCCESS'){
$callback_result = $callbackContext->success($result);
if($callback_result){
$output = array(
'success' => true,
'msg' => '退款成功'
);
}else{
$output = array(
'success' => false,
'msg' => '业务处理失败, 请重新尝试'
);
}
}else if($result['refund_status_$n'] == 'FAIL'){
$output = array(
'success' => false,
'msg' => '退款失败'
);
}else if($result['refund_status_$n'] == 'PROCESSING'){
$output = array(
'success' => false,
'msg' => '退款正在处理中'
);
}else if($result['refund_status_$n'] == 'NOTSURE'){
$output = array(
'success' => false,
'msg' => '请重新发起退款'
);
}else if($result['refund_status_$n'] == 'CHANGE'){
$output = array(
'success' => false,
'msg' => '接收退款的银行卡冻结了, 请联系客服'
);
}else{
$output = array(
'success' => false,
'msg' => '未知错误, 请重新尝试'
);
}
}else{
$output = array(
'success' => false,
'msg' => '查询失败, 请重新尝试'
);
}
return $output;
}
/**
* @name 生成成功提示
* @param string 提示语
* @output JSON
*/
public static function success($msg){
echo json_encode(array(
'return_code' => 'SUCCESS',
'msg' => $msg
));
}
/**
* @name 生成错误提示
* @param string 提示语
* @output JSON
*/
public static function error($msg){
echo json_encode(array(
'return_code' => 'FAIL',
'msg' => $msg
));
}
//=======将XML转成数组=============//
protected static function toArray($xml){
//加上反斜杠防止引入命名空间时报错
$xml_obj = new \SimpleXMLElement($xml);
$xml_array = array();
foreach($xml_obj as $key=>$value){
//类型转换
$xml_array[$key] = (string)$value;
}
return $xml_array;
}
//======将数组转成XML==============//
protected static function toXml($array){
//\r\n是为了兼容windows notepad下的换行
$xml = "<xml>\r\n";
foreach($array as $key=>$value){
$xml.="<$key>$value</$key>\r\n";
}
$xml.="</xml>\r\n";
return $xml;
}
//=========生成签名算法===============//
public static function makeSign($array){
//排除sign字段
unset($array['sign']);
//字典排序
ksort($array);
//参数拼接,值为空不参与签名生成!!!
foreach($array as $key=>$value){
if($value != ''){
$array[$key] = "$key=$value";
}else{
unset($array[$key]);
}
}
//加上密钥
$array['key'] = "key=".self::$config['app_key'];
//连接成字符串
$params = implode('&',$array);
//得到签名
return strtoupper(md5($params));
}
//========生成随机字串=======//
public function makeNonceStr(){
return base64_encode(time());
}
/**
* @name 使用证书发出POST请求
* @param $arr array 参数
* @param $url string 地址
* @param $second integer 超时时间
*/
public static function postSSL($url, $arr, $second = 30)
{
$xml = self::toXml($arr);
$ch = curl_init();
$config = self::$config;
//超时时间
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);
//设置证书
//使用证书:cert 与 key 分别属于两个.pem文件
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($ch,CURLOPT_SSLCERT, $config['SSLCERT_PATH']);
//默认格式为PEM,可以注释
curl_setopt($ch,CURLOPT_SSLKEYTYPE,'PEM');
curl_setopt($ch,CURLOPT_SSLKEY, $config['SSLKEY_PATH']);
//post提交方式
curl_setopt($ch,CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS, $xml);
$result = curl_exec($ch);
//返回结果
if($result){
curl_close($ch);
return self::toArray($result);
}
else {
$error = curl_errno($ch);
echo "curl出错,错误码:$error"."<br>";
echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
curl_close($ch);
return false;
}
}
/**
* @name 发出POST请求
* @param $arr array 参数
* @param $url string 地址
* @param $second integer 超时时间
* @return array 返回值
*/
public static function post($url, $arr, $second = 30)
{
$xml = self::toXml($arr);
//初始化curl
$ch = curl_init();
//设置超时
curl_setopt($ch, CURLOP_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
$result = curl_exec($ch);
//返回结果
if($result)
{
curl_close($ch);
return self::toArray($result);
}
else
{
$error = curl_errno($ch);
echo "curl出错,错误码:$error"."<br>";
echo "<a href='http://curl.haxx.se/libcurl/c/libcurl-errors.html'>错误原因查询</a></br>";
curl_close($ch);
return false;
}
}
}
?>
PHP
1
https://gitee.com/jiusem/WechatPay-for-ThinkPHP.git
git@gitee.com:jiusem/WechatPay-for-ThinkPHP.git
jiusem
WechatPay-for-ThinkPHP
WechatPay-for-ThinkPHP
master

搜索帮助