Handling Put/Delete Arguments in PHP

Handling PUT/DELETE arguments in PHP

Instead of using CURLOPT_PUT = TRUE use CURLOPT_CUSTOMREQUEST = 'PUT'
and CURLOPT_CUSTOMREQUEST = 'DELETE' then just set values with CURLOPT_POSTFIELDS.

How to get PUT/DELETE arguments in PHP

Can you try this, PHP doesn't have a built-in way to do this, can be read from the incoming stream to PHP, php://input.

 parse_str(file_get_contents("php://input"));

EX:

  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";
}

Ref: http://www.lornajane.net/posts/2008/accessing-incoming-put-data-from-php

HTTP protocol's PUT and DELETE and their usage in PHP

What are these methods (PUT) and (DELETE) for...

There are a lot of words to spend to explain this, and I'm not skilled enough to do it, but as already posted, a quick recap of what the HTTP specification describes.

The protocol basically says this:

  • use GET when you need to access a resource and retrieve data, and you don't have to modify or alter the state of this data.

  • use POST when you need to send some data to the server. Ex. from a form to save these data somewhere.

  • use HEAD when you need to access a resource and retrieve just the Headers from the response, without any resource data.

  • use PUT when you need to replace the state of some data already existing on that system.

  • use DELETE when you need to delete a resource (relative to the URI you've sent) on that system.

  • use OPTIONS when you need to get the communication options from a resource, so for checking allowed methods for that resource. Ex. we use it for CORS request and permissions rules.

  • You can read about the remaining two methods on that document, sorry I've never used it.

Basically a protocol is a set of rules you should use from your application to adhere to it.



... and if it's possible to
use them in PHP, how would I go about this.

From your php application you can retrieve which method was used by looking into the super global array $_SERVER and check the value of the field REQUEST_METHOD.

So from your php application you're now able to recognize if this is a DELETE or a PUT request, ex. $_SERVER['REQUEST_METHOD'] === 'DELETE' or $_SERVER['REQUEST_METHOD'] === 'PUT'.

* Please be also aware that some applications dealing with browsers that don't support PUT or DELETE methods use the following trick, a hidden field from the html form with the verb specified in its value attribute, ex.:

<input name="_method" type="hidden" value="delete" />


Follow an example with a small description on a possible way to handle those 2 http requests

When you (your browser, your client) request a resource to an HTTP server you must use one of the method that the protocol (HTTP) accepts. So your request needs to pass:

  • A METHOD
  • An Uri of the resource
  • Request Headers, like User-Agent, Host, Content-Length, etc
  • (Optional body of the request)

Now, while you would be able to get data from POST and GET requests with the respective globals ($_GET, $_POST), in case of PUT and DELETE requests PHP doesn't provide these fast access globals; But you can use the value of $_SERVER['REQUEST_METHOD'] to check the method in the request and handle your logic consequently.

So a PUT request would look like:

PUT /something/index.php

(body) maybe=aparameter

and you can access those data in PHP by reading the php://input stream, ex. with something like:

if ($_SERVER['REQUEST_METHOD'] === 'PUT') { 
$myEntireBody = file_get_contents('php://input'); //Be aware that the stream can only be read once
}

and a DELETE request would look like:

DELETE /something/index.php?maybe=aparameter

and again you can build your logic after have checked the method:

if ($_SERVER['REQUEST_METHOD'] === 'DELETE') { 
// do something
}

Please pay attention that a DELETE request has no Body and pay very attention to Response Status Code too (ex. if you received a PUT request and you've updated that resource without error you should return a 204 status -No content-).

PHP REST put/delete options

There are two common ways to send a request from an HTML page, using an http method other than GET or POST.

#1: use an html form to send a POST request, but include a hidden form field that tells the server to treat the request as though it were using a different method. This is the approach outlined by @xdazz.

<form method="post" action="my_resource.php">
...
<input type="hidden" name="REQUEST_METHOD" value="PUT" />
<form>

In your PHP script, "my_resource.php", you'll have to look at both the real request method, and the submitted form field, to determine which logic to invoke:

/* my_resource.php */

$method = strtolower($_SERVER['REQUEST_METHOD']);
if( $method === 'post' && isset($_REQUEST['REQUEST_METHOD'])) {
$tmp = strtolower((string)$_REQUEST['REQUEST_METHOD']);
if( in_array( $tmp, array( 'put', 'delete', 'head', 'options' ))) {
$method = $tmp;
}
unset($tmp);
}

// now, just run the logic that's appropriate for the requested method
switch( $method ) {
case "get":
// logic for GET here
break;

case "put":
// logic for PUT here
break;

case "post":
// logic for POST here
break;

case "delete":
// logic for DELETE here
break;

case "head":
// logic for DELETE here
break;

case "options":
// logic for DELETE here
break;

default:
header('HTTP/1.0 501 Not Implemented');
die();
}

Note: you can put the above logic into each page (or call it from each page). An alternative is to build a proxy script, (eg. "rest-form-proxy.php"). Then, all forms in your site will submit to the proxy, including a request_method, and a target url. The proxy will extract the provided information, and forward the request on to the desired url using the proper requested http method.

The proxy approach is a great alternative to embedding the logic in each script. If you do build the proxy though, be sure to check the requested URL, and dis-allow any url that doesn't point back to your own site. Failure to do this check will allow others to use your proxy to launch malicious attacks on other websites; and it could also compromise security and/or privacy on your website.

--

#2: Use Javascript, in your HTML page, to initiate an XMLHttpRequest. This is a more complex approach, which requires a bit of javascript, but it can be more flexible in some cases. It allows you to send requests to the server without re-loading the page. It also allows you to send data in many different formats (you are not limited to sending only data from an html form). For example:

<button onclick="doSave()">Save</button>

<script>
var myObject = {
// ... some object properties that
// that you'll eventually want to save ...
};

function doSave() {
var xhr = createxmlhttprequest();

// initialize the request by specifying the method
// (ie: "get", "put", "post", "delete", etc.), and the
// url (in this case, "my_resource.php"). The last param
// should always be `true`.

xhr.open("put", "my_resource.php", true);
xhr.setRequestHeader('Content-Type', 'application/json');

xhr.onreadystatechange = function() {
if (xhr.readystate != 4) { return; }
var serverresponse = xhr.responsetext;

// ... this code runs when the response comes back
// from the server. you'll have to check for success
// and handle the response document (if any).
};

// this initiates the request, sending the contents
// of `myObject` as a JSON string.

xhr.send(JSON.stringify(myObject));

// The request runs in the background
// The `onreadystatechange` function above
// detects and handles the completed response.
}
</script>

There's a lot more to XMLHttpRequest than I've shown in the basic example above. If you choose this route, please research it thoroughly. Among other things, make sure you handle the various error conditions properly. There are also a number of issues with cross-browser compatibility, many of which can be addressed by using an intermediary, like jQuery's $.ajax() function.

Finally, I should note that the two methods above are not mutually exclusive. It's quite possible to use forms for some requests, and XMLHttpRequest for others, as long as you build your server so that it can handle either kind of request (as shown in #1 above).

POST and GET works in Postmen but PUT and DELETE doesn't

In the case of PUT and DELETE you need to get the request parameters this way:

$requestParams = array();
parse_str(file_get_contents('php://input'), $requestParams);

Then you can access the values like using $_GET or $_POST:

$requestParams['product_id']

Hope this helps.

Detecting request type in PHP (GET, POST, PUT or DELETE)

By using

$_SERVER['REQUEST_METHOD']

Example

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// The request is using the POST method
}

For more details please see the documentation for the $_SERVER variable.

get a PHP delete variable

You might have to look at reading the data directly from the php://input stream.

I knwo this is how you have to do it for PUT requests and some quick googling indicates the method works for DELETE as well.

See here for an example. The comment here says this method works for DELETE also.

Here is an interesting code sample that will help (from sfWebRequest.class.php of the symfony 1.4.9 framework altered slight for brevity):

public function initialize(...) 
{
... code ...

$request_vars = array();
if (isset($_SERVER['REQUEST_METHOD']))
{
switch ($_SERVER['REQUEST_METHOD'])
{
case 'PUT':
if ('application/x-www-form-urlencoded' === $this->getContentType())
{
parse_str($this->getContent(), $request_vars );
}
break;

case 'DELETE':
if ('application/x-www-form-urlencoded' === $this->getContentType())
{
parse_str($this->getContent(), $request_vars );
}
break;
}
... more code ...
}

public function getContent()
{
if (null === $this->content)
{
if (0 === strlen(trim($this->content = file_get_contents('php://input'))))
{
$this->content = false;
}
}

return $this->content;
}

This code sample puts the PUT or DELETE request parameters into the $request_vars array. A limitation appears to be that the form (if you are using one other the content-type header) must be 'application/x-www-form-urlencoded', some quick googling confirms this.

REST API - why use PUT DELETE POST GET?

The idea of REpresentational State Transfer is not about accessing data in the simplest way possible.

You suggested using post requests to access JSON, which is a perfectly valid way to access/manipulate data.

REST is a methodology for meaningful access of data. When you see a request in REST, it should immediately be apparant what is happening with the data.

For example:

GET: /cars/make/chevrolet

is likely going to return a list of chevy cars. A good REST api might even incorporate some output options in the querystring like ?output=json or ?output=html which would allow the accessor to decide what format the information should be encoded in.

After a bit of thinking about how to reasonably incorporate data typing into a REST API, I've concluded that the best way to specify the type of data explicitly would be via the already existing file extension such as .js, .json, .html, or .xml. A missing file extension would default to whatever format is default (such as JSON); a file extension that's not supported could return a 501 Not Implemented status code.

Another example:

POST: /cars/
{ make:chevrolet, model:malibu, colors:[red, green, blue, grey] }

is likely going to create a new chevy malibu in the db with the associated colors. I say likely as the REST api does not need to be directly related to the database structure. It is just a masking interface so that the true data is protected (think of it like accessors and mutators for a database structure).

Now we need to move onto the issue of idempotence. Usually REST implements CRUD over HTTP. HTTP uses GET, PUT, POST and DELETE for the requests.

A very simplistic implementation of REST could use the following CRUD mapping:

Create -> Post
Read -> Get
Update -> Put
Delete -> Delete

There is an issue with this implementation: Post is defined as a non-idempotent method. This means that subsequent calls of the same Post method will result in different server states. Get, Put, and Delete, are idempotent; which means that calling them multiple times should result in an identical server state.

This means that a request such as:

Delete: /cars/oldest

could actually be implemented as:

Post: /cars/oldest?action=delete

Whereas

Delete: /cars/id/123456

will result in the same server state if you call it once, or if you call it 1000 times.

A better way of handling the removal of the oldest item would be to request:

Get: /cars/oldest

and use the ID from the resulting data to make a delete request:

Delete: /cars/id/[oldest id]

An issue with this method would be if another /cars item was added between when /oldest was requested and when the delete was issued.



Related Topics



Leave a reply



Submit