Skip to content

Commit 0265e8a

Browse files
authored
Merge pull request #23 from DevDavido/development
Bump to v1.1.0
2 parents 7df2296 + 5c050f8 commit 0265e8a

20 files changed

+281
-43
lines changed

.github/workflows/tests.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
php-versions: ['7.1']
1818
#php-versions: ['7.1', '7.2', '7.3', '7.4', '8.0']
19-
matomo-versions: ['3.12.0', '3.13.6']
19+
matomo-versions: ['3.12.0', '3.14.0']
2020
node-version: [12.x]
2121
#node-version: [10.x, 12.x]
2222

@@ -57,7 +57,7 @@ jobs:
5757
cd matomo
5858
git fetch --all
5959
git submodule update
60-
git checkout -q tags/${{ matrix.matomo-versions }}
60+
git checkout -f -q tags/${{ matrix.matomo-versions }}
6161
[ -d ./tests/travis/.git ] || sh -c "rm -rf ./tests/travis && git clone https://github.com/matomo-org/travis-scripts.git ./tests/travis"
6262
cd ./tests/travis
6363
git checkout master

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,16 @@
33
- Added: Support for Matomo 4 🎉
44
- Updated: Bumped the minimum PHP version to 7.2.5 for this new major plugin version, just as Matomo 4 itself
55

