Steps to setting up a CardDAV and CalDAV server

1,929 views
Skip to first unread message

BN

unread,
May 18, 2012, 10:17:52 PM5/18/12
to sabredav...@googlegroups.com
I have a contact/calendar management application written in PHP.  I am looking to implement a CardDAV and CalDAV server so that users can sync with my app.  I have gone through the documentation on the Google code site, tried to set up a standalone CardDAV/CalDAV server, but was not successful.  The whole concept of WebDAV and syncing is new to me, so please forgive me if I am not seeing the big picture.

My current setup is a linux VM.  In my webroot (/var/www), I have a folder called test.  I have set up an apache config file as follows:
<VirtualHost *:80>
    ServerName test.tst
    ServerAlias www.test.tst
    DocumentRoot /var/www/test
    ErrorLog /var/log/tester-error_log
    <Directory />
        AllowOverride all
        Options Indexes FollowSymLinks
    </Directory>
</VirtualHost>

I have also modified my hosts file on my physical computer so that it redirect "www.test.tst" to the test directory.  Within test, sdav holds the contents of /lib of the SabreDAV zip (which is a folder called Sabre and a file Sabre.includes.php).  I also created the data and public folders so sdav looks like:
/sdav
/Sabre
/data
/public
Sabre.includes.php

1) I read that it is recommended to have SabreDAV in the root.  Does this imply that it should be in /var/www or is test considered to be a root?  Could I just remove the sdav folder completely and move everything up one?

Using addressbookserver.php from the examples folder, I only changed two lines:
$baseUri = '/sdav/addressbookserver.php';
and
$pdo = new PDO('mysql:host=localhost;dbname=test','root',''); (the DB contains all the tables generated from the mysql. files in examples/sql)

So addressbookserver.php is otherwise the same.  I then visited www.test.tst/sdav/addressbookserver.php which prompted me for the default "admin/admin" and then showed the index page as having:
principals
addressbooks

I then opened up Thunderbird with the SOGo connector extension (http://www.sogo.nu/english/downloads/frontends.html), and tried to add a remote address book.  I tried entering the URL as both:

I added a new contact in each case.  I hit "synchronize" both times.

2) At this point, should I have been able to see the new contacts pushed somewhere into my CardDAV server?  I tried to visit the folders "principals" and "addressbooks" in the index, but both yielded blank pages.  I viewed the records in the database tables "addressbooks" and "cards", but both were empty.

Was something incorrect in my setup?

The following is for more down the line, but it revolves around getting CardDAV/CalDAV set up with my own app.  I know that the documentation says I will have to write my own backend classes, but what functionality is actually contained in the default ones?  Is it handling requests, telling which database to push and pull from, etc?  Which files are these exactly? Is it only the following?
/lib/Sabre/CardDAV/Backend/
Abstract.php
PDO.php

So will I need to rewrite these so they are geared toward my contacts, calendars, and users database tables (meaning they know which fields to pull from)?

Any guidance in helping me with my struggles will be greatly, greatly appreciated.




BN

unread,
May 19, 2012, 4:33:40 AM5/19/12
to sabredav...@googlegroups.com
EDIT:
I meant to say the URLs I tried in SOGo connector were:
http://test.tst/sdav/addressbookserver.php/
http://test.tst/sdav/addressbookserver.php

Evert Pot

unread,
May 19, 2012, 7:56:47 AM5/19/12
to sabredav...@googlegroups.com
On May 19, 2012, at 10:33 AM, BN wrote:

> EDIT:
> I meant to say the URLs I tried in SOGo connector were:
> http://test.tst/sdav/addressbookserver.php/
> http://test.tst/sdav/addressbookserver.php


For the SoGo connector you need a full url to an addressbook, such as:

> http://test.tst/sdav/addressbookserver.php/addressbooks/[name]/


BN

unread,
May 20, 2012, 2:10:21 AM5/20/12
to sabredav...@googlegroups.com
Thank you very much, Evert.  That was definitely the problem.

I am also having problems with the CalDAV with Mozilla Lightning.

I created a new CalDAV calendar with the url as:
http://www.test.tst/calendarserver.php/calendars/admin/[name]

