dongzhuo1498 2015-08-20 14:43
浏览 211
已采纳

无法获得实际的文件大小

I'm working on a class whose purpose is to restrict users to making only 10 requests within any 30 second period. It utilizes a file to maintain IP addresses, last request time. and the number of tries they've made. The problem is that, no matter what I try, I can't get the filesize. I've tried using clearstatcache(), and I've tried using a function I found in the comments on the filesize() page of the PHP manual.

Here's the code, in it's current debugging state.

// Makes sure user can only try to generate a coupon x number of times over x amount of seconds
class IpChecker{    
    const WAIT_TIME = 30; //seconds until user can try again
    const MAX_TRIES = 10; // maximum tries

    const COUPON_IP = 0;
    const COUPON_TIME = 1;
    const COUPON_TRIES = 2;

    private $ip_data;
    private $path;
    private $fh;
    private $safe;

    public function __construct(){
        clearstatcache();

        $this->path = realpath(dirname(__FILE__))."/ips/.ips";
        $this->fh = fopen($this->path,'w+');
        $this->filesize = $this->realfilesize($this->fh);
        echo "fs: ".$this->filesize; exit;


        $this->getIPs();
        $this->checkIP();
        $this->logRequest();
        fclose($this->fh);
        $this->safe || die(json_encode("You have exhausted all available tries. Please try again later."));
    }

    private function logRequest(){
        $str = "";
        foreach($this->ip_data as $data){
            foreach($data as $col){
                if(self::WAIT_TIME < (time() - $col[self::COUPON_TIME])) $str .= $col."\t";
            }
            $str = rtrim($str, '\t');
            $str .= "
";
        }
        $str = rtrim($str, '
');
        try{
            $fw = fwrite($this->fh, $str) || die(json_encode("Unable to check IP"));
        }catch(Exception $e){
            die(json_encode($e));
        }
    }

    private function checkIP(){     
        $IP = $_SERVER['REMOTE_ADDR'];
        $TIME = time();
        $safe = true;
        $user_logged = false;
        echo "<pre>"; var_dump($this->ip_data); exit;
        foreach($this->ip_data as $key=>$data){
            echo "<prE>"; var_dump($data); exit;
//          if($data[$key][self::COUPON_IP] == $IP){
//              $user_logged = true;
//              if(
//                  (($TIME - $data[$key][self::COUPON_TIME]) < self::WAIT_TIME) ||
//                  (self::MAX_TRIES >= $data[$key][self::COUPON_TRIES])
//              ) $safe = false;
//              $this->ip_data[$key][self::COUPON_TRIES] = $this->ip_data[$key][self::COUPON_TRIES]+1;
//              $this->ip_data[$key][self::COUPON_TIME] = $TIME;
//          }
        }
        if(!$user_logged){
            die("user not logged");
            $this->ip_data[] = array(
                self::COUPON_IP => $IP,
                self::COUPON_TIME => $TIME,
                self::COUPON_TRIES => 1
            );
        }
        $this->safe = $safe;
    }

    private function getIPs(){
        $IP_DATA = array();
        echo file_get_contents($this->path); exit;
        // this always returns 0. 
        $size = filesize($this->path);
        echo "filesize: ".$size; exit;
        if($size){
            $IPs = fread($this->fh,$size);
            $IP_ARR = explode("
",$IPs);
            foreach($IP_ARR as $line) $IP_DATA[] = explode("\t",$line);
        }
        $this->ip_data = $IP_DATA;
    }

    // Copied from the comments in the PHP Manual for filesize()
    public function realfilesize($fp) {
        $return = false;
        if (is_resource($fp)) {
            if (PHP_INT_SIZE < 8) {
                // 32bit
                if (0 === fseek($fp, 0, SEEK_END)) {
                    $return = 0.0;
                    $step = 0x7FFFFFFF;
                    while ($step > 0) {
                        if (0 === fseek($fp, - $step, SEEK_CUR)) {
                            $return += floatval($step);
                        } else {
                            $step >>= 1;
                        }
                    }
                }
            } elseif (0 === fseek($fp, 0, SEEK_END)) {
                // 64bit
                $return = ftell($fp);
            }
        }
        return $return;
    }
}

How can I get the real filesize? I'm on PHP 5.2.

  • 写回答

1条回答 默认 最新

  • dongyuanguang3893 2015-08-24 16:31
    关注

    I wasn;t able to figure out what was wrong with my code, if anythign, but I worked around it like this:

    /**
     * Makes sure user can only access a given page
     * x number of times over x amount of seconds.
     * If multiple instances of this class are used, the $namespace
     * properties for each should be unique.
     * Default wait time is 90 seconds while default request limit
     * is 10 tries.
     * 
     * -+ Usage +-
     * Just create the object with any parameters, no need to assign,
     * just make sure it's initialized at the top of the page:
     * new RequestThrottler;
     * 
     * -+- Parameters -+-
     * null RequestThrottler ( [ string $namespace [, int $WaitTime [, int $MaxTries ] ] ] )
     */
    class RequestThrottler{
        // settings
        private static $WAIT_TIME; // seconds until count expires
        private static $MAX_TRIES; // maximum tries
    
        // used to keep session variables unique
        // in the event that this class is used in multiple places.
        private $namespace;
    
        // for debugging
        const DBG = false;
    
        // array index constants
        const _TIME = 0;
        const _TRIES = 1;
    
        // defines whether or not access is permitted
        private $safe;
    
        // seconds until reset
        private $secs; 
    
        /**
         * -+- Constructor -+-
         * @param String $namespace - A unique prefix for SESSION data
         * @param Int $WaitTime - Total seconds before user can try again
         * @param Int $MaxTries - Total tries user can make until their request is denied
         */
        public function __construct($namespace='Throttler', $WaitTime=90, $MaxTries=10){
            // make sure a session is available
            if(!headers_sent() && !isset($_SESSION)) session_start();
            if(!isset($_SESSION)) die(json_encode("No session available"));
    
            // save settings
            $this->namespace = $namespace;
            self::$MAX_TRIES = $MaxTries;
            self::$WAIT_TIME = $WaitTime;
    
            // do the footwork
            $this->checkHistory();
    
            // if set to debug mode, print a short helpful string
            if(self::DBG) die(json_encode(
                    "You are ".($this->safe ? 'SAFE' : 'NOT SAFE')."! "
                    . "This is try number {$_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES]} of ".self::$MAX_TRIES.". "
                    . $this->secs." seconds since last attempt. "
                    . (self::$WAIT_TIME - $this->secs)." seconds until reset."
                ));
    
            // if not safe, kill the script, show a message
            $this->safe || die(json_encode("You're going too fast. Please try again in ".(self::$WAIT_TIME - $this->secs)." seconds."));
        }
    
        /**
         * -+- checkHistory -+-
         * Does the footwork to determine whether
         * or not to throttle the current user/request.
         */
        private function checkHistory(){
            $TIME = time();
            $safe = true;
    
            // make sure session is iniitialized
            if( !isset($_SESSION[$this->namespace.'_ATTEMPTS']) || 
                !isset($_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES]) || 
                !isset($_SESSION[$this->namespace.'_ATTEMPTS'][self::_TIME])   ) 
                    $_SESSION[$this->namespace.'_ATTEMPTS'] = array(
                        self::_TIME =>$TIME,
                        self::_TRIES => 1
                    );
            else $_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES] = 
                    $_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES]+1;
    
