核心概念
- 32 位十六進制:
md5($str) 預設輸出,每字節 2 個十六進制字符,共 32 字符
- 16 位二進制:
md5($str, true) 輸出原始 16 字節二進制數據(可能包含不可見字符)
互轉代碼演示
<?php
$str = 'test';
// 1. 32 位十六進制(預設)
$cm = md5($str); // "098f6bcd4621d373cade4e832627b4f6"
// 2. 16 位二進制(原始)
$bm = md5($str, true); // 二進制字符串,長度 16 字節
// ---------------------------------------------------------
// 十六進制字符串 → 二進制
// ---------------------------------------------------------
// 方法一:pack(標準方式)
$bstr = pack('H*', $cm); // 等同於 $bm
// 方法二:手動轉換(教學用)
$bstr_manual = '';
for ($i = 0; $i < 32; $i += 2) {
$bstr_manual .= chr(hexdec(substr($cm, $i, 2)));
}
// ---------------------------------------------------------
// 二進制 → 十六進制字符串
// ---------------------------------------------------------
// 方法一:unpack + implode(標準方式)
$cstr = implode(unpack('H*', $bm)); // 等同於 $cm
// 方法二:bin2hex(PHP 內建,最簡潔)
$cstr2 = bin2hex($bm); // 等同於 $cm
// ---------------------------------------------------------
// 驗證與展示
// ---------------------------------------------------------
echo "原始字符串: $str\n";
echo "32位十六進制: $cm\n";
echo "bin2hex還原: $cstr2\n";
echo "pack還原長度: " . strlen($bstr) . " 字節\n";
// URL 編碼查看二進制內容
echo "urlencode(二進制): " . urlencode($bm) . "\n";
echo "urlencode(pack): " . urlencode($bstr) . "\n";
// 關鍵斷言
assert($cm === $cstr2, "hex 互轉失敗");
assert($bm === $bstr, "bin 互轉失敗");
assert($bm === $bstr_manual, "手動轉換失敗");
echo "\n✅ 所有斷言通過!\n";
?>
函數對照表
| 需求 | 推薦函數 | 備註 |
| 二進制 → 十六進制 | bin2hex($bin) | 最簡潔、效能最佳 |
| 十六進制 → 二進制 | pack('H*', $hex) | 標準打包函數 |
| 二進制 → 十六進制(陣列) | unpack('H*', $bin) | 返回陣列需 implode |
| 直接獲取二進制 MD5 | md5($str, true) | 參數 true 關鍵 |
實際應用場景
- 數據庫存儲:二進制
BINARY(16) 節省 50% 空間(vs CHAR(32))
- 網絡傳輸:二進制體積小,但需 Base64 編碼放入 JSON/Header
- 加密/簽名:HMAC、AES 金鑰派生常需原始二進制
- 索引/比較:二進制比較比字符串快,MySQL
BINARY 索引更高效
資料庫字段選型建議
-- 推薦:二進制存儲(最省空間、最快比較)
`md5_hash` BINARY(16) NOT NULL
-- 兼容舊系統:十六進制字符串
`md5_hash` CHAR(32) NOT NULL COLLATE ascii_bin
-- 插入示例(PDO)
$stmt = $pdo->prepare("INSERT INTO files (md5_hash) VALUES (?)");
$stmt->bindValue(1, md5($content, true), PDO::PARAM_LOB); // 或 PARAM_STR
$stmt->execute();
-- 查詢示例
$stmt = $pdo->prepare("SELECT * FROM files WHERE md5_hash = ?");
$stmt->bindValue(1, md5($searchContent, true), PDO::PARAM_LOB);
$stmt->execute();
常見坑點
md5($str, true) 返回的二進制字符串不能直接 用 echo 輸出、json_encode、存入文本字段
unpack('H*', ...) 返回關聯陣列(鍵名為 1),需 implode 或 reset 取值
- PHP 8.0+ 可用
$hash >>> 0 處理無符號整數,舊版用 sprintf('%u', $hash)