Click here to Skip to main content
14,932,407 members
Please Sign up or sign in to vote.
1.00/5 (2 votes)
See more:
PHP
<?php

$file = "/tmp/kok.bin";

$fp = fopen ($file, 'rb')
    or die ("File $file cannot be opened.");


$data = fread ($fp, filesize($file));
    or die ("Could not read data from file $file");

# Create the format for unpacking the header data
$header_format = 
    'Cid/' .            # Grab 1 byte      
    'Cnumber/' .        # Grab 1 byte
    'CIdentifier/' .    # Grab 1 byte     
    'CTime/' .          # Grab 8 bytes 
    'L# of Records/' .  # Grab 1 byte , number of target in a packet
    'SHeader Size/' .   # Grab 4 bytes
    'SRecord Size';     # Grab 2 bytes

# Unpack the header data
$header = unpack ($header_format, $data);
$targetRecord =$header_format['L# of Records'];

    
# Create the format for unpacking the data that describes the format of the records in the file
$record_format = 
    'CField Name/' .    # Grab 1 byte
    'fField Type1/' .   # Grab 4 bytes 
    'fField Type2/' .   # Grab 4 bytes
    'fField Type3/' .   # Grab 4 bytes 
    'fField number/' .  # Grab 4 bytes           
    'fdistance/' .      # Grab 4 bytes
    'CField id /'       # Grab 1 byte 
    'iField Precision/' # Grab 4 bytes the size of the Field Data
    'SField Data';      # Grab x bytes 
for ($offset = 0; $offset < strlen ($data); $offset ++) {
    print_r (unpack ("$record_format", $data));
}
?>




1 first unpack $header_format to get 'L# of Records' for every packet.(have a total of 200 packets)
2 unpack  $record_format  'L# of Records' times
$record_format = 
     CField Name/' .    # Grab 1 byte
    'fField Type1/' .   # Grab 4 bytes 
    'fField Type2/' .   # Grab 4 bytes
    'fField Type3/' .   # Grab 4 bytes 
    'fField number/' .  # Grab 4 bytes           
    'fdistance/' .      # Grab 4 bytes
    'CField id /'       # Grab 1 byte 
    'iField Precision/' # Grab 4 bytes
    'SField Data';      # Grab x bytes 

3 Step 1 and 2 are for one packet from the file.
4 Repeat 1-3 until end of file is reached.  


What I have tried:

for ($offset = 0; $offset < strlen ($data); $offset += 32) {
    $unpackeddata= unpack ("@$offset/$header_format", $data);
    print "";
    print_r ($unpackeddata);
    print "";
}
Posted
Updated 31-Aug-18 23:24pm
v9
Comments
Patrice T 30-Aug-18 10:31am
   
We have no idea what you talk about.
Give context.
We are not NSA, we can't see your screen or access your HDD
Member 13967442 30-Aug-18 13:59pm
   
I tried to explain a bit,added more code

As far as I understand you have a file with a header followed by a number of recordsets. Then you have to adjust the offset accordingly while processing your data:
PHP
$header = unpack ($header_format, $data);
// Note that your code used header_format here wrongly
$numRecords = $header['L# of Records'];
// Assuming these are what the name indicates
$offset = $header['SHeader Size'];
$recordSize = $header['SRecord Size'];
for ($i = 0; $i < $numRecords; $i++)
{
    $record = unpack ($record_format, $data, $offset);
    $offset += $recordSize;
}
This requires setting up the unpack() format strings properly so that they match the data in the file. The CTime field for example looks suspicious because I have no idea how a time value can be stored in 8 bits.

[EDIT]
If there are multiple packets beginning with a header you have to put the above into an outer loop:
PHP
$offset = 0;
$data_len = strlen($data);
while ($offset < $data_len)
{
    // Get package header
    $header = unpack ($header_format, $data, $offset);
    // Number of records in this package
    $numRecords = $header['L# of Records'];
    // Size of each record for this packet
    $recordSize = $header['SRecord Size'];
    // Adjust offset to point to first record of this packet
    $offset += $header['SHeader Size'];
    // Process records of this packet
    for ($i = 0; $i < $numRecords; $i++)
    {
        $record = unpack ($record_format, $data, $offset);
        // Adjust offset to point to next record of this packet
        $offset += $recordSize;
    }
    // $offset points to next package header if not at end of data
}
[/EDIT]
   
