部分舊系統需整合第三方驗證碼,需將遠端驗證碼圖片下載至本地、識別或轉檔。本文示範使用 GD 函式庫搭配 exif_imagetype() 自動偵測格式 (PNG/GIF/JPEG),下載並輸出為統一 PNG 格式,含逾時控制與錯誤處理。
<?php
/**
* 取得遠端驗證碼並輸出為 PNG
*
* @param string $url 遠端驗證碼圖片 URL
* @param int $timeout 連線逾時秒數
* @return void 直接輸出圖片二進位資料
* @throws Exception 取得失敗
*/
function fetchCaptcha(string $url, int $timeout = 10): void {
// 1. 初始化 cURL
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_MAXREDIRS => 5,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_TIMEOUT => $timeout,
CURLOPT_SSL_VERIFYPEER => false, // 僅測試環境,生產請設 true 並配置 CA
CURLOPT_USERAGENT => 'Mozilla/5.0 (compatible; CaptchaFetcher/1.0)',
]);
$binary = curl_exec($ch);
$errno = curl_errno($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($errno) {
throw new Exception("cURL 錯誤 ($errno): " . curl_strerror($errno));
}
if ($info['http_code'] !== 200) {
throw new Exception("HTTP 狀態碼: {$info['http_code']}");
}
if (empty($binary)) {
throw new Exception("回應內容為空");
}
// 2. 偵測圖片類型 (需啟用 exif 擴展)
$type = exif_imagetype($url); // 注意:此函式需檔案路徑或 URL (PHP 7.2+ 支援 URL)
// 相容舊版:從二進位偵測
if ($type === false) {
$type = @exif_imagetype('data://application/octet-stream;base64,' . base64_encode($binary));
}
// 3. 依類型建立 GD 影像資源
$src = null;
switch ($type) {
case IMAGETYPE_GIF:
$src = imagecreatefromstring($binary); // GIF 直接用 string 建立
break;
case IMAGETYPE_JPEG:
$src = imagecreatefromstring($binary);
break;
case IMAGETYPE_PNG:
$src = imagecreatefromstring($binary);
break;
default:
throw new Exception("不支援的圖片格式: " . ($type ?: 'unknown'));
}
if ($src === false) {
throw new Exception("GD 無法解析圖片資料");
}
// 4. 可選:影像預處理 (灰階、二值化、去噪) - 留給 OCR 階段
// imagefilter($src, IMG_FILTER_GRAYSCALE);
// 5. 輸出為 PNG
header('Content-Type: image/png');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
imagepng($src);
imagedestroy($src);
}
// 使用範例
try {
$captchaUrl = 'https://example.com/captcha.php?' . time(); // 加時間戳防快取
fetchCaptcha($captchaUrl);
} catch (Exception $e) {
http_response_code(500);
header('Content-Type: application/json');
echo json_encode(['error' => $e->getMessage()]);
}
| 技術點 | 說明 |
|---|---|
imagecreatefromstring() | 直接從二進位字串建立 GD 資源,自動識別 PNG/JPEG/GIF,**不需**先存檔,效能最佳 |
exif_imagetype() | 快速偵測圖片類型,回傳常數 IMAGETYPE_*,比 getimagesize() 輕量 |
| cURL 逾時設定 | CURLOPT_CONNECTTIMEOUT (連線階段)、CURLOPT_TIMEOUT (整體) 必須設定,防止掛住 |
| 防快取 | 請求 URL 加隨機參數、回應 Header 禁用快取,確保每次取得新驗證碼 |
| SSL 驗證 | 生產環境**必須**啟用 CURLOPT_SSL_VERIFYPEER = true 並配置 CURLOPT_CAINFO |
function saveCaptchaToFile(string $url, string $savePath, int $timeout = 10): bool {
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_CONNECTTIMEOUT => $timeout,
CURLOPT_TIMEOUT => $timeout,
]);
$binary = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($code !== 200 || empty($binary)) {
return false;
}
// 直接寫入二進位檔案
$bytes = file_put_contents($savePath, $binary);
return $bytes !== false;
}
// 使用
if (saveCaptchaToFile('https://site.com/captcha', '/tmp/captcha_' . time() . '.png')) {
echo "儲存成功,可送入 Tesseract/其他 OCR";
}
⚠️ 重要:自動化取得/破解驗證碼可能違反網站服務條款、相關法規 (如《電腦犯罪條例》)。本文僅供**授權整合測試、自有系統驗證碼代理**等合法場景使用。請尊重 robots.txt、API 使用政策,勿用於惡意爬蟲、暴力破解、刷單等行為。
cURL + imagecreatefromstring() 即可高效下載並轉換遠端驗證碼圖片。