首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 獲取 QQ 達人用戶資訊:Referer 偽造與 JSONP 解析實作

     編輯:PHP 相關知識

QQ 達人 (city.qq.com) 曾提供公開的用戶搜尋介面,透過偽造 Referer 繞過防盜鏈、解析 JSONP 回調獲取用戶資料。**注意:此介面已停止維護、極大概率已失效,且屬於未授權資料抓取,僅作技術教學參考。**

原始實作邏輯分析

<?php
/**
 * 獲取 QQ 達人用戶列表 (教學用,介面已失效)
 * 原理:
 * 1. 目標 URL 返回 JSONP:showSrchResult({...})
 * 2. 需偽造 Referer: https://city.qq.com 繞過防盜鏈
 * 3. 參數 cd=城市代碼, nl=性別, xb=年齡, pg=頁碼
 */
function getQqUsers(string $cityCode = '610900', int $page = 1, int $perPage = 10): array {
    $url = 'https://city.qq.com/json.php';
    $params = [
        'mod'      => 'search',
        'act'      => 'page',
        'callback' => 'showSrchResult',
        'jsontype' => 'str',
        'perpage'  => $perPage,
        'cd'       => $cityCode,
        'nl'       => 3,      // 性別:1男 2女 3不限
        'xb'       => 0,      // 年齡段
        'type'     => 'city',
        'pg'       => $page,
    ];

    $referer = 'https://city.qq.com';
    $context = stream_context_create([
        'http' => [
            'method'  => 'GET',
            'header'  => "Referer: {$referer}\r\n" .
                         "User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36\r\n",
            'timeout' => 10,
        ],
    ]);

    $query = http_build_query($params);
    $fullUrl = $url . '?' . $query;

    $jsonp = @file_get_contents($fullUrl, false, $context);
    if ($jsonp === false) {
        return ['error' => '請求失敗'];
    }

    // 解析 JSONP:去除回調函數包裹
    // 格式:showSrchResult({...});
    if (preg_match('/^\s*showSrchResult\s*\(\s*(.+)\s*\)\s*;?\s*$/s', $jsonp, $m)) {
        $json = $m[1];
    } else {
        return ['error' => 'JSONP 格式錯誤', 'raw' => $jsonp];
    }

    $data = json_decode($json, true);
    if (json_last_error() !== JSON_ERROR_NONE) {
        return ['error' => 'JSON 解析失敗: ' . json_last_error_msg()];
    }

    return $data['data']['list'] ?? [];
}

// 使用
$users = getQqUsers('610900', 1, 20);
print_r($users);
?>

關鍵技術點

技術說明
Referer 偽造stream_context_create(['http'=>['header'=>'Referer: ...']]) 設定 HTTP Referer 標頭
JSONP 解析正則提取回調函數內的 JSON 字串,再 json_decode
參數含義cd 城市代碼, nl 性別, xb 年齡, pg 頁碼, perpage 每頁筆數
防盜鏈繞過伺服器檢查 Referer 是否為 city.qq.com,偽造即可通過

現代替代方案:官方開放平台

QQ 用戶資料獲取應使用 騰訊開放平台 OAuth2.0:

  1. 註冊開發者帳號,建立應用,獲取 AppID、AppKey
  2. 引導用戶授權:https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=APP_ID&redirect_uri=REDIRECT_URI&scope=get_user_info
  3. 換取 Access Token:https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&...
  4. 獲取用戶資訊:https://graph.qq.com/user/get_user_info?access_token=TOKEN&oauth_consumer_key=APP_ID&openid=OPENID

PHP 實作 OAuth2 獲取 QQ 用戶資訊

<?php
namespace App\Service;

class QqOAuth {
    private string $appId;
    private string $appKey;
    private string $redirectUri;

    public function __construct(string $appId, string $appKey, string $redirectUri) {
        $this->appId = $appId;
        $this->appKey = $appKey;
        $this->redirectUri = $redirectUri;
    }