v2
Comments
Patrice T 31-Aug-18 7:26am
   
This is a .dbf file.
The OP happily mistaking the records set with what is in fact the fields headers.
The first header start at offset 32 and each header is size 32.
Jochen Arndt 31-Aug-18 7:41am
   
That was not quite clear for me because the provided format strings did not match the DBF structures.

But my solution still shows how to iterate adjusting the offset as necessary.

More important then:
It seems that he used the DBF data type characters in his PHP unpack format strings instead of using the corresponding PHP identifiers.
Member 13967442 31-Aug-18 10:26am
   
The file is not a .dbf file, it is a .bin file with each packet having header size 18. and 'CTime/' is wrong 'dTime', since it is timestamp
Patrice T 31-Aug-18 11:01am
   
Where does this line came from ?
"# Get the top of the dbf file header"
Member 13967442 31-Aug-18 11:15am
   
sorry that is a mistake
Jochen Arndt 31-Aug-18 11:24am
   
Your recordset has actually a size of 28 and the header of 12 with one byte for the time field. A time stamp might have 4 or 8 bytes making it a total of 15 or 19.
Member 13967442 31-Aug-18 11:39am
   
the record has a size of 30 and the header 18 in size, that is how i counted it
Jochen Arndt 31-Aug-18 12:42pm
   
C = 1 byte, S = 2 byte, L = 4 byte, I = depends, Q = 8 bytes, f = 4 bytes (single precision)
Member 13967442 31-Aug-18 12:35pm
   
$header = unpack ($header_format, $data);
$numRecords = $header['L# of Records'];

for ($i = 0; i < $numRecords; $i++)
{
$record = unpack ($record_format, $data, $i);
}

I believe the above code might unpack the first packet, how do I do it for next packet until to the end of file
Jochen Arndt 31-Aug-18 12:44pm
   
As in my solution:
The third parameter specifies the offset into the data.
So that has to been set accordingly (size of header for first record and then incremented by the size of the record).
Member 13967442 31-Aug-18 13:12pm
   
what about reading the next packet header?
Jochen Arndt 31-Aug-18 14:49pm
   
I don't get you.
If the file structure is as assumed in my solution, you have a header and recordsets. Then you access the header first at offset zero and then the recordsets at their matching offset.
Member 13967442 31-Aug-18 15:16pm
   
what I am saying is, the above solution only works for the first packet,
$numRecords = $header['L# of Records']; // the value in the $numRecords is the number of records in the first first packet. how do I loop to get $numRecords in the header file of each packet.
Jochen Arndt 1-Sep-18 5:02am
   
That can be only answered when knowing the file structure which I don't know.

My solution is for
- one header, contains info about # of following records
- 1. recordset
- 2. recordset
- ...
- # of recordsets - 1 recordset

If the file structure is different, you have to tell us the structure.
Member 13967442 1-Sep-18 5:19am
   
one header, contains info about # records that needs to be unpacked for that particular packet. and so the info in each header is different. e.g one packet can have 2 records or the next packet could be 5...according to the read in each $header['L# of Records'];
Jochen Arndt 1-Sep-18 5:25am
   
Then you have to write an outer loop around my solution. I will update it.
Quote:
I need to unpack the rest of the packet.

I think your problem is that you unpack always at beginning of file
PHP
unpack ("$record_format", $data)

instead of the position of what you want to unpack.
File header start at offset 0
First Field header start at offset 32
Second Field header start at offset 64
...


But $data is the whole file.
.dbf - Wikipedia[^]

[Update]
NO!
It is the loop start at 32 and it is not header_format:
PHP
for ($offset = 0; $offset < strlen ($data); $offset += 32) {
    $unpackeddata= unpack ("@$offset/$header_format", $data);
    print "";
    print_r ($unpackeddata);
    print "";
}


[Update]
Anything about .dbf in solution is wrong because
PHP
# Get the top of the dbf file header

in original code is wrong too.
   
v3
Comments
Patrice T 31-Aug-18 0:40am
   
Use Improve question to update your question.
So that everyone can pay attention to this information.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900