Output a PDF in PHP from a byte array - php

I am getting a byte array from a WCF service that generated the PDF and converted it to a byte array. I need to able to get the byte array and using either PHP or Javascript (or jQuery) take that byte array and convert it back to a downloadable PDF. I would prefer a solution in Javascript, but PHP would work fine too.
The code I'm using to get the PDF is:
<?php
$userPDF = $_POST['username'];
$passPDF = $_POST['password'];
$idPDF = 'MO-N007175A';
//PDF Function
$data = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);
$data_string = json_encode($data);
$ch = curl_init('http://********.com/******/v1/DealPdf');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_VERBOSE, 1 );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
var_dump($result);
?>
The var_dump($result); is
string(1053285) "[37,80,68,70,45,49,46,54,10,37,211,244,204,225, ...
The array goes on for a while... so I only provided a small portion for example purposes.
Where do I start on getting a PDF out of this array?
EDIT
To clarify - The WCF Service IS returning an actual PDF, just in a byte array. I need to save this byte array as a PDF on the clients machine. I have used fwrite and so forth, but I must be missing something because I dont see it working.
Also - If I do use fwrite, where does it output the file?
EDIT

I had to do the same thing. For me, I was generating the PDF server-side, but wanted to send it down with a bunch of other data to the client in an AJAX response. Here's the JavaScript that I ended up with. The Blob and saveAs methods are rather new technologies, so you might want to (as I did) get the polyfills for each of them, linked to above.
// Convert the Base64 string back to text.
var byteString = atob(data.reportBase64Bytes);
// Convert that text into a byte array.
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
// Blob for saving.
var blob = new Blob([ia], { type: "application/pdf" });
// Tell the browser to save as report.pdf.
saveAs(blob, "report.pdf");
// Alternatively, you could redirect to the blob to open it in the browser.
//document.location.href = window.URL.createObjectURL(blob);

At first, I thought this would be a great use of the JavaScript library PDF.js, but then I realized that you wanted to download the file. The best place to do this would be in PHP setting all of the appropriate headers along the way.
However, there may be something that will work for you, but I have never tried it with PDFs. I have seen image saves done well with data url's in some browsers. A great example of this is Canvas2Image. The code would look something liket he following:
document.location.href = "data:application/pdf;base64," + base64PDFdata;
Where base64PDFdata would be your byte array converted to base 64 string representation. No guarantees on this working, but it may be worth a shot.

As mention in my comment to your question, it looks like you're getting a string representation of an array of decimal representations of bytes. e.g. "[37,80,68,70]"
You likely need to transform that.
Can be done like this:
// with:
$data = "[50,20,36,34,65]";
// remove brackets
$data = trim($data,'[]');
// split into array on ',' character
$data = explode(',',$data);
// transform each decimal value to a byte representation. chr does just that
$data = array_map('chr',$data);
// turn the resulting array back into a string
$data = implode('',$data);
The comments about setting the headers to force download are also relevant so you should use that too.
Here's the final code:
<?php
// This is good to keep
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="output.pdf"');
$userPDF = $_POST['username'];
$passPDF = $_POST['password'];
$idPDF = 'MO-N007175A';
//PDF Function
$result = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);
$result_string = json_encode($result);
$ch = curl_init('http://********.com/******/v1/DealPdf');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $result_string);
curl_setopt($ch, CURLOPT_VERBOSE, 1 );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
// remove brackets
$result = trim($result,'[]');
// split into array on ',' character
$result = explode(',',$result);
// transform each decimal value to a byte representation. chr does just that
$result = array_map('chr',$result);
// turn the resulting array back into a string
$result = implode('',$result);
echo $result;
?>
Note that echo is used here, var_dump is not good as it adds extra formatting to the output.
Also, note, you're not doing any testing on the result of the curl, if it fails you should probably handle the output differently.

Set MIME header with header() to match a PDF and then print out byte array.
Something like this:
In PHP, output as byte array and stream. Which one is better?

