我在网络服务器上运行了一个PHP API前端。这个特定的PHP程序需要分发,因此它应该尽可能便携。
我想要实现的功能是IP冷却时间段,这意味着相同的IP每秒最多只能请求API两次,这意味着至少延迟500ms。
我想到的方法是将IP存储在MySQL数据库中,以及最新的请求时间戳。我得到了IP:
if (getenv('REMOTE_ADDR'))
$ipaddress = getenv('REMOTE_ADDR');
但是有些服务器可能没有MySQL数据库,或者用户无法安装此数据库。另一个问题是清理数据库。
是否有更便携的临时存储IP方式(牢记IPv6)?
和
如何自动清除超过500毫秒的IP,对性能影响最小?
另外:我没有兴趣查看存储的IP,这只是延迟。
答案 0 :(得分:0)
这就是我现在使用文件解决它的方法。
<?php
$sIPHash = md5($_SERVER[REMOTE_ADDR]);
$iSecDelay = 10;
$sPath = "bucket.cache";
$bReqAllow = false;
$iWait = -1;
$sContent = "";
if ($nFileHandle = fopen($sPath, "c+")) {
flock($nFileHandle, LOCK_EX);
$iCurLine = 0;
while (($sCurLine = fgets($nFileHandle, 4096)) !== FALSE) {
$iCurLine++;
$bIsIPRec = strpos($sCurLine, $sIPHash);
$iLastReq = strtok($sCurLine, '|');
// this record expired anyway:
if ( (time() - $iLastReq) > $iSecDelay ) {
// is it also our IP?
if ($bIsIPRec !== FALSE) {
$sContent .= time()."|".$sIPHash.PHP_EOL;
$bReqAllow = true;
}
} else {
if ($bIsIPRec !== FALSE) $iWait = ($iSecDelay-(time()-$iLastReq));
$sContent .= $sCurLine.PHP_EOL;
}
}
}
if ($iWait == -1 && $bReqAllow == false) {
// no record yet, create one
$sContent .= time()."|".$sIPHash.PHP_EOL;
echo "Request from new user successful!";
} elseif ($bReqAllow == true) {
echo "Request from old user successful!";
} else {
echo "Request failed! Wait " . $iWait . " seconds!";
}
ftruncate($nFileHandle, 0);
rewind($nFileHandle);
fwrite($nFileHandle, $sContent);
flock($nFileHandle, LOCK_UN);
fclose($nFileHandle);
?>
新用户
如果IP哈希不匹配任何记录,则会创建新记录。注意:如果您无权执行此操作,则访问可能会失败。
<强>内存强>
如果您期望获得更多流量,请一起切换到this等数据库解决方案。
冗余代码
&#34;但是minxomat&#34;,你可能会说,&#34;现在每个客户端遍历整个文件!&#34;。是的,的确,这就是我想要的解决方案。这样,每个客户端都负责清理整个文件。即便如此,性能影响仍然很低,因为如果每个客户端都在清理,文件大小将保持在绝对最小值。如果这种方式不适合你,请改变这一点。