无法获取实际文件大小

Can't get actual filesize

我正在开发一个 class,其目的是限制用户在任何 30 秒内只能发出 10 次请求。它使用一个文件来维护 IP 地址、上次请求时间。以及他们所做的尝试次数。问题是,无论我尝试什么,我都无法获取文件大小。我试过使用 clearstatcache(),我试过使用我在 PHP 手册的 filesize() 页面的评论中找到的函数。

这是代码,处于当前调试状态。

// 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 .= "\n";
        }
        $str = rtrim($str, '\n');
        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("\n",$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;
    }
}

如何获得真实的文件大小?我在 PHP 5.2.

我无法弄清楚我的代码有什么问题,如果有的话,但我是这样解决的:

/**
 * 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;
    }
}