Laravel form without Collective - php

I'm learning Laravel. The current stable version is, as far as I'm aware, 5.8. I'm following tutorials and really liking the framework, but it gets a bit troublesome when these tutorials get to the point where they introduce how forms are incorporated. All of those tutorials use LaravelCollective forms, which is no longer working as of 5.8 and it is an abandoned project so I'd prefer not to use it anyway.
But this leaves me confused as to what the best practices are for using forms with Laravel. I've had some goes at creating forms, but... most of it is just HTML with hardly any Laravel "in there", if that makes sense. The only Laravel bit here is the form action, where it points to the store function in the TodosController. See below, for a file called create.blade.php.
#extends('layouts.app')
#section('content')
<h1>Create Todo</h1>
<form action="{{action('TodosController#store')}}" method="post">
#csrf
<div class="form-group">
<label for="text">Text</label>
<input type="text" name="text" class="form-control" placeholder="Enter title"/>
</div>
<div class="form-group">
<label for="body">Body</label>
<textarea class="form-control" name="body" id="body" rows="10" placeholder="Enter details"></textarea>
</div>
<div class="form-group">
<label for="due">Due date</label>
<input type="text" name="due" class="form-control" placeholder="Enter due date"/>
</div>
<input type="submit" value="Submit" class="btn btn-primary">
</form>
#endsection
This works fine, but I just feel like I'm not utilising blade properly here at all. Any pointers would be greatly appreciated.

Actually, you're using more laravel there than just the form action. The #csrf stands for Cross-site request forgery and it's the laravel way to protect you against that, as said in the docs:
Laravel automatically generates a CSRF "token" for each active user session managed by the application. This token is used to verify that the authenticated user is the one actually making the requests to the application.
Anytime you define a HTML form in your application, you should include a hidden CSRF token field in the form so that the CSRF protection middleware can validate the request. You may use the #csrf Blade directive to generate the token field:
When you have a PUT, PATCH OR DELETE form you should use the blade directive #method to inform wich action laravel should use:
HTML forms do not support PUT, PATCH or DELETE actions. So, when defining PUT, PATCH or DELETE routes that are called from an HTML form, you will need to add a hidden _method field to the form. The value sent with the _method field will be used as the HTTP request method:
You can achieve that, simply using:
<form action="/foo/bar" method="POST">
#method('PUT')
#csrf
</form>
Besides that, i think you're using laravel/blade just fine. Make sure you read the docs for more info.
Good luck!

What you have is a good point to start from, however another good place to take a look at is the boilerplate registration form (this is not from the official Laravel project page because the boilerplates are optionally introduced and are not in the official repo by default).
There are a few improvements you can do based on this:
<div class="form-group">
<label for="text">{{__('Text')}}</label>
<input type="text" name="text" class="form-control{{ $errors->has('text') ? ' is-invalid' : '' }}" value="{{ old('text') }}"placeholder="Enter title"/>
</div>
The extras:
__('Text') will automatically translate Text based on the selected locale and available language assets.
{{ $errors->has('text') ? ' is-invalid' : '' }} will "decorate" the field with the bootstrap-4 error style if serverside validation failed (and therefore passed the $errors variable to the view)
{{ old('text') }} will pre-fill the input with the value that was previously filled in case the form failed validation and the user was redirected back to the same page.
This will help improve the user experience, however keep in mind these are all server-side tools (because Laravel is a server-side framework) so it's probably a better user experience to also add client-side checks and validation.

Related

How to get data passed from PUT method

