Send attachment/Download file from Symfony action - php

I'm trying to deliver a CSV file through an action. The mime-type in the response still shows as text/html. Can someone help? Thanks
//$this->setLayout(false);
//$this->getUser()->shutdown();
//sfConfig::set('sf_web_debug', false);
$response = $this->getContext()->getResponse();
$response = $this->getResponse();
$response->clearHttpHeaders();
$response->setHttpheader('Pragma: public', true);
$response->addCacheControlHttpHeader('Cache-Control', 'must-revalidate');
$response->setContentType('application/octet-stream', true);
$response->setHttpHeader('Content-Description', 'File Transfer');
$response->setHttpHeader('Content-Transfer-Encoding', 'binary', true);
$response->setHttpHeader('Content-Length', filesize($file_path));
$response->setHttpHeader('Content-Disposition', 'attachment; filename="' . $file_name . '"');
$this->getResponse()->sendHttpHeaders();
//$response->setContent(file_get_contents($file_path));
//readfile($file_path);
$this->renderText(file_get_contents($file_path));
//return sfView::NONE;
return sfView::HEADER_ONLY;
Trust me, before getting here, I've all search results purple. As you can see all the permutations & combinations above, I still couldn't get this working!

Try something like this:
$path = 'absolute/path/to/the/file';
/** #var $response sfWebResponse */
$response = $this->getResponse();
$response->setContentType('text/csv');
$response->setHttpHeader('Content-Disposition', 'attachment; filename="' . basename($path) . '"');
$response->setContent(file_get_contents($path));
return sfView::NONE;
Note: filename must be ASCII see RFC 6266

Related

slim create response with guzzle streamFor content

I have an issue when building a slim (slim 4) response with a streamed content (a huge xlsx file content).
$fileHandler = \fopen(getenv('SHARED_FILES_PATH') . $filename, 'r');
if (!$fileHandler) {
throw new \Exception('Unable to open file ' . getenv('SHARED_FILES_PATH') . $filename . ' for reading.');
}
$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);
// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->withBody($stream);
return $response;
The error:
Fatal error: Uncaught RuntimeException: Unable to read from stream in /home/vincent/workspace/opco2i_applis/opco2i_portail/server/vendor/guzzlehttp/psr7/src/Stream.php on line 232
I have made some check and the file exists and is readable.
If i do the following after the fopen call:
$contents = '';
while (!feof($fileHandler)) {
$contents .= fread($fileHandler, 8192);
break;
}
fclose($fileHandler);
var_dump($contents);die();
, i can read some content of my file.
Can you help me to find why guzzle stream cannot work in this case ?
After some tests, i have found the solution.
I must use $response->getBody()->write($stream) instead of $response->withBody($stream);
$stream = GuzzleHttp\Psr7\Utils::streamFor($fileHandler);
// $this->response is Psr\Http\Message\ResponseInterface
$response = $this->response;
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' . $filename . '"');
$response = $response->withHeader('Content-Type', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
$response = $response->getBody()->write($stream);
return $response;

PHP - Returning response with downloadable url

I am trying for hours to figure out how to return my csv file trough URL in response.
The csv file is there, url is matched but I don't know how can I return downloadable url in my response.
$rootDir = $this->container->get('kernel')->getRootDir();
$dir = $rootDir . '/../web/uploads/news/';
/// - rest of the code that is not relevant and generates my csv $fileName
$fp = fopen($fileName, 'w');
In this part I am trying to set my response headers and downloadable url with no luck:
$baseurl = $request->getScheme() . '://' . $request->getHttpHost()
. $request->getBasePath() . $dir . $fileName;
// Set response
$response = new BinaryFileResponse($dir .DIRECTORY_SEPARATOR. $fileName);
// Set headers
$d = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$fileName
);
$response->headers->set('Content-Disposition', $d);
return $this->success();
$response = new BinaryFileResponse($pathToFile);
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
'filenameThatWillBeDownloaded.yourextension'
);
return $response;
dont forget to import the classes
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;

PHP REST download file

