I am trying to change the approach of rendering templates. I was using a server-side template engine. Now that I need to return only JSON from backend instead of HTML, I need to move my templating to front-end.
The problem for me as a newbie, is when the template contains a form. In other words, when the final JSON should also contain a csrf token. Please to take the example of CRUD application for books (one entity Book(id_book, name)). The template for Reading a record shows the book name and allow deletion of a book.
In Symfony2 controller, I use createFormBuilder() method that creates the delete form object, to which I apply createView()method. The object returned by the latter is used by form_widget()in the template engine (Twig). At the end:
<div id="bookName">{{book.name}}</div>
<div id="bookDelete">
<form action="{{ path('book_delete', { 'id': book.id }) }}" method="post">
<input type="hidden" name="_method" value="DELETE" />
{{ form_widget(delete_form) }}
<button type="submit"></button>
</form>
</div>
Which will return:
<div id="bookName">Symfony2 In Depth</div>
<div id="bookDelete">
<form action="/web/app_dev.php/deletes" method="post">
<input type="hidden" name="_method" value="DELETE">
<div id="form">
<input type="hidden" id="form_id" name="form[id]" value="15">
<input type="hidden" id="form__token" name="form[_token]" value="dd6573ae916ae30f78ba35a8c67e5d42a2764c1c">
</div>
<button type="submit"></button>
</form>
What I imagine when moving template rendering to front-end is a final JSON from server looking like:
{
'id':15,
'name': 'Symfony2 in Depth',
'csrf_token' : 'dd6573ae916ae30f78ba35a8c67e5d42a2764c1c'
}
Question is how to implement the same Symfony2 internal mechanism to render csrf token for DELETE form, as part of the final JSON to read a book entity? Is it acceptable to get rid of {{ form_widget(delete_form) }} and all its long objects, and only serialize csrf token with book name? What does this will affect? I feel it is good for performance but how?
Your usual guidance is much appreciated.
You can create you twig file something like:
{
'id': '{{ form.id.vars.value }}'
'name': '{{ form.name.vars.value }}'
'csrf_token': '{{ form._token.vars.value }}'
}
Anyway I dont recommend you use csrf token when you are using API, it is better if you disabled. If you want to disable for all application in the config.yml:
framework:
csrf_protection:
enabled: false
Or just for one form in the Type form add:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'csrf_protection' => false,
));
}
Related
I'm in the process of making a Bootstrap 4 styled payment form for my app, wherein radio buttons select the payment method. In attempting to make my form via Symfony's form classes, I've found them to be too restrictive/clumsy to do what I want. I DO NOT want to mess around with Symfony form theming (I find it annoyingly verbose), I DO NOT want to use Symfony's pre-made Bootstrap theme, and I DO NOT want to use any createFormBuilder anything.
So, is there a way for me to make a plain old HTML form, but with Symfony's CSRF token? This answer seems promising, but doesn't mention CSRF protection.
According to this documentation How to Implement CSRF Protection ,
an attempt of solution is to use something like (in symfony 3.4 and 4) :
in your controller, you can have something like :
/**
* #Route("/names", methods={"POST"}, name="app_post_names")
*/
public function postName(Request $request)
{
$name = $request->request->get('name');
$csrfToken = $request->request->get('_csrf_token');
if(!$this->isCsrfTokenValid('token_id', $csrfToken)) {
// ... throw bad request
}
// ... Do other thing
}
Now in your template you can have something like (with your own design) :
<form action="{{ path('app_post_names') }}" method="post">
Name : <input name="name" type="text" />
<input name="_csrf_token" value="{{ csrf_token('token_id') }}" type="hidden" />
<input type="submit" value="send" />
</form>
Don't use Symfony at all, and generate your own token?
You don't really need to use Symfony form theming when making a form. Myself, I always build my own form tags.
You want to customise your select? Can be done too
You want to use fields which aren't in an entity, can be done as well...
Symfony forms aren't as restrictive as you think.
You most likely don't have the "know how" about this matter.
Controller
public function customFormAction(Request $request) {
$form=$this->createFormBuilder()
->setAction($this->generateUrl('route_name'))
->setMethod('POST')
->add("customField", ChoiceType::class, array(
'choices'=>array(
'1'=>'Choice 1',
'2'=>'Choice 2',
'3'=>'Choice 2',
),
'required'=>true,
'mapped'=>false, //Isn't mapped to any entity
))
->getForm();
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$customField=$form->get('customField')->getData();
//do your stuff
}
return $this->render('route_name', array(
'form'=>$form->createView(),
));
}
Twig view
<form action="{{ form.vars.action }}" method="{{ form.vars.method }}">
<div class="input-field">
<select id="{{ form.customField.vars.id }}" name="{{ form.customField.vars.full_name }}" class="my_classes">
{% for option in form.customField.vars.choices %}
<option data-attr="my_attributes" value="{{ option.value }}">{{ option.label }}</option>
{% endfor %}
</select>
</div>
<input name="{{ form._token.vars.full_name }}" value="{{ form._token.vars.value }}" type="hidden">
</form>
With this, I'm barely using any twig templating, I still have a CSRF token and Symfony barely handle the form (it will only check CSRF token)
I am learning Routing in Laravel 5.4 by viewing a tutorial created by DevDojo. Using the following codes in routes/web.php will emerge the TokenMismatchException error and my code does not work after I press the submit button:
Route::post('test', function () {
return 'Printed by the route responsible for test post action.';
});
Route::get('test', function () {
echo '<form method="post" action="test">';
echo '<input type="submit">';
echo '</form>';
});
I searched this same forum here and also the other places on the net like laravel.io or laracasts.com and everyone is talking about problems that occur when Laravel tries to detect the session of the request that is getting made.
I tried to fix the problem by adding the following lines to the Route::get rules but the issue does not get fixed:
echo '<input type="hidden" name="_method" value="post">';
echo '<input type="hidden" name="_token" value="csrf_field();">';
I hope you help me fix it by telling me how to properly use csrf_field(), csrf_token() or anything else needed here in the route file.
Thank you very much in advance.
csrf_token() just gives you the token.
csrf_field() builds the entire input field for you.
example:
{{ csrf_token() }} // Outputs: SomeRandomString
{{ csrf_field() }} // Outputs: <input type="hidden" name="_token" value="SomeRandomString">
in your question:
use
<input type="hidden" name="_token" value="csrf_token();">;
instead of
<input type="hidden" name="_token" value="csrf_field();">;
on the other hand
you could use
echo csrf_field();
OR
{{ csrf_field() }}
I think you're on the right track with the hidden inputs (if you've got a fresh Laravel install, otherwise make sure checking the token isn't disabled);
I recommend you use the (official) Form Builder for Laravel to handle forms (have a look here).
Afterwards, have a look here:
(1)
{{ Form::open(array('url' => 'profile')) }}
your form stuff goes here
{{ Form::close() }}
(2) Make sure to have this to output the token: echo Form::token(); (before you close the form)
(3) And finally, have a POST Route registered, that checks the token:
Route::post('profile', array('before' => 'csrf', function()
{
//
}));
Alternatively, you can specify form action directly to the function (my personal favorite):
echo Form::open(array('action' => 'Controller#method'))
I want to pass an input value from one blade file to another blade file.
I'm new to PHP Laravel, and I'm getting an error when attempting to use it.
I think my syntax is wrong here. Can somebody help?
channeling.blade:
<select class="form-control " name="fee" id ="fee"></select>
This is the link to the next page, where i want to send the value of "fee":
<input type="hidden" value="fee" name="fee" />
Click to Channel</p>
This is my web.php:
Route::post('pay', [
'as' => 'fee',
'uses' => 'channelController#displayForm'
]);
This my controller class:
public function displayForm()
{
$input = Input::get();
$fee = $input['fee'];
return view('pay', ['fee' => $fee]);
}
Error message:
Undefined variable: fee
(View: C:\xampp\htdocs\lara_test\resources\views\pay.blade.php)
pay.blade:
<h4>Your Channeling Fee Rs:"{{$fee}}"</h4>
You should use form to send post request, since a href will send get. So, remove the link and use form. If you use Laravel Collective, you can do this:
{!! Form::open(['url' => 'pay']) !!}
{!! Form::hidden('fee', 'fee') !!}
{!! Form::submit() !!}
{!! Form::close() !!}
You can value inside a controller or a view with request()->fee.
Or you can do this:
public function displayForm(Request $request)
{
return view('pay', ['fee' => $request->fee]);
}
I think you can try this, You mistaken url('pay ') with blank:
change your code:
Click to Channel</p>
to
Click to Channel</p>
Further your question require more correction so I think you need to review it first.
You can review about how to build a form with laravel 5.3. Hope this helps you.
You have to use form to post data and then you have to submit the form on click event
<form id="form" action="{{ url('pay') }}" method="POST" style="display: none;">
{{ csrf_field() }}
<input type="hidden" value="fee" name="fee" />
</form>
On the click event of <a>
<a href="{{ url('/pay') }}" onclick="event.preventDefault();
document.getElementById('form').submit();">
Logout
</a>
tl;dr: I believe #AlexeyMezenin's answer is the best help, so far.
Your current issues:
If you have decided to use Click to Channel, you should use Route::get(...). Use Route::post(...) for requests submitted by Forms.
There isn't an Input instance created. Input::get() needs a Form request to exist. Thus, the $fee an Undefined variable error message.
The value of <input type="hidden" value="fee" name="fee"/> is always going to be the string "fee". (Unless there's some magical spell casted by some JavaScript code).
The laravel docs suggest that you type-hint the Request class when accessing HTTP requests, so that the incoming request is automatically injected into your controller method. Now you can $request->fee. Awesome, right?
The way forward:
The BasicTaskList Laravel 5.2 tutorial kick-started my Laravel journey.
I changed the code like this and it worked..
echanneling.blade
<input type="hidden" value="fee" name="fee" />
<button type="submit" class="btn btn-submit">Submit</button>
channelController.php
public function about(Request $request)
{
$input = Input::get();
$fee = $input['fee'];
return view('pay')->with('fee',$fee);
}
Web.php
Route::post('/pay', 'channelController#about' );
I am setting up a simple form in laravel:
This is the route file:
Route::get('backoffice/upload', [ 'as' => 'backoffice/upload',
'uses' => 'UploadController#uploadForm']);
Route::post('backoffice/saveimage',[ 'as' => 'backoffice/saveimage',
'uses' => 'UploadController#saveImage']);
This is the controller:
class UploadController extends \BaseController
{
public function uploadForm()
{
return View::make("backoffice.upload.create");
}
public function saveImage()
{
return "Uploading...";
}
}
And this is the View file:
<h1>Upload Image</h1>
{{ Form::open(['action' => 'UploadController#saveImage']) }}
<div class='formfield'>
{{ Form::label('newfilename','New File Name (optional):') }}
{{ Form::input('text','newfilename') }}
{{ $errors->first('newfilename') }}
</div>
<div class='formfield'>
{{ Form::submit($action,['class'=>'button']) }}
{{ Form::btnLink('Cancel',URL::previous(),['class'=>'button']) }}
</div>
{{ Form::close() }}
// Generated HTML
<h1>Upload Image</h1>
<form method="POST" action="http://my.local/backoffice/saveimage" accept-charset="UTF-8"><input name="_token" type="hidden" value="x9g4SW2R7t9kia2B8HRJTm1jbLRl3BB8sPMwvgAM">
<div class='formfield'>
<label for="newfilename">New File Name (optional):</label>
<input name="newfilename" type="text" id="newfilename">
</div>
<div class='formfield'>
<input class="button" type="submit" value="Create">
</div>
</form>
So, if I go to: http://my.local/backoffice/upload I get the form with the HTML above.
However, if I type anything, then click SUBMIT, I return to the form but now have the following URL:
http://my.local/backoffice/upload?pz_session=x9g4SW2R7t9kia2B8HRJTm1jbLRl3BB8sPMwvgAM&_token=x9g4SW2R7t9kia2B8HRJTm1jbLRl3BB8sPMwvgAM&newfilename=ddd
This makes no sense to me. Up until now I have always used route::resource when dealing with forms, and had no problem. I am trying to do a simple form with GET and POST and am having no end of grief. What am I missing?
Furthermore, if I modify routes.php and change it from post to any, then open a browser window and type: http://my.local/backoffice/saveimage then I get the message "Uploading..." so that part is working ok.
Found the solution. In making the backoffice of the system, I had re-used the frontoffice template but removed all the excess. Or so I had thought. However, the front office header template had a form which I had only partially deleted.
So the problem was that there was an opening FORM tag I didn't know about. Consequently, when I clicked on submit to my form, it was actually submitting to this other form.
As the other form had no action it was default to itself.
Of course, had I just validated the HTML this would have shown up straight away. The lesson learned here is to validate my html before submitting questions!
Try this, and be sure to correctly configure your url at app/config/app.php
{{Form::open(['url'=>'backoffice/saveimage'])}}
//code
{{Form::close()}}
I know there's the usual way to render CSRF token hidden input with form_rest, but is there a way to render just CSRF input itself? I've overridden {% block field_widget %} in theme to render a piece of additional text. But as CSRF token is rendered in input field too and I got a piece of text I don't need next to a hidden field. So I'd like to render it separately with an argument that tells it not to render this text.
you can do it with {{ form_widget(formView._token) }}
If you have formView object, you can render it using Twig function:
{{ form_widget(formView._token) }}
If you haven't - you can render token without using form object directly:
<input type="hidden" name="token" value="{{ csrf_token('some-name') }}">
Works in Symfony 2.x and 3.x
To validate the token you can use the following code in your controller (Symfony 3.x):
$submittedToken = $request->request->get('token');
if ($this->isCsrfTokenValid('some-name', $submittedToken)) {
// ... do something,
}
Or you can just simply use this :
{{ form_row(form._token) }}
This will automatically generate the proper hidden HTML elements, ie the proper HTML structure and field names, according to the type of form you're using.
I needed to render the csrf input inside Twig so that I could use it for Delete operations.
Using {{ csrf_token('authenticate') }} as per #YuryPliashkou's answer gives me the incorrect token (one which is only valid for logins!)
What worked for me was this {{ csrf_token('form') }} which gives me the correct csrf token which I would then pass to my controller via ajax.
<span id="csrf_token" data-token="{{ csrf_token('form') }}"></span>
// my ajax call
$.ajax({
url: localhost/admin/product/4545, // 4545->id of the item to be deleted
type: 'POST',
data: {
"_method": "DELETE",
"form[_token]": $("#csrf_token").data("token") // passed csrf token here
},
success: function(result) {
// Do something
}
});
Verified its working on Symfony 3.x.
Reference
didn't find solution worked for me, finded and tested and worked for my Simfony3 value="{{ _token }}" in example
<form name="form" method="post" action="{{ path('blog_show', { 'id': blog.id }) }}">
<input name="_method" value="DELETE" type="hidden">
<input class="btn btn-danger" value="Delete" type="submit">
<input id="form__token" name="form[_token]" value="{{ _token }}" type="hidden">
</form>
more about scrf can be viewed here: Creating forms manually in Symfony2, but still use its CSRF and isValid() functionalily