PHP에서 Pack () 함수는 데이터를 이진 문자열로 변환하는 데 매우 유용한 도구이며, 이는 네트워크 전송 또는 파일 작업에 사용하기에 편리합니다. 그러나 많은 개발자들은 다른 플랫폼 (예 : Windows, Linux 및 MACOS)에서 동일한 팩 () 기능을 사용하면 때로는 이진 데이터가 정확히 동일하지 않다는 것을 발견했습니다. 이게 왜? 이 기사는 기본 메커니즘, 플랫폼 차이 및 솔루션의 관점에서 자세히 분석 할 것입니다.
Pack () 함수는 지정된 형식에 따라 하나 이상의 데이터를 이진 문자열로 패키지합니다. 일반적인 형식은 다음과 같습니다.
C : 서명 된 캐릭터 (1 바이트)
C : 서명되지 않은 문자 (1 바이트)
S : 서명 된 짧은 정수 (2 바이트)
S : 서명되지 않은 짧은 정수 (2 바이트)
L : 서명 긴 정수 (4 바이트)
L : 서명되지 않은 긴 정수 (4 바이트)
F : 단일 정밀 부동 소수점 번호 (4 바이트)
D : 이중 정밀 플로팅 포인트 번호 (8 바이트)
예를 들어:
$data = pack("Nn", 0x12345678, 0x1234);
echo bin2hex($data);
이 코드는 네트워크 엔지니어 (Big-Endian)의 정수를 포장하며 결과는 모든 플랫폼에서 일관성이 있어야합니다.
차이는 주로 플랫폼 바이트 주문 및 기본적으로 데이터 유형 크기에 의존하는 팩 () 형식의 기호가 다음과 같이 기본적으로 있기 때문입니다.
S 및 S : 바이트 순서와 크기는 플랫폼에 의존하는 "짧은 정수"에 해당합니다 (일반적으로 2 바이트이지만 플랫폼이 거의 다를 수 있음).
L 및 L : "긴 정수"에 해당하며 크기와 엔디 니스는 플랫폼, 일반적으로 4 바이트에 따라 다르지만 일부 플랫폼은 8 바이트 일 수 있습니다.
또한 Endian Order에는 두 가지 주류가 있습니다.
Big-Endian : 높은 바이트는 낮은 주소로 저장됩니다
Little-Endian : 낮은 바이트는 낮은 주소로 저장됩니다
다른 플랫폼의 CPU는 다른 엔지니어를 사용합니다.
플랫폼/아키텍처 | 바이트 순서 |
---|---|
Windows (x86/x64) | 리틀 엔디언 |
리눅스 (x86/x64) | 리틀 엔디언 |
마코스 (인텔) | 리틀 엔디언 |
마코스 (팔) | 리틀 엔디언 |
일부 임베디드 플랫폼 | 아마도 빅 엔디 안 |
pack () 의 s 와 l은 기계의 기본 엔지니어에 따라 달라 지므로 동일한 코드의 출력은 다른 아키텍처 또는 운영 체제에서 다릅니다.
<?php
// 짧은 정수를 포장하십시오 0x1234
$data = pack("s", 0x1234);
echo bin2hex($data);
?>
소규모 엔디 언 플랫폼 (대부분의 x86 Windows/Linux 등)에서 출력은 다음과 같습니다. 3412
빅 엔디 언 플랫폼의 출력 결과는 다음과 같습니다. 1234
이것은 S가 플랫폼 엔지니어에 의존하기 때문입니다.
Pack () 의 출력 데이터가 플랫폼에서 일관되도록하는 것이 좋습니다.
바이트 순서를 지정하는 데 포맷터를 사용하십시오
PHP는 네트워크 바이트 주문 형식을 제공합니다.
N : 서명되지 않은 짧은 정수 (16 비트), 네트워크 엔디 언 (Big Endian)
N : 서명되지 않은 긴 정수 (32 비트), 네트워크 엔지니어 (Big Endian)
네이티브 엔지니어에 의존하는 S 와 L을 사용하지 말고 대신 N 과 N을 사용하십시오.
바이트 주문 변환을 사용자 정의하십시오
네이티브 엔디 어 형식을 사용해야하는 경우 먼저 pack ()를 사용한 다음 unpack () 및 strrev () 와 같은 함수를 사용하여 엔디 언을 수동으로 변환 할 수 있습니다.
명확한 데이터 크기
데이터 크기가 불확실한 경우 S 와 L을 사용하지 않고 대신 S 와 L (서명되지 않은)을 사용하여 네트워크 엔지니어와 결합하는 것이 가장 좋습니다.
<?php
// 네트워크 엔지니어를 사용하여 크로스 플랫폼 일관성을 보장하십시오
$short = 0x1234;
$long = 0x12345678;
// pack서명되지 않은 짧은 정수와 서명되지 않은 긴 정수,모든 네트워크 바이트 순서(빅 엔디언)
$data = pack("nN", $short, $long);
// 16 진수 문자열을 인쇄하십시오
echo bin2hex($data);
?>
Windows, Linux 또는 MacOS에서 실행 되든 출력은 다음과 같습니다.
123412345678
Pack () 의 일부 형태는 플랫폼 엔지니어 및 데이터 크기에 의존하여 크로스 플랫폼 출력이 일치하지 않습니다.
일반적으로 사용되는 형식 S , S , L 및 L은 다른 시스템에서 다르게 수행 될 수 있습니다.
네트워크 바이트 주문 형식 N 및 N을 사용하면 데이터의 교차 플랫폼 일관성을 보장 할 수 있습니다.
플랫폼 바이트 주문 및 데이터 유형 크기를 이해하는 것은 크로스 플랫폼 바이너리 데이터 오류를 피하기위한 핵심입니다.
이러한 세부 사항을 이해하면 이진 데이터의 구조를보다 잘 제어 할 수 있으며 다양한 프로그램 환경에서 호환성 문제를 피할 수 있습니다.