221 lines
5.9 KiB
PHP
Executable File
221 lines
5.9 KiB
PHP
Executable File
<?php
|
||
namespace taobao;
|
||
|
||
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']; // 只获取参与签名的头部字段
|
||
|
||
if(!$signList) {
|
||
return $headerMap;
|
||
}
|
||
|
||
$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[$key] = $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);
|
||
}
|
||
}
|
||
?>
|