Save byte array to a file PHP - 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);

Related

Sending array using curl

I want to send data from server 1 to server 2, first I select necessary data from the database, but how to send data with curl? I understand that I cannot send $result parameter just like in my code, but how should I do this?
My Code server 1:
public function setDivisions(){
$result = $this->conn->query("SELECT *FROM data_divisions");
$ch = curl_init('https://example.com/api.php?siteid='.$this->site_key.'');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $result);
curl_setopt($ch, CURLOPT_POST, 1);
$response = curl_exec($ch);
print_r($response);
}
Code on server 2:
$array = $_POST['result'];
//loop throw array and insert data into database
you can use it that way.
$ch = curl_init('https://upxxx.cod3fus1ontm.com/curl/json');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode((object)["records" => json_encode($result)]));
$response = curl_exec($ch);
var_dump($response);
on receipt, like this!
$json = file_get_contents("php://input");
$content = json_decode($json, true);
$records = json_decode($content['records'], true);
foreach($records as $record) {
echo $record['id'] . " - " . $record['text'] . "<br/>";
}
remember, that as you did to encode, you will have to do to decode
Come on, php://input returns all raw data after the request's HTTP headers, regardless of content type.
When we do this with file_get_contents (which reads the contents of a file and puts it into a variable of type string), we can read the content that was sent by curl.
Reviewing the code, you can optimize as follows, when sending to the server you placed, I suggested:
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode((object)["records" => json_encode($result)]));
you can replace it with:
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($result));
it's much simpler, but it's very important to put the query result inside a json_encode
finally, you can access the entire body of the message, through file_get_contents ("php://input") and put it inside a variable, which is nothing more than a JSON of the your query.
for you to understand how the parameters were passed, it is interesting to do the following:
$json = file_get_contents("php: // input");
var_dump($json); <- Here you see the thing as it is.
$records = json_decode($json, true); <- Here you generate an object with the content of json
var_dump($records);
With that, I think that solves the situation.
on server 1
$result = "result=".base64_encode($result)
curl_setopt($ch, CURLOPT_POSTFIELDS, $result);
...
on server 2
$array = base64_decode($_POST['result']);

Processing CSV through php function

I made a PHP function that works with an API to show me the dollar balance of an account. This function is called: get_balance
function get_balance($account){
$url = 'http://mycompaniesurl.com/' . $account; // url of website
global $response;
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
$response = curl_exec($ch);
curl_close($ch);
}
The function get_balance returns the output in the variable $response
I'm certain that the function works, so I have no questions on that part. However, I'm trying to process accountnumbers written down in a CSV file. I call the CSV file with the following code:
$file = new SplFileObject("test.csv");
$file->setFlags(SplFileObject::READ_CSV);
$data = call_user_func_array('array_merge', iterator_to_array($file));
$data = array_combine(range(1, count($data)), $data);
extract($data, EXTR_PREFIX_ALL, 'variable');
I'm testing my code with a csv file called test.csv, containing 4 addresses (first one has a balance of 0, other 3 have a balance of >0).
With the following code I get the balance with the accountnumber printed to my screen:
get_balance($data[2]);
if ($response > 0){
echo $response,"---------------",$data[2];
}
Because $data[1] has a balance of 0, nothing is printed. $data[2],$data[3] and $data[4] have a balance of more than 0, so they do return the balance together with the accountnumber.
Now what my question is; is there a way to 'automatically' do this? Something like
get_balance($data[]);
seems to not work. The CSV that this php file has to process is about ~1000 accountnumber and may have more in the future, so typing a get_balance($data[1]) up to get_balance($data[999]) will be a time consuming business.
Is there a (simple) way to apply the function to ALL the $data[] ?
Yes, there is, called array_map:
$balanced_data = array_map("get_balance", $data);
This will leave $balanced_data empty, because at the moment get_balance has no return, but uses a global variable. Change it to something like this
function get_balance($account){
$url = 'http://mycompaniesurl.com/' . $account; // url of website
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 3);
$response = curl_exec($ch);
curl_close($ch);
return $response;
}
If you don't want to or can't change get_balance, you will need a workaround like this
$max = count($data);
for ($i=0; $i<$max; $i++) {
$response = 0; // reset to make sure we get a new value
get_balance($data[$i]);
$balanced_data[$i] = $response;
}

Strange API issue when looping in PHP

I'm working with this API here: https://gatewaydtx1.giact.com/gVerifyV2/POST/Verify.asmx?op=Call using curl in php. I am able to do a test just fine on a single call to the API. However when I try to loop over several records, I get an error on every attempt after the first one.
Here's my code:
<?
//set the variables for posting
$CompanyID = "123";
$Token = "013443234-224e-4f46-bad4-6693deae2231";
$CheckNumber = "1";
$Amount = "30";
$UniqueID = "111";
$url = "https://gatewaydtx1.giact.com/gVerifyV2/POST/Verify.asmx/Call";
//Get the records from table
$sql = "SELECT id,account_no,routing_no FROM banktable WHERE(status = 'queued') LIMIT 0,100";
$result = mysql_query($sql) or die("Error: " . mysql_error() . "<br>");
while($row = mysql_fetch_array($result)) {
$RoutingNumber = $row['routing_no'];
$AccountNumber = $row['account_no'];
//Do the curl
$ch = curl_init();
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_VERBOSE, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible;)");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_URL, $url );
$post_array = array(
"CompanyID"=>$CompanyID,
"Token"=>$Token,
"RoutingNumber"=>$RoutingNumber,
"AccountNumber"=>$AccountNumber,
"CheckNumber"=>$CheckNumber,
"Amount"=>$Amount,
"UniqueID"=>$UniqueID,
);
//url-ify the data
foreach($post_array as $key=>$value){
$post_array_string .= $key.'='.$value.'&';
}
$post_array_string = rtrim($post_array_string,'&');
//set the url, number of POST vars, POST data
curl_setopt($ch,CURLOPT_POST,count($post_array ));
curl_setopt($ch,CURLOPT_POSTFIELDS,$post_array_string);
$response = curl_exec($ch);
echo $response;
curl_close($ch);
}
?>
And here's what this code outputs after looping 4 rows:
<?xml version="1.0" encoding="utf-8"?>
<string xmlns="http://www.giact.com/webservices/gVerifyV2/">33302261|true|No Data|ND00</string>
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx).
Note that the first record it tried produced a correct result. After that, the errors. And even though I mention my loop specifically here, I should note that this also happens if I simply hard code two or more curls on the page.
//url-ify the data
foreach($post_array as $key=>$value){
$post_array_string .= $key.'='.$value.'&';
}
$post_array_string = rtrim($post_array_string,'&');
I think you need to clear the $post_array_string variable in each loop.
unset($post_array_string);
Before:
foreach($post_array as $key=>$value){
Add:
$post_array_string = '';
Or you can use http_build_query() function.

Output a PDF in PHP from a byte array

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);
?>

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');

Categories