I created new events, and as soon as I hit "Synchronize", the events disappeared from my Lightning calendar.  I visited the address (http://www.test.tst/calendarserver.php/calendars/admin/[name]) in my web browser, and saw that an iCal file was created for each event.  Although when I synchronize, why does it not also pull the events into my Lighting Calendar?

Evert Pot

unread,
May 21, 2012, 6:04:38 AM5/21/12
to SabreDAV Discussion
On May 20, 8:10 am, BN <brett.shigoto.c...@gmail.com> wrote:
> Thank you very much, Evert.  That was definitely the problem.
>
> I am also having problems with the CalDAV with Mozilla Lightning.
>
> I created a new CalDAV calendar with the url as:http://www.test.tst/calendarserver.php/calendars/admin/[name]
>
> I created new events, and as soon as I hit "Synchronize", the events
> disappeared from my Lightning calendar.  I visited the address
> (http://www.test.tst/calendarserver.php/calendars/admin/[name]) in my web
> browser, and saw that an iCal file was created for each event.  Although
> when I synchronize, why does it not also pull the events into my Lighting
> Calendar?

This *should* work. Are you getting any errors at all? The best way to
really find out what may be wrong is to setup Charles HTTP proxy and
see if there are any errors.

When you setup the calendar, there should be a number of REPORT http
requests that return the events.

Let me know if you can find out :)

Evert

BN

unread,
May 21, 2012, 8:45:53 PM5/21/12
to sabredav...@googlegroups.com
Hey Evert,

It is now working in Lightning.  I am not quite sure exactly what I changed, but I don't believe I was getting my errors.  I have successfully gotten my test CardDAV server to sync with SOGo Connector and Apple Addressbook, and the test CalDAV server to sync with Mozilla Lightning and Apple iCal.

Now my goal is to implement SabreDAV into my own application.  I have read through the documentation and I understand that I need to create my own backend classes.  I have looked through the backend classes on:
http://code.google.com/p/sabredav/wiki/IntegrationGuide#Backends

And I am still a little cloudly on how I can integrate SabreDAV into my app.  I will give a brief overview.  From my app, each user has contacts and calendars that belong to them.  These contacts and calendars are tied to the user through foreign keys.

I guess my biggest confusion lies within how I can integrate SabreDAV into my app when my database looks different.  Looking through the Backend classes, such as Sabre_CardDAV_Backend_PDO, I can see that its main purpose is to create, update, retrieve, and delete contact data.  And in this class, I can see that it is geared specifically toward the default database schema provided in the example mysql files.

My contacts database has separate columns for things like first name, surname, work email, phone, etc.  It also has a vcard column which is just a text type, contains straight vcard data and is updated whenever a user updates one of the contact fields.  I see that the SabreDAV table "cards" is probably the closest thing to this.

1) How much am I allowed to modify the databases that were setup in the examples/sql files.  For example, does my contacts table have to be called "cards"?  And can I append extra columns on to my contacts such as "first name", "last name", "email", etc?  More specifically, are all the database queries for performing create/update/retrieve/delete to contact data all specified within the "Sabre_CardDAV_Backend_PDO"?  Or are there other classes in SabreDAV that depend on, for example, the vcard field to be called "carddata"?

2) An extension of #1, so basically the purpose of these backend classes is to handle update/create/retrieve/delete?  And as long as I implement and follow the abstract class, and as long as my functions output the data in the same format, I am on the right track?

Sorry if my questions are too general, I am still just wrapping my head around this.

Evert Pot

unread,
May 22, 2012, 4:35:46 AM5/22/12
to sabredav...@googlegroups.com

On May 22, 2012, at 2:45 AM, BN wrote:

> Hey Evert,
>
> It is now working in Lightning. I am not quite sure exactly what I changed, but I don't believe I was getting my errors. I have successfully gotten my test CardDAV server to sync with SOGo Connector and Apple Addressbook, and the test CalDAV server to sync with Mozilla Lightning and Apple iCal.
>
> Now my goal is to implement SabreDAV into my own application. I have read through the documentation and I understand that I need to create my own backend classes. I have looked through the backend classes on:
> http://code.google.com/p/sabredav/wiki/IntegrationGuide#Backends
>
> And I am still a little cloudly on how I can integrate SabreDAV into my app. I will give a brief overview. From my app, each user has contacts and calendars that belong to them. These contacts and calendars are tied to the user through foreign keys.
>
> I guess my biggest confusion lies within how I can integrate SabreDAV into my app when my database looks different. Looking through the Backend classes, such as Sabre_CardDAV_Backend_PDO, I can see that its main purpose is to create, update, retrieve, and delete contact data. And in this class, I can see that it is geared specifically toward the default database schema provided in the example mysql files.
>
> My contacts database has separate columns for things like first name, surname, work email, phone, etc. It also has a vcard column which is just a text type, contains straight vcard data and is updated whenever a user updates one of the contact fields. I see that the SabreDAV table "cards" is probably the closest thing to this.
>
> 1) How much am I allowed to modify the databases that were setup in the examples/sql files. For example, does my contacts table have to be called "cards"? And can I append extra columns on to my contacts such as "first name", "last name", "email", etc? More specifically, are all the database queries for performing create/update/retrieve/delete to contact data all specified within the "Sabre_CardDAV_Backend_PDO"? Or are there other classes in SabreDAV that depend on, for example, the vcard field to be called "carddata"?
>
> 2) An extension of #1, so basically the purpose of these backend classes is to handle update/create/retrieve/delete? And as long as I implement and follow the abstract class, and as long as my functions output the data in the same format, I am on the right track?

