Skip to content

TypeErrors in UrlHelper #20189

@djmetzle

Description

@djmetzle

Opening an issue on advice from the forums:
https://forum.matomo.org/t/mediaanalytics-error-message/48642/2

Expected Behavior

No errors process tracking requests with array form GET parameters.

Current Behavior

We're seeing type errors.

Possible Solution

We are currently using a patch to work around the type error from utm get param arrays:

diff --git core/UrlHelper.php core/UrlHelper.php
index 1e51828977..1faf819c63 100644
--- core/UrlHelper.php
+++ core/UrlHelper.php
@@ -279,7 +279,7 @@ class UrlHelper
     {
         $nameToValue = self::getArrayFromQueryString($urlQuery);
 
-        if (isset($nameToValue[$parameter])) {
+        if (isset($nameToValue[$parameter]) && is_string($nameToValue[$parameter])) {
             return $nameToValue[$parameter];
         }
         return null;

Note that this probably breaks the tests around UrlHelper::getParameterFromQueryString:

array('x[]=', 'x', array('')),
array('x[]=1', 'x', array('1')),
array('x[]=y==1', 'x', array('y==1')),
array('?x[]=1&x[]=2', 'x', array('1', '2')),
array('?x%5b%5d=3&x[]=4', 'x', array('3', '4')),
array('?x%5B]=5&x[%5D=6', 'x', array('5', '6')),

But those tests enforce contradiction with the docblock return type!

* @return string|null Parameter value if found (can be the empty string!), null if not found.

This method should always return a string (not an array) in order to meet the documented interface.

Steps to Reproduce (for Bugs)

Tracking hits that include `utm` GET params in array format (which are not correct, but error out the tracker), such as
[2022-12-21 20:11:45] piwik.ERROR: Uncaught exception: TypeError: urldecode(): Argument #1 ($string) must be of type string, array given in /var/www/html/plugins/Referrers/Columns/Base.php:379 Stack trace: #0 /var/www/html/plugins/Referrers/Columns/Base.php(379): urldecode(Array) #1 
/var/www/html/plugins/Referrers/Columns/Base.php(417): Piwik\Plugins\Referrers\Columns\Base->detectCampaignFromString('utm_campaign[]=...') #2 /var/www/html/plugins/Referrers/Columns/Base.php(560): Piwik\Plugins\Referrers\Columns\Base->detectReferrerCampaignFromLandingurl("") #3 /var/w
ww/html/plugins/Referrers/Columns/Base.php(121): Piwik\Plugins\Referrers\Columns\Base->detectReferrerCampaign(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor)) #4 /var/www/html/plugins/Referrers/Columns/Base.php(267): Piwik\Plugins\Referrers\Columns\Base->getReferrerInfor
mation('', 'https://www.ifi...', 1, Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor)) #5 /var/www/html/plugins/Referrers/Columns/Keyword.php(35): Piwik\Plugins\Referrers\Columns\Base->getReferrerInformationFromRequest(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Vi
sitor)) #6 /var/www/html/core/Tracker/Visit.php(514): Piwik\Plugins\Referrers\Columns\Keyword->onNewVisit(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor), Object(Piwik\Tracker\ActionPageview)) #7 /var/www/html/core/Tracker/Visit.php(317): Piwik\Tracker\Visit->triggerHook
OnDimensions(Array, 'onNewVisit') #8 /var/www/html/core/Tracker/Visit.php(210): Piwik\Tracker\Visit->handleNewVisit(NULL) #9 /var/www/html/core/Tracker.php(172): Piwik\Tracker\Visit->handle() #10 /var/www/html/plugins/QueuedTracking/Queue/Processor/Handler.php(46): Piwik\Tracker->tra
ckRequest(Object(Piwik\Tracker\Request)) #11 /var/www/html/plugins/QueuedTracking/Queue/Processor.php(194): Piwik\Plugins\QueuedTracking\Queue\Processor\Handler->process(Object(Piwik\Tracker), Object(Piwik\Tracker\RequestSet)) #12 /var/www/html/plugins/QueuedTracking/Queue/Processor.
php(143): Piwik\Plugins\QueuedTracking\Queue\Processor->processRequestSets(Object(Piwik\Tracker), Array) #13 /var/www/html/plugins/QueuedTracking/Commands/Process.php(88): Piwik\Plugins\QueuedTracking\Queue\Processor->process() #14 /var/www/html/vendor/symfony/console/Symfony/Compone
nt/Console/Command/Command.php(257): Piwik\Plugins\QueuedTracking\Commands\Process->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #15 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(87
4): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #16 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(195): Symfony\Component\Console\Application
->doRunCommand(Object(Piwik\Plugins\QueuedTracking\Commands\Process), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #17 [internal function]: Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Inpu
t\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #18 /var/www/html/core/Console.php(135): call_user_func(Array, Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #19 /var/www/html/core/Access.php(670): Piwi
k\Console->Piwik\{closure}() #20 /var/www/html/core/Console.php(136): Piwik\Access::doAsSuperUser(Object(Closure)) #21 /var/www/html/core/Console.php(87): Piwik\Console->doRunImpl(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput
)) #22 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(126): Piwik\Console->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput)) #23 /var/www/html/console(32): Symfony\Component\Console\Applica
tion->run() #24 {main} {"exception":"[object] (TypeError(code: 0): urldecode(): Argument #1 ($string) must be of type string, array given at /var/www/html/plugins/Referrers/Columns/Base.php:379)","ignoreInScreenWriter":true} {"class":"Piwik\\ExceptionHandler","request_id":138}
Uncaught exception in /var/www/html/plugins/Referrers/Columns/Base.php line 379:                                                                                                                                                                                                            
urldecode(): Argument #1 ($string) must be of type string, array given                                                                        
#0 /var/www/html/plugins/Referrers/Columns/Base.php(379): urldecode(Array)                                                                                                                                                                                                                  
#1 /var/www/html/plugins/Referrers/Columns/Base.php(417): Piwik\Plugins\Referrers\Columns\Base->detectCampaignFromString('utm_campaign[]=...')                                                                                                                                              
#2 /var/www/html/plugins/Referrers/Columns/Base.php(560): Piwik\Plugins\Referrers\Columns\Base->detectReferrerCampaignFromLandingurl("")                                                                                                                                                      
#3 /var/www/html/plugins/Referrers/Columns/Base.php(121): Piwik\Plugins\Referrers\Columns\Base->detectReferrerCampaign(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor))
#4 /var/www/html/plugins/Referrers/Columns/Base.php(267): Piwik\Plugins\Referrers\Columns\Base->getReferrerInformation('', 'https://www.ifi...', 1, Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor))
#5 /var/www/html/plugins/Referrers/Columns/Keyword.php(35): Piwik\Plugins\Referrers\Columns\Base->getReferrerInformationFromRequest(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor))
#6 /var/www/html/core/Tracker/Visit.php(514): Piwik\Plugins\Referrers\Columns\Keyword->onNewVisit(Object(Piwik\Tracker\Request), Object(Piwik\Tracker\Visitor), Object(Piwik\Tracker\ActionPageview))
#7 /var/www/html/core/Tracker/Visit.php(317): Piwik\Tracker\Visit->triggerHookOnDimensions(Array, 'onNewVisit')                                                                                                                                                                             
#8 /var/www/html/core/Tracker/Visit.php(210): Piwik\Tracker\Visit->handleNewVisit(NULL)                                                                                                                                                                                                     
#9 /var/www/html/core/Tracker.php(172): Piwik\Tracker\Visit->handle()                                                                         
#10 /var/www/html/plugins/QueuedTracking/Queue/Processor/Handler.php(46): Piwik\Tracker->trackRequest(Object(Piwik\Tracker\Request))                                                                                                                                                        
#11 /var/www/html/plugins/QueuedTracking/Queue/Processor.php(194): Piwik\Plugins\QueuedTracking\Queue\Processor\Handler->process(Object(Piwik\Tracker), Object(Piwik\Tracker\RequestSet))
#12 /var/www/html/plugins/QueuedTracking/Queue/Processor.php(143): Piwik\Plugins\QueuedTracking\Queue\Processor->processRequestSets(Object(Piwik\Tracker), Array)
#13 /var/www/html/plugins/QueuedTracking/Commands/Process.php(88): Piwik\Plugins\QueuedTracking\Queue\Processor->process()                                                                                                                                                                  
#14 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Command/Command.php(257): Piwik\Plugins\QueuedTracking\Commands\Process->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#15 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(874): Symfony\Component\Console\Command\Command->run(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#16 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(195): Symfony\Component\Console\Application->doRunCommand(Object(Piwik\Plugins\QueuedTracking\Commands\Process), Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Outp
ut\ConsoleOutput))
#17 [internal function]: Symfony\Component\Console\Application->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#18 /var/www/html/core/Console.php(135): call_user_func(Array, Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#19 /var/www/html/core/Access.php(670): Piwik\Console->Piwik\{closure}()                                                                                                                                                                                                                    
#20 /var/www/html/core/Console.php(136): Piwik\Access::doAsSuperUser(Object(Closure))                                                                                                                                                                                                       
#21 /var/www/html/core/Console.php(87): Piwik\Console->doRunImpl(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#22 /var/www/html/vendor/symfony/console/Symfony/Component/Console/Application.php(126): Piwik\Console->doRun(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\Component\Console\Output\ConsoleOutput))
#23 /var/www/html/console(32): Symfony\Component\Console\Application->run()                                                                                                                                                                                                                 
#24 {main}                        

Fail to be processed.

Context

These are "bad" tracking hits, in the sense that utm_campaign[]=... are not technically correct, but we should not be failing hard on processing these hits. Specifically, these errors stall out processing while using the QueuedTracking plugin, and stall all processing of the queue, similar to matomo-org/plugin-QueuedTracking#192

Your Environment

  • Matomo Version: 4.12.3
  • PHP Version: 8.0.26
  • Server Operating System: Docker (alpine) (running on Fedora)
  • Additionally installed plugins:
    • CustomReports
    • MarketingCampaignsReporting
    • CustomAlerts
    • LogViewer
    • InvalidateReports
    • TasksTimetable
    • QueuedTracking
    • AbTesting
    • MediaAnalytics
    • FormAnalytics
    • Funnels
    • RollUpReporting
    • SearchEngineKeywordsPerformance
    • MultiChannelConversionAttribution
    • HeatmapSessionRecording
    • SEOWebVitals
    • UsersFlow
    • ActivityLog
    • WhiteLabel
    • Cohorts
    • AdvertisingConversionExport
    • LoginSaml
    • WooCommerceAnalytics
    • CustomVariables
    • GoogleAnalyticsImporter

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugFor errors / faults / flaws / inconsistencies etc.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions