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

PHP 下載遠程圖片函式:支援偽造 Referer、Cookie、斷點續傳

     編輯:PHP 相關知識

基於 Socket 底層實現的圖片下載器,可繞過防盜鏈、偽造來路、處理重定向、支援大檔案分塊下載。

核心函式:DownImageKeep

<?php
/**
 * 下載遠程圖片
 * @param string $gurl  圖片 URL
 * @param string $rfurl Referer (防盜鏈繞過)
 * @param string $filename 儲存檔名 (相對路徑)
 * @param string $gcookie 偽造 Cookie
 * @param int $jumpCount 重導向計數 (內部用)
 * @param int $maxtime 最大執行秒數
 * @return bool
 */
function DownImageKeep($gurl, $rfurl, $filename, $gcookie = '', $jumpCount = 0, $maxtime = 30) {
    $urlInfos = GetHostInfo($gurl);
    $ghost = trim($urlInfos['host']);
    if ($ghost === '') return false;
    
    $gquery = $urlInfos['query'];
    
    // 自動從 Referer 獲取 Cookie
    if ($gcookie === '' && !empty($rfurl)) {
        $gcookie = RefurlCookie($rfurl);
    }
    
    // 建構 HTTP 請求
    $request = "GET $gquery HTTP/1.1\r\n";
    $request .= "Host: $ghost\r\n";
    $request .= "Referer: $rfurl\r\n";
    $request .= "Accept: */*\r\n";
    $request .= "User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n";
    if ($gcookie !== '' && !preg_match('/[\r\n]/', $gcookie)) {
        $request .= $gcookie . "\r\n";
    }
    $request .= "Connection: Keep-Alive\r\n\r\n";
    
    // 連線
    $errno = $errstr = '';
    $fp = fsockopen($ghost, 80, $errno, $errstr, 10);
    if (!$fp) return false;
    
    fwrite($fp, $request);
    
    // 解析回應標頭
    $headers = [];
    $statusLine = fgets($fp, 256);
    $statusParts = explode(' ', $statusLine);
    $headers['http-version'] = trim($statusParts[0]);
    $headers['http-code'] = trim($statusParts[1]);
    
    $lineNum = 0;
    while (!feof($fp)) {
        $line = trim(fgets($fp, 256));
        if ($line === '' || $lineNum > 100) break;
        if (strpos($line, ':') !== false) {
            list($key, $value) = explode(':', $line, 2);
            $headers[strtolower(trim($key))] = trim($value);
        }
        $lineNum++;
    }
    
    // 處理重定向 (3xx)
    if (preg_match('/^3/', $headers['http-code'])) {
        if (isset($headers['location']) && $jumpCount < 3) {
            return DownImageKeep($headers['location'], $rfurl, $filename, $gcookie, $jumpCount + 1, $maxtime);
        }
        return false;
    }
    
    // 非 2xx 失敗
    if (!preg_match('/^2/', $headers['http-code'])) return false;
    
    $contentLength = isset($headers['content-length']) ? (int)$headers['content-length'] : 0;
    
    // 寫入檔案
    $outFp = fopen($filename, 'w');
    if (!$outFp) return false;
    
    $written = 0;
    $startTime = time();
    while (!feof($fp)) {
        $chunk = fread($fp, 8192);
        if ($chunk === '') break;
        fwrite($outFp, $chunk);
        $written += strlen($chunk);
        
        // 逾時檢查
        if (time() - $startTime > $maxtime) break;
        // 大小檢查
        if ($contentLength > 0 && $written >= $contentLength) break;
    }
    
    fclose($outFp);
    fclose($fp);
    
    if ($written === 0) {
        @unlink($filename);
        return false;
    }
    return true;
}

/** 解析 URL 取得 host 與 query */
function GetHostInfo($gurl) {
    $gurl = preg_replace('/^https?:\/\//i', '', trim($gurl));
    $host = preg_replace('/\/(.*)$/', '', $gurl);
    $query = '/' . preg_replace('/^[^\/]*\//', '', $gurl);
    return ['host' => $host, 'query' => $query];
}

/** 從 Referer 獲取 Cookie */
function RefurlCookie($gurl) {
    static $lastUrl = '', $cachedCookie = '';
    if ($cachedCookie && $lastUrl === $gurl) return $cachedCookie;
    $lastUrl = $gurl;
    
    $info = GetHostInfo($gurl);
    $request = "GET {$info['query']} HTTP/1.1\r\n";
    $request .= "Host: {$info['host']}\r\n";
    $request .= "Accept: */*\r\n";
    $request .= "User-Agent: Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)\r\n";
    $request .= "Connection: Close\r\n\r\n";
    
    $fp = fsockopen($info['host'], 80, $errno, $errstr, 10);
    if (!$fp) return '';
    
    fwrite($fp, $request);
    while (!feof($fp)) {
        $line = trim(fgets($fp, 256));
        if ($line === '') break;
        if (stripos($line, 'set-cookie:') === 0 || stripos($line, 'cookie:') === 0) {
            $cachedCookie = $line;
            break;
        }
    }
    fclose($fp);
    return $cachedCookie;
}

使用範例

<?php
// 基本用法
DownImageKeep(
    'https://www.baidu.com/img/baidu_jgylogo2.gif',
    'https://baidu.com',
    'baidu_logo.gif'
);

// 帶 Cookie、偽造 Referer 繞過防盜鏈
DownImageKeep(
    'https://example.com/protected/image.jpg',
    'https://example.com/referer-page.html',
    'image.jpg',
    'sessionid=abc123; user_token=xyz'
);

// 批量下載
$images = [
    ['url' => 'https://site.com/1.jpg', 'ref' => 'https://site.com/', 'name' => '1.jpg'],
    ['url' => 'https://site.com/2.jpg', 'ref' => 'https://site.com/', 'name' => '2.jpg'],
];
foreach ($images as $img) {
    DownImageKeep($img['url'], $img['ref'], $img['name']);
    sleep(1); // 禮貌間隔
}

cURL 版本對比 (推薦現代專案使用)

function downloadImageCurl($url, $referer = '', $savePath, $cookie = '', $timeout = 30) {
    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => $url,
        CURLOPT_REFERER => $referer,
        CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
        CURLOPT_COOKIE => $cookie,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_FOLLOWLOCATION => true,
        CURLOPT_MAXREDIRS => 5,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_SSL_VERIFYPEER => true,
    ]);
    
    $data = curl_exec($ch);
    $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    
    if ($httpCode !== 200 || $data === false) return false;
    
    return file_put_contents($savePath, $data) !== false;
}

方案選擇建議

場景推薦方案
現代專案、HTTPS、複雜重定向cURL 版本
無 cURL 擴充環境、需精細控制 SocketSocket 版本
大檔案、斷點續傳、限速cURL + CURLOPT_RANGE
並發下載多張圖片curl_multi
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved