以下是自己写的调用支付和退款和查询订单
class ICBCRefundBizContentParameter {
// 商户、部门编号
public $mer_id;
// 退货流水号,商户系统生成的退款编号,每次部分退款需生成不同的退款编号
public $outtrx_serial_no;
// 商户订单号 ,商户订单号或工行订单号必输其一
public $out_trade_no;
// 退款金额,单位:分
public $ret_total_amt;
// 交易币种,目前只支持人民币,送001
public $trnsc_ccy;
// 商户在工行API平台的APPID
public $icbc_appid;
// 商户清算账号,暂不使用
public $mer_acct;
/**
* ICBCRefundBizContentParameter constructor.
* @param string $refundId
* @param string $orderId
* @param string $money
*/
public function __construct($subMerchantId, $refundId, $orderId, $money){
$this->mer_id = $subMerchantId;
$this->outtrx_serial_no = $refundId;
$this->out_trade_no = $orderId;
$this->ret_total_amt = $money;
$this->trnsc_ccy = "001";
$this->icbc_appid = "";
// $this->mer_acct = "";
}
}
<?php
class ICBCPayBizContentParameter {
// 支付方式,9-微信;10-支付宝
public $pay_mode;
// 收单接入方式,5-APP,7-微信公众号,8-支付宝生活号,9-微信小程序
public $access_type;
// 交易日期时间,格式为yyyy-MM-dd’T’HH:mm:ss
public $orig_date_time;
// 设备号
public $decive_info;
// 商品描述,商品描述交易字段格式根据不同的应用场景按照以下格式:1)PC网站:传入浏览器打开的网站主页title名-实际商品名称 ;2)公众号:传入公众号名称-实际商品名称;3)H5:传入浏览器打开的移动网页的主页title名-实际商品名称;4)线下门店:门店品牌名-城市分店名-实际商品名称;5)APP:传入应用市场上的APP名字-实际商品名称
public $body;
// 订单号
public $out_trade_no;
// 订单金额
public $total_fee;
// 支付币种 人名币
public $fee_type = "001";
// 用户端IP
public $spbill_create_ip;
// 商户代码
public $mer_id;
// 收单协议编号
public $mer_prtcl_no;
// 商户账号,目前暂不支持
public $mer_acct;
// 交易过期时间 支付宝和微信使用
public $expire_time;
// 附加数据,在查询API和支付通知中原样返回,该字段主要用于商户携带订单的自定义数据
public $attach;
// 商户在微信开放平台注册的APPID,支付方式为微信时不能为空
public $shop_appid;
// 商户在工行API平台的APPID
public $icbc_appid;
// 回调通知地址
public $mer_url;
// 通知类型 HS为发送 AG为不发送
public $notify_type = "HS";
/**
* ICBCPayBizContentParameter constructor.
* @param $subMerchantId 商户号
* @param string $orderId 订单id
* @param string $payType 支付类型 9-微信;10-支付宝
* @param string $mobileDecive 手机设备号
* @param string $money 订单金额 (分)
* @param string $attach 附加数据
* @param string $clientIp 客户端ip
* @param string $notifyUrl 回调地址
*/
public function __construct($subMerchantId, $mer_prtcl_no, $orderId, $payType, $mobileDecive,$money,$attach,$clientIp,$notifyUrl){
$this->spbill_create_ip = $clientIp;
$this->pay_mode = $payType;
$this->decive_info = $mobileDecive;
$this->attach = $attach;
$this->out_trade_no = $orderId;
$this->total_fee = $money;
$this->icbc_appid = "";
$this->mer_url = $notifyUrl;
// $this->mer_acct = $subMerchantId;
$this->mer_id = $subMerchantId;
$this->mer_prtcl_no = $mer_prtcl_no;
$this->orig_date_time = substr(date("c",time()),0,strpos(date("c",time()),"+"));
$this->expire_time = "180";//秒
$this->body = "";
$this->access_type = "5";
if ($payType == 9) {
$this->shop_appid = C("icbc_weChat_shopAppID");
}
}
}
<?php
class ICBCEPayBizContentParameter {
// 工行API平台的APPID
public $icbc_appid;
// 交易日期时间,格式为:YYYYMMDDHHmmss,要求在银行系统当前时间的前1小时和后12小时范围内,否则判定交易时间非法\
public $order_date;
// 商户订单号
public $order_id;
// 订单金额,单位分
public $amount;
// 分期付款期数,1、3、6、9、12、18、24;1代表全额付款,必须为以上述值,否则订单校验不通过
public $installment_times;
// 交易币种,目前工行只支持使用人民币(001)支付
public $cur_type;
// 商户编号
public $mer_id;
// 收单协议编号
public $mer_prtcl_no;
// 商户账号,商户入账账号,只能交易时指定。(商户付给银行手续费的账户,可以在开户的时候指定,也可以用交易指定方式;用交易指定方式则使用此商户账号)
public $mer_acct;
// 通知商户URL,必须合法的URL,交易结束,银行使用HTTP协议POST方式向此地址发送通知信息;目前只支持80端口
public $merURL;
// 支付成功回显页面,支付成功后,跳转至该页面显示
public $return_url;
// 返回商户变量, 工行给商户发送商户通知时会原样返回,可参考响应报文中attach字段(可理解为附加参数)
public $mer_var;
// 只走H5标志,0-不限制,1-只走H5,默认0。商户如需嵌入APP内使用,h5_flag只能送1
public $h5_flag;
/**
* ICBCEPayBizContentParameter constructor.
* @param $subMerchantId 商户号
* @param string $orderId 订单号
* @param string $money 金额
* @param string $attach 附加字段
* @param boolean $isInApp 是否在app内嵌入 true 是 false 否
* @param string $notifyUrl 回调地址
* @param string $returnUrl 支付完跳转地址
*/
public function __construct($subMerchantId, $mer_prtcl_no, $orderId, $money, $attach, $isInApp, $notifyUrl, $returnUrl){
$this->icbc_appid = "";
$this->order_date = date("YmdHis");
$this->order_id = $orderId;
$this->amount = $money;
$this->installment_times = "1";
$this->cur_type = "001";
$this->mer_id = $subMerchantId;
$this->mer_prtcl_no = $mer_prtcl_no;
// $this->mer_acct = C("icbc_merAcct");
// $this->mer_acct = "";
$this->merURL = $notifyUrl;
$this->return_url = $returnUrl;
$this->mer_var = $attach;
if ($isInApp) {
$this->h5_flag = "1";
}
}
}
<?php
namespace Org\IcbcPhp;
use Exception;
/**
* Class ICBCPay
* 工银支付
*/
class ICBCPay
{
private $client;
private $payType;
/**
* ICBCPay constructor.
* @param string $payType 9 微信 10 支付宝 11 e支付
*/
public function __construct($payType)
{
$this->payType = $payType . "";
if ($payType == "9" || $payType == "10" || !$payType) {
$this->client = new DefaultIcbcClient(C("icbc_app_id"), C("icbc_private_key"), C("icbc_sign_type"), C("icbc_charset"), C("icbc_format"), C("icbc_gateway_public_key"), C("icbc_encryptKey"), C("icbc_encryptType"), "", "");
} elseif ($payType == "11") {
$this->client = new UiIcbcClient(C("icbc_app_id"), C("icbc_private_key"), C("icbc_sign_type"), C("icbc_charset"), C("icbc_format"), C("icbc_gateway_public_key"), C("icbc_encryptKey"), C("icbc_encryptType"), "", "");
}
}
/**
* app 支付宝和微信下单
* 张志强
* 2021-01-12
* @param string $subMerchantId 商户号
* @param string $mer_prtcl_no 协议编号
* @param string $orderId 订单号
* @param string $money 金额
* @param string $decive 设备号
* @param string $attach 附加字段
* @param string $clientIp 设备ip
* @param string $notifyUrl 回调地址
* @return false|string
* @throws Exception
*/
public function appPay($subMerchantId, $mer_prtcl_no, $orderId, $money, $decive, $attach, $clientIp, $notifyUrl)
{
if ($this->payType == 11) {
throw new Exception("请使用e支付的接口");
}
$data = [
'serviceUrl' => 'https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/consumepurchase/V1',
'biz_content' => get_object_vars(new ICBCPayBizContentParameter($subMerchantId, $mer_prtcl_no, $orderId . "", $this->payType, $decive, $money . "", $attach, $clientIp, $notifyUrl)),
'extraParams' => [],
'method' => "POST",
'isNeedEncrypt' => true
];
return $this->client->execute($data, $orderId, "");
}
/**
* e支付 h5
* 张志强
* 2021-01-12
* @param string $subMerchantId 商户号
* @param string $mer_prtcl_no 协议编号
* @param string $orderId string 订单号
* @param string $money string 金额
* @param string $attach string 附加字段
* @param boolean $isInApp bool 是否嵌入app内
* @param string $notifyUrl 回调地址
* @param string $returnUrl 支付完跳转地址
* @return string
* @throws Exception
*/
public function ePay($subMerchantId, $mer_prtcl_no, $orderId, $money, $attach, $isInApp, $notifyUrl, $returnUrl)
{
if ($this->payType != 11) {
throw new Exception("请使用聚合支付的接口");
}
$data = [
'serviceUrl' => 'https://gw.open.icbc.com.cn/ui/cardbusiness/epayh5/ui/consumption/V1',
'biz_content' => get_object_vars(new ICBCEPayBizContentParameter($subMerchantId, $mer_prtcl_no, $orderId . "", $money . "", $attach, $isInApp, $notifyUrl, $returnUrl)),
'extraParams' => [],
'method' => "POST",
'isNeedEncrypt' => true
];
return $this->client->buildPostForm($data, $orderId, "");
}
/**
* 退款
* 张志强
* 2021-01-12
* @param string $subMerchantId 商户编号
* @param string $refundId 自己生成的唯一退款id
* @param string $orderId 订单号
* @param string $money 金额
* @return false|string
* @throws Exception
*/
public function refund($subMerchantId, $refundId, $orderId, $money)
{
// 退款
$data = [
'serviceUrl' => 'https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/merrefund/V1',
'biz_content' => get_object_vars(new ICBCRefundBizContentParameter($subMerchantId, $refundId . "", $orderId . "", $money . "")),
'extraParams' => [],
'method' => "POST",
'isNeedEncrypt' => true
];
return $this->client->execute($data, $orderId, "");
}
// 查询订单
/**
* @param $subMerchantId
* @param $serial_number
* @return false|string
* @throws Exception
*/
public function selectIcbcOrder($subMerchantId, $serial_number)
{
$data = [
'serviceUrl' => 'https://gw.open.icbc.com.cn/api/cardbusiness/aggregatepay/b2c/online/orderqry/V1',
'biz_content' => [
'mer_id' => $subMerchantId,
'out_trade_no' => $serial_number,
'deal_flag' => "0",
'icbc_appid' => C('icbc_app_id')
],
'extraParams' => [],
'method' => "POST",
'isNeedEncrypt' => true
];
return $this->client->execute($data, microtime(), "");
}
}
支付回调
/**
* 工银支付回调
* @throws Exception
*/
public function icbcNotify() {
$file_pointer = fopen(APP_PATH."/Lib/Action".__GROUP__."/aa.txt","a+");
fwrite($file_pointer,"回调开始");
try {
// 获取参数
$responseStr = urldecode(file_get_contents("php://input"));
if (!$responseStr) {
throw new Exception("【".date("Y-m-d H:i:s")."】 参数不能为空\r\n");
}
$response = explode("&",$responseStr);
$responseArr = [];
$sign = "";
foreach ($response as $k => $v) {
if (strstr($v,"=",true) == 'sign') {
$sign = substr(strstr($v,"=",false),1);
} else {
$responseArr[strstr($v,"=",true)] = substr(strstr($v,"=",false),1);
}
}
// 生成待签名字符串
$path = parse_url('域名' +'接口名', PHP_URL_PATH);
$respBizContentStr = WebUtils::buildOrderedSignStr($path,$responseArr);
// 验证签名1
$passed = IcbcSignature::verify($respBizContentStr, $responseArr['sign_type'], C("icbc_gateway_public_key"), $responseArr['charset'], $sign,'');
if (!$passed) {
$responseArr = json_encode($responseArr);
throw new Exception("【".date("Y-m-d H:i:s")."】 icbc sign verify not passed!\r\n订单信息为【{$responseArr}】签名为【{$sign}】\r\n");
}
// 返回业务参数
$bizContent = json_decode($responseArr['biz_content'],true);
$merOrderId = $bizContent['out_trade_no'];
$notify_return_code = $bizContent['return_code'];
// 验证返回消息码是否正确
if ($notify_return_code !== "0") {
return $this->response("-1","error");
}
// 修改unipay_log
$result = M('unionpay_log')->data(['is_valid' => 2])->where(['serial_number'=>$merOrderId])->save();
if ($result === false) {
throw new Exception("【".date("Y-m-d H:i:s")."】 修改unipay_log失败!\r\n订单信息为【{$responseArr}】签名为【{$sign}】\r\n");
}
// 自己的业务逻辑
//return $this->response("0","success");成功响应
//return $this->response("-1","error");失败响应
} catch (Exception $exception) {
fwrite($file_pointer,$exception->getMessage());
return $this->response("-1","error");
}
}
/**
* 工行回调应答
* 张志强
* 2021-07-15
*/
private function response($return_code,$return_msg) {
// 应答
$respBizContent = array(
'return_code' => $return_code,
'return_msg' => $return_msg,
'msg_id' => microtime()
);
$answer['response_biz_content'] = json_encode($respBizContent);
$answer['sign_type'] = C('icbc_sign_type');
$answer['sign'] = IcbcSignature::sign(substr(json_encode($answer),1),C("icbc_sign_type"),C("icbc_private_key"),C("icbc_charset"),'');
return json_encode($answer);
}
强调:
在支付回调签名验证的时候的path不要自己手写,会发生验签不通过,切记要用
$path = parse_url('域名' +'接口名', PHP_URL_PATH);