How to limit speed of outgoing response from php s

2019-07-16 00:41发布

问题:

How to limit speed of outgoing response from php script? So I have a script generating data in keep-alive connection. It just opens file and reads it. How to limit outgoing speed

(By now i have such code)

if(isset($_GET[FILE]))
 {
  $fileName = $_GET[FILE];
  $file =  $fileName;

  if (!file_exists($file))
  {
   print('<b>ERROR:</b> php could not find (' . $fileName . ') please check your settings.'); 
   exit();
  }
  if(file_exists($file))
  {
   # stay clean
   @ob_end_clean();
   @set_time_limit(0);

   # keep binary data safe
   set_magic_quotes_runtime(0);

   $fh = fopen($file, 'rb') or die ('<b>ERROR:</b> php could not open (' . $fileName . ')');
   # content headers
   header("Content-Type: video/x-flv"); 

   # output file
   while(!feof($fh)) 
   {
     # output file without bandwidth limiting
     print(fread($fh, filesize($file))); 
   } 
  } 
 }

So what shall I do to limit speed of response (limit to for example 50 kb/s)

回答1:

Change your file output to be staggered rather that outputting the whole file in one go.

# output file
while(!feof($fh)) 
{
    # output file without bandwidth limiting
    print(fread($fh, 51200)); # 51200 bytes = 50 kB
    sleep(1);
}

This will output 50kB then wait one second until the whole file is output. It should cap the bandwidth to around 50kB/second.

Even though this is possible within PHP, I'd use your web-server to control the throttling.



回答2:

I wouldn't use php to limit the bandwidth:

For Apache: Bandwidth Mod v0.7 (How-To - Bandwidth Limiter For Apache2)

For Nginx: http://wiki.nginx.org/NginxHttpCoreModule#limit_rate

For Lighttpd: http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:TrafficShaping This even allows you to configure the speed per connection in PHP



回答3:

You can read n bytes and then use use sleep(1) to wait a second, as suggested here.



回答4:

I think the method of 'Ben S' and 'igorw' is wrong because they imply unlimited bandwidth which is a false assumption. Basically a script that says

while(!feof($fh)) {
   print(fread($fh, $chunk_size));
   sleep(1);
}

will pause for a second after outputting $chunk_size number of bytes regardless of how long it took. If for example if your current throughput is 100kb and you want to stream at 250kb, the script above will take 2.5 seconds to do the print() and then wait yet another second, effectively pushing the real bandwidth down to around 70kb.

The solution should either measure the time it took for PHP to complete the print() statemnt or use a buffer and call flush with every fread(). The first approach would be:

list($usec, $sec) = explode(' ', microtime());
$time_start = ((float)$usec + (float)$sec);
# output packet
print(fread($fh, $packet_size));
# get end time
list($usec, $sec) = explode(' ', microtime());
$time_stop = ((float)$usec + (float)$sec);
# wait if output is slower than $packet_interval
$time_difference = $time_stop - $time_start;
if($time_difference < (float)$packet_interval) {
    usleep((float)$packet_interval*1000000-(float)$time_difference*1000000);
}

while the second would be something like:

ob_start();
while(!feof($fh)) {
       print(fread($fh, $chunk_size));
       flush();
       ob_flush();
       sleep(1);
    }


回答5:

You could attach a bandwidth-throttle/bandwidth-throttle to a stream:

use bandwidthThrottle\BandwidthThrottle;

$in  = fopen(__DIR__ . "/resources/video.mpg", "r");
$out = fopen("php://output", "w");

$throttle = new BandwidthThrottle();
$throttle->setRate(500, BandwidthThrottle::KIBIBYTES); // Set limit to 500KiB/s
$throttle->throttle($out);

stream_copy_to_stream($in, $out);