현재 위치: > 최신 기사 목록> Unpack ()가 잘못된 데이터를 얻습니까? pack ()의 ​​형식이 올바르지 않을 수 있습니다

Unpack ()가 잘못된 데이터를 얻습니까? pack ()의 ​​형식이 올바르지 않을 수 있습니다

M66 2025-05-28

PHP에서 이진 데이터를 처리 할 때 Pack ()Unpack ()은 데이터를 이진 문자열로 변환하거나 원래 값을 구문 분석 할 수있는 강력한 함수 쌍입니다. 그러나이 두 기능을 사용할 때 많은 개발자가 종종 일반적인 문제에 직면합니다. Pack () 로 패키지 된 데이터는 포장을 풀면 ()을 풀 때 예외가 나타납니다. 이 상황은 주로 오인 형식 문자열로 인해 발생합니다.

일반적인 "barlybled"시나리오

정수와 문자열이 있고 이진 데이터 저장소 또는 전송에 패키지를 포장 한 다음 포장을 풀고 검색한다고 가정하십시오.

 $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);

그러나 참고 : VN 의 순서를 혼동하지 마십시오! 서버가 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 코드를 만나면 데이터를 의심하기 위해 서두르지 말고 먼저 형식 문자열이 올바르게 작성되었는지 확인하십시오.