Yes, you should just extend the abstract classes, and make sure you are returning the correct responses from these methods.
The classes themselves have a lot of documentation embedded, so it shouldn't be too terribly difficult.

The caveat is that you need return actual 'vcards' and 'icalendar' objects. If your database has these in separate fields,
it means that your backend classes must generate these on the fly.

The Sabre_VObject library is specifically for parsing, creating and manipulation of these objects.

HOWEVER

If a client, such as Thunderbird of OS X addressbook uploads a vcard, this means you have to parse it and split
up the information in your separate database fields.

But some clients really dislike it when they upload a new contact, retrieve it again and notice it has changed
in the meanwhile.

So you can give this a shot, but I would recommend actually *also* storing the entire vcard and icalendar object
the client sends.

I hope this makes sense..

Evert

>
> Sorry if my questions are too general, I am still just wrapping my head around this.
>
> On Monday, May 21, 2012 3:04:38 AM UTC-7, Evert Pot wrote:
> On May 20, 8:10 am, BN <brett.shigoto.c...@gmail.com> wrote:
> > Thank you very much, Evert. That was definitely the problem.
> >
> > I am also having problems with the CalDAV with Mozilla Lightning.
> >
> > I created a new CalDAV calendar with the url as:http://www.test.tst/calendarserver.php/calendars/admin/[name]
> >
> > I created new events, and as soon as I hit "Synchronize", the events
> > disappeared from my Lightning calendar. I visited the address
> > (http://www.test.tst/calendarserver.php/calendars/admin/[name]) in my web
> > browser, and saw that an iCal file was created for each event. Although
> > when I synchronize, why does it not also pull the events into my Lighting
> > Calendar?
>
> This *should* work. Are you getting any errors at all? The best way to
> really find out what may be wrong is to setup Charles HTTP proxy and
> see if there are any errors.
>
> When you setup the calendar, there should be a number of REPORT http
> requests that return the events.
>
> Let me know if you can find out :)
>
> Evert
>
> --
> You received this message because you are subscribed to the Google Groups "SabreDAV Discussion" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/sabredav-discuss/-/UiShcRjNbQkJ.
> To post to this group, send email to sabredav...@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discu...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

BN

unread,
May 22, 2012, 2:28:20 PM5/22/12
to sabredav...@googlegroups.com
Thank you for the response, it is making a lot more sense now.

I do have import/export of vCard in my app, so I can parse out vCard data to my database fields, but from this:


> But some clients really dislike it when they upload a new contact, retrieve it again and notice it has changed in the meanwhile.

...does that mean I will eventually run into trouble?  So for example, say a user adds a contact to the database from a CardDAV client.  It creates a record in my contacts database both with a vCard object and normal text fields representing name, phone, etc.  A user then runs my app in a web browser, edits a phone number field in the database, and in the background, the vCard object is updated.  So if they decide to sync using CardDAV client, it will not properly send the updated contact data?

Also, just wanted to thank you for your patience and answers.  And of course for developing this project, which has been a great help.
> To post to this group, send email to sabredav-discuss@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discuss+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

> To post to this group, send email to sabredav-discuss@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discuss+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

> To post to this group, send email to sabredav-discuss@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discuss+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

> To post to this group, send email to sabredav-discuss@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discuss+unsubscribe@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/sabredav-discuss?hl=en.

> To post to this group, send email to sabredav-discuss@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discuss+unsubscribe@googlegroups.com.

Evert Pot

unread,
May 22, 2012, 5:01:15 PM5/22/12
to sabredav...@googlegroups.com
> > But some clients really dislike it when they upload a new contact, retrieve it again and notice it has changed in the meanwhile.
>
> ...does that mean I will eventually run into trouble? So for example, say a user adds a contact to the database from a CardDAV client. It creates a record in my contacts database both with a vCard object and normal text fields representing name, phone, etc. A user then runs my app in a web browser, edits a phone number field in the database, and in the background, the vCard object is updated. So if they decide to sync using CardDAV client, it will not properly send the updated contact data?