I am creating an API for Laravel. I use the PUT method for updating data.
I send data with Postman using the PUT method. In my controller, I got an empty array. How to access the passed data?
In my route, I have:
Route::put('vehicletypes/{id}','API\VehicletypeController#update');
In my controller:
public function update(Request $request, $id){
print_r($request->all()); exit;
}
How to get the data passed in PUT method?
You are getting empty response because PHP have some security restrictions against PUT. But Laravel have a workaround for this.
So, to solve this you have to send a POST request from Postman instead, with a POST param _method with value PUT. And that should work.
Laravel cheats because html forms only support GET and POST, but it does understand a real PUT/PATCH request.
The problem looks like lies in Symfony it can't parse the data if it's multipart/form-data, as an alternative try using x-www-form-urlencoded content disposition.
public function putUpdate(Request $request, $id){
print_r($request->all()); exit;
}
And change route too,
Route::put('vehicletypes/{id}','API\VehicletypeController#putUpdate');
Checked "x-www-form-urlencoded" instead of "form-data" under body tab in the Postman, the put methood will work as well...
Why nobody is giving clear explanation
at first put method field of
{{method_field('put')}}
as your router uri is that is displayed using command
php artisan router:list
of update method is put/patch so first add
{{method_field('put')}}
and field in your form should be the same
<form action="{{route('posts.update',$post->id)}}" method="post">
after adding the csrf_toke form will be working. and final shape would be as below of form.
<form action="{{route('posts.update',$post->id)}}" method="post" >
{{method_field('put')}}
<input type="hidden" name="_token" value="{{csrf_token()}}">
<!-- Name input-->
<div class="form-group">
<label class="col-md-3 control-label" for="name">Title</label>
<div class="col-md-9">
<input id="name" name="title" type="text" value="{{$post->title}}" class="form-control">
</div>
</div>
<!-- Message body -->
<div class="form-group">
<label class="col-md-3 control-label" for="body">
Body</label><br>
<div class="col-md-9">
<textarea class="form-control" id="message" name="body" rows="5">
{{$post->body}}
</textarea>
</div>
</div>
<!-- Form actions -->
<div class="form-group">
<div class="col-md-9 text-right col-md-offset-3">
<button type="submit" class="btn btn-success btn-lg">Update</button>
Cancel
</div>
</div>
</form>
Following link will resolve the issue to get the request form data plus the images.
If you are working on Laravel, you can easily parse and bind the form params in the \Illuminate\Http\Request Instance
Simply just get the ParseInputStream Class from the link below:
Class ParseInputStream.php
Create another Validation Rule Class in Laravel optional but not required,
class NoteUpdateRequest extends Request {
public function all($keys = null)
{
if(strtolower($this->getMethod())=='put' && preg_match('/multipart\/form-data/', $this->headers->get('Content-Type')) or
preg_match('/multipart\/form-data/', $this->headers->get('content-type')))
{
$result = [];
new ParseInputStream($result);
$result = array_merge($result, $this->route()->parameters());
$this->request->add($result);
}
return parent::all($keys);
}
public function rules()
{
dd($this->all());
return [
'noteId' => 'required|integer|exists:notes,id',
'title' => 'required|string|max:200',
'note' => 'required|string|min:10|max:2000'
];
}
}
I hope it resolved what you want to achieve, using PUT or PATCH method along with Form Params
As mentioned, this isn't a laravel (or symfony, or any other framework) issue, it's a limitation of PHP.
That said, I managed to find this PECL extension. I'm not very familiar with pecl, and couldn't seem to get it working using pear. but I'm using CentOS and Remi PHP which has a yum package.
I believe there are other packages in various flavours of linux and I'm sure anybody with more knowledge of pear/pecl/general php extensions could get it running on windows or mac with no issue.
I ran yum install php-pecl-apfd and it literally fixed the issue straight away (well I had to restart my docker containers but that was a given).
That is, request->all() and files->get() started working again with PATCH and PUT requests using multipart/form-data.
Ergo, I managed to get my api playing nicely with my front-end without adding any quirks (that would need to be relayed to anybody developing front-end solutions) or breaking RESTful conventions.

Acunetix scan of Laravel login page

