KeloopSdk.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. <?php
  2. /*
  3. * Copyright (c) 2012—2018 成都零点信息技术有限公司 All
  4. */
  5. /**
  6. * 2018 年快跑者正式版开放接口 SDK
  7. *
  8. * @author xuhaha sxuhaha@gmail.com
  9. */
  10. class KeloopSdk
  11. {
  12. const BASE_URL = 'https://open.keloop.cn';
  13. const VERSION = 1;
  14. private $_team_token = ''; // 团队 Token
  15. private $_dev_key = ''; // 开发者 key
  16. private $_dev_secret = ''; // 开发者 密钥
  17. /**
  18. * KeloopSdk constructor.
  19. * @param $config
  20. * @throws Exception
  21. */
  22. public function __construct($config)
  23. {
  24. $this->_dev_key = $config['dev_key'];
  25. $this->_dev_secret = $config['dev_secret'];
  26. $this->_team_token = $config['team_token'];
  27. if (empty($this->_dev_key) || empty($this->_dev_secret)) {
  28. throw new Exception('dev_key 或 dev_secret 异常');
  29. }
  30. if (empty($this->_team_token)) {
  31. throw new Exception('team_token 异常');
  32. }
  33. }
  34. /**
  35. * generate ticket
  36. * @return string
  37. */
  38. private function _genTicket()
  39. {
  40. if (function_exists('com_create_guid')) {
  41. $uuid = trim(com_create_guid(), '{}');
  42. } else {
  43. mt_srand((double)microtime() * 10000);
  44. $charid = strtoupper(md5(uniqid(rand(), true)));
  45. $hyphen = chr(45);
  46. $uuid = substr($charid, 0, 8) . $hyphen
  47. . substr($charid, 8, 4) . $hyphen
  48. . substr($charid, 12, 4) . $hyphen
  49. . substr($charid, 16, 4) . $hyphen
  50. . substr($charid, 20, 12);
  51. }
  52. return strtoupper($uuid);
  53. }
  54. /**
  55. * 封装参数
  56. * @param array $paramm
  57. * @return array
  58. */
  59. private function _genParam($paramm = [])
  60. {
  61. $data = [
  62. 'version' => self::VERSION,
  63. 'timestamp' => time(),
  64. 'ticket' => $this->_genTicket(),
  65. 'team_token' => $this->_team_token,
  66. 'dev_key' => $this->_dev_key,
  67. 'body' => json_encode($paramm)
  68. ];
  69. $sign = Md5Sign::getSign($data, $this->_dev_secret);
  70. $data['sign'] = $sign;
  71. return $data;
  72. }
  73. /**
  74. * @param $path
  75. * @param array $param
  76. * @return mixed|null
  77. */
  78. public function getUrl($path, $param = [])
  79. {
  80. $data = $this->_genParam($param);
  81. $url = self::BASE_URL . $path;
  82. $result = HTTPRequest::getUrl($url, $data);
  83. if (!empty($result)) {
  84. return json_decode($result, true);
  85. } else {
  86. return null;
  87. }
  88. }
  89. /**
  90. * @param $path
  91. * @param array $param
  92. * @return mixed|null
  93. */
  94. public function postUrl($path, $param = [])
  95. {
  96. $data = $this->_genParam($param);
  97. $url = self::BASE_URL . $path;
  98. $result = HTTPRequest::postUrl($url, $data);
  99. if (!empty($result)) {
  100. return json_decode($result, true);
  101. } else {
  102. return null;
  103. }
  104. }
  105. /**
  106. * 检测 sign 是否正确
  107. * @param $paramm
  108. * @return bool
  109. */
  110. public function checkSign($paramm)
  111. {
  112. if (!isset($paramm['sign'])) {
  113. return false;
  114. }
  115. return Md5Sign::isSignCorrect($paramm, $this->_dev_secret, $paramm['sign']);
  116. }
  117. // ********************** 订单相关接口 ********************** //
  118. /**
  119. * 向绑定的配送站发送订单
  120. * @param $param
  121. * @return mixed|null
  122. */
  123. public function createOrder($param)
  124. {
  125. $path = '/open/order/createOrder';
  126. return $this->postUrl($path, $param);
  127. }
  128. /**
  129. * 获取订单信息
  130. * @param $param
  131. * @return mixed|null
  132. */
  133. public function getOrderInfo($param)
  134. {
  135. $path = '/open/order/getOrderInfo';
  136. return $this->getUrl($path, $param);
  137. }
  138. /**
  139. * 获取订单进程
  140. * @param $param
  141. * @return mixed|null
  142. */
  143. public function getOrderLog($param)
  144. {
  145. $path = '/open/order/getOrderLog';
  146. return $this->getUrl($path, $param);
  147. }
  148. /**
  149. * 计算快跑者商户配送费
  150. * @param $param
  151. * @return mixed|null
  152. */
  153. public function getFee($param)
  154. {
  155. $path = '/open/order/getFee';
  156. return $this->getUrl($path, $param);
  157. }
  158. /**
  159. * 获取配送员最新坐标
  160. * @param $param
  161. * @return mixed|null
  162. */
  163. public function getCourierTag($param)
  164. {
  165. $path = '/open/order/getCourierTag';
  166. return $this->getUrl($path, $param);
  167. }
  168. /**
  169. * 取消订单
  170. * @param $param
  171. * @return mixed|null
  172. */
  173. public function cancelOrder($param)
  174. {
  175. $path = '/open/order/cancelOrder';
  176. return $this->postUrl($path, $param);
  177. }
  178. /**
  179. * 评论订单
  180. * @param $param
  181. * @return mixed|null
  182. */
  183. public function commentOrder($param)
  184. {
  185. $path = '/open/order/commentOrder';
  186. return $this->postUrl($path, $param);
  187. }
  188. /**
  189. * 获取商户计价明细
  190. * @param $param
  191. * @return mixed|null
  192. */
  193. public function getMerchantCalc($param)
  194. {
  195. $path = '/open/order/getFee';
  196. return $this->postUrl($path, $param);
  197. }
  198. // ********************** 团队相关接口 ********************** //
  199. /**
  200. * 获取团队信息
  201. * @return mixed|null
  202. */
  203. public function getTeamInfo()
  204. {
  205. $path = '/open/team/getTeamInfo';
  206. return $this->getUrl($path);
  207. }
  208. // ********************** 商户相关接口 ********************** //
  209. /**
  210. * 获取团队所有合作商户信息
  211. * @return mixed|null
  212. */
  213. public function getMerchants()
  214. {
  215. $path = '/open/merchant/getMerchants';
  216. return $this->getUrl($path);
  217. }
  218. // ********************** 配送员相关接口 ********************** //
  219. /**
  220. * 获取团队合作的所有配送员信息
  221. * @return mixed|null
  222. */
  223. public function getCouriers()
  224. {
  225. $path = '/open/courier/getCouriers';
  226. return $this->getUrl($path);
  227. }
  228. }
  229. /**
  230. * 签名类
  231. * Class Md5Sign
  232. */
  233. class Md5Sign
  234. {
  235. /**
  236. * 获取签名
  237. * @param array $param 密的参数数组
  238. * @param string $accessSec 加密的key
  239. * @return bool|string 生产的签名
  240. */
  241. public static function getSign($param, $accessSec)
  242. {
  243. if (empty($param) || empty($accessSec)) {
  244. return false;
  245. }
  246. // 除去待签名参数数组中的空值和签名参数
  247. $param = self::paraFilter($param);
  248. $param = self::argSort($param);
  249. $str = self::createLinkstring($param);
  250. $sign = self::md5Verify($str, $accessSec);
  251. return $sign;
  252. }
  253. /**
  254. * 判断签名是否正确
  255. * @param $paramm
  256. * @param $encKey
  257. * @param $sign
  258. * @return bool
  259. */
  260. public static function isSignCorrect($paramm, $encKey, $sign)
  261. {
  262. if (empty($sign)) {
  263. return false;
  264. } else {
  265. $prestr = self::getSign($paramm, $encKey);
  266. return $prestr === $sign ? true : false;
  267. }
  268. }
  269. /**
  270. * 除去数组中的空值和签名参数
  271. * @param array $param 签名参数组
  272. * @return array 获取去掉空值与签名参数后的新签名参数组
  273. */
  274. private static function paraFilter($param)
  275. {
  276. $param_filter = array();
  277. while (list ($key, $val) = each($param)) {
  278. //去掉 '',null,保留数字0
  279. if ($key == 'sign' || $key == 'sign_type' || $key == 'key' || (empty($val) && !is_numeric($val))) {
  280. continue;
  281. } else {
  282. $param_filter[$key] = $param[$key];
  283. }
  284. }
  285. return $param_filter;
  286. }
  287. /**
  288. * 对数组排序
  289. * @param array $param 排序前的数组
  290. * @return mixed 排序后的数组
  291. */
  292. private static function argSort($param)
  293. {
  294. ksort($param);
  295. reset($param);
  296. return $param;
  297. }
  298. /**
  299. * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
  300. * @param array $param 需要拼接的数组
  301. * @return string 拼接完成以后的字符串
  302. */
  303. private static function createLinkstring($param)
  304. {
  305. $arg = '';
  306. while (list ($key, $val) = each($param)) {
  307. $arg .= $key . '=' . $val . '&';
  308. }
  309. //去掉最后一个&字符
  310. $arg = trim($arg, '&');
  311. //如果存在转义字符,那么去掉转义
  312. if (get_magic_quotes_gpc()) {
  313. $arg = stripslashes($arg);
  314. }
  315. return $arg;
  316. }
  317. /**
  318. * 生成签名
  319. * @param string $prestr 需要签名的字符串
  320. * @param string $sec 身份认证密钥(access_sec)
  321. * @return string 签名结果
  322. */
  323. private static function md5Verify($prestr, $sec)
  324. {
  325. return md5($prestr . $sec);
  326. }
  327. }
  328. /**
  329. * HTTP 请求类
  330. * Class HTTPRequest
  331. */
  332. class HTTPRequest
  333. {
  334. /**
  335. * Http post request
  336. * @param $url
  337. * @param array $paramms
  338. * @param int $timeout
  339. * @return bool|mixed
  340. */
  341. public static function postUrl($url, $paramms = array(), $timeout = 3)
  342. {
  343. //编码特殊字符
  344. $p = http_build_query($paramms);
  345. $curl = curl_init();
  346. curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书检查
  347. curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 检查SSL加密算法是否存在
  348. curl_setopt($curl, CURLOPT_URL, $url);
  349. // 设置header
  350. curl_setopt($curl, CURLOPT_HEADER, 0);
  351. curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
  352. curl_setopt($curl, CURLOPT_POST, 1);
  353. curl_setopt($curl, CURLOPT_POSTFIELDS, $p);
  354. // 设置cURL 参数,要求结果保存到字符串中还是输出到屏幕上。
  355. curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
  356. // 运行cURL,请求网页
  357. $data = curl_exec($curl);
  358. curl_close($curl);
  359. if ($data === false) {
  360. return false;
  361. } else {
  362. return $data;
  363. }
  364. }
  365. /**
  366. * Http get request
  367. * @param $url
  368. * @param array $paramm
  369. * @return mixed
  370. */
  371. public static function getUrl($url, $paramm = array())
  372. {
  373. $url = self::buildUrl($url, $paramm);
  374. return self::get($url);
  375. }
  376. /**
  377. * Http get request
  378. * @param $url
  379. * @param int $timeout
  380. * @return mixed
  381. */
  382. public static function get($url, $timeout = 3)
  383. {
  384. $ch = curl_init($url);
  385. curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  386. curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
  387. $resposne = curl_exec($ch);
  388. return $resposne;
  389. }
  390. /**
  391. * Build request url
  392. * @param $url
  393. * @param $paramm
  394. * @return string
  395. */
  396. private static function buildUrl($url, $paramm)
  397. {
  398. $url = rtrim(trim($url), '?');
  399. $url = $url . '?';
  400. $query = '';
  401. if (!empty($paramm)) {
  402. $query = http_build_query($paramm);
  403. }
  404. return $url . $query;
  405. }
  406. }