No, if you use this approach, you're completely fine. This is the best way to approach it, hands down :)

Evert

BN

unread,
May 22, 2012, 7:46:44 PM5/22/12
to sabredav...@googlegroups.com
That's good to hear.  Still a few more clarifications left:

1) When you say "vCard Object", is that simply referring to the field "carddata" that has raw vCard data?  Or is that something separate?  I guess this is still me getting confused about WebDAV.  When I open my CardDAV server through a browser plugin, and I navigate to an addressbook with .vcf files, there no actual vCard files stored anywhere, correct?  It is just when a request is made for a "vCard" file, the vCard data is retrieved from the database, then it is built using Sabre_VObject?

2) Would it cause any problems to rename the carddata field and change the data type to "text" (as long as I take this into account in the backend classes)?  My app is sharing databases with another app and there is already a raw vCard field of data type "text".  I was wondering if I could just reuse this for SabreDAV.   I noticed that the field 'carddata' is referenced in the class Sabre_CardDAV_Card, so would that mean I would have to change it there in addition to the backend classes?

Evert Pot

unread,
May 23, 2012, 9:10:28 AM5/23/12
to sabredav...@googlegroups.com

On May 23, 2012, at 1:46 AM, BN wrote:

> That's good to hear. Still a few more clarifications left:
>
> 1) When you say "vCard Object", is that simply referring to the field "carddata" that has raw vCard data? Or is that something separate?

Yes, I was talking about the actual field / blob.

> I guess this is still me getting confused about WebDAV. When I open my CardDAV server through a browser plugin, and I navigate to an addressbook with .vcf files, there no actual vCard files stored anywhere, correct? It is just when a request is made for a "vCard" file, the vCard data is retrieved from the database, then it is built using Sabre_VObject?

No you only need that lib to manipulate the objects, or create new ones from scratch.. or read them. If you already have them stored, you can just return them as-is.

>
> 2) Would it cause any problems to rename the carddata field and change the data type to "text" (as long as I take this into account in the backend classes)? My app is sharing databases with another app and there is already a raw vCard field of data type "text". I was wondering if I could just reuse this for SabreDAV. I noticed that the field 'carddata' is referenced in the class Sabre_CardDAV_Card, so would that mean I would have to change it there in addition to the backend classes?

There is completely zero dependency on the existing database schema. If you create your own backend class, you can store it in whatever format you want.

I would want to suggest.. try it out and report back when you run into more specific problems..

Evert

>
> On Tuesday, May 22, 2012 2:01:15 PM UTC-7, Evert Pot wrote:
> > > But some clients really dislike it when they upload a new contact, retrieve it again and notice it has changed in the meanwhile.
> >
> > ...does that mean I will eventually run into trouble? So for example, say a user adds a contact to the database from a CardDAV client. It creates a record in my contacts database both with a vCard object and normal text fields representing name, phone, etc. A user then runs my app in a web browser, edits a phone number field in the database, and in the background, the vCard object is updated. So if they decide to sync using CardDAV client, it will not properly send the updated contact data?
>
> No, if you use this approach, you're completely fine. This is the best way to approach it, hands down :)
>
> Evert
>
> On Tuesday, May 22, 2012 2:01:15 PM UTC-7, Evert Pot wrote:
> > > But some clients really dislike it when they upload a new contact, retrieve it again and notice it has changed in the meanwhile.
> >
> > ...does that mean I will eventually run into trouble? So for example, say a user adds a contact to the database from a CardDAV client. It creates a record in my contacts database both with a vCard object and normal text fields representing name, phone, etc. A user then runs my app in a web browser, edits a phone number field in the database, and in the background, the vCard object is updated. So if they decide to sync using CardDAV client, it will not properly send the updated contact data?
>
> No, if you use this approach, you're completely fine. This is the best way to approach it, hands down :)
>
> Evert
>
> --
> You received this message because you are subscribed to the Google Groups "SabreDAV Discussion" group.
> To view this discussion on the web visit https://groups.google.com/d/msg/sabredav-discuss/-/AXte7EOi7UYJ.
> To post to this group, send email to sabredav...@googlegroups.com.
> To unsubscribe from this group, send email to sabredav-discu...@googlegroups.com.

BN

unread,
May 30, 2012, 7:53:20 PM5/30/12
to sabredav...@googlegroups.com
Hi Evert,

