MWS Fulfilment Inbound API - Decode Base64 PDF data from GetPackageLabels - php

I'm trying to decode the PDF data returned by the MWS Fulfilment Inbound API - GetPackageLabels request. The documentation is here: http://docs.developer.amazonservices.com/en_UK/fba_inbound/FBAInbound_GetPackageLabels.html
I have successfully made the call and got a response, but a using straight base64_decode in php the resulting pdf is corrupted. As I also can't get the check sum to match it would suggest that I'm missing a step in the decoding process. I've tried downloading from multiple test shipments, so it isn't a case of a single request getting corrupted in transit. I've outlined the steps I'm using below, any help would be appreciated.
XML response:
<GetPackageLabelsResponse xmlns="http://mws.amazonaws.com/FulfillmentInboundShipment/2010-10-01/">
<GetPackageLabelsResult>
<TransportDocument>
<PdfDocument>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</PdfDocument>
<Checksum>n0Cdtwupz9V68HnMp0Go7Q==</Checksum>
</TransportDocument>
</GetPackageLabelsResult>
<ResponseMetadata>
<RequestId>87a9d81a-6ec4-4d45-b2fc-8d0e6dfbe0a8</RequestId>
</ResponseMetadata>
</GetPackageLabelsResponse>
In PHP I've successfully extracted the PdfDocument string into $data, which matches the above. I then output the data using the following:
$pdf_document = base64_decode($data);
header("Content-type: application/pdf");
header("Content-Length: " . strlen($pdf_document));
header("Content-Disposition: inline; filename=PackageLabels.pdf");
echo $pdf_document;
exit();
I have checked that the script isn't outputting any data before the pdf data is echoed out. I've also used file_put_contents($filename, $pdf_document) to save the data to a file and that file is also corrupted.
I also can't get the md5 checksum to match:
echo base64_encode(md5($pdf_document, true)); // outputs: Pn0C06ZOgzDBfYwWXBvvow==
// from response: n0Cdtwupz9V68HnMp0Go7Q==

The contents of that PdfDocument is a ZIP file - the first three letters ("UEs") decode to "PK" which is the magic identifier for ZIP files. For testing purposes, you can use this website to download a copy of that ZIP. PHP has functions that let you do the same, you'll have to check what's compiled into your PHP version.
The contents of said ZIP archive is a single file labeled PackageLabels.pdf which is the PDF you're looking for.
The Checksum is also base64-encoded and the one in your example decodes to 9f409db70ba9cfd57af079cca741a8ed. This is supposed to be the MD5 hash of the document data. However, I have yet to find out how exactly it is calculated. It did NOT match the MD5 of any of the following:
The raw Base64 encoded string
The zip file
The contained pdf file

Related

How could I get PHP to decrypt some files in memory and then make the client download those files?

I'm currently learning PHP and programming in general. I'm currently writing my first website where I have a simple login system and users can enter some data in plain text. Upon entry, PHP encrypts this data.
I want to add a feature where users can then download an unencrypted copy of the data and I want to do it in such a way that the files on disk remain encrypted the entire time and an unencrypted copy is not stored anywhere.
At the moment I should be able to decrypt the data line by line and store it in an array, but I don't know what I could do once I get to that point. Is there a way for PHP to treat an array as if it was just a text file and then ask the client to download it? Or maybe I could just somehow stream the array to a file on the client, line by line?
I have no code to show at the moment as I'm still trying to work out in my head how it will all be structured.
The solution must also be portable between a windows and Linux server.
Assuming the encrypted file is plain text. Second, writing in pseudo-code, because I do not know your solution
First, you need to decrypt the data in something that can be echoed to the user. Or more generally, something that is represented as a String.
I am doing something simillar with PDF files, so I am showing the similar on TXT file:
$encryptedData = $this->getEncryptedData(); // load what needs to be decrypted. Pseudocode
$filename = 'download.txt'; // file name to download. Will be download.txt
$contents = $this->decrypt($encryptedData) // $contents should be String. Decryption is pseudocode
header("Content-Type: text/plain"); //set header as TXT file
header("Content-Disposition:attachment;filename={$filename}"); //force download prompt from the browser
echo $contents; //print decrypted data to TXT
exit; //stop script after download

Unable to download binary file in PHP

