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

Google PageRank 查詢接口 PHP 實現:Checksum 算法與 64 位兼容詳解

     編輯:PHP 綜合知識

背景

Google 早期提供 Toolbar PageRank 查詢接口,需計算特定 `ch` 參數(checksum)。隨著演算法更新、64 位系統普及、PHP 整數溢出行為差異,舊代碼頻繁失效。本文深度解析演算邏輯並提供跨平台兼容實現。

核心算法流程

  1. 將 URL 規範化(補全協議、規範路徑)。
  2. 計算第一輪雜湊(類似 Jenkins Hash)。
  3. **關鍵**:對第一輪結果進行**第二輪**特定位運算(移位、異或、加法)。
  4. 最終生成 `ch` 參數格式:`6` + 10 位數字。

PHP 兼容實現 (支援 32/64 位、Windows/Linux)

 [
                'timeout' => 10,
                'header' => "User-Agent: " . self::USER_AGENT . "\r\n",
            ]
        ]);
        $response = @file_get_contents($queryUrl, false, $ctx);
        if ($response === false) return false;

        // 解析回應: Rank_1:1:9
        if (preg_match('/Rank_\d+:\d+:(\d+)/', $response, $m)) {
            return (int)$m[1];
        }
        return false;
    }

    /**
     * 核心 Checksum 計算 (兼容 32/64 位)
     */
    private static function computeChecksum(string $url): string {
        $url = 'info:' . $url;
        $len = strlen($url);

        // 初始化魔數 (32 位無符號整數)
        $a = 0x9e3779b9;
        $b = 0x9e3779b9;
        $c = 0xe6359a60; // Google 魔數

        // 以 12 字節為塊處理
        $k = 0;
        while ($k + 12 <= $len) {
            $a += self::strToUInt32($url, $k);
            $b += self::strToUInt32($url, $k + 4);
            $c += self::strToUInt32($url, $k + 8);
            self::mix($a, $b, $c);
            $k += 12;
        }

        // 處理剩餘字節
        $c += $len;
        $rem = $len - $k;
        $offset = $k;
        switch ($rem) {
            case 11: $c += (self::uint32($url[$offset + 10]) << 24);
            case 10: $c += (self::uint32($url[$offset + 9]) << 16);
            case 9:  $c += (self::uint32($url[$offset + 8]) << 8);
            case 8:  $b += (self::uint32($url[$offset + 7]) << 24);
            case 7:  $b += (self::uint32($url[$offset + 6]) << 16);
            case 6:  $b += (self::uint32($url[$offset + 5]) << 8);
            case 5:  $b += self::uint32($url[$offset + 4]);
            case 4:  $a += (self::uint32($url[$offset + 3]) << 24);
            case 3:  $a += (self::uint32($url[$offset + 2]) << 16);
            case 2:  $a += (self::uint32($url[$offset + 1]) << 8);
            case 1:  $a += self::uint32($url[$offset]);
        }

        self::mix($a, $b, $c);

        // 返回 "6" + 10 位數字 (無符號 32 位整數)
        return '6' . str_pad(self::uint32ToString($c), 10, '0', STR_PAD_LEFT);
    }

    /** 字符串 4 字節轉無符號 32 位整數 (小端序) */
    private static function strToUInt32(string $str, int $offset): int {
        return self::uint32($str[$offset])
            | (self::uint32($str[$offset + 1]) << 8)
            | (self::uint32($str[$offset + 2]) << 16)
            | (self::uint32($str[$offset + 3]) << 24);
    }

    /** 字符轉無符號 8 位整數 */
    private static function uint32(string $char): int {
        return ord($char) & 0xFF;
    }

    /** 關鍵:強制模擬 32 位無符號整數運算 (解決 64 位/負數溢出) */
    private static function toUInt32(int $val): int {
        // PHP 8.0+ 可用: $val & 0xFFFFFFFF
        // 兼容舊版: 手動處理溢出
        $val &= 0xFFFFFFFF;
        // PHP 整數溢出會轉 float,需修正
        if ($val > 0x7FFFFFFF) {
            $val -= 0x100000000; // 轉為有符號負數表示,但位模式不變
        }
        return $val;
    }

    /** Jenkins Hash 混合函數 (全程 32 位運算) */
    private static function mix(int &$a, int &$b, int &$c): void {
        $a = self::toUInt32($a - $b - $c); $a ^= self::rshift($c, 13);
        $b = self::toUInt32($b - $c - $a); $b ^= ($a << 8) & 0xFFFFFFFF;
        $c = self::toUInt32($c - $a - $b); $c ^= self::rshift($b, 13);
        $a = self::toUInt32($a - $b - $c); $a ^= self::rshift($c, 12);
        $b = self::toUInt32($b - $c - $a); $b ^= ($a << 16) & 0xFFFFFFFF;
        $c = self::toUInt32($c - $a - $b); $c ^= self::rshift($b, 5);
        $a = self::toUInt32($a - $b - $c); $a ^= self::rshift($c, 3);
        $b = self::toUInt32($b - $c - $a); $b ^= ($a << 10) & 0xFFFFFFFF;
        $c = self::toUInt32($c - $a - $b); $c ^= self::rshift($b, 15);
    }

    /** 邏輯右移 (無符號右移) */
    private static function rshift(int $val, int $bits): int {
        if ($val >= 0) return $val >> $bits;
        // 負數在 PHP 中算術右移會保留符號位,需轉為無符號邏輯右移
        return ($val & 0xFFFFFFFF) >> $bits;
    }

    /** 無符號 32 位整數轉 10 位十進制字符串 */
    private static function uint32ToString(int $val): string {
        // 確保為無符號值
        $val = $val & 0xFFFFFFFF;
        // PHP 8.0+ 直接返回 (string)$val 即為無符號十進制
        // 舊版 PHP 負數需手動轉換
        if ($val > 0x7FFFFFFF) {
            // 利用 BCMath 或 sprintf('%u') (需編譯支持)
            // 這裡用純 PHP 模擬: 2^32 = 4294967296
            return (string)($val + 4294967296);
        }
        return (string)$val;
    }
}

