QQ 達人(城市達人)曾提供公開的 JSON 介面供搜尋用戶資料,但介面設有 Referer 防盜鏈,直接請求會被拒絕。本文示範如何使用 PHP stream_context_create() 偽造 Referer: https://city.qq.com,成功呼叫 API 並解析回傳的 JSONP 資料。
https://city.qq.com/json.php?mod=search&act=page&callback=showSrchResult&jsontype=str&perpage=10&cd=610900&nl=3&xb=0&type=city&pg=1
| 參數 | 說明 |
|---|---|
cd | 城市代碼(例:610900 = 西安) |
perpage | 每頁筆數 |
pg | 頁碼 |
xb | 性別(0=不限, 1=男, 2=女) |
callback | JSONP 回呼函數名稱 |
<?php
/**
* 取得 QQ 達人搜尋結果
* @param string $cityCode 城市代碼
* @param int $page 頁碼
* @param int $perPage 每頁筆數
* @return array 解析後的用戶陣列
*/
function fetchQqDarenUsers(string $cityCode = '610900', int $page = 1, int $perPage = 10): array
{
$referer = 'https://city.qq.com';
$url = "https://city.qq.com/json.php?mod=search&act=page&callback=showSrchResult&jsontype=str&perpage={$perPage}&cd={$cityCode}&nl=3&xb=0&type=city&pg={$page}";
$context = stream_context_create([
'http' => [
'method' => 'GET',
'header' => "Referer: {$referer}\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n",
'timeout' => 10,
],
'ssl' => [
'verify_peer' => false, // 僅示範
'verify_peer_name' => false,
],
]);
$jsonp = @file_get_contents($url, false, $context);
if ($jsonp === false) {
throw new RuntimeException('API 請求失敗,請檢查網路或參數');
}
// 移除 JSONP 包裝:showSrchResult({...}) → {...}
$json = trim($jsonp);
if (strpos($json, '(') !== false && strrpos($json, ')') === strlen($json) - 1) {
$json = substr($json, strpos($json, '(') + 1, -1);
}
$data = json_decode($json, true);
if (json_last_error() !== JSON_ERROR_NONE) {
throw new RuntimeException('JSON 解析失敗:' . json_last_error_msg());
}
return $data['result']['list'] ?? []; // 視實際結構調整
}
// --- 使用範例 ---
try {
$users = fetchQqDarenUsers('610900', 1, 20);
foreach ($users as $u) {
echo "QQ: {$u['uin']} | 暱稱: {$u['nick']} | 年齡: {$u['age']} | 性別: " . ($u['sex']==1?'男':'女') . "\n";
}
} catch (Throwable $e) {
error_log($e->getMessage());
}
?>
stream_context_create() 允許在不安裝 cURL 擴展的情況下自訂 HTTP 標頭,輕量且內建。callback(...) 格式,需以字串處理移除首尾,再 json_decode()。file_get_contents 回傳值與 json_last_error(),避免靜默失敗。function fetchWithCurl(string $url, string $referer): ?string
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_REFERER => $referer,
CURLOPT_USERAGENT => 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
CURLOPT_TIMEOUT => 10,
CURLOPT_SSL_VERIFYPEER => false,
]);
$resp = curl_exec($ch);
$err = curl_error($ch);
curl_close($ch);
return $err ? null : $resp;
}