Пример #1
0
 /**
  * Checks if the submitted iCalendar data is in fact, valid.
  *
  * An exception is thrown if it's not.
  *
  * @param resource|string $data
  * @param bool $modified Should be set to true, if this event handler
  *                       changed &$data.
  * @return void
  */
 protected function validateVCard(&$data, &$modified)
 {
     // If it's a stream, we convert it to a string first.
     if (is_resource($data)) {
         $data = stream_get_contents($data);
     }
     $before = md5($data);
     // Converting the data to unicode, if needed.
     $data = DAV\StringUtil::ensureUTF8($data);
     if (md5($data) !== $before) {
         $modified = true;
     }
     try {
         // If the data starts with a [, we can reasonably assume we're dealing
         // with a jCal object.
         if (substr($data, 0, 1) === '[') {
             $vobj = VObject\Reader::readJson($data);
             // Converting $data back to iCalendar, as that's what we
             // technically support everywhere.
             $data = $vobj->serialize();
             $modified = true;
         } else {
             $vobj = VObject\Reader::read($data);
         }
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vCard or jCard data. Parse error: ' . $e->getMessage());
     }
     if ($vobj->name !== 'VCARD') {
         throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.');
     }
     if (!isset($vobj->UID)) {
         // No UID in vcards is invalid, but we'll just add it in anyway.
         $vobj->add('UID', DAV\UUIDUtil::getUUID());
         $data = $vobj->serialize();
         $modified = true;
     }
 }
Пример #2
0
 /**
  * Checks if the submitted iCalendar data is in fact, valid.
  *
  * An exception is thrown if it's not.
  *
  * @param resource|string $data
  * @param string $path
  * @param bool $modified Should be set to true, if this event handler
  *                       changed &$data.
  * @param RequestInterface $request The http request.
  * @param ResponseInterface $response The http response.
  * @param bool $isNew Is the item a new one, or an update.
  * @return void
  */
 protected function validateICalendar(&$data, $path, &$modified, RequestInterface $request, ResponseInterface $response, $isNew)
 {
     // If it's a stream, we convert it to a string first.
     if (is_resource($data)) {
         $data = stream_get_contents($data);
     }
     $before = md5($data);
     // Converting the data to unicode, if needed.
     $data = DAV\StringUtil::ensureUTF8($data);
     if ($before !== md5($data)) {
         $modified = true;
     }
     try {
         // If the data starts with a [, we can reasonably assume we're dealing
         // with a jCal object.
         if (substr($data, 0, 1) === '[') {
             $vobj = VObject\Reader::readJson($data);
             // Converting $data back to iCalendar, as that's what we
             // technically support everywhere.
             $data = $vobj->serialize();
             $modified = true;
         } else {
             $vobj = VObject\Reader::read($data);
         }
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage());
     }
     if ($vobj->name !== 'VCALENDAR') {
         throw new DAV\Exception\UnsupportedMediaType('This collection can only support iCalendar objects.');
     }
     $sCCS = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
     // Get the Supported Components for the target calendar
     list($parentPath) = Uri\split($path);
     $calendarProperties = $this->server->getProperties($parentPath, [$sCCS]);
     if (isset($calendarProperties[$sCCS])) {
         $supportedComponents = $calendarProperties[$sCCS]->getValue();
     } else {
         $supportedComponents = ['VJOURNAL', 'VTODO', 'VEVENT'];
     }
     $foundType = null;
     $foundUID = null;
     foreach ($vobj->getComponents() as $component) {
         switch ($component->name) {
             case 'VTIMEZONE':
                 continue 2;
             case 'VEVENT':
             case 'VTODO':
             case 'VJOURNAL':
                 if (is_null($foundType)) {
                     $foundType = $component->name;
                     if (!in_array($foundType, $supportedComponents)) {
                         throw new Exception\InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType);
                     }
                     if (!isset($component->UID)) {
                         throw new DAV\Exception\BadRequest('Every ' . $component->name . ' component must have an UID');
                     }
                     $foundUID = (string) $component->UID;
                 } else {
                     if ($foundType !== $component->name) {
                         throw new DAV\Exception\BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType);
                     }
                     if ($foundUID !== (string) $component->UID) {
                         throw new DAV\Exception\BadRequest('Every ' . $component->name . ' in this object must have identical UIDs');
                     }
                 }
                 break;
             default:
                 throw new DAV\Exception\BadRequest('You are not allowed to create components of type: ' . $component->name . ' here');
         }
     }
     if (!$foundType) {
         throw new DAV\Exception\BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL');
     }
     // We use an extra variable to allow event handles to tell us wether
     // the object was modified or not.
     //
     // This helps us determine if we need to re-serialize the object.
     $subModified = false;
     $this->server->emit('calendarObjectChange', [$request, $response, $vobj, $parentPath, &$subModified, $isNew]);
     if ($subModified) {
         // An event handler told us that it modified the object.
         $data = $vobj->serialize();
         // Using md5 to figure out if there was an *actual* change.
         if (!$modified && $before !== md5($data)) {
             $modified = true;
         }
     }
 }
