Ronni Egeriis Persson
Ronni Egeriis Persson

Reputation: 2289

Laravel doesn't read HTTP request payload for PUT request

So I am stumbling a bit here, as I have figured out that PHP will not read the HTTP request body from a PUT request. And when the Content-Type header in the request is set to application/json, there doesn't seem to be any way to get the body.

I am using Laravel, which builds their request layer on top of Symfony2's HttpFoundation lib.

I have debugged this a bit with jQuery, and these are some example requests:

Doing a request like this, I can find the content through Input::getContent()

$.ajax({ 
    url: 'http://api.host/profiles/12?access_token=abcdef', 
    type: 'PUT', 
    data: {"profiles":[{"name":"yolanda ellis","email":"[email protected]"}]} 
});

I cannot get the content with file_get_contents('php://input') though. jQuery per default sends the data as application/x-www-form-urlencoded.

It becomes even more mindboggeling when I pass another Content-Type in the request. Just like Ember-Data does:

$.ajax({ 
    url: 'http://api.host/profiles/12?access_token=abcdef', 
    type: 'PUT', 
    data: {"profiles":[{"name":"yolanda ellis","email":"[email protected]"}]},
    contentType: 'application/json' 
});

The data seems nowhere to be found, when doing it like this. This means that my Ember.js app does not properly work with my API.

What on earth is going on here?

Edit

Here's a full request example as seen in Chrome DevTools: http://pastebin.com/ZEjDAsmJ

I have found that this is a Laravel specific issue.

Edit 2: Answer found

It appears that there's a dependency in my project, which reads from php://input when the Content-Type: application/json header is sent with the request. This clears the stream—as pointed out in the link provided by @Mark_1—causing it to be empty when it reaches Laravel.

The dependency is bshaffer/oauth2-server-php

Upvotes: 6

Views: 6812

Answers (2)

Barryvdh
Barryvdh

Reputation: 6579

You should be able to use Input::json() in your code to get the json decoded content.

I think you can only read the input stream once, so if a different package read the input stream before you, you can't access it.

Are you using OAuth2\Request::createFromGlobals() to create the request to handle your token? You should pass in the existing request object from Laravel, so both have access to the content. Did you read this? http://bshaffer.github.io/oauth2-server-php-docs/cookbook/laravel/ That links to https://github.com/bshaffer/oauth2-server-httpfoundation-bridge which explains how to create a request object from an httpfoundation request object (which Laravel uses).

Something like this:

$bridgeRequest = \OAuth2\HttpFoundationBridge\Request::createFromRequest($request);
$server->grantAccessToken($bridgeRequest, $response);

So they both share the same content etc.

Upvotes: 8

Mark_1
Mark_1

Reputation: 643

I found the following comment at http://php.net/manual/en/features.file-upload.put-method.php

PUT raw data comes in php://input, and you have to use fopen() and fread() to get the content. file_get_contents() is useless.

Does this help?

Upvotes: 3

Related Questions