最近做了一个海外项目,需要接入海外公司提供的微信支付接口IOTPay,看了文档基本跟国内版的一致。
微信JSAPI支付集成(微信小程序)
小程序要接入海外支付,必须主体是海外公司。中国境内公司申请的小程序无法接入海外支付。
请求URL
服务地址: https://api.iotpaycloud.com/v1/create_order
请求方式:
- POST
- Content-Type: application/x-www-form-urlencoded
-
参数说明
-
字段名 变量名 必填 类型 示例值 描述 商户ID mchId 是 String(30) 20001222 支付中心分配的商户号 商户订单号 mchOrderNo 是 String(30) 20160427210604000490 商户生成的订单号,请保证唯一性 渠道ID channelId 是 String(24) WX_JSAPI 小程序接口 币种 currency 是 String(3) CAD 三位货币代码,加币:CAD 支付金额 amount 是 int 100 支付金额,单位分 客户端IP clientIp 是 String(32) 210.73.10.148 客户端IP地址 设备 device 否 String(64) WEB 终端设备号(门店号或收银设备ID),注意:PC网页或公众号内支付请传"WEB 支付结果回调URL notifyUrl 是 String(200) http://xxx.com/notify.php 支付结果回调URL 商品主题 subject 是 String(64) 测试商品 商品主题 商品描述信息 body 是 String(256) xxpay测试商品描述 商品描述信息 扩展参数1 param1 否 String(64) 支付中心回调时会原样返回 扩展参数2 param2 否 String(64) 支付中心回调时会原样返回 附加参数 extra 是 String(512) {"openId":"o2RvowBf7sOVJf8kJksUEMceaDqo", "type":"minipay","appId":"xxxxxxxxx"} 子账号 jobNo 是 String(50) 商户登录名 附言 remarks 否 String(200) 商户的附言 签名 sign 是 String(32) C380BEC2BFD727A4B6845133519F3AD6 签名值,详见签名算法 当小程序后端接收到返回值后,将返回值传回小程序前端并调用
wx.requestPayment
,将以下参数填入进行发起支付:
wx.requestPayment({
appId: res.data.payParams.appId,
timeStamp: res.data.payParams.timeStamp,
nonceStr: res.data.payParams.nonceStr,
package: res.data.payParams.package,
signType: res.data.payParams.signType,
paySign: res.data.payParams.paySign,
success(res) {
console.log(res);
wx.navigateTo({
url: '',
})
},
fail(res) {
console.log(res);
wx.navigateTo({
url: '',
})
}
})
返回结果
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
返回状态码 | retCode | 是 | String(16) | SUCCESS | SUCCESS/FAIL此字段是通信标识,非交易标识,交易是否成功需要查看resCode来判断 |
返回信息 | retMsg | 否 | String(128) | 签名失败 | 返回信息,如非空,为错误原因 签名失败 参数格式校验错误 |
# 以下字段在retCode和resCode都为SUCCESS的时候有返回
字段名 | 变量名 | 必填 | 类型 | 示例值 | 描述 |
---|---|---|---|---|---|
支付订单号 | payOrderId | 是 | String | 支付订单号 | |
支付参数 | payParams | 是 | Array | 小程序调用支付需要的参数 | |
签名 | sign | 是 | String | 签名值 |
源码示例
Utility.php,createorder.php,notify.php
<?php
class Utility
{
public static function request($url, $params)
{
$ch = curl_init();
$this_header = array("content-type: application/x-www-form-urlencoded;charset=UTF-8");
curl_setopt($ch, CURLOPT_HTTPHEADER, $this_header);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
curl_setopt($ch, CURLOPT_TIMEOUT, 30);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
$output = curl_exec($ch);
curl_close($ch);
return $output;
}
public static function real_ip()
{
static $realip = NULL;
if ($realip !== NULL) {
return $realip;
}
if (isset($_SERVER)) {
if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
/* Take the first non-unknown valid IP string in X-Forwarded-For */
foreach ($arr AS $ip) {
$ip = trim($ip);
if ($ip != 'unknown') {
$realip = $ip;
break;
}
}
} elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
$realip = $_SERVER['HTTP_CLIENT_IP'];
} else {
if (isset($_SERVER['REMOTE_ADDR'])) {
$realip = $_SERVER['REMOTE_ADDR'];
} else {
$realip = '0.0.0.0';
}
}
} else {
if (getenv('HTTP_X_FORWARDED_FOR')) {
$realip = getenv('HTTP_X_FORWARDED_FOR');
} elseif (getenv('HTTP_CLIENT_IP')) {
$realip = getenv('HTTP_CLIENT_IP');
} else {
$realip = getenv('REMOTE_ADDR');
}
}
preg_match("/[\d\.]{7,15}/", $realip, $onlineip);
$realip = !empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0';
return $realip;
}
/** Signature string
*$prestr: Strings to be signed
*return: Signature result
*/
public static function md5sign($prestr, $sign_type)
{
$sign = '';
if ($sign_type == 'MD5') {
$sign = strtoupper(md5($prestr));//All uppercase letters
} else {
die("The signature method " . $sign_type . " is not supported at this time");
}
return $sign;
}
/**
*Put all the elements of the array into a string with the "&" character according to the pattern of "parameter = parameter value"
*$array: array to be stitched
*return: string after stitching completed
*/
public static function create_linkstring($array)
{
$arg = "";
foreach ($array as $k => $v) {
if ($v !== '') {
$arg .= $k . '=' . $v . '&';
}
}
$arg = substr($arg, 0, strlen($arg) - 1); //Remove the last & character
return $arg;
}
public static function build_mysign($sort_array, $key, $sign_type = "MD5")
{
$prestr = self::create_linkstring($sort_array);
$prestr = $prestr . "&key=" . $key;
//Connect the stitched string directly to the security check code
$mysgin = self::md5sign($prestr, $sign_type);
//Sign the final string to get the signature result
return $mysgin;
}
/**Sort array
*$array: array before sorting
*return: sorted array
*/
public static function arg_sort($array)
{
ksort($array, SORT_NATURAL | SORT_FLAG_CASE);
reset($array);
return $array;
}
}
<?php
require_once('Utility.php');
$openid = ''; //Get openid using the interface provided by WeChat. See detail: https://developers.weixin.qq.com/miniprogram/dev/api/open-api/login/wx.login.html
$merchant_id = $_POST['merchantid'];
$merchant_key = $_POST['merchantKey'];
$url = 'https://api.iotpaycloud.com/v1/create_order';
$order_amount = $_POST['orderamount'];
$order_sn = $_SERVER['REQUEST_TIME'];
$Utility = new Utility();
$ip = $Utility->real_ip();
$notifyUrl = 'https://develop.iotpay.ca/newdemo/mini/notifyy.php?cc=00000';
$subject = 'test';
$body = 'paytest';
$sceneInfo = '{"openId":"' . $openid . '","type":"minipay","appId":"xxxxxxxxx"}';
$arr = array(
'mchId' => $merchant_id,
'mchOrderNo' => $order_sn,
'channelId' => 'WX_JSAPI',
'currency' => 'CAD',
'amount' => intval($order_amount * 100),
'clientIp' => $ip,
'notifyUrl' => $notifyUrl,
'subject' => $subject,
'body' => $body,
'param1' => '',
'param2' => '',
'extra' => $sceneInfo
);
$sort_array = $Utility->arg_sort($arr);
$arr['sign'] = $Utility->build_mysign($sort_array, $merchant_key, "MD5");//build sign
$param = 'params=' . json_encode($arr);
$outputparams = "Param: " . $param . '<br/>';
$resBody = $Utility->request($url, $param);
$res = json_decode($resBody, true);
if ($res['success'] == true) {
return $res;
} else {
$resarr = array(0, 'error!' . $res['retMsg'] . $res['errCodeDes']);
return $resarr[1];
}
?>
<?php
file_put_contents("./log.txt", date("Y/m/d") . " " . date("h:i:sa") . " " . "Notify" . " " . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] . "\r\n", FILE_APPEND);
//Complete the system payment transaction process, such as: change the order payment status to paid
return "success";
?>
支付成功截图,传入了0.10CAD加币,支付的时候,根据最新汇率,转换为人民币支付。