Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
54 changes: 37 additions & 17 deletions lib/CalDAV/Backend/PDO.php
Original file line number Diff line number Diff line change
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 @@ -1311,13 +1322,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
39 changes: 20 additions & 19 deletions lib/CardDAV/Backend/PDO.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,18 +316,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 +362,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
24 changes: 24 additions & 0 deletions tests/Sabre/CalDAV/Backend/AbstractPDOTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,30 @@ 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');
if (is_resource($result['calendardata'])) {
$result['calendardata'] = stream_get_contents($result['calendardata']);
}
self::assertEquals($object, $result['calendardata']);
}

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