Problem/Motivation
Calling drupal_http_build_query() --or another function like url() which calls drupal_http_build_query-- with some empty params adds extra ampersand signs. Take a look at next code:
$q = array(
'action' => 'search',
'filter' => array(
'name' => array(),
'city' => array(),
'location' => array(),
),
'page' => 10,
);
echo drupal_http_build_query($q);
++++++ sample for for Drupal 11
use Drupal\Component\Utility\UrlHelper;
echo UrlHelper::buildQuery($q);
This displays
action=search&&&&page=10
and you notice that 3 extra amps are added. I know this is because name, city and location are empty but this can happen often if you are making some complex filters.
PHP http_build_query() handles well these empty arrays but drupal don't. With PHP http_build_query we get
action=search&page=10
which is correct.
Steps to reproduce
Proposed resolution
Modify buildQuery to ignore empty arrays and NULL valiues.
--- original proposal ---
To fix this we have to check if $params is empty or not before implode. Please check patch:
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -489,7 +489,8 @@ function drupal_http_build_query(array $query, $parent = '') {
}
}
- return implode('&', $params);
+ $params = array_filter($params);
+ return empty($params) ? NULL : implode('&', $params);
}Remaining tasks
Review
Commit
User interface changes
API changes
Data model changes
Release notes snippet
| Comment | File | Size | Author |
|---|---|---|---|
| #65 | 1425588-65.patch | 1.87 KB | abhaypai |
| #65 | interdiff_57-65.txt | 1.71 KB | abhaypai |
| #57 | 1425588-57.patch | 2.67 KB | quietone |
| #57 | 1425588-57-fail.patch | 973 bytes | quietone |
| #57 | interdiff-43-57.txt | 3.15 KB | quietone |
Issue fork drupal-1425588
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #1
ptocheia commentedI've verified that this is a bug. The patch looks promising, please attach it for testing!
Comment #2
webkenny commentedNice patch. I'm merely converting the code to patch format and queuing for testing. Also confirming this works but I won't RTBC it since I'm the one submitting it.
Comment #3
lslinnet commentedHave reviewed the code and tested the implementation, it works as expected.
Also good to see that it doesn't strip out empty variables like
Reason for this is that some web services require that you pass all parameters even if they are empty, taking an example "p1=&q=123213" is valid and is in some cases required by the receiving server.
Comment #4
webchickThanks for the fix! Let's add a test here to prove the fix works.
Also, patches go into D8 first, then are backported to D7, so bumping to D8.
Comment #5
webkenny commentedRight, right. Forgot about that piece. :) I haven't the slightest idea how to code a test. Sounds like I have a project to do. I'll work on it.
Comment #6
webkenny commentedOk, so I am attaching this here so I don't lose it but here's the D8 version. Still needs a test. Working on that now.
Comment #7
webkenny commentedSo far the following test has failed but i am continuing to check into it:
I have to assume this is just my newness to writing tests. I'll post back when I have something.
Comment #8
lslinnet commentedYour test assertion assumes that it should be empty correct output would be a=1&b=&c=3
Comment #9
Sorin Sarca commentedFor
array('a' => '1', 'b' => NULL, 'c' => '3')the correct output isa=1&b&c=3which I thinnk is equivalent witha=1&b=&c=3since for both the output of the following code is the same:Output:
Because of this I thinks we should also change the line
with
to remove "=" when no value OR
we should modify the line
with
to always have "=".
(OR of course we can leave it as is because there is no difference between them)
Comment #10
cweagansUpdating tags per http://drupal.org/node/1517250
Comment #11
cgreaten commentedSpoke with chx in IRC and he confirmed this is the desired behavior. See the attached test and fix files.
Comment #13
tim.plunkettReading http://en.wikipedia.org/wiki/Query_string:
So it looks like we got this one wrong. Either ?a=1&b=&c=3 or ?a=1&b&c=3 are valid, but ?a=1&c=3 is not valid.
Comment #14
Melissamcewen commentedSo in the test that is in the newest patch for
the result should be a=1&b[c]&b[d]&e=2&f?
Comment #15
cgreaten commentedBoth having an equals sign and not having an equals sign for empty string parameters seem to be valid. Uploading both variations of the patch to determine which will break the least amount of code in core.
Comment #16
cgreaten commentedComment #18
tim.plunketthttp://example.com/node/123?foo= is VERY weird.
Comparing a=1&e&f=2 and a=1&e=&f=2, I think we definitely want the former.
Unfortunately, that means debugging why _openid_get_params() is blowing up.
Comment #19
tim.plunkettchx demonstrated that a pure HTML form includes the = sign, and it's required for OpenID.
Comment #21
cgreaten commentedAlright. I think I have the test created and bug fixed. I have attached the test for this bug and also the bug fix as well as the test fixes.
Comment #22
cgreaten commentedAlright. I think I have the test created and bug fixed. I have attached the test for this bug and also the bug fix as well as the test fixes.
Comment #23
tim.plunkettThis had chx's input at MWDS, and I think Chris nailed it here.
Comment #24
jcfiala commentedJust a note...
I'm actually working on a link bug http://drupal.org/node/1710578 where the user has a url he's entering - 'http://www.example.com/?something' and I'm outputting 'http://www.example.com/?something=', the latter of which breaks what he's trying to point at. I'm currently able to fix this by setting the query array so that it's array('something' => NULL), but this change would break that. I realize that for PHP, the querystrings are equivalent, but that may not be true in all languages, would it?
Comment #25
tim.plunkettThen he can parse it differently. They are equivalent in HTTP.
Comment #26
jcfiala commentedHe doesn't have any control over the target's processing in this case, but if they're equivalent in HTTP, then that's fine. Just pointing out that it could cause trouble for someone else.
Comment #27
damien tournoud commentedThis
array_filter()feels sloppy (it removes any falsish value by default, aka NULL, '', 0, '0', etc.). If I understand this correctly, we are just removing the special caseelseif (!isset($value))and checking that we don't add an entry if the sub-query is empty. So the whole function could read:That cannot possibly be the intention of the test? This clearly only passes by chance (because it does a
assertText()which is a substring match).We likely want something like:
Comment #28
Sorin Sarca commentedThat's true.
But can be done without auxiliary variable:
Comment #29
damien tournoud commentedNo, because the sub-array could contain empty sub-sub-arrays.
Comment #30
Melissamcewen commentedYes, the test written by cgreaten contains an array with an empty array and I don't think it would pass without the auxiliary variable.
Comment #31
cgreaten commentedThis evening I applied the test I originally wrote to prove there was a bug and then applied Damien's proposed code. When I ran the test, it failed. The reason it failed is that '&d=' was added to the query string for the d => NULL portion of the array in the test. In the patch I submitted, that portion of the query string is left out (and I think correctly).
I am happy to re-roll my patches again or make changes, if needed. Sorry I'm not quite sure what the process is from here (it's my first attempt at contributing to the community).
Comment #32
cgreaten commentedAlright, I took a bit of time tonight and I tweaked Damien's code so it passes the test. I also used his feedback to modify the test in the GotoTest to be better. With the tests that are in UrlTest tests, I added a test for '' along side the NULL so that both are there instead of just changing the NULLs to '' so that the tests pass.
This patch can be reviewed and then compared to my first one to see which is preferable (or whether we want some kind of hybrid of the two).
Comment #35
mgiffordGotoTest.php is no longer there and patch no longer applies.
Comment #36
Sawascwoolf commentedHi,
I don't know how to create a patch, but here is my code suggestion:
In my tests this function returns the expected Results.
Comment #37
tim.plunkettCreating a patch built on #36 just to show which unit tests fail.
@Sawascwoolf, https://www.drupal.org/patch should help with patch creation if you'd like to learn!
Comment #40
MixologicThe phpunit test that failed might have more information with this patch - its identical to #37 with the exception to the change to the simpletest module, but probably with more information
Comment #41
MixologicHow come everybody but me remembers to mark it needs
workreview?Comment #42
marvin_b8 commentedA problem is that
array(array('a' => '1', 'b' => array('c' => array()), 'd' => NULL, 'e' => '', 'f' => '2'), 'a=1&e=&f=2', 'Empty query parameter values are properly ignored.'),
and
array(array('foo' => NULL), 'foo', 'Simple parameters are properly added.')
this two tests are not right.
see:
'd' => NULL = ''
'foo' => NULL = foo
and this can not work.
We need a clear behavior for this function .
Comment #43
tim.plunkettSo there should be no 'd'
@marvin_B8, it's really hard to see what changed from one patch to the other without an interdiff
Comment #47
Sawascwoolf commentedI think we should consider the testcases a bit more precisely.
We should use http_build_query to generate test cases!
With the following code I've created the test cases:
The test-cases
And here is my current version:
I don't have much time right now to learn the patch-system, if I'm going on to contribute I will learn it.
Comment #48
Sawascwoolf commentedI'm not sure right now if it is really desired to use the http_build_query() as reference.
Is there a need for passing:
Assume a form with a huge amount of checkboxes, with the current version every checkbox-value is added to the query string with value=0, this results in really long query-strings which don't hold information.
I suggest to ignore the values (see list above) and don't append anything at all for this case.
As this could cause notices of type
Undefined index:it must be discussed if it should be backported to D7 in this way.Comment #57
quietone commentedUpdated IS and rerolled patch.
Comment #65
abhaypai commentedLanding here from Bug smash initiative.
Few updates from end:
Comment #66
abhaypai commentedUpdating status to Needs Review after test run:
Need some advice or suggestion for following doubts.
elseif (!isset($value)) {i didnt change line for this and its giving errorcore/tests/Drupal/Tests/Component/Utility/UrlHelperTest.php passedWill create MR, once above issue is addressed.
Comment #67
smustgrave commentedThink it's saying your change caused that check to be redundant. So may need to look at the solution and make sure.
Comment #70
dcam commentedI added #65 to the MR.