|
|
|
|
<?php
|
|
|
|
|
class SpiUtils{
|
|
|
|
|
private static $top_sign_list = "HTTP_TOP_SIGN_LIST";
|
|
|
|
|
private static $timestamp = "timestamp";
|
|
|
|
|
private static $header_real_ip = array("X_Real_IP", "X_Forwarded_For", "Proxy_Client_IP",
|
|
|
|
|
"WL_Proxy_Client_IP", "HTTP_CLIENT_IP", "HTTP_X_FORWARDED_FOR");
|
|
|
|
|
/**
|
|
|
|
|
* 校验SPI请求签名,适用于所有GET请求,及不包含文件参数的POST请求。
|
|
|
|
|
*
|
|
|
|
|
* @param request 请求对象
|
|
|
|
|
* @param secret app对应的secret
|
|
|
|
|
* @return true:校验通过;false:校验不通过
|
|
|
|
|
*/
|
|
|
|
|
public static function checkSign4FormRequest($secret){
|
|
|
|
|
return self::checkSign(null,null,$secret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 校验SPI请求签名,适用于请求体是xml/json等可用文本表示的POST请求。
|
|
|
|
|
*
|
|
|
|
|
* @param request 请求对象
|
|
|
|
|
* @param body 请求体的文本内容
|
|
|
|
|
* @param secret app对应的secret
|
|
|
|
|
* @return true:校验通过;false:校验不通过
|
|
|
|
|
*/
|
|
|
|
|
public static function checkSign4TextRequest($body,$secret){
|
|
|
|
|
return self::checkSign(null,$body,$secret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 校验SPI请求签名,适用于带文件上传的POST请求。
|
|
|
|
|
*
|
|
|
|
|
* @param request 请求对象
|
|
|
|
|
* @param form 除了文件参数以外的所有普通文本参数的map集合
|
|
|
|
|
* @param secret app对应的secret
|
|
|
|
|
* @return true:校验通过;false:校验不通过
|
|
|
|
|
*/
|
|
|
|
|
public static function checkSign4FileRequest($form, $secret){
|
|
|
|
|
return self::checkSign($form, null, $secret);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function checkSign($form, $body, $secret) {
|
|
|
|
|
$params = array();
|
|
|
|
|
// 1. 获取header参数
|
|
|
|
|
$headerMap = self::getHeaderMap();
|
|
|
|
|
foreach ($headerMap as $k => $v){
|
|
|
|
|
$params[$k] = $v ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 2. 获取url参数
|
|
|
|
|
$queryMap = self::getQueryMap();
|
|
|
|
|
foreach ($queryMap as $k => $v){
|
|
|
|
|
$params[$k] = $v ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. 获取form参数
|
|
|
|
|
if ($form == null && $body == null) {
|
|
|
|
|
$formMap = self::getFormMap();
|
|
|
|
|
foreach ($formMap as $k => $v){
|
|
|
|
|
$params[$k] = $v ;
|
|
|
|
|
}
|
|
|
|
|
} else if ($form != null) {
|
|
|
|
|
foreach ($form as $k => $v){
|
|
|
|
|
$params[$k] = $v ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if($body == null){
|
|
|
|
|
$body = file_get_contents('php://input');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$remoteSign = $queryMap["sign"];
|
|
|
|
|
$localSign = self::sign($params, $body, $secret);
|
|
|
|
|
if (strcmp($remoteSign, $localSign) == 0) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
$paramStr = self::getParamStrFromMap($params);
|
|
|
|
|
self::logCommunicationError($remoteSign,$localSign,$paramStr,$body);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function getHeaderMap() {
|
|
|
|
|
$headerMap = array();
|
|
|
|
|
$signList = $_SERVER['HTTP_TOP_SIGN_LIST']; // 只获取参与签名的头部字段
|
|
|
|
|
$signList = trim($signList);
|
|
|
|
|
if (strlen($signList) > 0){
|
|
|
|
|
$params = split(",", $signList);
|
|
|
|
|
foreach ($_SERVER as $k => $v){
|
|
|
|
|
if (substr($k, 0, 5) == 'HTTP_'){
|
|
|
|
|
foreach($params as $kk){
|
|
|
|
|
$upperkey = strtoupper($kk);
|
|
|
|
|
if(self::endWith($k,$upperkey)){
|
|
|
|
|
$headerMap[$kk] = $v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $headerMap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function getQueryMap(){
|
|
|
|
|
$queryStr = $_SERVER["QUERY_STRING"];
|
|
|
|
|
$resultArray = array();
|
|
|
|
|
foreach (explode('&', $queryStr) as $pair) {
|
|
|
|
|
list($key, $value) = explode('=', $pair);
|
|
|
|
|
if (strpos($key, '.') !== false) {
|
|
|
|
|
list($subKey, $subVal) = explode('.', $key);
|
|
|
|
|
|
|
|
|
|
if (preg_match('/(?P<name>\w+)\[(?P<index>\w+)\]/', $subKey, $matches)) {
|
|
|
|
|
$resultArray[$matches['name']][$matches['index']][$subVal] = $value;
|
|
|
|
|
} else {
|
|
|
|
|
$resultArray[$subKey][$subVal] = urldecode($value);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
$resultArray[$key] = urldecode($value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return $resultArray;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function checkRemoteIp(){
|
|
|
|
|
$remoteIp = $_SERVER["REMOTE_ADDR"];
|
|
|
|
|
foreach ($header_real_ip as $k){
|
|
|
|
|
$realIp = $_SERVER[$k];
|
|
|
|
|
$realIp = trim($realIp);
|
|
|
|
|
if(strlen($realIp) > 0 && strcasecmp("unknown",$realIp)){
|
|
|
|
|
$remoteIp = $realIp;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return self::startsWith($remoteIp,"140.205.144.") || self::startsWith($remoteIp,"40.205.145.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function getFormMap(){
|
|
|
|
|
$resultArray = array();
|
|
|
|
|
foreach($_POST as $key=>$v) {
|
|
|
|
|
$resultArray[$k] = $v ;
|
|
|
|
|
}
|
|
|
|
|
return $resultArray ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function startsWith($haystack, $needle) {
|
|
|
|
|
return $needle === "" || strpos($haystack, $needle) === 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function endWith($haystack, $needle) {
|
|
|
|
|
$length = strlen($needle);
|
|
|
|
|
if($length == 0)
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return (substr($haystack, -$length) === $needle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function checkTimestamp(){
|
|
|
|
|
$ts = $_POST['timestamp'];
|
|
|
|
|
if($ts){
|
|
|
|
|
$clientTimestamp = strtotime($ts);
|
|
|
|
|
$current = $_SERVER['REQUEST_TIME'];
|
|
|
|
|
return ($current - $clientTimestamp) <= 5*60*1000;
|
|
|
|
|
}else{
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function getParamStrFromMap($params){
|
|
|
|
|
ksort($params);
|
|
|
|
|
$stringToBeSigned = "";
|
|
|
|
|
foreach ($params as $k => $v)
|
|
|
|
|
{
|
|
|
|
|
if(strcmp("sign", $k) != 0)
|
|
|
|
|
{
|
|
|
|
|
$stringToBeSigned .= "$k$v";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
unset($k, $v);
|
|
|
|
|
return $stringToBeSigned;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static function sign($params,$body,$secret){
|
|
|
|
|
ksort($params);
|
|
|
|
|
|
|
|
|
|
$stringToBeSigned = $secret;
|
|
|
|
|
$stringToBeSigned .= self::getParamStrFromMap($params);
|
|
|
|
|
|
|
|
|
|
if($body)
|
|
|
|
|
$stringToBeSigned .= $body;
|
|
|
|
|
$stringToBeSigned .= $secret;
|
|
|
|
|
return strtoupper(md5($stringToBeSigned));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected static function logCommunicationError($remoteSign, $localSign, $paramStr, $body)
|
|
|
|
|
{
|
|
|
|
|
$localIp = isset($_SERVER["SERVER_ADDR"]) ? $_SERVER["SERVER_ADDR"] : "CLI";
|
|
|
|
|
$logger = new TopLogger;
|
|
|
|
|
$logger->conf["log_file"] = rtrim(TOP_SDK_WORK_DIR, '\\/') . '/' . "logs/top_comm_err_". date("Y-m-d") . ".log";
|
|
|
|
|
$logger->conf["separator"] = "^_^";
|
|
|
|
|
$logData = array(
|
|
|
|
|
"checkTopSign error" ,
|
|
|
|
|
"remoteSign=".$remoteSign ,
|
|
|
|
|
"localSign=".$localSign ,
|
|
|
|
|
"paramStr=".$paramStr ,
|
|
|
|
|
"body=".$body
|
|
|
|
|
);
|
|
|
|
|
$logger->log($logData);
|
|
|
|
|
}
|
|
|
|
|
private static function clear_blank($str, $glue='')
|
|
|
|
|
{
|
|
|
|
|
$replace = array(" ", "\r", "\n", "\t"); return str_replace($replace, $glue, $str);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
?>
|