Dada.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. <?php
  2. namespace common\components\delivery\platform\dada;
  3. class Dada
  4. {
  5. // API 配置常量
  6. const API_VERSION = '1.0';
  7. const FORMAT = 'json';
  8. // 测试环境和生产环境基础 URL
  9. const TEST_BASE_URL = 'https://newopen.qa.imdada.cn';
  10. const PROD_BASE_URL = 'https://newopen.imdada.cn';
  11. protected $baseUrl;
  12. protected $appKey;
  13. protected $appSecret;
  14. protected $sourceId;
  15. protected $shopNo;
  16. /**
  17. * 初始化达达适配器
  18. * 根据运行环境加载对应的配置信息
  19. */
  20. public function __construct($token='', $shopId=0, $sourceId=0)
  21. {
  22. $isProduction = getenv('YII_ENV') == 'production';
  23. if ($isProduction) {
  24. // 生产环境配置
  25. $this->baseUrl = self::PROD_BASE_URL;
  26. $this->appKey = 'dadaf2279d901a5ba40';
  27. $this->appSecret = '828a03677a1c00a3a5b3c59209c4433d';
  28. } else {
  29. // 测试环境配置
  30. $this->baseUrl = self::PROD_BASE_URL; // TODO
  31. //$this->baseUrl = self::TEST_BASE_URL;
  32. $this->appKey = 'dadaf2279d901a5ba40';
  33. $this->appSecret = '828a03677a1c00a3a5b3c59209c4433d';
  34. }
  35. $this->shopNo = $shopId;
  36. $this->sourceId = $sourceId;
  37. }
  38. public function setShopNo($shopNo)
  39. {
  40. $this->shopNo = $shopNo;
  41. }
  42. public function getShopNo()
  43. {
  44. return $this->shopNo;
  45. }
  46. public function balance()
  47. {
  48. $api = 'api/balance/query';
  49. $params = [
  50. 'category' => 1, //查询运费账户类型(1:运费账户;2:红包账户,3:所有),默认查询运费账户余额
  51. 'shop_no' => $this->shopNo,
  52. ];
  53. $body = json_encode($params);
  54. $requestParams = $this->buildRequestPayload($api, $body);
  55. $result = $this->getHttpRequestWithPost($api, json_encode($requestParams));
  56. $resp = json_decode($result, true);
  57. if(isset($resp['code']) && $resp['code']==0){
  58. return [
  59. 'success' => true,
  60. 'balance' => $resp['result']['deliverBalance'] * 100, // 乘以100是把金额单位元改成分
  61. 'message' => '查询余额成功',
  62. ];
  63. }
  64. return [
  65. 'success' => false,
  66. 'balance' => 0,
  67. 'message' => $resp['msg'] ?? '查询余额失败',
  68. ];
  69. }
  70. /**
  71. * 构建达达 API 请求参数
  72. *
  73. * 根据达达 API 规范构建完整的请求参数,包括签名
  74. * 参数说明详见接口协议文档
  75. *
  76. * @param string $apiMethod 接口方法名(不包括基础 URL)
  77. * @param string $body 业务参数 JSON 字符串
  78. * @return array 完整的 POST 请求参数
  79. */
  80. protected function buildRequestPayload($apiMethod, $body = '')
  81. {
  82. // 获取当前时间戳(单位:秒)
  83. $timestamp = (string)time();
  84. // 构建待签名的参数(不包括 signature)
  85. $params = [
  86. 'app_key' => $this->appKey,
  87. 'v' => self::API_VERSION,
  88. 'format' => self::FORMAT,
  89. 'source_id' => $this->sourceId,
  90. 'timestamp' => $timestamp,
  91. 'body' => $body,
  92. ];
  93. // 计算签名(按达达 API 规范)
  94. $signature = $this->generateSignature($params);
  95. // 加入签名到请求参数
  96. $params['signature'] = $signature;
  97. return $params;
  98. }
  99. /**
  100. * 生成达达 API 签名
  101. *
  102. * 达达签名算法:
  103. * 1. 将所有参数(除 signature 外)按 key 升序排列
  104. * 2. 拼接为 key1value1key2value2...keyNvalueN 的形式
  105. * 3. 在字符串后面加上 app_secret
  106. * 4. 对结果进行 MD5 加密,得到 32 位大写字符串
  107. *
  108. * @param array $params 待签名参数(不包括 signature)
  109. * @return string 签名值(32 位大写)
  110. */
  111. protected function generateSignature($params)
  112. {
  113. // 按 key 升序排列参数
  114. ksort($params);
  115. // 拼接参数字符串
  116. $str = '';
  117. foreach ($params as $key => $value) {
  118. // 跳过 null 值,但保留空字符串(如 body 为空时)
  119. //if ($value === null) {
  120. //continue;
  121. //}
  122. $str .= $key . $value;
  123. }
  124. // 加上 app_secret
  125. $str = $this->appSecret . $str . $this->appSecret;
  126. // MD5 加密
  127. return strtoupper(md5($str));
  128. }
  129. /**
  130. * 发送请求,POST
  131. * @param $url 指定URL完整路径地址
  132. * @param $data 请求的数据
  133. */
  134. public function getHttpRequestWithPost($api, $data){
  135. $url = $this->baseUrl . '/' . $api;
  136. // json
  137. $headers = array(
  138. 'Content-Type: application/json',
  139. );
  140. $curl = curl_init($url);
  141. curl_setopt($curl, CURLOPT_URL, $url);
  142. curl_setopt($curl, CURLOPT_HEADER, false);
  143. curl_setopt($curl, CURLOPT_POST, true);
  144. curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
  145. curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
  146. curl_setopt($curl, CURLOPT_TIMEOUT, 3);
  147. curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
  148. $resp = curl_exec($curl);
  149. //var_dump( curl_error($curl) );//如果在执行curl的过程中出现异常,可以打开此开关查看异常内容。
  150. $info = curl_getinfo($curl);
  151. curl_close($curl);
  152. if (isset($info['http_code']) && $info['http_code'] == 200) {
  153. return $resp;
  154. }
  155. return '';
  156. }
  157. }