批量下載遠端圖片是常見需求。本文從簡單的 file_get_contents 迴圈進階到支援斷點續傳、併發控制、錯誤重試的生產級下載器。
<?php
$imageUrls = [
'https://example.com/img1.jpg',
'https://example.com/img2.png',
// ...
];
set_time_limit(0); // 移除執行時間限制
$imageUrls = array_unique($imageUrls); // 去重
foreach ($imageUrls as $url) {
$filename = basename($url);
$content = @file_get_contents($url);
if ($content !== false) {
file_put_contents($filename, $content);
echo "下載成功: $filename\n";
} else {
echo "下載失敗: $url\n";
}
}
?>
<?php
function downloadImage(string $url, string $saveDir = '.', int $timeout = 30): array {
$filename = basename(parse_url($url, PHP_URL_PATH));
if (empty($filename) || $filename === '/') {
$filename = 'image_' . time() . '.jpg';
}
$filepath = rtrim($saveDir, '/') . '/' . $filename;
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_SSL_VERIFYPEER => true,
CURLOPT_USERAGENT => 'Mozilla/5.0 PHP Downloader',
CURLOPT_WRITEFUNCTION => function($ch, $data) use ($filepath) {
static $fp = null;
if ($fp === null) {
$fp = fopen($filepath, 'wb');
}
return fwrite($fp, $data);
},
]);
$success = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$contentType = curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
curl_close($ch);
if ($success && $httpCode === 200 && str_starts_with($contentType, 'image/')) {
return ['success' => true, 'file' => $filepath];
}
@unlink($filepath); // 失敗刪除殘檔
return ['success' => false, 'error' => "HTTP $httpCode: $contentType"];
}
// 批量下載主程式
$urls = array_unique([/* 圖片 URL 陣列 */]);
$results = ['success' => 0, 'failed' => 0];
foreach ($urls as $i => $url) {
$result = downloadImage($url, 'downloads');
if ($result['success']) {
$results['success']++;
echo "[$i] ✓ {$result['file']}\n";
} else {
$results['failed']++;
echo "[$i] ✗ $url - {$result['error']}\n";
}
usleep(100000); // 禮貌延遲 0.1 秒
}
echo "完成: 成功 {$results['success']}, 失敗 {$results['failed']}\n";
?>
| 功能 | 實作方案 |
|---|---|
| 斷點續傳 | CURLOPT_RESUME_FROM + Range Header |
| 併發下載 | curl_multi_* 或 parallel 擴展 / Swoole |
| 重試機制 | 指數退避:1s, 2s, 4s, 8s... 最大 3 次 |
| 去重複檔 | MD5/SHA256 檢查已下載檔案 |
| 頻率限制 | Token Bucket / Leaky Bucket 演算法 |
| 進度條 | CURLOPT_PROGRESSFUNCTION + CLI 進度顯示 |
<?php
function extractImagesFromCss(string $cssContent): array {
// 匹配 url(...) 格式,支援單雙引號、無引號
preg_match_all('/url\(\s*[\'"]?([^\'")]+)[\'"]?\s*\)/i', $cssContent, $matches);
return array_unique($matches[1]);
}
$css = file_get_contents('https://example.com/style.css');
$imageUrls = extractImagesFromCss($css);
// 轉換相對路徑為絕對 URL
$baseUrl = 'https://example.com/';
$imageUrls = array_map(fn($u) => $u[0] === '/' ? $baseUrl . ltrim($u, '/') : $baseUrl . $u, $imageUrls);
?>
robots.txt 與網站服務條款User-Agent 標識爬蟲身分