Problem/Motivation

In PHP 8.3, strrpos() and strlen() have become more strict. In LeafletMap::getPopupContent(), when using #rendered_view_fields, the code passes a malformed render array or receives a NULL theme hook, leading to a cascade of errors. On large datasets (e.g., 25,000+ rows), this results in memory exhaustion due to the sheer volume of logs.
Two main errors occur:

Deprecated function: strrpos(): Passing null to parameter #1 ($haystack) of type string is deprecated in Drupal\Core\Theme\ThemeManager->render()

TypeError: strlen(): Argument #1 ($string) must be of type string, array given in Drupal\Component\Utility\Unicode::strlen()

#1 [internal function]: _drupal_error_handler(8192, 'strrpos(): Pass...', '/var/www/html/w...', 168)
#2 /var/www/html/web/core/lib/Drupal/Core/Theme/ThemeManager.php(168): strrpos(NULL, '__')
#3 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(497): Drupal\Core\Theme\ThemeManager->render(NULL, Array)
#4 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(510): Drupal\Core\Render\Renderer->doRender(Array, Object(Drupal\Core\Render\RenderContext))
#5 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(250): Drupal\Core\Render\Renderer->doRender(Array, Object(Drupal\Core\Render\RenderContext))
#6 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(141): Drupal\Core\Render\Renderer->doRenderRoot(Array, Object(Drupal\Core\Render\RenderContext))
#7 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(627): Drupal\Core\Render\Renderer->Drupal\Core\Render\{closure}()
#8 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(140): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#9 /var/www/html/web/modules/contrib/leaflet/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php(1271): Drupal\Core\Render\Renderer->renderInIsolation(Array)
#10 /var/www/html/web/modules/contrib/leaflet/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php(1110): Drupal\leaflet_views\Plugin\views\style\LeafletMap->getPopupContent('node', '1562', Object(Drupal\node\Entity\Node), Object(Drupal\views\ResultRow), 'en')
#11 /var/www/html/web/modules/contrib/leaflet/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php(1000): Drupal\leaflet_views\Plugin\views\style\LeafletMap->processEntityFeatures(Array, Array, Object(Drupal\views\ResultRow), Array, 'ski_point_coord...', 108, '', Array)
#12 /var/www/html/web/modules/contrib/leaflet/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php(941): Drupal\leaflet_views\Plugin\views\style\LeafletMap->processGeofield('ski_point_coord...', Array, Array, Array, 'google-roadmap', '', Array)
#13 /var/www/html/web/modules/contrib/leaflet/modules/leaflet_views/src/Plugin/views/style/LeafletMap.php(898): Drupal\leaflet_views\Plugin\views\style\LeafletMap->processResultsGroups(Array, Array, Array, Array, 'google-roadmap')
#14 /var/www/html/web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php(2213): Drupal\leaflet_views\Plugin\views\style\LeafletMap->render()
#15 /var/www/html/web/core/modules/views/src/ViewExecutable.php(1595): Drupal\views\Plugin\views\display\DisplayPluginBase->render()
#16 /var/www/html/web/core/modules/views/src/Plugin/views/display/DisplayPluginBase.php(2504): Drupal\views\ViewExecutable->render()
#17 /var/www/html/web/core/modules/views/src/ViewExecutable.php(1724): Drupal\views\Plugin\views\display\DisplayPluginBase->preview()
#18 /var/www/html/web/core/modules/views_ui/src/ViewUI.php(627): Drupal\views\ViewExecutable->preview('block_1', Array)
#19 /var/www/html/web/core/modules/views_ui/src/ViewPreviewForm.php(63): Drupal\views_ui\ViewUI->renderPreview('block_1', Array)
#20 /var/www/html/web/core/lib/Drupal/Core/Entity/EntityForm.php(107): Drupal\views_ui\ViewPreviewForm->form(Array, Object(Drupal\Core\Form\FormState))
#21 /var/www/html/web/core/modules/views_ui/src/ViewFormBase.php(42): Drupal\Core\Entity\EntityForm->buildForm(Array, Object(Drupal\Core\Form\FormState))
#22 [internal function]: Drupal\views_ui\ViewFormBase->buildForm(Array, Object(Drupal\Core\Form\FormState), 'block_1')
#23 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(528): call_user_func_array(Array, Array)
#24 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(370): Drupal\Core\Form\FormBuilder->retrieveForm('view_preview_fo...', Object(Drupal\Core\Form\FormState))
#25 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(625): Drupal\Core\Form\FormBuilder->rebuildForm('view_preview_fo...', Object(Drupal\Core\Form\FormState), Array)
#26 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(321): Drupal\Core\Form\FormBuilder->processForm('view_preview_fo...', Array, Object(Drupal\Core\Form\FormState))
#27 /var/www/html/web/core/lib/Drupal/Core/Controller/FormController.php(73): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\views_ui\ViewPreviewForm), Object(Drupal\Core\Form\FormState))
#28 [internal function]: Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#29 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#30 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(627): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#31 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(121): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#32 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#33 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(183): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#34 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(76): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1)
#35 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(53): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#36 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#37 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ContentLength.php(28): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#38 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(116): Drupal\Core\StackMiddleware\ContentLength->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#39 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(90): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#40 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#41 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#42 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/AjaxPageState.php(53): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#43 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/StackedHttpKernel.php(51): Drupal\Core\StackMiddleware\AjaxPageState->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#44 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(715): Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#45 /var/www/html/web/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#46 {main}";}, 7, , http://test/admin/structure/views/view/ski_lift_map/preview/block_1?_wra..., http://test/admin/structure/views/view/ski_lift_map/edit/block_1, 172.21.0.4, 1771343854)
[0.002614 ms] INSERT INTO "watchdog" ("uid", "type", "message", "variables", "severity", "link", "location", "referer", "hostname", "timestamp") VALUES (1, theme, Theme hook %hook not found., a:1:{s:5:"%hook";N;}, 4, , http://test/admin/structure/views/view/ski_lift_map/preview/block_1?_wra..., http://test/admin/structure/views/view/ski_lift_map/edit/block_1, 172.21.0.4, 1771343854)
[0.001469 ms] INSERT INTO "watchdog" ("uid", "type", "message", "variables", "severity", "link", "location", "referer", "hostname", "timestamp") VALUES (1, php, %type: @message in %function (line %line of %file) @backtrace_string., a:6:{s:5:"%type";s:19:"Deprecated function";s:8:"@message";O:25:"Drupal\Core\Render\Markup":1:{s:9:"*string";s:80:"strrpos(): Passing null to parameter #1 ($haystack) of type string is deprecated";}s:9:"%function";s:40:"Drupal\Core\Theme\ThemeManager->render()";s:5:"%file";s:61:"/var/www/html/web/core/lib/Drupal/Core/Theme/ThemeManager.php";s:5:"%line";i:168;s:17:"@backtrace_string";s:7839:"#0 /var/www/html/web/core/includes/bootstrap.inc(104): _drupal_error_handler_real(8192, 'strrpos(): Pass...', '/var/www/html/w...', 168)

Steps to reproduce

Create a View with Leaflet Map style.

Set "Popup Source" to #rendered_view_fields.

Use PHP 8.3 and Drupal 11.

(Optional) Use a large number of markers to see the memory exhaustion.

Proposed resolution

Ensure that the render array passed to renderInIsolation has a proper #markup key or a valid #theme hook. Added protection against NULL values in the theme suggestions array.

Remaining tasks

User interface changes

API changes

Data model changes

Issue fork leaflet-3574034

Command icon 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

just-me created an issue. See original summary.

just-me’s picture

Issue summary: View changes

just-me changed the visibility of the branch 3574034-deprecated-function-strrpos to active.

just-me’s picture

Hello,

During the execution of the getPopupContent method, the call to $this->view->rowPlugin->render($result) may return a render array where the #theme property is malformed.

Specifically, in certain configurations, the #theme array contains a NULL value as its last element (which should normally be the base hook). See the attached screenshot for a debugger inspection.

In PHP 8.3, this causes a cascade of issues because the core ThemeManager::render() method passes this value to strrpos(). Since PHP 8.3 no longer allows passing NULL to string functions, it triggers a Deprecated function notice or a TypeError. On large datasets (e.g., thousands of markers), this leads to massive watchdog logging and immediate memory exhaustion.

just-me’s picture

Assigned: just-me » Unassigned
Status: Active » Needs review
just-me’s picture

Issue summary: View changes
itamair’s picture

Status: Needs review » Postponed (maintainer needs more info)

hi @just-me thanks for reporting this ...
But I couldn't reproduce the problem that you arise.

In my testing Drupal Leaflet environments (PHP 8.3, Drupal 11, etc.) I never found/hit an invalid / malformed render array and my
$render_row['markup']['#theme'] always looks like the ones shown in the attached screenshots.

How could the $render_row result in an invalid render array, considering that $this->view->rowPlugin->render($result) would always return a string?
https://git.drupalcode.org/project/drupal/-/blob/11.x/core/modules/views...

It looks/seems generally working as designed, but would like from you a further clarification.
Could you provide more details on your detailed use case that generates what you describe?
"when using #rendered_view_fields, the code passes a malformed render array or receives a NULL theme hook, leading to a cascade of errors"

As the Steps to reproduce that you describe look indeed very generic and not generally true ... (normally it doesn't happen what you report: " the code passes a malformed render array or receives a NULL theme hook").

itamair’s picture

itamair’s picture

Status: Postponed (maintainer needs more info) » Fixed

Closing this, as no reply was added since my last request of more info.

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.