I have a webservice with a function like this
$app->get('/downloadPdf', function () use($app)
{
$log = 'example.pdf';
$res = $app->response();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($log);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($log);
readfile($log);
});
Testing it with Advanced Rest Client works fine..
Question is .. how do i call it from my client with all the headers etc.
To specify more. I know there are a lot of examples on how to download a specific file by inserting its url into the curlopt_url with the complete address to the file. What i want is to let the webservice decide which file to return...
Thanks
Never got an answer .. so !!!
This is how i made it work....
Service Function can be seen below
$app->post('/downloadReport', 'authenticate', function() use ($app)
{
verifyRequiredParams(array('reportId'));
$body = $app->request()->getBody();
$params_str = urldecode($body);
$input = json_decode($params_str,true);
$report_id = $input['reportId'];
$db = new DbHandler();
$db->getReport($report_id);
$path = $db->getReportPdfPath($report_id);
$res = $app->response();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($path);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($path);
readfile($path);
});
Called the function like this:
public function downloadReport($api_key,$id)
{
$curl_post_data = array('reportId' => $id);
$headers = array('Content-type: application/json','Authorization: '.$api_key,);
$fp = fopen (dirname(__FILE__) . '/localfile.tmp', 'w+');//This is the file where we save the information
$curl = curl_init(DONWLOAD_REPORT);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode($curl_post_data));
curl_setopt($curl, CURLOPT_USERPWD, $api_key);
$file = curl_exec($curl);
if ($file === false)
{
$info = curl_getinfo($curl);
curl_close($curl);
die('error occured during curl exec. Additioanl info: ' . var_export($info));
}
curl_close($curl);
header('Content-type: ' . 'application/octet-stream');
header('Content-Disposition: ' . 'attachment; filename=report.pdf');
echo $file;
}
I have same problem with you,
I am using this code, and it works, return a pdf file from webservice.
$api = new RestClient(array(
'base_url' => 'http://another-webservice.com/',
'headers' => array(
'X-Token' => $res->headers->x_token,
'Accept' => 'application/pdf',
),
));
$result = $api->execute("reports/report",'GET', $params);
$filename = 'Report.pdf';
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename="' . $filename . '"');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
echo $result->response;
References: How to display PDF in Browser

Issues when downloading file from Slim Framework

