SpiUtils.php 7.0 KB

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