Symfony2 : how to force download - symfony

I am trying to make a link to download a file with symfony2. It does download a file, but it's useless as it is zero octect. I don't know how to make it work. Does anybody know how to do?
The file is in web/uploads/documents/.
Here is the code in the controller:
// here I get the name of the file
$response = new Response();
$response->headers->set('Content-type', 'application/octet-stream');
$response->headers->set('Content-Disposition', sprintf('attachment; filename="%s"', $filename));
return $response;
I tried to write the whole path instead of $filename but it changes all the slashes in underscore.

You forgot to set the content:
$response->setContent(file_get_contents($localFilePath));

Related

Where do you store user uploaded content within a Symfony 4 application?

I have a section within my site where the user can upload their own profile pictures which is stored in the output directory and tracked in the database like so:
$form = $this->createForm(ProfileUpdateForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
$user = $this->getUser();
$firstname = $form->get('firstname')->getData();
$lastname = $form->get('lastname')->getData();
$picture = $form->get('profilepicture')->getData();
if($picture == null)
{
$user
->setFirstName($firstname)
->setLastName($lastname);
}
else
{
$originalFilename = pathinfo($picture->getClientOriginalName(), PATHINFO_FILENAME);
// this is needed to safely include the file name as part of the URL
$safeFilename = strtolower(str_replace(' ', '', $originalFilename));
$newFilename = $safeFilename.'-'.uniqid().'.'.$picture->guessExtension();
try {
$picture->move(
'build/images/user_profiles/',
$newFilename
);
} catch (FileException $e) {
$this->addFlash("error", "Something happened with the file upload, try again.");
return $this->redirect($request->getUri());
}
// updates the 'picture' property to store the image file name
// instead of its contents
$user
->setProfilePicture($newFilename)
->setFirstName($firstname)
->setLastName($lastname);
}
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($user);
$entityManager->flush();
$this->addFlash("success", "Your profile was updated!");
return $this->redirectToRoute('account');
}
return $this->render('account/profile.html.twig', [
'profileform' => $form->createView()
]);
That issue I've found is that every time I compile my (local) project, the image is then deleted (because the public/build directory gets built by deleting and creating again).
If I'm not mistaken, isn't that how deployments work too? And if so, is that the right way to upload an image? What's the right way of going about this?
I'm not sure why, but your public/ directory shouldn't be deleted.
If you're using Webpack Encore, then public/build/ content is deleted and created again when you compile assets. But not public/ itself.
For uploads, we create public/upload/ directory.
Then, most of the time, we set some globals, which allow us to save the file name only.
Globals for Twig in config/packages/twig.yaml which "root" will be in your public/ directory
twig:
globals:
app_ul_avatar: '/upload/avatar/'
app_ul_document: '/upload/document/'
And globals for your controllers, repositories, etc in config/services.yaml
parameters:
app_ul_avatar: '%kernel.root_dir%/../public/upload/avatar/'
app_ul_document: '%kernel.root_dir%/../public/upload/document/'
It's handy because, as I just said, you only get to save the file name in the database.
Which mean that, if you got a public/upload/img/ folder, and want to also generates thumbnails, you can then create public/upload/img/thumbnail/ and nothing will change in your database, nor do you have to save an extra path.
Just create a new global app_ul_img_thumbnail, and you're set.
Then all you have to do is call your globals when you need them, and contact with the file name:
In Twig:
{{ app_ul_avatar~dbResult.filename }}
Or in Controller:
$this->getParameter('app_ul_avatar').$dbResult->getFilename();

Open pdf from server path in Symfony3

