function downloadCssImages(string $cssPath, string $saveDir = 'css_images/'): array {
if (!is_file($cssPath)) return ['error' => 'CSS 文件不存在'];
if (!is_dir($saveDir)) mkdir($saveDir, 0755, true);
$css = file_get_contents($cssPath);
if ($css === false) return ['error' => '讀取 CSS 失敗'];
// 匹配 url(...) 多種寫法:url("..."), url('...'), url(...)
preg_match_all('/url\(\s*[\'"]?([^\'")]+)[\'"]?\s*\)/i', $css, $matches);
$urls = array_unique($matches[1]);
$results = ['success' => [], 'failed' => []];
$ctx = stream_context_create([
'http' => ['timeout' => 15, 'follow_location' => 1, 'user_agent' => 'CSS Image Downloader'],
'ssl' => ['verify_peer' => true]
]);
foreach ($urls as $url) {
// 處理相對路徑
if (strpos($url, '://') === false && $url[0] !== '/') {
$baseDir = dirname($cssPath);
$url = $baseDir . '/' . $url;
} elseif ($url[0] === '/') {
// 相對域名根路徑,需補全域名(此處簡化,實際需解析 CSS 所在域)
// $url = 'https://example.com' . $url;
}
$filename = basename(parse_url($url, PHP_URL_PATH));
$filename = urldecode($filename); // 處理 URL 編碼
$filepath = $saveDir . $filename;
// 避免覆蓋:同名文件加哈希後綴
if (is_file($filepath)) {
$info = pathinfo($filename);
$filename = $info['filename'] . '_' . substr(md5($url), 0, 8) . '.' . $info['extension'];
$filepath = $saveDir . $filename;
}
$content = @file_get_contents($url, false, $ctx);
if ($content !== false && strlen($content) > 0) {
if (file_put_contents($filepath, $content) !== false) {
$results['success'][] = ['url' => $url, 'local' => $filepath];
} else {
$results['failed'][] = ['url' => $url, 'reason' => '寫入失敗'];
}
} else {
$results['failed'][] = ['url' => $url, 'reason' => '下載失敗/空內容'];
}
}
return $results;
}
// 使用
$res = downloadCssImages('assets/style.css', 'public/images/');
echo "成功:" . count($res['success']) . ",失敗:" . count($res['failed']);
print_r($res['failed']);
data:image/... 需單獨處理 base64 解碼)。array_unique 避免重複下載。現代構建工具(Webpack、Vite、Rollup)配合 postcss-url、css-loader 可在構建階段自動內聯、複製、哈希重命名圖片,無需運行時腳本。