قرینه از
https://github.com/matomo-org/matomo.git
synced 2025-08-24 16:07:37 +00:00
545 خطوط
23 KiB
PHP
545 خطوط
23 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license https://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*/
|
|
|
|
namespace Piwik\Tests\Integration\Tracker;
|
|
|
|
use Piwik\Config;
|
|
use Piwik\Plugins\SitesManager\API;
|
|
use Piwik\Tests\Framework\Fixture;
|
|
use Piwik\Tests\Framework\Mock\FakeAccess;
|
|
use Piwik\Tracker\Action;
|
|
use Piwik\Tracker\ActionPageview;
|
|
use Piwik\Tracker\PageUrl;
|
|
use Piwik\Tracker\Request;
|
|
use Piwik\Plugin\Manager as PluginManager;
|
|
use Piwik\Tests\Framework\TestCase\IntegrationTestCase;
|
|
|
|
/**
|
|
* @group Core
|
|
* @group ActionTest
|
|
*/
|
|
class ActionTest extends IntegrationTestCase
|
|
{
|
|
public function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
|
|
$section = Config::getInstance()->Tracker;
|
|
$section['default_action_url'] = '/';
|
|
$section['campaign_var_name'] = 'campaign_param_name,piwik_campaign,matomo_campaign,utm_campaign,test_campaign_name';
|
|
$section['action_url_category_delimiter'] = '/';
|
|
$section['campaign_keyword_var_name'] = 'piwik_kwd,matomo_kwd,utm_term,test_piwik_kwd';
|
|
Config::getInstance()->Tracker = $section;
|
|
|
|
PluginManager::getInstance()->loadPlugins(array('Actions', 'SitesManager'));
|
|
|
|
Fixture::loadAllTranslations();
|
|
}
|
|
|
|
public function tearDown(): void
|
|
{
|
|
parent::tearDown();
|
|
|
|
Fixture::resetTranslations();
|
|
}
|
|
|
|
protected function setUpRootAccess()
|
|
{
|
|
FakeAccess::$superUser = true;
|
|
}
|
|
|
|
public function testIsCustomActionRequest()
|
|
{
|
|
$request = new Request(array('ca' => '1'));
|
|
$this->assertTrue(Action::isCustomActionRequest($request));
|
|
|
|
$request = new Request(array('ca' => '0'));
|
|
$this->assertFalse(Action::isCustomActionRequest($request));
|
|
|
|
$request = new Request(array());
|
|
$this->assertFalse(Action::isCustomActionRequest($request));
|
|
}
|
|
|
|
public function testFactoryNotDefaultsToPageViewWhenCustomPluginRequest()
|
|
{
|
|
$this->expectException(\Exception::class);
|
|
$this->expectExceptionMessage('Request was meant for a plugin which is no longer activated. Request needs to be ignored.');
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite("site1", array('http://example.org'));
|
|
$request = new Request(array('ca' => '1', 'idsite' => $idSite));
|
|
|
|
Action::factory($request);
|
|
}
|
|
|
|
public function testFactoryDefaultsToPageviewWhenNotCustomPluginRequest()
|
|
{
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite("site1", array('http://example.org'));
|
|
$request = new Request(array('idsite' => $idSite));
|
|
|
|
$action = Action::factory($request);
|
|
$this->assertTrue($action instanceof ActionPageview);
|
|
}
|
|
|
|
public function getTestUrls()
|
|
{
|
|
$campaignNameParam = 'test_campaign_name';
|
|
$campaignKwdParam = 'test_piwik_kwd';
|
|
|
|
$urls = array(
|
|
// a wrongly formatted url (parse_url returns false)
|
|
array('http:////wrongurl',
|
|
array(false,
|
|
false)),
|
|
|
|
// a URL with all components
|
|
array('http://username:password@hostname:80/path?phpSESSID=value#anchor',
|
|
array('http://username:password@hostname:80/path#anchor',
|
|
'http://username:password@hostname:80/path#anchor')),
|
|
|
|
// a standard url with excluded campaign parameters
|
|
array('http://a.com/index?p1=v1&' . $campaignNameParam . '=Adwords-CPC&' . $campaignKwdParam . '=My killer keyword',
|
|
array('http://a.com/index?p1=v1',
|
|
'http://a.com/index?p1=v1')),
|
|
|
|
// a standard url with excluded campaign parameters, GA style
|
|
array('http://a.com/index?p1=v1&utm_campaign=Adwords-CPC&utm_term=My killer keyword',
|
|
array('http://a.com/index?p1=v1',
|
|
'http://a.com/index?p1=v1')),
|
|
|
|
// testing with capital parameter
|
|
array('http://a.com/index?p1=v1&P2=v2&p3=v3',
|
|
array('http://a.com/index?p1=v1&P2=v2&p3=v3',
|
|
'http://a.com/index?p1=v1&p3=v3')),
|
|
|
|
// testing with array []
|
|
array('http://a.com/index?p1=v1&p2[]=v;2a&p2[]=v2b&p2[]=v2c&p3=v3&p4=v4',
|
|
array('http://a.com/index?p1=v1&p2[]=v;2a&p2[]=v2b&p2[]=v2c&p3=v3&p4=v4',
|
|
'http://a.com/index?p1=v1&p3=v3')),
|
|
|
|
// testing with missing value
|
|
array('http://a.com/index?p1=v1&p2=&p3=v3&p4',
|
|
array('http://a.com/index?p1=v1&p2=&p3=v3&p4',
|
|
'http://a.com/index?p1=v1&p3=v3')),
|
|
array('http://a.com/index?p1&p2=v2&p3=v3&p4',
|
|
array('http://a.com/index?p1&p2=v2&p3=v3&p4',
|
|
'http://a.com/index?p1&p3=v3')),
|
|
|
|
// testing with extra &&
|
|
array('http://a.com/index?p1=v1&&p2=v;2&p3=v%3b3&p4=v4&&',
|
|
array('http://a.com/index?p1=v1&p2=v;2&p3=v%3b3&p4=v4',
|
|
'http://a.com/index?p1=v1&p3=v%3b3')),
|
|
|
|
// encode entities
|
|
array('http://a.com/index?p1=v1&p2%5B%5D=v2&p3=v3&p4=v4',
|
|
array('http://a.com/index?p1=v1&p2[]=v2&p3=v3&p4=v4',
|
|
'http://a.com/index?p1=v1&p3=v3')),
|
|
array('http://a.com/index?var%5Bvalue%5D%5Bdate%5D=01.01.2012',
|
|
array('http://a.com/index?var[value][date]=01.01.2012',
|
|
'http://a.com/index')),
|
|
|
|
// matrix parameters
|
|
array('http://a.com/index;jsessionid=value;p1=v1;p2=v2',
|
|
array('http://a.com/index?p1=v1&p2=v2',
|
|
'http://a.com/index?p1=v1')),
|
|
array('http://a.com/index;jsessionid=value?p1=v1&p2=v2',
|
|
array('http://a.com/index?p1=v1&p2=v2',
|
|
'http://a.com/index?p1=v1')),
|
|
);
|
|
|
|
return $urls;
|
|
}
|
|
|
|
/**
|
|
* No excluded query parameters specified, apart from the standard "session" parameters, always excluded
|
|
*
|
|
* @dataProvider getTestUrls
|
|
*/
|
|
public function testExcludeQueryParametersNone($url, $filteredUrl)
|
|
{
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite(
|
|
"site1",
|
|
array('http://example.org'),
|
|
$ecommerce = 0,
|
|
$siteSearch = 1,
|
|
$searchKeywordParameters = null,
|
|
$searchCategoryParameters = null,
|
|
$excludedIps = '',
|
|
$excludedQueryParameters = '',
|
|
$timezone = null,
|
|
$currency = null,
|
|
$group = null,
|
|
$startDate = null,
|
|
$excludedUserAgents = null,
|
|
$keepURLFragments = 1
|
|
);
|
|
$this->assertEquals($filteredUrl[0], PageUrl::excludeQueryParametersFromUrl($url, $idSite));
|
|
}
|
|
|
|
public function getTestAdvertisingClickIdUrls()
|
|
{
|
|
return [
|
|
['https://www.example.com?gclid=1234', 'https://www.example.com'],
|
|
['https://www.example.com?fbclid=1234', 'https://www.example.com'],
|
|
['https://www.example.com?msclkid=1234', 'https://www.example.com'],
|
|
['https://www.example.com?yclid=1234', 'https://www.example.com'],
|
|
['https://www.example.com?li_fat_id=1234', 'https://www.example.com'],
|
|
['https://www.example.com/path1?gclid=1234', 'https://www.example.com/path1'],
|
|
['https://www.example.com/path2?fbclid=1234', 'https://www.example.com/path2'],
|
|
['https://www.example.com/path3?msclkid=1234', 'https://www.example.com/path3'],
|
|
['https://www.example.com/path4?yclid=1234', 'https://www.example.com/path4'],
|
|
['https://www.example.com/path5?twclid=1234', 'https://www.example.com/path5'],
|
|
['https://www.example.com/path6?wbraid=1234', 'https://www.example.com/path6'],
|
|
['https://www.example.com/path7?gbraid=1234', 'https://www.example.com/path7'],
|
|
['https://www.example.com?random=1234', 'https://www.example.com?random=1234'],
|
|
['https://www.example.com?random=1234&yclid=qwerty', 'https://www.example.com?random=1234'],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* No excluded query parameters specified, apart from the standard "session" parameters, always excluded
|
|
*
|
|
* @dataProvider getTestAdvertisingClickIdUrls
|
|
*/
|
|
public function testExcludeQueryParametersAdvertisingClickIds($url, $filteredUrl)
|
|
{
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite(
|
|
"site1",
|
|
array('http://example.org'),
|
|
$ecommerce = 0,
|
|
$siteSearch = 1,
|
|
$searchKeywordParameters = null,
|
|
$searchCategoryParameters = null,
|
|
$excludedIps = '',
|
|
$excludedQueryParameters = '',
|
|
$timezone = null,
|
|
$currency = null,
|
|
$group = null,
|
|
$startDate = null,
|
|
$excludedUserAgents = null,
|
|
$keepURLFragments = 1
|
|
);
|
|
$this->assertEquals($filteredUrl, PageUrl::excludeQueryParametersFromUrl($url, $idSite));
|
|
}
|
|
|
|
public function getTestUrlsHashtag()
|
|
{
|
|
$urls = array(
|
|
// URL, Expected URL
|
|
array('wrongurl/#', 'http://wrongurl/'),
|
|
array('wrongurl/#t', 'http://wrongurl/#t'),
|
|
array('wrongurl/#test', 'http://wrongurl/#test'),
|
|
array('wrongurl/#test=1', 'http://wrongurl/#test=1'),
|
|
array('wrongurl/#test=1#', 'http://wrongurl/#test=1'),
|
|
);
|
|
return $urls;
|
|
}
|
|
|
|
/**
|
|
* Test removing hash tag
|
|
* @dataProvider getTestUrlsHashtag
|
|
*/
|
|
public function testRemoveTrailingHashtag($url, $expectedUrl)
|
|
{
|
|
$this->assertEquals(PageUrl::reconstructNormalizedUrl($url, PageUrl::$urlPrefixMap['http://']), $expectedUrl);
|
|
}
|
|
|
|
/**
|
|
* Testing with some website specific parameters excluded
|
|
* @dataProvider getTestUrls
|
|
*/
|
|
public function testExcludeQueryParametersSiteExcluded($url, $filteredUrl)
|
|
{
|
|
$excludedQueryParameters = 'p4, p2, var[value][date]';
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite(
|
|
"site1",
|
|
array('http://example.org'),
|
|
$ecommerce = 0,
|
|
$siteSearch = 1,
|
|
$searchKeywordParameters = null,
|
|
$searchCategoryParameters = null,
|
|
$excludedIps = '',
|
|
$excludedQueryParameters,
|
|
$timezone = null,
|
|
$currency = null,
|
|
$group = null,
|
|
$startDate = null,
|
|
$excludedUserAgents = null,
|
|
$keepURLFragments = 1
|
|
);
|
|
$this->assertEquals($filteredUrl[1], PageUrl::excludeQueryParametersFromUrl($url, $idSite));
|
|
}
|
|
|
|
/**
|
|
* Testing with some website specific parameters excluded using regular expressions
|
|
* @dataProvider getTestUrls
|
|
*/
|
|
public function testExcludeQueryParametersRegExSiteExcluded($url, $filteredUrl)
|
|
{
|
|
$excludedQueryParameters = '/p[4|2]/, /^var.*/';
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite(
|
|
"site1",
|
|
array('http://example.org'),
|
|
$ecommerce = 0,
|
|
$siteSearch = 1,
|
|
$searchKeywordParameters = null,
|
|
$searchCategoryParameters = null,
|
|
$excludedIps = '',
|
|
$excludedQueryParameters,
|
|
$timezone = null,
|
|
$currency = null,
|
|
$group = null,
|
|
$startDate = null,
|
|
$excludedUserAgents = null,
|
|
$keepURLFragments = 1
|
|
);
|
|
$this->assertEquals($filteredUrl[1], PageUrl::excludeQueryParametersFromUrl($url, $idSite));
|
|
}
|
|
|
|
/**
|
|
* Testing with some website specific and some global excluded query parameters
|
|
* @dataProvider getTestUrls
|
|
*/
|
|
public function testExcludeQueryParametersSiteAndGlobalExcluded($url, $filteredUrl)
|
|
{
|
|
// testing also that query parameters are case insensitive
|
|
$excludedQueryParameters = 'P2,var[value][date]';
|
|
$excludedGlobalParameters = 'blabla, P4';
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite(
|
|
"site1",
|
|
array('http://example.org'),
|
|
$ecommerce = 0,
|
|
$siteSearch = 1,
|
|
$searchKeywordParameters = null,
|
|
$searchCategoryParameters = null,
|
|
$excludedIps = '',
|
|
$excludedQueryParameters,
|
|
$timezone = null,
|
|
$currency = null,
|
|
$group = null,
|
|
$startDate = null,
|
|
$excludedUserAgents = null,
|
|
$keepURLFragments = 1
|
|
);
|
|
API::getInstance()->setGlobalExcludedQueryParameters($excludedGlobalParameters);
|
|
$this->assertEquals($filteredUrl[1], PageUrl::excludeQueryParametersFromUrl($url, $idSite));
|
|
}
|
|
|
|
public function getExtractUrlData()
|
|
{
|
|
return array(
|
|
// outlinks
|
|
array(
|
|
'request' => array('link' => 'http://example.org'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org',
|
|
'type' => Action::TYPE_OUTLINK),
|
|
),
|
|
// outlinks with custom name -> no custom name
|
|
array(
|
|
'request' => array('link' => 'http://example.org', 'action_name' => 'Example.org'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org',
|
|
'type' => Action::TYPE_OUTLINK),
|
|
),
|
|
// keep the case in urls, but trim
|
|
array(
|
|
'request' => array('link' => ' http://example.org/Category/Test/ '),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/Category/Test/',
|
|
'type' => Action::TYPE_OUTLINK),
|
|
),
|
|
|
|
// no custom name
|
|
array(
|
|
'request' => array('link' => ' http://example.org/Category/Test/ ', 'action_name' => ' Example dot org '),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/Category/Test/',
|
|
'type' => Action::TYPE_OUTLINK),
|
|
),
|
|
|
|
// downloads
|
|
array(
|
|
'request' => array('download' => 'http://example.org/*$test.zip'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/*$test.zip',
|
|
'type' => Action::TYPE_DOWNLOAD),
|
|
),
|
|
|
|
// downloads with custom name -> no custom name
|
|
array(
|
|
'request' => array('download' => 'http://example.org/*$test.zip', 'action_name' => 'Download test.zip'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/*$test.zip',
|
|
'type' => Action::TYPE_DOWNLOAD),
|
|
),
|
|
|
|
// keep the case and multiple / in urls
|
|
array(
|
|
'request' => array('download' => 'http://example.org/CATEGORY/test///test.pdf'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/CATEGORY/test///test.pdf',
|
|
'type' => Action::TYPE_DOWNLOAD),
|
|
),
|
|
|
|
// page view
|
|
array(
|
|
'request' => array('url' => 'http://example.org/'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/', 'action_name' => 'Example.org Website'),
|
|
'expected' => array('name' => 'Example.org Website',
|
|
'url' => 'http://example.org/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/CATEGORY/'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/CATEGORY/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/CATEGORY/TEST',
|
|
'action_name' => 'Example.org / Category / test /'),
|
|
'expected' => array('name' => 'Example.org / Category / test /',
|
|
'url' => 'http://example.org/CATEGORY/TEST',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/?2,123'),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/?2,123',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
|
|
// empty request
|
|
array(
|
|
'request' => array(),
|
|
'expected' => array('name' => null, 'url' => '',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('name' => null, 'url' => "\n"),
|
|
'expected' => array('name' => null, 'url' => '',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/category/',
|
|
'action_name' => 'custom name with/one delimiter/two delimiters/'),
|
|
'expected' => array('name' => 'custom name with/one delimiter/two delimiters/',
|
|
'url' => 'http://example.org/category/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/category/',
|
|
'action_name' => 'http://custom action name look like url/'),
|
|
'expected' => array('name' => 'http://custom action name look like url/',
|
|
'url' => 'http://example.org/category/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: delete tab, trimmed, not strtolowered
|
|
array(
|
|
'request' => array('url' => "http://example.org/category/test///test wOw "),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/category/test///test wOw',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: inclusion of zero values in action name
|
|
array(
|
|
'request' => array('url' => "http://example.org/category/1/0/t/test"),
|
|
'expected' => array('name' => null,
|
|
'url' => 'http://example.org/category/1/0/t/test',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: action name ("Test …") - expect decoding of some html entities
|
|
array(
|
|
'request' => array('url' => 'http://example.org/ACTION/URL',
|
|
'action_name' => "Test …"),
|
|
'expected' => array('name' => 'Test …',
|
|
'url' => 'http://example.org/ACTION/URL',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: action name ("Special & chars") - expect no conversion of html special chars
|
|
array(
|
|
'request' => array('url' => 'http://example.org/ACTION/URL',
|
|
'action_name' => "Special & chars"),
|
|
'expected' => array('name' => 'Special & chars',
|
|
'url' => 'http://example.org/ACTION/URL',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: action name ("Tést") - handle wide character
|
|
array(
|
|
'request' => array('url' => 'http://example.org/ACTION/URL',
|
|
'action_name' => "Tést"),
|
|
'expected' => array('name' => 'Tést',
|
|
'url' => 'http://example.org/ACTION/URL',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: action name ("Tést") - handle UTF-8 byte sequence
|
|
array(
|
|
'request' => array('url' => 'http://example.org/ACTION/URL',
|
|
'action_name' => "T\xc3\xa9st"),
|
|
'expected' => array('name' => 'Tést',
|
|
'url' => 'http://example.org/ACTION/URL',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
// testing: action name ("Tést") - invalid UTF-8 (e.g., ISO-8859-1) is not handled
|
|
array(
|
|
'request' => array('url' => 'http://example.org/ACTION/URL',
|
|
'action_name' => "T\xe9st"),
|
|
'expected' => array('name' => version_compare(PHP_VERSION, '5.2.5') === -1 ? 'T\xe9st' : 'Tést',
|
|
'url' => 'http://example.org/ACTION/URL',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
array(
|
|
'request' => array('url' => 'http://example.org/', 'action_name' => ' not trimmed '),
|
|
'expected' => array('name' => 'not trimmed',
|
|
'url' => 'http://example.org/',
|
|
'type' => Action::TYPE_PAGE_URL),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @dataProvider getExtractUrlData
|
|
*/
|
|
public function testExtractUrlAndActionNameFromRequest($request, $expected)
|
|
{
|
|
$this->setUpRootAccess();
|
|
$idSite = API::getInstance()->addSite("site1", array('http://example.org'));
|
|
$request['idsite'] = $idSite;
|
|
$request = new Request($request);
|
|
|
|
$action = Action::factory($request);
|
|
|
|
$processed = array(
|
|
'name' => $action->getActionName(),
|
|
'url' => $action->getActionUrl(),
|
|
'type' => $action->getActionType(),
|
|
);
|
|
|
|
$this->assertEquals($expected, $processed);
|
|
}
|
|
|
|
public function provideContainerConfig()
|
|
{
|
|
return array(
|
|
'Piwik\Access' => new FakeAccess()
|
|
);
|
|
}
|
|
}
|