在開發采集、代理轉發、第三方登入回調等場景時,常需模擬瀏覽器行為發送 HTTP 請求,並控制 Referer、User-Agent 等 Header。PHP 原生 header('Location:...')、Meta Refresh、JS 跳轉均無法攜帶自訂 Referer。本文深入講解使用 fsockopen 底層 Socket 通訊與 cURL 高階庫實現偽造 Referer、POST/GET 請求、處理 301/302 重導向的完整技巧。
header("Location: $url"):瀏覽器發起新請求,Referer 為原頁面或空。<meta http-equiv="refresh" content="0;url=...">:同屬瀏覽器導向,Referer 由瀏覽器決定。window.location.href = "...":客戶端導向,Referer 為當前頁。結論: 必須在伺服端以 HTTP Client 身分發起請求,才能完全控制 Header。
適用於未安裝 cURL 擴充套件的環境,可精細控制每個 Header 與原始回應。
<?php
function socketRequest($url, $method = 'GET', $postData = '', $referer = '', $headers = []) {
$parsed = parse_url($url);
$host = $parsed['host'];
$port = $parsed['port'] ?? ($parsed['scheme'] === 'https' ? 443 : 80);
$path = $parsed['path'] ?? '/';
if (!empty($parsed['query'])) $path .= '?' . $parsed['query'];
// 建立連線 (支援 SSL)
$fp = @fsockopen(($parsed['scheme'] === 'https' ? 'ssl://' : '') . $host, $port, $errno, $errstr, 10);
if (!$fp) {
throw new Exception("連線失敗: $errstr ($errno)");
}
// 組裝請求行
$request = "$method $path HTTP/1.1\r\n";
$request .= "Host: $host\r\n";
$request .= "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n";
$request .= "Referer: " . ($referer ?: $url) . "\r\n";
$request .= "Connection: Close\r\n";
// 自訂 Header
foreach ($headers as $k => $v) {
$request .= "$k: $v\r\n";
}
if ($method === 'POST') {
$request .= "Content-Type: application/x-www-form-urlencoded\r\n";
$request .= "Content-Length: " . strlen($postData) . "\r\n";
}
$request .= "\r\n";
if ($method === 'POST') $request .= $postData;
// 發送
fwrite($fp, $request);
// 接收回應
$response = '';
while (!feof($fp)) {
$response .= fgets($fp, 4096);
}
fclose($fp);
// 解析 Header 與 Body
list($headerStr, $body) = explode("\r\n\r\n", $response, 2);
$headerLines = explode("\r\n", $headerStr);
$statusLine = array_shift($headerLines);
$headers = [];
foreach ($headerLines as $line) {
list($k, $v) = explode(': ', $line, 2);
$headers[$k] = $v;
}
return [
'status' => $statusLine,
'headers' => $headers,
'body' => $body,
];
}
// 使用範例:偽造 Referer 為 google.com 訪問目標站
try {
$result = socketRequest(
'https://httpbin.org/get',
'GET',
'',
'https://www.google.com/search?q=test'
);
echo "Status: {$result['status']}\n";
echo "Referer seen by server: " . ($result['headers']['Referer'] ?? '無') . "\n";
// 可進一步處理 301/302 Location 重導向
} catch (Exception $e) {
echo "錯誤: " . $e->getMessage();
}
?>
cURL 封裝度高、支援 HTTPS、Cookie 自動處理、多執行緒、超時控制、重導向追蹤,程式碼更簡潔健壯。
<?php
function curlRequest($url, $options = []) {
$ch = curl_init();
$defaults = [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true, // 自動追蹤 301/302
CURLOPT_MAXREDIRS => 5,
CURLOPT_SSL_VERIFYPEER => false, // 測試用,生產請設 true 並配置 CA
CURLOPT_SSL_VERIFYHOST => false,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
CURLOPT_TIMEOUT => 10,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_HEADER => true, // 包含 Header 於回傳
];
curl_setopt_array($ch, $defaults + $options);
$response = curl_exec($ch);
$errno = curl_errno($ch);
$error = curl_error($ch);
$info = curl_getinfo($ch);
curl_close($ch);
if ($errno) throw new Exception("cURL 錯誤 [$errno]: $error");
// 分離 Header 與 Body
$headerSize = $info['header_size'];
$headerStr = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
return ['info' => $info, 'headers' => $headerStr, 'body' => $body];
}
// 範例 1:偽造 Referer 進行 GET
$res = curlRequest('https://httpbin.org/headers', [
CURLOPT_REFERER => 'https://www.facebook.com/',
]);
echo $res['body']; // 可見 Referer 已被偽造
// 範例 2:偽造 Referer 進行 POST 表單提交
$res = curlRequest('https://httpbin.org/post', [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['username' => 'demo', 'password' => 'secret']),
CURLOPT_REFERER => 'https://example.com/login_page',
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
]);
echo $res['body'];
// 範例 3:不自動追蹤重導向,手動處理 302 (如需捕獲 Location)
$res = curlRequest('https://httpbin.org/redirect/1', [
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_REFERER => 'https://mysite.com/',
]);
// 從 Header 解析 Location
if (preg_match('/Location:\s*(\S+)/i', $res['headers'], $m)) {
echo "重導向至: $m[1]";
}
?>
結合 CURLOPT_COOKIEJAR/CURLOPT_COOKIEFILE 維持 Session,可模擬完整登入流程:
$cookieFile = sys_get_temp_dir() . '/cookie_' . md5($url) . '.txt';
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => 'https://target.com/login',
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['user'=>'a','pass'=>'b']),
CURLOPT_COOKIEJAR => $cookieFile,
CURLOPT_COOKIEFILE => $cookieFile,
CURLOPT_REFERER => 'https://target.com/login',
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);
// 後續請求自動攜帶 Cookie
curl_setopt($ch, CURLOPT_URL, 'https://target.com/user/profile');
curl_setopt($ch, CURLOPT_POST, false);
$profile = curl_exec($ch);
curl_close($ch);