Ahh now I see what you want to do!
Try this:
<?php
header('Content-Type: application/pdf');
header('Content-Disposition: attachment; filename="downloaded.pdf"');
$userPDF = $_POST['username'];
$passPDF = $_POST['password'];
$idPDF = 'MO-N007175A';
//PDF Function
$data = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);
$data_string = json_encode($data);
$ch = curl_init('http://localhost/test/file.pdf');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_VERBOSE, 1 );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));
$result = curl_exec($ch);
var_dump($result);
?>

Related

Curl/PHP challenge transferring image and base64_encode/decode

I am transfering data from one linux-box to another. In generel this works fine, BUT I am having trouble when it comes to transferring images. I have tested all kinds of stuff. I hope some one may be able to help me out.
$filename = "/home/user/image.jpg";
$handle = fopen($filename, "r");
$data = fread($handle, filesize($filename));
$data = base64_encode($data);
# Transfer reading
#$arrIn['changeCharset'] = "true";
$arrIn['postFields'] = "action=test&data=$base64";
$test = curlServerPost($arrIn);
Here is my CURL-function:
function curlServerPost($arrIn)
{
$postFields = $arrIn['postFields'];
$url = "$GLOBALS[remoteSite]"; // Where you want to post data
$ch = curl_init(); // Initiate cURL
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true); // Tell cURL you want to post something
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields); // Define what you want to post
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Return the output in string format
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // Accepter alle certifikater, se: http://unitstep.net/blog/2009/05/05/using-curl-in-php-to-access-https-ssltls-protected-sites/
$res = curl_exec($ch); // Execute
curl_close($ch); // Close cURL handle
return($res);
}
Finally, here is the receiver (server) part
$data = $_POST[data];
$data = base64_decode($data);
$stmt = $GLOBALS[pdo]->prepare("INSERT INTO cameraImages (cameraImagesId) VALUES ('')");
$stmt->execute();
$cameraImagesId = $GLOBALS[pdo]->lastInsertId();
$stmt = $GLOBALS[pdo]->prepare("UPDATE cameraImages SET cameraImagesFile='$data' WHERE cameraImagesId='$cameraImagesId'");
$stmt->execute();
Some last remarks:
- If I don't base_decode on server-side I receive (but completely wrong format. Errors in image)
If I base_decode om server-side. Nothing is received.
I would like to don't encode/decode at all. If I do that. Only a small part of the image is stored (corrupted image)
My datafield is LONGBLOB (mysql)
PHP on server side is: PHP 5.3.3
PHP on client side is: PHP 7.0.27-0+deb9u1
I have tried all kinds of stuff. Followed all kinds of tutorials. It just won't work for me :-/
So if anyone can come up with ideas I am more than willing to test and try :)
Loooking forward to hear from you.
Succes. I just needed
urlencode($data);
And removed base64_encode($data); / base64_decode($data);
I have dropped putting images in database since many ppl don't recommend it.

'file_get_contents' The contents are encrypted?

