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

PHP 將字串轉為十六進制輸出:hex_dump 完整實作

     編輯:PHP 相關知識

前言

除錯二進位協定、檢視檔案標頭、分析加密資料時,常需將字串/二進位資料以十六進制(Hex Dump)格式輸出。本文提供一個功能完整的 hex_dump() 函式,支援自訂每行位元組數、不可列印字元替代符號、位移顯示,並附帶詳細原理解析。

一、核心實作:hex_dump()

<?php
/**
 * 將二進位資料以十六進制 + ASCII 形式輸出(類似 xxd / hexdump -C)
 *
 * @param string $data      輸入資料(可含 null byte)
 * @param string $newline   換行符,預設 "\n"
 * @param int    $width     每行位元組數,預設 16
 * @param string $padChar   不可列印字元替代符,預設 '.'
 * @return void 直接輸出至標準輸出
 */
function hex_dump(string $data, string $newline = "\n", int $width = 16, string $padChar = '.'): void {
    // 建立位元組 → 可列印字元 對應表(靜態快取)
    static $from = '';
    static $to   = '';
    if ($from === '') {
        for ($i = 0; $i <= 0xFF; $i++) {
            $from .= chr($i);
            $to   .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $padChar;
        }
    }

    // 1. 轉為十六進制字串,再按 $width*2 切分(每位元組 2 字元)
    $hexLines = str_split(bin2hex($data), $width * 2);
    // 2. 原始資料做字元轉換,再按 $width 切分
    $charLines = str_split(strtr($data, $from, $to), $width);

    $offset = 0;
    foreach ($hexLines as $i => $line) {
        // 將十六進制字串每 2 字元一組(如 "7468" → "74 68")
        $hexFormatted = implode(' ', str_split($line, 2));
        // 輸出:位移(6位十六進制) : 十六進制內容 [ASCII 內容]
        echo sprintf('%06X', $offset) . ' : ' . $hexFormatted . ' [' . $charLines[$i] . ']' . $newline;
        $offset += $width;
    }
}

// 測試
$test = "this is a test\x00\x99hex_dump";
hex_dump($test);
/* 輸出範例:
000000 : 74 68 69 73 20 69 73 20 61 20 74 65 73 74 00 99 [this is a test..]
000010 : 68 65 78 5f 64 75 6d 70 [hex_dump]
*/
?>

二、關鍵技術點解析

  1. bin2hex():將二進位資料轉為十六進制字串,效能極佳(C 層實作)。
  2. strtr($data, $from, $to):單次遍歷完成所有位元組的字元轉換,比迴圈 chr() 快數倍。
  3. str_split(..., $width * 2):十六進制字串每位元組佔 2 字元,故寬度乘 2。
  4. sprintf('%06X', $offset):位移以 6 位十六進制顯示(支援最大 16MB),對齊美觀。

三、進階版:回傳字串而非直接輸出

<?php
function hex_dump_str(string $data, int $width = 16, string $padChar = '.'): string {
    static $from = '', $to = '';
    if ($from === '') {
        for ($i = 0; $i <= 0xFF; $i++) {
            $from .= chr($i);
            $to   .= ($i >= 0x20 && $i <= 0x7E) ? chr($i) : $padChar;
        }
    }
    $hexLines  = str_split(bin2hex($data), $width * 2);
    $charLines = str_split(strtr($data, $from, $to), $width);
    $out = '';
    $offset = 0;
    foreach ($hexLines as $i => $line) {
        $out .= sprintf('%06X', $offset) . ' : ' . implode(' ', str_split($line, 2))
             . ' [' . $charLines[$i] . ']' . "\n";
        $offset += $width;
    }
    return $out;
}

// 用法:寫入日誌、回傳 API、單元測試比對
$log = hex_dump_str($binaryPacket);
file_put_contents('packet.log', $log, FILE_APPEND);
?>

四、應用場景範例

1. 檢查 PNG 檔案標頭

<?php
$pngHeader = file_get_contents('image.png', false, null, 0, 8);
echo hex_dump_str($pngHeader);
// 輸出:000000 : 89 50 4e 47 0d 0a 1a 0a [.PNG....]
?>

2. 除錯 TCP 封包內容

<?php
$packet = "\x00\x01\x00\x00GET / HTTP/1.1\r\nHost: example.com\r\n\r\n";
hex_dump($packet);
/* 輸出:
000000 : 00 01 00 00 47 45 54 20 2f 20 48 54 54 50 2f 31 [....GET / HTTP/1]
000010 : 2e 31 0d 0a 48 6f 73 74 3a 20 65 78 61 6d 70 6c [.1..Host: exampl]
000020 : 65 2e 63 6f 6d 0d 0a 0d 0a                        [e.com....]
*/
?>

3. 比對加密前後資料

<?php
$plain = "Secret data 123";
$key   = "mykey";
$cipher = openssl_encrypt($plain, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
echo "Plain:\n";  hex_dump($plain);
echo "Cipher:\n"; hex_dump($cipher);
?>

五、效能優化建議

  • 大資料流:避免一次 file_get_contents 讀入巨大檔案,改用 fread($fp, 8192) 分塊處理並即時輸出。
  • 靜態快取:$from/$to 表格只建立一次,後續呼叫零成本。
  • 輸出緩衝:大量輸出時用 ob_start() 避免頻繁 I/O。

結語

hex_dump() 是開發者除錯二進位資料的瑞士刀。本文實作僅用核心函式 bin2hex、strtr、str_split 即達到專業工具級輸出格式,無需外部擴展。將其納入專案共用 Debug 類別,即可隨時快速檢視資料真面目。

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