Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 44 additions & 21 deletions lib/CalDAV/Backend/PDO.php
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ public function getCalendarObject($calendarId, $objectUri)
'lastmodified' => (int) $row['lastmodified'],
'etag' => '"'.$row['etag'].'"',
'size' => (int) $row['size'],
'calendardata' => $row['calendardata'],
'calendardata' => is_resource($row['calendardata']) ? stream_get_contents($row['calendardata']) : $row['calendardata'],
Comment thread
sylvinus marked this conversation as resolved.
Outdated
'component' => strtolower($row['componenttype']),
];
}
Expand Down Expand Up @@ -507,7 +507,7 @@ public function getMultipleCalendarObjects($calendarId, array $uris)
'lastmodified' => (int) $row['lastmodified'],
'etag' => '"'.$row['etag'].'"',
'size' => (int) $row['size'],
'calendardata' => $row['calendardata'],
'calendardata' => is_resource($row['calendardata']) ? stream_get_contents($row['calendardata']) : $row['calendardata'],
'component' => strtolower($row['componenttype']),
];
}
Expand Down Expand Up @@ -544,19 +544,19 @@ public function createCalendarObject($calendarId, $objectUri, $calendarData)

$extraData = $this->getDenormalizedData($calendarData);

$stmt = $this->pdo->prepare('INSERT INTO '.$this->calendarObjectTableName.' (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence, uid) VALUES (?,?,?,?,?,?,?,?,?,?)');
$stmt->execute([
$calendarId,
$objectUri,
$calendarData,
time(),
$extraData['etag'],
$extraData['size'],
$extraData['componentType'],
$extraData['firstOccurence'],
$extraData['lastOccurence'],
$extraData['uid'],
]);
$stmt = $this->pdo->prepare('INSERT INTO '.$this->calendarObjectTableName.' (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence, uid) VALUES (:calendarid, :uri, :calendardata, :lastmodified, :etag, :size, :componenttype, :firstoccurence, :lastoccurence, :uid)');
$lastmodified = time();
$stmt->bindParam('calendarid', $calendarId, \PDO::PARAM_INT);
$stmt->bindParam('uri', $objectUri, \PDO::PARAM_STR);
$stmt->bindParam('calendardata', $calendarData, \PDO::PARAM_LOB);
$stmt->bindParam('lastmodified', $lastmodified, \PDO::PARAM_INT);
$stmt->bindParam('etag', $extraData['etag'], \PDO::PARAM_STR);
$stmt->bindParam('size', $extraData['size'], \PDO::PARAM_INT);
$stmt->bindParam('componenttype', $extraData['componentType'], \PDO::PARAM_STR);
$stmt->bindParam('firstoccurence', $extraData['firstOccurence'], \PDO::PARAM_INT);
$stmt->bindParam('lastoccurence', $extraData['lastOccurence'], \PDO::PARAM_INT);
$stmt->bindParam('uid', $extraData['uid'], \PDO::PARAM_STR);
$stmt->execute();
$this->addChange($calendarId, $objectUri, 1);

return '"'.$extraData['etag'].'"';
Expand Down Expand Up @@ -590,8 +590,19 @@ public function updateCalendarObject($calendarId, $objectUri, $calendarData)

$extraData = $this->getDenormalizedData($calendarData);

$stmt = $this->pdo->prepare('UPDATE '.$this->calendarObjectTableName.' SET calendardata = ?, lastmodified = ?, etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ?, uid = ? WHERE calendarid = ? AND uri = ?');
$stmt->execute([$calendarData, time(), $extraData['etag'], $extraData['size'], $extraData['componentType'], $extraData['firstOccurence'], $extraData['lastOccurence'], $extraData['uid'], $calendarId, $objectUri]);
$stmt = $this->pdo->prepare('UPDATE '.$this->calendarObjectTableName.' SET calendardata = :calendardata, lastmodified = :lastmodified, etag = :etag, size = :size, componenttype = :componenttype, firstoccurence = :firstoccurence, lastoccurence = :lastoccurence, uid = :uid WHERE calendarid = :calendarid AND uri = :uri');
$lastmodified = time();
$stmt->bindParam('calendardata', $calendarData, \PDO::PARAM_LOB);
$stmt->bindParam('lastmodified', $lastmodified, \PDO::PARAM_INT);
$stmt->bindParam('etag', $extraData['etag'], \PDO::PARAM_STR);
$stmt->bindParam('size', $extraData['size'], \PDO::PARAM_INT);
$stmt->bindParam('componenttype', $extraData['componentType'], \PDO::PARAM_STR);
$stmt->bindParam('firstoccurence', $extraData['firstOccurence'], \PDO::PARAM_INT);
$stmt->bindParam('lastoccurence', $extraData['lastOccurence'], \PDO::PARAM_INT);
$stmt->bindParam('uid', $extraData['uid'], \PDO::PARAM_STR);
$stmt->bindParam('calendarid', $calendarId, \PDO::PARAM_INT);
$stmt->bindParam('uri', $objectUri, \PDO::PARAM_STR);
$stmt->execute();

