一、Model层,Wxpay.php
appid = $appid;
if(!empty($secret)) $this->secret = $secret;
if(!empty($mchid)) $this->mchid = $mchid;
if(!empty($key)) $this->key= $key;
}
/*
* 微信内H5调起支付
* @params string $openid : 微信用户openid
* @params string $out_trade_no : 商家生成的订单号(唯一性)
* @params int $total_fee : 支付金额,单位分
* return array $ret : 返回支付时所需要的数据
* */
public function payForWeixin($openid,$out_trade_no,$total_fee,$attach="微信支付",$body="微信支付")
{
//支付数据
$data["openid"] = $openid;
$data["out_trade_no"] = $out_trade_no;
$data["total_fee"] = $total_fee*100;
$data["spbill_create_ip"] = $_SERVER["REMOTE_ADDR"];
$data["attach"] = $attach;
$data["body"] = $body;
$data["appid"] = $this->appid;
$data["mch_id"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["trade_type"] = "JSAPI";
$data["notify_url"] = "http://****.com/home/wxpaynofiy/notify.html";
$sign = $this->getParam($data);
$dataXML = "
".$data["appid"]."
".$data["attach"]."
".$data["body"]."
".$data["mch_id"]."
".$data["nonce_str"]."
".$data["notify_url"]."
".$data["openid"]."
".$data["out_trade_no"]."
".$data["spbill_create_ip"]."
".$data["total_fee"]."
".$data["trade_type"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if($ret["return_code"] == "SUCCESS" && $ret["return_msg"] == "OK") {
return array(
"appId" => $this->appid,
"timeStamp" => time(),
"nonceStr" => $data["nonce_str"],
"package" => "prepay_id=".$ret["prepay_id"],
"signType" => "MD5",
"paySign" => $sign
);
} else {
$this->errorLog("微信支付失败,",$ret);
return null;
}
}
/*
* 微信二维码支付
* @params string $openid : 用户的openid
* @params string $out_trade_no : 商户订单号
* @params number $total_fee : 订单金额,单位分
* return string $code_url : 二维码URL链接
*/
public function payForQrcode($out_trade_no,$total_fee,$body="魔盒CMS",$attach="微信支付")
{
//支付数据
$data["out_trade_no"] = $out_trade_no;
$data["total_fee"] = $total_fee*100;
$data["spbill_create_ip"] = $_SERVER["REMOTE_ADDR"];
$data["attach"] = $attach;
$data["body"] = $body;
$data["appid"] = $this->appid;
$data["mch_id"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["trade_type"] = "NATIVE";
$data["notify_url"] = "http://****.com/home/wxpaynofiy/notify.html";
$sign = $this->getParam($data);
$dataXML = "
".$data["appid"]."
".$data["attach"]."
".$data["body"]."
".$data["mch_id"]."
".$data["nonce_str"]."
".$data["notify_url"]."
".$data["out_trade_no"]."
".$data["spbill_create_ip"]."
".$data["total_fee"]."
".$data["trade_type"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/pay/unifiedorder";
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if($ret["return_code"] == "SUCCESS" && $ret["return_msg"] == "OK") {
return $ret["code_url"];
} else {
$this->errorLog("获取微信支付二维码失败,",$ret);
return null;
}
}
/*
* 订单查询
* @params string $transaction_id : 微信订单号
* @params string $out_trade_no : 商家订单号(与微信订单号二选一)
* */
public function findOrder($out_trade_no)
{
$data["appid"] = $this->appid;
$data["mch_id"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["out_trade_no"] = $out_trade_no;
$sign = $this->getParam($data);
$dataXML = "
".$data["appid"]."
".$data["mch_id"]."
".$data["nonce_str"]."
".$data["out_trade_no"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/pay/orderquery";
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if($ret["return_code"] == "SUCCESS" && $ret["return_msg"] == "OK") {
return $ret;
} else {
$this->errorLog("查询微信支付订单失败,",$ret);
return null;
}
}
/*
* 退款订单查询
* @params string $transaction_id : 微信订单号
* @params string $out_trade_no : 商家订单号(与微信订单号二选一)
* */
public function findRefundOrder($out_trade_no)
{
$data["appid"] = $this->appid;
$data["mch_id"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["out_trade_no"] = $out_trade_no;
$sign = $this->getParam($data);
$dataXML = "
".$data["appid"]."
".$data["mch_id"]."
".$data["nonce_str"]."
".$data["out_trade_no"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/pay/refundquery";
$result = $this->https_post($url,$dataXML);
$ret = $this->xmlToArray($result);
if($ret["return_code"] == "SUCCESS" && $ret["return_msg"] == "OK") {
return $ret;
} else {
$this->errorLog("查询微信支付退款订单失败,",$ret);
return $ret["err_code_des"];
}
}
/*
* 申请退款
* @params string $out_trade_no : 商户订单号
* @params string $out_refund_no : 商户退款单号
* @params int $total_fee : 订单金额
* @params int $refund_fee : 退款金额
* @params string $refund_desc : 退款原因
* */
public function refund($out_trade_no,$out_refund_no,$total_fee,$refund_fee,$refund_desc="退款")
{
$data["appid"] = $this->appid;
$data["mch_id"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["out_trade_no"] = $out_trade_no;
$data["out_refund_no"] = $out_refund_no;
$data["total_fee"] = $total_fee*100;
$data["refund_fee"] = $refund_fee*100;
$data["refund_desc"] = $refund_desc;
$data["notify_url"] = "http://*****.com/home/wxpaynofiy/refund.html";
$sign = $this->getParam($data);
$dataXML = "
".$data["appid"]."
".$data["mch_id"]."
".$data["nonce_str"]."
".$data["out_trade_no"]."
".$data["out_refund_no"]."
".$data["total_fee"]."
".$data["refund_fee"]."
".$data["refund_desc"]."
".$data["notify_url"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/secapi/pay/refund";
$result = $this->https_post($url,$dataXML,true);
$ret = $this->xmlToArray($result);
if($ret["return_code"] == "SUCCESS" && $ret["return_msg"] == "OK") {
return $ret;
} else {
$this->errorLog("微信退款失败,",$ret);
return null;
}
}
/*
* 企业付款至用户零钱
* @params string $openid : 用户openid
* @params int $total_fee : 付款金额,单位分
* @params string $out_trade_no : 商家订单号
* @params string $username : 微信用户名称(注意微信昵称若为空时支付会出错)
* @params string $desc : 付款描述
* @params string $check_name : 是否检测用户名
* */
public function payForUser($openid,$total_fee,$out_trade_no,$username="魔盒CMS",$desc="魔盒CMS付款给用户",$check_name="NO_CHECK")
{
$data["amount"] = $total_fee*100;
$data["check_name"] = $check_name;
$data["desc"] = $desc;
$data["mch_appid"] = $this->appid;
$data["mchid"] = $this->mchid;
$data["nonce_str"] = random(12);
$data["openid"] = $openid;
$data["partner_trade_no"] = $out_trade_no;
$data["re_user_name"] = $username;
$data["spbill_create_ip"] = $_SERVER["REMOTE_ADDR"];
$sign = $this->getParam($data);
$dataXML="
".$data["mch_appid"]."
".$data["mchid"]."
".$data["nonce_str"]."
".$data["partner_trade_no"]."
".$data["openid"]."
".$data["check_name"]."
".$data["re_user_name"]."
".$data["amount"]."
".$data["desc"]."
".$data["spbill_create_ip"]."
".$sign."
";
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/promotion/transfers";
$result = $this->https_post($url,$dataXML,true);
$ret = $this->xmlToArray($result);
if($ret["return_code"]=="SUCCESS" && $ret["result_code"] == "SUCCESS")
{
//支付成功返回商户订单号、微信订单号、微信支付成功时间
$result["partner_trade_no"] = $ret["partner_trade_no"];
$result["payment_no"] = $ret["payment_no"];
$result["payment_time"] = $ret["payment_time"];
return $ret;
} else {
$this->errorLog("付款给用户失败",$ret);
return null;
}
}
/*
* 普通红包
* @params string $out_trade_no : 商家订单号
* @params string $openid : 接收红包用户的openid
* @params int $total_fee : 红包金额,单位分
* @params int $total_num : 红包发放总人数
* @params string $wishing : 红包祝福语
* @params string $act_name : 活动名称
* @params string $remark : 备注
* @params string $scene_id :场景值ID。发放红包使用场景,红包金额大于200或者小于1元时必传。PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖 、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖
* */
public function redPack($openid,$total_fee,$out_trade_no,$total_num = 1,$wishing = "感谢您光临***平台进行购物",$act_name="***购物发红包",$remark = "购物领红包")
{
$data["mch_billno"] = $out_trade_no;
$data["mch_id"] = $this->mchid;
$data["wxappid"] = $this->appid;
$data["send_name"] = "发送红包者的名称";
$data["re_openid"] = $openid;
$data["total_amount"] = $total_fee;
$data["total_num"] = $total_num;
$data["wishing"] = $wishing;
$data["client_ip"] = $_SERVER["REMOTE_ADDR"];
$data["act_name"] = $act_name;
$data["remark"] = $remark;
$data["nonce_str"] = random(12);
$sign = $this->getParam($data);
$dataXML="
".$sign."
".$data["mch_billno"]."
".$data["mch_id"]."
".$data["wxappid"]."
".$data["send_name"]."
".$data["re_openid"]."
".$data["total_amount"]."
".$data["total_num"]."
".$data["wishing"]."
".$data["client_ip"]."
".$data["act_name"]."
".$data["remark"]."
".$data["nonce_str"]."
";
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendredpack";
$result = $this->https_post($url,$dataXML,true);
$ret = $this->xmlToArray($result);
if($ret["return_code"]=="SUCCESS" && $ret["result_code"] == "SUCCESS")
{
return $ret;
} else {
$this->errorLog("发放普通红包失败",$ret);
return $ret["err_code_des"];
}
}
/*
* 裂变红包:一次可以发放一组红包。首先领取的用户为种子用户,种子用户领取一组红包当中的一个,并可以通过社交分享将剩下的红包给其他用户。
* 裂变红包充分利用了人际传播的优势。
* @params string $out_trade_no : 商家订单号
* @params string $openid : 接收红包用户的openid
* @params int $total_fee : 红包金额,单位分
* @params int $total_num : 红包发放总人数
* @params string $wishing : 红包祝福语
* @params string $act_name : 活动名称
* @params string $remark : 备注
* @params string $scene_id :场景值ID。发放红包使用场景,红包金额大于200或者小于1元时必传。PRODUCT_1:商品促销、PRODUCT_2:抽奖、PRODUCT_3:虚拟物品兑奖 、PRODUCT_4:企业内部福利、PRODUCT_5:渠道分润、PRODUCT_6:保险回馈、PRODUCT_7:彩票派奖、PRODUCT_8:税务刮奖
* */
public function redPackGroup($openid,$total_fee,$out_trade_no,$total_num,$wishing = "感谢您光临***进行购物",$act_name="**购物发红包",$remark = "购物领红包")
{
$data["mch_billno"] = $out_trade_no;
$data["mch_id"] = $this->mchid;
$data["wxappid"] = $this->appid;
$data["send_name"] = "发送红包者的名称";
$data["re_openid"] = $openid;
$data["total_amount"] = $total_fee;
$data["amt_type"] = "ALL_RAND"; //ALL_RAND—全部随机,商户指定总金额和红包发放总人数,由微信支付随机计算出各红包金额
$data["total_num"] = $total_num;
$data["wishing"] = $wishing;
$data["client_ip"] = $_SERVER["REMOTE_ADDR"];
$data["act_name"] = $act_name;
$data["remark"] = $remark;
$data["nonce_str"] = random(12);
$sign = $this->getParam($data);
$dataXML="
".$sign."
".$data["mch_billno"]."
".$data["mch_id"]."
".$data["wxappid"]."
".$data["send_name"]."
".$data["re_openid"]."
".$data["total_amount"]."
".$data["amt_type"]."
".$data["total_num"]."
".$data["wishing"]."
".$data["client_ip"]."
".$data["act_name"]."
".$data["remark"]."
".$data["nonce_str"]."
";
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendgroupredpack";
$result = $this->https_post($url,$dataXML,true);
$ret = $this->xmlToArray($result);
if($ret["return_code"]=="SUCCESS" && $ret["result_code"] == "SUCCESS")
{
return $ret;
} else {
$this->errorLog("发放裂变红包失败",$ret);
return $ret["err_code_des"];
}
}
/*
* 查询红包记录
* @params string $out_trade_no : 商家订单号
* */
public function findRedPack($out_trade_no)
{
$data["mch_billno"] = $out_trade_no;
$data["mch_id"] = $this->mchid;
$data["appid"] = $this->appid;
$data["bill_type"] = "MCHT"; //MCHT:通过商户订单号获取红包信息。
$data["nonce_str"] = random(12);
$sign = $this->getParam($data);
$dataXML="
".$sign."
".$data["mch_billno"]."
".$data["mch_id"]."
".$data["appid"]."
".$data["bill_type"]."
".$data["nonce_str"]."
";
$url = "https://api.mch.weixin.qq.com/mmpaymkttransfers/gethbinfo";
$result = $this->https_post($url,$dataXML,true);
$ret = $this->xmlToArray($result);
if($ret["return_code"]=="SUCCESS" && $ret["result_code"] == "SUCCESS")
{
return $ret;
} else {
$this->errorLog("查询红包记录失败",$ret);
return $ret["err_code_des"];
}
}
/*
* 获取用户微信的OPENID
* */
public function openid($c=false)
{
if($_GET["state"]!="zgm"){
$t = $c ? "snsapi_userinfo" : "snsapi_base";
$url=urlencode(get_url());
$url="https://open.weixin.qq.com/connect/oauth2/authorize?appid=".$this->appid."&redirect_uri=".$url."&response_type=code&scope=".$t."&state=zgm#wechat_redirect";
echo "";
exit;
}
if($_GET["code"]){
$url="https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->secret."&code=".$_GET["code"]."&grant_type=authorization_code";
$wx_db=json_decode($this->https_get($url));
if($c){
$url_2="https://api.weixin.qq.com/sns/userinfo?access_token=".$wx_db->access_token."&openid=".$wx_db->openid."&lang=zh_CN";
$db=json_decode($this->https_get($url_2));
return $db;
}else{
return $wx_db->openid;
}
}
}
/*
* 发起网络GET请求
* @params string $url : URL链接
*/
private function https_get($url)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_HEADER, FALSE) ;
curl_setopt($curl, CURLOPT_TIMEOUT,60);
if (curl_errno($curl)) {
return "Errno".curl_error($curl);
}
else{$result=curl_exec($curl);}
curl_close($curl);
return $result;
}
//对参数排序,生成MD5加密签名
private function getParam($paramArray, $isencode=false)
{
$paramStr = "";
ksort($paramArray);
$i = 0;
foreach ($paramArray as $key => $value)
{
if ($key == "Signature"){
continue;
}
if ($i == 0){
$paramStr .= "";
}else{
$paramStr .= "&";
}
$paramStr .= $key . "=" . ($isencode?urlencode($value):$value);
++$i;
}
$stringSignTemp=$paramStr."&key=".$this->key;
$sign=strtoupper(md5($stringSignTemp));
return $sign;
}
//POST提交数据
private function https_post($url,$data,$ssl = false)
{
$ch = curl_init ();
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_CUSTOMREQUEST, "POST" );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYPEER, FALSE );
curl_setopt ( $ch, CURLOPT_SSL_VERIFYHOST, FALSE );
if($ssl) {
curl_setopt ( $ch,CURLOPT_SSLCERT,$this->sslcert_path);
curl_setopt ( $ch,CURLOPT_SSLKEY,$this->sslkey_path);
}
curl_setopt ( $ch, CURLOPT_FOLLOWLOCATION, 1 );
curl_setopt ( $ch, CURLOPT_AUTOREFERER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $data );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, true );
$result = curl_exec($ch);
if (curl_errno($ch)) {
return "Errno: ".curl_error($ch);
}
curl_close($ch);
return $result;
}
/*
* XML转array
* @params xml $xml : xml 数据
* return array $data : 转义后的array数组
*/
private function xmlToArray($xml)
{
libxml_disable_entity_loader(true);
$xmlstring = simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA);
$val = json_decode(json_encode($xmlstring),true);
return $val;
}
/*
* 记录日志
* @params string $msg : 提示语句
* @params array $ret : 错误结果
*/
private function errorLog($msg,$ret)
{
file_put_contents(ROOT_PATH . "runtime/error/wxpay.log", "[" . date("Y-m-d H:i:s") . "] ".$msg."," .json_encode($ret).PHP_EOL, FILE_APPEND);
}
}
二、Controller层,Test.php
openid();
$pay = $wxpay->payForWeixin($openid,date("YmdHis").rand(1,5),"0.1");
$paySign =strtoupper(MD5("appId=".$pay["appId"]."&nonceStr=".$pay["nonceStr"]."&package=".$pay["package"]."&signType=MD5&timeStamp=".$pay["timeStamp"]."&key=536*****9e8"));
$h5 = array(
"appId" => $pay["appId"],
"timeStamp" => $pay["timeStamp"],
"nonceStr" => $pay["nonceStr"],
"package" => $pay["package"],
"signType" => $pay["signType"],
"paySign" => $paySign
);
$this->assign("wxpay",$h5);
return view();
}
}
三、HTML中调用微信支付,wx.html
订单示例
四、接收微信支付返回结果,支付时设置的notify_url值,确保此链接外网能访问。wxpaynofiy.php
checkSign($data)) {
$transaction_id = $data["transaction_id"]; //微信支付订单号
$out_trade_no = $data["out_trade_no"]; //商家订单号
$this->errorLog("微信支付返回结果,微信支付订单号:".$transaction_id.",商家订单号:".$out_trade_no,[]);
} else {
$this->errorLog("微信支付返回结果签名验证失败",$data);
}
} else {
$this->errorLog("微信支付返回结果",$data);
}
echo " ";
}
/*
* 验证签名
* @params array $result : 微信支付成功返回的结果数组
* return bool $ret : 成功true,失败false
* */
private function checkSign(array $data)
{
$str = "";
ksort($data);
foreach ($data as $k => $v) {
if($k != "sign") $str .= $k."=".$v."&";
}
$temp = $str . "key=5363******49e8"; //key:商户支付密钥
$sign = strtoupper(md5($temp));
return $sign == $data["sign"] ? true : false;
}
private function errorLog($msg,$ret)
{
file_put_contents(ROOT_PATH . "runtime/error/wxpaynofiy.log", "[" . date("Y-m-d H:i:s") . "] ".$msg."," .json_encode($ret).PHP_EOL, FILE_APPEND);
}
}
五、常见问题
1、H5支付时出现“签名错误”,需要注意的调用微信“统一下单”接口后返回pre_pay_id后,需要用户再次进行签名返回给HTML; 2、“支付目录没有授权”,进入微信商家管理后台设置即可;
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/29095.html
摘要:本文是浅析微信支付系列文章的第二篇,主要讲解一下普通商户接入的支付方式以及其中的不同之处。浅析微信支付前篇大纲微信支付是集成在微信客户端的支付功能,用户可以通过手机完成快速的支付流程。目前微信支付支持手机系统有苹果安卓和。 本文是【浅析微信支付】系列文章的第二篇,主要讲解一下普通商户接入的支付方式以及其中的不同之处。 上篇文章讲了本系列的大纲,没有看过的朋友们可以看一下。 浅析微信支...
摘要:本文是浅析微信支付系列文章的第五篇,主要讲解如何调用统一下单接口生成预支付单及调起支付页面。浅析微信支付系列已经更新四篇了哟,没有看过的朋友们可以看一下哦。 本文是【浅析微信支付】系列文章的第五篇,主要讲解如何调用统一下单接口生成预支付单及调起支付页面。 浅析微信支付系列已经更新四篇了哟~,没有看过的朋友们可以看一下哦。 浅析微信支付:微信公众号网页授权 浅析微信支付:开发前的准备 ...
摘要:这个坑就是要注意回调结束要返回成功的响应这几天做微信支付暂时遇到的问题就这么多,只能说注意细节吧,爬过的坑记录下来以后遇到就懂处理了。 前言 其实任何接口开发只要按照给出来的接口文档和例子开发基本上不会有太大问题的,一些问题都是出在杂七杂八的小细节上,现在分享一下微信支付开发中自己遇到的小细节。按照文档做完开发前配置,比如JS安全域名配置、网页授权域名、公众号授权目录等等... 坑一:...
摘要:微信支付支付在服务端调用统一下单接口后,服务端需要将返回的订单数据进行二次签名后才能返回给端。微信支付服务端提供了类,类中也的确提供了生成签名方法,即对结果集签名,源码如下以版为例,其他语言自行对照。 获取到 prepay_id 后将参数再次签名传输给 APP 发起支付。 相信有不少同学因为看到统一下单返回的结果中有 sign 字段,会直接将结果返回给 APP 端,结果 APP 端没办...
摘要:这几天在做小程序的支付,没有用官方的,这里就纯用官方的文档搞一发。 这几天在做小程序的支付,没有用官方的SDK,这里就纯用官方的文档搞一发。 * 注作者使用的PHP,不过支付流程都是这样 开发前必读 主要流程 小程序前端发送求参请求 接受请求封装 统一下单 获取package 小程序接受 统一下单 获取的package值带入wx.requestPayment发起支付请求 准备...
阅读 3923·2021-11-25 09:43
阅读 912·2021-09-22 15:59
阅读 2006·2021-09-06 15:00
阅读 2021·2021-09-02 09:54
阅读 926·2019-08-30 15:56
阅读 1379·2019-08-29 17:14
阅读 2073·2019-08-29 13:15
阅读 1110·2019-08-28 18:28