Пример #3
0
 /**
  * Checks if the submitted iCalendar data is in fact, valid.
  *
  * An exception is thrown if it's not.
  *
  * @param resource|string $data
  * @param bool $modified Should be set to true, if this event handler
  *                       changed &$data.
  * @return void
  */
 protected function validateVCard(&$data, &$modified)
 {
     // If it's a stream, we convert it to a string first.
     if (is_resource($data)) {
         $data = stream_get_contents($data);
     }
     $before = $data;
     try {
         // If the data starts with a [, we can reasonably assume we're dealing
         // with a jCal object.
         if (substr($data, 0, 1) === '[') {
             $vobj = VObject\Reader::readJson($data);
             // Converting $data back to iCalendar, as that's what we
             // technically support everywhere.
             $data = $vobj->serialize();
             $modified = true;
         } else {
             $vobj = VObject\Reader::read($data);
         }
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vCard or jCard data. Parse error: ' . $e->getMessage());
     }
     if ($vobj->name !== 'VCARD') {
         throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.');
     }
     $options = VObject\Node::PROFILE_CARDDAV;
     $prefer = $this->server->getHTTPPrefer();
     if ($prefer['handling'] !== 'strict') {
         $options |= VObject\Node::REPAIR;
     }
     $messages = $vobj->validate($options);
     $highestLevel = 0;
     $warningMessage = null;
     // $messages contains a list of problems with the vcard, along with
     // their severity.
     foreach ($messages as $message) {
         if ($message['level'] > $highestLevel) {
             // Recording the highest reported error level.
             $highestLevel = $message['level'];
             $warningMessage = $message['message'];
         }
         switch ($message['level']) {
             case 1:
                 // Level 1 means that there was a problem, but it was repaired.
                 $modified = true;
                 break;
             case 2:
                 // Level 2 means a warning, but not critical
                 break;
             case 3:
                 // Level 3 means a critical error
                 throw new DAV\Exception\UnsupportedMediaType('Validation error in vCard: ' . $message['message']);
         }
     }
     if ($warningMessage) {
         $this->server->httpResponse->setHeader('X-Sabre-Ew-Gross', 'vCard validation warning: ' . $warningMessage);
         // Re-serializing object.
         $data = $vobj->serialize();
         if (!$modified && strcmp($data, $before) !== 0) {
             // This ensures that the system does not send an ETag back.
             $modified = true;
         }
     }
     // Destroy circular references to PHP will GC the object.
     $vobj->destroy();
 }
Пример #4
0
 function testParseStreamArg()
 {
     $input = array("vcard", array(array("FN", new \StdClass(), 'text', "foo")));
     $stream = fopen('php://memory', 'r+');
     fwrite($stream, json_encode($input));
     rewind($stream);
     $result = VObject\Reader::readJson($stream, 0);
     $this->assertEquals('foo', $result->FN->getValue());
 }