            // get seconds since last attempt
            $secondSinceLastAttempt = $TIME - $_SESSION[$this->namespace.'_ATTEMPTS'][self::_TIME];
    
            // reset the counter if the wait time has expired
            if($secondSinceLastAttempt  > self::$WAIT_TIME){
                $_SESSION[$this->namespace.'_ATTEMPTS'][self::_TIME] = $TIME;
                $_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES] = 1;
                $secondSinceLastAttempt  = 0;
            }
    
            // finally, determine if we're safe
            if($_SESSION[$this->namespace.'_ATTEMPTS'][self::_TRIES] >= self::$MAX_TRIES) $safe=false;
    
            // log this for debugging
            $this->secs = $secondSinceLastAttempt;
    
            // save the "safe" flag
            $this->safe = $safe;
        }
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 seatunnel-web使用SQL组件时候后台报错,无法找到表格
  • ¥15 fpga自动售货机数码管(相关搜索:数字时钟)
  • ¥15 用前端向数据库插入数据,通过debug发现数据能走到后端,但是放行之后就会提示错误
  • ¥30 3天&7天&&15天&销量如何统计同一行
  • ¥30 帮我写一段可以读取LD2450数据并计算距离的Arduino代码
  • ¥15 飞机曲面部件如机翼,壁板等具体的孔位模型
  • ¥15 vs2019中数据导出问题
  • ¥20 云服务Linux系统TCP-MSS值修改?
  • ¥20 关于#单片机#的问题:项目:使用模拟iic与ov2640通讯环境:F407问题:读取的ID号总是0xff,自己调了调发现在读从机数据时,SDA线上并未有信号变化(语言-c语言)
  • ¥20 怎么在stm32门禁成品上增加查询记录功能