Php чтение файла двоичного

Работа с бинарными данными в php

PHP как язык плохо подходит для работы бинарными данными напрямую. Но иногда приложения должны взаимодействовать по таким протоколам, где размер пакетов очень важен или родным форматом данных для какого-то приложения, который никем в красивый json или xml не переводится.

Целые типы данных

Напоминаю какие типы данных есть в Си, на котором основан php

Тип Размер памяти Значений всего
char 1 байт = 8 бит 256
int 2 байт = 16 бит 2^16=65536
short 2 байта
long 4 байта = 32 бита 4294967295

Char при этом используется универсально согласно ASCII табличке как в качестве явного кодирования текста, так и вспомогательными маркерами. Про float я умолчу, ибо мне не понадобилось.

Нотация

Если с бинарными данными не работать, то можно и забыть основы языка. С целыми числами на основании 10 всё понятно, но обычно значения длинных данных в них не пишут. Это объясняет табличку выше.

  • Бинарная, например 0b1011
  • Восьмеричная, например 0123
  • Шестнадцатиричная, например 0xF560B1A9

Кроме этого, если вы переписываетесь с коллегами которые пишут на си, то они могут обозначать приставками или окончаниями

  • Unsigned int 14u
  • Long double или long int. Например 1.2l или 1L — фиг поймёшь, это единица или long
  • Float (с плавающей запятой) 1.3f или 1.3F

Итого, у нас char a будет хранить значение от -128 до 127.. ну или 256 если это extended ASCII. Отлично. Теперь как это использовать в php?

Читайте также:  Wordpress widget functions php

Порядок битов

Честно, для меня было откровением что порядок в данных имеет значение. Я привык что 123 уже подразумевает где сотни, десятки и единицы, но для компьютера ведь всё равно. Конечно одно дело порядок написания для человека.. но тут другое — порядок записи байтов в зависимости от адреса. И больше всего удивительно что архитектуры на уровне работы с памятью разделились — x86 на стороне little endian, а за big endian SPARC и прочие. Поэтому если вы интегрируете разные архитектуры с бинарным форматом данных — договоритесь которая система будет работать.

Операции

1. Бинарное чтение файла — fopen(«binaryfile»,»b»);

2. Битовые маски — популярный метод хранить много булевых значений в одной переменной и включать/проверять с помощью AND/OR операций. Если вы когда либо выполняли chmod 755, то уже включали эти флажки на привилий.

3. Побитовые сдвиги — помогают работать с битовыми масками и с битами в вообще

$b = $a >> 2 ; — сдвиг битов на две позиции вправо, тут может пригодится константа PHP_INT_SIZE
$b = 8 >> 3 ; // 1

4. Cyclic redundancy check

Проверка данных с помощью контрольных сумм увы для меня осталась за пределами понимания. Важно знать что биты суммируются, и что полиномы бывают разные. Соответсвенно алгоритмы тоже бывают разные и как правило неограничивается функцией crc32(). Гляньте на мою коллекцию и онлайн валидатор .

Вот пример самого короткого кода для CRC16 CCITT

function crc16_ССITT($data) < $crc = 0xFFFF; for($i = 0; $i < strlen($data); $i++) < $x = (($crc >> 8) ^ ord($data[$i])) & 0xFF; $x ^= $x >> 4; $crc = (($crc 8) ^ ($x 12) ^ ($x 5) ^ $x) & 0xFFFF; > return $crc; >

5. Упаковка

Если вы обычную переменную в php начнёте сохранять в файл, то она наверняка не будет оптимальной. А если таких однородных данных много — то тем более имеет смысл создать более компактную версию.

Например, если вы хотите число 250 записать в один байт как char-тип, вместо того что-бы писать «строкой» в три символа, как то будет делать php по умолчанию, пишем:

Первый аргумент это формат данных по длине. Если все данные char-типа, то можно написать c* как в регулярных выражениях, получить повторение типа. Можно написать c4, что будет аналогично cccc (четыре повторения данных char-типа)

  • a — строка, свободные места в поле заполняются символом с кодом 0
  • A — строка, свободные места заполняются пробелами
  • h — шестнадцатеричная строка, младшие разряды в начале (little endian)
  • H — шестнадцатеричная строка, старшие разряды в начале (big endian)
  • c — 1 байт (signed char)
  • C — 1 байт (unsigned char)
  • x — символ с нулевым кодом
  • X — возврат назад на 1 байт
  • @ — заполнение нулевым кодом до заданной абсолютной позиции
  • s — short (16 bit)
  • S — unsigned short
  • n — short (big endian)
  • v — unsigned short (little endian)
  • i — integer (размер и порядок байтов определяется архитектурой)
  • I — unsigned integer
  • l — знаковое длинное целое (32 бита, порядок знаков определяется архитектурой)
  • L — беззнаковое длинное целое
  • N — беззнаковое длинное целое (32 бита, старшие разряды в конце)
  • V — беззнаковое целое (32 бита, младшие разряды в конце)

Сам не проверял, но говорят что unsigned int получить не так то просто

6. Распаковка