6+
## 1.1.0
7+
- Fixed: Regular users cannot login anymore if plugin is activated
8+
- Fixed: Renamed and fixed option to remove query strings from audited URLs which is now named group URLs and it doesn't throw SQL warnings anymore in certain (edge) cases
9+
- Improved: Added security information for applied no sandbox mode of Chromium
10+
- Improved: Increase database connection timeouts for longer running site audits
11+
- Improved: Increase timeout for (audit) processes to 5 minutes
12+
- Improved: Throw warning instead error for audited pages with HTTP 403 / 404 response
13+
- Improved: Added FAQ entry for missing Chromium dependencies
14+
- Improved: Error message during installation if directory permissions are incorrect
15+
616
## 1.0.11
717
- Added: Option to remove query strings from audited URLs
818
- Improved: Small refactoring in settings
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Matomo - free/libre analytics platform
4+
*
5+
* @link https://matomo.org
6+
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7+
*/
8+
9+
namespace Piwik\Plugins\PerformanceAudit\Exceptions;
10+
11+
require PIWIK_INCLUDE_PATH . '/plugins/PerformanceAudit/vendor/autoload.php';
12+
13+
use Exception;
14+
15+
class AuditFailedAuthoriseRefusedException extends Exception
16+
{
17+
/**
18+
* AuditFailedAuthoriseRefusedException constructor.
19+
*
20+
* @param string $url
21+
* @param null|string $output
22+
*/
23+
public function __construct(string $url, $output = null)
24+
{
25+
parent::__construct('Audit of ' . $url . ' failed due to refused authorisation: ' . $output);
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
/**
3+
* Matomo - free/libre analytics platform
4+
*
5+
* @link https://matomo.org
6+
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7+
*/
8+
9+
namespace Piwik\Plugins\PerformanceAudit\Exceptions;
10+
11+
require PIWIK_INCLUDE_PATH . '/plugins/PerformanceAudit/vendor/autoload.php';
12+
13+
use Exception;
14+
15+
class AuditFailedNotFoundException extends Exception
16+
{
17+
/**
18+
* AuditFailedNotFoundException constructor.
19+
*
20+
* @param string $url
21+
* @param null|string $output
22+
*/
23+
public function __construct(string $url, $output = null)
24+
{
25+
parent::__construct('Audit of ' . $url . ' failed due to not found target: ' . $output);
26+
}
27+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
/**
3+
* Matomo - free/libre analytics platform
4+
*
5+
* @link https://matomo.org
6+
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
7+
*/
8+
9+
namespace Piwik\Plugins\PerformanceAudit\Exceptions;
10+
11+
require PIWIK_INCLUDE_PATH . '/plugins/PerformanceAudit/vendor/autoload.php';
12+
13+
use RuntimeException;
14+
15+
class DependencyNpmMisconfigurationException extends RuntimeException
16+
{
17+
18+
}

Lighthouse.php

+29-8
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
require PIWIK_INCLUDE_PATH . '/plugins/PerformanceAudit/vendor/autoload.php';
1212

1313
use Dzava\Lighthouse\Lighthouse as BaseLighthouse;
14+
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedAuthoriseRefusedException;
1415
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedException;
16+
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedNotFoundException;
1517
use Piwik\Plugins\PerformanceAudit\Exceptions\DependencyMissingException;
1618
use Piwik\Plugins\PerformanceAudit\Exceptions\DependencyUnexpectedResultException;
1719
use UnexpectedValueException;
@@ -38,7 +40,7 @@ public function __construct()
3840
*
3941
* @param string $url
4042
* @return string
41-
* @throws AuditFailedException
43+
* @throws AuditFailedAuthoriseRefusedException|AuditFailedNotFoundException|AuditFailedException
4244
*/
4345
public function audit($url)
4446
{
@@ -49,7 +51,7 @@ public function audit($url)
4951
$process->setTimeout($this->timeout)->run();
5052

5153
if (!$process->isSuccessful()) {
52-
throw new AuditFailedException($url, $process->getErrorOutput());
54+
$this->throwAuditException($url, $process->getErrorOutput());
5355
}
5456

5557
return $process->getOutput();
@@ -145,6 +147,19 @@ public function disableDeviceEmulation()
145147
return $this;
146148
}
147149

150+
/**
151+
* Enable audit.
152+
*
153+
* @param string $audit
154+
* @return self
155+
*/
156+
public function enableAudit($audit)
157+
{
158+
$this->setAudit($audit, true);
159+
160+
return $this;
161+
}
162+
148163
/**
149164
* Creates the config file used during the audit.
150165
*
@@ -191,15 +206,21 @@ protected function setAudit($audit, $enable)
191206
}
192207

193208
/**
194-
* Enable audit.
209+
* Throw an corresponding exception if audit fails.
195210
*
196-
* @param string $audit
197-
* @return self
211+
* @param string $url
212+
* @param string $errorOutput
213+
* @return void
214+
* @throws AuditFailedAuthoriseRefusedException|AuditFailedNotFoundException|AuditFailedException
198215
*/
199-
public function enableAudit($audit)
216+
protected function throwAuditException($url, $errorOutput)
200217
{
201-
$this->setAudit($audit, true);
218+
if (stristr($errorOutput, 'Status code: 403')) {
219+
throw new AuditFailedAuthoriseRefusedException($url, $errorOutput);
220+
} elseif (stristr($errorOutput, 'Status code: 404')) {
221+
throw new AuditFailedNotFoundException($url, $errorOutput);
222+
}
202223

203-
return $this;
224+
throw new AuditFailedException($url, $errorOutput);
204225
}
205226
}

MeasurableSettings.php

+10-10
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class MeasurableSettings extends BaseMeasurableSettings
2424
public $emulatedDevice;
2525

2626
/** @var Setting */
27-
public $hasUrlsWithoutQueryString;
27+
public $hasGroupedUrls;
2828

2929
/** @var Setting */
3030
public $hasExtraHttpHeader;
@@ -46,11 +46,11 @@ class MeasurableSettings extends BaseMeasurableSettings
4646
*/
4747
protected function init()
4848
{
49-
Piwik::checkUserHasSomeAdminAccess();
49+
Piwik::checkUserHasSomeViewAccess();
5050

5151
$this->runCount = $this->makeRunCountSetting();
5252
$this->emulatedDevice = $this->makeEmulatedDeviceSetting();
53-
$this->hasUrlsWithoutQueryString = $this->makeHasUrlsWithoutQueryStringSetting();
53+
$this->hasGroupedUrls = $this->makeHasGroupedUrlsSetting();
5454
$this->hasExtraHttpHeader = $this->makeHasExtraHttpHeaderSetting();
5555
$this->extraHttpHeaderKey = $this->makeExtraHttpHeaderKeySetting();
5656
$this->extraHttpHeaderValue = $this->makeExtraHttpHeaderValueSetting();
@@ -113,11 +113,11 @@ private function makeEmulatedDeviceSetting()
113113
* @return MeasurableSetting
114114
* @throws ValidatorException|Exception
115115
*/
116-
private function makeHasUrlsWithoutQueryStringSetting()
116+
private function makeHasGroupedUrlsSetting()
117117
{
118-
return $this->makeSetting('has_urls_without_query_string', false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
119-
$field->title = Piwik::translate('PerformanceAudit_Settings_HasUrlsWithoutQueryString_Title');
120-
$field->inlineHelp = Piwik::translate('PerformanceAudit_Settings_HasUrlsWithoutQueryString_Help');
118+
return $this->makeSetting('has_grouped_urls', false, FieldConfig::TYPE_BOOL, function (FieldConfig $field) {
119+
$field->title = Piwik::translate('PerformanceAudit_Settings_HasGroupedUrls_Title');
120+
$field->inlineHelp = Piwik::translate('PerformanceAudit_Settings_HasGroupedUrls_Help');
121121
$field->uiControl = FieldConfig::UI_CONTROL_CHECKBOX;
122122
});
123123
}
@@ -218,12 +218,12 @@ public function getEmulatedDevicesList()
218218
}
219219

220220
/**
221-
* Returns if site has URLs without query strings for site.
221+
* Returns if site has grouped URLs for site.
222222
*
223223
* @return bool
224224
*/
225-
public function hasUrlsWithoutQueryString()
225+
public function hasGroupedUrls()
226226
{
227-
return $this->getSetting('has_urls_without_query_string')->getValue();
227+
return $this->getSetting('has_grouped_urls')->getValue();
228228
}
229229
}

NodeDependencyInstaller.php

+8-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
use Exception;
1414
use Piwik\Log;
15+
use Piwik\Plugins\PerformanceAudit\Exceptions\DependencyNpmMisconfigurationException;
1516
use Piwik\Plugins\PerformanceAudit\Exceptions\DependencyOfChromeMissingException;
1617
use Piwik\Plugins\PerformanceAudit\Exceptions\DependencyUnexpectedResultException;
1718
use Piwik\Plugins\PerformanceAudit\Exceptions\InstallationFailedException;
@@ -121,9 +122,13 @@ private function checkDependency($executableName, $args)
121122

122123
if (!$process->isSuccessful()) {
123124
$errorOutput = $process->getErrorOutput();
124-
throw (stristr($errorOutput, 'libX11-xcb')) ?
125-
new DependencyOfChromeMissingException() :
126-
new DependencyUnexpectedResultException(ucfirst($executableName) . ' has the following unexpected output: ' . PHP_EOL . $errorOutput);
125+
if (stristr($errorOutput, 'libX11-xcb')) {
126+
throw new DependencyOfChromeMissingException();
127+
} elseif (stristr($errorOutput, 'cache folder contains root-owned files')) {
128+
throw new DependencyNpmMisconfigurationException($executableName . ' has the following issue: ' . PHP_EOL . $errorOutput);
129+
}
130+
131+
throw new DependencyUnexpectedResultException(ucfirst($executableName) . ' has the following unexpected output: ' . PHP_EOL . $errorOutput);
127132
}
128133

129134
return floatval(trim(preg_replace('/[^0-9.]/', '', $process->getOutput())));

Process.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,6 @@ public function __construct($command, $env = null)
3333
];
3434
}
3535