I took your advice and wrote some custom backend classes.  So far I have a CardDAV/CalDAV server running and it is functional.  SabreDAV has been an amazing help, so thank you for that.

I have been working with it for the past week and have run into some roadblocks, so I have returned.

1) Rewrite Rules.  I have my SabreDAV server running in the webroot (/var/www/server.php) and my base URI is set as "/server.php".  Is it possible to create rewrite rules so that users can enter shortened URLs when adding CardDAV/CalDAV accounts to mobile devices?

For example, instead of adding a CardDAV account as "http://www.test.tst/server.php/addressbooks/firstname.lastname/default/", I would like to have it be shortened to something like: "http://www.test.tst/sync/ab/.

I have tried the following in my .htaccess (located in the same directory as sever.php):
<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteRule    ^sync/ab/([A-Za-z0-9\.-]+)/?$    server.php/addressbooks/$1/default/
</IfModule>

2) Sorry to bring this up again, but this is more of a concern.  My installation of SabreDAV is using my database for my app.  As mentioned before, my "cards" table has the raw vCard data stored in a field called "vcard".  Similarly, my "calendarsobjects" table has a foreign key for the "calendars" table as "cal_id" (rather than "calendarid").  I created my own CardDAV and CalDAV backend classes, but in order to make it fully functional, I also had to modify the classes Sabre_CardDAV_Card and Sabre_CalDAV_CalendarObject (changing any instance of "carddata" to "vcard" and any instance of "calendar_id" to "cal_id").  I believe I remember reading somewhere that it was recommended not to modify non-backend classes.  So I am concerned that this will cause issues later if there are updates.  Did I approach this wrong?  Was I supposed to create backend classes for Sabre_CardDAV_Card and Sabre_CalDAV_CalendarObject instead?

Thanks again, Evert

Evert Pot

unread,
May 31, 2012, 6:13:14 AM5/31/12
to SabreDAV Discussion
Hi!

On May 31, 1:53 am, BN <brett.shigoto.c...@gmail.com> wrote:
> Hi Evert,
>
> I took your advice and wrote some custom backend classes.  So far I have a
> CardDAV/CalDAV server running and it is functional.  SabreDAV has been an
> amazing help, so thank you for that.
>
> I have been working with it for the past week and have run into some
> roadblocks, so I have returned.
>
> 1) Rewrite Rules.  I have my SabreDAV server running in the webroot
> (/var/www/server.php) and my base URI is set as "/server.php".  Is it
> possible to create rewrite rules so that users can enter shortened URLs
> when adding CardDAV/CalDAV accounts to mobile devices?
>
> For example, instead of adding a CardDAV account as
> "http://www.test.tst/server.php/addressbooks/firstname.lastname/default/",
> I would like to have it be shortened to something like:
> "http://www.test.tst/sync/ab/.

No, this is not possible in this way.. I would recommend adding a
rewrite that just takes out the 'server.php' bit.
What you could try however, is a redirect. I just don't know for sure
if clients will follow it.

So you will have to test this first.

[snip]


>
> 2) Sorry to bring this up again, but this is more of a concern.  My
> installation of SabreDAV is using my database for my app.  As mentioned
> before, my "cards" table has the raw vCard data stored in a field called
> "vcard".  Similarly, my "calendarsobjects" table has a foreign key for the
> "calendars" table as "cal_id" (rather than "calendarid").  I created my own
> CardDAV and CalDAV backend classes, but in order to make it fully
> functional, I also had to modify the classes Sabre_CardDAV_Card and
> Sabre_CalDAV_CalendarObject (changing any instance of "carddata" to "vcard"
> and any instance of "calendar_id" to "cal_id").  I believe I remember
> reading somewhere that it was recommended not to modify non-backend
> classes.  So I am concerned that this will cause issues later if there are
> updates.  Did I approach this wrong?  Was I supposed to create backend
> classes for Sabre_CardDAV_Card and Sabre_CalDAV_CalendarObject instead?

The answer is much simpler.. Your database fields don't exactly match
what you need to return from the functions in the backend classes. Why
don't you just change the data before you return it?

Just loop through the arrays you're getting back from mysql, and
transform the array..

Evert

BN

unread,
May 31, 2012, 2:53:00 PM5/31/12
to sabredav...@googlegroups.com
Hello Evert,

To 1)
I am new to using RewriteRules, so I guess I don't completely understand why.  I set up a test website to try out Rewrite rules:
/var/www/testrewrite/
    addressbooks/
        firstname1.lastname1
            contacts/
                index.php
        firstname2.lastname2
            contacts/
                index.php
        firstname3.lastname3
            contacts/
                index.php

