許多網站啟用「防盜鏈」機制,透過檢查 HTTP Request Header 中的 Referer 欄位,僅允許自家域名或白名單域名請求圖片/頁面內容。常見的 file_get_contents()、fopen()、cURL (預設) 往往發送空 Referer 或 PHP 機器特徵 Referer,導致被擋回 403/404 或跳轉頁面。
本文提供一個 底層 Socket 實現的 HTTP/1.0 客戶端,可完全自訂 Header (Referer, User-Agent, Accept, Cookie 等),繞過大多數基於 Header 的防盜鏈檢查。
retrieveURLContentBySocket()<?php
/**
* 使用原始 Socket 發送 HTTP GET 請求,支援自訂 Host、Port、Timeout、完整 Header 控制
*
* @param string $url 目標 URL (若提供 $host 則視為 URI Path)
* @param string $host 指定 Host Header (可偽裝 Referer 來源域名)
* @param int $port 連接埠 (預設 80)
* @param int $timeout 連線/讀取超時秒數
* @return string|false 回應 Body 內容,失敗回傳 false
*/
function retrieveURLContentBySocket($url, $host = "", $port = 80, $timeout = 30) {
// 1. 解析 URL 與 Host
if ($host === "") {
if (($pos = strpos($url, '://')) === false) return false;
$host = substr($url, $pos + 3);
$host = substr($host, 0, strpos($host, '/'));
$uri = substr($url, strpos($url, '/', $pos + 3));
if ($uri === false || $uri === '') $uri = '/';
} else {
$uri = $url; // 此模式下 $url 應為 URI Path
}
// 2. 建構 HTTP/1.0 請求報文 (關鍵:手動控制 Header)
$request = "GET $uri HTTP/1.0\r\n"
. "Host: $host\r\n"
. "Accept: */*\r\n"
. "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36\r\n"
. "Referer: https://$host/\r\n" // 核心:偽裝來自目標站點首頁
. "Connection: Close\r\n" // HTTP/1.0 預設短連線,避免 Keep-Alive 卡住
. "\r\n";
// 3. 建立 Socket 連線
$errno = 0; $errstr = '';
$socket = @fsockopen($host, $port, $errno, $errstr, $timeout);
if (!$socket) {
error_log("Socket 連線失敗 [$errno]: $errstr (Host: $host:$port)");
return false;
}
// 4. 設定串流超時 (讀取/寫入)
stream_set_timeout($socket, $timeout);
// 5. 發送請求
if (@fwrite($socket, $request) === false) {
fclose($socket);
return false;
}
// 6. 讀取完整回應
$response = '';
while (!feof($socket)) {
$chunk = fread($socket, 8192);
if ($chunk === false || $chunk === '') break;
$response .= $chunk;
// 讀取超時檢查
$info = stream_get_meta_data($socket);
if ($info['timed_out']) {
error_log("Socket 讀取超時: $host$uri");
break;
}
}
fclose($socket);
// 7. 分離 Header 與 Body
$headerEnd = strpos($response, "\r\n\r\n");
if ($headerEnd === false) {
return $response; // 非標準回應,全回傳
}
// 可選:解析狀態碼、Content-Type、Set-Cookie 等
// $header = substr($response, 0, $headerEnd);
// if (strpos($header, 'HTTP/1.') !== 0) return false;
// if (strpos($header, ' 200 ') === false) return false; // 非 200 視為失敗
return substr($response, $headerEnd + 4);
}
// ===== 進階用法範例 =====
// 采集受防盜鏈保護的圖片
$imageUrl = '/images/protected/photo.jpg';
$targetHost = 'example.com';
$binaryContent = retrieveURLContentBySocket($imageUrl, $targetHost, 80, 15);
if ($binaryContent !== false) {
file_put_contents('photo.jpg', $binaryContent);
echo "圖片采集成功 (" . strlen($binaryContent) . " bytes)";
} else {
echo "采集失敗";
}
// 采集 HTTPS 頁面 (需搭配 SSL Context 或改用 cURL)
?>
HTTP/1.0 + Connection: Close,簡化連線管理,避免 Chunked Transfer Encoding 解析麻煩。| Header | 偽裝目的 | 建議值 |
|---|---|---|
| Referer | 核心防盜鏈判斷依據 | https://target-domain.com/ 或具體列表頁 URL |
| User-Agent | 識別爬蟲/機器人 | 最新 Chrome/Edge/Firefox 完整 UA 字串 |
| Accept | 內容協商 | text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 |
| Accept-Language | 地區化內容 | zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7 |
| Cookie | 會話/登入狀態 | 從瀏覽器開發工具複製完整 Cookie 字串 |
| X-Forwarded-For | IP 白名單繞過 (部分站點) | 隨機內網 IP 或目標國家代理 IP |
function fetchWithAntiHotlink($url, $referer = '', $opts = []) {
$ch = curl_init();
$defaultOpts = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true, // 自動追蹤 301/302
CURLOPT_MAXREDIRS => 5,
CURLOPT_CONNECTTIMEOUT => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => false, // 采集通常關閉驗證
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
CURLOPT_REFERER => $referer ?: $url, // 自動帶入目標域名
CURLOPT_ENCODING => 'gzip,deflate', // 自動解壓
CURLOPT_COOKIEJAR => '', // 啟用記憶體 Cookie 罐
CURLOPT_COOKIEFILE => '',
CURLOPT_HTTPHEADER => [
'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7',
'Cache-Control: no-cache',
'Pragma: no-cache',
],
];
curl_setopt_array($ch, array_merge($defaultOpts, $opts));
$content = curl_exec($ch);
$errno = curl_errno($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($errno) return ['error' => curl_strerror($errno), 'info' => $info];
if ($info['http_code'] >= 400) return ['error' => "HTTP {$info['http_code']}", 'info' => $info];
return ['content' => $content, 'info' => $info];
}
// 使用
$result = fetchWithAntiHotlink('https://target.com/page.html', 'https://target.com/list.html');
if (isset($result['content'])) {
// 成功
}
robots.txt:User-agent: * Disallow: /path/ 禁止路徑不可抓取。Terms of Service:網站條款若明文禁止爬蟲/采集,法律風險極高。sleep(rand(1, 5))。Socket 底層實現展示了 HTTP 協定本質,是理解「繞過防盜鏈」原理的最佳教材。但實務上,請直接使用 cURL 並配合完整 Header 偽裝、代理 IP 池、Headless Chrome 渲染 組合拳,才能穩定應對現代 WAF (Web Application Firewall)、行為分析、JS 挑戰 等多層防護。技術無罪,用途決定合法性,請謹慎使用。