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

PHP 獲取 QQ 用戶昵稱與在線狀態:多種方案深度解析與實戰代碼

     編輯:PHP 相關知識

前言

QQ 作為國內主流即時通訊工具,其用戶昵稱與在線狀態獲取常用於客服系統、社交應用、營銷工具。騰訊未提供官方開放 API,開發者需通過逆向分析 Web 協議實現。本文深度解析三種主流方案原理、代碼實現、優缺點對比及風險控制。

方案一:HTTP Head Content-Length 判斷(經典舊版)

原理:請求 https://wpa.qq.com/pa?p=1:QQ號:4 返回在線/離線圖片,兩種狀態圖片大小固定不同,通過 Content-Length 區分。

function getQqStatusV1(string $uin): bool {
    $url = "https://wpa.qq.com/pa?p=1:{$uin}:4";
    $content = @file_get_contents($url);
    if ($content === false) return false; // 網絡錯誤視為離線
    
    foreach ($http_response_header as $header) {
        if (stripos($header, 'Content-Length:') === 0) {
            $length = (int)trim(substr($header, 15));
            // 經驗閾值:在線圖片 > 1000 bytes,離線較小
            return $length > 1000;
        }
    }
    return false;
}

缺點:騰訊可能隨時調整圖片大小、壓縮算法,閾值失效;依賴 allow_url_fopen;無法獲取昵稱。

方案二:Socket 直連分析 Location Header(穩健版)

原理:模擬 HTTP 請求 wpa.qq.com/pa?p=1:QQ號:1,解析響應中的 Location 重定向 URL,包含 online 或 offline 關鍵字。

function getQqStatusV2(string $uin): int {
    // -1: 錯誤, 0: 離線, 1: 在線
    $request = "GET /pa?p=1:{$uin}:1 HTTP/1.1\r\n";
    $request .= "Host: wpa.qq.com\r\n";
    $request .= "User-Agent: PHP_QQ_STATUS_CHECKER\r\n";
    $request .= "Connection: Close\r\n\r\n";
    
    $socket = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
    if (!$socket) return -1;
    
    if (!@socket_connect($socket, 'wpa.qq.com', 80)) {
        socket_close($socket);
        return -1;
    }
    
    socket_write($socket, $request);
    $response = @socket_read($socket, 2048, PHP_BINARY_READ);
    socket_close($socket);
    
    if (!$response) return -1;
    
    foreach (explode("\r\n", $response) as $line) {
        if (stripos($line, 'Location:') === 0) {
            if (stripos($line, 'online') !== false) return 1;
            if (stripos($line, 'offline') !== false) return 0;
            return -1;
        }
    }
    return -1;
}

優點:不依賴 allow_url_fopen,可控超時,解析邏輯穩健。缺點:需 sockets 擴展,無法獲取昵稱。

方案三:綜合接口獲取昵稱 + 狀態(推薦生產用)

原理:

  • 狀態:請求 https://wpa.qq.com/pa?p=2:QQ號:41,通過 Content-Length 固定值(如 1243)判斷在線。
  • 昵稱:請求 https://r.qzone.qq.com/cgi-bin/user/cgi_personal_card?uin=QQ號,返回 JSONP,提取 nickname 字段。
class QqUserInfo {
    private const STATUS_URL = 'https://wpa.qq.com/pa?p=2:%s:41&r=%d';
    private const NICK_URL   = 'https://r.qzone.qq.com/cgi-bin/user/cgi_personal_card?uin=%s';
    private const ONLINE_CONTENT_LENGTH = 1243; // 經驗值,需定期驗證
    private $timeout = 3; // 秒
    
    /**
     * 獲取在線狀態
     * @return bool|null true在線 false離線 null失敗
     */
    public function getStatus(string $uin): ?bool {
        $url = sprintf(self::STATUS_URL, $uin, time());
        $headers = @get_headers($url, 1);
        if ($headers === false) return null;
        
        $length = $headers['Content-Length'] ?? 0;
        return (int)$length === self::ONLINE_CONTENT_LENGTH;
    }
    
    /**
     * 獲取昵稱
     * @return string|false
     */
    public function getNickname(string $uin): string|false {
        $url = sprintf(self::NICK_URL, $uin);
        $content = @file_get_contents($url);
        if ($content === false) return false;
        
        // 響應格式:portraitCallBack({"nickname":"xxx",...});
        if (preg_match('/"nickname"\s*:\s*"([^"]+)"/', $content, $matches)) {
            return $matches[1];
        }
        return false;
    }
    
    /**
     * 綜合獲取
     * @return array ['nickname'=>string|false, 'online'=>bool|null, 'uin'=>string]
     */
    public function getInfo(string $uin): array {
        return [
            'uin' => $uin,
            'nickname' => $this->getNickname($uin),
            'online' => $this->getStatus($uin),
        ];
    }
}

// 使用示例
$qq = new QqUserInfo();
$info = $qq->getInfo('561272831');
var_dump($info);
/*
array(3) {
  'uin' => '561272831'
  'nickname' => '張三'
  'online' => true
}
*/

生產環境優化與風險控制

1. 緩存策略(核心)

function getQqInfoCached(string $uin): array {
    $redis = new Redis();
    $redis->connect('127.0.0.1', 6379);
    $key = "qq:info:{$uin}";
    
    if ($cached = $redis->get($key)) {
        return json_decode($cached, true);
    }
    
    $qq = new QqUserInfo();
    $info = $qq->getInfo($uin);
    
    // 緩存 10 分鐘,狀態變化允許延遲
    $redis->setex($key, 600, json_encode($info));
    return $info;
}

2. 併發控制與限流

  • 單 IP 調用頻率限制(如 30 次/分鐘),防止被騰訊封禁 IP。
  • 使用連接池復用 Socket/HTTP 連接(Swoole/Workerman 環境下)。
  • 異步隊列預熱熱門 QQ 號緩存。

3. 多節點部署與 IP 池

高併發場景下,部署多台服務器輪詢調用,或使用代理 IP 池分散請求來源。

4. 監控與告警

  • 監控 API 成功率、響應時間、Content-Length 閾值變化。
  • 閾值異常自動告警(騰訊調整圖片大小會導致判斷失效)。

法律與合規提醒

⚠️ 重要:上述接口均為騰訊內部/未公開接口,**非官方開放 API**。使用前請評估:

  • 是否違反《騰訊服務協議》、《計算機信息網絡國際聯網管理暫行規定》等法規。
  • 是否構成非法獲取公民個人信息(昵稱屬個人信息)。
  • 高頻調用可能被判定為攻擊行為,面臨 IP 封禁、法律追責風險。

建議:

  1. 優先引導用戶授權登錄(QQ 互聯 OAuth2.0),合法獲取 OpenID、昵稱、頭像。
  2. 若必須使用非官方接口,嚴格控制頻率、加緩存、做降級、記錄審計日志。
  3. 關鍵業務**不依賴**此類非穩定接口,僅作輔助展示。

總結

方案獲取狀態獲取昵稱穩定性依賴推薦度
Content-Length 判斷✓✗低allow_url_fopen⭐
Socket Location 解析✓✗中sockets 擴展⭐⭐
綜合接口 (推薦)✓✓中allow_url_fopen / sockets⭐⭐⭐
QQ 互聯 OAuth2.0 (官方)✗✓高官方 SDK⭐⭐⭐⭐⭐ (合規首選)

技術無罪,用途定性。**合規合法、緩存優先、降級兜底、監控告警** 是生產環境接入非官方接口的鐵律。

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