Для раскодирования используется unpack() с аналогичным форматом типов данных, только теперь можно добавлять названия ключей для результатов ассоциативного массива
unpack ( «cmessageid/Vtimestamp» , pack ( «H*» ,FFFF));

Заметьте что pack я тут использую вместо hex2bin, которая недоступна для версий php менее 5.4

7. Конвертирование

base_convert — конвертирование строковых представлений чисел из любого основания в другое (скажем 16 в 2)
bindec, decbin — конвертирование 5 двоичных и десятичных данных
octdec, decoct — конвертирование 10 десятичных и восьмеричных данных
hexdec, dechex — конвертирование 16 десятичных и шестнадцатиричных данных
ord, chr — конвертирование 256 десятичных и символьных (ascii) данных

base64_encode, base64_decode — конвертирование 256 данных, но в отличие от предыдущих форматов, данные одного значения не кодируются в 6 битах что-бы получить 64 значения, а по прежнему в 8 битах — остальные символы просто не используются.. Из-за этого формат менее эффективен в хранении, но для человека в виде текста более компактен чем нули, единицы или hex.

Отличительная и неприятная особенность, конечно в том что каждая из функций конвертирует данные со строго определённым размером данных. Обычно же у нас есть какой-то пакет данных. Их можно проконвертировать в цикле с определённым шагом..

function str2bin($str, $mode=0, $visual_aid=true) < $out = false; for($a=0; $a < strlen($str); $a++) < $dec = ord(substr($str,$a,1)); $bin = ''; for($i=7; $i>=0; $i--) < if ( $dec >= pow(2, $i) ) < $bin .= "1"; $dec -= pow(2, $i); > else < $bin .= "0"; > > /* Default-mode */ if ( $mode == 0 ) $out .= $bin; /* Human-mode (easy to read) */ if ( $mode == 1 ) $out .= $bin . " "; /* Array-mode (easy to use) */ if ( $mode == 2 ) $out[$a] = $bin; if($visual_aid)< $out.=" "; > > return $out; > function str2dec($string, $visual_aid=true)< $hex=''; for ($i=0; $i < strlen($string); $i++) < $hex .= ord($string[$i]); if($visual_aid)< $hex.= "(".$string[$i].") "; > > return $hex; > function str2hex($string, $visual_aid=true)< $hex=''; for ($i=0; $i < strlen($string); $i++) < $hex .= dechex(ord($string[$i])); if($visual_aid)< $hex.= " "; > > return $hex; > function hex2str($hex)< $string=''; for ($i=0; $i < strlen($hex)-1; $i+=2) < $string .= chr(hexdec($hex[$i].$hex[$i+1])); > return $string; >

Читайте также

Простейший backdoor на php Backdoor — тайный ход, лазейка. Разумное человечество использовало всегда запасной случай что-бы не попасть впросак. К примеру те же замки,…

Сортировка матрицы на PHP Сортировку можно производить на стороне сервера в БД (самое логичное решение), но зачастую система не продумана заранее настолько и получается…

Cлучайные числа с плавающей точкой в PHP Стандартные библиотеки PHP умеют генерировать только целые случайные числа. Однако, возникают задачи где нужно не целое рандомное число с максимально…

Источник

bzread

bzread() читает из переданного bzip2 файлового указателя.

Чтение останавливается, если было считано length (несжатых) байт или был достигнут конец файла, в зависимости от того, что произойдёт раньше.

Список параметров

Указатель на файл. Должен быть корректным и указывать на файл, успешно открытый bzopen() .

Если не указан, bzread() будет считывать 1024 (несжатых) байта за один раз. За один раз может быть считано максимум 8192 байта.

Возвращаемые значения

Возвращает распакованные данные либо false в случае возникновения ошибки.

Примеры

Пример #1 Пример использования bzread()

$file = «/tmp/foo.bz2» ;
$bz = bzopen ( $file , «r» ) or die( «Невозможно открыть $file » );

$decompressed_file = » ;
while (! feof ( $bz )) $decompressed_file .= bzread ( $bz , 4096 );
>
bzclose ( $bz );

echo «Содержимое $file :
\n» ;
echo $decompressed_file ;

Смотрите также

  • bzwrite() — Бинарно-безопасная запись bzip2 файла
  • feof() — Проверяет, достигнут ли конец файла
  • bzopen() — Открывает файл, сжатый с использованием bzip2

User Contributed Notes 2 notes

Make sure you check for bzerror while looping through a bzfile. bzread will not detect a compression error and can continue forever even at the cost of 100% cpu.

$fh = bzopen(‘file.bz2′,’r’);
while(!feof($fh)) $buffer = bzread($fh);
if($buffer === FALSE) die(‘Read problem’);
if(bzerror($fh) !== 0) die(‘Compression Problem’);
>
bzclose($fh);

The earlier posted code has a small bug in it: it uses bzerror instead of bzerrno. Should be like this:

$fh = bzopen(‘file.bz2′,’r’);
while(!feof($fh)) $buffer = bzread($fh);
if($buffer === FALSE) die(‘Read problem’);
if(bzerrno($fh) !== 0) die(‘Compression Problem’);
>
bzclose($fh);

Источник

Оцените статью