From 282b8cd3ffe105e13a9453e11e3e0b73f8df190d Mon Sep 17 00:00:00 2001 From: PhilZ Date: Sat, 9 Jan 2021 23:21:52 +0100 Subject: [PATCH 1/5] Proper Fix "Trying to access array offset on value of type bool" Since php74, we must properly ensure that array is not null/false before checking any of its column ranges This properly fixes the "Trying to access array offset on value of type bool" when no time range is specified to filter our calendar events. It also preserves the accurate filtering query when time range is specified --- lib/CalDAV/Backend/PDO.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/CalDAV/Backend/PDO.php b/lib/CalDAV/Backend/PDO.php index bb12d590da..1357aa2ecb 100644 --- a/lib/CalDAV/Backend/PDO.php +++ b/lib/CalDAV/Backend/PDO.php @@ -789,8 +789,10 @@ public function calendarQuery($calendarId, array $filters) // If start time OR the end time is not specified, we can do a // 100% accurate mysql query. - if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && (!$timeRange['start'] || !$timeRange['end'])) { - $requirePostFilter = false; + if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && $timeRange) { + if (!$timeRange['start'] || !$timeRange['end']) { + $requirePostFilter = false; + } } } } From ef7d410ddfc57e249ab0c4d2a1c7c4f83a32cf90 Mon Sep 17 00:00:00 2001 From: Phil Davis Date: Fri, 26 Jun 2020 16:28:30 +0545 Subject: [PATCH 2/5] Add unit test cases for variations of specifying time-range --- .../Sabre/CalDAV/Backend/AbstractPDOTest.php | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php b/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php index 9460b89228..77817c4fd0 100644 --- a/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php +++ b/tests/Sabre/CalDAV/Backend/AbstractPDOTest.php @@ -780,7 +780,7 @@ public function testCalendarQueryTimeRange() ], $backend->calendarQuery([1, 1], $filters)); } - public function testCalendarQueryTimeRangeNoEnd() + public function testCalendarQueryTimeRangeEndNull() { $backend = new PDO($this->pdo); $backend->createCalendarObject([1, 1], 'todo', "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); @@ -811,6 +811,94 @@ public function testCalendarQueryTimeRangeNoEnd() ], $backend->calendarQuery([1, 1], $filters)); } + public function testCalendarQueryTimeRangeNoEnd() + { + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], 'todo', "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event2', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'start' => new \DateTime('20120102'), + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + 'event2', + ], $backend->calendarQuery([1, 1], $filters)); + } + + public function testCalendarQueryTimeRangeNoStart() + { + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], 'todo', "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event2', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => [ + 'end' => new \DateTime('20120102'), + ], + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $this->assertEquals([ + 'event', + ], $backend->calendarQuery([1, 1], $filters)); + } + + public function testCalendarQueryTimeRangeNotSpecified() + { + $backend = new PDO($this->pdo); + $backend->createCalendarObject([1, 1], 'todo', "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject([1, 1], 'event2', "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = [ + 'name' => 'VCALENDAR', + 'comp-filters' => [ + [ + 'name' => 'VEVENT', + 'comp-filters' => [], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => false, + ], + ], + 'prop-filters' => [], + 'is-not-defined' => false, + 'time-range' => null, + ]; + + $result = $backend->calendarQuery([1, 1], $filters); + $this->assertTrue(in_array('event', $result)); + $this->assertTrue(in_array('event2', $result)); + } + public function testGetChanges() { $backend = new PDO($this->pdo); From b04269f89ef95af21b2938a3393f5b756b8c401b Mon Sep 17 00:00:00 2001 From: Phil Davis Date: Mon, 11 Jan 2021 08:37:10 +0545 Subject: [PATCH 3/5] Check that start or end time range keys exist --- lib/CalDAV/Backend/PDO.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/CalDAV/Backend/PDO.php b/lib/CalDAV/Backend/PDO.php index 1357aa2ecb..acda1c9cbd 100644 --- a/lib/CalDAV/Backend/PDO.php +++ b/lib/CalDAV/Backend/PDO.php @@ -790,7 +790,7 @@ public function calendarQuery($calendarId, array $filters) // If start time OR the end time is not specified, we can do a // 100% accurate mysql query. if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && $timeRange) { - if (!$timeRange['start'] || !$timeRange['end']) { + if ((array_key_exists('start', $timeRange) && !$timeRange['start']) || (array_key_exists('end', $timeRange) && !$timeRange['end'])) { $requirePostFilter = false; } } @@ -812,11 +812,11 @@ public function calendarQuery($calendarId, array $filters) $values['componenttype'] = $componentType; } - if ($timeRange && $timeRange['start']) { + if ($timeRange && array_key_exists('start', $timeRange) && $timeRange['start']) { $query .= ' AND lastoccurence > :startdate'; $values['startdate'] = $timeRange['start']->getTimeStamp(); } - if ($timeRange && $timeRange['end']) { + if ($timeRange && array_key_exists('end', $timeRange) && $timeRange['end']) { $query .= ' AND firstoccurence < :enddate'; $values['enddate'] = $timeRange['end']->getTimeStamp(); } From 66c4a98098592c7263f84b6a08f4d44abc33c4be Mon Sep 17 00:00:00 2001 From: PhilZ Date: Mon, 11 Jan 2021 11:29:06 +0100 Subject: [PATCH 4/5] Update CalendarQueryValidator.php --- lib/CalDAV/CalendarQueryValidator.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/CalDAV/CalendarQueryValidator.php b/lib/CalDAV/CalendarQueryValidator.php index ab6c602d2e..cc8540152e 100644 --- a/lib/CalDAV/CalendarQueryValidator.php +++ b/lib/CalDAV/CalendarQueryValidator.php @@ -69,7 +69,15 @@ protected function validateCompFilters(VObject\Component $parent, array $filters if ($filter['time-range']) { foreach ($parent->{$filter['name']} as $subComponent) { - if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) { + $start = null; + $end = null; + if (array_key_exists('start', $filter['time-range'])) { + $start = $filter['time-range']['start']; + } + if (array_key_exists('end', $filter['time-range'])) { + $end = $filter['time-range']['end']; + } + if ($this->validateTimeRange($subComponent, $start, $end)) { continue 2; } } From 9d2958144fad411cae05a795d48f43da3043f98b Mon Sep 17 00:00:00 2001 From: PhilZ Date: Mon, 11 Jan 2021 14:02:38 +0100 Subject: [PATCH 5/5] Update CalendarQueryValidator.php --- lib/CalDAV/CalendarQueryValidator.php | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/CalDAV/CalendarQueryValidator.php b/lib/CalDAV/CalendarQueryValidator.php index cc8540152e..8217da0b69 100644 --- a/lib/CalDAV/CalendarQueryValidator.php +++ b/lib/CalDAV/CalendarQueryValidator.php @@ -138,7 +138,15 @@ protected function validatePropFilters(VObject\Component $parent, array $filters if ($filter['time-range']) { foreach ($parent->{$filter['name']} as $subComponent) { - if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) { + $start = null; + $end = null; + if (array_key_exists('start', $filter['time-range'])) { + $start = $filter['time-range']['start']; + } + if (array_key_exists('end', $filter['time-range'])) { + $end = $filter['time-range']['end']; + } + if ($this->validateTimeRange($subComponent, $start, $end)) { continue 2; } }