php - 如何限制一分钟内发出的用户请求数

标签 php url ip limit

用户将通过类似 script.php?userid=222 的 URL 按编号请求文件。此示例将显示文件 #222 的记录。

现在我想将每个(远程 IP)用户的文件数限制为一分钟内最多 5 个不同的记录。但是,用户应该能够多次访问相同的 ID 记录。

所以用户可以访问文件 #222 任意次数,但是如果(远程 IP)用户在一分钟内访问超过 5 个其他不同的记录,那么它应该显示错误。

例如,假设在一分钟内发出了以下请求:

script.php?userid=222
script.php?userid=523
script.php?userid=665
script.php?userid=852
script.php?userid=132
script.php?userid=002

然后在最后一次请求时它应该显示错误消息。

基本代码如下:

$id = $_GET['userid'];
if (!isset($_GET['userid']) || empty($_GET['userid'])) {
    echo "Please enter the userid";
    die();
}

if (file_exists($userid.".txt") &&
        (filemtime($userid.".txt") > (time() - 3600 * $ttime ))) {
    $ffile = file_get_contents($userid.".txt");} else {
    $dcurl = curl_init();
    $ffile = fopen($userid.".txt", "w+");
    curl_setopt($dcurl, CURLOPT_URL,"http://remoteserver.com/data/$userid");
    curl_setopt($dcurl, CURLOPT_RETURNTRANSFER, TRUE);
    curl_setopt($dcurl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);
    curl_setopt($dcurl, CURLOPT_TIMEOUT, 50);
    curl_setopt($dcurl, CURLOPT_FILE, $ffile);
    $ffile = curl_exec($dcurl); 
    if(curl_errno($dcurl)) // check for execution errors
    {
        echo 'Script error: ' . curl_error($dcurl);
        exit;
    }
    curl_close($dcurl);
    $ffile = file_get_contents($userid.".txt");
}

最佳答案

您可以使用 session 机制来代替依赖 IP 地址。您可以通过 session_start() 创建 session 范围,然后存储与同一用户 session 相关的信息。

然后我会建议在此 session 范围内保留用户先前请求中使用的唯一 ID 列表以及请求时间,忽略任何重复的请求,这些请求始终是允许的。一旦此列表包含 5 个元素且时间戳在最后一分钟内并且请求新 ID,您将显示错误并拒绝查找。

这是执行此操作的代码。您应该在检查了 userid 参数之后,在检索文件内容之前将其放置:

// set the variables that define the limits:
$min_time = 60; // seconds
$max_requests = 5;

// Make sure we have a session scope
session_start();

// Create our requests array in session scope if it does not yet exist
if (!isset($_SESSION['requests'])) {
    $_SESSION['requests'] = [];
}

// Create a shortcut variable for this array (just for shorter & faster code)
$requests = &$_SESSION['requests'];

$countRecent = 0;
$repeat = false;
foreach($requests as $request) {
    // See if the current request was made before
    if ($request["userid"] == $id) {
        $repeat = true;
    }
    // Count (only) new requests made in last minute
    if ($request["time"] >= time() - $min_time) {
        $countRecent++;
    }
}

// Only if this is a new request...
if (!$repeat) {
    // Check if limit is crossed.
    // NB: Refused requests are not added to the log.
    if ($countRecent >= $max_requests) {
        die("Too many new ID requests in a short time");
    }   
    // Add current request to the log.
    $countRecent++;
    $requests[] = ["time" => time(), "userid" => $id];
}

// Debugging code, can be removed later:
echo  count($requests) . " unique ID requests, of which $countRecent in last minute.<br>"; 

// if execution gets here, then proceed with file content lookup as you have it.

已删除 session cookie...

session 由客户端上的 cookie 维护。用户可以删除此类 cookie,从而获得一个新 session ,这将允许用户发出新请求而无需考虑之前请求的内容。

解决这个问题的一种方法是为每个新 session 引入一个冷却期。例如,您可以让他们等待 10 秒,然后才能发出第一个请求。为此,请替换上面的代码:

if (!isset($_SESSION['requests'])) {
    $_SESSION['requests'] = [];
}

通过:

$initial_delay = 10; // 10 seconds delay for new sessions
if (!isset($_SESSION['requests'])) {
    $_SESSION['requests'] = array_fill(0, $max_requests,
        ["userid" => 0, "time" => time()-$min_time+$initial_delay] 
    );
}

这当然对用户不太友好,因为它会影响任何新 session ,也会影响那些不想通过删除 cookie 作弊的用户。

注册

更好的方法是只允许注册用户使用查找服务。为此,您必须提供用户数据库和身份验证系统(例如基于密码)。请求应记录在数据库中,以用户 ID 为关键字。如果随后开始新 session ,则用户必须首先再次进行身份验证,一旦通过身份验证,就会从数据库中检索请求历史记录。这样,用户就无法通过更改客户端配置(IP 地址、cookie、并行使用多个设备……)来作弊。

关于php - 如何限制一分钟内发出的用户请求数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34475376/

相关文章:

.htaccess - 我可以只使用服务器IP而不使用域名来运行网站吗?

mysql - ASP 连接 MYSQL 错误 80004005 "Can' t 连接到 'IP' 上的 MySQL 服务器”

python - URL 的最长前缀匹配

swift - 基本 URL(string,relativeTo) 未正确输出

php - 使用带有mysql查询结果的php获取父节点下的所有子节点、孙节点等节点

php - CSS 文件未使用 mod_rewrite 加载

Powershell-将WebRequest调用到其中带有文字 '/'(%2F)的URL

c - 在inet_pton 中使用什么地址?

php - Mysql 处理非英文字符输入,可以使用 phpMyAdmin 命令框,而不是通过 PHP

绝对路径的 PHP 文件大小