    /** 獲取授權 URL */
    public function getAuthUrl(string $state = ''): string {
        $params = [
            'response_type' => 'code',
            'client_id'     => $this->appId,
            'redirect_uri'  => $this->redirectUri,
            'scope'         => 'get_user_info',
            'state'         => $state ?: bin2hex(random_bytes(16)),
        ];
        return 'https://graph.qq.com/oauth2.0/authorize?' . http_build_query($params);
    }

    /** 回調處理:code 換取 access_token */
    public function handleCallback(string $code, string $state): array {
        // 1. 驗證 state (防 CSRF)
        // 2. 請求 token
        $tokenUrl = 'https://graph.qq.com/oauth2.0/token';
        $params = [
            'grant_type'    => 'authorization_code',
            'client_id'     => $this->appId,
            'client_secret' => $this->appKey,
            'code'          => $code,
            'redirect_uri'  => $this->redirectUri,
        ];
        $resp = $this->httpGet($tokenUrl, $params);
        // 回應格式:access_token=XXX&expires_in=7776000&refresh_token=YYY
        parse_str($resp, $tokenData);
        if (empty($tokenData['access_token'])) {
            throw new RuntimeException("獲取 token 失敗: {$resp}");
        }

        // 3. 獲取 openid
        $openidUrl = 'https://graph.qq.com/oauth2.0/me';
        $resp = $this->httpGet($openidUrl, ['access_token' => $tokenData['access_token']]);
        // 回應格式:callback( {"client_id":"APPID","openid":"OPENID"} );
        if (preg_match('/\{.*\}/', $resp, $m)) {
            $openidData = json_decode($m[0], true);
        } else {
            throw new RuntimeException("解析 openid 失敗: {$resp}");
        }

        // 4. 獲取用戶資訊
        $userInfo = $this->getUserInfo($tokenData['access_token'], $openidData['openid']);
        return array_merge($userInfo, $tokenData, $openidData);
    }

    private function getUserInfo(string $accessToken, string $openid): array {
        $url = 'https://graph.qq.com/user/get_user_info';
        $params = [
            'access_token'       => $accessToken,
            'oauth_consumer_key' => $this->appId,
            'openid'             => $openid,
        ];
        $resp = $this->httpGet($url, $params);
        $data = json_decode($resp, true);
        if (json_last_error() !== JSON_ERROR_NONE || ($data['ret'] ?? -1) !== 0) {
            throw new RuntimeException("獲取用戶資訊失敗: {$resp}");
        }
        return $data;
    }

    private function httpGet(string $url, array $params): string {
        $ch = curl_init($url . '?' . http_build_query($params));
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => true,
            CURLOPT_TIMEOUT => 10,
        ]);
        $resp = curl_exec($ch);
        if (curl_errno($ch)) throw new RuntimeException("cURL 錯誤: " . curl_error($ch));
        curl_close($ch);
        return $resp;
    }
}
?>

法律與道德提醒

  • 未授權抓取違法:繞過 Referer 檢查、爬取非公開介面可能違反《計算機信息網絡國際聯網安全保護管理辦法》、網站服務條款。
  • 個人隱私保護:QQ 號、暱稱、頭像、性別、地區屬個人信息,需用戶明確授權(OAuth)才能合法獲取。
  • 反爬蟲風險:高頻請求會觸發 IP 封禁、帳號凍結、法律追訴。
  • 資料準確性:非官方介面資料可能過時、不完整、或被污染。

總結

原文技術棧(Referer 偽造 + JSONP 解析)展示了早期「非官方 API」常用手法,但**現代開發必須使用官方 OAuth2 開放平台**。《個人信息保護法》、平台服務條款、技術穩定性均要求合規接入。本文代碼僅供學習 HTTP 上下文建立、JSONP 解析、OAuth2 流程等通用技術。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved