PHP - Запись и чтение бинарных файлов

2014-03-04
PHP

Для записи и чтения бинарных файлов в PHP есть две функции pack() и unpack(). Более подробно они писаны на оф. сайте:

Пример записи и чтения массива

Далее пример записи массива в бинарный файл и чтение из него:

<?php

////////////////// Запись массива в бинарный файл //////////////////

//id,login,email,phone
$users = [
    [1, 'user1', 'user1@mail.com', 786214569851],
    [2, 'user2', 'user2@mail.com', 786214569852],
    [3, 'user3', 'user3@mail.com', 786214569853],
];

$bin = '';
foreach ($users as $values) {
    list($id, $login, $email, $phone) = $values;
    $loginLength = strlen($login);
    $emailLength = strlen($email);

    /*
    Записываем $loginLength и $emailLength, 
    они нам понадобятся при чтении из бинарного файла.

    I2 - означает что будут идти два целочисленных без знаковых параметра, 
    в данном случае $id и $loginLength.

    a{$loginLength} - Строка длинной $loginLength

    и т.д.
    */
    $bin .= pack("I2a{$loginLength}Ia{$emailLength}I", 
        $id, $loginLength, $login, $emailLength, $email, $phone);
}

$handle = fopen('users.bin', 'wb');
fwrite($handle, $bin);
fclose($handle);

////////////////// Чтение из бинарного файла в массив //////////////////

$users = [];
$handle = fopen('users.bin', 'rb');
$size = filesize ('users.bin');

/*
Читаем до тех пор, пока внутренний указатель файла не окажется на последнем байте.
Т.е. пока не достигнем конца файла.
*/
while(ftell($handle) < $size) {
    /*
    Параметр I, который использовался в функции pack означает целочисленное 
    без знаковое число длинной в 4 байта. Поэтому считываем эти 4 байта.
    */
    $data = fread($handle, 4);
    $data = unpack('Iid', $data);
    $result['id'] = $data['id'];

    // Получаем длину логина для того что бы знать,
    // сколько байт считать для его получения
    $data = fread($handle, 4);
    $data = unpack('Ilength', $data);
    $loginLength = $data['length'];

    // После того как узнали длину логина в байтах,
    // считываем это кол-во байт и получаем логин
    $data = fread($handle, $loginLength);
    $data = unpack('a*login', $data);
    $result['login'] = $data['login'];

    $data = fread($handle, 4);
    $data = unpack('Ilength', $data);
    $emailLength = $data['length'];

    $data = fread($handle, $emailLength);
    $data = unpack('a*email', $data);
    $result['email'] = $data['email'];

    $data = fread($handle, 4);
    $data = unpack('Iphone', $data);
    $result['phone'] = $phone;

    $users[] = $result;
}
fclose($handle);

print_r($users);

Результатом работы данного скрипта будет по сути исходный массив, который и был записан в бинарный файл, т.е.:

Array
(
    [0] => Array
        (
            [id] => 1
            [login] => user1
            [email] => user1@mail.com
            [phone] => 786214569853
        )

    [1] => Array
        (
            [id] => 2
            [login] => user2
            [email] => user2@mail.com
            [phone] => 786214569853
        )

    [2] => Array
        (
            [id] => 3
            [login] => user3
            [email] => user3@mail.com
            [phone] => 786214569853
        )

)

Чтение данных MP3 файла (ID3 тегов)

Также с помощью pack() и unpack() можно получать информацию с различных других бинарных файлов, например MP3 ID3 теги:

<?php

$bin = file_get_contents('test.mp3');
$metadata = substr($bin, -128);
$info = unpack('a3tag/a30title/a30artist/a30album/a4year', $metadata);
print_r($info);

Результатом работы этого скрипта будет массив следующего вида:

Array
(
    [tag] => Track tags
    [title] => Track title
    [artist] => Track artist name
    [album] => Track album name
    [year] => Track year
)

Естественно при реальной работе скрипта вместо Track * будут данные того MP3 файла, который был считан.

Кроме MP3 файлов можно получать информацию и с других файлов бинарных типов, главное знать формат, в котором записаны те или иные бинарные данные.