From 707cc298b67b66d17e31d34acdbcd8f7f3c0758b Mon Sep 17 00:00:00 2001 From: sgiehl Date: Wed, 18 Sep 2024 16:46:39 +0200 Subject: [PATCH 1/3] Limit the end date of range periods to 10 years in the future --- core/Period/Range.php | 20 +++++++++++++++ tests/PHPUnit/Unit/DateTest.php | 17 ++++++------- tests/PHPUnit/Unit/Period/RangeTest.php | 33 +++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 9 deletions(-) diff --git a/core/Period/Range.php b/core/Period/Range.php index 19c347a1d8a..4776eb430e7 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -264,7 +264,13 @@ protected function generate() if (strpos($strDateEnd, '-') === false) { $timezone = $this->timezone; } + $endDate = Date::factory($strDateEnd, $timezone)->setTime("00:00:00"); + $maxAllowedEndDate = Date::factory(self::getMaxAllowedEndTimestamp()); + + if ($endDate->isLater($maxAllowedEndDate)) { + $endDate = $maxAllowedEndDate; + } } else { throw new Exception($this->translator->translate('General_ExceptionInvalidDateRange', array($this->strDate, ' \'lastN\', \'previousN\', \'YYYY-MM-DD,YYYY-MM-DD\''))); } @@ -587,4 +593,18 @@ public function getParentPeriodLabel() { return null; } + + /** + * Returns the max allowed end timestamp for a range. If an enddate after this timestamp is provided, Matomo will + * automatically lower the end date to the date returned by this method. + * The max supported timestamp is always set to end of the current year plus 10 years. + * + * @return int + */ + public static function getMaxAllowedEndTimestamp(): int + { + return strtotime( + date('Y-12-31 00:00:00', strtotime("+10 year", Date::$now ?? time())) + ); + } } diff --git a/tests/PHPUnit/Unit/DateTest.php b/tests/PHPUnit/Unit/DateTest.php index 76159efb765..cc3bcf26f52 100644 --- a/tests/PHPUnit/Unit/DateTest.php +++ b/tests/PHPUnit/Unit/DateTest.php @@ -126,15 +126,14 @@ public function testInvalidDateThrowsException($valueToTest) Date::factory($valueToTest); } - public function getInvalidDates(): array - { - return [ - ['0001-01-01'], - ['randomString'], - [null], - [''], - [['arrayValue']], - ]; + public function getInvalidDates(): iterable + { + yield 'valid format, earliest possible date' => ['0001-01-01']; + yield 'valid format, day before first website creation' => ['1991-08-05']; + yield 'ivalid string value' => ['randomString']; + yield 'empty string value' => ['']; + yield 'null value' => [null]; + yield 'array value' => [['arrayValue']]; } public function getTimezoneOffsets() diff --git a/tests/PHPUnit/Unit/Period/RangeTest.php b/tests/PHPUnit/Unit/Period/RangeTest.php index 23b23389e59..32b98129b05 100644 --- a/tests/PHPUnit/Unit/Period/RangeTest.php +++ b/tests/PHPUnit/Unit/Period/RangeTest.php @@ -404,6 +404,17 @@ public function testRangeMonthcomma1() $this->assertEquals('2006-12-01,2007-01-31', $range->getRangeString()); } + // test range date1,date2 + public function testRangeMonthcommaAfterMaxAllowedDate() + { + Date::$now = strtotime('2024-07-09'); + $range = new Range('month', '2024-01-01,2100-01-03'); + + // range should be limited to 2034, so includes 11 years + $this->assertEquals(11 * 12, $range->getNumberOfSubperiods()); + $this->assertEquals('2024-01-01,2034-12-31', $range->getRangeString()); + } + // test range WEEK public function testRangeWeek() { @@ -1215,6 +1226,28 @@ public function testCustomRangeBeforeIsAfterYearRight() $range->getPrettyString(); } + /** + * @dataProvider getAbnormalDateRanges + */ + public function testCustomRangeWithOutOfRangeDate($dateStr) + { + self::expectException(Exception::class); + + $range = new Range('range', $dateStr); + $range->getDateStart(); + } + + public function getAbnormalDateRanges(): iterable + { + yield 'range starts before first website creation' => [ + '1900-01-01,2021-01-01', + ]; + + yield 'range starts after it ends' => [ + '2024-01-01,2020-12-16', + ]; + } + public function testCustomRangeLastN() { $range = new Range('range', 'last4'); From 2ff2f1622ddd653a195d98e9f2b4718bc4e8d246 Mon Sep 17 00:00:00 2001 From: Stefan Giehl Date: Fri, 20 Sep 2024 17:34:43 +0200 Subject: [PATCH 2/3] Mark method as api --- core/Period/Range.php | 1 + 1 file changed, 1 insertion(+) diff --git a/core/Period/Range.php b/core/Period/Range.php index 4776eb430e7..58aea9a2cf4 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -600,6 +600,7 @@ public function getParentPeriodLabel() * The max supported timestamp is always set to end of the current year plus 10 years. * * @return int + * @api */ public static function getMaxAllowedEndTimestamp(): int { From 1b26cb43ce992e4b8a5d25438b9a816c77f53f5e Mon Sep 17 00:00:00 2001 From: Stefan Giehl Date: Tue, 24 Sep 2024 17:36:28 +0200 Subject: [PATCH 3/3] Apply review feedback Co-authored-by: Marc Neudert --- core/Period/Range.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/Period/Range.php b/core/Period/Range.php index 58aea9a2cf4..36c450c84d8 100644 --- a/core/Period/Range.php +++ b/core/Period/Range.php @@ -605,7 +605,7 @@ public function getParentPeriodLabel() public static function getMaxAllowedEndTimestamp(): int { return strtotime( - date('Y-12-31 00:00:00', strtotime("+10 year", Date::$now ?? time())) + date('Y-12-31 00:00:00', strtotime('+10 year', Date::getNowTimestamp())) ); } }