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

Introduction
I've read the following:
Hypertext Transfer Protocol (HTTP) is the life of the web. It's used every time you transfer a document, or make an AJAX request. But HTTP is surprisingly a relative unknown among some web developers.
The HTTP verbs comprise a major portion of our “uniform interface” constraint and provide us the action counterpart to the noun-based resource. The primary or most-commonly-used HTTP verbs (or methods, as they are properly called) are POST, GET, PUT, and DELETE.
Huh?
Well, we came to the point I lost track of things.
PUT and DELETE, they say. I've only ever heard of POST and GET and never saw something like $_PUT or $_DELETE passing by in any PHP code I've ever viewed.
My question
What are these methods (PUT) and (DELETE) for and if it's possible to use them in PHP, how would I go about this.
Note: I know this is not really a problem but I always grab a learning opportunity if I see one and would very much like to learn to use these methods in PHP if this is possible.

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-).

Way to use PUT data from PHP:
$method = $_SERVER['REQUEST_METHOD'];
if ('PUT' === $method) {
parse_str(file_get_contents('php://input'), $_PUT);
var_dump($_PUT); //$_PUT contains put fields
}

PHP's $_GET and $_POST are poorly named. $_GET is used to access the values of query string parameters, and $_POST lets you access the request body.
Using query string parameters is not limited to GET requests, and other kinds of requests than just POST can come with a request body.
If you want to find out the verb used to request the page, use $_SERVER['REQUEST_METHOD'].

Most suitable place to use these (PUT and DELETE) methods is REST API. Where we use http methods to define the mode of operation for example you want to fetch any resources then you can use following:
GET http://api.example.com/employee/<any_id>
to add a new item:
POST http://api.example.com/employee/
to Update or Edit:
PUT http://api.example.com/employee/
to Delete an existing resource:
DELETE http://api.example.com/employee/1
etc.
Now on PHP side you just need to read what HTTP method used so that you can make an action according to that.
There are lots of libraries available which can do that for you.

What are these methods (PUT) and (DELETE)
There are described in the HTTP spec.
In a nutshell, and simplifying somewhat, PUT is for uploading a file to a URL and DELETE is for deleting a file from a URL.
never sawy something like $_PUT or $_DELETE passing by in any PHP code I've ever viewed
$_POST and $_GET are terribly named superglobals. $_POST is for data parsed from the request body. $_GET is for data parsed from the URL. There's nothing that strictly ties data in either of those places (especially the URL) to a particular request method.
DELETE requests only care about the URL's path, so there is no data to parse.
PUT requests usually care about the entire request body (not a parsed version of it) which you would access with file_get_contents('php://input');.
for and if it's possible to use them in PHP, how would I go about this.
You'd need to map the URL onto a PHP script (e.g. with URL rewriting), test the request method, work out what URL you were actually dealing with, and then write code to do the appropriate action.

$GLOBALS["_PUT"]=null;
if($_SERVER['REQUEST_METHOD'] == 'PUT') {
$form_data= json_encode(file_get_contents("php://input"));
$key_size=52;
$key=substr($form_data, 1, $key_size);
$acc_params=explode($key,$form_data);
array_shift($acc_params);
array_pop($acc_params);
foreach ($acc_params as $item){
$start_key=' name=\"';
$end_key='\"\r\n\r\n';
$start_key_pos=strpos($item,$start_key)+strlen($start_key);
$end_key_pos=strpos($item,$end_key);
$key=substr($item, $start_key_pos, ($end_key_pos-$start_key_pos));
$end_value='\r\n';
$value=substr($item, $end_key_pos+strlen($end_key), -strlen($end_value));
$_PUT[$key]=$value;
}
$GLOBALS["_PUT"]=$_PUT;
}
if (!function_exists("getParameter")){
function getParameter($parameter)
{
$value=null;
if(($_SERVER['REQUEST_METHOD'] == 'POST')&& (isset($_POST[$parameter]))){
$value=$_POST[$parameter];
}
else if(($_SERVER['REQUEST_METHOD'] == 'PUT')&& (isset($GLOBALS["_PUT"][$parameter])))
{
$value=$GLOBALS["_PUT"][$parameter];
}
else if(($_SERVER['REQUEST_METHOD'] == 'DELETE')&& (isset($_DELETE[$parameter]))){
$value=$_DELETE[$parameter];
}
else if(($_SERVER['REQUEST_METHOD'] == 'PATCH')&& (isset($_PATCH[$parameter]))){
$value=$_PATCH[$parameter];
}
else if(isset($_GET[$parameter])){
$value=$_GET[$parameter];
}
return $value;
}
}

Related

Deleting a file on server by DELETE form method

