If the user-supplied ID for an exposed filter includes a space, the filter will not work.

To reproduce using a clean install of D8 via the standard install profile:

  1. Go to: admin/structure/views/add, enter a view name, tick "Create a page," and click "Save and edit"
  2. Set the path for the page display to whatever you want
  3. Click the existing "Content: publishing status" filter to edit it, tick the "Expose this filter..." option
  4. Enter "has spaces" in the "Filter identifier" field, click "Apply" followed by "Save"
  5. Navigate to the path entered in step #2
  6. Set the "Published status" to "No" and click "Apply"

The URL will contain the correct value (eg: ?has+space=0) but the filter will not be applied and the default value of the filter on the subsequent page will be "Yes."

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

mikeker’s picture

Issue summary: View changes
mikeker’s picture

Status: Active » Needs review
Issue tags: +Needs tests
FileSize
3.46 KB

This fixes the problem in the UI by only allowing non-reserved characters in filter IDs. This is more restrictive than is technically necessary -- we should accept percent-encoded anything. But that doesn't work at the moment and seems like part of a larger issue.

This needs tests. Also, this could be an upgrade issue as I don't believe there was any restriction on filter IDs in D7 (unverified).

Lendude’s picture

Followed the steps to reproduce and could reproduce the issue.

Also, this could be an upgrade issue as I don't believe there was any restriction on filter IDs in D7 (unverified).

Checked and this is just as broken in D7, so don't know if that would be an issue.

