Accessing Incoming PUT Data from PHP

Recently I started writing a REST service. I began in the usual way, writing a php script, calling it with a GET request, accessing the variables using the PHP superglobal variable $_GET. I wrote code to handle a POST request and used the variables I found in $_POST. Then I tried to write a PUT request.

PHP doesn’t have a built-in way to do this, and at first I was a little confused as to how I could reach this information. It turns out that this can be read from the incoming stream to PHP, php://input.

file_get_contents("php://input");

The above line provided me with a query string similar to what you might see on the URL with a GET request. key/value pairs separated by question marks. I was rescued from attempting to parse this monster with a regex by someone pointing out to me that parse_str() is intended for this purpose (seriously, I write a lot of PHP, I don’t know how I miss these things but its always fun when I do “discover” them) – it takes a query string and parses out the variables. Look out for a major health warning on str_parse() – by default it will create all the variables all over your local scope!! Pass in the second parameter though and it will put them in there as an associatvive array instead – I’d strongly recommend this approach and I’ve used it here with my $post_vars variable.

parse_str(file_get_contents("php://input"),$post_vars);

This loads the variable $post_vars with the associative array of variables just like you’d expect to see from a GET request.

Simple Example

Its a bit of a contrived example but it shows use of the REQUEST_METHOD setting from the $_SERVER variable to figure out when we need to grab the post vars. Firstly, here’s the script:

if($_SERVER['REQUEST_METHOD'] == 'GET') {
    echo "this is a get request\n";
    echo $_GET['fruit']." is the fruit\n";
    echo "I want ".$_GET['quantity']." of them\n\n";
} elseif($_SERVER['REQUEST_METHOD'] == 'PUT') {
    echo "this is a put request\n";
    parse_str(file_get_contents("php://input"),$post_vars);
    echo $post_vars['fruit']." is the fruit\n";
    echo "I want ".$post_vars['quantity']." of them\n\n";
}

And here’s what happened when I request the same script using two different HTTP verbs. I’m using cURL to show the example simply because I think it shows it best.

Via GET:

curl "http://localhost/rest_fruit.php?quantity=2&fruit=plum"
this is a get request
plum is the fruit
I want 2 of them

Via PUT:

curl -X PUT http://localhost/rest_fruit.php -d fruit=orange -d quantity=4
this is a put request
orange is the fruit
I want 4 of them

Purists will tell me that I shouldn’t be returning data from a PUT request, and they’d be right! But this does show how to access the incoming variables and detect which verb was being used. If you’re going to write a REST service then the correct naming of resources and the correct response to each resource being accessed in various ways is really important, but its a story I’ll save for another day. If you use this, or perhaps you access the variables another way, then do post a comment – there aren’t a lot of resources available on this topic for PHP.

