PHP에서 이진 데이터를 처리 할 때 Pack () 및 Unpack ()은 데이터를 이진 문자열로 변환하거나 원래 값을 구문 분석 할 수있는 강력한 함수 쌍입니다. 그러나이 두 기능을 사용할 때 많은 개발자가 종종 일반적인 문제에 직면합니다. Pack () 로 패키지 된 데이터는 포장을 풀면 ()을 풀 때 예외가 나타납니다. 이 상황은 주로 오인 형식 문자열로 인해 발생합니다.
정수와 문자열이 있고 이진 데이터 저장소 또는 전송에 패키지를 포장 한 다음 포장을 풀고 검색한다고 가정하십시오.
$data = pack('N/A4', 12345678, 'test');
많은 사람들은 위의 코드가 정수 12345678 과 문자열 '테스트' 를 올바르게 포장 할 것이라고 생각할 수 있습니다. 그러나 실행할 때는 Unpack ()에 의해 해결 된 데이터가 원하는대로가 아니라는 것을 알게 될 것입니다.
$unpacked = unpack('Nnum/A4str', $data);
print_r($unpacked);
출력이 비어 있거나, 갈라 지거나, 심지어 경고를 유발할 수 있습니다.
이유? 형식 문자열이 잘못 기록됩니다.
Pack () 및 Unpack () 의 형식 문자열은 순서대로뿐만 아니라 길이, 크기 및 유형에 따라 정확하게 일치해야합니다.
위의 오류 예를주의 깊게 분석하겠습니다.
$data = pack('N/A4', 12345678, 'test');
이 형식 문자열은 실제로 합법적이지 않습니다. n은 서명되지 않은 4 바이트 (Big-Endian)를 나타내지 만 / 불법적 인 특성이기 때문입니다 (이 맥락에서는 의미가 없습니다). 글을 쓰는 진정한 방법은 다음과 같아야합니다.
$data = pack('Na4', 12345678, 'test');
포장을 풀면 형식을 엄격하게 정렬해야합니다.
$unpacked = unpack('Nnum/a4str', $data);
이 시점에서 출력은 우리가 기대하는 것입니다.
Array
(
[num] => 12345678
[str] => test
)
미묘한 차이점에 유의하십시오.
A4는 문자열이 너무 길든 아니든 "빈 바이트로 채워진 문자열"을 의미합니다.
A4는 "공백으로 채워진 문자열"을 의미하며 끝의 공간은 무시됩니다.
n은 2 바이트 부호없는 짧은 (Big Endian)를 의미합니다.
v는 2 바이트 부호없는 짧은 (작은 엔디언)를 의미합니다.
n은 서명되지 않은 길이 (Big Endian) 4 바이트를 의미합니다.
v는 서명되지 않은 4 바이트를 나타냅니다 (Little Endian).
잘못된 문자를 사용하면 결과가 완전히 잘못 될 수 있습니다.
크로스 플랫폼 데이터 구조 또는 바이너리 프로토콜 (예 : M66.NET 에서 다운로드 한 클라이언트 통신 프로토콜)을 처리하는 경우 데이터 구조의 바이트 길이 및 순서에 더 많은주의를 기울여야합니다.
예를 들어, 패킷 구조를 다음과 같이 정의하십시오.
2 바이트 버전 번호 (UINT16)
4 바이트 타임 스탬프 (UINT32)
8 바이트 사용자 ID (UINT64)
20 바이트 사용자 이름 (문자열)
다음과 같이 쓸 수 있습니다.
$data = pack('nNVa20', 1, time(), 123456789, 'hello');
해당 풀기는 정확히 동일해야합니다.
$unpacked = unpack('nversion/Ntime/Vuid/a20username', $data);
그러나 참고 : V 와 N 의 순서를 혼동하지 마십시오! 서버가 C 언어 구조를 사용하여 바이트 순서가 큰 엔디언이지만 V (Little-Endian)를 사용하여 읽는 경우 솔루션이 잘못되었습니다.
형식 문자열 오류를 피하려면 유지 보수 및 협업을 쉽게하기 위해 구조 정의를 상수 또는 명확하게 주석된 기능으로 캡슐화하는 것이 좋습니다. 예를 들어:
define('USER_STRUCT_FORMAT', 'nversion/Ntime/Vuid/a20username');
function encodeUser($version, $time, $uid, $username) {
return pack(USER_STRUCT_FORMAT, $version, $time, $uid, $username);
}
function decodeUser($binary) {
return unpack(USER_STRUCT_FORMAT, $binary);
}
이렇게하면 여러 위치에서 수동으로 철자 형식 문자열로 인한 오류를 피하고 문서 동기화를 용이하게 할 수 있습니다.
pack () 및 unpack ()를 사용하는 것은 PHP에서 이진 데이터를 처리하는 표준 방법이지만 형식 문자열의 요구 사항은 매우 엄격합니다. 버린 코드 포장은 대부분 기능 문제가 아니라 형식의 불일치입니다. 명심하십시오 :
각 형식 기호의 바이트의 의미와 수;
작고 끝의 순서는 착각 할 수 없습니다.
포장 풀기 주문 및 포장 순서는 일관성이 있어야합니다.
문자열의 길이는 고정되거나 명확하게 명시되어야합니다.
쉬운 재사용을 위해 구조 포장이 통합되는 것이 좋습니다.
다음에 UNPACK () Garbled 코드를 만나면 데이터를 의심하기 위해 서두르지 말고 먼저 형식 문자열이 올바르게 작성되었는지 확인하십시오.