293

Consider this form:

<form action="http://www.blabla.com?a=1&b=2" method="GET">
    <input type="hidden" name="c" value="3" /> 
</form>

When submitting this GET form, the parameters a and b are disappearing.
Is there a reason for that?
Is there a way of avoiding this behaviour?

miken32
  • 42,008
  • 16
  • 111
  • 154
  • They shouldn't disappearing, so I think we'll need to see your form. – UnkwnTech Jul 12 '09 at 13:12
  • 3
    Hi, Here is the full form, you can just create an HTML with this form and see that parameters I pass in the action are disppearing:
    –  Jul 12 '09 at 14:02
  • I posted a possible workaround using JavaScript here: http://stackoverflow.com/questions/3548795/html-form-why-action-cant-have-get-value-in-it/21874387#21874387 – Krisztián Balla Feb 19 '14 at 10:08
  • Same thing happens to me in android webview. – JSON Nov 23 '17 at 03:24

14 Answers14

330

Isn't that what hidden parameters are for to start with...?

<form action="http://www.example.com" method="GET">
  <input type="hidden" name="a" value="1" /> 
  <input type="hidden" name="b" value="2" /> 
  <input type="hidden" name="c" value="3" /> 
  <input type="submit" /> 
</form>

I wouldn't count on any browser retaining any existing query string in the action URL.

As the specifications (RFC1866, page 46; HTML 4.x section 17.13.3) state:

