'https://open-sitprod-sg.alipay.com', // 万里汇API测试域名,测试时需要把ip发给万里汇技术加白才能开发测试 'is_sandbox' => 0, // 是否沙箱环境,true为沙箱环境,false为正式环境 'ClientID' => '3J5Y8Y382Y3K3105035', //商户id 'CustomerId' => '2120120007146804', //开发者中心customer id 'MID' => '2120120235023340', //门户帐号MID 'CertificationType' => 'RSA2', //商户密钥 'publicKey' => 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiBMwCt/FA7NlSX0x0oYaxgAgbJy61K5MuvsxBNm7QvOzKNcC17kxoVh17gl1jKmZt+OVaWyzzxxg1P1KBtJvdIWRvt87XD31uYRe75F6NTWi0Okc6mJ0TgHYaZX25eufWiIDzR+rsyolaL3F+INfoXvIbygP8YG/wxdYqssRiUq546j2vlIIgmY9LpByEJwQcLEzaJqcw1lpfoogOLBa/opRVn5FavVaI58gHMqWCcc9LIohrqywyZehv6bV/1h0cZ1MN/7nnCF1S16iAZqL1Tqgo+RMKDzJ2zvRyMSl+N8ZXcmWVDalreaV4+mi8rZBBooJ4mEmXEFKHIB09+ALwQIDAQAB', //公钥 'privateKey' => 'MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCIEzAK38UDs2VJfTHShhrGACBsnLrUrky6+zEE2btC87Mo1wLXuTGhWHXuCXWMqZm345VpbLPPHGDU/UoG0m90hZG+3ztcPfW5hF7vkXo1NaLQ6RzqYnROAdhplfbl659aIgPNH6uzKiVovcX4g1+he8hvKA/xgb/DF1iqyxGJSrnjqPa+UgiCZj0ukHIQnBBwsTNompzDWWl+iiA4sFr+ilFWfkVq9VojnyAcypYJxz0siiGurLDJl6G/ptX/WHRxnUw3/uecIXVLXqIBmovVOqCj5EwoPMnbO9HIxKX43xldyZZUNqWt5pXj6aLytkEGigniYSZcQUocgHT34AvBAgMBAAECggEAJKe2i1dYBPUwVamJ4EILuEaUdW2KznvdY4kC3WGhlhl7q4av11ily+a+bc7SgX+2TtjZiLqlfScR1o4cgNXy/Bp29km//csbBExqHnK7ztWR9GC3T1QSLGlG2Lpy9eCQ3oDHMVxUrkCuLxbf21/YRPHJPlg2Y0ImW/FQC0IEiUzZUr5Owg7zNzDYcyjt1A0I9w2GCxgaZDxxoNE/AwD5cp0dc3+LT/QKdIVY/hxQZ3BlE541pk5LsLQN5639DyivQx4LouTTu5LaYOdd9EW/f/9YxUOnYwBA2A1Yd/OVJhyuAI8fV31hp+vFNlcRKnGQg5I69L24E+LKUmOuC/d4AQKBgQC8rNzleFiSyxgT/oKUk7RNjvBnbmP2ADiWeAsAxWo+nmDcrSj1QxJ/SdQ5r30An0onaZ3R2kD1Oz7t4s/H+yFNhA6/ZEWe8zAxYqGBIgCoNpDPgY382eF5CJpea9zXSKxv5XuIlFbtpNh1HBBEp2uUKjSx9448fcEzn/SogMeCIQKBgQC4oWJzHtrm/toojLIAczTGkFZuSs7GIyuk3XI4L3BF6ZCdV57SPJpYGhe7twk3+bBEE8pyvZjcFOtMaqk4kxyUh3N6+ixw/uy2cPbqs/yOlv6bgC5kyXmf/lzh7a6vxtJnJ1Cxvxv/TZ/CYLbVjp+jEhAqi0+NTPwvHvxgumqVoQKBgBDyujkGsXYmNjh9kT9FcVnSMDgqS2JqrKqfh+V+1kdftLW9/ELjzoKOoDi6UdE/fcrCiwGxyEn/E20NBbsiDODIrwZ0PGjF0ZtuD7Ho2wRBOorZSWbgL4fOxQccS08vYQYAKDOhl5lrSGJkrfVs0JYToH4oDafTaAp6IOEOCF3hAoGBAI5AWZgVB9e+N9vSOzs5iEoM32ru3E2wv2mw7NX5Rum2wSNZZRbadpi20d5hcgrcqEBrdynchq/atkgUTfk272hIzGLN6fvNjhgrBTNkJYy/LcAljJk+2iS5WFsCQ/tOlsG/et7YPfwAlLyww23bC4ga3LXKzCo0TIEJwK3OM1zBAoGBAICf031sETlA3ICd1oynfFuLDIp7erRxZgWmh2fgASY1a98LR7nvm4F7XgUHeinILIiHLrdaQtS439DydEC8wf2Q+GlcQqyv048He+8vgjNoz7CP9kqYyIex567K/MJTrRkh3KHMSyX1oaSXrgvW4/6SYvCX2hlxXeOnLJie6LVe', //商户私钥privateKey ]; // ISO 4217标准货币最小单位(小数点位数) private static $currencyUnits = [ 'AUD' => 2, 'BDT' => 2, 'BRL' => 2, 'CAD' => 2, 'CLP' => 0, 'CNY' => 2, 'EUR' => 2, 'GBP' => 2, 'HKD' => 2, 'IDR' => 2, 'JPY' => 0, 'KRW' => 0, 'MXN' => 2, 'MYR' => 2, 'NZD' => 2, 'PEN' => 2, 'PHP' => 2, 'PKR' => 2, 'PLN' => 2, 'SGD' => 2, 'THB' => 2, 'TWD' => 2, 'USD' => 2, 'VND' => 0 ]; //获取货币最小单位对应的值 private function getCurrenyMoneytoMinorUnit(float $amount, string $currency): int { $currency = strtoupper($currency); if (!isset(self::$currencyUnits[$currency])) { return "Unsupported currency: {$currency}"; } $decimals = self::$currencyUnits[$currency]; return (int)round($amount * pow(10, $decimals)); } //将最小单位值转换回标准金额 private function getCurrenyMoneyfromMinorUnit(int $minorValue, string $currency): float { $currency = strtoupper($currency); if (!isset(self::$currencyUnits[$currency])) { return "Unsupported currency: {$currency}"; } $decimals = self::$currencyUnits[$currency]; return $minorValue / pow(10, $decimals); } public function index() { // 从表单获取的参数(模拟$_POST) //获取请求时间() 为 2022-04-28T12:31:30+08:00,时间遵循ISO 8601标准 $requestTime = date('Y-m-d\TH:i:sP'); $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $post_data = ["paymentId" => "202205311234234"]; // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; $publicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->config['publicKey'], 64, "\n", true) . "\n-----END PUBLIC KEY-----"; $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/inquiryPayOrder'; // 请求API路径 $bodyData = json_encode($post_data); // 请求体JSON字符串 $params = [ 'clientId' => $clientId, //'customerId' => $this->config['CustomerId'], 'requestTime' => $requestTime, 'httpMethod' => $httpMethod, 'api' => $api_url, 'bodyData' => $bodyData, 'privkey' => $privateKey, ]; $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); // 验证签名示例(需要公钥) $isValid = $this->verifySignature( $signatureBody, $signature, $publicKey ); $params['signature'] = $signature; $params['isValid'] = $isValid; $res = [ 'isValid' => $isValid, //'signature' => $signature, ]; return dhkSuccess($res); //echo $signature; } public function indexjj() { // 从表单获取的参数(模拟$_POST) //获取请求时间() 为 2022-04-28T12:31:30+08:00,时间遵循ISO 8601标准 $requestTime = date('Y-m-d\TH:i:sP'); $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $post_data = [ "inquiryRateConditionList" => [ [ "sellCurrency" => "USD", "buyCurrency" => "CNY" ], [ "sellCurrency" => "USD", "buyCurrency" => "GBP" ] ] ]; // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; $publicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap($this->config['publicKey'], 64, "\n", true) . "\n-----END PUBLIC KEY-----"; $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/fund/inquiryRate'; // 请求API路径 $bodyData = json_encode($post_data); // 请求体JSON字符串 $params = [ 'clientId' => $clientId, //'customerId' => $this->config['CustomerId'], 'requestTime' => $requestTime, 'httpMethod' => $httpMethod, 'api' => $api_url, 'bodyData' => $bodyData, 'privkey' => $privateKey, ]; $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); // 验证签名示例(需要公钥) $isValid = $this->verifySignature( $signatureBody, $signature, $publicKey ); $params['signature'] = $signature; $params['isValid'] = $isValid; $res = [ 'isValid' => $isValid, 'signature' => $signature, ]; return dhkSuccess($params); //echo $signature; } //发起第一个请求---获取 //沙箱测试通过,线上测试未通过 public function getFirst() { $post_data = [ "inquiryRateConditionList" => [ [ "sellCurrency" => "USD", "buyCurrency" => "CNY" ], [ "sellCurrency" => "USD", "buyCurrency" => "GBP" ] ] ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/fund/inquiryRate'; //支付完成后,集成商可以使用此接口来查询支付结果。 $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); $post_url = $this->config['domain'] . $api_url; $header = []; $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $header['client-id'] = $clientId; $header['request-time'] = $requestTime; $header['Content-Type'] = 'application/json'; $header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature; $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $res = $dhkhttp->dhkpost($post_url, $post_data, $header); return dhkSuccess($res); } //用户开通--构建重定向URL--暂未开放 public function goLoginAuth() { //1. 构建待签名字符串,按照以下格式拼接:顺序不能变,每个参数之间用&符号连接。 //格式:clientId=clientId&redirectUrl=redirectUrl&referenceCustomerId=referenceCustomerId&storeUrl=storeUrl&storeName=storeName¤cy=currency&requestId=requestId $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $redirectUrl = "http://zhc.develop.dahuiku.com/home/testpay/getAuth"; // 授权成功后的回调地址 $referenceCustomerId = "dhk-2"; //由本站卖家用户的唯一ID $storeUrl = "http://zhc.develop.dahuiku.com/seller/index/index.html?sid=2"; //本站卖家店铺地址 $storeName = "一火TEST"; //本站卖家店铺名称 $currency = "CNY"; //代表RA账户的币种 $requestId = "dhk" . Date('YmdHis') . uniqid(); //集成商指定给每个跳转URL的唯一请求ID $post_data = [ "clientId" => $clientId, "redirectUrl" => $redirectUrl, "referenceCustomerId" => $referenceCustomerId, "storeUrl" => $storeUrl, "storeName" => $storeName, "currency" => $currency, "requestId" => $requestId, ]; //格式化成get请求字符串 $signatureBody = http_build_query($post_data); //$signatureBody = "clientId={$clientId}&redirectUrl={$redirectUrl}&referenceCustomerId={$referenceCustomerId}&storeUrl={$storeUrl}&storeName={$storeName}¤cy={$currency}&requestId={$requestId}"; $raw = "clientId={$clientId}&redirectUrl=" . urlencode($redirectUrl) . "&referenceCustomerId={$referenceCustomerId}&storeUrl=" . urlencode($storeUrl) . "&storeName={$storeName}¤cy={$currency}&requestId={$requestId}"; //2、字符串编码使用 base64 编码和使用 urlencode编码 //$signatureBody = base64_encode($getRaw); //对字符串进行base64编码 //$signatureBody = urlencode($signatureBody); //对字符串进行URL编码 //3、使用商户私钥对编码后的字符串进行签名 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; $signature = $this->generateSignature($signatureBody, $privateKey); //对字符串进行签名 //4、给URL加签和把其中的url进行编码 $GET_DATA = "clientId={$clientId}&redirectUrl=" . urlencode($redirectUrl) . "&referenceCustomerId={$referenceCustomerId}&storeUrl=" . urlencode($storeUrl) . "&storeName={$storeName}¤cy={$currency}&requestId={$requestId}"; $ss_url = "https://portal.worldfirst.com/enterprise/auth?" . $signatureBody . "&signature=" . $signature; $res = [ 'url' => $ss_url, 'raw' => $raw, 'signatureBody' => $signatureBody ]; echo_dhklog($res, '构建重定向URL:', 'worldfirst_pay'); return dhkSuccess($res); //5、重定向到URL return redirect($ss_url); } //接收授权 public function getAuth() { $params = Request::param(); echo_dhklog($params, '授权回调data:', 'worldfirst_pay'); return dhkSuccess($params, '接收授权成功,等待处理....'); } //查询支付状态http://zhc.test.com/home/testpay/query?pay_code=202504171234234 public function query() { $params = Request::param(); $payToRequestId = $params['pay_code'] ?? ''; //商户生成的支付单号 $payToId = $params['payToId'] ?? ''; //万里汇生成的支付单号 if (!$payToRequestId and !$payToId) { return dhkMsg('支付单号不能为空'); } $post_data = []; if ($payToRequestId) { $payToRequestIds = [$payToRequestId]; $post_data['payToRequestIds'] = $payToRequestIds; } if ($payToId) { $payToIds = [$payToId]; $post_data['payToIds'] = $payToIds; } $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/inquiryPayOrder'; //支付完成后,集成商可以使用此接口来查询支付结果。 $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); $post_url = $this->config['domain'] . $api_url; $header = []; $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $header['client-id'] = $clientId; $header['request-time'] = $requestTime; $header['Content-Type'] = 'application/json'; $header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature; $dhkhttp = new \app\common\toole\Dhkhttp(); $res = $dhkhttp->dhkpost($post_url, $post_data, $header); return dhkSuccess($res); } public function notify() { $params = Request::param(); echo_dhklog($params, '支付通知data:', 'worldfirst_pay'); $headers = Request::header(); echo_dhklog($headers, '支付通知header:', 'worldfirst_pay'); $requestTime = $headers['request-time'] ?? ''; //请求时间 $signature = $headers['signature'] ?? ''; //签名 //algorithm=RSA256,keyVersion=1,signature=IHZfFMPNQITqmz%2FDZTlm6DEfm6yfR3NtK0LkONscZxZLqOuCa5b%2FDyLGqwZaSrGIQeFFNnGS5EgqRtFFdOmBSuSSiwK%2BjvhnIE6qHP7xr%2BjBpjFFztTOyyniGJdN5HlT8UE2wONjPIsIMh8koXa6Kb8uh1ScnCGbTzY8ogfihupFXJt%2B1%2BHPYno9483cVyA2l9UOYb6ai6SWgAxnJJUWi%2BkBQLXp%2FzvRG6SmDETbZ8MpMM2gUTbRGB4p4eSqVcX6KgwVyLSgrzAGekPv6dkZOH5zulHCv%2FmMXdO3%2FWmQn%2FX2rS1unS9yilDJbzDW86XwUf46UD2qgxkFGi6UPWaTfw%3D%3D //从$signature中提取signature=后面的内容 $signature = str_replace('algorithm=RSA256,keyVersion=1,signature=', '', $signature); echo_dhklog($signature, 'HEADER签名', 'worldfirst_pay'); $clientId = $headers['client-id'] ?? ''; $httpMethod = 'POST'; $api_url = '/home/testpay/notify'; // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; $res = ["result" => ["resultStatus" => "S", "resultCode" => "SUCCESS", "resultMessage" => "success"]]; $signatureBody = $this->getSignatureBody($params, $httpMethod, $api_url, $requestTime); // 生成签名 $signature_new = $this->generateSignature($signatureBody, $privateKey); if ($signature_new != $signature) { echo_dhklog($signature_new, '签名不匹配', 'worldfirst_pay'); } else { echo_dhklog('验证通过', '签名匹配', 'worldfirst_pay'); } //返回响应头 header('Content-Type: application/json'); header('client-id: ' . $clientId); header('request-time: ' . $requestTime); header('signature: algorithm=RSA256,keyVersion=1,signature=' . $signature_new); return json($res); } //1. 构造待签名字符串(与JavaScript逻辑完全一致) public function getSignatureBody($post_data = [], $httpMethod = 'POST', $api_url = '', $requestTime = '') { $bodyData = json_encode($post_data); $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $signatureBody = sprintf( "%s %s\n%s.%s.%s", strtoupper($httpMethod), $api_url, $clientId, $requestTime, $bodyData ); return $signatureBody; } /** * 生成签名 * @param string $clientId 商户ID * @param string $requestTime 请求时间戳 * @param string $httpMethod HTTP方法(GET/POST等) * @param string $api 请求API路径 * @param string $bodyData 请求体JSON字符串 * @param string $privateKey 私钥(PEM格式) * @return string 返回URL编码后的签名 */ public static function generateSignature($signatureBody, $privateKey): string { // 2. 使用私钥进行SHA256签名 $signature = ''; if (!openssl_sign($signatureBody, $signature, $privateKey, OPENSSL_ALGO_SHA256)) { // 输出错误信息 echo_dhklog(openssl_error_string(), 'OpenSSL错误', 'worldfirst_pay'); return ''; } // 3. Base64编码签名 $ss = base64_encode($signature); echo_dhklog($ss, '签名', 'worldfirst_pay'); // 4. URL编码签名,非必要 $ss = urlencode($ss); return $ss; } /** * 验证签名(可选) */ public static function verifySignature( string $plainText, string $signature, string $publicKey ): bool { $signature = base64_decode(urldecode($signature)); return (bool)openssl_verify( $plainText, $signature, $publicKey, OPENSSL_ALGO_SHA256 ); } //账单查询API--列表ok public function inquiryStatementList() { //uzzyName字段取值为空时,startTime 和 endTime 计算的账单时长不得超过3个月(100天)。 $nowdate = date('Y-m-d\TH:i:sP'); $nowtime = time(); $starttime = strtotime('-3 month', $nowtime); //3个月前时间戳 $endtime = strtotime('-1 month', $nowtime); //现在时间戳 $post_data = [ "startTime" => date('Y-m-d\TH:i:sP', $starttime), //开始时间,格式为ISO 8601 "endTime" => date('Y-m-d\TH:i:sP', $endtime), //结束时间,格式为ISO 8601 "pageSize" => 10, //每页大小,最大为100 "pageNumber" => 1, //页码,从1开始 "transactionTypeList" => [], //交易类型列表,可选,不传则查询所有类型 "currencyList" => [], //币种列表,可选,不传则查询所有币种 "fuzzyName" => "" //模糊查询字段,可选,不传则不进行模糊查询 ]; $requestTime = $nowdate; $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/account/inquiryStatementList'; //支付完成后,集成商可以使用此接口来查询支付结果。 $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); $post_url = $this->config['domain'] . $api_url; $header = []; $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $header['client-id'] = $clientId; $header['request-time'] = $requestTime; $header['Content-Type'] = 'application/json'; $header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature; $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $totalCount = $apidata['totalCount']; //总条数 if ($totalCount == 0) { return dhkMsg('暂无账单'); } $totalPageNumber = $apidata['totalPageNumber']; //总页数 $currentPageNumber = $apidata['currentPageNumber']; //当前页码 $list = $apidata['statementList']; //账单列表 $res = [ 'totalCount' => $totalCount, //总条数 'totalPageNumber' => $totalPageNumber, //总页数 'currentPageNumber' => $currentPageNumber, //当前页码 'list' => $list, //账单列表 ]; return dhkSuccess($res); } //帐单详情API--ok public function inquiryStatementDetail() { $bno = Request::param('bno'); $post_data = [ "accountingBizNo" => $bno //万里汇账单动账流水单号,由万里汇生成,用于查询账单详情 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/account/inquiryStatementDetail'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } return dhkSuccess($apidata); } //余额查询API-- public function inquiryBalance() { $post_data = [ "currencyList" => [], //币种列表,为 ISO 4217 标准规定的三位字母货币代码,为空时,则会响应所有币种的余额信息 "balanceTypes" => [] //余额类型列表,可选,不传则查询所有类型,当该字段为空时,NORMAL_BALANCE为默认取值。 //NORMAL_BALANCE: 普通余额类型(即电商余额类型)。(默认);SAME_NAME_TOP_UP_BALANCE: 同名充值余额类型。 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/account/inquiryBalance'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $accountBalances = $apidata['accountBalances']; //用户的账户信息列表,包括账号、账户币种、账户余额等信息。 //accountNo万里汇定义的唯一账户ID return dhkSuccess($apidata); } //获取万里汇主账号和子账号的信息 public function inquiryAccountInfo() { $post_data = [ "pageSize" => 20, //每页包含的条目数 "pageNumber" => 1 //当前页码 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/user/inquirySubuser'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $totalCount = $apidata['totalCount']; //总条数 if ($totalCount == 0) { return dhkMsg('暂无账单'); } $totalPageNumber = $apidata['totalPageNumber']; //总页数 $currentPageNumber = $apidata['currentPageNumber']; //当前页码 $primaryUserInformation = $apidata['primaryUserInformation']; //主账号信息 $userInformations = $apidata['userInformations']; //子账号信息 $list = $apidata['statementList']; //账单列表 $res = [ 'totalCount' => $totalCount, //总条数 'totalPageNumber' => $totalPageNumber, //总页数 'currentPageNumber' => $currentPageNumber, //当前页码 'primaryUserInformation' => $primaryUserInformation, //主账号信息 'userInformations' => $userInformations, //子账号信息 ]; return dhkSuccess($apidata); } //店铺管理API--获取店铺信息以及店铺关联账号的信息 public function inquiryStore() { $post_data = [ "pageSize" => 100, //每页包含的条目数 "pageNumber" => 1 //当前页码 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/store/inquiryStore'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $totalCount = $apidata['totalCount']; //总条数 if ($totalCount == 0) { return dhkMsg('暂无账单'); } $totalPageNumber = $apidata['totalPageNumber']; //总页数 $currentPageNumber = $apidata['currentPageNumber']; //当前页码 $storeInformation = $apidata['storeInformation']; //storeInformation $res = [ 'totalCount' => $totalCount, //总条数 'totalPageNumber' => $totalPageNumber, //总页数 'currentPageNumber' => $currentPageNumber, //当前页码 'storeInformation' => $storeInformation, ]; return dhkSuccess($apidata); } //结汇额度查询API--帐户管理 public function inquiryAvailableQuota() { $post_data = [ "quotaAccumulationMethod" => "USER_ID", //结汇额度的累计方式 //可取值如下:USER_ID :根据申报主体UID(即已入驻万里汇的用户ID)累积申报额度。标识传入交易卖家的用户ID //RECEIVING_ACCOUNT :根据收款账户(RA)累计申报额度。标识传入交易卖家的收款账户(RA)号 //VIRTUAL_ACCOUNT:根据虚拟账户(VA)累计申报额度。标识传入交易卖家的虚拟账户(VA)号 //BENEFICIARY:根据收款人(即未入驻万里汇的外部平台用户)累计申报额度。标识传入外部平台的用户ID "quotaAccumulationId" => "2193110014766029", //结汇额度累计方式的标识 "currency" => 'USD', //结汇额度的币种。 币种必须满足ISO 4217 标准,比如 "USD" 。 //"tradeType" => "ALL", //贸易类型。可取值如下:GOODS:货物贸易,SERVICE:服务贸易。当 quotaAccumulationMethod = BENEFICIARY时,此字段为必传。 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/account/inquiryAvailableQuota'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $availableQuota = $apidata['availableQuota']; //可申报的结汇额度。 return dhkSuccess($apidata); } //独立站平台标识INDEPENDENT_SITE //上传交易信息累计额度API--未对接 public function uploadTransactionInfo() { $post_data = [ "quotaAccumulationMethod" => "USER_ID", //结汇额度的累计方式 //可取值如下:USER_ID :根据申报主体UID(即已入驻万里汇的用户ID)累积申报额度。标识传入交易卖家的用户ID //RECEIVING_ACCOUNT :根据收款账户(RA)累计申报额度。标识传入交易卖家的收款账户(RA)号 //VIRTUAL_ACCOUNT:根据虚拟账户(VA)累计申报额度。标识传入交易卖家的虚拟账户(VA)号 //BENEFICIARY:根据收款人(即未入驻万里汇的外部平台用户)累计申报额度。标识传入外部平台的用户ID "quotaAccumulationId" => "2193110014766029", //结汇额度累计方式的标识 "currency" => 'USD', //结汇额度的币种。 币种必须满足ISO 4217 标准,比如 "USD" 。 //"tradeType" => "ALL", //贸易类型。可取值如下:GOODS:货物贸易,SERVICE:服务贸易。当 quotaAccumulationMethod = BENEFICIARY时,此字段为必传。 ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/account/submitTradeOrder'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $availableQuota = $apidata['availableQuota']; //可申报的结汇额度。 return dhkSuccess($apidata); } //获取转账相关信息API--转帐前1 public function fund_consultPayout() { //转帐金额 $transferFromAmount = $this->getCurrenyMoneytoMinorUnit(100, 'USD'); $post_data = [ "transferFromDetail" => [ "transferFromAmount" => [ "currency" => "USD", "value" => $transferFromAmount, ], ], //转账业务类型码。当 transferToDetail . transferToAmount . currency = CNY 时,此字段为必传。 //THIRD_PARTY_PAYOUT:转账到第三方卡。第三方卡包括企业卡和个人卡。SAME_NAME_PAYOUT:提现到同名卡 "businessSceneCode" => "THIRD_PARTY_PAYOUT", "transferToDetail" => [ "transferToMethod" => [ "paymentMethodMetaData" => [ "bankLocalName" => "xxxxxxx", "bankCountryCode" => "CN", "bankAccountLocalName" => "xxxxxxx", "beneficiaryType" => "THIRD_PARTY_PERSONAL_BANK_ACCOUNT", "bankAccountNo" => "xxxxxxxxxxxx" ], "paymentMethodType" => "BANK_ACCOUNT_DETAIL" ], "transferToAmount" => [ "currency" => "CNY", "value" => 100, ] ] ]; $requestTime = date('Y-m-d\TH:i:sP'); $httpMethod = 'POST'; // 请求方法(GET/POST等) $api_url = '/amsin/api/v1/business/fund/consultPayout'; //支付完成后,集成商可以使用此接口来查询支付结果。 $post_url = $this->config['domain'] . $api_url; $header = $this->getHeaderData($post_data, $httpMethod, $api_url, $requestTime); $dhkhttp = new \app\common\toole\Dhkhttp(); echo_dhklog($api_url, '请求地址:', 'worldfirst_pay'); $apidata = $dhkhttp->dhkpost($post_url, $post_data, $header); if ($apidata['http_code'] != 200) { $msg = $apidata['msg'] ?? '接口请求失败'; return dhkMsg($msg); } $api_result = $apidata['result']; if ($api_result['resultStatus'] != 'S') { return dhkMsg($api_result['resultMessage']); } $availableQuota = $apidata['availableQuota']; //可申报的结汇额度。 return dhkSuccess($apidata); } //获取请求头及签名 public function getHeaderData($post_data = [], $httpMethod = 'POST', $api_url = '', $requestTime = '') { if ($requestTime == '') { $requestTime = date('Y-m-d\TH:i:sP'); } $signatureBody = $this->getSignatureBody($post_data, $httpMethod, $api_url, $requestTime); // 包裹私钥 $privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap($this->config['privateKey'], 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----"; // 生成签名 $signature = $this->generateSignature($signatureBody, $privateKey); $post_url = $this->config['domain'] . $api_url; $header = []; $clientId = $this->config['is_sandbox'] == 1 ? 'SANDBOX_' . $this->config['ClientID'] : $this->config['ClientID']; $header['client-id'] = $clientId; $header['request-time'] = $requestTime; $header['Content-Type'] = 'application/json'; $header['signature'] = 'algorithm=RSA256,keyVersion=1,signature=' . $signature; return $header; } }