Each index.php contained different text.  My Rewrite rules were:

<IfModule mod_rewrite.c>
   RewriteEngine on
   RewriteRule    ^sync/card/([A-Za-z0-9\.-]+)/?$    addressbooks/$1/contacts/index.php
</IfModule>

Since that worked, so I am confused as to why it doesn't apply to SabreDAV.  Even though SabreDAV doesn't actually create addressbooks/username/ directories, I still thought that since you can visit the URL in the browser, it will work.  Does it have to do with the fact that it is running the server.php?  And how could I take out the server.php using rewrite?

To 2)

Are you referring to the function of the backend classes that returns data about a card or a calendarobject?  Using the class Sabre_CardDAV_Backend_PDO as an example, the resulting data in $result after the database query has raw vCard data in an associative array where the array key is "carddata".  So in my case, I just need to modify the array to change the "vcard" key to "carddata"?

    public function getCard($addressBookId, $cardUri) {

        $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ? LIMIT 1');
        $stmt->execute(array($addressBookId, $cardUri));

        $result = $stmt->fetchAll(PDO::FETCH_ASSOC);

        return (count($result)>0?$result[0]:false);

Evert Pot

unread,
May 31, 2012, 3:25:17 PM5/31/12
to sabredav...@googlegroups.com

On May 31, 2012, at 8:53 PM, BN wrote:

> Hello Evert,
>
> To 1)
> I am new to using RewriteRules, so I guess I don't completely understand why. I set up a test website to try out Rewrite rules:
> /var/www/testrewrite/
> addressbooks/
> firstname1.lastname1
> contacts/
> index.php
> firstname2.lastname2
> contacts/
> index.php
> firstname3.lastname3
> contacts/
> index.php
>
> Each index.php contained different text. My Rewrite rules were:
>
> <IfModule mod_rewrite.c>
> RewriteEngine on
> RewriteRule ^sync/card/([A-Za-z0-9\.-]+)/?$ addressbooks/$1/contacts/index.php
> </IfModule>

That's the craziest setup I've seen so far :) Does this imply you effectively have a separate installation for every single user?

You need more than just the addressbook urls though, there's also principal urls..

Rewriting urls is also not enough.. there's different parts in the system that need to know the current url, and besides acting on the real, current url with the correct response, the responses also contain these urls. If the request url, and the response urls don't match.. things will break.

Is this enough explanation?

> Since that worked, so I am confused as to why it doesn't apply to SabreDAV. Even though SabreDAV doesn't actually create addressbooks/username/ directories, I still thought that since you can visit the URL in the browser, it will work. Does it have to do with the fact that it is running the server.php? And how could I take out the server.php using rewrite?
>
> To 2)
>
> Are you referring to the function of the backend classes that returns data about a card or a calendarobject? Using the class Sabre_CardDAV_Backend_PDO as an example, the resulting data in $result after the database query has raw vCard data in an associative array where the array key is "carddata". So in my case, I just need to modify the array to change the "vcard" key to "carddata"?

Yes.. it's quite simple.

you have an array like:

array(
'vcard' => '..',
'url' => '..',
)

And you need to change this to:

array(
'carddata' => '..',
'uri' => '..',
)

It's quite simple really.

Evert


BN

unread,
May 31, 2012, 4:21:25 PM5/31/12
to sabredav...@googlegroups.com


That's the craziest setup I've seen so far :) Does this imply you effectively have a separate installation for every single user?

You need more than just the addressbook urls though, there's also principal urls..  

Rewriting urls is also not enough.. there's different parts in the system that need to know the current url, and besides acting on the real, current url with the correct response, the responses also contain these urls. If the request url, and the response urls don't match.. things will break.
 
Is this enough explanation?

Oh no, I don't have a separate installation for every user.  That example above was just a test completely unrelated to SabreDAV. Each "index.php" set "Hello I am [first name] [last name]".  So using my rewrite rule above, I was able to successfully make it so /sync/card/firstname.lastname was rewritten to  /addressbook/firstname.lastname/contacts/index.php.  And then I tried to use this rewrite rule for my SabreDAV installation, but it was not successful and would say
"Sabre_DAV_Exception_Forbidden
Requested uri (/sync/card/firstname.lastname) is out of base uri (/server.php/)
"
Sorry for that confusion.  But what you are saying is that in the background, clients make requests to different URLs (not just /addressbooks/[username]/[addressbookname]) so rewriting that is not just enough.  I...think...I understand correctly.

