Symfony 2 ESI Cache - php

I have an action which is called in all my page (for logged people only), this action retrieves recent tweets from my twitter account.
API access is limited so I would like the result of this action to be in cache for 10 minutes
public function socialAction(){
$consumerKey = $this->container->getParameter('consumer_key');
$consumerSecret = $this->container->getParameter('consumer_secret');
$accessToken = $this->container->getParameter('access_token');
$accessTokenSecret = $this->container->getParameter('access_token_secret');
// on appel l'API
$tweet = new TwitterOAuth($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);
$screen_name = "blabla";
$tweets = $tweet->get('statuses/user_timeline', [
'screen_name' => $screen_name,
'exclude_replies' => true,
'count' => 50
]);
$tweets = array_splice($tweets, 0, 5);
$response = $this->render('GestionJeuBundle:Default:social.html.twig', array("tweets" => $tweets));
$response->setPublic();
$response->setSharedMaxAge(600);
return $response;
}
To enable caching I have made ​​the following changes
app/config/config.yml
framework:
esi: { enabled: true }
fragments: { path: /_proxy }
and
app/AppCache.php
<?php
require_once __DIR__.'/AppKernel.php';
use Symfony\Bundle\FrameworkBundle\HttpCache\HttpCache;
class AppCache extends HttpCache
{
protected function getOptions()
{
return array(
'debug' => false,
'default_ttl' => 0,
'private_headers' => array('Authorization', 'Cookie'),
'allow_reload' => false,
'allow_revalidate' => false,
'stale_while_revalidate' => 2,
'stale_if_error' => 60,
);
}
}
and
web/app_dev.php
<?php
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Debug\Debug;
// If you don't want to setup permissions the proper way, just uncomment the following PHP line
// read http://symfony.com/doc/current/book/installation.html#configuration-and-setup for more information
//umask(0000);
// This check prevents access to debug front controllers that are deployed by accident to production servers.
// Feel free to remove this, extend it, or make something more sophisticated.
if (isset($_SERVER['HTTP_CLIENT_IP'])
|| isset($_SERVER['HTTP_X_FORWARDED_FOR'])
|| !in_array(#$_SERVER['REMOTE_ADDR'], array('127.0.0.1', '.....', 'fe80::1', '::1'))
) {
header('HTTP/1.0 403 Forbidden');
exit('You are not allowed to access this file. Check '.basename(__FILE__).' for more information.');
}
$loader = require_once __DIR__.'/../app/bootstrap.php.cache';
Debug::enable();
require_once __DIR__.'/../app/AppKernel.php';
require_once __DIR__.'/../app/AppCache.php';
$kernel = new AppKernel('dev', true);
$kernel->loadClassCache();
$kernel = new AppCache($kernel);
// When using the HttpCache, you need to call the method in your front controller instead of relying on the configuration parameter
Request::enableHttpMethodParameterOverride();
$request = Request::createFromGlobals();
$response = $kernel->handle($request);
$response->send();
$kernel->terminate($request, $response);
error_log($kernel->getLog());
Despite that the page is updated every page refresh (after testing, it does exactly the same things in production environment with change on app.php too)
Have I misunderstood or forgotten a thing ?
Thank you in advance for your help.
EDIT solve : i was rendering this action with
{{render(controller("GestionJeuBundle:Default:social")) }}
changing it for
{{render_esi(controller("GestionJeuBundle:Default:social")) }}
solve my problem
Hexune

i was rendering this action with
{{render(controller("GestionJeuBundle:Default:social")) }}
changing it for
{{render_esi(controller("GestionJeuBundle:Default:social")) }}
solve my problem

As far as I experimented last weeks, it's worth noting that if you use debug environment in Symfony, Varnish always passes-by your request to the back-end.

Related

Laravel 5.6 ckfinder integration

I want to integrate ckfinder with my laravel but I am stuck with authentication.
I found many ways but there were for older laravel versions and none are working for 5.6.
I found this:
require '../../vendor/autoload.php';
$app = require_once '../../bootstrap/app.php';
$app->make('Illuminate\Contracts\Http\Kernel')
->handle(Illuminate\Http\Request::capture());
But I am getting Invalid request from Ckfinder when I put it in config.php
I would like to access Auth::check() and return it in authentication
require __DIR__ . '/../../vendor/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/app.php';
$request = Illuminate\Http\Request::capture();
$request->setMethod('GET');
$app->make('Illuminate\Contracts\Http\Kernel')
->handle($request);
$config['authentication'] = function () {
return auth()->check();
};
EDIT
So I had a look at index.php and copied this into config.php:
define('LARAVEL_START', microtime(true));
require '/Applications/MAMP/htdocs/laravel-dealer/vendor/autoload.php';
$app = require_once '/Applications/MAMP/htdocs/laravel-dealer/bootstrap/app.php';
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
$response = $kernel->handle(
$request = Illuminate\Http\Request::capture()
);
But I am getting runtime exceptions for $acl argument.
Fatal error: Uncaught RuntimeException: Controller
"CKSource\CKFinder\Command\Init::execute()" requires that you provide
a value for the "$acl" argument. Either the argument is nullable and
no null value has been provided, no default value has been provided or
because there is a non optional argument after this one. in
/Applications/MAMP/htdocs/laravel-dealer/vendor/symfony/http-kernel/Controller/ArgumentResolver.php:78
Stack trace: #0
/Applications/MAMP/htdocs/laravel-dealer/vendor/symfony/http-kernel/HttpKernel.php(141):
Symfony\Component\HttpKernel\Controller\ArgumentResolver->getArguments(Object(Symfony\Component\HttpFoundation\Request),
Array) #1
/Applications/MAMP/htdocs/laravel-dealer/vendor/symfony/http-kernel/HttpKernel.php(66):
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request),
1) #2
/Applications/MAMP/htdocs/laravel-dealer/public/ckfinder/core/connector/php/vendor/cksource/ckfinder/src/CKSource/CKFinder/CKFinder.php(610):
Symfony\Component\HttpKernel\HttpKernel- in
/Applications/MAMP/htdocs/laravel-dealer/vendor/symfony/http-kernel/Controller/ArgumentResolver.php
on line 78
Thanks for any help
Here's how the authentication section looks like on one of my projects
/*============================ Enable PHP Connector HERE ==============================*/
// http://docs.cksource.com/ckfinder3-php/configuration.html#configuration_options_authentication
require __DIR__ . '/../../vendor/autoload.php';
$app = require_once __DIR__ . '/../../bootstrap/app.php';
$request = Illuminate\Http\Request::capture();
$request->setMethod('GET');
$app->make('Illuminate\Contracts\Http\Kernel')
->handle($request);
$config['authentication'] = function () {
return auth()->check();
};
Well I spent some time with this and came up with this solution:
This function gets the value of $_COOKIE['allowCkfinder'] and decrypts it using cipher and your app key.
// /public/ckfinder/config.php
$config['authentication'] = function () {
$APP_KEY = "YOUR_APP_KEY";
$cookie_contents = json_decode( base64_decode( $_COOKIE['allowCkfinder'], true ));
$value = base64_decode( $cookie_contents->value );
$iv = base64_decode( $cookie_contents->iv );
return unserialize( openssl_decrypt($value, "AES-256-CBC", base64_decode($APP_KEY), OPENSSL_RAW_DATA, $iv));
};
When logging in user / admin set cookie with name allowCkfinder:
Also dont forget to remove the cookie on user logout.
// /app/Http/Controllers/LoginController.php
if (Auth::attempt(['user_email' => $validatedData['email'], 'password' => $validatedData['password'], "user_active" => 1, "user_banned" => 0]))
{
if (Auth::user()->user_admin == TRUE)
return redirect()->intended('/')->withCookie(cookie()->forever('allowCkfinder', "1"));
else
return redirect()->intended('/');
} else
{
$request->session()->flash('error', __("E-mail and/or password do not match"));
return redirect('login')->withInput();
}
That's the best I came up with.

