在專案開發中,常需從外部 URL 抓取圖片並儲存至伺服器。本文提供一個健壯、可復用的 PHP 函式 getImage(),支援 cURL 與 readfile() 兩種下載方式、自動建立目錄、副檔名驗證、錯誤代碼回傳,並附上完整呼叫範例。
<?php
/**
* 遠端下載圖片至本地
*
* @param string $url 圖片 URL
* @param string $save_dir 儲存目錄(預設 ./)
* @param string $filename 儲存檔名(預設取 URL 尾部副檔名 + 時間戳)
* @param int $type 下載方式:0=readfile(預設), 1=cURL
* @return array ['file_name', 'save_path', 'error']
*/
function getImage($url, $save_dir = '', $filename = '', $type = 0) {
// 參數檢核
if (trim($url) === '') {
return ['file_name' => '', 'save_path' => '', 'error' => 1]; // URL 為空
}
if (trim($save_dir) === '') {
$save_dir = './';
}
// 確保目錄以 / 結尾
if (substr($save_dir, -1) !== '/') {
$save_dir .= '/';
}
// 自動產生檔名
if (trim($filename) === '') {
$ext = strrchr($url, '.');
// 僅允許常見圖片副檔名
if (!in_array(strtolower($ext), ['.gif', '.jpg', '.jpeg', '.png', '.webp'], true)) {
return ['file_name' => '', 'save_path' => '', 'error' => 3]; // 副檔名不支援
}
$filename = time() . $ext;
}
// 建立目錄(遞迴、權限 0777)
if (!file_exists($save_dir) && !mkdir($save_dir, 0777, true)) {
return ['file_name' => '', 'save_path' => '', 'error' => 5]; // 目錄建立失敗
}
// 取得遠端檔案內容
$img = '';
if ($type === 1) {
// cURL 方式(支援 HTTPS、可設定逾時)
$ch = curl_init();
$timeout = 10;
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_FOLLOWLOCATION => true, // 支援重導向
CURLOPT_SSL_VERIFYPEER => false, // 正式環境建議設 true 並配置 CA 憑證
]);
$img = curl_exec($ch);
if (curl_errno($ch)) {
curl_close($ch);
return ['file_name' => '', 'save_path' => '', 'error' => 6]; // cURL 錯誤
}
curl_close($ch);
} else {
// readfile + output buffering 方式(簡單但無法精細控制逾時/標頭)
ob_start();
$result = @readfile($url);
$img = ob_get_contents();
ob_end_clean();
if ($result === false) {
return ['file_name' => '', 'save_path' => '', 'error' => 7]; // 讀取失敗
}
}
// 寫入檔案
$filepath = $save_dir . $filename;
$fp = @fopen($filepath, 'wb'); // 使用二進位模式
if (!$fp) {
return ['file_name' => '', 'save_path' => '', 'error' => 8]; // 無法開啟檔案
}
fwrite($fp, $img);
fclose($fp);
return [
'file_name' => $filename,
'save_path' => $filepath,
'error' => 0
];
}
?>
<?php
require_once 'getImage.func.php'; // 假設函式存放於此檔案
$url = 'https://example.com/images/photo.jpg';
$result = getImage($url, 'uploads/images/');
if ($result['error'] === 0) {
echo "下載成功!檔案儲存於:{$result['save_path']}";
} else {
$errors = [
1 => 'URL 不得為空',
3 => '不支援的圖片格式',
5 => '無法建立儲存目錄',
6 => 'cURL 下載失敗',
7 => 'readfile 讀取失敗',
8 => '無法寫入檔案',
];
echo "下載失敗:{$errors[$result['error']] ?? '未知錯誤'} (代碼:{$result['error']})";
}
?>
Content-Type 標頭確為圖片類型。getimagesizefromstring() 驗證檔案真偽,防止惡意腳本偽裝圖片上傳。open_basedir 限制,禁止執行權限。.webp、.avif 等現代格式。| 代碼 | 說明 |
|---|---|
| 0 | 成功 |
| 1 | URL 為空 |
| 3 | 不支援的副檔名(非 gif/jpg/png) |
| 5 | 目錄建立失敗(權限不足) |
| 6 | cURL 執行錯誤(連線逾時、DNS 失敗等) |
| 7 | readfile 讀取失敗(URL 無效、允許 url_fopen 關閉) |
| 8 | 檔案寫入失敗(磁碟空間不足、權限問題) |
透過封裝 getImage() 函式,即可輕鬆實現遠端圖片下載與本地儲存。實務部署時,請根據專案需求選擇 cURL 或原生函式,並務必加入檔案驗證與安全防護措施,確保系統穩定與安全。