Jump to content

Mixup between GET and POST


NotionCommotion

Recommended Posts

After wasting two hours investigating Apache and JavaScript which I suspected was redirecting my request, I realize my silly mistake.

 

Previously, I always hard coded an action in my forms.  I wish the form to be submitted to itself, and I recently started not including an action.

 

Well, it works fine until you have a variable in both GET and POST, and you wish to use that variable to make a decision.

 

Other than giving POST higher precedent than GET for this type of application, is there anything else I should have learned.


<?php
echo('<pre>'.print_r($_POST,1).'</pre>');
echo('<pre>'.print_r($_GET,1).'</pre>');
echo(isset($_GET['task'])?$_GET['task']:(isset($_POST['task'])?$_POST['task']:'default'));
echo('<hr>');
?>
<!DOCTYPE html>
<html>
    <head>
        <title>post and get</title>
        <meta charset="utf-8" />
    </head>

    <body>
        <a href="testget.php?task=display">Link</a>
        <form method="post">
            <input type="submit" id="save" value="Save" />
            <input type="hidden" name="task" value="save" />
        </form>
        <form method="post" action="">
            <input type="submit" id="save" value="Save" />
            <input type="hidden" name="task" value="save" />
        </form>
        <form method="post" action="testget.php">
            <input type="submit" id="save" value="Save" />
            <input type="hidden" name="task" value="save" />
        </form>
    </body>
</html>
Link to comment
Share on other sites

You shouldn't mix URL parameters and request body parameters at all.

 

It indicates that you don't really have a concept for what to put where. But it's actually very easy: URL parameters contain the data necessary for retrieving a resource. This includes IDs, page numers, search terms etc. On the other hand, request body parameters contain the data that should be changed or added like a new username, a new blog entry or whatever.

 

The URL parameter task=display makes no sense, because displaying a page is the one and only purpose of GET. Even the body parameter task=save is rather nonsensical, because saving changes is, again, the whole point of POST. So maybe you can fix the whole confusion simply by removing the superfluous parameter and checking the request method instead.

Edited by Jacques1
Link to comment
Share on other sites

You shouldn't mix URL parameters and request body parameters at all.....  URL parameters contain the data necessary for retrieving a resource. This includes IDs, page numers, search terms etc. On the other hand, request body parameters contain the data that should be changed or added like a new username, a new blog entry or whatever.

 

Not sure I understand.  If I am saving record id #321 for page #4 with new values for username and blogtext, are you saying that id and page (and task unless I default to “save” for post requests) should be in the url and username and blogtext should be in the body?

Link to comment
Share on other sites

$_GET values are meant to "get" data. So, if you have a page to display a product page you might have a URL such as showProduct.php?prod_id=55 because you want to "GET" the details for product 55. Get requests should not change data.

 

$_POST values are meant to "post" (submit) data to the server to do something with it (add/edit/delete). Post requests are meant to change data.

 

I'm guessing your "action" variable is used to determine what you are going to do. For example, I have some applications where all requests get run through a single core page which determines what actions I will take. Instead of setting the action directly through a POST/GET variable, you can dynamically determine the action based on what data you received.

 

Here's a page that gives a more thorough explanation. I didn't read the entire thing, so I can't say whether it is all 100% accurate.

Link to comment
Share on other sites

Thanks Psycho,

 

Note that your referenced page wasn't included.

 

I understand how GET requests should be used only for idempotent methods, and that is not what I am asking.  It is my understanding that a request is either GET or POST and not both.  But, my form displayed in my original post will populate both the GET and POST global variables.  Whether a variable is included in the action doesn't indicate whether it will use a GET or POST request, but it does determine whether the GET global which is rather confusing.

Link to comment
Share on other sites

I strongly recommend that you avoid terms like “GET parameters” or “POST parameters”. They make no sense and only cause confusion. Yes, I know that PHP has a $_GET and a $_POST superglobal, but that's nonsensical as well.

 

A request has a method, be it GET, POST, PUT, DELETE or whatever. Requests also have a body which may be empty (in the case of GET) or contain additional information (in the case of POST and PUT).

 

To retrieve a resource, a send a GET request to the URL where the resource is located. For example:

GET /blog-posts/321 HTTP/1.1

The exact format of the URL is irrelevant. Instead of using “pretty URLs”, you might as well put the ID into a URL parameter: id=321. That's entirely up to you as long as the URL uniquely identifies the resource.

 

To update a resource, you send a PUT (or POST) request to the URL where the resource is located:

