【问题标题】:Limit upload speed per user with PHP or swfupload使用 PHP 或 swfupload 限制每个用户的上传速度
【发布时间】:2012-09-06 12:07:08
【问题描述】:

我有一个用 PHP 和 Yii 编写的 Web 应用程序,它允许用户使用 swfupload 上传图像和视频。有两种类型的用户:高级用户和普通用户。

我想限制普通用户的上传速度,但我找不到任何非全球性的方式。

能否限制 PHP、Yii 或 swfupload 每个用户的上传速度?

【问题讨论】:

    标签: php yii swfupload bandwidth-throttling


    【解决方案1】:

    php://input的流...

    不适用于 enctype="multipart/form-data"。

    如果您没有该限制,您可以注册一个流过滤器并在其上执行一些令牌桶,例如bandwidth-throttle/bandwidth-throttle

    use bandwidthThrottle\BandwidthThrottle;
    
    $in  = fopen("php://input", "r");
    $out = fopen(__DIR__ . "/upload.txt", "w");
    
    $throttle = new BandwidthThrottle();
    $throttle->setRate(100, BandwidthThrottle::KIBIBYTES); // Set limit to 100KiB/s
    $throttle->throttle($in);
    
    stream_copy_to_stream($in, $out);
    

    【讨论】:

      【解决方案2】:

      这里是下载的限速解决方案。您可以使用相同的上传。 .i.e.将文件读入较小的块,然后用睡眠上传每个块:)

      假设我们想要限制在 /images/ 文件夹中找到的图像的带宽。

      首先,我们需要一个带宽 php 脚本,我们在其中设置下载速度的限制。我们通过从请求的文件中读取小数据包来实现这一点,读取之间有一个超时:

      <?php
      //Enter the bandwidth here
      $bandwidth = '32'; // KB/s
      //For security reason, we will add here all the pattern that we allow for the filename
      //Change this to your own needs
      $allowed_file_patterns = array('/images\/(\w+)\.(jpg|gif|jpeg|png)/i');
       
      function getMimeType($file_path)
      {
          $mtype = '';
          if (function_exists('mime_content_type')){
              $mtype = mime_content_type($file_path);
          }
          elseif (function_exists('finfo_file')){
              $finfo = finfo_open(FILEINFO_MIME);
              $mtype = finfo_file($finfo, $file_path);
              finfo_close($finfo);
          } elseif (function_exists('getimagesize')){
              $finfo = @getimagesize($file_path);
              //var_dump($finfo);
              $mtype = !empty($finfo['mime'])?$finfo['mime']:'';
          }
          if ($mtype == ''){
                   $mtype = "application/force-download";
          }
          return $mtype;
      }
      $accepted_pattern = false;
      foreach ($allowed_file_patterns as $pattern){
          if (preg_match($pattern,$_GET['file'])){
              $accepted_pattern = true;
          }
      }
      if (!$accepted_pattern){
          //Stop the script if is not a valid access
          header("HTTP/1.1 403 Forbidden");
          echo 'Forbidden request';
          exit;
       
      }
       
      $fileName = $_GET['file'];
      $fh = @fopen($fileName,'rb');
      if (!$fh){
          echo 'Unable to open file';
          exit;
      }
      $fileSize = filesize($fileName);
      header("Content-Type: ".getMimeType($fileName));
      header("Content-Length: " . $fileSize);
      while(!feof($fh))
      {
          //Read the allowed bandwidth, and then just wait a second
          print(fread($fh, $bandwidth*1024));
          usleep(1000000);
      }
      fclose($fh);
      ?>
      

      现在,您可以创建一个 .htaccess 文件,将您需要限制的所有请求重定向到该带宽脚本:

      RewriteEngine on
      RewriteCond %{REQUEST_URI} \.(gif|jpg|jpeg|png|GIF|JPG|JPEG|PNG)$
      RewriteRule (.*) bandwidth.php?file=$1 [L]
      

      如果您愿意,您可以仅限制某些 ip 或某些引用的带宽。在 htaccess 文件中,您将拥有:

      RewriteEngine on
      

      在下面输入要限制的ip或ip类别,在它们之间用[OR]

      其他ip直接访问url,不经过bandwidth.php

      RewriteCond %{REMOTE_ADDR} ^123\.45\.6\.78$ [NC,OR]
      RewriteCond %{REMOTE_ADDR} ^127\.0\.0 [NC]
      RewriteCond %{REQUEST_URI} \.(gif|jpg|jpeg|png|GIF|JPG|JPEG|PNG)$
      RewriteRule (.*) bandwidth.php?file=$1 [L]
      

      在下面输入要限制的ip或ip类别,在它们之间用[OR]

      其他ip直接访问url,不经过bandwidth.php

      RewriteCond %{HTTP_REFERER} ^http://(www\.)?php-code.net/.*$ [NC,OR]
      RewriteCond %{HTTP_REFERER} ^http://(www\.)?example.com/.*$ [NC]
      RewriteCond %{REQUEST_URI} \.(gif|jpg|jpeg|png|GIF|JPG|JPEG|PNG)$
      RewriteRule (.*) bandwidth.php?file=$1 [L]
      

      通过这种方式,您可以限制来自 leecher 站点的流量,而不禁止它们,我认为这是一个更优雅的解决方案。

      【讨论】:

      • 谢谢你,但我不需要限制下载速度,如果可能的话,我需要限制每个用户的上传速度:)
      • 这就是主意。使用相同的上传。将文件拆分为多个较小的文件。然后上传每个块并将 sleep/usleep 放在那里
      • 很可能是因为您只是说使用相同的想法进行上传。我不知道您可以轻松地使用相同的想法进行上传,如何将文件拆分为您没有的部分。下载很容易,因为您控制文件,上传不同,因为用户控制文件。
      • @shail:我不知道如何应用您的解决方案。在获取整个文件之前,我不能只是“将文件拆分为多个较小的文件”。我们的想法不是尽可能快地获取整个文件。一旦用户发送带有文件的 POST 请求,我就不能只是“拆分”文件。
      • 是的,我已经通过 Perl 实现了。我在我的 php 脚本中使用了它。这是链接,使用它来上传块中的文件labs.consol.de/blog/misc/…
      猜你喜欢
      • 2014-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-24
      • 2011-09-10
      相关资源
      最近更新 更多