Parser un fichier binaire en PHP

Décembre 2016

Supposons que vous ayez enregistré des données binaires dans un fichier, c'est-à-dire un enregistrement brut qui n'est pas traduit en texte.
C'est une chose que l'on fait couramment avec certains langages de bas niveau comme le C ou le Pascal.

Voici un exemple en C, mettons que vous vouliez enregistrer la valeur 500 dans un fichier, le code sera le suivant:
#include <stdio.h>

int main()
{
    int val = 500;
    FILE *fp = fopen("fichier", "wb");
    
    fwrite(&val, sizeof(int), 1, fp); //Enregistrement de val dans "fichier"
    fclose(fp);
    return 0;
}


Si vous ouvrez le fichier enregistré avec un éditeur de texte, vous risquez de trouver un charabia car votre valeur n'est pas enregistrée sous forme de texte mais sous forme brute, binaire.

Or, si vous utilisez un langage comme le PHP, il se peut que vous ayez besoin de récupérer des valeurs enregistrées en binaire un jour ou l'autre. Toutefois, PHP ne lit et n'écrit dans les fichiers que sous forme de texte. Il faut donc passer par une fonction spécifique pour récupérer vos valeurs correctement.

La solution


La fonction unpack() est là pour résoudre ce genre de souci.
En premier argument, vous devez signaler le type de la donnée que vous voulez récupérer et en deuxième argument, la chaîne depuis laquelle vous récupérez ces données.

Le type de la donnée à récupérer doit être détaillé sous la forme d'un caractère symbolique. Par exemple, pour récupérer un entier signé (type int en C), on utilisera le caractère "i".

Donc si on se réfère au fichier que nous venons d'enregistrer dans l'exemple au-dessus, voici le code pour récupérer notre valeur:
<?php
$fp = fopen("fichier", "rb");
$data = fread($fp, 4); //4 est la taille en octets d'un entier sur un PC 32 bits.
$nombre = unpack("i", $data);
echo $nombre[1]; //affichera 500
?>

Attention, les remarques qui suivent sont très importantes:
  • La taille des données peut changer selon les architectures de processeur. Un même programme écrit en C utilisera des entiers de tailles différentes en passant d'un PC 32 bits à 64 bits. La taille pourra également être différente d'une architecture de processeur à l'autre (Sparc, Arm, PowerPc etc...).
  • L'agencement des données pourra ne pas être le même. Certaines machines enregistrent les données en Big Endian, d'autres en Little Endian.
  • La taille des données peut aussi varier selon le compilateur.
  • La fonction unpack retourne un tableau pour permettre une utilisation un peu plus élaborée que celle donnée ici en exemple. Dans notre cas, avec une seule valeur demandée, notre valeur est située dans l'offset 1 du tableau.

Équivalences formats / types de données pour architecture PC 32 bits


Les formats utilisables sont documentés à cette adresse.
Voici un petit tableau d'équivalence pour les données enregistrées par un programme en C compilé pour un PC 32 bits.
Méfiez-vous, ces équivalences ne sont pas forcément valables selon le compilateur utilisé pour compiler le programme qui a produit le fichier, sans compter d'autres paramètres qui rentrent en jeu. Aussi, je vous recommande fortement de tester votre programme, aussi bien avec des petites valeurs que des grandes.
De même, ces équivalences sont données à titre théorique, je ne les ai pas testées.

char : c
unsigned char : C
short : s
unsigned short : S
int : l
unsigned int : L
float : f
double : d

A voir également :

Ce document intitulé «  Parser un fichier binaire en PHP  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.