Views exposed form doesn't handle non-array values correctly, where an array is expected ("Allow multiple selections")

Created on 22 July 2024, about 2 months ago
Updated 12 August 2024, 27 days ago

Problem/Motivation

Views exposed filters allow multiple selections using the "Allow multiple selections" checkbox.

This can for example be tested using a filter on a node content type, which then allows filtering using multiple checkboxes for the different node types.

In the form this leads to an array structure like
type[] = article
type[] = page

using GET to submit the form, you can even make that visible.

The problem is that Views Exposed Filters expect the given parameter "type" to be an array (type[]) and nothing else (e.g. type=) and fails with an exception indirectly:

LogicException: Cannot create key "article" on non-array value. in Drupal\Component\Utility\NestedArray::setValue() (line 154 of core/lib/Drupal/Component/Utility/NestedArray.php).

LogicException: Cannot create key "article" on non-array value. in Drupal\Component\Utility\NestedArray::setValue() (line 154 of core/lib/Drupal/Component/Utility/NestedArray.php).

Drupal\Core\Form\FormBuilder->handleInputElement() (Line: 999)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 1069)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 1069)
Drupal\Core\Form\FormBuilder->doBuildForm() (Line: 579)
Drupal\Core\Form\FormBuilder->processForm() (Line: 326)
Drupal\Core\Form\FormBuilder->buildForm() (Line: 134)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm() (Line: 1297)
Drupal\views\ViewExecutable->build() (Line: 393)
Drupal\views\Plugin\views\display\PathPluginBase->execute() (Line: 198)
Drupal\views\Plugin\views\display\Page->execute() (Line: 1689)
Drupal\views\ViewExecutable->executeDisplay() (Line: 81)
Drupal\views\Element\View::preRenderViewElement()
call_user_func_array() (Line: 113)
Drupal\Core\Render\Renderer->doTrustedCallback() (Line: 870)
Drupal\Core\Render\Renderer->doCallback() (Line: 432)
Drupal\Core\Render\Renderer->doRender() (Line: 248)
Drupal\Core\Render\Renderer->render() (Line: 238)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 638)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 231)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare() (Line: 128)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse() (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray()
call_user_func() (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch() (Line: 186)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 53)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle() (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle() (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass() (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle() (Line: 50)
Drupal\ban\BanMiddleware->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 49)
Drupal\remove_http_headers\StackMiddleware\RemoveHttpHeadersMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 741)
Drupal\Core\DrupalKernel->handle() (Line: 19)

Such exceptions then fill up the logs and can be provoked from third party by URL.

The following URL would be the correct URL:
https://www.example.com/search?search=test&type[]=article

The following URL leads to the described exception:
https://www.example.com/search?search=test&type=article

Steps to reproduce

See above

Proposed resolution

Having a scalar value instead of the expected array should be handled more gracefully.
Ensure to validate the given value to be an array in form validation or other input validation, so it's not getting processed on lower levels running into lower level exceptions.

Also consider that when using a GET form, the parameter might also be changed / manipulated on the user-side. (intentionally or unintentionally)

We could also discuss if a scalar value is given, it should just be transformed into an array value to simplify handling, but I'm not sure if that's a good or a bad idea.

Remaining tasks

  1. Discuss
  2. Implement a fix
  3. Write test
  4. Review
  5. Release

User interface changes

None

API changes

None

Data model changes

None

Release notes snippet

πŸ“Œ Task
Status

Active

Version

11.0 πŸ”₯

Component
ViewsΒ  β†’

Last updated about 11 hours ago

Created by

πŸ‡©πŸ‡ͺGermany Anybody Porta Westfalica

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Anybody
  • πŸ‡©πŸ‡ͺGermany Anybody Porta Westfalica
  • πŸ‡³πŸ‡ΏNew Zealand quietone New Zealand
  • πŸ‡³πŸ‡±Netherlands Lendude Amsterdam

    How would you get these 'wrong' URLs? Manually I would guess? Or is there some way that these are generated through Drupal?

    Making this a little more robust makes sense, but doesn't feel like a bug unless Drupal generates these URLs sometimes.

  • πŸ‡©πŸ‡ͺGermany Anybody Porta Westfalica

    Thanks for the reply @Lendude! We had these log entries popping up, it seems it's caused by hacking attempts or some kind of crawlers / spiders. We're not generating these links and I'm really unsure how this happens, but I don't think it's by humans. So I'd still consider the result to be kind of a bug.

  • πŸ‡©πŸ‡ͺGermany pminf Nuremburg (Germany), formerly Dresden

    Since the update to Drupal 10.3, these errors are also occurring for us according to the log. I also don't know how to reproduce them, except by customizing the URL.

Production build 0.71.5 2024