I have to encrypt a file and save it in mysql as a blob, then decrypt it and make it available for download.
I save the file in a blob like so:
$certificate_tmp=$_FILES['certificate']['tmp_name'];
$certificate=openssl_encrypt(file_get_contents($certificate_tmp),$ciphers,$password_tmp);
$wpdb->insert("my_table",array("certificate"=>$certificate));
Note: I've cut unrelated code, the table is not just certificate, but I don't want this to get confusing.
This is the download php page:
$password_tmp=$_SESSION['pwd']; //decrypt password
global $wpdb; //wordpress db conncetion
$results_file = $wpdb->get_row("select * from my_table where id='$id'",ARRAY_A); //i get the id from wp's curr_user
$m_file = openssl_decrypt($results_file['certificate'],"AES-128-CBC",$password_tmp);
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=\certificate".$id."\"");
header('Content-Transfer-Encoding: binary');
print_r($m_file);
And everything works perfectly with text files, but the result is empty with binary files, although in the blob the binary file is there.
EDIT
My guess is, as soon as I decrypt the file from the db blob, php or html (because of print_r) understands that it is a binary file and doesn't let you show it because of security reasons. You can't execute programs on the web like .exe or .bin, although the files I upload, either binary or text have no extension.
From what I understand php treats binary files as strings, but file_get_contents is binary safe.
I think not using blobs would be the best approach for this, but I cannot do that, I have to use blobs.
EDIT 2
The problem seems to be openssl which doesn't seem to like binary data, I've tried the same code using mcrypt and it works perfectly.
Make sure you are decrypting the data using the same key.
Why do you use print instead of print_r?
Try to add the content length:
header('Content-Length: '.strlen(YourFileData));
For more information please visit:
http://www.media-division.com/the-right-way-to-handle-file-downloads-in-php/

Get contents from gzipped file

I am trying to get the contents from a gzipped file that is returned to me after using Mailchimp API doing a batch operation request. I expect to get only a JSON string as response, but also receive a bunch of numbers and random (?) strings.
This is what I do.
$gz = gzopen($response->response_body_url, "r");
$contents = trim(gzread($gz, 10000));
print_r($contents); //see output below
gzclose($gz);
This is what is returned to me.
0000777000000000000000000000000012705141572007721 5ustar
rootroot./05fa27ceab.json0000666000000000000000000000121212705141572012327
0ustar
rootroot[{"status_code":400,"operation_id":null,"response":"{\"type\":\"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/\",\"title\":\"Member
Exists\",\"status\":400,\"detail\":\"xxxx.xxxx#xxxx.xx is
already a list member. Use PUT to insert or update list
members.\",\"instance\":\"\"}"},{"status_code":400,"operation_id":null,"response":"{\"type\":\"http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/\",\"title\":\"Member
Exists\",\"status\":400,\"detail\":\"xxxx2.xxxx2#xxxx2.xx is
already a list member. Use PUT to insert or update list
members.\",\"instance\":\"\"}"}]
What am I missing here? Why won't it work?
It looks like you may be dealing with a .tar.gz file instead of just gzip. The easiest way to do that is either with the PharData extension or by just saving it to disk and using a shell tool to unzip.
Here's an answer to a question on how to deal with .tar.gz files in php

Create Base64 from uploaded file without saving locally php

I need to send a file in base 64 format through a SOAP service. I cannot save the file locally. Is there a way to convert an uploaded file and send it through in one instance, without saving it?
I initially thought it was as easy as:
$base64file = base64_encode($_FILES["cv"]["tmp_name"]);
But that doesn't seem to be working great.
The problem with your code is that you are encoding the filename, not the file content.
Use this to open the file and convert it to base64:
$base64file = base64_encode(file_get_contents($_FILES["cv"]["tmp_name"]));
Then you can send it back to the client. Just double check that the Soap server does not double base64 encode the string.

Create file from JFIF data

I have a dump of our LDAP database, and i'm attempting to extract all images from it using PHP. The images seem to be stored in JFIF format (at least, according to https://www.rfc-editor.org/rfc/rfc2798#page-5). However, i can't figure out how to create a JPEG file from this; I attempted file_put_contents to dump everything in name.jpeg, imagecreatefromstring's output to imagejpeg and some variations on those. However, either I'm not using them correctly, or I'm just attempting this wrong alltogether.
So the question:
Here's a small part of the field:
jpegPhoto:: /9j/4AAQSkZJRgABAQAAAQABAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2Mi4wICh1c2lu
ZyBJSkcgSlBFRyB2NjIpLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCww
ZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMi
EcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAh
QBkAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMF
BQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU
2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpq
eoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBA
QEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEH
YXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFl
aY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8
jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8Kihad+OB3JrQhtI7aHzG
bdKTwMdBVKSGWFVc7lDZAPTOOv6H9aTzJlKMGO4gEH26VEk31Jaua8MkSpIHk3dSkWw854J/wDrUtzb
uCTuYkZDZH5VW06AMwIZss/DZweo5H51ptKzM6SYJGAGIwSMfr0rnk+WWhk9GYzR+Y4AJUgd/wDP0qN
2JVDjnOM5zjGP6VoXVsUl+Rcbjk4qg8Xlz5429Qf6VtGSaNYu6G4U5U9fX3qOJC7bTzn0qY5HDYwe9M
CxhnBYnP3QO9WO5s6aJmiZWUtDyN+/P4dfxrNu0PmH50ZckEgd+P8AGpYbkwxBInOxnVmU9Diku49jj
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
The data is base64 encoded, decode it first and then save it to a file. See http://www.php.net/manual/en/function.base64-decode.php

Categories