POST /blog-posts/231 HTTP/1.1

What exactly should be changed is specified in the request body. The exact format of the body is, again, irrelevant. Could be JSON, could be XML, it doesn't matter. However, HTML forms typically use percent-encoded parameters, so the body may look like this:

author=NotionCommotion&text=Hello%20world!

So, yes, the ID goes into the URL, and the author and text go into the request body.

 

Now, for some strange reason the PHP people have decided to copy the URL parameters into a superglobal called “_GET” and put data from the parsed request body into a superglobal called “_POST”. This is plain nonsense, because the location of the parameters has nothing to do with the request method. A POST request may very well use URL parameters, which leads to the absurd situation that you have to pull them from the $_GET superglobal. There is no GET anywhere!

 

I guess there's some historical explanation for those names, but in practice, just accept it as a weird tradition. $_GET has nothing to do with GET requests, and $_POST has nothing to do with POST requests.

Edited by Jacques1
Link to comment
Share on other sites

  It is my understanding that a request is either GET or POST and not both.

 

It can be both.

<?php
echo '<pre>',print_r($_REQUEST, true),'</pre>';
?>

<form action='?id=321' method='post'>

    Name <input type="text" name="name" value="Fred" size="10">
    <input type="submit" name="btnSubmit" value="Submit">

</form>

which give this when the form is submitted

Array
(
    [id] => 321                    // from URL
    [name] => Fred                 // from posted form field
    [btnSubmit] => Submit          // from posted form field
)

However, in this instance, I would put the id in a hidden form field so everything is POSTed rather than have a mixture

Link to comment
Share on other sites

So, yes, the ID goes into the URL, and the author and text go into the request body.

 

Typically, I use the same form for editing an existing record and adding a new record, but use ID equal to zero for a new record.  So, you recommend putting id of 0 in the URL?  Also, if I had two forms on a given page who's action specified the same page/controller, I would need to also include a task in the URL and not the body?

 

Makes coding a little more intensive unless I use the $_REQUEST superglobal.  Previously, I had not used $_REQUEST since I wish to know exactly where it is coming from and didn't want it to include $_COOKIEs.  But maybe I should be using it?

Link to comment
Share on other sites

So, yes, the ID goes into the URL, and the author and text go into the request body.

 

Ah, I think I understand your position.  If I have a form with various parameters, put the ones which might change state in the body and put the rest in the URL (i.e. id, page, controller, task, CSRF, etc).

 

Correct?  Why do you recommend doing so?  Putting them all in the body allows them to be all accessed via the $_POST global.  Also, please provide your thoughts on using the $_REQUEST global.

Link to comment
Share on other sites

First: A request does not have multiple methods as suggested by Barand. There's no such thing in HTTP. The first line of a request specifies exactly one method (if the RFC is too abstract, you may also observe actual HTTP messages with your browser or a network sniffer).

 

I do not recommend the use of $_REQUEST. In fact, it's awful and should be avoided like the plague, because it blurs the line between different aspects of the request, can lead to name collisions and has major security implications. For example, if URL parameters take precedence over cookies, an attacker can easily perform session fixation and break the CSRF protection of your application.

 

There's a big difference between URL parameters, request body parameters and cookies, and throwing everything into one big array means asking for trouble. Like always: PHP makes it very easy to write bad code, but it makes you jump through hoops to write good code. :(

 

 

 

Typically, I use the same form for editing an existing record and adding a new record, but use ID equal to zero for a new record.  So, you recommend putting id of 0 in the URL?

 

No, send the request to the parent resource. In the previous example, that would be /blog-posts/. This is actually the original meaning of POST: It appends a new resource to a parent resource.

 

 

 

Ah, I think I understand your position.  If I have a form with various parameters, put the ones which might change state in the body and put the rest in the URL (i.e. id, page, controller, task, CSRF, etc).

 

No no no. The URL specifies the resource (like a blog post or a user). Think of it as a unique address pointing to an object.

 

In fact, the URL is usually the same for GET requests and POST requests. You may fetch /blog-posts/321, but you may also update /blog-posts/321.

 

Things like CSRF tokens are only relevant for updating the data, so they go into the request body. They have nothing to do with the resource itself.

Edited by Jacques1
Link to comment
Share on other sites

No no no. The URL specifies the resource (like a blog post or a user). Think of it as a unique address pointing to an object.

 

In fact, the URL is usually the same for GET requests and POST requests. You may fetch /blog-posts/321, but you may also update /blog-posts/321.

 