36-
parent::__construct($command, __DIR__, $env, null, 60);
36+
parent::__construct($command, __DIR__, $env, null, 300);
3737
}
3838
}

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,7 @@ If you have any questions or inquiries, you can contact `github {at} diskoboss {
8080
## Security
8181
If you discover any security related issues, please contact `github {at} diskoboss {døt} de` instead of using the issue tracker.
8282

83+
Please note that the performance audits will be performed with Chromium which renders Matomo-tracked web pages on your server without the sandbox mode of Chromium. You can find more information about this possible issue on the [lighthouse-cli repository](https://github.com/GoogleChrome/lighthouse-ci/tree/master/docs/recipes/docker-client#--no-sandbox-issues-explained).
84+
8385
## License
8486
Licensed under the [GPLv3 License](LICENSE.md).

Tasks.php

+49-5
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
use Piwik\Piwik;
2626
use Piwik\Plugin\Tasks as BaseTasks;
2727
use Piwik\Plugins\PerformanceAudit\Columns\Metrics\Audit;
28+
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedAuthoriseRefusedException;
2829
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedException;
30+
use Piwik\Plugins\PerformanceAudit\Exceptions\AuditFailedNotFoundException;
2931
use Piwik\Site;
3032
use Piwik\Tracker\Action;
3133
use Piwik\Tracker\Db\DbException;
@@ -101,6 +103,9 @@ public function auditSite(int $idSite, bool $debug = false)
101103
return;
102104
}
103105

106+
$this->setDatabaseTimeoutConfiguration();
107+
$this->logInfo('Database timeout configuration: ' . json_encode($this->getDatabaseTimeoutConfiguration()));
108+
104109
$this->logInfo('Performance Audit task for site ' . $idSite . ' will be started now');
105110
try {
106111
if (!$this->isInDebugMode()) {
@@ -112,8 +117,8 @@ public function auditSite(int $idSite, bool $debug = false)
112117
$runs = $siteSettings->getRuns();
113118
$emulatedDevices = $siteSettings->getEmulatedDevicesList();
114119

115-
if ($siteSettings->hasUrlsWithoutQueryString()) {
116-
$this->removeQueryStrings($urls);
120+
if ($siteSettings->hasGroupedUrls()) {
121+
$this->groupUrlsByPath($urls);
117122
}
118123

119124
if ($this->isInDebugMode()) {
@@ -295,16 +300,24 @@ private function getPageUrls(int $idSite, string $date)
295300
}
296301

297302
/**
298-
* Remove query string from each url.
303+
* Group by path and remove duplicates of URLs
304+
* which only differ in their query strings.
299305
*
300306
* @param array $urls
301307
* @return void
302308
*/
303-
private function removeQueryStrings(array &$urls)
309+
private function groupUrlsByPath(array &$urls)
304310
{
305311
foreach ($urls as $key => $url) {
306-
$urls[$key] = current(explode('?', $url, 2));
312+
$urlBase = current(explode('?', $url, 2));
313+
// Remove any URLs which differ only by query string
314+
// by setting URL base as key and assign actual URL as value
315+
$urls[$urlBase] = $url;
316+
// Remove old entry by key
317+
unset($urls[$key]);
307318
}
319+
// Reset keys
320+
$urls = array_values($urls);
308321

309322
$this->removeUrlDuplicates($urls);
310323
}
@@ -320,6 +333,30 @@ private function removeUrlDuplicates(array &$urls)
320333
$urls = array_values(array_unique($urls, SORT_STRING));
321334
}
322335

336+
/**
337+
* Set timeout configuration of the current database connection.
338+
*
339+
* @return void
340+
* @throws Exception
341+
*/
342+
private function setDatabaseTimeoutConfiguration()
343+
{
344+
// Set timeouts to maximum 1 week
345+
Db::get()->exec('SET SESSION wait_timeout=604800;');
346+
Db::get()->exec('SET SESSION interactive_timeout=604800;');
347+
}
348+
349+
/**
350+
* Return timeout configuration of the database.
351+
*
352+
* @return array
353+
* @throws DbException
354+
*/
355+
private function getDatabaseTimeoutConfiguration()
356+
{
357+
return Db::get()->fetchAll('SHOW VARIABLES LIKE "%timeout%"');
358+
}
359+
323360
/**
324361
* Perform audits for every combination of urls,
325362
* emulated devices and amount of runs.
@@ -355,6 +392,8 @@ private function performAudits(int $idSite, array $urls, array $emulatedDevices,
355392
))
356393
->setEmulatedDevice($emulatedDevice)
357394
->audit($url);
395+
} catch (AuditFailedAuthoriseRefusedException | AuditFailedNotFoundException $exception) {
396+
$this->logWarning($exception->getMessage());
358397
} catch (AuditFailedException $exception) {
359398
$this->logError($exception->getMessage());
360399
}
@@ -560,6 +599,11 @@ private function storeResultsInDatabase(int $idSite, array $results)
560599
foreach ($siteResult as $url => $emulatedDevices) {
561600
foreach ($emulatedDevices as $emulatedDevice => $metrics) {
562601
foreach ($metrics as $key => $values) {
602+
// Skip URL without an entry in lookup table
603+
if (!isset($actionIdLookupTable[$url])) {
604+
$this->logWarning('Entry for the following hashed URL in lookup table is missing: ' . $url);
605+
continue;
606+
}
563607
[$min, $median, $max] = $values;
564608

565609
$result = Db::get()->query('

0 commit comments

Comments
 (0)