+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -614,7 +614,7 @@ public function buildExposeForm(&$form, FormStateInterface $form_state) {
+      '#description' => $this->t('This will appear in the URL after the ? to identify this filter. Cannot be blank. Only letters, digits and the dot ("."), hyphen ("-"), underscore ("_"), and tilda ("~") characters are allowed.'),

Isn't ~ called a 'tilde'?

Adding a patch with just a test if the override for the identifier works. Will see if I can update that to fail when supplied with an identifier with spaces or other restricted characters.

Lendude’s picture

Here a version of the test only patch to illustrate the problem. The current version of the patch doesn't fix this, so that's something to look at.

Status: Needs review » Needs work

The last submitted patch, 4: 2342325-4-TEST-ONLY.patch, failed testing.

The last submitted patch, 4: 2342325-4-TEST-ONLY.patch, failed testing.

mikeker’s picture

Assigned: Unassigned » mikeker
+++ b/core/modules/views/src/Tests/Plugin/ExposedFormTest.php
@@ -82,6 +82,60 @@ public function testSubmitButton() {
+    $view->save();
+    $this->drupalGet('test_exposed_form_buttons', array('query' => array($random => 'article')));
+    $this->assertFieldById(str_replace(' ', '-', strtolower('edit-' . $random)), 'article', "Article type filter set with random identifier.");

This won't work. The fix in #2 prevents spaces and other illegal chars at the UI level. So we need to verify submitting the form with a space in that field raises an error.

Lendude’s picture

#7 good point. And instead of the manual str_replace/strtolower stuff I did, we should probably use Html::cleanCssIdentifier

amytswan’s picture

Assigned: mikeker » amytswan

Working with @mikeker at the PNW Drupal Summit - assigning this issue over to me.

amytswan’s picture

This patch combines #2 and #4. I'm going to apply suggestions from comments #3 and #7 now.

amytswan’s picture

amytswan’s picture

Status: Needs work » Needs review

Forgot to set it to "Needs review" - Doh!

The last submitted patch, 10: spaces_in_exposed-2342325-10.patch, failed testing.

Status: Needs review » Needs work

The last submitted patch, 11: spaces_in_exposed-2342325-11.patch, failed testing.

amytswan’s picture

I'm not sure what's wrong with the test, but I've got to leave this issue for now.

Lendude’s picture

Status: Needs work » Needs review
FileSize
10.21 KB
8.11 KB

Thanks for taking a look at this @amyvs!

Did a rewrite of this. Got rid of the strtolower stuff, got rid of some code duplication, added some tests for the validation rules (old and new).

The original test with the space inserted directly into the settings still fails though. Would have figuered that adding a validate() function to the handler would stop it, but that doesn't seem to to be the case.

Still needs work, but want to see what the testbot has to say so far.

Lendude’s picture

+++ b/core/modules/views/src/Tests/Plugin/ExposedFormTest.php
@@ -85,9 +85,68 @@ public function testSubmitButton() {
-  public function testResetButton() {
+  public function ptestResetButton() {

bleh, added this by mistake

Status: Needs review » Needs work

The last submitted patch, 16: spaces_in_exposed-2342325-16.patch, failed testing.

mikeker’s picture

+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -681,6 +662,42 @@ protected function buildGroupValidate($form, FormStateInterface $form_state) {
+  protected function validateIdentifier($identifier, FormStateInterface $form_state = NULL, &$form_group = array()) {

+1!

I like this approach much better than what I had in #2. While site builders add filter IDs via the UI, it would be easy to add an invalid ID via migrate, CMI, or something similar. I haven't had a chance to review the rest of the changes yet...

Thanks, @Lendude and @amyvs!

mikeker’s picture

Assigned: amytswan » Unassigned
mikeker’s picture

Assigned: Unassigned » mikeker
+++ b/core/modules/views/src/Plugin/views/filter/FilterPluginBase.php
@@ -1490,6 +1507,15 @@ public function getCacheTags() {
+  /**
+   * {@inheritdoc}
+   */
+  public function validate() {
+    if (!empty($this->options['exposed']) && $error = $this->validateIdentifier($this->options['expose']['identifier'])) {
+      return [$error];
+    }
+  }
+

The problem is that none of the classes that extend FilterPluginBase are calling parent::validate().

Working on a fix, though it may not happen this evening.

mikeker’s picture

Assigned: mikeker » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
10.62 KB
1.69 KB

OK, that didn't take nearly as long as I thought...

Attached patch fixes #21, cleans up the expected value for the validate test (I assume that was a leftover copy/paste?), and removes an extra space to meet Drupal coding standards. Let's see what the testbot says...

Lendude’s picture

Issue tags: +VDC
+++ b/core/modules/views/src/Plugin/views/filter/InOperator.php
@@ -415,7 +415,7 @@ protected function opEmpty() {
-    $errors = array();
+    $errors = parent::validate();

@mikeker Ah yeah! Good catch. And yes, the expected value in the test was just left over copy/paste that I hadn't bothered to clean up since the test wasn't doing what I wanted anyway, sloppy me.

Rechecked that Drupal\views\Plugin\views\filter\InOperator is indeed the only override of FilterPluginBase::validate() so no other methods need to be updated.

Looks good now. Would love to RTBC but wrote a bit to much of the patch to justify that. Adding VDC tag to maybe get some extra eyes on this.

dawehner’s picture

+++ b/core/modules/views/src/Tests/Plugin/ExposedFormTest.php
@@ -85,6 +85,69 @@ public function testSubmitButton() {
+    $random = $this->randomMachineName();
...
+    $random = $this->randomMachineName() . ' ' . $this->randomMachineName();

Let's not use a random string, but rather use a dedicated known bad value

Lendude’s picture

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Yeah exactly, thank you!

This issue doesn't really sounds problematic for a release. Feel free to add the 'rc target triage' if you want to.

The last submitted patch, 11: spaces_in_exposed-2342325-11.patch, failed testing.

The last submitted patch, 16: spaces_in_exposed-2342325-16.patch, failed testing.

The last submitted patch, 10: spaces_in_exposed-2342325-10.patch, failed testing.

Lendude’s picture

Issue tags: +rc target triage

per @dawehner in #26, +rc target triage

xjm’s picture

Issue tags: -rc target triage

Discussed with @effulgentsia and we don't think this change needs to be made during RC since it is fairly low impact. It looks like this would be okay during a patch release (it just adds a protected method and fixes internal behavior), so untagging and leaving RTBC for more thorough review after 8.0.0.

alexpott’s picture

What about existing views? Do we need to think about update paths here?

dawehner’s picture

Well sure, there is the chance that there are existing broken views out there, but in that case someone really entered something and then never actually tested the result on a real website.

mikeker’s picture

someone really entered something and then never actually tested the result on a real website

In both D7 and D8 you could enter a filter ID with a space in the UI but the filter would not work. To me, that suggests that it is not an upgrade issue but I defer to your judgement.

catch’s picture

So for existing views if you try to save via the UI, you'd get a validation error then have to fix it manually.

Since this isn't validated on the configuration entity itself, then it's not going to affect config sync or similar either way.

I think that makes sense in terms of upgrade path being a 'nice to have'. Longer term I'd expect us to be moving the validation out of the form handling though.

  • catch committed 42eb466 on 8.1.x
    Issue #2342325 by Lendude, mikeker, amyvs: Spaces in exposed filter ID...
catch’s picture

Status: Reviewed & tested by the community » Patch (to be ported)

Committed/pushed to 8.1.x, thanks!

This adds a protected method to a base class, which theoretically could conflict with an extending class in core or contrib.

Due to this, moving to 8.0.x for backport - we could underscore prefix the protected method and mark it @internal to get around the potential breakage. Or we can not backport and just let this be fixed in 8.1.x.

catch’s picture

Status: Patch (to be ported) » Fixed

Actually I'm going to mark this fixed - if someone wants to backport, then please change status.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.