If you'd like to understand pack/unpack. There is a tutorial here in perl, that works equally well in understanding it for php:
http://perldoc.perl.org/perlpacktut.html(PHP 4, PHP 5, PHP 7, PHP 8)
pack — データをバイナリ文字列にパックする
   指定された引数を format に基づいて
   バイナリ文字列にパックします。
  
この関数のアイデアは Perl からのものであり、フォーマット指定用の コードは Perl と同様に動作します。しかし、中には存在しない書式コードもあります。 たとえば Perl の "u" は存在しません。
符号付及び符号無しの区別は関数 unpack() にのみ 影響を与えます。関数 pack() は符号付及び符号無しの フォーマットコードのどちらでも同じ結果となることに注意しましょう。
format
       フォーマット文字列は、
       フォーマットコードの後にオプションの反復指定用引数が続く形式と
       なっています。反復指定用引数として整数値、または入力データの最後まで
       反復を意味する * のどちらかを指定することができます。
       a, A, h, H の場合、
       反復数はそのデータ引数が取得する文字の数を指定します。反復数が @ の場合、
       次のデータを置く場所の絶対位置を表します。その他の場合、反復数は
       データ引数が使われる数を指定し、結果のバイナリ文字列にパックされます。
      
現在、実装されているものを以下に示します。
| コード | 説明 | 
|---|---|
| a | NUL で埋めた文字列 | 
| A | 空白で埋めた文字列 | 
| h | 十六進文字列、下位ニブルが先 | 
| H | 十六進文字列、上位ニブルが先 | 
| c | signed char | 
| C | unsigned char | 
| s | signed short (常に 16 ビット、マシンのバイトオーダー) | 
| S | unsigned short (常に 16 ビット、マシンのバイトオーダー) | 
| n | unsigned short (常に 16 ビット、ビッグエンディアンバイトオーダー) | 
| v | unsigned short (常に 16 ビット、リトルエンディアンバイトオーダー) | 
| i | signed integer (サイズおよびバイトオーダーはマシン依存) | 
| I | unsigned integer (サイズおよびバイトオーダーはマシン依存) | 
| l | signed long (常に 32 ビット、マシンのバイトオーダー) | 
| L | unsigned long (常に 32 ビット、マシンのバイトオーダー) | 
| N | unsigned long (常に 32 ビット、ビッグエンディアンバイトオーダー) | 
| V | unsigned long (常に 32 ビット、リトルエンディアンバイトオーダー) | 
| q | signed long long (常に 64 ビット、マシンのバイトオーダー) | 
| Q | unsigned long long (常に 64 ビット、マシンのバイトオーダー) | 
| J | unsigned long long (常に 64 ビット、ビッグエンディアンバイトオーダー) | 
| P | unsigned long long (常に 64 ビット、リトルエンディアンバイトオーダー) | 
| f | float (サイズおよび表現はマシン依存) | 
| g | float (サイズはマシン依存。 リトルエンディアンバイトオーダー) | 
| G | float (サイズはマシン依存。 ビッグエンディアンバイトオーダー) | 
| d | double (サイズおよび表現はマシン依存) | 
| e | double (サイズはマシン依存。 リトルエンディアンバイトオーダー) | 
| E | double (サイズはマシン依存。 ビッグエンディアンバイトオーダー) | 
| x | NUL バイト | 
| X | 1 バイト戻る | 
| Z | NUL終端(ASCIIZ) 文字列をNUL で埋める | 
| @ | 絶対位置まで NUL で埋める | 
values
バイナリ文字列を含むデータを返します。
| バージョン | 説明 | 
|---|---|
| 8.0.0 | この関数は、失敗時に falseを返さなくなりました。 | 
| 7.2.0 | float と double 型は、ビッグエンディアンとリトルエンディアンを両方サポートしました。 | 
| 7.0.15, 7.1.1 | "e", "E", "g" および "G" コードが、float と double のバイトオーダーをサポートするために追加されました。 | 
例1 pack() の例
<?php
$binarydata = pack("nvc*", 0x1234, 0x5678, 65, 66);
?>この結果のバイナリ文字列の長さは 6 バイト長で、バイト列 0x12, 0x34, 0x78, 0x56, 0x41, 0x42となります。
フォーマットコード q, Q, J,
    P は、32ビット版のPHPビルドでは利用できません