I want to download file through Slim Framework (The reason why I'm using Slim Framework is because I want to write a simple REST API). I found this post:
Download file from Slim Framework 2.4 and this post: http://help.slimframework.com/discussions/questions/359-file-download. I followed the method. Here is my code:
$app->get('/download/:id', 'authenticate', function($id) use ($app)
{
$log = '../download/'.$id.'/myfile.zip';
$res = $app->response()->headers();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($log);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($log);
readfile($log);
// NOTE:
// $response = array();
// $response["error"] = false;
// echoRespnse(200, $response);
});
I'm using the Google Chrome's Advanced Rest Client application to test. The problem is the browser hung after the file downloaded.If I comments out the NOTE part in my source code, the browser won't hang again. But I got a "Unexpected token P" error.
Can anybody help? Thanks.
Try the solution here: PHP readfile() adding extra bytes to downloaded file.
You lack the calls to ob_clean, flush and exit.
The problem might be becasue of extra characters output with the rest of the file contents.
For Slim 3, I had a bit of struggle.
I struggled with this in Slim 3.0.
I was trying something like the following and the pdf binary was getting displayed on the screen.
$header['Content-Description'] = 'File Transfer';
$header['Content-Disposition'] = 'attachment; filename="' .basename("$file") . '"';
// ...
$response = $response->withHeader($header);
In order to make it work, you need to set the key/value pairs using $response->withHeader(). And it works like a charm. For example:
$response = $response->withHeader('Content-Type', 'application/pdf');
$response = $response->withHeader('Content-Description', 'File Transfer');
$response = $response->withHeader('Content-Disposition', 'attachment; filename="' .basename("$file") . '"');
$response = $response->withHeader('Content-Transfer-Encoding', 'binary');
$response = $response->withHeader('Expires', '0');
$response = $response->withHeader('Cache-Control', 'must-revalidate');
$response = $response->withHeader('Pragma', 'public');
$response = $response->withHeader('Content-Length', filesize($file));
maybe it's a little late but you can use this package for slim http file response :
https://github.com/mhndev/slim-file-response
Is the solution above working for you? Here's my code, which just outputs obscure characters directly into the browser window:
$app->get('/file/:fileid', function($fileid) use ($app)
{
$zip = new ZipArchive();
$zipname = "zipfile3.zip"; // Zip name
$zip->open($zipname, ZipArchive::CREATE);
$files = array ( "sprecher_inserts_en_VB.doc" );
foreach ($files as $file) {
$path = "uploads/".$file;
if(file_exists($path)){
$zip->addFromString(basename($path), file_get_contents($path));
}
else{
echo"file does not exist";
}
}
$zip->close();
// after that, the zip file is on the server and valid when downloaded manually (e.g. by entering its URL directly)
$res = $app->response()->headers();
$res['Content-Description'] = 'File Transfer';
$res['Content-Type'] = 'application/octet-stream';
$res['Content-Disposition'] ='attachment; filename=' . basename($zipname);
$res['Content-Transfer-Encoding'] = 'binary';
$res['Expires'] = '0';
$res['Cache-Control'] = 'must-revalidate';
$res['Pragma'] = 'public';
$res['Content-Length'] = filesize($zipname);
ob_clean();
flush();
readfile($zipname);
exit();
});
The output in the browser window is the following, no dialog for downloading the file is loaded whatsoever:

Why Response::download() won't download anything except PDF in Laravel 4?

This is the line of code which is giving me sick.
return Response::download(storage_path().'/file/' . $file->id . "." . $file->file->extension);
The files are uploaded and given an id which they are saved under e.g. 25.pdf this works fine if the file is a PDF but doesn't for anything else e.g. PNG. we upgraded from Laravel 3 to 4 to try to overcome this problem.
Any ideas?
EDIT:
I just uploaded a test text file with the word test in it once I uploaded it and then downloaded it I opened it, there were 3 blank lines and the letters te!!!!!I downloaded it through sftp and the file is correctly stored on the server so it is defiantly the download procedure!
I used this function instead of any of the Laravel stuff. :/
(Stolen from other places around the web)
public static function big_download($path, $name = null, array $headers = array()) {
if (is_null($name))
$name = basename($path);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$pathParts = pathinfo($path);
// Prepare the headers
$headers = array_merge(array(
'Content-Description' => 'File Transfer',
'Content-Type' => finfo_file($finfo, $path),
'Content-Transfer-Encoding' => 'binary',
'Expires' => 0,
'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
'Pragma' => 'public',
'Content-Length' => File::size($path),
'Content-Disposition' => 'inline; filename="' . $name . '.' . $pathParts['extension'] . '"'
), $headers);
finfo_close($finfo);
$response = new Symfony\Component\HttpFoundation\Response('', 200, $headers);
// If there's a session we should save it now
if (Config::get('session.driver') !== '') {
Session::save();
}
// Below is from http://uk1.php.net/manual/en/function.fpassthru.php comments
session_write_close();
ob_end_clean();
$response->sendHeaders();
if ($file = fopen($path, 'rb')) {
while (!feof($file) and (connection_status() == 0)) {
print(fread($file, 1024 * 8));
flush();
}
fclose($file);
}
// Finish off, like Laravel would
Event::fire('laravel.done', array($response));
$response->foundation->finish();
exit;
}
One may ask, How can i get path to file in laravel?
Path to file can be achieved like:
public function getDownload(){
$file = public_path()."/downloads/info.pdf";
$headers = array('Content-Type: application/pdf',);
return Response::download($file, 'info.pdf',$headers);
}
function will download file from : 'project/public/download' folder.
(don't forget to set-up routes and controller by your self)
Try including the MIME in the return:
$file = storage_path().'/file/' . $file->id . "." . $file->file->extension;
return Response::download($file, 200, array('content-type' => 'image/png'));
If you are using Windows, go to php.ini and then uncomment "extension=php_fileinfo.dll" section and then use this code:
Route::get('file/download', function()
{
$file = public_path(). '\download\myfile.png';
return Response::download($file);
});

Categories