I would like to open the pdf file in the window browser but I have "The file "\\servername\20\2016080.pdf" does not exist"
If I copy this path in a browser, it's work.
Edit: I have found in the logs
CRITICAL - Uncaught PHP Exception Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException: "The file "\\servername\20\2016080.pdf" does not exist" at C:\wamp64\www\his\vendor\symfony\symfony\src\Symfony\Component\HttpFoundation\File\File.php line 37
Thank you.
$response = new BinaryFileResponse($result = $ServerModel->getDocument($request-> get('id'));
$response->headers->set('Content-Type', 'application/pdf');
return $response;
If you're using symfony 3.2 or later (which you should be), you can use the new file helper to serve binary files.
from the symfony docs
$pdfPath = $this->getParameter('dir.downloads').'/sample.pdf';
return $this->file($pdfPath);
how you go about getting the path of the file may differ depending on your implementation. But if its a straight SplFileInfo:: object php docs then you can just use:
$file->getPathname();
The file helper will automagically do much of heavy lifting for you.
Make sure the file is accessible, either by a route or by an un-firewalled path.
/**
* #Route("/show-pdf", name="show-pdf")
*/
public function showPdf(Request $request) {
ini_set('display_errors', 'On');
$pdf = file_get_contents('path/to/file.pdf');
return new Response($pdf, 200, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="file.pdf"'
]);
}

Symfony2 forcing jpg download returns corrupted file

Following some of the many posts related to the subject I finally came up with this version of the "force download" code:
public function downloadAction(Request $request){
$filename= 'test.jpg';
$response = new Response();
$response->headers->set('Content-Type','image/jpg');
$response->headers->set('Content-Disposition', 'attachment; filename="' . basename($filename) . '"');
$response->sendHeaders();
$response->setContent(file_get_contents($filename));
return $response;
}
Now, this works fine with zip files (obviously using the right content-type), but for jpg something different happens. When using HexCompare to check both original and downloaded JPG I found that the downloaded version adds "EF BB BF" at the beginning of the file. This seems to be enough for the Windows Image Viewer, which ends reporting a corrupt file error.
On the other hand, the same downloaded jpg opens perfectly in Adobe Photoshop (less strict perhaps?)
Ideas? anyone?
Thanks in advance.
Z
UPDATE: Downloaded Zip files using this code can only be opened with WinRAR or WinZIP, Windows Explorer Zip Extract shows a Corrupt File Error message.
UPDATE2: OK, I know now is a BOM issue. Now, how can I get rid of that nasty "EF BB BF" from the file_get_content result?
Please try the following as suggested here
// Set headers
$response->headers->set('Cache-Control', 'private');
$response->headers->set('Content-type', mime_content_type($filename));
$response->headers->set('Content-Disposition', 'attachment; filename="' . basename($filename) . '"');
$response->headers->set('Content-length', filesize($filename));
// Send headers before outputting anything
$response->sendHeaders();
$response->setContent(readfile($filename));
If you're using apache with mod_xsendfile, try:
return new Response('', 200, array(
'X-Sendfile' => $filename,
'Content-type' => 'application/octect-stream',
'Content-Disposition' => sprintf('attachment; filename="%s"', $filename)),
// ...
));
If you're using nginx's X-Accel read here. and use
return new Response('', 200, array(
'X-Accel-Redirect' => $filename,
'Content-type' => 'application/octect-stream',
'Content-Disposition' => sprintf('attachment; filename="%s"', $filename)),
// ...
));
to gain more control with nginx additional available options are ...
// ...
'X-Accel-Limit-Rate' => '1024',
'X-Accel-Buffering' => 'yes', // yes|no
'X-Accel-Charset' => 'utf-8',
// ...

PHPExcel Bundle in Symfony2: Declaration of PHPExcel_Style_Color error

