Laravel-4 Empty PUT data being sent to a resourceful controller - laravel

G'day,
I'm having issues with PUT requests made via Chrome Postman to a controller, the PUT data is not present, POST data works fine.
I had performed a composer update prior to ensure that the latest version of vendor products where available and even removed bootstrap/compiled.php.
Is anybody else having similar issues?
The update function with both section_id and data being empty in the response:
public function update($id)
{
$section_id = Input::get('section_id');
$data = Input::all();
return Response::json(array('id' => $id, 'section_id' => $section_id, 'data' => $data));
}
I've debugged the code all the way to ParameterBag.php and $this->request's parameter list is empty, I'm not sure what's supposed to contain any values but all through the code the input values are empty. Not sure what to do now, short of using post instead of put.

PUT parameters don't work "out of the box" because PHP itself has some security restrictions around them. See: http://www.php.net/manual/en/features.file-upload.put-method.php
Laravel does implement a common workaround for this, though.
In Postman (or your form, or curl, or whatever client you're using), simply add a URL parameter name: "_method" value: PUT
Example 1:
?_method=PUT
Example 2:
<input type="hidden" name="_method" value="PUT" />
Laravel uses the symfony Http Foundation which checks for the _method variable and if it's present it routes based on its value, instead of the actual HTTP method used.

You have to send a POST request with adding an extra parameter _method with value PUT and it will works fine.

Related

How to use PUT method in Laravel API with File Upload

Having read this SO link,
PUT is most-often utilized for update capabilities, PUT-ing to a known resource URI with the request body containing the newly-updated representation of the original resource.
From this answer,
... we need to send all the parameters of the data again.
In my controller, I have:
$student = Student::find($student_id);
$student->username = $request->username;
$student->email = $request->email;
$student->password = $request->password;
$path = $request->file('passport')->store('upload');
$student->passport = $path;
I have once used this same code for POST method and it worked, but while using it for APIs, I used POSTMAN form-data and got $request->all() to be null. Some said I should use x-www-form-urlencoded but this does not allow files upload.
This is actually an incapability of PHP itself. A PUT/PATCH request with multipart/form-data just will not populate $_FILES, so Laravel has nothing to work with.
Every once in a while, people report bugs like this when they find $request->all() returns null, thinking it's Laravel's fault, but Laravel can't help it.
Files are best sent as multipart/form-data and that sort of request will only populate $_FILES if it's a POST. No $_FILES, no $request->file().
In lieu of having this work as-expected in PHP, if it works using a POST, just use a POST.
When the form contains uploaded file it works only with POST method - probably an issue with PHP/Laravel
If someone wants to use a PUT or PATCH request for form containing file uploads
<form action="/foo/bar" method="POST">
#method('PUT')
...
</form>
via any javascript framework like vue
let data = new FormData;
data.append("_method", "PUT")
axios.post("some/url", data)
Using _method and setting it to 'PUT' or 'PATCH' will allow to declare route as a PUT route and still use POST request to submit form data
I have answered a similar question How to update image with PUT method in Laravel REST API?

Get parameter passed in URL Codeigniter

Basically I have an anchor tag (update) that gets the id of the request in the table and load the update view getting all the request details
<i class="fa fa-eye"></i> Update
This is then received in my method
public function update_request_view($idx)
{
//some code here to load the view and get details
}
The url then becomes http://localhost/dashboard/staff/request/update_request_view/48
Now when I try to save the update that I make using another method
public function update()
{
$idx = $this->uri->segment(5);
}
My $idx variable is empty. When I use $this->uri->segment(4), I get update_request_view.
I dont wanna use hidden fields since it will cause lots of security issues and also when I will be able to work this out i will encrypt the id. Why is my $this->uri->segment(5) empty and how do I get it?
Most likely, if I understand you correctly, it is because the update function is a separate page than http://localhost/dashboard/staff/request/update_request_view/48. So CI doesn't see any of the previous url variables. You can either submit to update/{$id} (action url) or you can use a hidden field; it is no less safer than using an id in the url as that can be just as easily manipulated with a change to the form action.
That being said, if you are really concerned about security you should restrict access to particular users for a given record using some sort of ACL.

Laravel $request->all() correctly returns data, but $_POST completely empty

I am making an ajax post request to the server, posting json data. In firebug I can see the network post call going through along with the json data.
In Laravel I was trying to do a simple var dump of the $_POST data and have just wasted a fair bit of time being confused as to why this should be completely empty. However, when I use the Request facade, my data is there.
ie. this just gives me an empty array:
public function test(){
Log::info($_POST);
}
...yet this prints my data, as I expect:
public function test(Request $request){
Log::info($request->all());
}
Why?
Edit
Thanks, #Webdesigner. The http verb is definitely post, as my method is called in my routes file via
Route::post('/image-upload', 'EntryController#test'); // Note "post" verb
I don't think $request->post() is valid in Laravel 5.4 as this throws an BadMethodCallException: Method post does not exist. error. However, I can confirm that
Log::info($request->method()); // POST
also tells me the method is post.
Very strange. I guess you're right that some part of the app is overwriting the $_POST global, though I have no idea why/where/how. Probably not relevant, but this call is being made from Angular 4.
Thanks for your help anyway!
This is not the normal behavior of Laravel. I tested this on a fresh Laravel 5.5 site and just did a Form submit and an Ajax POST request to the same Route.
Both give me the same result. A POST Request should have at least the CSRF Token as _token with a value.
One other point is $request->all() is not only the the content of $_POST so to have a fair compression you should try $request->post().
BTW only because you did a POST request do not mean that the data is send by the POST Method, it could be that the data you see in $request->all() is from $_GET and $_COOKIE, etc and only the Method was a POST.
Last but not least there it the option that some part of your APP is deleting the content of the Superglobal Variables. $_POST and the others are not like constants, so they can be changed during runtime e.g. $_POST = [];
I don't thing that there is a difference in Laravel 5.4.27.

Registering routes with Laravel but make them unaccessible

I am trying to make a single page CRUD application with Laravel. I will use ajax to create, edit and delete my entity, and also to render partial views. The corresponding controller methods will process the information and return the views.
I want to register the routes so I can call the different methods when necessary. I don't see any other way:
However, registering them so I can do something like this {{ Form::open(['route' => ['cities.store', $city->id]]) }} will allow access via the URL, and I only want to make those routes accessible through the tools I am going to create in that one page CRUD.
I can only think of applying a before filter, but what would be the filter? Also, any other ideas on how I should approach this situtation?
I've had to do something similar with a web service I created. Basically, I wanted only my app to be able to access the routes I created.
What I ended up doing was adding a hashed key to each request being sent, then checking for this key value in the controller. So, only if the key is present and matches the one sent would you then process the request.
Or, if you're using forms, you could do something like the following:
//check if request was sent from our form
if ( Session::token() !== Input::get( '_token' ) ) {
return Response::json( array(
'msg' => 'Unauthorized access attempt'
) );
}
Hope this helps.
another way that doesnt need tokens but is less secure, you got to know what you need,
is using laravels request information
if (Request::ajax())
{
//your action
}else{
//error
}
note this only works when your application always uses ajax you could even type this in your before filter and add it to all needed routes

Codeigniter: Pass form variable into URI

Not sure if this can be done but it seems my main issue is because i have a default route to a method called "index." I want to be able to list all users tagged with a specific keyword. In addition, users can search for other users based on these keywords.
i.e.
www.domain.com/tags/apples
www.domain.com/tags/oranges
www.domain.com/tags/blueberry
It works fine if I go to the URL manually. I'm having issues getting it to work with a form field.
Snippet of the form_open:
<?=form_open('tags/');?>
<p>Search for Tag: <input type="text" name="tag" /></p>
<p><input type="submit" value="Search" /></p>
Here's a snippet of my controller:
function index() {
$data['result'] = $this->tags_model->searchByTag($this->uri->segment(2));
$this->load->view('tags_view', $data);
}
Here's a snippet of my router:
$route['tags'] = "tags/index";
$route['tags/(:any)'] = "tags/index/$1";
Now, I can easily fix all this if I have a method called search, but I don't want the URL to show up as www.domain.com/tags/search/orange.
When you create your form you set it to use POST variables instead of GET, that way they don't go through the url, that's codeigniter's default method for forms.
So your form_open code will generate the following code:
<form method="post" action="tags/" />
If you want them to got through url though, call the form opener this way instead:
form_open('tags/', array('method' => 'get'));
The same applies to any other attributes you want to specify for the form, just follow the same pattern attribute_name => attribute_value inside the array.
More info on the user guide
The problem here is that your form will be submitting all it's data to "/tags", with nothing trailing it, as POST data doesn't come in as part of the URL. Even if it was a GET request however, I don't think that CodeIgniter will take anything out of the querystring and use it as part of the routing segments.
I think what you should do is have a small Javascript function that automatically updates the form action parameter to be tags/<select option value> whenever the select value is changed. This way it will submit to the right place. In order to handle non-javascript enabled browsers, you could have a default action called tags/search that would simply analyze your form data and put out a 301 redirect to the proper tags/<location> once you'd figured it out.
It seems like a bit of overkill here however, as you could really point the form at tags/index and not worry about it. I'm not sure search engines index form submission locations, and even if they did, they certainly wouldn't index a form that submits to dynamic URIs in the way that you want it to. You could still link to the search result pages using tags/apples, etc, but the form could work quite normally just by going to tags/index.
I ended up redirecting the URL and passed the keyword into the URI.
i.e. domain.com/tags/view/

Resources