PHP は、int 型の値を内部的に格納する際に サイズがマシン依存の符号付き値を使うことに注意しましょう。int 型の範囲外の数値となる整数リテラルや演算結果は float として保持されます。この float 値を integer としてパックする際には まず最初に integer 型へのキャストを行います。 その結果、できあがるバイトパターンは期待通りにはならないかもしれません。
    この問題にもっとも関連するのが、符号なしの数値で int
    型で表現できるものをパックする場合です。
    int 型のサイズが 32 ビットであるシステムでのキャスト結果は、
    (実装で定義されている標準 C の符号なし型から符号付き型への変換に依存しますが)
    まるで int が符号なし整数であるかのような同一のバイトパターンになることがよくあります。
    int 型のサイズが 64 ビットであるシステムでは、
    たいていの場合は float の仮数部のサイズが足りず、
    値の精度を損なわずに保持することができません。
    ネイティブの 64 ビット C int 型を持つシステム
    (UNIX 系システムのほとんどは持っていません) では、上側の範囲の値で
    パック書式 I を使うための唯一の方法は、
    希望する符号なし値と同じバイト表現になるような負の
    int 値を作ることになります。
   
If you'd like to understand pack/unpack. There is a tutorial here in perl, that works equally well in understanding it for php:
http://perldoc.perl.org/perlpacktut.htmlA helper class to convert integer to binary strings and vice versa. Useful for writing and reading integers to / from files or sockets.
<?php
    class int_helper
    {
        public static function int8($i) {
            return is_int($i) ? pack("c", $i) : unpack("c", $i)[1];
        }
        public static function uInt8($i) {
            return is_int($i) ? pack("C", $i) : unpack("C", $i)[1];
        }
        public static function int16($i) {
            return is_int($i) ? pack("s", $i) : unpack("s", $i)[1];
        }
        public static function uInt16($i, $endianness=false) {
            $f = is_int($i) ? "pack" : "unpack";
            if ($endianness === true) {  // big-endian
                $i = $f("n", $i);
            }
            else if ($endianness === false) {  // little-endian
                $i = $f("v", $i);
            }
            else if ($endianness === null) {  // machine byte order
                $i = $f("S", $i);
            }
            return is_array($i) ? $i[1] : $i;
        }
        public static function int32($i) {
            return is_int($i) ? pack("l", $i) : unpack("l", $i)[1];
        }
        public static function uInt32($i, $endianness=false) {
            $f = is_int($i) ? "pack" : "unpack";
            if ($endianness === true) {  // big-endian
                $i = $f("N", $i);
            }
            else if ($endianness === false) {  // little-endian
                $i = $f("V", $i);
            }
            else if ($endianness === null) {  // machine byte order
                $i = $f("L", $i);
            }
            return is_array($i) ? $i[1] : $i;
        }
        public static function int64($i) {
            return is_int($i) ? pack("q", $i) : unpack("q", $i)[1];
        }
        public static function uInt64($i, $endianness=false) {
            $f = is_int($i) ? "pack" : "unpack";
            if ($endianness === true) {  // big-endian
                $i = $f("J", $i);
            }
            else if ($endianness === false) {  // little-endian
                $i = $f("P", $i);
            }
            else if ($endianness === null) {  // machine byte order
                $i = $f("Q", $i);
            }
            return is_array($i) ? $i[1] : $i;
        }
    }
