首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP限制文件下載速度:流量控制、防盜鏈、公平帶寬分配實戰

     編輯:PHP 相關知識

下載限速:從簡單 sleep 到 Token Bucket 算法的工程化演進

場景:會員免費下載限速 100KB/s,VIP 不限速;防止單用戶佔滿帶寬;實現公平隊列。

方案一:基礎固定塊 + sleep(教學用)

<?php
function downloadThrottled(string $file, float $kbps = 100): void {
    if (!is_file($file)) { http_response_code(404); exit; }
    $fp = fopen($file, 'rb');
    $chunk = 1024 * round($kbps); // 每秒塊大小
    header('Content-Type: application/octet-stream');
    header('Content-Length: ' . filesize($file));
    header('Content-Disposition: attachment; filename="' . basename($file) . '"');
    while (!feof($fp)) {
        echo fread($fp, $chunk);
        @ob_flush(); @flush();
        sleep(1); // 硬性睡眠 1 秒
    }
    fclose($fp);
}

缺陷:精度差(網絡延遲不計入)、阻塞進程、無法應對併發、CPU 空轉。

方案二:Token Bucket (令牌桶) 平滑限速(生產推薦)

<?php
class TokenBucket {
    public function __construct(
        private float $rate,   // tokens per second (bytes/s)
        private float $burst   // max bucket size (bytes)
    ) {
        $this->tokens = $burst;
        $this->last = microtime(true);
    }

    public function consume(int $bytes): float {
        $now = microtime(true);
        $since = $now - $this->last;
        $this->tokens = min($this->burst, $this->tokens + $since * $this->rate);
        $this->last = $now;

        if ($this->tokens >= $bytes) {
            $this->tokens -= $bytes;
            return 0; // 即時發送
        }
        $wait = ($bytes - $this->tokens) / $this->rate;
        $this->tokens = 0;
        return $wait; // 需等待秒數
    }
}

function downloadSmooth(string $file, float $kbps = 100): void {
    if (!is_file($file)) { http_response_code(404); exit; }
    $bucket = new TokenBucket($kbps * 1024, $kbps * 1024 * 2); // 允許 2 秒突發
    $fp = fopen($file, 'rb');
    $chunkSize = 16 * 1024; // 16KB 塊
    header('Content-Type: application/octet-stream');
    header('Content-Length: ' . filesize($file));
    header('Content-Disposition: attachment; filename="' . basename($file) . '"');
    while (!feof($fp)) {
        $data = fread($fp, $chunkSize);
        $wait = $bucket->consume(strlen($data));
        if ($wait > 0) usleep($wait * 1_000_000);
        echo $data;
        @ob_flush(); @flush();
    }
    fclose($fp);
}

方案三:Nginx `limit_rate` 併發級限速(最佳性能)

# nginx.conf
location /download/ {
    # 根據用戶等級設置變量 $limit_rate
    # 免費用戶 100k,VIP 0(不限速)
    set $limit_rate $limit_rate_var;
    limit_rate_after 1m;  # 前 1MB 不限速,體驗更好
    internal;             # 僅內部重定向訪問
    alias /var/www/files/;
}

# PHP 僅驗證權限並簽發簽名 URL
header('X-Accel-Redirect: /download/secret.zip');
header('X-Accel-Limit-Rate: 102400'); # 100KB/s
exit;

方案對比

防盜鏈簽名 URL 生成

function signDownloadUrl(string $file, int $userId, int $ttl = 3600): string {
    $secret = 'your-secret-key';
    $expire = time() + $ttl;
    $data = "$file|$userId|$expire";
    $sig = hash_hmac('sha256', $data, $secret);
    return "/download/$file?uid=$userId&exp=$expire&sig=$sig";
}
// Nginx ngx_http_auth_request_module 或 Lua 腳本驗證簽名

結論:**業務邏輯(權限/等級)在 PHP 判斷,流量控制交給 Nginx**,架構最清晰、性能最強。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
方案精度併發性能實現複雜度推薦場景
PHP sleep低差(阻塞進程)極簡極低併發、臨時腳本
PHP Token Bucket高(ms級)中(佔用 PHP 進程)中中等併發、需邏輯控制(會員等級)
Nginx limit_rate高極佳(內核態)低(配置)高併發、生產環境首選