Symfony2 invalid token with big files - symfony

I'm having problem with token and file field form.
The validation of the form is like this:
public function getDefaultOptions(array $options)
{
$collectionConstraint = new Collection(array(
'fields' => array(
'file' => new File(
array(
'maxSize' => '2M',
'mimeTypes' => array(
'application/pdf', 'application/x-pdf',
'image/png', 'image/jpg', 'image/jpeg', 'image/gif',
),
)
),
)
));
return array(
'validation_constraint' => $collectionConstraint
}
When I upload a invalid size file(~5MB) I get this error which is what I hope:
The file is too large. Allowed maximum size is 2M bytes
But when I upload a too big file(~30MB) the error changes:
The CSRF token is invalid. Please try to resubmit the form
The uploaded file was too large. Please try to upload a smaller file
The problem is the error token. I've in my form the {{ form_rest(form) }} code. I think the error change is because of this: How to increase the upload limit for files on a Symfony 2 form?
I don't want to increase the upload limit. I want the token error doesn't show.

PHP (not Symfony) rejects the file if it is bigger than your configured values in:
post_max_size
upload_max_filesize
Because of this the csrf-error is thrown.
If you want to avoid this you have to increase the upload limit. It is the only way. If you add your file-constraint this should be no risk.

PROBLEM
CSRF token invalid & upload file too large errors
This two errors are form generated errors, and besides the field errors, they will appear when any exception occurs inside the form.
In this case of uploading files CSRF token invalid error appears due to post_max_size parameter in php.ini configuration file and
upload file too large error appears due to upload_max_filesize parameter in php.ini configuration file.
SOLUTION:
1- You can increase the value in the configuration files.
2- You can have field validation and comment or omit the line of form_errors inside your template.html.twig, notice that this solution will remove all kind of form generated errors notifications.
Example of template.html.twig:
<div class="form">
{{ form_start(form) }}
{{ form_errors(form) }} --> before
{# {{ form_errors(form) }} #} --> after
<div class="field">
{{ form_label(form.field) }}
{{ form_errors(form.field) }}
{{ form_widget(form.field) }}
</div>
{{ form_end(form) }}
</div>

In your Entity.php you need to specify the "maxSize" property to your Assert file.
For the exemple, the value "2147483648" equals 2GB.
/**
* #ORM\Column(type="string", length=255)
*/
public $path;
/**
* #Assert\File(maxSize="2147483648")
*/
public $file;

Related

Silex, how to translate login error messages?

How to translate security error messages like 'Bad credentials' in Silex?
Currently I show login form using this code from Silex docs https://silex.symfony.com/doc/2.0/providers/security.html:
$app->get('/login', function(Request $request) use ($app) {
return $app['twig']->render('login.twig', array(
'error' => $app['security.last_error']($request),
'last_username' => $app['session']->get('_security.last_username'),
));
});
twig:
{{ error }}
But looks like $app['security.last_error'] is just a string, so I can't get its key for translation like this {{ error.messageKey|trans(error.messageData, 'security') }}.
This http://symfony.com/doc/2.8/security/form_login_setup.html suggests to use $this->get('security.authentication_utils')->getLastAuthenticationError() but looks like it's not available in Silex?
It's not ideal, but I am simply using Bad credentials as a key in my array with translations.

How can I unmap a File input without using the form builder?

I have inherited an application that seems to have existed before the form builder existed. The developer kind of rolled his own with twig macros. Now I want to add a file upload to some existing forms, but I get what seems to be a well known error:
There was 1 error:
myBundle\Tests\Controller\snip\DefaultControllerUnitTest::testCanStoreDocumentAtS3
Exception: Serialization of
'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
C:\apath\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\DataCollector\DataCollector.php:27
C:\apath\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\Profiler\Profiler.php:218
The solutions is to unmap the file field:
$builder->add('pic','file');
to this :
$builder->add('pic','file', array('mapped'=>false));
But in this case a builder is not used. Instead it looks like this:
{# file(name, value) #}
{% macro file(name, value) %}
<input type="file" name="{{ name }}" id="{{ name }}" value="{{ value }}" />
{% endmacro %}
Is there anything I can add to this macro, or do in the controller action to keep the Profiler from serializing this?
The answer was in part pilot error, but there is enough going on here that I hope I can help others avoid the same pitfall.
This error was triggered by a unit test where I was simulating a file upload along with other parameters. Initially the code that caused this error was:
$photo = new UploadedFile(
__DIR__ . '/TestReportMethod.xlsx',
'TestReportMethod.xlsx',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
123
);
....
$form['reportFile'] = $photo;
//submit
This caused the error in my original post.
After trying a few things I moved to this form instead.
$crawler = $this->client->request('POST',
$url,
array('id' => 328),
array('agencyInfoId' => 328),
array('reportFile' => $photo)
);
Which causes an InvalidArgumentException I think a little better example in the cookbook could have prevented. The correct form needs to be an array of parameter values, followed by an array of files:
$crawler = $this->client->request('POST',
$url,
array('id' => 328,
'agencyInfoId' => 328),
array('reportFile' => $photo)
);
I hope this helps somebody else!

symfony trying to export a csv file from a link

I have this function in the controller, that returns a form with a select box. When the values are selected, I retrieve them with
$manifestations = $form['manifestations']->getData();
then put them in a repository function that queries the database $invites = $repository->searchInviteByManif($manifestations);
public function indexAction() {
$entity = new Invite();
$form = $this->createForm(new ManifSearchType(), $entity);
$request = $this->get('request');
$invites = null;
if ($request->getMethod() == 'POST') {
$form->handleRequest($request);
$message = '';
$manifestations = $form['manifestations']->getData();
$repository = $this->getDoctrine()
->getManager()
->getRepository('PrifProtocoleBundle:Invite');
$invites = $repository->searchInviteByManif($manifestations);
$response1 = $this->render('PrifProtocoleBundle:Invite:index.html.twig', array(
'form' => $form->createView(),
'entities' => $invites,
'message' => $message,
));
return $response1;
}
return array(
'form' => $form->createView(),
'entities' => $invites,
);
}
This function then returns a view index.html.twig with a table and all the fields found in the db.
What I want is to export all the queried data $invites in a CSV file, by clicking on a link directly from the HTML table.
So I've put an href="" link in the Twig file,
{% if message is defined %}
<div class="pdf">
<img height="40px" width="40px" src={{ asset('bundles/prifprotocole/images/excel.jpg') }}>
{% for entity in entities %}
<tr class="{{ cycle(['odd', 'even'], loop.index0) }}">
<td>{% if entity.etat == 1 %} Actif {% else %} Inactif {% endif %}</td>
<td>{{ entity.titreGrade }} {{ entity.prenom }} {{ entity.nom }}</td>
<td>{{ entity.fonction }}</td>
This is how I use to export the CSV file without the link :
$response2 = $this->render('PrifProtocoleBundle:Invite:export.csv.twig', array(
'entities' => $invites));
$response2->headers->set('Content-Type', 'text/csv');
$csvfile = $response2->headers->set('Content-Disposition', 'attachment; filename="export.csv"');
return $csvfile;
export.csv.twig file
{% for entity in entities %}
Id {{ entity.id }};
Etat {{ entity.etat }};
Titregrade {{ entity.titreGrade }};
Prenom {{ entity.prenom }};
Nom {{ entity.nom }};
Fonction {{ entity.fonction }};
{% endfor %}
Can someone give me a detailed solution on how to perform this? Much thanks!
You should simply pass the filter criterias, here the $manifestations array as a route parameter, by serializing it first.
Then, you should put a controller like downloadCsvAction() handling this route, querying the $invites from the database, and rendering your export.csv.twig template.
Another option, if you cannot serialize the data in URI, is to create a form with hidden fields containing the data. Then you replace the download link with the submit button of this hidden form.
Guillaume's answer is great if you don't mind fetching your data twice. Once when you display your page, and then when you download the CSV. Another way to do this is to cache the answer. I will give an example using memcache (which is what I use).
First, make sure that memcache is active in your php.ini.
Then before rendering your first page (after fetching the data), cache it:
$key = "csv.$userId";
$memcache = new \Memcache();
$memcache->connect($yourServerHost, $yourServerPort);
$memcache->set($key, json_encode($invites), MEMCACHE_COMPRESSED, 86400); // 24h
The trick is to find a good key, to add your report to the cache, and then be able to retrieve it. It has to be unique. Here, I assume that you have a user that is logged in, and I use the user ID to create a key. If that is not the case, you could create yourself a token, and pass it when rendering the page (along with $invites). This way, you can add the token to the URL to generate the CSV.
Then, in your second action, where you download the CSV, you just fetch the cached data:
$memcache = new \Memcache();
$memcache->connect($yourServerHost, $yourServerPort);
$json = $memcache->get($key);
$invites = json_decode($json , true);
That's it. You should probably create yourself a service for Memcache, so you don't have to create an object, and connect everytime.

Symfony2 : How to upload a file without Doctrine?

I use Symfony2.3. I have a form like this :
<form action="{{ path("member_update") }}" method="post" {{ form_enctype(form) }}>
{{ form_widget(form.pic) }}
...
{{ form_widget(form._token) }}
</form>
and i want to upload user pictures in a directory.Then i use this in controller :
$member , $form , $dm is defined...
if ($form->isValid()) {
// Handle profile picture upload process
$uploadDir=dirname($this->container->getParameter('kernel.root_dir')) . '/web/bundles/mybundle/myfiles';
$form['pic']->getData()->move($uploadDir,$member->getId());
// End of upload
$dm->persist($member);
$dm->flush();
return $this->redirect($this->generateUrl("member_profile"));
}
It must work,but i see this error:
Exception: Serialization of 'Symfony\Component\HttpFoundation\File\UploadedFile' is not allowed
1. in pathToMyProject...\vendor\symfony\symfony\src\Symfony\Component\HttpKernel\DataCollector\DataCollector.php line 27
2. at serialize(.....
What's the problem??!
The problem solved! I change this line in MemberType :
$builder->add('pic','file');
to this :
$builder->add('pic','file', array('mapped'=>false));
My mistake was that i must explain the "pic" field is not mapped to the Entity(or Document in Mongo,as my project). Else Symfony kernel try to put the value of "pic" in a field of Entity. And i have not any field that hold a file! I upload the picture in a directory and store only path to the picture within the entity. When i changed this,the problem solved easily! :-)
So keep in mind to explain all things clearly to Symfony!

Symfony2: How use 'ckeditor' in a form?

I installed TRsteelCkeditorBundle, when I'm building in the view a form manually, it works.
<form method="post">
<p>
My Editor:<br>
<textarea name="editor1"><p>Initial value.</p></textarea>
<script>
CKEDITOR.replace( 'editor1' );
</script>
</p>
<p>
<input type="submit">
</p>
</form>
But when I try to use the Symfony2 form I get this error :
An exception has been thrown during the rendering of a template
("Route "route_name" does not exist.") in
lbTestBundle:Default:index.html.twig at line 8
My codes :
In the Twig template
{{ form_widget(form) }}
Ligne 8 is the form_widget
In the controller:
public function indexAction()
{
$formBuilder = $this->createFormBuilder();
$formBuilder
->add('date', 'date')
->add('title', 'text')
->add('content', 'ckeditor')
->add('author', 'text');
$form = $formBuilder->getForm();
$view['form'] = $form -> CreateView();
return $this->render('lbTestBundle:Default:index.html.twig', $view);
}
I followed step by step the indications of the Read_me.txt in he github page, and try to find answers elsewhere but found nothing. If someone can help me to solve that problem, i'm still beginner with SF2. Thanks
What is at lbTestBundle:Default:index.html.twig at line 8?
Obviously you have a route route_name in you template which is not defined in you routing.yml file.
That's all the error message says.
Same problem here. Spend all day today researching.
Finally, fixed it by replacing the TRsteelCkeditor bundle with the IvoryCKEditor bundle.
I found where the error comes from.
the route_name comes from
#config.yml for TrsteelCkeditor
filebrowser_image_browse_url:
route: route_name
route_parameters:
type: image
I suppose I have to put the route where the editor goes when you want to upload images in the editor.
I'll continue to test this budle till I got something fine and I'll give the result
Adding in comment the line
#route: route_name
In the config.yml solve the problem, this line is for uploading images on the server I think, see this link :
http://docs.cksource.com/CKEditor_3.x/Developers_Guide/File_Browser_(Uploader)
But now I am having some issues with language, I want to put it in French, at the moment the skin seems language dependent just like the hover on the buttons.
Also if you want to configure it, you can do it either in the config.yml or the config.js in /web/bundle repository if you already install the assets.

Resources