The problem is when i use file_get_contents to get source (HTML) from this site, the result that i receive is NOT a plain html code.
The code i used:
$source = file_get_contents("http://mp3.zing.vn/bai-hat/Dance-With-My-Father-Luther-Vandross/ZWZ9D6FD.html");
echo $source;
// OR print_r($source);
The source i received:
��}{�#Ǒ��-��!E��=��Mv�5�B���R�����h��E�HV7YE�������a�X��p{��[�:�!{��;,v��u��Or��̬��Y��M��ʌ̌�����������F��ޖ����ػ��S� #�~��H�7k�����ʎȦ2���M?�ު&D�����t���$u�O��N���>%(Y����I��Vb�[���VN�=�[�![*�dE*�]3:�ޑ�xiA���Z��g ��祇VejI �R�y�֨�ea��o��s�M/�... *MORE
I tried with cURL, but i also received the same result:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://mp3.zing.vn/bai-hat/Dance-With-My-Father-Luther-Vandross/ZWZ9D6FD.html");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$source = curl_exec($ch);
curl_close($ch);
I think the source i received must have been encrypted, but if i use browser to view source, the source will NOT be encrypted.
Eventually, i dont really know what happened, and how to get the plain source (plain HTML) ?
It's gzip compressed, just set the correct encoding and you're good to go
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://mp3.zing.vn/bai-hat/Dance-With-My-Father-Luther-Vandross/ZWZ9D6FD.html");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch,CURLOPT_ENCODING , "gzip");
$source = curl_exec($ch);
curl_close($ch);
Take a look at gzdecode (requires the ZLIB PHP module, though - if you don't have it, I'd strongly consider to use JimL's method using cURL).
string gzdecode ( string $data [, int $length ] )
$source = file_get_contents("http://mp3.zing.vn/bai-hat/Dance-With-My-Father-Luther-andross/ZWZ9D6FD.html");
echo gzdecode($source);
// OR print_r($source);

Save byte array to a file PHP

I have not been able to find a solution using PHP. Basically, when a user clicks on the "download PDF" link, It will call a PHP function that takes a byte array and parses it as a PDF. I dont know how to go about it. Any help would be great!
EDIT:
I'm getting the "byte array" like this:
<?php
$userPDF = $_POST['username'];
$passPDF = $_POST['password'];
$idPDF = 'MO-N007175A';
//PDF Function
$data = array("id" => $idPDF, "username" => $userPDF, "password" => $passPDF);
$data_string = json_encode($data);
$ch = curl_init('http://*****.com/****/v1/DealPdf');
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_VERBOSE, 1 );
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json')
);
$result = curl_exec($ch);
var_dump($result);
?>
The "$result" is supposedly the byte array that looks like this:
string(1053240) "[37,80,68,70,45,49,46,54,10,37,211,244,204,225,10,49,32,48,32,111,98
..etc.
Basically I need to take what im getting back and save it as a PDF (or any generic file for the matter).
You can try something like this:
// suppose that the response is a JSON array (look like it)
$bytes = json_decode($results);
$fp = fopen('myfile.pdf', 'wb+');
while(!empty($bytes)) {
$byte1 = array_shift($bytes);
$byte2 = array_shift($bytes);
if(!$byte2) {
$byte2 = 0;
}
fwrite($fp, pack("n*", ($byte1 << 8) + $byte2); // big endian byte order ?
}
fclose($fp);
GiDo's answer will work, but will take very long for large files. I would recommend doing the following:
$bytes = json_decode($results);
$bytesStr = pack('C*', ...$bytes);
file_put_contents('myfile.pdf', $bytesStr);

PHP Printing with Google Cloud Print

I am currently adding the ability to a php back-end system to allow it to print directly and I am trying to get things working with Google's Cloud Print. Imagine the app as an online shopping cart and I want it to print picking notes (completed orders) without the need for someone to login. The server is remote and the destination has Cloud Ready Printers.
So far I have been successful in getting it to print using the interfaces, as long as I am simply passing HTML, plain text or a URL to a PDF. I am able to set the print to color, marginless and the print quality.
However where I have hit a problem is, the PDF which the system creates are not publicly accessible, hence I can't pass a URL to the file, I need to pass the contents of the file.
I have been trying with no success to modify one of the examples I have found on the web HERE. However I don't know the language so am struggling with it.
Another example in python HERE again I have been trying without success!
I'm using PHP and the Zend framework to work with the interface. Here is one sample I have tried, cut down to where I am trying to prepare the file to send, like I say I'm not really sure on translating from python to php, or if the python script even works, but this is what I came up with:
<?php
// Test print a job:
$b64_pathname = PDF_PATH.'ec22c3.pdf'.'.b64';
$fileType = "application/pdf";
// Open the original file and base64 encode it:
$dataHandle = fopen(PDF_PATH.'ec22c3.pdf', "rb");
$dataContent = fread($dataHandle, filesize(PDF_PATH.'ec22ed167763a15e8591a3776f3c65c3.pdf'));
fclose($dataHandle);
$b64data = $fileType.base64_encode($dataContent);
// Store the base64 encoded file:
$ourFileHandle = fopen($b64_pathname, 'w');
fwrite($ourFileHandle, $b64data);
fclose($ourFileHandle);
// Read the contents of the base64 encoded file and delete it:
$fileHandle = fopen($b64_pathname, "rb");
$fileContent = fread($fileHandle, filesize($b64_pathname));
fclose($fileHandle);
unlink($b64_pathname);
// URL encode the file contents:
$file = urlencode($fileContent);
// Add the file and send to the printer:
$client->setParameterPost('content', $file);
$client->setParameterPost('contentType', $fileType);
$client->request(Zend_Http_Client::POST);
?>
Here's a method in php using cUrl (note, I have object level variables called _auth, _username, _password & _printerId).
First, build a function to post with cUrl:
function processRequest($url, $postFields, $referer) {
$ret = "";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_USERAGENT, "");
if(!is_null($postFields)) {
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS,
$postFields);
// http_build_query() will properly escape the fields and
// build a query string.
}
if(strlen($this->_auth) > 0) {
$headers = array(
"Authorization: GoogleLogin auth=". $this->_auth,
//"GData-Version: 3.0",
"X-CloudPrint-Proxy", "yourappname"
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
}
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_REFERER, $referer);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
$ret = curl_exec ($ch);
curl_close ($ch);
return $ret;
}
Then, a function to authorize against Google:
public function authorize() {
$url = "https://www.google.com/accounts/ClientLogin";
$post = array("accountType" => "HOSTED_OR_GOOGLE",
"Email" => $this->_username,
"Passwd" => $this->_password,
"service" => "cloudprint",
"source" => "yourappname");
$resp = $this->processRequest($url, $post, "");
preg_match("/Auth=([a-z0-9_\-]+)/i", $resp, $matches);
$this->_auth = $matches[1];
}
Finally, build a function to submit to the cloud printer:
function printDocument($title, $docBytes)
{
$url = "http://www.google.com/cloudprint/submit?printerid=". $this->_printerId."&output=json";
$post = array(
"printerid" => $this->_printerId,
"capabilities" => "",
"contentType" => "dataUrl",
"title" => $title,
"content" => 'data:application/pdf;base64,'. base64_encode($docBytes)
);
$ret = $this->processRequest($url, $post, "");
echo $ret;
}
In use, call authorize() to get the authentication token. Then just read your file (from wherever) into a variable and pass it to printDocument with the title.
In order to send base64 encoded content you need to send another parameter in submit request:
$client->setParameterPost('contentTransferEncoding', 'base64');

POST Base64 encoded data in PHP

I need to POST some data to a PHP page using cURL, and the request contains three parameters:
Two of them are regular text values
One is a Base64 encoded file
I've noticed that the Base64 value is corrupted during the transmission.
This is the code that's sending the request:
$filename = "img2.jpg"; //A sample image file
$handle = fopen($filename, "r");
$data = fread($handle, filesize($filename));
$base64 = base64_encode($data);
$postData = "id=1234&sometext=asdasd&data=" . $base64;
$ch = curl_init("http://mydomain/post.php");
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$httpResponse = curl_exec($ch);
curl_close($ch);
Any tips?
Maybe you should use urlencode() because the + and = in a base64 string?
Make sure that the size of the post data does not exceed your 'max_post_size' in your php.ini file.
A fair guess is that the encoding adds + - signs, which mess up your data.
After encode, try to add replace + to -
(And backwards on recieve of course.)
Ref:
http://en.wikipedia.org/wiki/Base64#URL_applications

Categories