If the method is "get" and the action is an HTTP URI, the user agent takes the value of action, appends a `?' to it, then appends the form data set, encoded using the "application/x-www-form-urlencoded" content type.

Maybe one could percent-encode the action-URL to embed the question mark and the parameters, and then cross one's fingers to hope all browsers would leave that URL as it (and validate that the server understands it too). But I'd never rely on that.

By the way: it's not different for non-hidden form fields. For POST the action URL could hold a query string though.

Arjan
  • 22,808
  • 11
  • 61
  • 71
88

In HTML5, this is per-spec behaviour.

See Association of controls and forms - Form submission algorithm.

Look at "4.10.22.3 Form submission algorithm", step 17. In the case of a GET form to an http/s URI with a query string:

Let destination be a new URL that is equal to the action except that its <query> component is replaced by query (adding a U+003F QUESTION MARK character (?) if appropriate).

So, your browser will trash the existing "?..." part of your URI and replace it with a new one based on your form.

In HTML 4.01, the spec produces invalid URIs - most browsers didn't actually do this though...

See Forms - Processing form data, step four - the URI will have a ? appended, even if it already contains one.

brasofilo
  • 25,496
  • 15
  • 91
  • 179
xyphoid
  • 1,380
  • 10
  • 12
  • this mean: everything behind the `?` in the action url is removed? So what is, if the GET parameter in the action url contains the target, where the form should be processed? like: `action="index.php?site=search"`. I'm not sure, if putting the GET parameter in hidden input fields is an god idea. – The Bndr Aug 24 '17 at 13:09
  • what do you mean by per-spec @xyphoid? – AmiNadimi Mar 07 '18 at 10:38
  • @AmiNadimi: It means "in accordance with the specification". – recursive Jun 11 '19 at 18:35
15

What you can do is using a simple foreach on the table containing the GET information. For example in PHP :

foreach ($_GET as $key => $value) {
    $key = htmlspecialchars($key);
    $value = htmlspecialchars($value);
    echo "<input type='hidden' name='$key' value='$value'/>";
}

As the GET values are coming from the user, we should escape them before printing on screen.

Community
  • 1
  • 1
Efx
  • 287
  • 2
  • 2
5

You should include the two items (a and b) as hidden input elements as well as C.

Bernhard Hofmann
  • 10,321
  • 12
  • 59
  • 78
  • Yes, ofcourse I would do this if possible. But lets say I have parameters in query string and in hidden inputs, what can I do? –  Jul 12 '09 at 13:25
  • I think your only option is to parse the query string name/value pairs and produce hidden input fields. Maybe if you described a bit more around the context of the page and URL we might be able to suggest a working solution. – Bernhard Hofmann Jul 13 '09 at 14:30
  • Alternatively, take the data from the hidden form items, and add them to the URL and additional query parameters, then replace the form submit button with a simple anchor link, or a server `Location:` redirect if you don't want any interaction with the end user. – Jason Feb 28 '18 at 16:27
0

If you need workaround, as this form can be placed in 3rd party systems, you can use Apache mod_rewrite like this:

RewriteRule ^dummy.link$ index.php?a=1&b=2 [QSA,L]

then your new form will look like this:

<form ... action="http:/www.blabla.com/dummy.link" method="GET">
<input type="hidden" name="c" value="3" /> 
</form>

and Apache will append 3rd parameter to query

wanis
  • 35
  • 1
0

When the original query has array, for php:

foreach (explode("\n", http_build_query($query, '', "\n")) as $keyValue) {
    [$key, $value] = explode('=', $keyValue, 2);
    $key = htmlspecialchars(urldecode($key), ENT_COMPAT | ENT_HTML5);
    $value = htmlspecialchars(urldecode($value), ENT_COMPAT | ENT_HTML5);
    echo '<input type="hidden" name="' . $key . '" value="' . $value . '"' . "/>\n";
}
Daniel-KM
  • 174
  • 1
  • 1
  • 13
0

To answer your first question yes the browser does that and the reason is that the browser does not care about existing parameters in the action URL so it removes them completely

and to prevent this from happening use this JavaScript function that I wrote using jQuery in:

function addQueryStringAsHidden(form){
    if (form.attr("action") === undefined){
        throw "form does not have action attribute"
    }

    let url = form.attr("action");
    if (url.includes("?") === false) return false;
    
    let index = url.indexOf("?");
    let action = url.slice(0, index)
    let params = url.slice(index);
    url = new URLSearchParams(params);
    for (param of url.keys()){
        let paramValue = url.get(param);
        let attrObject = {"type":"hidden", "name":param, "value":paramValue};
        let hidden = $("<input>").attr(attrObject);
        form.append(hidden);
    }
    form.attr("action", action)
}
MRE20
  • 27
  • 4
0

My observation

  • when method is GET and form is submitted, hidden input element was sent as query parmater. Old params in action url were wiped out. So basically in this case, form data is replacing query string in action url

  • When method is POST, and form is submitted, Query parameters in action url were intact (req.query) and input element data was sent as form data (req.body)

So short story long, if you want to pass query params as well as form data, use method attribute as "POST"

user2298124
  • 341
  • 2
  • 7
0

Here's some simple JavaScript to keep your existing query strings when you submit your GET form. It uses the URL API which supported everywhere except IE.

const form = document.querySelector('form');

form.addEventListener('submit', (e) => {
  e.preventDefault();
  
  const form = e.currentTarget;
  const { action } = form;
  const to = new URL(action, location);
  const formData = new FormData(form);
  
  for (const [k, v] of formData.entries())
    to.searchParams.append(k, v);

  location.href = String(to);
});

The main drawback with this solution is that users with JavaScript disabled will fallback to having their form's action's existing query strings removed.

jason.
  • 319
  • 1
  • 7
-1

I had a very similar problem where for the form action, I had something like:

<form action="http://www.example.com/?q=content/something" method="GET">
   <input type="submit" value="Go away..." />&nbsp;
</form>

The button would get the user to the site, but the query info disappeared so the user landed on the home page rather than the desired content page. The solution in my case was to find out how to code the URL without the query that would get the user to the desired page. In this case my target was a Drupal site, so as it turned out /content/something also worked. I also could have used a node number (i.e. /node/123).

KillerRabbit
  • 173
  • 1
  • 8
-2

This is in response to the above post by Efx:

If the URL already contains the var you want to change, then it is added yet again as a hidden field.

Here is a modification of that code as to prevent duplicating vars in the URL:

foreach ($_GET as $key => $value) {
    if ($key != "my_key") {
        echo("<input type='hidden' name='$key' value='$value'/>");
    }
}
TH_
  • 97
  • 2
  • 9
-3

I usually write something like this:

foreach($_GET as $key=>$content){
        echo "<input type='hidden' name='$key' value='$content'/>";
}

This is working, but don't forget to sanitize your inputs against XSS attacks!

Rápli András
  • 3,869
  • 1
  • 35
  • 55
-3

Your construction is illegal. You cannot include parameters in the action value of a form. What happens if you try this is going to depend on quirks of the browser. I wouldn't be surprised if it worked with one browser and not another. Even if it appeared to work, I would not rely on it, because the next version of the browser might change the behavior.

"But lets say I have parameters in query string and in hidden inputs, what can I do?" What you can do is fix the error. Not to be snide, but this is a little like asking, "But lets say my URL uses percent signs instead of slashes, what can I do?" The only possible answer is, you can fix the URL.

Jay
  • 26,876
  • 10
  • 61
  • 112
  • This whole answer is technically correct ("its wrong, so fix it") but of no use whatsoever. The OP already knows something is wrong, and is here asking how to fix it. – Jason Feb 28 '18 at 16:20
  • I'm sorry, wasn't that clear? "You cannot include parameters in the action value of a form." To fix it, remove the parameters from the action value of the form. – Jay Feb 28 '18 at 17:22
  • @Jay The problem is clearly that the user needs the URL parameters to stay, so saying "remove them" isn't going to help – Chuck Le Butt Dec 12 '19 at 13:42
  • @ChuckLeButt Saying "but I need to do this thing that doesn't work" isn't a useful thing to say. If someone tells me, "I keep turning the radio knob but my car won't move", the only response I can think of would be to say, "Turning the radio knob doesn't make the car move. You have to turn the ignition key and push on the gas pedal." To reply, "but I need to make the car move by turning the radio knob" is an unproductive response. It doesn't work. It won't work. – Jay Dec 12 '19 at 15:21
-4
<form ... action="http:/www.blabla.com?a=1&b=2" method ="POST">
<input type="hidden" name="c" value="3" /> 
</form>

change the request method to' POST' instead of 'GET'.

Shashidhar Gr
  • 420
  • 2
  • 6
  • 15