I am trying to delete a file on my server using DELETE method in my html form.
I have a file ,and url to that file is :
http://example.com/file2.php
I am using the following code for deleting the file :
<form action="file2.php"method="DELETE">
<input type="submit"value="delete file">
</form>
When I press "delete file" button I get redirected to "file2.php" but it is not deleting the file.
Server is receving the request header in GET method :
GET /file2.php HTTP/1.1
instead of DELETE :
DELETE /file2.php HTTP/1.1
Does someone know why the delete method is not working? or how can I delete my file using DELETE method?
Most browser do not support DELETE as method parameter for <form ...>. Indeed it's not even part of the HTML specification:
The method and formmethod content attributes are enumerated attributes with the following keywords and states:
The keyword get, mapping to the state GET, indicating the HTTP GET method.
The keyword post, mapping to the state POST, indicating the HTTP POST method.
And here is some kind of explanation:
It seems that we currently do not understand how PUT and DELETE will be useful for HTML forms.
For DELETE, it's indeed easy to create a useful request. However, server implementations usually respond with 200 and a minimal response body ("deleted") or 204 (no content). So it's not clear how this can be used in a web application.
For PUT, it seems there's no real use case as long as the web page doesn't have full control over the payload, and also can set the content type.
Please consider removing this feature until there's a clearer understanding about what it's good for.
Frameworks like laravel provide method spoofing:
<input type='_method' value='DELETE' />
This will override the method of the request and will - for example - call a destroy function:
Route::delete('/items/{id}', 'ItemController#destroy');
If you don't use a framework, you can try to mimic this behaviour:
if($_SERVER['REQUEST_METHOD'] === 'DELETE' || (isset($_REQUEST['_method'] && $_REQUEST['_method'] === 'delete') {
...
}
Mozilla only specifies only GET and POST
I have 2 recommendations:
Use a POST to send data to your PHP code and handle it from there
Don't actually delete stuff that simple. Create some function that will just say it is deleted till after you are really sure it has to be gone

$_POST request in PHP how can i apply?

I want to know how to use POST request in PHP. I used $_REQUEST['text'] for getting data from url like http://localhost/data.php?text=ABCDEFGH but If i pass very long text than ERROR : Request-URI Too Long.
if(isset($_REQUEST['text'])){
$parsetext=$_REQUEST['text']; //get data here data > ABCDEFGH
}else{
echo "not valid";
}
Please any one tell me how to support long TEXT using POST request. I know that $_REQUEST is for both request GET & POST.
Regarding the error, you can check these links (I assume you've already seen this):
How do I resolve a HTTP 414 “Request URI too long” error?
Request-URI Too Large
And for your question: I want to know how to use POST request in PHP.
Create a form.
(I assume that the textbox from this form will get the long data that you want to POST).
<form method="POST" action="http://localhost/data.php">
<input type="text" name="input_text" />
<button type="submit">Submit</button>
</form>
Receive the data from the from input using the defined method on your form. In this case the method is POST and the url/file that will receive the submitted data is http://localhost/data.php.
if (isset($_POST['input_text'])) {
// Where input_text is the name of your textbox.
$text = $_POST['input_text'];
echo $text;
}
ERROR : Request-URI Too Long.
$_REQUEST, as you say, handles $_POST and $_GET methods is correct.
Regarding your question, even though you use $_REQUEST to get the data, in the background it use the $_GET method to catch the query string you pass with the url.
$_GET method has limit on size and this is the main reason why you encounter that error. Whereas $_POST method don't have limit: Is there a maximum size for content of an HTTP POST?.
Conclusion: Better not use $_REQUEST, use $_GET or $_POST specifically :D
First of all, read this Question/Answer, this will probably clear some things for you on the differences between POST and GET and what method you should use for your project.
Then, you should forget about the $_REQUEST and use either $_GET or $_POST. This will prevent some security issues that you'll probably run into if you keep using $_REQUEST. More on that in the PHP Manual
Next up, you should definitely switch to POST, instead of GET if you're passing large sets of data. Otherwise you have to modify your apache config and that is not recommended if you plan on releasing you code to the public.
-EDIT START-
You can even use POST within AJAX, if everything is on the same server.
-EDIT END-

Error decoding JSON input via json_decode

I'm writing my first web service, and I have a problem related to JSON data passing. I have my web service divided in two files: controller.php, which contains the service handler, and service.php, which contains the classes and methods to be served on request.
This is the acquisition fragment from controller.php:
public function atender() {
// pre-procesamos la petición
if (!empty($_POST)) {
if (!empty($_POST["class"]) && !empty($_POST["action"]) && !empty($_POST["function"])) {
$clase = ucwords($_POST["class"]);
$metodo = "{$_POST["action"]}{$this->obtenerMetodo($_POST["function"])}";
$id = (!empty($_POST["datos"]) ? stripslashes($_POST["datos"]) : null);
I can attend requests on both GET and POST mode (I use GET for methods not requiring authentication, like getCategories, getCategoryById, getProducts and getProductById. These are methods to get the dish categories and dishes in a sushi restaurant.)
For any of the GET requests, everything works like expected. My problem comes when I handle POST requests. I need to get all URL parameters in JSON, as this is to serve an iOS app, and JSON is the way we handle data to/from.
This is the processing fragment from service.php:
public function putUser($datos) {
if (!empty($datos)) {
$usuario = json_decode($datos);
$this->log .= implode("/", $usuario) . "\r\n";
In this case, $datos is the JSON-encoded data from the request. It's received as $id in controller.php (the code above). As it's my first web service, it's very probable I'm doing something really bad here, but I'm a bit blinded.
I've tried different variations of the service handling code. Using json_decode($datos, true) doesn't work either. I get
'Unexpected token <' as a response and, in raw form (using the advanced REST client from Google Chrome) it says: ''Warning: implode() [<a href='function.implode'>function.implode</a>]: Invalid arguments passed in /home/refine/public_html/sushigo/palma/service.php on line 344'.
I know SOAP is, usually, a better alternative to writing custom code like this but, for now, I need to stick with this code and implement a better alternative for my next project. Could you tell me what am I doing wrong?
The error message says, basically, that it is NOT a valid JSON - and such error messages are usually right.
Your error is somewhere in the sending / receiving code. Probably you send the JSON in one form and try to access it in some other way. Since I have no way of looking at the requests sent from the phone, I would guess that:
you send the data as application/json and try to receive it as an url encoded form. If you don't understand the difference, here's your problem.
you use stripslashes on the JSON data, which is wrong. UNLESS you have magic_quotes turned on, which would also be wrong (that is: both magic_quotes and stripslashes have to go).

PHP get PUT request body

I'm currently developing a Restful Json-API in PHP. I want to send a PUT-Request to items/:id to update a record. The data will be transferred as application/json.
I want to call the API with
curl -H "Content-Type: application/json" -X PUT -d '{"example" : "data"}' "http://localhost/items/someid"
On the server side, I'm not able the retrieve the request body. I tried
file_get_contents("php://input");
but this returns an empty string. Also a fopen()/fread() combination doesn't work.
When calling via POST, everything works great, I can read the json perfectly on the server side. But the API isn't Restful anymore. Does anyone have a solution for this? Is there another way to send and receive Json?
btw, I'm developing the API with the Slim Framework.
php://input is only readable once for PUT requests:
Note: A stream opened with php://input can only be read once; the stream does not support seek operations. However, depending on the SAPI implementation, it may be possible to open another php://input stream and restart reading. This is only possible if the request body data has been saved. Typically, this is the case for POST requests, but not other request methods, such as PUT or PROPFIND.
http://php.net/manual/en/wrappers.php.php
The Slim framework already reads the data upon request. Take the data from the Request object, into which it has been read.
On the server side, I'm not able the retrieve the request body. I tried file_get_contents("php://input");
You can only use file_get_contents( 'php://input', 'r' ); once per request. Retrieving its values will truncate the values as well, so if you call it twice, it'll return an empty string. Slim's request object contains the values you need, so:
<?php
$app = new Slim( );
$app->put( '/items/someid', function () use ( $app ) {
echo $app->request( )->put( 'example' ); // should display "data".
});
The example from the PHP manual uses fopen to access php://input in read mode. Have you tried doing it that way instead?
EDIT: The manual page for PHP:// says some stuff that seems to suggest that PUT data might not be available in some cases!
Note: A stream opened with php://input can only be read once; the
stream does not support seek operations. However, depending on the
SAPI implementation, it may be possible to open another php://input
stream and restart reading. This is only possible if the request body
data has been saved. Typically, this is the case for POST requests,
but not other request methods, such as PUT or PROPFIND.
I don't know where this will leave you regarding PUT processing. One page seems to say it's possible, the other seems to imply that it won't work under the wrong set of circumstances
I was reading the SLIM framework documentation the other day and it said that some browsers have problems with PUT and DELETE.
Excerpt:
Unfortunately, modern browsers do not provide native support for PUT requests. To work around this limitation, ensure your HTML form’s method is “post”, then add a method override parameter to your HTML form like this:
<form action="/books/1" method="post">
... other form fields here...
<input type="hidden" name="_METHOD" value="PUT"/>
<input type="submit" value="Update Book"/>
</form>
Source: http://www.slimframework.com/documentation/stable

Receiving and handling a GET request in PHP

I'm trying to replace RSS polling with PubSubHubbub on my site. I'm able to use the subscriber library that google offers to send the subscription request. From the code it looks like it sends a post request via cURL with the RSS URL and a callback URL.
So this is where I need some direction:
In order to complete the subscription request my callback URL has to receive a GET request and then echo back a value from the GET request along with a 200 response. How do I get the parameters from the GET request? Is the echo done again via cURL? If so what option should include the 200 response?
This very simple script should be a start:
echo $_GET["request_name"];
this will output the GET parameter request_name and (implicitly) send a 200.
It's also a good idea to explicitly declare a content type before echoing, to prevent the default content type (usually "text/html") from kicking in:
header("Content-type: text/plain");
Note that when echoing external data, you may need to sanitize the output first - if the for example the output format is HTML, you would want to do something like echo htmlspecialchars($_GET["request_name"]); to prevent Cross-Site Scripting.
There was recently a thread on the php-dev mailing list about this. The reason you can't access 'hub.challenge' in the $_GET superglobal is due to register_globals. Basically PHP cleans up any argument names before creating the superglobals. Any dots will be converted to underscores. It's looking to be 'fixed' in PHP 6, but not before due to BC issues.
Here's the thread about it.

Categories