Guzzle Http Client and authorization in LinkedIn

I try to simulate the authorization LinkedIn web browser (PHP). I use Guzzle Http Client.
Here is part of the authorization code:
use GuzzleHttp\Client as LinkedinClient;
use PHPHtmlParser\Dom as Parser;
public function authLinkedin()
{
$client = new LinkedinClient(['base_url' => 'https://www.linkedin.com']);
try {
$postData = [
'session_key' => 'My_email',
'session_password' => 'My_password',
'action' => 'login'
];
$request = $client->createRequest('POST', '/uas/login', ['body' => $postData, 'cookies' => true]);
$response = $client->send($request);
if ($response->getStatusCode() === 200) {
$parser = new Parser();
$parser->load($client->get('https://www.linkedin.com/', ['cookies' => true])->getBody());
return $parser;
} else {
Log::store("Authorization error", Log::TYPE_ERROR, $request->getStatusCode());
return null;
}
return $request;
} catch (Exception $ex) {
Log::store("Failure get followers", Log::TYPE_ERROR, $ex->getMessage());
return null;
}
}
The request is successful, returns a 200 code, but I did not authorize.
Who can faced with a similar task, or in the code have missed something. I would appreciate any advice.
I think that the issue is with CSRF protection and other hidden parameters. LinkedIn, as other sites, usually returns 200 OK for all situations, even for an error, and describes details in resulting HTML.
In your case it's better to use a web scraper, like Goutte. It emulates a user with a browser, so you don't need to worry about many things (like CSRF protection and other hidden fields). Examples can be found on the main pages, try something like this:
$crawler = $client->request('GET', 'https://www.linkedin.com');
$form = $crawler->selectButton('Sign In')->form();
$crawler = $client->submit($form, array(
'login' => 'My_email',
'password' => 'My_password'
));
You can use it with Guzzle as a driver, but some sites might require JavaScript (I'm not sure about Amazon). Then you have to go to a real browser or PhantomJS (a kind of headless Chrome).

Facebook PHP SDK 5 :: API 2.4 :: Cross-site request forgery validation failed. Required param "state" missing

I did a very simple PHP script, just to try to login via Facebook and get an accessToken. But when I try the following code, I get an Exception from the SDK : « Cross-site request forgery validation failed. Required param "state" missing. ».
Here is my code :
require_once __DIR__ . '/facebook-sdk-v5/autoload.php';
session_start();
$fb = new Facebook\Facebook([
'app_id' => '{my-own-app-id}',
'app_secret' => '{my-own-app-secret}'
]);
// Check to see if we already have an accessToken ?
if (isset($_SESSION['facebook_access_token'] )) {
$accessToken = $_SESSION['facebook_access_token'];
echo "Horray we have our accessToken:$accessToken<br />\n";
} else {
// We don't have the accessToken
// But are we in the process of getting it ?
if (isset($_REQUEST['code'])) {
$helper = $fb->getRedirectLoginHelper();
try {
$accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
if (isset($accessToken)) {
// Logged in!
$_SESSION['facebook_access_token'] = (string) $accessToken;
// Now you can redirect to another page and use the
// access token from $_SESSION['facebook_access_token']
echo "Finally logged in! Token:$accessToken";
}
} else {
// Well looks like we are a fresh dude, login to Facebook!
$helper = $fb->getRedirectLoginHelper();
$permissions = ['email', 'user_likes']; // optional
$loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions);
echo 'Log in with Facebook!';
}
}
exit;
I had to add this lines in some servers:
$helper = $fb->getRedirectLoginHelper();
if (isset($_GET['state'])) {
$helper->getPersistentDataHandler()->set('state', $_GET['state']);
}
I get this error randomly, depending of the server config.
session_start() at the beginning of both the scripts. I got solution from here: https://github.com/facebook/facebook-php-sdk-v4/issues/473
If you're using a "www" version of your site to generate the login link and you get redirected to the non-www version, you'll run into issues with your session. So make sure you access the www version of your site and then define the callback url to the same www version. Also, you can define permanent redirects in your server configuration to make sure anyone accessing your site from the non-www version gets redirected to the www version or vice versa.
I also ran into the same problem and after researching on stackoverflow
putting line
$_SESSION['FBRLH_state']=$_GET['state'];
above has solved my problem
$helper = $fb->getRedirectLoginHelper();
you receive this error if you origin hostname is different than the target hostname once authenticated.
$loginUrl = $helper->getLoginUrl('http://mywebsite.com/myapp/index.php', $permissions);
with this statement, if the visitor on your website used http://www.mywebsite.com/ the cross-site error will be raised.
You must ensure that origin and target hostname are exactly the same, including the eventual www prefix.
Fixed version:
$loginUrl = $helper->getLoginUrl('http://'.$_SERVER['SERVER_NAME'].'/myapp/index.php', $permissions);
Laravel 5.2
I have this error too "Cross-site request forgery validation failed. Required param “state” missing".
and after reading this for hours. I tried to change the vendor script.
in vendor\facebook\php-sdk-v4\src\Facebook\Helpers\FacebookRedirectLoginHelper.php
on line 123, I change this script:
private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
$state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
$this->persistentDataHandler->set('state', $state);
return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}
into (I add Session::put('state', $state);)
private function makeUrl($redirectUrl, array $scope, array $params = [], $separator = '&')
{
$state = $this->pseudoRandomStringGenerator->getPseudoRandomString(static::CSRF_LENGTH);
$this->persistentDataHandler->set('state', $state);
Session::put('state', $state);
return $this->oAuth2Client->getAuthorizationUrl($redirectUrl, $state, $scope, $params, $separator);
}
and on line 234, I change this script:
protected function validateCsrf()
{
$state = $this->getState();
$savedState = $this->persistentDataHandler->get('state');
if (!$state || !$savedState) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
}
$savedLen = strlen($savedState);
$givenLen = strlen($state);
if ($savedLen !== $givenLen) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($state[$i]) ^ ord($savedState[$i]);
}
if ($result !== 0) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
}
into (I added $this->persistentDataHandler->set('state', Session::get('state'));)
protected function validateCsrf()
{
$state = $this->getState();
$this->persistentDataHandler->set('state', Session::get('state'));
$savedState = $this->persistentDataHandler->get('state');
if (!$state || !$savedState) {
throw new FacebookSDKException('Cross-site request forgery validation failed. Required param "state" missing.');
}
$savedLen = strlen($savedState);
$givenLen = strlen($state);
if ($savedLen !== $givenLen) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
$result = 0;
for ($i = 0; $i < $savedLen; $i++) {
$result |= ord($state[$i]) ^ ord($savedState[$i]);
}
if ($result !== 0) {
throw new FacebookSDKException('Cross-site request forgery validation failed. The "state" param from the URL and session do not match.');
}
}
that is all what I did. and the error gone.
Setting [PersistentDataHandler] explicitly before you get your tokens will guarantee that the request will be a success. Below shows how to fetch $_GET['state'] & simply inject it into the "to be used [helper]" on Symfony 2.x | 3.x
I had the exact same issue as the O.P. and this fixed my problem.
//create your new facebook sdk instance
$this->fb = new Facebook([
'app_id' => $facebookAppId,
'app_secret' =>$facebookAppSecret,
'default_graph_version' =>$facebookDefaultGraphVersion
]);
//retrieve the helper
$this->helper = $this->fb->getRedirectLoginHelper();
//below is the money shot
//setting this explicitly before you get your tokens will guarantee that the request will be a success. It Fetches $_GET['state'] & simply injects it into the "to be used [helper]"
$this->helper->getPersistentDataHandler()->set('state', $request->query->get('state'));
This is a common issue that many people facing in FB Api. this is only a SESSION problem. To solve this issue add some code like.
On callback script usually fb-callback.php add "session_start();" just before you include the facebook autoload file. and then "$_SESSION['FBRLH_state']=$_GET['state'];" after the "$helper = $fb->getRedirectLoginHelper();" line.
Example :
<?php
session_start(); /*Add session start*/
include 'vendor/autoload.php';
include 'config.php'; /*Facebook Config*/
$helper = $fb->getRedirectLoginHelper();
$_SESSION['FBRLH_state']=$_GET['state']; /*Add This*/
try {
$accessToken = $helper->getAccessToken();
} ?>
The real problem here was the encoding of my PHP file. I used UTF8, but it should have been UTF8 w/o BOM.
The side effect of the wrong encoding was that my SESSION was not working properly, and then the SDK wasn't able to retrieve the necessary informations to work properly.
A properly configured error reporting would have told that there was an issue straight way.
I think that we can fill this bug in the "noob" category. But still, I think it can be useful to other noobs like me.
For me the problem is solved now just by starting the session by adding this:
session_start();
at the beginning of both files (the first file generating facebook url and the callback file: login.php and fb-callback.php (https://developers.facebook.com/docs/php/howto/example_facebook_login)).
I also had to add this:
$config['app_id'] = 'myapp_id';
at the top of to prevent another non related error.
As I answered here : Facebook SDK returned an error: Cross-site request forgery validation failed. The "state" param from the URL and session do not match
you need to make sure your native PHP session feature is properly set.
For me this was happening due to 'persistent_data_handler' . By adding this in Facebook config, I was able to make it work.
session_start();
$fb = new Facebook\Facebook([
'app_id' => '6XXXXXXXXX',
'app_secret' => '5XXXXXXXXXXXXXX',
'default_graph_version' => 'v2.6',
'persistent_data_handler' => 'session'
]);
I ran into similar problem and found Nanang Koesharwanto's solution. It's more like quirk as modifying source files in vendor directory is a very bad idea.
So here's the trick.
public function callback(Request $request)
{
$this->helper->getPersistentDataHandler()->set('state', $request->state);
return $this->helper->getAccessToken();
}
If it fails put use Session; in your controller.
I was trying to implement Facebook login in Symfony with Facebook PHP SDK and I had the same error "Cross-site request forgery validation failed. Required param “state” missing".
I solved the problem by adding persistent_data_handler parameter to my facebook app instanciation with a custom handler which implements the PersistentDataInterface of Facebook PHP SDK.
Works like a charm.
public function facebookCallbackAction(Request $request) {
$session = $request->getSession();
$fb = new \Facebook\Facebook([
'app_id' => $this->container->getParameter('facebook_app_id'),
'app_secret' => $this->container->getParameter('facebook_app_secret'),
'default_graph_version' => 'v2.5',
'persistent_data_handler' => new SymfonyPersistentDataHandler($session),
]);
}
My custom handler :
use Facebook\PersistentData\PersistentDataInterface;
use Symfony\Component\HttpFoundation\Session\Session;
class SymfonyPersistentDataHandler implements PersistentDataInterface {
protected $session;
protected $sessionPrefix = 'FBRLH_';
public function __construct(Session $session) {
$this->session = $session;
}
public function get($key) {
return $this->session->get($this->sessionPrefix . $key);
}
public function set($key, $value) {
$this->session->set($this->sessionPrefix . $key, $value);
}
}
Finally, looking into FB code, I discovered that the problem "Cross-site request forgery validation failed. Required param “state” missing" and similars are caused by PHP variable $_SESSION['FBRLH_state'] that for some "strange" reason when FB call the login-callback file.
To solve it I store this variable "FBRLH_state" AFTER the call of function $helper->getLoginUrl(...). Is very important to do only after the call of this function due to is inside this function when the variable $_SESSION['FBRLH_state'] is populated.
Below an example of my code in the login.php:
$uri=$helper->getLoginUrl($uri, $permissions);
foreach ($_SESSION as $k=>$v) {
if(strpos($k, "FBRLH_")!==FALSE) {
if(!setcookie($k, $v)) {
//what??
} else {
$_COOKIE[$k]=$v;
}
}
}
var_dump($_COOKIE);
And in the login-callback.php before calling all FB code:
foreach ($_COOKIE as $k=>$v) {
if(strpos($k, "FBRLH_")!==FALSE) {
$_SESSION[$k]=$v;
}
}
Last, but not least, remember also to include code for PHP session so..
if(!session_id()) {
session_start();
}
...
...
...
...
<?php session_write_close() ?>
I hope this response can help you to save 8-10 hours of work :)
Bye, Alex.
you have to make sure that the session start before the script runs. but again it will throw an 443: Network is unreachable if you start a session again on the same script. hope this helps some one.
I just used
if (session_status() == PHP_SESSION_NONE){ session_start(); }
To those of you of you who use cakephp 3.x and have this problem and you have no clue how to solve it.
Add session_start(); at the beginning of your auth and callback method.
public function Facebookauth()
{
session_start();
$fb = new Facebook([
'app_id' => '{app_id}',
'app_secret' => '{app_secret}',
'default_graph_version' => 'v2.6',
..........
]);
you can still use
$session = $this->request->session();
The fix for me was to change 'secure' => true to false in config/session.php.
I had accidently set this to true while not using https in the first place.
For me the solution was catching the exception by replacing the namespaced Facebook\Exceptions\FacebookSDKException to just Exception, because the script already used it.
use Facebook\Facebook;
// code ...
$fb = new Facebook([
'app_id' => FB_APP_ID,
'app_secret' => FB_APP_SECRET,
'default_graph_version' => 'v2.5',
]);
$helper = $fb->getRedirectLoginHelper();
try {
$accessToken = $helper->getAccessToken();
} catch (Exception $e) {
echo $e->getMessage();
exit;
}
If the session_start() does not still solve the problem, you put a wrong URI in the Valid OAuth Redirect URI of your Facebook developer app.
To solve:
First, go to your fb-callback.php, find the URI you put in the header function, example: header("Location: https://localhost/home.php"). Then go to your Facebook developer apps and then in the sidebar, click Facebook Login which is under the Products tab then click Settings. In the Valid OAuth Redirect URIs, add the URI you put in the header. From my example, I will put https://localhost/home.php.
Hope this helps.
I resolved this error by setting my call back url in the "Facebook -> Login -> Valid OAuth Redirect URIs" in facebook's developer account.
Finally after all this nice errors ,
i fixed all my problems with another solution ,
the example from facebook developer docs are outdated .
SDK V5 and APi 2.4
works like in this tutorial described ,
the access token need to be defined
Be sure you fill APP-IP|APP-SECRET with your credentials .
Example from tutorial :
$fb = new Facebook\Facebook([
'app_id' => 'APP-ID',
'app_secret' => 'APP-SECRET',
'default_graph_version' => 'v2.4',
'default_access_token' => 'APP-ID|APP-SECRET'
]);
Use this and not the example on developer facebook docs .
Have fun :)
Whatever you do. Just don't call getAccessToken() more than once. It removes the state from session as soon as it is called.

Wkhtmltopdf redirect to login page in symfony2

I'm using wkhtmltopdf to generate a pdf report in my application,but when the pdf is generated,i got the login page in the pdf.
this is my Action:
public function exportPdfAction($id = 0)
{
$em = $this->container->get('doctrine')->getEntityManager();
$id = $this->get('request')->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id));
}
if (false === $this->admin->isGranted('VIEW', $object)) {
throw new AccessDeniedException();
}
$pageUrl = $this->generateUrl('admin_rh_leave_conge_show', array('id'=>$id), true); // use absolute path!
return new Response(
$this->get('knp_snappy.pdf')->getOutput($pageUrl),
200,
array(
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="Fiche_conge.pdf"'
)
);
}
how can i resolve the problem ?
this is a bit late, but I had the exact same problem, and found a solution for it:
You can pass in options as second parameter in the getOutput()-method. One of these options is cookie:
use Symfony\Component\HttpFoundation\Response;
...
$session = $this->get('session');
$session->save();
session_write_close();
return new Response(
$this->get('knp_snappy.pdf')->getOutput(
$pageUrl,
array('cookie' => array($session->getName() => $session->getId()))
),
200,
array(
'Content-Type' => 'application/pdf',
)
);
See http://wkhtmltopdf.org/ and https://github.com/KnpLabs/KnpSnappyBundle/issues/42 for details.
I had a similar problem with that bundle. In my case was the issue that the script was running from the command line. And the problem was that there the executed user was not authenticated in the sonata admin.
So be sure your calling the pdf is logged in user and don't switch between production and development environment that will lost the session and you have to relogin.
So check if the script with is calling the snappy pdf generation is correctly authenticated and has the sonata_admin_role (access to the sonata admin backend).
Hope that helps.
2021: I still had the exact same problem but found the accepted solution of Iris Schaffer a little bit dirty. So here is another way. You can just generate the html in the controller you're in.
Instead of using ->getOutput() we use ->getOutputFromHtml()
/**
* #Route("/dossiers/{dossier}/work-order/download", name="download_work_order")
* #Security("is_granted('DOWNLOAD_WORK_ORDER', dossier)")
*
* #param Dossier $dossier
* #return Response
*/
public function generateWorkOrderPdfAction(Dossier $dossier): Response
{
/**
* Since we are a valid logged-in user in this controller we generate everything in advance
* So wkhtmltopdf does not have login issues
*/
$html = $this->forward('PlanningBundle\Controller\WorkOrderController::generateWorkOrderHTMLAction', [
'dossier' => $dossier,
])->getContent();
$options = [
'footer-html' => $this->renderView('#Dossier/PDF/footer.html.twig', [
'dossier' => $dossier,
]),
];
return new Response(
$this->get('knp_snappy.pdf')->getOutputFromHtml($html, $options),
200,
[
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename="work-order-' . $dossier->getName() . '.pdf"',
]
);
}