I have an application written using Laravel 5.1 framework. Recently, one of my clients ran an Acunetix security scan on the application and found HTML form with no apparent CSRF protection on my login page.
However, the login form DOES have CSRF protection. The name of the element with the CSRF token is "_token". The scan result says "Discovered by: Crawler".
So my questions are:
Why is acunetix showing this result?
Is "_token" not a recognized name for a CSRF token element? Should I add another hidden element into the form with the same value using a more recognizable name?
What does it mean "Discovered by: Crawler"? Does this mean the scan only checks the form HTML and nothing else?
Below is the snippet of the HTML form blade template:
#section('content')
<form id="loginForm" class="form-signin" role="form" method="POST" action="{{ url('/auth/login') }}">
<h2 class="form-signin-heading"><img src="/images/J10_Logo_330x194.jpg" alt="{{ trans('content.image_alt.j10_logo') }}"></h2>
<input type="hidden" name="_token" value="">
<label for="username" class="">{{ trans('auth.login.username') }}</label>
<input type="username" class="form-control" name="username" value="{{ old('username') }}">
<label for="inputPassword" class="">{{ trans('auth.login.password') }}</label>
<input type="password" class="form-control" name="password" autocomplete="off">
<div class="forgot-password"><input type="checkbox" name="remember"> {{ trans('auth.login.remember_me') }}</div>
<div class="forgot-password">{{ trans('auth.login.forgot_password') }}</div>
<button type="submit" class="btn btn-lg btn-primary btn-block">{{ trans('auth.login.login') }}</button>
#if (count($errors) > 0)
<p class="text-danger">
#foreach($errors->all() as $error)
{{ $error }}<br />
#endforeach
</p>
#endif
</form>
#endsection
You may notice that in the above snippet, the "_token" element value is blank. This is intentional since I am basically trying to "circumvent" acunetix's detection by only setting its value using javascript since everything I have tried so far does not seem to work.
The alert provided most probably indicates that this may be a false positive. CSRF alerts more often than not require human intervention to verify whether:
There actually is an anti-CSRF token
If the form (or rather, input) requires any anti-CSRF
If you are already making use of the anti-CSRF token, then you can go ahead and mark that alert as a false positive. That will omit it from any future scans on the affected item (e.g. userinfo.php, being considered an item).
Certain alerts such as the one you specified, are discovered by the crawler module. Since Acunetix Vulnerability Scanner adopts a black-box methodology, it has no prior knowledge of the application it is scanning.
Thus, it first starts by dynamicaly mapping out the application's site structure using the crawler module and at the same time discovering particular alerts (Medium or Low alerts generally). Once the crawl is complete, the actual scanner module starts which proceeds to run every security test (script) on all the items discovered by the crawler.
Regarding one of you comments - "I am assuming that the acunetix crawler does not run javascript and would not populate the _token element."
The crawler perse does not execute and analyze Javascript, however the DeepScan (read more here) technology does, which occurs during the crawling stage. Thus the scanner is still able to understand client-side heavy application such as SPAs making use of frameworks like AngularJS, ReactJS etc.

Url and Form security in Laravel 5.1

What's the Problem?
Primary Key is present in Url so the data for other records can be seen easily by easily changing the Url.
Rendered html has hidden field present. Anybody can easily change other records based upon this Hidden Field.
When I edit the page. My Url looks like below.
http://localhost/Category/3
and Below is the rendered Html
<form method="POST" action="http://localhost/UpdateCategory" accept-charset="UTF-8">
<input name="_token" type="hidden" value="AmAXKmqtct6VOFbAVJhKLswEtds4VwHWjgu3w5Q8">
<input name="CategoryID" type="hidden" value="3">
<input required="required" name="Category" type="text">
<input class="btn btn-success" type="submit" value="Update">
</form>
Please suggest some Url and Form security in Laravel 5.1
There are many worksaround which shall by handled by us to avoid such incidents.
Fix 1 :
If you don't want to reach the user's by just changing the url
(i.e., Directly passing the id in url )
You shall filter the requests by
if($_SERVER['HTTP_REFERER']!='')
{
}
else
{
exit;
}
You shall have this in your Middleware or even in your view if you wish
Fix 2 : Never worry about the _token that is visible when you see form source
It is just the token that is generated by laravel app which is to identify whether the request is from authenticated source or not.
If you edit the token and pass the form you will surely get CSRF Token Mismatch Exception
Infact this is one of the great feature of Laravel.
Interesting Point : You can also find something in the headers of the browser ;)
Happy using Laravel ;)