I install this bundle:
https://github.com/liuggio/ExcelBundle
In my Symfony2, basically add:
[PHPExcel]
git=http://github.com/PHPOffice/PHPExcel.git
target=/phpexcel
version=origin/master
[n3bStreamresponse]
git=git://github.com/liuggio/Symfony2-StreamResponse.git
target=n3b/src/n3b/Bundle/Util/HttpFoundation/StreamResponse
[LiuggioExcelBundle]
git=https://github.com/liuggio/ExcelBundle.git
target=/bundles/Liuggio/ExcelBundle
to deps, update Autoload.php and AppKernel.php and use this Action in one controller:
$excelService = $this->get('xls.service_xls2007');
$excelService->excelObj->getProperties()
->setTitle("Reunión comercial")
->setDescription("Reunión Comercial - Generación automática desde la aplicación de RRHH.");
$excelService->excelObj->getActiveSheet()->setTitle('Reunión Comercial');
// Set active sheet index to the first sheet, so Excel opens this as the first sheet
$excelService->excelObj->setActiveSheetIndex(0);
//create the response
$response = $excelService->getResponse();
$response->headers->set('Content-Type', 'text/vnd.ms-excel; charset=utf-8');
$response->headers->set('Content-Disposition', 'attachment;filename=reuComercial-'.date("Y_m_d_His").'.xls');
// If you are using a https connection, you have to set those two headers for compatibility with IE <9
/*$response->headers->set('Pragma', 'public');
$response->headers->set('Cache-Control', 'maxage=1');
*/
$excelService->setActiveSheetIndex(0)
->setCellValue('A1', 'Lead')
->setCellValue('B1', 'Peticion')
->setCellValue('C1', 'Estado Candidato')
->setCellValue('D1', 'Nombre Candidato')
->setCellValue('E1', 'Apellido Candidato')
->setCellValue('F1', 'Cliente')
->setCellValue('G1', 'Descripcion');
$em = $this->getDoctrine()->getEntityManager();
$data = $em->getRepository('OportunidadBundle:Oportunidad')->reunionComercial();
$aux = 2;
foreach ($data as $row)
{
$excelService->setActiveSheetIndex(0)
->setCellValue('A'.$aux, $row->Lead)
->setCellValue('B'.$aux, $row->Peticion)
->setCellValue('C'.$aux, $row->Estado_Candidato)
->setCellValue('D'.$aux, $row->Nombre_Candidato)
->setCellValue('E'.$aux, $row->Apellido_Candidato)
->setCellValue('F'.$aux, $row->Cliente)
->setCellValue('G'.$aux, $row->Descripcion);
$aux++;
};
$excelService->getStreamWriter()->write( $filename );
return $response;
And I get this error :(
Runtime Notice: Declaration of PHPExcel_Style_Color::bindParent() should be compatible with that of PHPExcel_Style_Supervisor::bindParent() in C:\Program Files\EasyPHP-5.3.8.1\www\www\www\intranet\vendor\phpexcel\Classes\PHPExcel\Style\Color.php line 36
I have no idea what this means, because there are many things in PHP that still escape me :/
It's a problem with pulling the latest development branch code rather than tagged releases: develop branch code is never guaranteed to be in a state where you can simply run it.
I've modified the signatures for the bindParent() method so that this particular notice won't occur again

Drupal rules php action

I am experimenting with the Rules module for the first time and I am attempting to redirect my users with some simple php code as below:
drupal_set_message('testing');
drupal_goto('node/3');
The first line of code executes but the second, which should direct my users to node/3, does not have the desired effect.
How can I get this redirecting feature working?
It's most likely because you have ?destination=some/path in the page URL, these lines in drupal_goto() cause any path you pass to the function to be overwritten by whatever's in the URL:
if (isset($_GET['destination']) && !url_is_external($_GET['destination'])) {
$destination = drupal_parse_url($_GET['destination']);
$path = $destination['path'];
// ...
You can probably get around it simply by changing your code to this:
if (isset($_GET['destination'])) {
unset($_GET['destination']);
}
drupal_goto('node/3');
If that doesn't work try adding this line before drupal_goto:
drupal_static_reset('drupal_get_destination');
which will reset the static cache for the drupal_get_destination() function, which also gets involved in this process at some point (I think).
If all else fails, go old school:
$path = 'node/3';
$options = array('absolute' => TRUE);
$url = url($path, $options);
$http_response_code = 302;
header('Location: ' . $url, TRUE, $http_response_code);
drupal_exit($url);
That's pretty much nicked straight from the drupal_goto() function itself and will definitely work.

Resources