// 使用示例
$pr = GooglePR::get('https://www.example.com');
var_dump($pr); // int(3) 或 false

關鍵兼容性難點解析

問題原因解決方案
64 位系統位移保留高位`$a >> 13` 在 64 位整數上不截斷高 32 位每步運算後 `& 0xFFFFFFFF` 強制截斷至 32 位
負數溢出轉 float 精度丟失PHP 整數超範圍自動轉 float,32 位 Linux 下負數最大只到 -2^31用 `& 0xFFFFFFFF` 保留位模式,輸出時手動加 `4294967296` 還原無符號值
Windows/Linux `sprintf('%u')` 差異Windows 支持 `%u` 無符號格式化,Linux (glibc) 不支持純 PHP 實現 `uint32ToString`,不依賴 `printf`
字符串索引 `$str[$i]` 返回字符而非 ASCII 碼PHP 特性用 `ord($str[$i]) & 0xFF` 獲取字節值

現狀提醒

  • Google **已正式關閉 Toolbar PageRank 服務** (2016 年),接口可能隨時失效、返回 404 或空內容。
  • 現代 SEO 工具(Ahrefs, Semrush, Moz)使用自有指標(DR, DA, AS 等),不再依賴 PR。
  • 本代碼僅供**算法研究、歷史項目維護、教學演示**使用,生產環境請勿依賴。

總結

Google PR `ch` 參數計算涉及雙輪雜湊、32 位無符號整數運算、邏輯右移、跨平台溢出處理。通過 `& 0xFFFFFFFF` 強制截斷、手動還原無符號十進制、純 PHP 邏輯右移,可實現 Windows/Linux、32/64 位全兼容。理解這些底層細節,對處理其他歷史加密/雜湊算法移植極有參考價值。

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