How to use Nginx X-Accel with Symfony? - symfony

I would want to use Nginx X-Accel with Symfony, for the moment I've this code.
$request->headers->set('X-Sendfile-Type', 'X-Accel-Redirect');
$request->headers->set('X-Accel-Mapping', '/var/www/html/files/=/protected-files/');
$request->headers->set('X-Accel-Limit-Rate', '1k');
BinaryFileResponse::trustXSendfileTypeHeader();
$response = new BinaryFileResponse($file->getAbsolutePath());
$response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"');
$response->headers->set('Cache-Control', 'no-cache');
return $response;
And the Nginx Conf:
location /protected-files {
internal;
alias /var/www/html/files;
}
To test the code (know if the file is really served by Nginx), I've add a X-Accel-Limit-Rate on 1ko/s, but a 2Mo file is downloaded instantly, then I'm sure, it doesn't work fine.
I've find this part of code on internet, because the Symfony doc, doesn't really explain how to use it... (http://symfony.com/doc/current/components/http_foundation.html#serving-files)
Why I need to return a BinaryResponse with the file, like without Nginx X-Sendfile, and add the X-Sendfile, X-Accel properties in the resuqest ? I just return the response, no the request, how it can work ?

Finally, I move the X-Accel part from $request to $response, and just set X-Accel-Redirect header.
If we want limit the download speed, we can use $request->headers->set('X-Accel-Limit-Rate', 10000);, it works well, the number is in bytes.
Then I've change the $response->headers->set('Content-Disposition', 'attachment;filename="'.$filename.'"'); to $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $filename);
The final code is:
BinaryFileResponse::trustXSendfileTypeHeader();
$response = new BinaryFileResponse($file->getAbsolutePath());
$response->setContentDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$filename
);
$response->headers->set('X-Accel-Redirect', '/protected-files/path/to/file');
return $response;
And in Nginx:
location /protected-files/ {
internal;
alias /var/www/html/files/;
}

Related

Symfony 3. Cookie auto deletes immediately after create

I create cookie in EventSubscriber:
function onKernelResponse(FilterResponseEvent $event)
{
$response = new Response();
$cookie_data = 'test';
$cookie = new Cookie('test_cookie', $cookie_data, strtotime('now +1 year'));
$response->headers->setCookie($cookie);
$response->send();
}
then I watch to Application tab in Chrome and press F5.
this cookie appears for 0.5 sec and automatically remove
what i am doing wrong?
I hope this helps somebody.
I found problem: nginx send missed static files like .jpg to application.
When i fix nginx vhost file - cookies starts to set correctly.

Return an image from a controller action in symfony

I need to access an image by providing its name in the url path, i tried to use this code but the image is not showing
/**
*
* #Route("images/{imgname}",name="workflow_image")
*/
public function WorkflowImageAction(Request $request,$imgname){
$filepath = $this->get('kernel')->getRootDir().'/../web/images/workflow/'.$imgname;
$file = readfile($filepath);
$headers = array(
'Content-Type' => 'image/png',
'Content-Disposition' => 'inline; filename="'.$file.'"');
return $file;
}
if you are serving a static file, you can use a BinaryFileResponse:
use Symfony\Component\HttpFoundation\BinaryFileResponse;
$file = 'path/to/file.txt';
$response = new BinaryFileResponse($file);
return $response;
More info about Serving Files in Symfony2 in the doc.
Hope this help
Are you sure, it's a good idea to share image through php?
You can write some rules for folder web/image/workflow in your server (nginx or apache).
Share them through php is bad idea.
Nginx/apache can do it very fast, not using RAM (php read full image in RAM).
Also, nginx/apache can cache this image.
All the answers here are outdated.
I would suggest not using BinaryFileResponse or using file_get_contents since they would read the whole file and place it in your memory.
Please use StreamedResponse provided at Symfony\Component\HttpFoundation\StreamedResponse.
$imageFilePath = dirname(__FILE__)."/../../var/tmp/bean.jpg";
$streamedResponse = new StreamedResponse();
$streamedResponse->headers->set("Content-Type", 'image/png');
$streamedResponse->headers->set("Content-Length", filesize($imageFilePath));
$streamedResponse->setCallback(function() use ($imageFilePath) {
readfile($imageFilePath);
});
return $streamedResponse;

