Problem/Motivation
Currently drupal_get_query_array does't support a syntax like that 'http://domain.org?flag' because it sets the value
of flag to "". If drupal_http_build_query is called on this it is converted to 'http://domain.org?flag=' which is wrong.
Proposed resolution
Let drupal_get_query_array return what's expected.
Remaining tasks
Write tests, write a patch.
Original report by [robit8deb]
// Text of original report here.
(for legacy issues whose initial post was not the issue summary)
I have a scenario where a customer is using an external website in correlation with his drupal site. The external vendor is using poorly formatted urls that are getting (correctly) rewritten with and = sign at the end because it is expecting a value. For example, http:///foo.cgi?foo gets rewritten to http:///foo.cgi?foo=. I need to turn off this validation because the resulting url with the = sign at the end takes the user to page cannot be displayed.
I fixed this behavior on link cck fields using this patch:
http://drupal.org/node/1306352
However, the field that i am rewriting now is a Boolean field where, when on, gets rewritten to a link.
Please advise.
Comment | File | Size | Author |
---|---|---|---|
#64 | 1464244-64.patch | 2.18 KB | nikitagupta |
#63 | urlhelper-parse-nullify-values.patch | 2.19 KB | mennega |
#48 | url_equals_sign-1464244-48.patch | 2.1 KB | drasgardian |
#47 | url_equals_sign-1464244-47--FAIL.patch | 1.23 KB | drasgardian |
#45 | parse_query-1464244-45.patch | 2.29 KB | ahebrank |
Comments
Comment #1
dawehnerThe problem is that drupal_get_query_array('foo') doesn't return array('foo' => NULL) but array('foo' => '');
Regarding the issue in views: this first has to be fixed 8.x and then get's backported to 7.x and then should work in views.
Comment #2
dawehnerHere is a test, lets see whether it fails.
Comment #4
dawehnerSo here is a path with an actual fix.
Comment #5
robit8deb CreditAttribution: robit8deb commentedExcuse my ignorance, but what directory should i be in to run this patch?
Thanks!
Comment #6
bleen CreditAttribution: bleen commented#4 looks good:
RTBC
@robit8deb - for core patches always patch from your webroot. For contrib module patches always patch from the top-level of the module folder.
Comment #7
xjmComment #8
Dries CreditAttribution: Dries commentedThis needs a quick re-roll because the tests moved from
./core/modules/simpletest/tests/common.test
to./core/modules/system/tests/common.test
. Otherwise this patch looks good to me.Comment #9
tim.plunkettBecause it was just a file switch and no other conflicts, setting back to RTBC.
Comment #10
catchHmm the test added is a proper unit test, but CommonUrlUnitTestCase extends DrupalWebTestCase (which is right in the sense the existing tests aren't proper unit tests, but the name is very wrong). Could we put this into a new class that extends DrupalUnitTestCase? A bit scope creepy to rename CommonUrlUnitTestCase here but just removing the 'Unit' would probably do fine, follow works for me too though.
Comment #11
xjmTagging novice for the test cleanup catch describes in #10.
Comment #12
tim.plunketts/DrupalUnitTestCase/UnitTestBase, but yeah.
Comment #13
ryan.gibson CreditAttribution: ryan.gibson commentedComment #14
catchThanks! Committed/pushed to 8.x.
Comment #15
sunDid anyone care to verify whether this change is actually correct?
The equal sign is optional for query parameters.
For a query string
?foo
, PHP returns an empty string in$_GET['foo']
.Normally, all query parameter values are expected to be strings.
Comment #16
bleen CreditAttribution: bleen commented@sun I'm confused. What the use-case is for ?foo= with nothing after the equal sign. This is equivalent to ?foo is it not? In both cases $_GET['foo'] will have a value of empty string.
Comment #17
sunThat's correct. But this patch changed our own user space parser to not comply with that:
PHP's value of $_GET['foo'] is an empty string in both cases.
Comment #18
catchOK reverted in 8.x for now so we can discuss some more.
Comment #19
Niklas Fiekas CreditAttribution: Niklas Fiekas commentedI merged this into #1598564: Convert common.test to PSR-0 (before I noticed it had been reverted). Here's the class converted to PSR-0. In case this is to be committed again, use the PSR-0 variant straight away (for the added class)?
Comment #19.0
Niklas Fiekas CreditAttribution: Niklas Fiekas commentedAdd issue summary
Comment #20
lokapujyaComment #21
dimaro CreditAttribution: dimaro commented12: drupal-1464244-12.patch queued for re-testing.
Comment #30
nikunjkotechaI think this is good to be closed now (outdated), function in reference (drupal_get_query_array) is removed - check https://www.drupal.org/node/1597784
Comment #33
rwam CreditAttribution: rwam commentedHm, but why I have this problem with current version 8.5.4 again? Or 8.5.x? I don't know how long this error exists because it was only reported today. I render a link field with external urls with
{{ content.field_external_url.0.['#url'] }}
This worked in the past, but now I get a trailing equal sign for a link of type http://domain.org/?flag. And this leads to an 404 on the external page.
I had to change to
{{ content.field_external_url.0.['#url'].uri }}
This works for me because I'm using external links only. But I don't know how if it works for internal links too.
Comment #34
rwam CreditAttribution: rwam commentedHi @all,
please have a look at this. There are more issues reporting by users now with the same wrong behavior. And I cannot fix it because of using default link formatter.
You can reproduce it with
http://www.domain.org/?flag
http://www.domain.org/?flag=
Argh – how can I fix this?
Ciao
Ralf
Comment #35
rwam CreditAttribution: rwam commentedComment #36
rwam CreditAttribution: rwam commentedI can fix the problem mentioned above by applying attached patch. But I think it could be a problem in future versions too. The @todo at UrlHelper::buildQuery() prefers the use of php build in http_build_query() but if I use this the same issue exists again.
The patch are usable for the 8.6.x and 8.7x branches too. What do you think?
Comment #38
MadSciencePro CreditAttribution: MadSciencePro as a volunteer commentedI'm running into the same issue with 8.5.5. It looks like the code from #36 is in Core now, but I'm still getting the added "=".
Comment #39
mpdonadioWe should have a test to demonstrate the problem and to prevent regressions in the future.
Comment #41
herzbube CreditAttribution: herzbube commentedI strongly believe that the patch in #36 is not correct!
First of all, it must be possible to distinguish between 1) valueless query parameters (
?foo
), and 2) query parameters whose value is an empty string (?foo=
). The original code, which usedisset()
, made that distinction possible, but the patched code, which usesempty()
, makes the distinction impossible. The patch therefore is no solution at all, it simply shifts the problem. Before the patch, all occurrences of 1) were wrong, but 2) were correct. After the patch, all occurrences of 1) are correct, but 2) are now incorrect. Example: After the patch,http://www.example.com/cgi-bin/foo.cgi?bar=
will be processed intohttp://www.example.com/cgi-bin/foo.cgi?bar
, i.e. the "=" character is omitted.Second, and this is even worse,
empty()
treats all kinds of values as "empty". According to the PHP docs (does anybody read the docs?) a variable is considered empty "[...] if its value equals FALSE." This means that the patch causes some query parameter values, which happen to be equal to PHP's definition of FALSE, to be omitted. Example:http://www.example.com/cgi-bin/foo.cgi?bar=0
would be processed intohttp://www.example.com/cgi-bin/foo.cgi?bar=
because the query parameter value 0 is, of course, equal to FALSE.The root of the problem, in my opinion, is not
UrlHelper::buildQuery()
, it is the use of the PHP functionparse_str()
inUrlHelper::parse()
. I believeparse_str()
is the wrong function to use, because it does not distinguish between valueless query parameters (?foo
) and query parameters whose value is an empty string (?foo=
) - it produces the same result for both. As long asparse_str()
is used to break down a query string into its parts, it is therefore simply impossible to correctly reassemble the query string later on.Also check out the discussion in issue 2987114, maybe the issue helps to understand where
parse_str()
was introduced.Comment #42
robindh CreditAttribution: robindh at Anvil commentedAfter looking for the root cause of this bug (before I stumbled onto this issue), I came to roughly the same conclusion as herzbube;
parse_str()
loses too much information about the query string. There is no way to distinguish a valueless query string and an empty-valued query string after this function has been executed.Ideally
NULL
should be returned as value, when dealing with valueless query string parameters.As a workaround, I've introduced https://github.com/thephpleague/uri-query-parser in my project and I've replaced the
parse_str
code inUrlHelper::parse()
with something like this:Comment #45
ahebrank CreditAttribution: ahebrank commentedFor my purposes (where the extra `=` causes a 404!), replacing parse_str with GuzzleHttp\Psr7\parse_query corrects this problem.
Adding a related issue since parse_str is messed up in other ways.
Comment #47
drasgardian CreditAttribution: drasgardian at Eighty Options commentedAttached patch adds test coverage for this issue.
But there seems to be other areas where the test coverage is checking for the opposite behaviour, as indicated in the failed tests on #45.
e.g. in UrlRewritingTest.php there is a test for this:
Which originates here: https://www.drupal.org/project/drupal/issues/2276203#comment-9289445
Why would that code be expecting the = to be added?
Comment #48
drasgardian CreditAttribution: drasgardian at Eighty Options commentedUpdated patch which is a lighter approach to a fix, based on #45.
Only using GuzzleHttp\Psr7\parse_query for external urls as that is where the added equals sign can cause 404s. PHP should treat ?foo and ?foo= the same, so not changing the processing of the internal urls, which avoids the problems with the failing tests in #45.
Comment #49
drasgardian CreditAttribution: drasgardian at Eighty Options commentedComment #50
porchlight CreditAttribution: porchlight as a volunteer and at Northern Commerce commented#48 worked for me.
Comment #51
CalamityJen#48 worked for me as well -thank you!
Comment #52
drasgardian CreditAttribution: drasgardian at Eighty Options commented@porchlight, @calamityjen perhaps you could mark as RTBC to help this progress towards being committed?
https://www.drupal.org/docs/develop/issues/fields-and-other-parts-of-an-...
Comment #53
porchlight CreditAttribution: porchlight as a volunteer and at Northern Commerce commentedComment #55
robpowellLet's see if these pass with a rerun of the tests.
Comment #56
SpokjeSeems to have tests, so removed needs test tag
Comment #57
drasgardian CreditAttribution: drasgardian at Eighty Options commentedTests passed on a re-run so setting back to RTBC.
Comment #58
quietone CreditAttribution: quietone as a volunteer commentedI notice that the proposed resolution in the IS does not match what is in the patch. Can that be updated?
Comment #59
catchComment #60
dawehnerTwo thoughts/questions:
core/lib/Drupal/Component/Utility/composer.json:17
Comment #61
alexpottWe definitely need to add the dependency as per #60
Also the docs to the Guzzle function say:
I wonder if this will have any unintended impacts. Making a change like this is really hard because of all of the unknowns.
Comment #62
alexpottMore on #61...
That's quite a big difference in output for the same input. Does this matter... not sure.
For me we should do the solution in #3038774-31: Url only outputs the last value of a query parameter and not parse and alter the external uri at all. That would mean we could also fix #2984272: Dots in query parameter names converted to underscores too.
Comment #63
mennega CreditAttribution: mennega as a volunteer commentedComment #64
nikitagupta CreditAttribution: nikitagupta at Srijan | A Material+ Company for Drupal India Association commentedComment #66
quietone CreditAttribution: quietone as a volunteer commentedThe patch in #64 still applies to Drupal 9.3.x, Changing version.
Needs work for #60 and #61 and still needs an Issue Summary Update.