SpiUtils.php 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. <?php
  2. class SpiUtils{
  3. private static $top_sign_list = "HTTP_TOP_SIGN_LIST";
  4. private static $timestamp = "timestamp";
  5. private static $header_real_ip = array("X_Real_IP", "X_Forwarded_For", "Proxy_Client_IP",
  6. "WL_Proxy_Client_IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR");
  7. /**
  8. * 校验SPI请求签名,适用于所有GET请求,及不包含文件参数的POST请求。
  9. *
  10. * @param request 请求对象
  11. * @param secret app对应的secret
  12. * @return true:校验通过;false:校验不通过
  13. */
  14. public static function checkSign4FormRequest($secret){
  15. return self::checkSign(null,null,$secret);
  16. }
  17. /**
  18. * 校验SPI请求签名,适用于请求体是xml/json等可用文本表示的POST请求。
  19. *
  20. * @param request 请求对象
  21. * @param body 请求体的文本内容
  22. * @param secret app对应的secret
  23. * @return true:校验通过;false:校验不通过
  24. */
  25. public static function checkSign4TextRequest($body,$secret){
  26. return self::checkSign(null,$body,$secret);
  27. }
  28. /**
  29. * 校验SPI请求签名,适用于带文件上传的POST请求。
  30. *
  31. * @param request 请求对象
  32. * @param form 除了文件参数以外的所有普通文本参数的map集合
  33. * @param secret app对应的secret
  34. * @return true:校验通过;false:校验不通过
  35. */
  36. public static function checkSign4FileRequest($form, $secret){
  37. return self::checkSign($form, null, $secret);
  38. }
  39. private static function checkSign($form, $body, $secret) {
  40. $params = array();
  41. // 1. 获取header参数
  42. $headerMap = self::getHeaderMap();
  43. foreach ($headerMap as $k => $v){
  44. $params[$k] = $v ;
  45. }
  46. // 2. 获取url参数
  47. $queryMap = self::getQueryMap();
  48. foreach ($queryMap as $k => $v){
  49. $params[$k] = $v ;
  50. }
  51. // 3. 获取form参数
  52. if ($form == null && $body == null) {
  53. $formMap = self::getFormMap();
  54. foreach ($formMap as $k => $v){
  55. $params[$k] = $v ;
  56. }
  57. } else if ($form != null) {
  58. foreach ($form as $k => $v){
  59. $params[$k] = $v ;
  60. }
  61. }
  62. if($body == null){
  63. $body = file_get_contents('php://input');
  64. }
  65. $remoteSign = $queryMap["sign"];
  66. $localSign = self::sign($params, $body, $secret);
  67. if (strcmp($remoteSign, $localSign) == 0) {
  68. return true;
  69. } else {
  70. $paramStr = self::getParamStrFromMap($params);
  71. self::logCommunicationError($remoteSign,$localSign,$paramStr,$body);
  72. return false;
  73. }
  74. }
  75. private static function getHeaderMap() {
  76. $headerMap = array();
  77. $signList = $_SERVER['HTTP_TOP_SIGN_LIST']; // 只获取参与签名的头部字段
  78. $signList = trim($signList);
  79. if (strlen($signList) > 0){
  80. $params = split(",", $signList);
  81. foreach ($_SERVER as $k => $v){
  82. if (substr($k, 0, 5) == 'HTTP_'){
  83. foreach($params as $kk){
  84. $upperkey = strtoupper($kk);
  85. if(self::endWith($k,$upperkey)){
  86. $headerMap[$kk] = $v;
  87. }
  88. }
  89. }
  90. }
  91. }
  92. return $headerMap;
  93. }
  94. private static function getQueryMap(){
  95. $queryStr = $_SERVER["QUERY_STRING"];
  96. $resultArray = array();
  97. foreach (explode('&', $queryStr) as $pair) {
  98. list($key, $value) = explode('=', $pair);
  99. if (strpos($key, '.') !== false) {
  100. list($subKey, $subVal) = explode('.', $key);
  101. if (preg_match('/(?P<name>\w+)\[(?P<index>\w+)\]/', $subKey, $matches)) {
  102. $resultArray[$matches['name']][$matches['index']][$subVal] = $value;
  103. } else {
  104. $resultArray[$subKey][$subVal] = urldecode($value);
  105. }
  106. } else {
  107. $resultArray[$key] = urldecode($value);
  108. }
  109. }
  110. return $resultArray;
  111. }
  112. private static function checkRemoteIp(){
  113. $remoteIp = $_SERVER["REMOTE_ADDR"];
  114. foreach ($header_real_ip as $k){
  115. $realIp = $_SERVER[$k];
  116. $realIp = trim($realIp);
  117. if(strlen($realIp) > 0 && strcasecmp("unknown",$realIp)){
  118. $remoteIp = $realIp;
  119. break;
  120. }
  121. }
  122. return self::startsWith($remoteIp,"140.205.144.") || $this->startsWith($remoteIp,"40.205.145.");
  123. }
  124. private static function getFormMap(){
  125. $resultArray = array();
  126. foreach($_POST as $key=>$v) {
  127. $resultArray[$k] = $v ;
  128. }
  129. return $resultArray ;
  130. }
  131. private static function startsWith($haystack, $needle) {
  132. return $needle === "" || strpos($haystack, $needle) === 0;
  133. }
  134. private static function endWith($haystack, $needle) {
  135. $length = strlen($needle);
  136. if($length == 0)
  137. {
  138. return true;
  139. }
  140. return (substr($haystack, -$length) === $needle);
  141. }
  142. private static function checkTimestamp(){
  143. $ts = $_POST['timestamp'];
  144. if($ts){
  145. $clientTimestamp = strtotime($ts);
  146. $current = $_SERVER['REQUEST_TIME'];
  147. return ($current - $clientTimestamp) <= 5*60*1000;
  148. }else{
  149. return false;
  150. }
  151. }
  152. private static function getParamStrFromMap($params){
  153. ksort($params);
  154. $stringToBeSigned = "";
  155. foreach ($params as $k => $v)
  156. {
  157. if(strcmp("sign", $k) != 0)
  158. {
  159. $stringToBeSigned .= "$k$v";
  160. }
  161. }
  162. unset($k, $v);
  163. return $stringToBeSigned;
  164. }
  165. private static function sign($params,$body,$secret){
  166. ksort($params);
  167. $stringToBeSigned = $secret;
  168. $stringToBeSigned .= self::getParamStrFromMap($params);
  169. if($body)
  170. $stringToBeSigned .= $body;
  171. $stringToBeSigned .= $secret;
  172. return strtoupper(md5($stringToBeSigned));
  173. }
  174. protected static function logCommunicationError($remoteSign, $localSign, $paramStr, $body)
  175. {
  176. $localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
  177. $logger = new TopLogger;
  178. $logger->conf["log_file"] = rtrim(TOP_SDK_WORK_DIR, '\\/') . '/' . "logs/top_comm_err_". date("Y-m-d") . ".log";
  179. $logger->conf["separator"] = "^_^";
  180. $logData = array(
  181. "checkTopSign error" ,
  182. "remoteSign=".$remoteSign ,
  183. "localSign=".$localSign ,
  184. "paramStr=".$paramStr ,
  185. "body=".$body
  186. );
  187. $logger->log($logData);
  188. }
  189. private static function clear_blank($str, $glue='')
  190. {
  191. $replace = array(" ", "\r", "\n", "\t"); return str_replace($replace, $glue, $str);
  192. }
  193. }
  194. ?>