public function get_open_id()
{
$sub_appid = '客户APPID';
$sub_mch_id = '客户macID';
$app_secret = "客户appsecret";
//通过code获得openid
if (!isset($_GET['code'])) {
//触发微信返回code码
$baseUrl = urlencode('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . $_SERVER['QUERY_STRING']);
$url = $this->_CreateOauthUrlForCode($sub_appid, $baseUrl);
Header("Location: $url");
exit();
} else {
//获取code码,以获取openid
$code = $_GET['code'];
$openid = $this->getOpenidFromMp($code, $sub_appid, $app_secret, $sub_mch_id);
return $openid;
}
}
public static function getSign($params, $key)
{
ksort($params, SORT_STRING);
$unSignParaString = self::formatQueryParaMap($params, false);
$signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
return $signStr;
}
protected static function formatQueryParaMap($paraMap, $urlEncode = false)
{
$buff = "";
ksort($paraMap);
foreach ($paraMap as $k => $v) {
if (null != $v && "null" != $v) {
if ($urlEncode) {
$v = urlencode($v);
}
$buff .= $k . "=" . $v . "&";
}
}
$reqPar = '';
if (strlen($buff) > 0) {
$reqPar = substr($buff, 0, strlen($buff) - 1);
}
return $reqPar;
}
//支付
public function pay($datas)
{
$order_no = '';
$data = ['type' => '', 'order_no' => $order_no];
$attach = json_encode($data, JSON_UNESCAPED_UNICODE);
$appid = '服务商APPID';
$sub_appid = '客户APPID';
$sub_mch_id = '客户MCHID';
$mch_id = '服务商MCHID';
$open_id = $this->get_open_id();
$sub_openid = $open_id;
$body = '';
$out_trade_no = $order_no;
$total_fee = $datas['money'] * 100;
$spbill_create_ip = \request()->ip();
$notify_url = '回调地址';
$trade_type = "JSAPI";
$nonce_str = getRandom(32);
$key = '服务商支付key';
$arr = [
'attach' => $attach,
'appid' => $appid,
'sub_mch_id' => $sub_mch_id,
'body' => $body,
'sub_appid' => $sub_appid,
'sub_openid' => $sub_openid,
'mch_id' => $mch_id,
'nonce_str' => $nonce_str,
'notify_url' => $notify_url,
'out_trade_no' => $out_trade_no,
'spbill_create_ip' => $spbill_create_ip,
'total_fee' => $total_fee,
'trade_type' => $trade_type,
];
ksort($arr);
$sign_str = "";
foreach ($arr as $k => $v) {
$sign_str .= $k . '=' . $v . '&';
}
$sign_str = rtrim($sign_str, '&');
$sign_str = $sign_str . '&key=' . $key;
$sign_str = strtoupper(md5($sign_str));
// 构造xml数据
$xmlData = "
<xml>
<appid>${appid}</appid>
<sub_appid>${sub_appid}</sub_appid>
<sub_mch_id>${sub_mch_id}</sub_mch_id>
<attach>${attach}</attach>
<body>${body}</body>
<mch_id>${mch_id}</mch_id>
<nonce_str>${nonce_str}</nonce_str>
<notify_url>${notify_url}</notify_url>
<sub_openid>${sub_openid}</sub_openid>
<out_trade_no>${out_trade_no}</out_trade_no>
<spbill_create_ip>${spbill_create_ip}</spbill_create_ip>
<total_fee>${total_fee}</total_fee>
<trade_type>${trade_type}</trade_type>
<sign>${sign_str}</sign>
</xml>";
$url = 'https://api.mch.weixin.qq.com/pay/unifiedorder'; //接收xml数据的文件
$ch = curl_init(); // 初始一个curl会话
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $xmlData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$result = curl_exec($ch); // 抓取URL并把它传递给浏览器
// 是否报错
if (curl_errno($ch)) {
print curl_error($ch);
}
curl_close($ch); // //关闭cURL资源,并且释放系统资源
$timeStamp = time() . "";
$result = xmlToArray($result);
$result['signType'] = "MD5";
$result['timeStamp'] = $timeStamp;
$result['nonce_str'] = $nonce_str;
$result['package'] = "prepay_id=" . $result['prepay_id'];
$arr = [
"appId" => $result['appid'],
"timeStamp" => $timeStamp, //这里是字符串的时间戳,不是int,所以需加引号
"nonceStr" => $nonce_str,
"package" => "prepay_id=" . $result['prepay_id'],
"signType" => 'MD5',
];
$result['paySign'] = self::getSign($arr, $key);
return $result;
}
//退款
public function refund($order_no, $total_fee, $refund_fee)
{
// 当前时间
$time = time();
// 生成随机字符串
$nonceStr = md5($time . $order_no . $total_fee . $refund_fee);
$main_appid = '服务商APPID';
$appid = '客户';
$sub_mch_id = '服务商';
$mch_id = '客户';
$key = '服务商支付key';
// API参数
$params = [
'sub_appid' => $appid,
'appid' => $main_appid,
'mch_id' => $mch_id,
'sub_mch_id' => $sub_mch_id,
'nonce_str' => $nonceStr,
'out_trade_no' => $order_no,
'out_refund_no' => $time,
'total_fee' => $total_fee * 100,
'refund_fee' => $refund_fee * 100,
];
// 生成签名
$params['sign'] = $this->makeSign($params, $key);
// 请求API
$url = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
$result = $this->post($url, $this->toXmls($params), true, $this->getCertPem());
// 请求失败
if (empty($result)) {
throw new BaseException(['msg' => '微信退款api请求失败']);
}
// 格式化返回结果
$prepay = $this->fromXml($result);
// 请求失败
if ($prepay['return_code'] === 'FAIL') {
throw new BaseException(['msg' => 'return_msg: ' . $prepay['return_msg']]);
}
if ($prepay['result_code'] === 'FAIL') {
throw new BaseException(['msg' => 'err_code_des: ' . $prepay['err_code_des']]);
}
return true;
}
/**
* 生成签名
*/
private function makeSign($values, $key = null)
{
//签名步骤一:按字典序排序参数
ksort($values);
$string = $this->toUrlParams($values);
//签名步骤二:在string后加入KEY
$string = $string . '&key=' . $key;
//签名步骤三:MD5加密
$string = md5($string);
//签名步骤四:所有字符转为大写
$result = strtoupper($string);
return $result;
}
private function ToUrlParams($urlObj)
{
$buff = "";
foreach ($urlObj as $k => $v) {
if ($k != "sign") {
$buff .= $k . "=" . $v . "&";
}
}
$buff = trim($buff, "&");
return $buff;
}
private function getCertPem()
// cert目录
$filePath ='';
$res = [
'certPem' => $filePath . 'cert.pem',
'keyPem' => $filePath . 'key.pem'
];
return $res;
}
public function _CreateOauthUrlForCode($appid, $redirectUrl)
{
$urlObj["appid"] = $appid;
$urlObj["redirect_uri"] = "$redirectUrl";
$urlObj["response_type"] = "code";
$urlObj["scope"] = "snsapi_base";
$urlObj["state"] = "STATE" . "#wechat_redirect";
$bizString = $this->ToUrlParams($urlObj);
return "https://open.weixin.qq.com/connect/oauth2/authorize?" . $bizString;
}
public function GetOpenidFromMp($code, $appid, $appsecret, $mch_id)
{
$url = $this->__CreateOauthUrlForOpenid($code, $appid, $appsecret);
//初始化curl
$ch = curl_init();
$curlVersion = curl_version();
$ua = "WXPaySDK/3.0.9 (" . PHP_OS . ") PHP/" . PHP_VERSION . " CURL/" . $curlVersion['version'] . " "
. $mch_id;
//设置超时
curl_setopt($ch, CURLOPT_TIMEOUT, 10);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_USERAGENT, $ua);
curl_setopt($ch, CURLOPT_HEADER, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
$res = curl_exec($ch);
curl_close($ch);
//取出openid
$data = json_decode($res, true);
$this->data = $data;
$openid = $data['openid'];
return $openid;
}
private function __CreateOauthUrlForOpenid($code, $appid, $appsecret)
{
$urlObj["appid"] = $appid;
$urlObj["secret"] = $appsecret;
$urlObj["code"] = $code;
$urlObj["grant_type"] = "authorization_code";
$bizString = $this->ToUrlParams($urlObj);
return "https://api.weixin.qq.com/sns/oauth2/access_token?" . $bizString;
}
private function fromXml($xml)
{
// 禁止引用外部xml实体
libxml_disable_entity_loader(true);
return json_decode(json_encode(simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
}
private function toXmls($values)
{
if (!is_array($values)
|| count($values) <= 0
) {
return false;
}
$xml = "<xml>";
foreach ($values as $key => $val) {
if (is_numeric($val)) {
$xml .= "<" . $key . ">" . $val . "</" . $key . ">";
} else {
$xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
}
}
$xml .= "</xml>";
return $xml;
}
protected function post($url, $data = [], $useCert = false, $sslCert = [])
{
$header = [
'Content-type: application/json;'
];
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_HEADER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
if ($useCert == true) {
// 设置证书:cert 与 key 分别属于两个.pem文件
curl_setopt($curl, CURLOPT_SSLCERTTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLCERT, $sslCert['certPem']);
curl_setopt($curl, CURLOPT_SSLKEYTYPE, 'PEM');
curl_setopt($curl, CURLOPT_SSLKEY, $sslCert['keyPem']);
}
$result = curl_exec($curl);
curl_close($curl);
return $result;
}
PHP js服务商支付和服务商退款
最新推荐文章于 2023-12-08 13:46:44 发布