Symfony redirect to external URL

How can I redirect to an external URL within a symfony action?
I tried this options :
1- return $this->redirect("www.example.com");
Error : No route found for "GET /www.example.com"
2- $this->redirect("www.example.com");
Error : The controller must return a response (null given).
3- $response = new Response();
$response->headers->set("Location","www.example.com");
return $response
No Error but blank page !
Answer to your question is in official Symfony book.
http://symfony.com/doc/current/book/controller.html#redirecting
public function indexAction()
{
return $this->redirect('http://stackoverflow.com');
// return $this->redirect('http://stackoverflow.com', 301); - for changing HTTP status code from 302 Found to 301 Moved Permanently
}
What is the "URL"? Do you have really defined route for this pattern? If not, then not found error is absolutelly correct. If you want to redirect to external site, always use absolute URL format.
You have to use RedirectResponse instead of Response
use Symfony\Component\HttpFoundation\RedirectResponse;
And then:
return new RedirectResponse('http://your.location.com');

Matching a URL to a route in Symfony

We have files behind authentication, and I want to do different things for post-authentication redirect if the user entered the application using a URL of a file versus a URL of an HTML resource.
I have a URL: https://subdomain.domain.com/resource/45/identifiers/567/here/11abdf51e3d7-some%20file%20name.png/download. I want to get the route name for this URL.
app/console router:debug outputs this: _route_name GET ANY subdomain.domain.{tld} /resource/{id2}/identifiers/{id2}/here/{id3}/download.
Symfony has a Routing component (http://symfony.com/doc/current/book/routing.html), and I'm trying to call match() on an instance of Symfony\Bundle\FrameworkBundle\Routing\Router as provided by Symfony IOC. I have tried with with the domain and without the domain, but they both create a MethodNotAllowed exception because the route cannot be found. How can I match this URL to a route?
Maybe a bit late but as I was facing the same problem, what I come to is something like
$request = Request::create($targetPath, Request::METHOD_GET, [], [], [], $_SERVER);
try {
$matches = $router->matchRequest($request);
} catch (\Exception $e) {
// throw a 400
}
The key part is to use $_SERVER superglobal array in order to have all things setted straight away.
According to this, Symfony uses current request's HTTP method while matching. I guess your controller serves POST request, while your download links are GET.
The route name is available in the _route_name attribute of the Request object: $request->attributes->get('_route_name').
You can do something like this ton get the route name:
public/protected/private function getRefererRoute(Request $request = null)
{
if ($request == null)
$request = $this->getRequest();
//look for the referer route
$referer = $request->headers->get('referer');
$path = substr($referer, strpos($referer, $request->getBaseUrl()));
$path = str_replace($request->getBaseUrl(), '', $lastPath);
$matcher = $this->get('router')->getMatcher();
$parameters = $matcher->match($path);
$route = $parameters['_route'];
return $route;
}
EDIT:
I forgot to explain what I was doing. So basicly you are getting the page url ($referer) then taking out your website's base url with str_replace and then trying to match the remaining part of the path with a know route pattern using route matcher.
EDIT2:
Obviously you need to have this inside you controller if you want to be able to use $this->get(...)

Content-Type for file export with Symfony2

I have a problem. I try to force the charset(ISO-8859-1) to download a file with this code :
$response = new Response($data);
$response->headers->set('Content-Type', 'text/plain; charset=ISO-8859-1');
$response->headers->set('Content-Type', 'application/octet-stream');
$response->headers->set('Content-Disposition', 'attachment; filename=test.ps1');
$response->headers->set('Content-Transfer-Encoding', 'binary');
$response->headers->set('Expires', 0);
$response->headers->set('Cache-Control', 'must-revalidate');
$response->headers->set('Pragma', 'public');
 
return $response;
but I still get a file in utf-8...
I looked in the profiler, I see the good charset but nothing works.
I feel that it still keeps the default charset of the application :s
Do you have any idea where it can come from?
Thank you in advance.
Since you're actually downloading the file it up to the external application that opens the file to honor the encoding (and not override it).
I think that charset only matters when you're outputing the content to the browser

Resources