Пример #5
0
 /**
  * Checks if the submitted iCalendar data is in fact, valid.
  *
  * An exception is thrown if it's not.
  *
  * @param resource|string $data
  * @param string $path
  * @param bool $modified Should be set to true, if this event handler
  *                       changed &$data.
  * @param RequestInterface $request The http request.
  * @param ResponseInterface $response The http response.
  * @param bool $isNew Is the item a new one, or an update.
  * @return void
  */
 protected function validateICalendar(&$data, $path, &$modified, RequestInterface $request, ResponseInterface $response, $isNew)
 {
     // If it's a stream, we convert it to a string first.
     if (is_resource($data)) {
         $data = stream_get_contents($data);
     }
     $before = $data;
     try {
         // If the data starts with a [, we can reasonably assume we're dealing
         // with a jCal object.
         if (substr($data, 0, 1) === '[') {
             $vobj = VObject\Reader::readJson($data);
             // Converting $data back to iCalendar, as that's what we
             // technically support everywhere.
             $data = $vobj->serialize();
             $modified = true;
         } else {
             $vobj = VObject\Reader::read($data);
         }
     } catch (VObject\ParseException $e) {
         throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage());
     }
     if ($vobj->name !== 'VCALENDAR') {
         throw new DAV\Exception\UnsupportedMediaType('This collection can only support iCalendar objects.');
     }
     $sCCS = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set';
     // Get the Supported Components for the target calendar
     list($parentPath) = Uri\split($path);
     $calendarProperties = $this->server->getProperties($parentPath, [$sCCS]);
     if (isset($calendarProperties[$sCCS])) {
         $supportedComponents = $calendarProperties[$sCCS]->getValue();
     } else {
         $supportedComponents = ['VJOURNAL', 'VTODO', 'VEVENT'];
     }
     $foundType = null;
     foreach ($vobj->getComponents() as $component) {
         switch ($component->name) {
             case 'VTIMEZONE':
                 continue 2;
             case 'VEVENT':
             case 'VTODO':
             case 'VJOURNAL':
                 $foundType = $component->name;
                 break;
         }
     }
     if (!$foundType || !in_array($foundType, $supportedComponents)) {
         throw new Exception\InvalidComponentType('iCalendar objects must at least have a component of type ' . implode(', ', $supportedComponents));
     }
     $options = VObject\Node::PROFILE_CALDAV;
     $prefer = $this->server->getHTTPPrefer();
     if ($prefer['handling'] !== 'strict') {
         $options |= VObject\Node::REPAIR;
     }
     $messages = $vobj->validate($options);
     $highestLevel = 0;
     $warningMessage = null;
     // $messages contains a list of problems with the vcard, along with
     // their severity.
     foreach ($messages as $message) {
         if ($message['level'] > $highestLevel) {
             // Recording the highest reported error level.
             $highestLevel = $message['level'];
             $warningMessage = $message['message'];
         }
         switch ($message['level']) {
             case 1:
                 // Level 1 means that there was a problem, but it was repaired.
                 $modified = true;
                 break;
             case 2:
                 // Level 2 means a warning, but not critical
                 break;
             case 3:
                 // Level 3 means a critical error
                 throw new DAV\Exception\UnsupportedMediaType('Validation error in iCalendar: ' . $message['message']);
         }
     }
     if ($warningMessage) {
         $response->setHeader('X-Sabre-Ew-Gross', 'iCalendar validation warning: ' . $warningMessage);
     }
     // We use an extra variable to allow event handles to tell us wether
     // the object was modified or not.
     //
     // This helps us determine if we need to re-serialize the object.
     $subModified = false;
     $this->server->emit('calendarObjectChange', [$request, $response, $vobj, $parentPath, &$subModified, $isNew]);
     if ($modified || $subModified) {
         // An event handler told us that it modified the object.
         $data = $vobj->serialize();
         // Using md5 to figure out if there was an *actual* change.
         if (!$modified && strcmp($data, $before) !== 0) {
             $modified = true;
         }
     }
     // Destroy circular references so PHP will garbage collect the object.
     $vobj->destroy();
 }