$this->addChange($calendarId, $objectUri, 2);

Expand Down Expand Up @@ -828,6 +839,9 @@ public function calendarQuery($calendarId, array $filters)
$result = [];
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
if ($requirePostFilter) {
if (isset($row['calendardata']) && is_resource($row['calendardata'])) {
$row['calendardata'] = stream_get_contents($row['calendardata']);
}
if (!$this->validateFilterForObject($row, $filters)) {
continue;
}
Expand Down Expand Up @@ -1252,7 +1266,7 @@ public function getSchedulingObject($principalUri, $objectUri)

return [
'uri' => $row['uri'],
'calendardata' => $row['calendardata'],
'calendardata' => is_resource($row['calendardata']) ? stream_get_contents($row['calendardata']) : $row['calendardata'],
'lastmodified' => $row['lastmodified'],
'etag' => '"'.$row['etag'].'"',
'size' => (int) $row['size'],
Expand All @@ -1279,7 +1293,7 @@ public function getSchedulingObjects($principalUri)
$result = [];
foreach ($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) {
$result[] = [
'calendardata' => $row['calendardata'],
'calendardata' => is_resource($row['calendardata']) ? stream_get_contents($row['calendardata']) : $row['calendardata'],
'uri' => $row['uri'],
'lastmodified' => $row['lastmodified'],
'etag' => '"'.$row['etag'].'"',
Expand Down Expand Up @@ -1311,13 +1325,22 @@ public function deleteSchedulingObject($principalUri, $objectUri)
*/
public function createSchedulingObject($principalUri, $objectUri, $objectData)
{
$stmt = $this->pdo->prepare('INSERT INTO '.$this->schedulingObjectTableName.' (principaluri, calendardata, uri, lastmodified, etag, size) VALUES (?, ?, ?, ?, ?, ?)');
$stmt = $this->pdo->prepare('INSERT INTO '.$this->schedulingObjectTableName.' (principaluri, calendardata, uri, lastmodified, etag, size) VALUES (:principaluri, :calendardata, :uri, :lastmodified, :etag, :size)');

if (is_resource($objectData)) {
$objectData = stream_get_contents($objectData);
}

$stmt->execute([$principalUri, $objectData, $objectUri, time(), md5($objectData), strlen($objectData)]);
$lastmodified = time();
$etag = md5($objectData);
$size = strlen($objectData);
$stmt->bindParam('principaluri', $principalUri, \PDO::PARAM_STR);
$stmt->bindParam('calendardata', $objectData, \PDO::PARAM_LOB);
$stmt->bindParam('uri', $objectUri, \PDO::PARAM_STR);
$stmt->bindParam('lastmodified', $lastmodified, \PDO::PARAM_INT);
$stmt->bindParam('etag', $etag, \PDO::PARAM_STR);
$stmt->bindParam('size', $size, \PDO::PARAM_INT);
$stmt->execute();
}

/**
Expand Down
45 changes: 26 additions & 19 deletions lib/CardDAV/Backend/PDO.php
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,9 @@ public function getCard($addressBookId, $cardUri)

$result['etag'] = '"'.$result['etag'].'"';
$result['lastmodified'] = (int) $result['lastmodified'];
if (is_resource($result['carddata'])) {
$result['carddata'] = stream_get_contents($result['carddata']);
}

return $result;
}
Expand Down Expand Up @@ -282,6 +285,9 @@ public function getMultipleCards($addressBookId, array $uris)
while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
$row['etag'] = '"'.$row['etag'].'"';
$row['lastmodified'] = (int) $row['lastmodified'];
if (is_resource($row['carddata'])) {
$row['carddata'] = stream_get_contents($row['carddata']);
}
$result[] = $row;
}

Expand Down Expand Up @@ -316,18 +322,18 @@ public function getMultipleCards($addressBookId, array $uris)
*/
public function createCard($addressBookId, $cardUri, $cardData)
{
$stmt = $this->pdo->prepare('INSERT INTO '.$this->cardsTableName.' (carddata, uri, lastmodified, addressbookid, size, etag) VALUES (?, ?, ?, ?, ?, ?)');
$stmt = $this->pdo->prepare('INSERT INTO '.$this->cardsTableName.' (carddata, uri, lastmodified, addressbookid, size, etag) VALUES (:carddata, :uri, :lastmodified, :addressbookid, :size, :etag)');

$etag = md5($cardData);

$stmt->execute([
$cardData,
$cardUri,
time(),
$addressBookId,
strlen($cardData),
$etag,
]);
$lastmodified = time();
$size = strlen($cardData);
$stmt->bindParam('carddata', $cardData, \PDO::PARAM_LOB);
$stmt->bindParam('uri', $cardUri, \PDO::PARAM_STR);
$stmt->bindParam('lastmodified', $lastmodified, \PDO::PARAM_INT);
$stmt->bindParam('addressbookid', $addressBookId, \PDO::PARAM_INT);
$stmt->bindParam('size', $size, \PDO::PARAM_INT);
$stmt->bindParam('etag', $etag, \PDO::PARAM_STR);
$stmt->execute();

$this->addChange($addressBookId, $cardUri, 1);

Expand Down Expand Up @@ -362,17 +368,18 @@ public function createCard($addressBookId, $cardUri, $cardData)
*/
public function updateCard($addressBookId, $cardUri, $cardData)
{
$stmt = $this->pdo->prepare('UPDATE '.$this->cardsTableName.' SET carddata = ?, lastmodified = ?, size = ?, etag = ? WHERE uri = ? AND addressbookid =?');
$stmt = $this->pdo->prepare('UPDATE '.$this->cardsTableName.' SET carddata = :carddata, lastmodified = :lastmodified, size = :size, etag = :etag WHERE uri = :uri AND addressbookid = :addressbookid');

$etag = md5($cardData);
$stmt->execute([
$cardData,
time(),
strlen($cardData),
$etag,
$cardUri,
$addressBookId,
]);
$lastmodified = time();
$size = strlen($cardData);
$stmt->bindParam('carddata', $cardData, \PDO::PARAM_LOB);
$stmt->bindParam('lastmodified', $lastmodified, \PDO::PARAM_INT);
$stmt->bindParam('size', $size, \PDO::PARAM_INT);
$stmt->bindParam('etag', $etag, \PDO::PARAM_STR);
$stmt->bindParam('uri', $cardUri, \PDO::PARAM_STR);
$stmt->bindParam('addressbookid', $addressBookId, \PDO::PARAM_INT);
$stmt->execute();

$this->addChange($addressBookId, $cardUri, 2);

Expand Down
21 changes: 21 additions & 0 deletions tests/Sabre/CalDAV/Backend/AbstractPDOTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,27 @@ public function testCreateCalendarObject()
], $row);
}

/**
* @see https://github.com/sabre-io/dav/issues/1587
*/
public function testCreateCalendarObjectWithIcsEscapes()
{
$backend = new PDO($this->pdo);
$returnedId = $backend->createCalendar('principals/user2', 'somerandomid', []);

// ICS data with escaped comma (\,) and newline (\n) in DESCRIPTION.
// These are standard RFC 5545 TEXT escapes but trigger PostgreSQL
// "invalid input syntax for type bytea" when calendardata is BYTEA
// and the parameter is bound as PARAM_STR instead of PARAM_LOB.
$object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nDESCRIPTION:Hello\\, world\\nSecond line\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n";

$backend->createCalendarObject($returnedId, 'ics-escapes-id', $object);

// Verify round-trip: read it back and compare
$result = $backend->getCalendarObject($returnedId, 'ics-escapes-id');
self::assertEquals($object, $result['calendardata']);
}

public function testGetMultipleObjects()
{
$backend = new PDO($this->pdo);
Expand Down