php - 提供基于 IP 的冷却期的可移植方式?

标签 php mysql ip-address

我有一个在网络服务器上运行的 PHP API 前端。这个特定的 PHP 程序是要分发的,因此它应该尽可能可移植。

我想要实现的功能是IP冷却期,这意味着同一个IP每秒最多只能请求API两次,意味着至少有500ms的延迟。

我想到的方法是将 IP 与最新请求时间戳一起存储在 MySQL 数据库中。我通过以下方式获取IP:

if (getenv('REMOTE_ADDR'))
    $ipaddress = getenv('REMOTE_ADDR');

但某些服务器可能没有 MySQL 数据库,或者安装此数据库的用户无权访问。另一个问题是数据库的清理。

是否有更便携的方式来临时存储 IP(记住 IPv6)?

如何自动清理早于 500 毫秒的 IP,同时将性能影响降至最低?

另外:我对查看存储的 IP 不感兴趣,这只是关于延迟。

最佳答案

这就是我现在使用文件解决这个问题的方法。

程序

  1. 获取客户端 IP 并对其进行哈希处理(以防止文件读出)。
  2. 打开 IP 文件并扫描每一行
  3. 将当前记录的时间与当前时间进行比较
  4. 如果差值大于设置的超时,则转到 5,否则转到 7。
  5. 如果 IP 与客户端匹配,则创建更新记录,否则
  6. 删除记录。
  7. 如果IP与客户端匹配,则提供失败消息,否则复制记录。

示例代码

<?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全部在一起。

冗余代码

“但是 minxomat”,您可能会说,“现在每个客户端都会循环访问整个文件!”。是的,确实如此,这就是我想要的解决方案。这样,每个客户端都有责任清理整个文件。即便如此,对性能的影响仍然很低,因为如果每个客户端都进行清理,文件大小将保持在绝对最小值。如果这种方式不适合您,请更改此设置。

关于php - 提供基于 IP 的冷却期的可移植方式?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31138984/

相关文章:

c# - 从服务引用 C# 中获取地址

javascript - iframe 的欺骗 IP 地址

javascript - PHP 重新排列数组并按值分组

mysql - 如何从mysql中选择字段的增量

ip-address - 你会如何比较IP地址?

mysql - 日期与日期格式的比较不符合预期

MySQL根据字段内容连接

php - 字符串损坏或 preg_match 错误?

php - 如何在 mysql 中更改 one day plus 的时间?

php - 如何记录基于 Symfony 的 REST API(类似于 enunciate 的文档功能)