Error using Slim framework and Twig template

I'm trying to make Slim work with Twig template system, this is part of my index.php
// Twig [Template]
require 'Extras/Views/Twig.php';
TwigView::$twigDirectory = __DIR__ . '/vendor/Twig/lib/Twig/';
//Slim
require 'Slim/Slim.php';
\Slim\Slim::registerAutoloader();
$app = new \Slim\Slim(array(
'view' => $twigView
));
And this is my structure
Extras
|_Views
|_Twig.php
Slim
templates
vendor
|_Twig
|_lib
|_Twig
index.php
I try several times with other configurations and searching buy I ALLWAYS get this error:
Fatal error: Class 'Slim\View' not found in C:\wamp\www\slim\Extras\Views\Twig.php on line 43
Can anyone help me here? All the examples I had found was using composer
Ok, I solve it.
This is the solution:
// Slim PHP
require "Slim/Slim.php";
\Slim\Slim::registerAutoloader();
// Twig
require "Twig/lib/Twig/Autoloader.php";
Twig_Autoloader::register();
// Start Slim.
/** #var $app Slim */
$app = new \Slim\Slim(array(
"view" => new \Slim\Extras\Views\Twig()
));
And this is my structure now.
Slim
|_Extras
|_Views
|_Twig.php
|_Slim
templates
Twig
|_lib
|_Twig
|_Autoloader.php
index.php
¡I hope this help someone else!
Now Slim-Extras is DEPRECATED, we must use Slim-Views (https://github.com/codeguy/Slim-Views):
require "Slim/Slim.php";
\Slim\Slim::registerAutoloader();
$slim = new \Slim\Slim( array(
'debug' => false,
'templates.path' => 'fooDirTemplates',
'view' => '\Slim\Views\Twig'
));
$twigView = $slim->view();
$twigView->parserOptions = array(
'debug' => false
);
$twigView->parserDirectory = 'Twig';
$twigView->parserExtensions = array(
'\Slim\Views\TwigExtension'
);
$slim->notFound( 'fooNotFoundFunction' );
$slim->error( 'fooErrorFunction' );
// SLIM routes...
$slim->run();
If someone is still running in to this issue.
The problem for me was that I had installed both slim/views AND slim/twig-view.
I uninstalled slim/views and it worked

Categories