You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用PHP下载远程文件至服务器并输出至浏览器,实现缓存省带宽

Got it, let's solve this caching problem for your PHP file download script. The core goal is to avoid redundant remote downloads when multiple users request the same file, while still serving fresh content and handling concurrency properly. Here's a robust, production-ready approach:

PHP File Download with Server-Side Caching

Full Implementation Code

<?php
// Configuration
$cacheDir = __DIR__ . '/file_cache/'; // Cache storage directory
$cacheTTL = 86400; // Cache validity in seconds (1 day)
$remoteUrl = $_GET['url'] ?? ''; // Get remote URL from request (sanitize this in production!)

// Sanitize input (critical for security!)
if (empty($remoteUrl) || !filter_var($remoteUrl, FILTER_VALIDATE_URL)) {
    http_response_code(400);
    echo "Invalid or missing URL";
    exit;
}

// Create cache directory if it doesn't exist
if (!is_dir($cacheDir)) {
    mkdir($cacheDir, 0755, true);
}

// Generate unique cache filename (based on remote URL hash)
$cacheKey = md5($remoteUrl);
$cacheFile = $cacheDir . $cacheKey;
$lockFile = $cacheFile . '.lock';

// Function to wait for lock release (handle concurrency)
function waitForLock($lockFile, $maxAttempts = 10, $delay = 1) {
    $attempts = 0;
    while (file_exists($lockFile) && $attempts < $maxAttempts) {
        sleep($delay);
        $attempts++;
    }
    return !file_exists($lockFile);
}

// Check if cache is valid
$cacheIsValid = file_exists($cacheFile) && (time() - filemtime($cacheFile) < $cacheTTL);

if (!$cacheIsValid) {
    // Handle concurrent requests: wait for existing download to finish
    if (!waitForLock($lockFile)) {
        http_response_code(503);
        echo "Too many concurrent requests. Please try again later.";
        exit;
    }

    // Create lock file to block other requests
    touch($lockFile);

    try {
        // Download remote file to cache
        $remoteContent = file_get_contents($remoteUrl);
        if ($remoteContent === false) {
            throw new Exception("Failed to download remote file");
        }

        // Save to cache
        file_put_contents($cacheFile, $remoteContent);
    } catch (Exception $e) {
        // Clean up on failure
        if (file_exists($cacheFile)) unlink($cacheFile);
        http_response_code(500);
        echo "Error: " . $e->getMessage();
        exit;
    } finally {
        // Release lock
        if (file_exists($lockFile)) unlink($lockFile);
    }
}

// Get file info for proper headers
$fileSize = filesize($cacheFile);
$contentType = mime_content_type($cacheFile);

// Set headers to output file to user
header("Content-Type: $contentType");
header("Content-Length: $fileSize");
header("Content-Disposition: inline; filename=\"" . basename(parse_url($remoteUrl, PHP_URL_PATH)) . "\"");
header("Cache-Control: public, max-age=3600"); // Client-side cache

// Output the cached file
readfile($cacheFile);
exit;
?>

Key Features Explained

  • Secure Input Handling: Uses filter_var to validate the remote URL, preventing path traversal or invalid requests.
  • Concurrency Control: Uses a lock file to ensure only one request downloads the remote file at a time—other requests wait for the cache to be ready instead of starting duplicate downloads.
  • TTL-Based Caching: The $cacheTTL variable lets you control how long cached files stay valid (adjust based on how often the remote file updates).
  • Proper Header Management: Sends correct Content-Type, Content-Length, and Content-Disposition headers so browsers handle the file correctly (inline download or attachment).
  • Error Handling: Cleans up incomplete cache files and lock files if the remote download fails, avoiding corrupted cache entries.

Important Notes

  1. Permissions: Ensure the file_cache directory is writable by your web server user (e.g., www-data on Apache).
  2. Cache Cleanup: Add a cron job to delete old cache files periodically to save disk space. For example:
    # Delete cache files older than 7 days
    find /path/to/file_cache -type f -mtime +7 -delete
    
  3. Advanced Cache Validation: For files that update frequently, you could extend this to check the remote server's Last-Modified header and only re-download if the file has changed (use get_headers() to fetch remote headers).
  4. Large Files: If downloading very large files, replace file_get_contents with a stream-based approach (e.g., using fopen and fwrite in chunks) to avoid memory issues.

内容的提问来源于stack exchange,提问作者tagueule

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 04:24:41