2016-08-09 6 views
1

Gibt es umfassende Informationen darüber, wie Binärdateien gelesen werden können? Ich habe Informationen auf der PHP-Website (http://www.php.net/manual/en/function.pack.php) gefunden, aber ich habe Schwierigkeiten zu verstehen, wie man mit "typedef struct" und struct arbeitet.Binärdateien in PHP lesen

Ich habe eine lange Binärdatei mit vielen Blöcken, jeder Block kann uns C-Struktur dargestellt werden. Diese C-Struktur hat verschiedene „typedef struct“ ähnlich dem, was ich mit unten gekommen sind:

typedef struct 
{ 
unsigned char Day; 
unsigned char Month; 
unsigned char Year; 
} DATE_OF_BIRTH; 
#define USER_TYPE 5 
DATE_OF_BIRTH Birth[2];\ 

EDIT:

ich eine Struktur unten haben, das ist ein Teil einer größeren Struktur

Die Binärdatei ist voll von Zeilenumbrüchen und ich konnte die erste Zeile dekodieren, die korrekt zurückgegeben wurde: Typ, Version, Modell, Nummer und eine Klasse. Ich denke, ich habe auch zwei nächste Variable entschlüsselt, aber ich bin mir nicht sicher, weil StartTime etwas Kauderwelsch zurückgibt.

Im Moment habe ich durch die Leitungen aus der Binärdatei am Looping und versuchen, jeden zu entpacken:

$i = 1; 
while (($line = fgets($handle)) !== false) { 
    // process the line read. 
    var_dump($line); 
    if($i == 1) { 
     $unpacked = unpack('iType/iVersion/LModel/LNumber/iClass/iTemplateLoaded', $line); 
    }if($i == 2) { 
     $i++; 
     continue; 
    }if($i == 3) { 
     $unpacked = unpack('C32TemplateName/CStartTime[Second]/CStartTime[Minute]/CStartTime[Hour]/CStartTime[Day]/CStartTime[Month]/CStartTime[Year]', $line); 
    } 

    print "<pre>"; 
    var_dump($unpacked); 
    print "</pre>"; 

    $i++; 

    if($i == 4) { exit; } 
} 
+1

'entpackt $ = auspacken ('15C', $ binary_string); '? – Cyclonecode

+0

php bietet nichts wie Strukturen. Sie können Bytes nicht direkt in einen PHP-Speicherort lutschen und dann beginnen, diesen Speicher als eine Struktur zu behandeln, da die Speicherinterna von PHP bei weitem nicht so simpel wie C's sind. Sie können alle gewünschten binären Daten in eine Zeichenfolge einlesen, aber Sie können dieser Bytefolge keine C-style-ähnliche Bedeutung zuweisen. –

Antwort

2

Ich bin nicht wirklich sicher, was Sie hier zu erreichen versuchen. Wenn Sie eine Binärdatei aus dem obigen C-Code erzeugt haben, dann könnten Sie ihren Inhalt wie diese lesen und Upack:

// get size of the binary file 
$filesize = filesize('filename.bin'); 
// open file for reading in binary mode 
$fp = fopen('filename.bin', 'rb'); 
// read the entire file into a binary string 
$binary = fread($fp, $filesize); 
// finally close the file 
fclose($fp); 

// unpack the data - notice that we create a format code using 'C%d' 
// that will unpack the size of the file in unsigned chars 
$unpacked = unpack(sprintf('C%d', $filesize), $binary); 

// reset array keys 
$unpacked = array_values($unpacked); 

// this variable holds the size of *one* structure in the file 
$block_size = 3; 
// figure out the number of blocks in the file 
$block_count = $file_size/$block_size; 

// you now should have an array where each element represents a 
// unsigned char from the binary file, so to display Day, Month and Year 
for ($i = 0, $j = 0; $i < $block_count; $i++, $j+=$block_size) { 
    print 'Day: ' . $unpacked[$j] . '<br />'; 
    print 'Month: ' . $unpacked[$j+1] . '<br />'; 
    print 'Year: ' . $unpacked[$j+2] . '<br /><br />'; 
} 

Natürlich können Sie auch ein Objekt erstellen, um die Daten zu halten:

class DATE_OF_BIRTH { 
    public $Day; 
    public $Month; 
    public $Year; 

    public function __construct($Day, $Month, $Year) { 
     $this->Day = $Day; 
     $this->Month = $Month; 
     $this->Year = $Year; 
    } 
} 

$Birth = []; 

for ($i = 0, $j = 0; $i < $block_count; $i++, $j+=$block_size) { 
    $Birth[] = new DATE_OF_BIRTH(
     $unpacked[$j], 
     $unpacked[$j+1], 
     $unpacked[$j+2] 
    ); 
} 

Ein anderer Ansatz wäre es an jedem dritten Element zu schneiden:

$Birth = [];  

for ($i = 0; $i < $block_count; $i++) { 
    // slice one read structure from the array 
    $slice = array_slice($unpacked, $i * $block_size, $block_size); 

    // combine the extracted array containing Day, Month and Year 
    // with the appropriate keys 
    $slice = array_combine(array('Day', 'Month', 'Year'), $slice); 

    $Birth[] = $slice; 
} 

Sie sich auch bewusst sein sollte, dass dies viel komplizierter, je nachdem, welche Daten werden könnte Ihre Struktur enthält, con Sider dieses Programm kleinen c:

#include <stdio.h> 
#include <stdlib.h> 

// pack structure members with a 1 byte aligment 
struct __attribute__((__packed__)) person_t { 
    char name[5]; 
    unsigned int age; 
}; 

struct person_t persons[2] = { 
    { 
    { 
     'l', 'i', 's', 'a', 0 
    }, 
    16 
    }, 
    { 
    { 
     'c', 'o', 'r', 'n', 0 
    }, 
    52 
    } 
}; 

int main(int argc, char** argv) { 
    FILE* fp = fopen("binary.bin", "wb"); 
    fwrite(persons, sizeof(persons), 1, fp); 
    fclose(fp); 
    return 0; 
} 

Die oben wird jede gepackten Struktur in die binary.bin Datei schreibt, wird die Größe genau 18 Byte sein. Um ein besseres Verständnis für die Ausrichtung erhalten/Verpacken Sie heraus überprüfen können diese so Beitrag: Structure padding and packing

Dann in PHP Code, den Sie jeden Block in einer Schleife lesen konnte wie so:

$filesize = filesize("binary.bin"); 
$fp = fopen("binary.bin", "rb"); 
$binary = fread($fp, $filesize); 
fclose($fp); 

// this variable holds the size of *one* structure 
$block_size = 9; 
$num_blocks = $filesize/$block_size; 

// extract each block in a loop from the binary string 
for ($i = 0, $offset = 0; $i < $num_blocks; $i++, $offset += $block_size) { 
    $unpacked_block = unpack("C5char/Iint", substr($binary, $offset)); 
    $unpacked_block = array_values($unpacked_block); 

    // walk over the 'name' part and get the ascii value 
    array_walk($unpacked_block, function(&$item, $key) { 
     if($key < 5) { 
     $item = chr($item); 
     } 
    }); 
    $name = implode('', array_slice($unpacked_block, 0, 5)); 
    $age = implode('', array_slice($unpacked_block, 5, 1)); 
    print 'name: ' . $name . '<br />'; 
    print 'age: ' . $age . '<br />'; 
} 
+0

Die Binärdatei wurde in C mit einer ähnlichen Struktur generiert wie in der Hauptfrage. Ich muss es in PHP entpacken, Idee ist, dass Benutzer es online hochladen würde. – user3402600

+0

Das obige zeigt, wie Sie es mit PHP entpacken können. Jedes dritte Element im '$ entpackten' Array wird' Day', 'Month' und' Year' für jede Struktur enthalten. – Cyclonecode

+1

Nachdem ich Ihren Code und die Struktur, die ich habe (mehr als 150 Zeilen), gesehen habe, habe ich bemerkt, dass fertige Binärdateien überall Daten haben und es mir scheint, dass es an mir liegt, wie viele Struktur A und welche haben sollen Linien sollten die Struktur B haben. Ich mag die Art, wie Sie eine Klasse haben und Daten hineinlegen. – user3402600