?>
Usage example:
<?php
    Header("Content-Type: text/plain");
    include("int_helper.php");
    echo int_helper::uInt8(0x6b) . PHP_EOL;  // k
    echo int_helper::uInt8(107) . PHP_EOL;  // k
    echo int_helper::uInt8("\x6b") . PHP_EOL . PHP_EOL;  // 107
    echo int_helper::uInt16(4101) . PHP_EOL;  // \x05\x10
    echo int_helper::uInt16("\x05\x10") . PHP_EOL;  // 4101
    echo int_helper::uInt16("\x05\x10", true) . PHP_EOL . PHP_EOL;  // 1296
    echo int_helper::uInt32(2147483647) . PHP_EOL;  // \xff\xff\xff\x7f
    echo int_helper::uInt32("\xff\xff\xff\x7f") . PHP_EOL . PHP_EOL;  // 2147483647
    // Note: Test this with 64-bit build of PHP
    echo int_helper::uInt64(9223372036854775807) . PHP_EOL;  // \xff\xff\xff\xff\xff\xff\xff\x7f
    echo int_helper::uInt64("\xff\xff\xff\xff\xff\xff\xff\x7f") . PHP_EOL . PHP_EOL;  // 9223372036854775807
?>Note that the the upper command in perl looks like this:
$binarydata = pack ("n v c*", 0x1234, 0x5678, 65, 66);
In PHP it seems that no whitespaces are allowed in the first parameter. So if you want to convert your pack command from perl -> PHP, don't forget to remove the whitespaces!If you need to unpack a signed short from big-endian or little-endian specifically, instead of machine-byte-order, you need only unpack it as the unsigned form, and then if the result is >= 2^15, subtract 2^16 from it.
And example would be:
<?php
$foo = unpack("n", $signedbigendianshort);
$foo = $foo[1];
if($foo >= pow(2, 15)) $foo -= pow(2, 16);
?>/* Convert float from HostOrder to Network Order */
function FToN( $val )
{
    $a = unpack("I",pack( "f",$val ));
    return pack("N",$a[1] );
}
    
/* Convert float from Network Order to HostOrder */
function NToF($val )
{
    $a = unpack("N",$val);
    $b = unpack("f",pack( "I",$a[1]));
    return $b[1];
}You will get the same effect with
<?php
function _readInt($fp)
{
   return unpack('V', fread($fp, 4));
}
?>
or unpack('N', ...) for big-endianness.Even though in a 64-bit architecure intval(6123456789) = 6123456789, and sprintf('%b', 5000000000) = 100101010000001011111001000000000
pack will not treat anything passed to it as 64-bit.  If you want to pack a 64-bit integer:
<?php
$big = 5000000000;
$left = 0xffffffff00000000;
$right = 0x00000000ffffffff;
$l = ($big & $left) >>32;
$r = $big & $right;
$good = pack('NN', $l, $r);
$urlsafe = str_replace(array('+','/'), array('-','_'), base64_encode($good));
//done!
//rebuild:
$unurl =  str_replace(array('-','_'), array('+','/'), $urlsafe);
$binary = base64_decode($unurl);
$set = unpack('N2', $tmp);
print_r($set);
$original = $set[1] << 32 | $set[2];
echo $original, "\\r\\n";
?>
results in:
Array
(
    [1] => 1
    [2] => 705032704
)
5000000000
but ONLY on a 64-bit enabled machine and PHP distro.Be aware of format code H always padding the 0 for byte-alignment to the right (for odd count of nibbles).
So pack("H", "7") results in 0x70 (ASCII character 'p') and not in 0x07 (BELL character)
as well as pack("H*", "347") results in 0x34 ('4') and 0x70 ('p') and not 0x03 and 0x47.pack()
h    Hex string, low nibble first (not same hex2bin())
H    Hex string, high nibble first (same hex2bin())Using pack to write Arabic char(s) to a file.
<?php
$text = "㔆㘆㘆";
$text = mb_convert_encoding($text, "UCS-2BE", "HTML-ENTITIES");
$len =  mb_strlen($text);
$bom = mb_convert_encoding("", "unicode", "HTML-ENTITIES");
$fp = fopen('text.txt', 'w');
fwrite($fp, pack('a2', $bom));  
fwrite($fp, pack("a{$len}", $text));
fwrite($fp, pack('a2', $bom)); 
fwrite($fp, pack('a2', "\n"));
fclose($fp);
?>