Snappy timeout while generating PDF with Silex - php

I have a Silex project where I want to generate a PDF of a view of this project.
I installed locally wkhtmltopdf on OSX, and i'm using Snappy.
For example, you're on localhost:8001/test/702254 and the page appears. If you access localhost:8001/test/702254/print then the page will be the PDF of the previous (I want the browser show the PDF to the client, then he can download it).
I have a variable in my routes and if it has the 'print' value I want to display the PDF.
$body = null;
$headers = null;
if ($request->get('print') == 'print') {
$uri = str_replace('/print', '', $_SERVER['REQUEST_URI']);
$this->snappy->setOption('cookie', array('MY-COOKIE' => $_COOKIE['MY-COOKIE']));
//$this->snappy->setTimeout(360);
$body = $this->snappy->getOutput('http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . "{$_SERVER['HTTP_HOST']}{$uri}");
$headers = array(
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="Export.pdf"'
);
}
else {
$body = $app['twig']->render('views/index.html.twig', $twigParams);
$headers = array('Cache-Control' => 'max-age=300, public');
}
return new Response($body, 200, $headers);
My problem is when I call the URL with '/print', I have the following error :
ProcessTimedOutException in Process.php line 1211:
The process "/usr/local/bin/wkhtmltopdf --lowquality --cookie 'MY-COOKIE' '4vkvcjnt2svf0' 'http://localhost:8001/test/702254' '/var/folders/2h/qwnt4dk97dsg1mhv_63ycbrh0000gp/T/knp_snappy574713575a5e51.78801388.pdf'" exceeded the timeout of 60 seconds.
I hope it is not an 'OSX issue' as I read in some topics...

Related

Zend Framework CSV download

I am currently working on a CSV generator in Zend Framwork. At this point I am able to create a valid CSV file on the server side and now I want to download that file. I am currently using the following code:
$reader = new \PHPExcel_Reader_CSV();
$reader->setReadDataOnly(true);
$excel = $reader->load($file); //$file = Path of the csv file in the local storage
$writer = \PHPExcel_IOFactory::createWriter($excel, 'CSV');
$path = 'public/download';
$fileName = 'test.csv';
$writer->save($path . '/' . $fileName);
$response = new ResponseStream();
$response->setStream(fopen($path . '/' . $fileName, 'r'));
$headers = new Headers();
$headers->addHeaders([
'Content-Type' => [
'application/force-download',
'application/octet-stream',
'application/download'
],
'Content-Length' => filesize($path . '/' . $fileName),
'Content-Disposition' => 'attachment;filename=' . $fileName,
'Cache-Control' => 'must-revalidate',
'Pragma' => 'no-cache',
'Expires' => 'Thu, 1 Jan 1970 00:00:00 GMT'
]);
$response->setHeaders($headers);
$cookie = new SetCookie('downloadComplete', 'true', time() + 60 * 60, '/');
$response->getHeaders()->addHeader($cookie);
$response->setContent($writer);
return $response;
The problem is now that I only get a Zend error popup:
statusCode 200 thrownError SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data at line 1 column 21 of the JSON data
And the content of my CSV as response text.
Do you have an idea?
Thanks in advance.
After a lot of investigation I found out that the download only fails if we send a Post request to the download action via zend (I assume it overrides the self-setted headers). So I sendt the request via a java script redirect ($viewModel->addScriptBlock('window.location = "Your URL";');) and it worked.

Response::download() doesn't work in Laravel 4

I'm trying to use this: Response::download() to make a download of a file, I'm using Laravel 4, here my code:
public function download_file($file)
{
$file = 'myfile.pdf';
//-- public/docs/myfile.pdf
$path = public_path(). '/docs/' . $file;
$headers = array(
'Content-Type' => 'application/pdf',
);
return Response::download($path, $file, $headers);
}
The error I got:
The file "C:\Users\myuser\Workbench\Web\sites\mysite\public/docs/myfile.pdf" does not exist
What did I went wrong?
Thanks!

Force download on GCS via App Engine using Signed URL

I get my file via:
require_once 'google/appengine/api/cloud_storage/CloudStorageTools.php';
use google\appengine\api\cloud_storage\CloudStorageTools;
$public_link = CloudStorageTools::getPublicUrl("gs://bucket/file.pdf", false);
If I go to $public_link in the browser, it shows the PDF inside the browser. I am trying to figure out how I can force the download of this file.
Google App Engine only has a 60 second timeout so I'm afraid the serve function wont work via GAE. Does anyone have any suggestions?
--
EDIT
Andrei Volga's previous answer in this post suggests I use a Signed URL with a response-content-distribution header.
So far, I am able to create a signed URL that successfully shows the file but I am not able to generate a signed url that has any sort of header at all aka create a signed URL that will force the download instead of just showing it.
This is what I have so far, most of which is courtesy of mloureiro.
function googleBuildConfigurationString($method, $expiration, $file, array $options = [])
{
$allowedMethods = ['GET', 'HEAD', 'PUT', 'DELETE'];
// initialize
$method = strtoupper($method);
$contentType = $options['Content_Type'];
$contentMd5 = $options['Content_MD5'] ? base64_encode($options['Content_MD5']) : '';
$headers = $options['Canonicalized_Extension_Headers'] ? $options['Canonicalized_Extension_Headers'] . PHP_EOL : '';
$file = $file ? $file : $options['Canonicalized_Resource'];
// validate
if(array_search($method, $allowedMethods) === false)
{
throw new RuntimeException("Method '{$method}' is not allowed");
}
if(!$expiration)
{
throw new RuntimeException("An expiration date should be provided.");
}
return <<<TXT
{$method}
{$contentMd5}
{$contentType}
{$expiration}
{$headers}{$file}
TXT;
}
function googleSignString($p12FilePath, $string)
{
$certs = [];
if (!openssl_pkcs12_read(file_get_contents($p12FilePath), $certs, 'notasecret'))
{
echo "Unable to parse the p12 file. OpenSSL error: " . openssl_error_string(); exit();
}
$RSAPrivateKey = openssl_pkey_get_private($certs["pkey"]);
$signed = '';
if(!openssl_sign( $string, $signed, $RSAPrivateKey, 'sha256' ))
{
error_log( 'openssl_sign failed!' );
$signed = 'failed';
}
else $signed = base64_encode($signed);
return $signed;
}
function googleBuildSignedUrl($serviceEmail, $file, $expiration, $signature)
{
return "http://storage.googleapis.com{$file}" . "?GoogleAccessId={$serviceEmail}" . "&Expires={$expiration}" . "&Signature=" . urlencode($signature);
}
$serviceEmail = '<EMAIL>';
$p12FilePath = '../../path/to/cert.p12';
$expiration = (new DateTime())->modify('+3hours')->getTimestamp();
$bucket = 'bucket';
$fileToGet = 'picture.jpg';
$file = "/{$bucket}/{$fileToGet}";
$string = googleBuildConfigurationString('GET', $expiration, $file, array("Canonicalized_Extension_Headers" => ''));
$signedString = googleSignString($p12FilePath, $string);
$signedUrl = googleBuildSignedUrl($serviceEmail, $file, $expiration, $signedString);
echo $signedUrl;
For small files you can use serve option instead of public URL with save-as option set to true. See documentation.
For large files you can use a Signed URL with response-content-disposition parameter.
You can add and additional query string only.
https://cloud.google.com/storage/docs/xml-api/reference-headers#responsecontentdisposition
response-content-disposition
A query string parameter that allows content-disposition to be overridden for authenticated GET requests.
Valid Values URL-encoded header to return instead of the content-disposition of the underlying object.
Example
?response-content-disposition=attachment%3B%20filename%3D%22foo%22

Safari (or Apple OS) adding .txt to .csv download

I am using PHP to create a simple .csv from database entries in Laravel, here's a little sample of the code:
$file = fopen(storage_path('file.csv'), 'w');
//$printer = array from database
foreach ($printer as $row) {
fputcsv($file, $row);
}
fclose($file);
//$formname = Object values
$headers = array(
'Content-Type: text/csv',
'Content-Length: ' . filesize(storage_path('file.csv')),
'Content-Disposition: attachment; filename="'.$formname->name.'.csv"'
);
return Response::download(storage_path('file.csv'), $formname->name.'.csv', $headers);
All pretty standard and work's fine for me, but my Client is using OS X 10.9.3 & Safari 7.0.4 and each download is given a .txt extension and I can't find a way to stop it from either server or client side. (so it downloads as file.csv.txt)
I have searched Google but can only find other users with the problem - no solution, the code above is already edited using suggestions found on Stackoverflow:
1. laravel adding .txt on the downloaded file
2. How to use the CSV MIME-type?
Can anyone tell me where this problem arises and how to fix it?
And is there anywhere I can test the download as I only have Windows and the testing websites I use only provide visual renders.
Also: The client has assured me he can download .csv's from other sources without this problem
As I can see Symfony iterates through the headers as key-value pairs:
public function __construct(array $headers = array())
{
foreach ($headers as $key => $values) {
$this->set($key, $values);
}
}
And then sets them this way:
if (true === $replace || !isset($this->headers[$key])) {
$this->headers[$key] = $values;
} else {
$this->headers[$key] = array_merge($this->headers[$key], $values);
}
So if you only have values in the $headers array with numeric indexes, the result might be unexpected. Try to change your code to this:
$headers = array(
'Content-Type' => 'text/csv',
'Content-Length' => filesize(storage_path('file.csv')),
'Content-Disposition' => 'attachment; filename="'.$formname->name.'.csv"'
);

Creating pdf in symfony 2.3.*

I have searched for creating pdf file in symfony 2.3 but was not successful. I've got 2 bundle
Knp snapy bundle and another is
psliwa / PHPPdf
My task is just download pdf file on click. For this I have given the link in html.twig like
Download file
In pdf action I am generating the PDF file
In knp snapy bundle I am doing:
$html = $this->renderView('MyBundle:Foo:bar.html.twig', array(
'some' => $vars
));
return new Response(
$this->get('knp_snappy.pdf')->getOutputFromHtml($html),
200,
array(
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="file.pdf"'
)
);
And got error
The exit status code '1' says something went wrong: stderr: "The
system cannot find the path specified.
Is wkpdftohtml necessary for installation if YES then how can I install on sharing based hosting.
In psliwa / PHPdf I have read the example from:
psliwa/PdfBundle
psliwa/PHPPdf
and got
unable to find twig file
If I change the $format = $this->get('request')->get('_format'); to $format='pdf'; then it show simple html file.
Unable to understand what should I do for completion of task...
Yes. For Knp Snappy Bundle, wkhtmltopdf is required and you need to configure it properly in the config.yml
knp_snappy:
pdf:
enabled: true
binary: /usr/local/bin/wkhtmltopdf #path to wkhtmltopdf binary
options: []
This is an excerpt from a controller in a live shared host environment using psliwa/PHPPdf:
$facade = $this->get('ps_pdf.facade');
$response = new Response();
$this->render('ManaClientBundle:Contact:roster.html.twig', array(
'date' => $found['latestDate'],
'center' => $location,
'roster' => $found['contactSet'],
), $response);
$date = new \DateTime($found['latestDate']);
$filename = str_replace(' ', '', $location) . date_format($date, '_Ymd') . '.pdf';
$xml = $response->getContent();
$stylesheet = $this->renderView('ManaClientBundle:Contact:contact.xml.twig', array());
$content = $facade->render($xml, $stylesheet);
return new Response($content, 200, array
('content-type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename=' . $filename
));

Categories