我正在我的项目中实现ip禁止功能。 首先,我想为此目的避免.htaccess'因为CMS可能会在修改时重置它,所以我必须使用PHP-send-header-and-die解决方案。 显然,将检查每个HTTP请求。
考虑到流量高的网站,我有两个存储ip禁止信息的解决方案:
1 - 在一个目录中,让我们说/禁止/,我可以创建N个文件,其中N =被禁止的ips数量,所以:
/bans/23.23.23.23.ban
将禁止23.23.23.23,在这种情况下,我必须从我的脚本中做的是检查 file_exists ,例如:
<?php
if( file_exists("bans/".$_SERVER['REMOTE_ADDR'].".ban"){
header("HTTP/1.0 403 Forbidden");
die();
}
else{
// Continue surfing ....
}
?>
2 - 使用MySQL表,比方说cms_bans,并为每个HTTP请求执行一次SELECT,以检查ip是否在禁止列表中。
考虑到这两个解决方案,哪个具有较少的过载影响(文件系统vs mysql:D),假设MySQL查询缓存被禁用?
请仅提供积极的答案,而不仅仅是个人喜好。
由于
答案 0 :(得分:1)
将MySQL表与MEMORY引擎一起使用。每隔一段时间将它转储到另一个永久表中,以便在服务器重启后保存IP并保持持久性。
答案 1 :(得分:0)
我倾向于认为file_exists()的开销较小,因为没有远程连接,PHP可以缓存它。但是如果你有大量的禁令,并且已经为应用程序的其他部分进行了数据库连接,那么MySQL解决方案开始变得更好,并且更容易管理。也就是说,我不喜欢这两种方法,并建议通过防火墙/代理/负载均衡器将禁令移至网络层。
或者,如果您没有大量的禁令并且它们不经常更改,那么最好将列表直接存储为PHP数组,在代码中包含()然后使用in_array()扫描禁令:
$banned = array(
'1.2.3.4',
'2.3.4.5',
'3.4.5.6'
);
if (in_array($ip, $banned)) { baninate(); }
答案 2 :(得分:0)
我更喜欢mysql数据库。您可以在表格中存储其他数据,例如banned_by
,banned_on
,bann_reason
和access_count
。
在您的代码中,您只能执行
SELECT COUNT(1) FROM banns WHERE ip = '23.23.23.23'
假设您在ip列上有索引,这应该非常快。如果有人点击禁令,你会做一个
UPDATE banns SET access_count = access_count + 1 WHERE ip = '23.23.23.23'
答案 3 :(得分:0)
为什么坚持使用另一个?
我会建立一个基于MySQL的禁令表,我可以轻松扩展。 MySQL是一个快速的系统,更加灵活,牢记未来。
但是,您也可以将结果自己缓存在一个文件中并从中读取。现在,任何熟悉MySQL的人都可以直接添加禁令,他们不必知道你的特殊格式就可以直接使用它(在你的禁止系统的扩展,使用它等的情况下)。那么,这里的问题是文件权限。所以,你只需要投入一些额外的代码来弥补这一点。
如果他们需要更新缓存,请给他们能力。
答案 4 :(得分:0)
你没有说你正在使用什么CMS,但是如果是开源或你自己为什么不修改它以使用.htaccess禁止?
答案 5 :(得分:0)
我认为这个问题与表现无关 与应用程序的其他部分相比,这种简单的键值查找永远不会成为瓶颈 这是经常犯的错误:人们倾向于优化网站中资源消耗较少的部分,没有任何特殊原因,但是因为它只是出现在他们的脑海中。
这就是为什么问题应该受到激励,而不仅仅是出于个人偏好。
答案 6 :(得分:-2)
就您的原始问题而言,使用file_exists()
对于少量禁令(约<1000禁令)更快,而对于较大数量使用MySQL则更快。连接只对数据库进行一次,答案只返回一次,因此MySQL的“瓶颈”只会在执行查询所需的时间内增加一组固定的时间。 MySQL(和其他数据库)软件然后非常好地扩展,因为每行有一个恒定的字节宽度,所以它只需要检查字节nRX到nRX + Y的整数倍n。
在较旧的文件系统中,操作系统可以不进行此类假设,因为文件的长度可以变化。因此,它将扫描end_of_file
位。较新的操作系统在分区的开头创建每个文件的数据库(“文件分配表”),它只需要搜索它。问题是 - 计算机上的文件越多,搜索此表所需的时间就越长。此外,如果文件仍然存在,驱动器碎片会使查找更加困难。这些小的减速并不等于连接到SQL数据库所需的时间......对于少量的禁令。
更好的解决方案是让每行包含一个禁令的文本文件。
bans.txt:
23.23.23.23
192.168.1.42
200.200.200.200
然后你只需使用strpos($file_contents, $_SERVER["REMOTE_ADDR"]
。请注意,由于PHP的C后端比解释快约100倍,所以PHP的行数越少,最终运行的速度就越快。因此,在两行中我们可以get_file_contents()
(将内容转储到RAM)和strpos()
(在RAM中搜索一个字符串)并且它完全由C后端处理,它很快地迭代。
如果你愿意编写自己的数据库来保存禁止数字的禁令(允许二进制搜索),那么甚至还有更快的方法。
虽然有几个人已经说过,但不,您的服务器中会出现任何主要瓶颈。优化您网站的“禁止检查”部分将使整个网站的速度提高0.01%。你想要非常小心地优化的是运行> 100次的循环,对远程服务器的调用,以及返回要解析的数据库的几行的查询。
另外,不要编写一个函数来执行已经内置PHP函数的函数。在学习如何使用substr(strpos())
preg_replace()
行的字符串