Laravel Form methods VS traditional coding

I am currently learning Laravel and finding it really useful and interesting.
At the moment I am making a simple online application form.
What are the biggest advantages to doing things using the Laravel syntax like:
{{ Form::open(array('url' => 'foo/bar')) }}
As opposed to simply:
<form action="foo/bar">
Or:
echo Form::text('username');
Instead of:
<input type="text" name="username" />
The Laravel way must be better, I just wish to know why exactly?
Using built-in HTML helpers have many benefits:
Using Form::open you add CSRF protection input hidden (by default)
Using form elements (inputs/textarea etc.) and withInput method for Redirection allows you to easily fill in the form with the same data with almost no coding
If you use Redirect::route('form'->withInput(); and have input
text {{Form::text('username')}} it will automatically set input's value the old data - you don't need to code it yourself checking it
Also if you want to match fields with labels its much easier:
{{ Form::label('username', 'Enter username') }}
{{ Form::text('username') }}
it will generate the following code:
<label for="username">Enter username</label>
<input name="username" type="text" id="username">
so as you see id will be created automatically
Probably there are some more. However the main disadvantage is that you need to learn and it's not portable in case you want to move your site to other Framework but each solution has pros and cons.
There are so many advantages of using Laravel's Form component but one useful advantage is that, when you just use this:
{{ Form::open(array('url' => 'foo/bar')) }}
{{ Form::close() }}
It automatically appends a hidden _token field which is useful for CSRF protection. otherwise you have to manually create the _token field using echo Form::token() or other way maybe. Also, when you use RESTful routes then Laravel's Form component appends the corresponding hidden _method field as well. Following note is taken from Laravel website:
Note: Since HTML forms only support POST and GET, PUT and DELETE
methods will be spoofed by automatically adding a _method hidden field
to your form.
There are also other advantages like Form Model Binding, generating form elements (specially select) easily and many more. Read more about Form on documentation.
BTW, the Redirect::back()->withInput() doesn't deppend only on use of Form component, if you use something like this, for example:
<input type='text' name='username' value='<?php echo Input::old('username') ?>' />
This will still work, the field will be repopulated on redirect back with inputs.

Cakephp submit form from outside of controller

i want to give my users the option to login to my cakephp domain from my maindomain (which is not a cakephp application)
for this purpose i have created the following:
<header>
<h2 id="loginHeader">Login</h2>
</header>
<form id="bloglic-login" action="http://www.myCakeApplication.com/cake2/index.php/users/login" method="post" name="blogliclogin">
<input id="UserEmail" type="text" placeholder="Email" name="data[User][username]" value="" >
<input id="UserPassword" type="password" placeholder="Password" name="data[User][password]" value=""/>
<a class="forgot" href="http://system.bloglic.com/users/forgot_password">Forgot your password?</a>
<button class="signup" id="button-signup" type="submit">Submit</button>
</form>
</section>
Now as you can see this form should access my usersController and the action login with a post request.
However when i click submit i get a cakephp error saying the request has blackholed.
Now i think the reason for this is that my form is not following the cake convention. But how can i avoid this error and make my users able to login?
im using Cakephp version 2.3. I am also using ACL to administrate my users
The blackhole is from the Security Component. To answer your question, read the "Disabling Security Component for Specific Actions" section.
Or (I'm not sure), you might be able to submit from another site if you disable CSRF protection (worth a try)

Categories