PHP pack('H*', $hexStr) 與 unpack('H*', $binary) 常用於二進位協議、加密資料處理。Java 標準庫無直接對應方法,本文提供一個工具類 PackUtil,完整相容 PHP 行為,支援十六進制字串 ↔ 位元組陣列雙向轉換。
package qghl.intp.util;
import java.io.IOException;
import java.io.InputStream;
public class PackUtil {
/**
* 相容 PHP pack('H*', $str)
* 將十六進制字串轉為 byte[]
* 例:pack("48656c6c6f") → [0x48, 0x65, 0x6c, 0x6c, 0x6f] ("Hello")
*/
public static byte[] pack(String str) {
int nibbleShift = 4;
int position = 0;
int len = str.length() / 2 + str.length() % 2;
byte[] output = new byte[len];
for (char c : str.toCharArray()) {
byte n = (byte) c;
if (n >= '0' && n <= '9') {
n -= '0';
} else if (n >= 'A' && n <= 'F') {
n -= ('A' - 10);
} else if (n >= 'a' && n <= 'f') {
n -= ('a' - 10);
} else {
continue; // 忽略非十六進制字元
}
output[position] |= (n << nibbleShift);
if (nibbleShift == 0) {
position++;
}
nibbleShift = (nibbleShift + 4) & 7; // 在 4 和 0 之間切換
}
return output;
}
/**
* 相容 PHP unpack('H*', $bin)
* 將 byte[] 轉為十六進制字串(小寫,無前綴)
*/
public static String unpack(byte[] bytes) {
if (bytes == null || bytes.length == 0) return null;
StringBuilder sb = new StringBuilder(bytes.length * 2);
for (byte b : bytes) {
int v = b & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) sb.append('0');
sb.append(hv);
}
return sb.toString();
}
/** 從 InputStream 讀取指定長度並 unpack */
public static String unpack(InputStream is, int len) throws IOException {
byte[] bytes = new byte[len];
int read = is.read(bytes);
if (read != len) throw new IOException("Incomplete read");
return unpack(bytes);
}
}
| PHP 程式碼 | PHP 結果 | Java 呼叫 | Java 結果 |
|---|---|---|---|
pack('H*', '48656c6c6f') | "Hello" (bytes) | PackUtil.pack("48656c6c6f") | [72, 101, 108, 108, 111] |
unpack('H*', "Hello") | ['' => '48656c6c6f'] | PackUtil.unpack("Hello".getBytes()) | "48656c6c6f" |
pack('H*', 'abc') | [0xab, 0xc0] (奇數長度補 0) | PackUtil.pack("abc") | [0xab, 0xc0] |
VARBINARY 欄位,應用層以 Hex 字串序列化/反序列化pack() 產生的資料,Java 端用 PackUtil.unpack() 還原pack() 接受大小寫混合的 Hex 字串,輸出 unpack() 固定小寫。pack('H*') 遇非 Hex 字元會跳過,本實作行為一致。"abc" 視為 "ab" + "c0",本實作同樣處理。DatatypeConverter.parseHexBinary() (JDK 內建) 或 Hex.decodeHex() (Apache Commons Codec),但需確認行為完全一致。PackUtil 以約 50 行程式碼完整複現 PHP pack/unpack('H*') 語意,解決跨語言二進位資料互通難題。專案若已引入 Commons Codec,建議改用 Hex 類別並撰寫單元測試驗證相容性,減少維護成本。