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

PHP 下載遠端圖片並儲存本地的 5 種實戰方案總結

     編輯:PHP 相關知識

PHP 遠端圖片下載與本地化儲存完整指南

在內容聚合、編輯器圖片自動儲存、爬蟲等場景中,將遠端圖片下載至本地伺服器是常見需求。本文整理 5 種不同層級的實作方案,從簡單的單張下載到支援斷點續傳的完整類庫,並分析各方案適用場景與效能考量。

方案一:基於 fsockopen 取得檔案大小與 Header 資訊

適合下載前預檢檔案大小、類型,避免下載超大或非預期檔案。

function getFileSize($url) {
    $parsed = parse_url($url);
    $host = $parsed['host'];
    $port = $parsed['port'] ?? 80;
    $path = $parsed['path'] ?? '/';
    if ($fp = @fsockopen($host, $port, $errno, $errstr, 5)) {
        fputs($fp, "GET $path HTTP/1.1\r\nHost: $host\r\n\r\n");
        while (!feof($fp)) {
            $line = fgets($fp);
            if (trim($line) === '') break;
            if (preg_match('/Content-Length:\s*(\d+)/i', $line, $m)) {
                return (int)$m[1];
            }
        }
    }
    return null;
}

方案二:readfile + output buffering 單張圖片下載

最常見的簡易做法,利用輸出緩衝捕獲二進位資料再寫入檔案。

function grabImage($url, $filename = '') {
    if (!$url) return false;
    if (!$filename) {
        $ext = strrchr($url, '.');
        if (!in_array(strtolower($ext), ['.gif', '.jpg', '.jpeg', '.png'])) return false;
        $filename = date('YmdHis') . $ext;
    }
    ob_start();
    readfile($url);
    $img = ob_get_clean();
    file_put_contents($filename, $img);
    return $filename;
}

方案三:批量解析 HTML 內容中的圖片並下載

適用於文章內容本地化,配合正則提取 src 屬性,逐一下載並替換路徑。

function saveRemoteImages(&$body, $saveDir) {
    preg_match_all('/src\s*=\s*["\']?(https?:\/\/[^"\'>\s]+\.(?:gif|jpg|jpeg|png|bmp))/i', $body, $matches);
    $urls = array_unique($matches[1]);
    $dateDir = $saveDir . '/' . date('Ymd');
    if (!is_dir($dateDir)) mkdir($dateDir, 0777, true);
    foreach ($urls as $i => $url) {
        $ext = pathinfo($url, PATHINFO_EXTENSION);
        $newName = date('His') . $i . '.' . $ext;
        $localPath = $dateDir . '/' . $newName;
        if ($data = @file_get_contents($url)) {
            file_put_contents($localPath, $data);
            $body = str_replace($url, $localPath, $body);
        }
    }
}

方案四:支援斷點續傳的 HttpDownload 類別

針對大檔案下載,實作 HTTP Range 請求、頻寬控制、進度追蹤,適合建立下載站或大型素材庫。

class HttpDownload {
    public $use_resume = true;
    public $bufsize = 8192;
    public $speed = 0; // KB/s, 0 = 不限速
    private $filePath;
    private $fileSize;
    public function set_byfile($path) {
        if (!is_readable($path)) return false;
        $this->filePath = $path;
        $this->fileSize = filesize($path);
        return true;
    }
    public function download() {
        if (!$this->filePath) return false;
        $fp = fopen($this->filePath, 'rb');
        $start = 0; $end = $this->fileSize - 1;
        if ($this->use_resume && isset($_SERVER['HTTP_RANGE'])) {
            list(, $range) = explode('=', $_SERVER['HTTP_RANGE']);
            list($start, $end) = array_map('intval', explode('-', $range));
            if ($end == 0 || $end > $this->fileSize - 1) $end = $this->fileSize - 1;
            header('HTTP/1.1 206 Partial Content');
            header("Content-Range: bytes $start-$end/{$this->fileSize}");
        }
        header('Content-Type: application/octet-stream');
        header('Content-Disposition: attachment; filename="' . basename($this->filePath) . '"');
        header("Content-Length: " . ($end - $start + 1));
        header('Accept-Ranges: bytes');
        fseek($fp, $start);
        while (!connection_aborted() && $start <= $end) {
            $read = min($this->bufsize, $end - $start + 1);
            echo fread($fp, $read);
            flush();
            $start += $read;
            if ($this->speed && ftell($fp) % (1024 * $this->speed) === 0) sleep(1);
        }
        fclose($fp);
    }
}
// 使用範例
$dl = new HttpDownload();
$dl->set_byfile('/data/large.zip');
$dl->download();

方案五:GD 庫建立圖片副本(可順便縮圖、加浮水印)

若需在下載時同步處理圖片(縮放、裁切、加浮水印),可透過 GD 讀取遠端圖片資源。

$src = imagecreatefromjpeg('https://example.com/photo.jpg');
$w = imagesx($src); $h = imagesy($src);
$dst = imagecreatetruecolor($w, $h);
imagecopy($dst, $src, 0, 0, 0, 0, $w, $h);
imagejpeg($dst, 'local_copy.jpg', 90);
imagedestroy($src); imagedestroy($dst);

注意: GD 讀取遠端圖片需啟用 allow_url_fopen,且受 memory_limit 限制,大圖建議改用方案四或 Imagick 串流處理。

方案選擇建議

  • 簡單單張下載:方案二
  • 文章內容圖片本地化:方案三
  • 大檔案/需斷點續傳:方案四
  • 下載同時處理圖片:方案五
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved