CardDAV-PHP
CardDAV-PHP copied to clipboard
Works good with SOGo, SabreDAV fix for simplify() method
Hi,
SOGo catalog list for simplify:
<?xml version="1.0" encoding="utf-8" ?>
- <D:multistatus xmlns:ap="http://apache.org/dav/props/" xmlns:D="DAV:">
- <D:response>
<D:href>/SOGo/dav/sogo1/Contacts/</D:href>
- <D:propstat>
<D:status>HTTP/1.1 200 OK</D:status>
- <D:prop>
<D:getlastmodified>Mon, 25 Jun 2012 08:45:47 -0400</D:getlastmodified>
<D:getetag>"None"</D:getetag>
- <D:resourcetype>
<D:collection />
</D:resourcetype>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
<D:displayname>Contacts</D:displayname>
<D:href>/SOGo/dav/sogo1/Contacts/</D:href>
<ap:executable>0</ap:executable>
</D:prop>
</D:propstat>
</D:response>
+ <D:response>
<D:href>/SOGo/dav/sogo1/Contacts/personal/</D:href>
- <D:propstat>
<D:status>HTTP/1.1 200 OK</D:status>
- <D:prop>
<D:getlastmodified>Mon, 25 Jun 2012 08:45:47 -0400</D:getlastmodified>
<D:getetag>"None"</D:getetag>
- <D:resourcetype>
<D:collection />
<vcard-collection xmlns="http://groupdav.org/" />
<addressbook xmlns="urn:ietf:params:xml:ns:carddav" />
</D:resourcetype>
<D:getcontenttype>httpd/unix-directory</D:getcontenttype>
<D:displayname>Hermeegille</D:displayname>
<D:href>/SOGo/dav/sogo1/Contacts/personal/</D:href>
<ap:executable>0</ap:executable>
</D:prop>
</D:propstat>
</D:response>
</D:multistatus>
produces this output:
<?xml version="1.0" encoding="UTF-8" ?>
- <response>
- <addressbook_element>
<display_name>Contacts</display_name>
<url>http://sogo-demo.inverse.ca/SOGo/dav/sogo1/Contacts/</url>
<last_modified>Mon, 25 Jun 2012 08:45:47 -0400</last_modified>
</addressbook_element>
- <addressbook_element>
<display_name>Hermeegille</display_name>
<url>http://sogo-demo.inverse.ca/SOGo/dav/sogo1/Contacts/personal/</url>
<last_modified>Mon, 25 Jun 2012 08:45:47 -0400</last_modified>
</addressbook_element>
SabreDAV returns list folders in following format:
<?xml version="1.0" encoding="utf-8" ?>
- <d:multistatus xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns" xmlns:cal="urn:ietf:params:xml:ns:caldav" xmlns:cs="http://calendarserver.org/ns/" xmlns:card="urn:ietf:params:xml:ns:carddav">
- <d:response>
<d:href>/trunk/dav.php/addressbooks/test%40localhost/</d:href>
- <d:propstat>
- <d:prop>
- <d:resourcetype>
<d:collection />
</d:resourcetype>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
- <d:response>
<d:href>/trunk/dav.php/addressbooks/test%40localhost/Default/</d:href>
- <d:propstat>
- <d:prop>
- <d:resourcetype>
<d:collection />
<card:addressbook />
</d:resourcetype>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
+ <d:response>
<d:href>/trunk/dav.php/addressbooks/test%40localhost/Collected/</d:href>
- <d:propstat>
- <d:prop>
- <d:resourcetype>
<d:collection />
<card:addressbook />
</d:resourcetype>
</d:prop>
<d:status>HTTP/1.1 200 OK</d:status>
</d:propstat>
</d:response>
</d:multistatus>
simplify() returns empty node. You may add the following fix:
private function simplify($response, $include_vcards = true)
{
$response = $this->clean_response($response);
$xml = new SimpleXMLElement($response);
$simplified_xml = new XMLWriter();
$simplified_xml->openMemory();
$simplified_xml->setIndent(4);
$simplified_xml->startDocument('1.0', 'utf-8');
$simplified_xml->startElement('response');
foreach ($xml->response as $response)
{
if (preg_match('/vcard/', $response->propstat->prop->getcontenttype) || preg_match('/vcf/', $response->href))
{
$id = basename($response->href);
$id = str_replace('.vcf', null, $id);
if (!empty($id))
{
$simplified_xml->startElement('element');
$simplified_xml->writeElement('id', $id);
$simplified_xml->writeElement('etag', str_replace('"', null, $response->propstat->prop->getetag));
$simplified_xml->writeElement('last_modified', $response->propstat->prop->getlastmodified);
if ($include_vcards === true)
{
$simplified_xml->writeElement('vcard', $this->get_vcard($id));
}
$simplified_xml->endElement();
}
}
else if (preg_match('/unix-directory/', $response->propstat->prop->getcontenttype))
{
if (isset($response->propstat->prop->href))
{
$href = $response->propstat->prop->href;
}
else if (isset($response->href))
{
$href = $response->href;
}
else
{
$href = null;
}
$url = str_replace($this->url_parts['path'], null, $this->url) . $href;
$simplified_xml->startElement('addressbook_element');
$simplified_xml->writeElement('display_name', $response->propstat->prop->displayname);
$simplified_xml->writeElement('url', $url);
$simplified_xml->writeElement('last_modified', $response->propstat->prop->getlastmodified);
$simplified_xml->endElement();
}
else // fix here
{
if (isset($response->href))
{
$href = $response->href;
$url = str_replace($this->url_parts['path'], null, $this->url) . $href;
$simplified_xml->startElement('addressbook_element');
$simplified_xml->writeElement('display_name', $href);
$simplified_xml->writeElement('url', $url);
$simplified_xml->endElement();
}
}
}
$simplified_xml->endElement();
$simplified_xml->endDocument();
return $simplified_xml->outputMemory();
}
The 'else // fix here' is not a good enough condition to be consider as a vcard list. The check should :
else if (preg_match('/x-vlist/', $response->propstat->prop->getcontenttype))
However the extension is not the same now ie: '.vlf' So it still won't work but it is a start.
It is possible only to check <card:addressbook /> empty node?
i've fixed it like that: -else if (preg_match('/unix-directory/', $response->propstat->prop->getcontenttype)) +else if ($response->propstat->prop->resourcetype->addressbook->getName()=="addressbook")
and in private function clean_response($response) { $response = utf8_encode($response); $response = str_replace('card:', null, $response); $response = str_replace('D:', null, $response);
Maybe a combination of preg_match and getName would be better?
I implement it in commit https://github.com/xbgmsharp/sogosync/commit/88febac5c886d66f539041a248bf715cfcb0b7a8