My goal was just to make the url simpler.  For example, when testing it out with Apple Addressbook, I was able to enter only www.domain.com/server.php/, but in iCal, I had to enter www.domain/server.php/principals/[username]/.  Even if I could just shorten it www.domain.com/server.php/ (or even better, www.domain.com/sync/) consistently across clients, that would be nice.

In the documentation, I saw that Apple clients can detect the principal uri by just entering the domain.  Could it be that my server is not running truly at the root of the server?

 

Yes.. it's quite simple.

you have an array like:

array(
  'vcard' => '..',
  'url'   => '..',
)

And you need to change this to:

array(
  'carddata' => '..',
  'uri'   => '..',
)

It's quite simple really.

Evert



Thank you for clarifying that, just wanted to make sure! :)

Evert Pot

unread,
May 31, 2012, 4:27:19 PM5/31/12
to sabredav...@googlegroups.com

On May 31, 2012, at 10:21 PM, BN wrote:

>
>
> That's the craziest setup I've seen so far :) Does this imply you effectively have a separate installation for every single user?
>
> You need more than just the addressbook urls though, there's also principal urls..
>
> Rewriting urls is also not enough.. there's different parts in the system that need to know the current url, and besides acting on the real, current url with the correct response, the responses also contain these urls. If the request url, and the response urls don't match.. things will break.
>
> Is this enough explanation?
>
> Oh no, I don't have a separate installation for every user. That example above was just a test completely unrelated to SabreDAV. Each "index.php" set "Hello I am [first name] [last name]". So using my rewrite rule above, I was able to successfully make it so /sync/card/firstname.lastname was rewritten to /addressbook/firstname.lastname/contacts/index.php. And then I tried to use this rewrite rule for my SabreDAV installation, but it was not successful and would say
> "Sabre_DAV_Exception_Forbidden
> Requested uri (/sync/card/firstname.lastname) is out of base uri (/server.php/)
> "
> Sorry for that confusion. But what you are saying is that in the background, clients make requests to different URLs (not just /addressbooks/[username]/[addressbookname]) so rewriting that is not just enough. I...think...I understand correctly.

Yes, this is one of the reasons.

>
> My goal was just to make the url simpler. For example, when testing it out with Apple Addressbook, I was able to enter only www.domain.com/server.php/, but in iCal, I had to enter www.domain/server.php/principals/[username]/.

This shouldn't be needed. This was only needed for iCal on OS/X 10.5.

http://www.domain/server.php/ should just work

And yea, you can just rewrite the base url to something like

http://www.domain/sync/

If you take a look at the examples/webserver directory, there are some examples for apache to do this.
You _have_ to make sure that you use the exact same url, in your server.php script where it says:

$server->setBaseUrl('/');

So this should be something like:

$server->setBaseUrl('/sync/');


After you've done this, you can even make it shorter..

If you create two special urls at:

http://www.domain/.well-known/carddav
http://www.domain/.well-known/caldav

And they both redirect (not a rewrite!!) to:

http://www.domain/sync/

Then all your user will have to type is:

www.domain

Evert

BN

unread,
Jun 1, 2012, 1:48:39 PM6/1/12
to sabredav...@googlegroups.com
Hey Evert,

Regarding transforming the arrays of my backend functions to change the keys back to "carddata" and "calendarid".  It successfully reverted Sabre_CardDAV_Card back to its default state by transforming the return results of getCards() and getCard().  But it does not to be successful for Sabre_CalDAV_CalendarObject and the CalDAV backend class.  I transformed the arrays of getCalendarObjects and getCalendarObject so they return "calendarid" as the key (even went as far to keep the array in order), but my clients no longer appear to be getting events anymore.  I then changed back to my modified Sabre_CalDAV_CalendarObject and backend class, and it worked again.  Is there anything else I need to touch in the CalDAV backend?

Just a note, I was able to do it successfully in the CardDAV backend side without keeping the array in the same order as retrieved from the database query.  And another thing to note is that the database results from the CalDAV backend spit out results in the format
array(
    'id' => [value]
    0 => null
    'calendardata' => [value]
    1 => null
     ....
)

Basically between every field, there was a numerical index with a null value (sometimes it would contain the value of the field above it).  Is this intended from PDO fetch results (the CardDAV database queries did not have this).



This shouldn't be needed. This was only needed for iCal on OS/X 10.5.

http://www.domain/server.php/ should just work

And yea, you can just rewrite the base url to something like

http://www.domain/sync/


 

If you take a look at the examples/webserver directory, there are some examples for apache to do this.
You _have_ to make sure that you use the exact same url, in your server.php script where it says:

