用户将通过script.php?userid=222
之类的网址按号码请求文件。此示例将显示文件#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");
}
答案 0 :(得分:11)
您可以使用会话机制,而不是依赖IP地址。您可以通过session_start()
创建会话范围,然后存储使用相同用户会话的信息。
然后,我建议在此会话范围中保留用户先前请求中使用的唯一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.
会话由客户端上的cookie维护。用户可以删除此类cookie,以便获得新会话,这将允许用户在不考虑先前请求的情况下发出新请求。
解决这个问题的一种方法是为每个新会话引入一个冷静期。例如,您可以让他们等待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]
);
}
这当然不太方便用户,因为它会影响任何新会话,也会影响那些不想通过删除cookie来欺骗的用户。
更好的方法是只允许注册用户查找服务。为此,您必须提供用户数据库和身份验证系统(例如基于密码)。请求应记录在数据库中,并由用户的ID键入。如果然后新会话开始,则用户必须首先再次进行身份验证,并且一旦经过身份验证,就会从数据库中检索请求历史记录。这样,用户就不能通过更改客户端配置(IP地址,cookie,并行使用多个设备,......)来欺骗它。
答案 1 :(得分:0)
<?php
// session_start();
// session_destroy();
// exit;
echo index();
function index()
{
$id = rand(000,020);
$min_time = 60;
$max_requests = 5;
// $id = 0;
session_start();
$repeat = false;
if(!isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"]) && !isset($_SESSION["countRecent"])){
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
$_SESSION['userid'][] = $id;
}else{
if ($_SESSION["countRecent"] >= $max_requests) {
if(!in_array($id,$_SESSION['userid'])){
if ($_SESSION["time"] <= time() - $min_time) {
$_SESSION["countRecent"] = 1;
$_SESSION["time"] = time();
}else{
return("Too many requests in a short time wait ". ( $_SESSION["time"] - (time() - $min_time) )). " Seconds";
}
}
}else{
if(!in_array($id,$_SESSION['userid'])){
$_SESSION["countRecent"] = $_SESSION["countRecent"] + 1;
$_SESSION['userid'][] = $id;
}
}
}
return "Your Result goes here.. id: $id Counts: ". $_SESSION["countRecent"];
}
试试这个。 快,低内存使用
但不安全;
也使用数据库
<?php
$conn = mysqli_connect("localhost", "root", "","db_name") or die("Could not connect database");
$id = rand(0,99);
// $id = 100;
echo index($id);
function index($id,$user=1,$ip='192.168.0.10',$max_requests = 5,$min_time = 20)
{
global $conn;
$time = time();
$req = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=req+1;";
$req2 = "INSERT INTO `limit_api_by_ip2`(`id`, `ip`, `time`, `user`, `req`)
VALUES (null,INET_ATON('$ip'),'$time','$user',1)
ON DUPLICATE KEY UPDATE req=1,`time`='".time()."' ;";
$reqid = "INSERT INTO `limit_api_by_ip2_count`(`id`, `user`, `ids`) VALUES (null,'$user',$id)";
$getid = "SELECT `ids` FROM `limit_api_by_ip2_count` WHERE user = $user and ids = $id limit 1;";
$gettime = "SELECT `time`,`req` FROM `limit_api_by_ip2` WHERE user = $user and ip = INET_ATON('$ip') limit 1;";
// $id = 0;
$q = mysqli_query($conn,$getid);
$c = mysqli_num_rows($q);
if($c==0){
$get_time = mysqli_query($conn,$gettime);
$c1 = mysqli_num_rows($get_time);
if($c1==0){
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}else{
$row = mysqli_fetch_row($get_time);
if ($row[1] >= $max_requests) {
if ($row[0] <= (time() - $min_time)) {
mysqli_query($conn,$req2);
mysqli_query($conn,$reqid);
}else{
return "Too many requests in a short time wait ".($row[0]-(time() - $min_time))." Seconds";
}
}else{
mysqli_query($conn,$req);
mysqli_query($conn,$reqid);
}
}
}else{
}
if(isset($row[1]))
{
$cc = "Counts: ".$row[1];
$dd = "new id: $id";
}else{
$cc = '';
$dd = "old id: $id";
}
return "Your Result goes here.. $dd ".$cc;
}