SAASAPIClient.php 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. <?php
  2. require_once __DIR__.'/SAASCryptAES.php';
  3. date_default_timezone_set('Asia/Shanghai');
  4. class SAASAPIClient
  5. {
  6. /**
  7. * 应用开发的AppID
  8. */
  9. protected $appid;
  10. /**
  11. * 应用开发的App密钥(用于API服务接口调用时的参数签名)
  12. */
  13. protected $appsecret;
  14. /**
  15. * 构造函数
  16. *
  17. * @param $appid 应用开发的AppID
  18. * @param $appsecret 应用开发的App密钥(用于API服务接口调用时的参数签名)
  19. * @return void
  20. */
  21. public function __construct($appid=null, $appsecret=null)
  22. {
  23. if (empty($appid) && empty($appsecret)) {
  24. $this->loadDefaultAppIdAndSecret();
  25. } else {
  26. $this->appid = $appid;
  27. $this->appsecret = $appsecret;
  28. }
  29. }
  30. /**
  31. * 调用各种SAAS系统HTTP请求方式的API服务接口,这些服务接口都遵循SAAS系统API服务接口规范,接口参数和签名都是按规范进行传递和验证。
  32. *
  33. * @param $url 服务地址
  34. * @param $args 具体的接口调用参数(除appid, timestamp, signature外),PHP数组对象,如:array("domain"=>"xxx.yydb.fanwe.com")
  35. * @return 接口调用结果,数组对象,如:array("errcode"=>0,"errmsg"=>"","data"=>array())
  36. */
  37. public function invoke($url, $args)
  38. {
  39. try {
  40. // 生成HTTP请求参数
  41. $params = $this->makeRequestParameters($args);
  42. // 执行HTTP POST请求
  43. $ch = curl_init(); // 初始化curl
  44. curl_setopt($ch, CURLOPT_URL, $url); // 服务地址
  45. curl_setopt($ch, CURLOPT_HEADER, false); // 设置header
  46. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 要求结果为字符串且输出到屏幕上
  47. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); // POST请求方式
  48. curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
  49. $data = curl_exec($ch); // 运行curl
  50. if(empty($data))
  51. {
  52. $data = curl_error($ch);
  53. }
  54. curl_close($ch);
  55. // 将返回值转为PHP数组对象并返回
  56. $result = json_decode($data, true);
  57. return is_null($result) ? array("errcode"=>1001,"errmsg"=>"Remote service return data error: ".$data) : $result;
  58. } catch (Exception $e) {
  59. return array("errcode"=>1001,"errmsg"=>"Remote service error: ".$e->getMessage());
  60. }
  61. }
  62. /**
  63. * 生成SAAS系统API调用的请求参数,请求参数中将包含基本的参数(如:appid,timestamp,signature),并返回包含这些参数的数组数据。
  64. *
  65. * @param $args 具体的接口调用参数(除appid, timestamp, signature外),PHP数组对象,如:array("domain"=>"xxx.yydb.fanwe.com")
  66. * @return 已生成的参数数组,如:array("appid"=>"","timestamp"=>1457839056,"signature"=>"")
  67. */
  68. public function makeRequestParameters($args)
  69. {
  70. // 计算参数签名,并设置返回值
  71. $systime = time();
  72. $params = array();
  73. $result = array();
  74. foreach($args as $key=>$value) {
  75. if ($key == 'appid' || $key == 'timestamp' || $key == 'signature') continue;
  76. $params[] = $key.$value;
  77. $result[$key] = $value;
  78. }
  79. $params['appid'] = 'appid'.$this->appid;
  80. $params['timestamp'] = 'timestamp'.$systime;
  81. sort($params, SORT_STRING);
  82. $paramsStr = implode($params);
  83. $signature = md5($this->appsecret.$paramsStr.$this->appsecret);
  84. $result['appid'] = $this->appid;
  85. $result['timestamp'] = $systime;
  86. $result['signature'] = $signature;
  87. // 返回结果
  88. return $result;
  89. }
  90. /**
  91. * 生成方维系统间信息安全传递地址,将要传递的参数加密后附加到指定地址后面。
  92. * @param $url 原始地址,用于附加安全参数
  93. * @param $params 待附加的参数数组
  94. * @param $widthAppid 可选参数,生成的安全地址是否附带appid参数(参数名:_saas_appid),默认不附带
  95. * @param $timeoutMinutes 安全参数过期时间(单位:分钟),小于等于0表示永不过期
  96. * @return 附加安全参数后的安全地址
  97. */
  98. public function makeSecurityUrl($url, $params, $withAppid = false, $timeoutMinutes = 0)
  99. {
  100. // 将参数数组加密成安全参数字符串
  101. $encstr = $this->encodeSecurityParams($params, $timeoutMinutes);
  102. // 将加密后的参数附加到$url后面,然后返回
  103. $split = strpos($url, '?') === false ? '?' : '&';
  104. $url .= $split.'_saas_params='.urlencode($encstr);
  105. if ($withAppid) {
  106. $url .= '&_saas_appid='.$this->appid;
  107. }
  108. return $url;
  109. }
  110. /**
  111. * 加密指定的数组成生成方维系统间传递的安全参数字符串,以便通过HTTP的GET请求或POST请求进行传递
  112. * @param $params 待附加的参数数组
  113. * @param $timeoutMinutes 安全参数过期时间(单位:分钟),小于等于0表示永不过期
  114. * @return 加密后的安全参数字符串
  115. */
  116. public function encodeSecurityParams($params, $timeoutMinutes = 0)
  117. {
  118. // 添加验证过期参数
  119. $params['_saas_timestamp'] = time();
  120. if ($timeoutMinutes > 0) {
  121. $params['_saas_timeout'] = $timeoutMinutes;
  122. }
  123. // 先将参数数组转为json格式字符串,然后加密
  124. $json = json_encode($params);
  125. $aes = new SAASCryptAES();
  126. $aes->set_key($this->appsecret);
  127. $aes->require_pkcs5();
  128. $encstr = $aes->encrypt($json);
  129. // 返回加密后的字符串
  130. return $encstr;
  131. }
  132. /**
  133. * 从saasapi.key配置文件中加载默认的appid和appsecret配置
  134. */
  135. private function loadDefaultAppIdAndSecret()
  136. {
  137. $keyfile = __DIR__.'/saasapi.key';
  138. if (!file_exists($keyfile)) {
  139. return;
  140. }
  141. $keystr = file_get_contents($keyfile);
  142. $keyinfo = json_decode($keystr, true);
  143. $this->appid = array_key_exists('appid', $keyinfo) ? $keyinfo['appid'] : '';
  144. $this->appsecret = array_key_exists('appsecret', $keyinfo) ? $keyinfo['appsecret'] : '';
  145. }
  146. }