$server->setBaseUrl('/');


I am a little confused as to where I can rewrite the base directory and where the "examples/webserver" directory is.

Is this accomplished by adding a rewriteBase to my .htaccess file?

<IfModule mod_rewrite.c>
   RewriteBase /sync/
</IfModule>
 
Thanks again for your help and patience, Evert :)

Evert Pot

unread,
Jun 1, 2012, 3:12:57 PM6/1/12
to sabredav...@googlegroups.com
Hi..

On Jun 1, 2012, at 7:48 PM, BN wrote:

> Hey Evert,
>
> Regarding transforming the arrays of my backend functions to change the keys back to "carddata" and "calendarid". It successfully reverted Sabre_CardDAV_Card back to its default state by transforming the return results of getCards() and getCard(). But it does not to be successful for Sabre_CalDAV_CalendarObject and the CalDAV backend class. I transformed the arrays of getCalendarObjects and getCalendarObject so they return "calendarid" as the key (even went as far to keep the array in order), but my clients no longer appear to be getting events anymore. I then changed back to my modified Sabre_CalDAV_CalendarObject and backend class, and it worked again. Is there anything else I need to touch in the CalDAV backend?

No, if you've done everything correctly.. There should be no further changes needed. One thing you can do is start Charles HTTP Proxy and try to use that to see if the server sends any errors back that could indicate you made a mistake somewhere.

And really.. I can not stress this enough:

This may not be an option for you right in this project, but you _have_ to get yourself into the habit of unit testing. Learn PHPUnit

>
> Just a note, I was able to do it successfully in the CardDAV backend side without keeping the array in the same order as retrieved from the database query. And another thing to note is that the database results from the CalDAV backend spit out results in the format
> array(
> 'id' => [value]
> 0 => null
> 'calendardata' => [value]
> 1 => null
> ....
> )

Check the first argument for the fetch() method:

http://www.php.net/manual/en/pdostatement.fetch.php



>
> If you take a look at the examples/webserver directory, there are some examples for apache to do this.
> You _have_ to make sure that you use the exact same url, in your server.php script where it says:
>
> $server->setBaseUrl('/');
>
>
> I am a little confused as to where I can rewrite the base directory and where the "examples/webserver" directory is.

In your server.php, or calendarserver.php (or however you may have called it), there will be a setBaseUrl method call, this should match your actual base url.

The SabreDAV download on the website will have an examples/ directory, which contains some mod_rewrite samples as well.

Do your best! And next time, for questions like these you _should_ be able to figure out a bit more by doing some searching. You could have done a grep on the sabredav source, or search the mailing list archives too.. This is the #1 question that has been asked here before ;)

>
> Is this accomplished by adding a rewriteBase to my .htaccess file?
>
> <IfModule mod_rewrite.c>
> RewriteBase /sync/
> </IfModule>

No, this is a separate thing from RewriteBase. SabreDAV itself needs to know from what directory it's supposed to be running.

Evert

BN

unread,
Jun 4, 2012, 5:27:43 PM6/4/12
to sabredav...@googlegroups.com

No, if you've done everything correctly.. There should be no further changes needed. One thing you can do is start Charles HTTP Proxy and try to use that to see if the server sends any errors back that could indicate you made a mistake somewhere.

And really.. I can not stress this enough:

This may not be an option for you right in this project, but you _have_ to get yourself into the habit of unit testing. Learn PHPUnit

Check the first argument for the fetch() method:

http://www.php.net/manual/en/pdostatement.fetch.php


Seems as if the problem was how the results array was indexed.  fetch() only gives a one-dimensional array, while the multi-dimensional array of fetchAll() corrected the problem. 
 

In your server.php, or calendarserver.php (or however you may have called it), there will be a setBaseUrl method call, this should match your actual base url.

The SabreDAV download on the website will have an examples/ directory, which contains some mod_rewrite samples as well.

Do your best! And next time, for questions like these you _should_ be able to figure out a bit more by doing some searching. You could have done a grep on the sabredav source, or search the mailing list archives too.. This is the #1 question that has been asked here before ;)

>
> Is this accomplished by adding a rewriteBase to my .htaccess file?
>
> <IfModule mod_rewrite.c>
>    RewriteBase /sync/
> </IfModule>

No, this is a separate thing from RewriteBase. SabreDAV itself needs to know from what directory it's supposed to be running.

Evert

Thank you very much, Evert.  I think I understand this better now.
Reply all
Reply to author
Forward
0 new messages