防止PHP脚本被淹没

Posted

技术标签:

【中文标题】防止PHP脚本被淹没【英文标题】:Prevent PHP script from being flooded 【发布时间】:2012-04-14 16:37:27 【问题描述】:

我想防止我的脚本被淹没 - 如果用户按 F5,它每次都会执行脚本。

我想防止这种情况并允许每 2 秒执行一个脚本,有什么解决方案吗?

【问题讨论】:

我知道你已经选择了我的答案,但是......感觉想为你写一个改进的版本......查看更新脚本的答案 【参考方案1】:

您可以使用 memcache 来执行此操作..

简单的演示脚本

$memcache = new Memcache ();
$memcache->connect ( 'localhost', 11211 );
$runtime = $memcache->get ( 'floodControl' );

if ((time () - $runtime) < 2) 
    die ( "Die! Die! Die!" );
 

else 
    echo "Welcome";
    $memcache->set ( "floodControl", time () );

这只是一个示例代码..还有其他需要考虑的事情,例如

A.更好的IP地址检测(Proxy、Tor)

B.当前操作

C.每分钟最大执行次数等...

D.在最大洪水等后禁止用户

编辑 1 - 改进版

用法

$flood = new FloodDetection();
$flood->check();

echo "Welcome" ;

class FloodDetection 
    const HOST = "localhost";
    const PORT = 11211;
    private $memcache;
    private $ipAddress;

    private $timeLimitUser = array (
            "DEFAULT" => 2,
            "CHAT" => 3,
            "LOGIN" => 4 
    );
    private $timeLimitProcess = array (
            "DEFAULT" => 0.1,
            "CHAT" => 1.5,
            "LOGIN" => 0.1 
    );

    function __construct() 
        $this->memcache = new Memcache ();
        $this->memcache->connect ( self::HOST, self::PORT );
    

    function addUserlimit($key, $time) 
        $this->timeLimitUser [$key] = $time;
    

    function addProcesslimit($key, $time) 
        $this->timeLimitProcess [$key] = $time;
    

    public function quickIP() 
        return (empty ( $_SERVER ['HTTP_CLIENT_IP'] ) ? (empty ( $_SERVER ['HTTP_X_FORWARDED_FOR'] ) ? $_SERVER ['REMOTE_ADDR'] : $_SERVER ['HTTP_X_FORWARDED_FOR']) : $_SERVER ['HTTP_CLIENT_IP']);
    

    public function check($action = "DEFAULT") 
        $ip = $this->quickIP ();
        $ipKey = "flood" . $action . sha1 ( $ip );

        $runtime = $this->memcache->get ( 'floodControl' );
        $iptime = $this->memcache->get ( $ipKey );

        $limitUser = isset ( $this->timeLimitUser [$action] ) ? $this->timeLimitUser [$action] : $this->timeLimitUser ['DEFAULT'];
        $limitProcess = isset ( $this->timeLimitProcess [$action] ) ? $this->timeLimitProcess [$action] : $this->timeLimitProcess ['DEFAULT'];

        if ((microtime ( true ) - $iptime) < $limitUser) 
            print ("Die! Die! Die! $ip") ;
            exit ();
        

        // Limit All request
        if ((microtime ( true ) - $runtime) < $limitProcess) 
            print ("All of you Die! Die! Die! $ip") ;
            exit ();
        

        $this->memcache->set ( "floodControl", microtime ( true ) );
        $this->memcache->set ( $ipKey, microtime ( true ) );
    


【讨论】:

我正在考虑投票。直到你使用那个 Singleton 的那一刻。 haaaa.. 我会立即更改它.. +1 感谢您的观察 @truth .. 还有一件事 .. 你为什么认为 Singleton 是个坏主意 .. 举个例子... 单例对静态类或实例对象没有任何好处。他们只会施加约束,并且在项目的后期阶段会遇到麻烦。难以测试,难以维护代码(紧密耦合等等等等)。 Read all about it【参考方案2】:
    将脚本的最后执行时间存储在数据库或 文件。 从该文件/数据库中读取并与当前时间进行比较。 如果差值小于 2 秒,则终止脚本。 否则,正常继续。

【讨论】:

我应该为此使用会话吗? 如果用户不保留 cookie,您的会话将毫无用处,脚本也不会限制。【参考方案3】:

您可以使用 cookie(可以禁用)所以这不是一个好主意,或者您可以使用将他的 IP 地址存储在数据库中,所以如果 X 尝试从同一个 IP 地址尝试更多,则不要执行代码,只是一个 if else 语句,您将需要一个带有 ip 地址的表,其中包含请求时间、尝试次数

如果您不想使用数据库,则可以使用以下代码

$file = "file.txt";
$file_content = file_get_contents($file);
$fh = fopen($file, 'w') or die("could not open file");
$now = time();
if($now - $file_content > 60)
// your code here
fwrite($fh, $now);
else
echo "Try again later";

fclose($fh);

但在这种情况下,它不是针对每个访问者,而是针对所有访问者(假设用户 A 来执行脚本,用户 B 将无法执行它,直到 60 秒过去。

【讨论】:

【参考方案4】:

最好的方法是将时间存储在服务器端。如果您将信息留在客户端,则很容易绕过。

例如,我会将时间戳保存在表格中。该输入并检查是否向您的脚本发送垃圾邮件。并且很容易设置公差。

【讨论】:

【参考方案5】:

使用 apc 缓存或 mencache 将信息存储到数据库或从文件中读取我认为是时间/资源消耗

【讨论】:

以上是关于防止PHP脚本被淹没的主要内容,如果未能解决你的问题,请参考以下文章

使用php邮件功能防止发送的电子邮件被视为垃圾邮件

如何防止一个高度相关的变量淹没 scikit-learn 中的其余变量?

如何防止 imagecreatefrom 创建静态 gif - PHP

如何防止使用php自动多次点击网站?

PHP如何防止邮件在标头中泄漏脚本和IP

从 php 提供图像时如何防止脚本名称附加到图像文件扩展名