Things like CSRF tokens are only relevant for updating the data, so they go into the request body. They have nothing to do with the resource itself.

 

Good, I am glad you say so as I didn't agree with including all those parameters in the URL.

 

You indicate that page (blog-posts) and id (321) should be URL parameters as they identify the resource.  Okay, but so what?  Why not put them all in the body?

 

And what about task (typically only needed for Ajax requests when not display for GET requests or save for POST requests)?  I suppose it identifies a resource, but will be different for GET and POST requests.

Link to comment
Share on other sites

You indicate that page (blog-posts) and id (321) should be URL parameters as they identify the resource.  Okay, but so what?  Why not put them all in the body?

 

Because it wouldn't make sense, neither semantically nor practically.

 

The fact that the URL specifies the target of the request is one of the most fundamental principles of HTTP. This is how the protocol works, and this is how everybody and every program expect it to work (including servers, browsers, proxies, caches etc.). If you instead invent your own variation of HTTP where the URL of some methods is always “/” and the actual routing information is hidden somewhere in the body, you'll make a huge mess.

 

You'd also have to create a separate router specifically for POST requests. Why not simply use the same routing logic for all requests?

 

 

 

And what about task (typically only needed for Ajax requests when not display for GET requests or save for POST requests)?  I suppose it identifies a resource, but will be different for GET and POST requests.

 

Not sure what you mean. There's a special parameter for requests triggered through Ajax? Why?

 

Where a request comes from shouldn't matter at all. Of course you may sometimes need a special representation of a resource (like JSON instead of HTML), but this should be specified through the Accept header. No need for an extra URL.

 

My point is that a lot of your parameters and if statements and special cases will be unnecessary if you simply use standard HTTP. It's actually a very elegant protocol:

  • A resource is located at a specific URL.
  • You can do different things with a resource by using different methods (unfortunately, HTML is currently limited to GET and POST).
  • You can also request different representations of the resource (HTML, JSON, XML, ...) through the Accept header.
Edited by Jacques1
Link to comment
Share on other sites

I suppose I mostly agree with your rational.  One aspect which I am undecided is the id.  Unlike the file or page, it doesn't identify a resource, only a record in the database.

 

 

And what about task (typically only needed for Ajax requests when not display for GET requests or save for POST requests)?  I suppose it identifies a resource, but will be different for GET and POST requests.

 

Not sure what you mean. There's a special parameter for requests triggered through Ajax? Why?

 

Based on the page, I will create a controller object, and then evoke the the applicable task method using $controller->$task.  Do you disagree with this approach?  If so, why?

class controller_blog extends controller
{
    public function display()
    {
        //Displays page HTML based on get request
    }

    public function searchBlogs()
    {
        //Displays JSON list based on get request
    }

    public function addComment()
    {
        //Adds comment based on POST request.  Returns JSON or text to indicate status
    }

    public function addLike()
    {
        //Updates DB to indicate user likes blog based POST request.  Returns JSON or text to indicate status
    }

    public function logoff()
    {
        //Logs user off based on POST request.  Will really be a method in controller and not controller_blog
    }
}
Link to comment
Share on other sites

I suppose I mostly agree with your rational.  One aspect which I am undecided is the id.  Unlike the file or page, it doesn't identify a resource, only a record in the database.

 

This is a resource. There's a parent resource (e. g. the collection of all blog posts), and there are specific subresources identified by IDs (e. g. the blog post #321). So the ID clearly belongs into the URL.

 

On a site note: If you have any chance to implement “clean URLs” (like /blog-posts/321 instead of /some_script.php?controller=blog_posts&id=321), do that. It will greatly improve the readability for your users as well as the technical clarity for yourself. We probably wouldn't even have this discussion if there weren't all those parameters flying around.

 

 

 

Based on the page, I will create a controller object, and then evoke the the applicable task method using $controller->$task.  Do you disagree with this approach?  If so, why?

 

The approach is inflexible and unnecessarily complicated.

  • Instead of writing methods specifically for Ajax, keep them generic. Use the Accept header if you need a specific response format.
  • Use response codes instead of custom status texts. If you need additional information in a certain format, again check the Accept header.
  • Searching is just retrieving with an additional query. This could be unified.
  • As you already said, logging out has nothing to do with the blog page, so it shouldn't be there at all. Put it into the user controller (or any other appropriate location).

Purists would probably disagree with the whole idea of having different tasks, but I think this is OK. You could get rid of those special methods if you create separate resources for comments etc. and send standard requests to them, but this might be overkill.

Link to comment
Share on other sites

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.