除錯二進位協定、檢視檔案標頭、分析加密資料時,常需將字串/二進位資料以十六進制(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]
*/
?>
bin2hex():將二進位資料轉為十六進制字串,效能極佳(C 層實作)。strtr($data, $from, $to):單次遍歷完成所有位元組的字元轉換,比迴圈 chr() 快數倍。str_split(..., $width * 2):十六進制字串每位元組佔 2 字元,故寬度乘 2。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);
?>
<?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....]
?>
<?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....]
*/
?>
<?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) 分塊處理並即時輸出。ob_start() 避免頻繁 I/O。hex_dump() 是開發者除錯二進位資料的瑞士刀。本文實作僅用核心函式 bin2hex、strtr、str_split 即達到專業工具級輸出格式,無需外部擴展。將其納入專案共用 Debug 類別,即可隨時快速檢視資料真面目。