62 thoughts on “Accessing Incoming PUT Data from PHP

  1. You might want to consider checking the Content-Type header, as well (to see if it is application/x-www-form-urlencoded; not sure how to deal with multipart/form-data; AFAIK that’s not supposed to be PUTted anyway, but hey…)

    • Well i never worked with put, but interesting.
      The line break inside the
      “curl -X PUT http://localhost/rest_fruit.php -d fruit=orange -d quantity=4″ statement is iritating a bit first i thought: Where is the value for quantity transfered and thought of some magic stuff until i saw it belongs to the same line.

  2. Thanks everyone for dropping in and adding comments :)

    David: I am leaning towards hoping I don’t need to deal with multipart PUTs!

    Balu: The impression I got from the PHP internals people was that it wasn’t really used enough so nobody had bothered to make one, but that it could be done.

    Johny: Actually now you mention it, the way that has wrapped is kind of annoying!

    Mark: You can retrieve the data for DELETE requests in the same way as PUT requests. Is that what you were asking?

    Paul: Hello! Not sure if I’ll make it down for PHP London, but I can probably track Zoe down if I need to pick her brain – thanks for mentioning it!

  3. I would like to here more about the script you wrote that handles $_POST variables. Especially if you have one that sends stuff via $_POST with php!!! email me if you can. thanks!

  4. Great post Lorna!
    This would also give you a great place to filter input variables.
    But you do know that apache doesn’t support PUT by default?
    I’d love to hear more about your REST implementation.

  5. No problem. I had to actually figure out what those two verbs where. Of course I feel like PUT/DELETE can pose as some major risks, yes you can secure the page, but feel like they are too much of a “strait to the point” operation that can cause some issues. I don’t know, never had the need to use those verbs.

    Just my 2 cents.

  6. Boy: Hey there, thanks for dropping in. Perhaps I should write a more comprehensive tutorial about the REST implementation I’ve been doing, its a wrapper for a library class similar to how the SOAP wrappers wrap classes.

    EllisGL: The PUT and DELETE verbs are only as direct as you let them be. Just as with a POST operation, you would check all the data, the user credentials and so on, you do the same for these and its no different to work with.

  7. LornaJane: Ah OK.

    David: Sounds like some code I had to maintain at my last job. Yeah extract can be evil and can make debugging a nightmare..

    • I am curious as to why extract() is so bad – I agree that it is for incoming data because of never trusting the client and the need for cleansing data before you use it elsewhere.

      However if you pull out database records as an associative array (i.e. the source is trusted) then extract() is really useful…? I code a lot of PHP as well so would be interested in your thoughts on this!

      Mark

      • Mark: I always think it is best to access the variables in their associative array, so that its very clear that you are using the “name column from the result set $foo” rather than “this variable called $foo that could have come from anywhere and its not declared so you can’t debug it”! Its too easy, especially on large systems, to accidentally use the same variable twice, or to be unclear where its coming from – so I always teach that extract is a BAD thing.

  8. David: I am lucky enough to have dodged code like that most of the time. Untraceable variable soup really scares me … maybe because I didn’t start using PHP until after register_globals was off by default!

  9. Hi,
    if you are going to use the $SERVER[] array like this, why not go the whole hog and use $_SERVER[‘QUERY_STRING’] to get the parameters, instead of going through the file_get_contents() which seems (slightly) more complicated ?

  10. shaun: good question! I’m not sure that PUT requests would populate this in the same way as GET does (for example). The file_get_contents just opens the stream to php://input, its an easy way to do this.

    • ok, I’ve been experimenting with this, ‘switch’ing on the REQUEST_METHOD to implement post, get, put, delete for a db resource; so far I’ve not had problems using $_SERVER[‘QUERY_STRING’] and parse_str()… what problems do you anticipate? (I’m not sending files, everything fits in the string). I was surprised to discover that cURL allows ANY string to be sent as the method e.g. curl ‘http://my.web.page/’ -X OBLITERATE would invent a new ‘obliterate’ request method.

      • shaun: I didn’t anticipate problems, I just didn’t think it worked in that way – but I’m completely happy to be told otherwise :) Don’t be surprised that curl lets you do weird and wonderful things, lots of tools are like that and it allows you to use them in ways that the original author hadn’t thought of. And if you feed them rubbish, well they will probably response with rubbish :) This is a common approach with the unix type apps, kind of “use at your own peril”!

  11. I recently had reason to write a REST server in PHP, which was very interesting. There aren’t a whole lot of resources on this topic around so I thought I’d write an outline of what I did. There is quite a lot to it so I’m publishing in multiple section

  12. Thanks a lot LornaJane! I’ve been hitting my head on the deck with this issue for a long time now.
    About the multipart, as far as I know, this is the assumed way a PUT request should work.
    PUT is not supposed to work with multipart/form-data, because you can send the raw contents of a file as the request body without encoding it. With curl, you’d specify the file with CURLOPT_INFILE and CURLOPT_INFILESIZE options. Or you can set CURLOPT_POSTFIELDS to a raw text/content and recieve it in php://input too.

  13. Very useful! Thanks LornaJane! I’m thinking more about web services since your talk at the PHP UK Conference last month. I enjoyed it a lot by the way, I’ve lost count of how many HORRIBLE ‘web services’ I’ve encountered!

  14. Rowan: Thanks for the comment, I’m glad the talk and this post were useful. I totally agree on the horrible services front, personally I am hoping that as the field becomes more established, the standards become more accepted.

  15. This is all about accessing incoming PUT data from PHP and the authors attempts to find out more resources to go about this activity and trying to find out people who could pitch in more information
    to add to the process. I think this exercise should bring in a lot more good for the community who have
    what it takes to go places on this front.

  16. Pingback: How to get Wireit json output? | SeekPHP.com

  17. Great resource, thanks for the tips. I think it’s a real shame there’s no $_PUT[] super global, but the HTTP Header extension in the SPL seems to have a lot of useful functions for PHP REST services, especially if you’re serious about using HTTP headers properly. Sadly I discovered them after doing my own thing, I very much dislike rewriting the wheel.

    • I must admit that (this is quite an old post) I can totally see why it makes no sense to have $_PUT in PHP now. The data will come in all sorts of formats; a few services do support the form post style as shown in the original post, but mostly the body will be XML or JSON, so you need to read php://input anyway and then decode appropriately.

      I have a code sample I’ve been meaning to post which illustrates PUTting other sorts of data in the body of the request, I am taking this as my cue to get organised with that :)

      • I still need the php://insert, and I just replace the mb_parse_str, with the appropriate request type… it was really the php://insert I needed.

        I think it could make sense to have $_PUT, it $_PUT were populated based on the Content-Type in the request header, which is effectively how I’m implementing my controller, but with member variables rather than globals. This way I have ready to go data in a consistent format, and the entire request is abstracted away.

  18. You can also use one of the RESTful PHP micro-frameworks. Slim in particular has good support for all the HTTP methods. I blogged a sample app here: http://coenraets.org/blog/2011/12/restful-services-with-jquery-php-and-the-slim-framework/. In this example, I send a JSON string when sending a PUT request. The JSON string is available using the getBody() method of Slim’s request object. But you can also “PUT” url encoded form params in which case you can access them like this at the server side:
    $paramValue = $app->request()->put(‘paramName’);

    • I’m interested to see you mention Slim as I fell over it pretty much the day before you posted this comment, although in that instance it was being used simply as a very lightweight web framework rather than something specifically RESTful. I liked what I saw of it and will certainly be looking at it again, so thanks for the mention!

  19. Pingback: receive output from java DataOutputStream in a php page • PHP Help Coding Programming

    • Cheers for that! There’s certainly more information around about this now, as more people move to RESTful services

  20. Thanks for the article. Saved me a lot of time.
    I got here googling “php read request data put method”, and this was the first result.

  21. Hi Lorna, thanks for the great post. Could you elaborate on how to determine what format the PUT data is in? e.g. XML/JSON or whatever?

    • Niels: Check the Content-Type header of the incoming request, it *should* give you an indication of how to unpack the body. The example shown in the original post (it’s really old!) shows form-style data, but you could also json_decode() the string you get from php://input or parse it as XML as appropriate. Hope that helps

      • Hi Lorna,
        Checking the Content-Type makes a lot of sense. Actually in my case i also control the incoming request but i want to get a good understanding of things before i burn myself ;-)
        Thanks alot!

  22. Pingback: Arduino / Twilio Project « Latest Thoughts

    • Sorry, I’ve never seen PUT used that way. Usually it’s for updating RESTful resources. If the only thing in the body is the file, perhaps you could file_put_contents(‘uploaded_file.type’, file_get_contents(php://input)) ?

      • Hi Lorna,

        the main idea behind PUT is that you send some data directly to a resource name, something like

        PUT https://mydomain.com/resources/myfile.ext

        Handling this server side you wouldn’t expect form-encoded data but a (possibly binary) stream containing data for the named resource. As this data might be quite huge it should never be accessed using file_get_contents() as you might easily run in an OOM condition. I managed to transfer a couple of hundred megabytes like this:

        $fin = fopen('php://input', 'rb');
        $fount = fopen($mytmpfile, 'w');
        while (!feof($fin)) {
        $chunk = fread($fin, 80960);
        fwrite($fout, $chunk);
        }
        fclose($fout);
        fclose($fin);

        Note this is only the skeleton, wihout any error handling. Note that at least on my end the chunksize read from input in one pass is never more than 8k, seems to be tied to the TCP window size.

  23. Pingback: receive output from java DataOutputStream in a php page - PHP Questions - Developers Q & A

  24. Thank you, this was very helpful! Just a note, I’m using the Postman extension for chrome, Always ensure you send the data as “x-www-form-urlencoded” and not just plain “form-data”, you will get some strange results otherwise.

  25. Thanks for sheding a lot of light on this.

    As for error handling in the REST code I found that the PUT data must be read or the script will wait until timeout. Adding something like the following will make sure that any error immediately handles the input stream:

    [code]
    set_error_handler(function() {
    @fclose(@fopen(‘php://input’, ‘rb’));
    exit;
    }, 0xFFFF);
    [/code]

    Of course the error handler would need to be be a bit more sophisticated in a real world application, but I hope you all get the picture.

  26. Thanks for the great example. There is a use case for returning data from PUT requests: For testing http clients. I’m writing some http clients using apache http client in java and needed to create some junit tests for various conditions. Having the php return something useful can tell the test if the call was successful or not.

    • I’d still be tempted to test success by checking status codes. All API tests should also be able to follow a location header and evaluate the data returned by that URL so that’s my preferred approach

  27. Pingback: Web Services | WEB TECHNOLOGIES II

  28. Pingback: Resolved: I can't get PUT data in PHP from jQuery Ajax request - Help Devs Fix Issues

Leave a Reply

Please use [code] and [/code] around any source code you wish to share.

This site uses Akismet to reduce spam. Learn how your comment data is processed.