I have a PHP array, which contains bytes, and the actual bytes represent a ZIP file (which contains multiple files inside the ZIP).
This is returned from a third party API, so I have no choice but to work with this format.
So I'm trying to convert this into the ZIP file.
Example of byte array returned by API:
[bytes] => Array
(
[0] => 37
[1] => 80
[2] => 68
[3] => 70
[4] => 45
[5] => 49
[6] => -46
... continues to close to 20,000
)
I have tried simply getting the browser to return it by creating a complete byte string, and adapting browser headers... using:
foreach($bytes as $byte)
{
$byteString .= $byte;
}
header("Content-type: application/zip");
header("Content-Disposition: inline; filename='test.zip'");
echo $byteString;
This does create a zip file, but it's invalid / corrupted.
I have also tried this which I found elsewhere on Stackoverflow:
$fp = fopen('/myfile.zip', 'wb+');
while(!empty($bytes)) {
$byte1 = array_shift($bytes);
$byte2 = array_shift($bytes);
if(!$byte2) {
$byte2 = 0;
}
fwrite($fp, pack("n*", ($byte1 << 8) + $byte2));
}
close($fp);
But again, the ZIP is created, but it's invalid / corrupted.
Any pointers, most appreciated.
Thanks
With the help of an ascii table it's easy to decode the data you're receiving, and you will see that it starts with
%PDF
which means that the returned data is in PDF format, not zip. Zip files start with PK, the initials of the inventor of the format, the late Phil Katz.
As a general note, knowing about the common file type signatures is quite useful and can save you lots of time.
Related
I tried to set up app attestation between my app and php but I rarely find any other source of explaination than Apple's own documentation, which let me stuck quite at an early state. So far I got the following steps:
On the client side, following https://developer.apple.com/documentation/devicecheck/establishing_your_app_s_integrity, I creted my attestation as a base64 encoded string:
attestation.base64EncodedString()
I then send that string to the server, following https://developer.apple.com/documentation/devicecheck/validating_apps_that_connect_to_your_server from now on.
The documentation says, that the attestation is in the CBOR format. I therefor first decode the base64 encoded string and parse it using (https://github.com/Spomky-Labs/cbor-php).
<?php
use CBOR\Decoder;
use CBOR\OtherObject;
use CBOR\Tag;
use CBOR\StringStream;
$otherObjectManager = new OtherObject\OtherObjectManager();
$tagManager = new Tag\TagObjectManager();
$decoder = new Decoder($tagManager, $otherObjectManager);
$data = base64_decode(/* .. base64 encoded attestation string as send from the client (see swift snippet above) */);
$stream = new StringStream($data);
$object = $decoder->decode($stream);
$norm = $object->getNormalizedData();
$fmt = $norm['fmt'];
$x5c = $norm['attStmt']['x5c'];
From the documentation, the normalized object should have the following format:
{
fmt: 'apple-appattest',
attStmt: {
x5c: [
<Buffer 30 82 02 cc ... >,
<Buffer 30 82 02 36 ... >
],
receipt: <Buffer 30 80 06 09 ... >
},
authData: <Buffer 21 c9 9e 00 ... >
}
which it does:
$fmt == "apple-appattest" // true
Then the next according to the documentation is described as:
Verify that the x5c array contains the intermediate and leaf certificates for App Attest, starting from the credential certificate in the first data buffer in the array (credcert). Verify the validity of the certificates using Apple’s App Attest root certificate.
However, I don't know how to proceed further on this. The content of e.g. $norm['attStmt']['x5c'][0] is a mix of readable chars and glyphs. To give you an idea, this is a random substring from the content of $norm['attStmt']['x5c'][0]: "Certification Authority10U Apple Inc.10 UUS0Y0*�H�=*�H�=B��c�}�". That's why I'm not really sure wheather I have to perform any further encodeing/decoding steps.
I tried parsing the certificate but without any luck (both var_dump return false):
$cert = openssl_x509_read($x5c[0]);
var_dump($cert); // false - indicating that reading the cert failed
$parsedCert = openssl_x509_parse($cert, false);
var_dump($parsedCert); // false - of course, since the prior step did not succeed
Any ideas, guidance or alternative ressources are highly appreciated. Thank you!
After a while I came up with the following solution. The $x5c field contains a list of certificates, all in binary form. I wrote the folowing converter to create a ready-to-use certificate in PEM format, which does the following:
base64 encode the binary data
break lines after 64 bytes
add BEGIN and END markers (also note the trailing line-break on the end certificate line)
function makeCert($bindata) {
$beginpem = "-----BEGIN CERTIFICATE-----\n";
$endpem = "-----END CERTIFICATE-----\n";
$pem = $beginpem;
$cbenc = base64_encode($bindata);
for($i = 0; $i < strlen($cbenc); $i++) {
$pem .= $cbenc[$i];
if (($i + 1) % 64 == 0)
$pem .= "\n";
}
$pem .= "\n".$endpem;
return $pem;
}
the following then works:
openssl_x509_read(makeCert($x5c[0]))
I get through Modbus some 4-Byte Float Values.
I get this 4 bytes in an array:
Array ( [0] => 67 [1] => 105 [2] => 25 [3] => 154 )
After some Bitconversion I made this:
1000011011010010001100110011010
when putting this binary string into a online converter such as
https://www.binaryconvert.com/result_float.html?hexadecimal=4369199A
I get the value of 2.331E2 which is correct (233.1).
However I fail to convert this binary in a PHP float variable. I tried to point the address to a float variable, but did not succeed.
How can I convert this binary string or the array above into a php float?
Added:
The pointer Idea was stupid, since php does not let me define the type of variable. So I tried a different approach using unpack to a float type. But it does not work either:
// This represents a 4 byte float read from modbus
$array=array(67,105,25,154);
$array=array_reverse($array);
print_r($array);
for ($i=0;$i<count($array);$i++) {
$t+=pow(2,$i*8)*$array[$i];
}
echo '<br>Binary: '.decbin($t). ' - This would be the correct Binary for 233.1';
echo '<br>float: ';
print_r(unpack('f',$t));
This code results in:
Array ( [0] => 154 [1] => 25 [2] => 105 [3] => 67 )
Binary: 1000011011010010001100110011010 - This would be the correct Binary for 233.1
float: Array ( [1] => 6.5189725839687E-10 )
No chance to get my 233.1 :(
I know I come with a possible answer a little bit later but maybe others found useful.
The conversion is a little bit complicated, I worked few hours on it to include in my application.
Firstly I created a function to get value of the Mantissa, then calculated a float number. I didn't created function for the calculation of the exponent and sign.
This example is valid for positive float numbers, for more details read this:
HOW REAL (FLOATING POINT) AND 32-BIT DATA IS ENCODED IN MODBUS RTU MESSAGES
And the script:
$array=array(67,105,25,154);
$result = pow(2,(((($array[0] * 256 + $array[1]) & 32640) >> 7)-127)) * calcMantissa((($array[1] & 127) << 16) + ($array[2] << 8) + $array[3]+1);
echo $result . "\n";
function calcMantissa($nb) {
$retValue = 1;
for ($i = 0; $i < 22; $i++) {
$retValue = $retValue + (($nb & (1 << (22 - $i))) > 0) / (pow(2,($i+1))) ;
}
return $retValue;
}
which gave the following result:
233.10000610352
I know that the PHP ord() function converts a certain character to ASCII. But I want to build a web application that encrypts an inputted text using several methods, and I want to implement a "Text to ASCII" method.
I tried to use the ord() function for each character from the inputted string $text. That's my code:
for ($i = 0; $i<strlen($text); $i++)
$text[$i] = ord($text[$i]);
The problem is, the characters aren't converted properly.
I also tried using $i<=strlen($text);, but it just spams my page with some type of error, and I'm pretty sure $i doesn't need to reach strlen($text) exactly.
What can I do?
The code is overwriting the string it is trying to convert. Also ord() can produce multiple characters per input character, so this will produce more confusion.
Instead you could build an array for each character, several ways to do it, but sticking with the current method(ish)...
$text = "Hello";
$chrs = [];
for ($i = 0; $i<strlen($text); $i++) {
$chrs[] = ord($text[$i]);
}
print_r($chrs);
gives an output of...
Array
(
[0] => 72
[1] => 101
[2] => 108
[3] => 108
[4] => 111
)
I am using BEncoded PHP Library to decode the bencoded response from a Bittorrent tracker.
The response of Tracker is:
d5:filesd20:¼€™rÄ2ÞÊþVA .]á^¦d8:completei285e10:downloadedi22911e10:incompletei9eeee
after decoding it using the below code:
require 'bencoded.php';
$be = new BEncoded;
//Response saved in scrape.txt
$data =file_get_contents('scrape.txt');
print_r($be->Decode($data));
the output is:
Array ( [files] => Array ( [¼€™rÄ2ÞÊþVA .]á^¦] => Array ( [complete] => 285 [downloaded] => 22911 [incomplete] => 9 [isDct] => 1 ) [isDct] => 1 ) [isDct] => 1 )
My Problem
my problem in the above output is how to decode those mysterious letters in output.
The link: http://wiki.vuze.com/w/Scrape posted by user3690414 pretty much explains what the different keys stands for.
To interpret the raw bencoded string:
d5:filesd20:¼€™rÄ2ÞÊþVA .]á^¦d8:completei285e10:downloadedi22911e10:incompletei9eeee
you need to understand how bencoding works: https://wiki.theory.org/BitTorrentSpecification#Bencoding
The most essential to know here is that that every entry in a bencoded dictionary is a Key,Value-pair.
Where Key is a byte string
and Value one of the following types: byte string, integer, a list or a dictionary.
With that in mind the raw string can be broken down like this:
d // The first d indicates the start of the Root dictionary
5:files // that has a Key with a 5 byte string name 'files',
d // the value of the 'files'-key is a second dictionary
20:¼€™rÄ2ÞÊþVA .]á^¦ // that has a Key 20 byte = 160 bit big endian SHA1 info-hash
d // the value of that key is a third dictionary
8:complete // that has a Key with a 8 byte string name 'complete',
i285e // the value of that key is a Integer=285
10:downloaded // that has a Key with a 10 byte string name 'downloaded',
i22911e // the value of that key is a Integer=22911
10:incomplete // that has a Key with a 10 byte string name 'incomplete',
i9e // the value of that key is a Integer=9
e // this e indicates the end of the third dictionary
e // this e indicates the end of the second dictionary
e // this e indicates the end of the Root dictionary
Hope this helps to understand the output from 'bencoded.php'.
edit.
If you want to make the 160 bit big endian SHA1 info-hash [¼€™rÄ2ÞÊþVA .]á^¦]
more human readable, I suggest that you output it as 40 byte hex-encoded string:
0xBC801B9D9972C432DECAFE56410F092E5DE15EA6
If you are referring to the mangled key of files array then it's raw infohash - check out the spec:
https://wiki.theory.org/BitTorrentSpecification#Tracker_.27scrape.27_Convention
http://wiki.vuze.com/w/Scrape
I want to find how many bytes per second are used in a mp3 file in order to be able to find the duration of the audio file.
Im using the script below and it shows me some strange values. Im not really familiar with all this audio file things and i would appreciate some help.
function getDuration($file) {
$fp = fopen($file, 'rb');
$size_in_bytes = filesize($file);
fseek($fp, 20);
$rawheader = fread($fp, 16);
$header = unpack('vtype/vchannels/Vsamplerate/Vbytespersec/valignment/vbits', $rawheader);
print_r($header);
$sec = ceil($size_in_bytes/$header['bytespersec']);
return $sec;
}
The output on print_r is
Array ( [type] => 25936 [channels] => 27489 [samplerate] => 1970037078 [bytespersec] => 2110652517 [alignment] => 0 [bits] => 21072 )
So this bytespersec rate (2 110 652 517) is confusing me.
maybe you can use the ffmpeg extension for php?
http://ffmpeg-php.sourceforge.net/doc/api/ffmpeg_movie.php