SabreDAV 1.0.9 released & CalDAV news
The last SabreDAV announcement I made here was 1.0.4, which happened in January. Just today I've released 1.0.9, so I figured it's time for a small update.
A public demo site
I've bought the sabredav.org domain, and placed a live demo on it for people to try out. Give it a shot:
- url demo.sabredav.org.
- username: testuser
- password: test
Please note that OS/X Finder will not be able to upload files here, because it uses the Chunked Transfer Encoding, which is not supported by sourceforge's webserver Nginx. Read more here.
Bugfixes
There's been a number of small(ish) bugfixes.
- Fixed fatal error when a malformed url was called.
- Issue 19: Better responses to HEAD requests on collections, improving compatibility with MS Office.
- Issue 23: Fixed Allow header, improving compatibility with Evolution.
- Issue 21: Typo.
- Issue 27: Incorrect encoding of entities in properties.
- Issue 29: Missing constant causing fatal error on lock requests with infinite timeouts.
So there it is. You can download the latest version on the googlecode project page.
CalDAV
CalDAV support is going well. Currently iCal, Evolution and Lightning/Sunbird are supported. If you want to test it out, be sure to download the alpha version (1.1.x), and read the related documentation.
IRC
I've also setup an irc channel on freenode.net. If you feel like idling somewhere new, head over to #sabredav.
CalDAV server for PHP
It's been a long time coming, but I finally have some working CalDAV code. The server has been tested with iCal 3.0 and 4.0 (Leopard and Snow leopard), Sunbird 1.0 pre-release and Evolution.
My main goal is to create a general-purpose CalDAV library, rather than a consumer-ready server app. I'm hoping people will be able to use this library to enable CalDAV functionality in their existing applications.
If you're interested in hacking around or testing, you'll have to grab a copy from subversion. Full installation instructions are available. Because of the alpha-stability nature of the code data-loss can occur, so beware!
Published in PHP|Architect
The January issue of PHP|Architect just got published, and I'm in it!
I've written an apparent 5-page article about SabreDAV. The process was a lot of fun. It's definitely quite different from blogging, where quick and dirty is the rule rather than the exception. I hope I get the chance to do this again (all provided if there's another subject I feel knowledgeable enough in).
So if you get a hold of a copy, I would be very interested in your feedback! The magazine is in PDF form these days, so subscribing and downloading is quick and easy =).
SabreDAV 1.0.4 released
I just released SabreDAV version 1.0.4.
SabreDAV now supports RFC 4709 through a plugin. This RFC defines a standard way to tell operating system a WebDAV share should be mounted. Example code to make this work easily is included in the actual RFC document (scroll down). It is not supported by default by any operation system at the moment, so if you want to plug your own DavMount implementation for OS/X or Linux, I'll be happy to list you.
The other change is that releases are now also pushed to Pearfarm. I'm still testing this so this might not end up being the official channel. If you'd like to try the new installation method, you can easily do so using:
pear channel-discover evert.pearfarm.org
pear install evert.pearfarm.org/Sabre_DAV
javascript's escape and encodeURI vs. PHP $_POST
I just stumbled upon an odd encoding issue with a web application.
Basically, data is coming into our PHP application through a Javascript's XMLHttpRequest (ajax). The data is sent as a standard form encoding (application/x-www-form-urlencoded), and picked up by PHP using the $_POST array. Any strings in form POST request are 'urlencoded', also known as Percent-encoding. As an example, this will turn a space into the often-seen %20.
Normally everything in the $_POST and $_GET arrays is already decoded, so when you're dealing with these arrays you don't really have to think about this. This time however, I was dealing with some non-latin unicode characters and for some reason they were never decoded and ended up in de database as raw url-encoded strings.
Doing a bit of research led me to the following: normally any special character is encoded as %XX, X and X being 2 hexadecimal values. These values simply represent bytes. The values I got were different altogether and took the form %uXXXX. I just assumed this was part of standard uri-encoding for unicode characters, so I was still a bit shook-up to see that PHP didn't just pick them up.
After a bit of research, I found out that the unicode representation was rejected by W3c, which is probably also why the PHP authors decided to not implement this. Javascript actually has 2 different methods to do percent-encoding, namely:
escape("☢"); // returns %u2622
encodeURI("☢"); // returns %E2%98%A2
Guess which one we were using?
Even though the %u syntax is arguably better to represent unicode characters, W3c seems to have voted against the syntax for backwards compatibility reasons. Before this happened the escape method was already adopted in javascript which in turn caused me to stumble upon this problem and write an article about it.
The more you know..
SabreDAV reaches 1.0
After lots of testing, coding and integrating SabreDAV in a few systems, SabreDAV has reached 1.0.
What's that?
For those of you randomly stumbling on this blog, SabreDAV is a tool I've been working on to allow easy integration of PHP and WebDAV. While looking at WebDAV implementions out there for PHP, there weren't really any standards-compliant and flexible solutions out there, so I decided to write my own.
Since then it has gained some popularity, and the beta version has been tested and implemented in a number of places. It's open source (under the BSD license), so anybody can grab it and use it.
If you don't really know what WebDAV is, it is basically a filesystem protocol that works on top of HTTP. By implementing WebDAV (or SabreDAV specifically) you are able to expose your web application as if it was a filesystem to the users. WebDAV is supported by any major operating system.
If you're interested in SabreDAV, check out the example, or tutorial.
Changes
The last round of changes since 0.12.1 are mostly cleanups, but the most important are the following:
- SimpleDirectory class
- Authentication plugin is no longer included. The plugin was not yet production ready, and in order to allow myself to make API changes, I needed to remove it for 1.0. This does not mean you can no longer use the recommended way to implement authentication.
- The unknownProperties event was removed, replaced by the afterGetPropertiesEvent (docs).
- Addition of more events for plugin writers.
- Lots of cleaning up, unittests.
Full changelog and download.
Future plans
Although the 1.0 version should be a bit of a milestone, the release had actually been sitting ready for a while. So while 1.0 is cool and all, I've already spent a great deal of time implementing RFC 3744 a.k.a. ACL extensions for WebDAV. Support for ACL will be added as a separate module in the future.
While these changes are going on, no backwards compatibility breaking changes should be made to the API's. For more details on the BC and versioning policy, check here.
Thanks!
It's been a lot of hard work to get here, but seeing some uptake is very rewarding. I would probably have given up on this if it weren't for the people asking questions, making suggestions and filing reports. Thanks for that, it makes it worth it!
SabreDAV 0.12
I just released a new version of SabreDAV, 0.12. I've skipped on posting for the last few versions, because I didn't want to get too spammy on this blog.
These were mostly bugfixes, and a few added features. SabreDAV is also a PEAR-package again, so installing is as simple as 'pear install SabreDAV-0.12.0.tgz'.
Full list of changes
- Added: Experimental PDO backend for Locks Manager.
- Fixed: Sending Content-Length: 0 for every empty response. This improves NGinx compatibility.
- Fixed: Last modification time is reported in UTC timezone. This improves Finder compatibility.
- Fixed: Issue 13.
- Added: now a PEAR-compatible package again, thanks to Michael Gauthier.
- Added: Plugin to automatically map GET requests to non-files to PROPFIND (Sabre_DAV_Browser_MapGetToPropFind). This should allow easier debugging of complicated WebDAV setups.
- Added: Ability to choose to use auth-int, auth or both for HTTP Digest authentication. (Issue 11)
- Fixed: TemporaryFileFilter plugin now intercepts HTTP LOCK requests to non-existant files. (Issue 12)
- Updated: Browser plugin now shows multiple {DAV:}resourcetype values if available.
- Added: generatePropfindResponse now takes a baseUri argument.
- Added: ResourceType property can now contain multiple resourcetypes.
- Added: Sabre_DAV_Property_Href class. For future use.
- Changed: Made more methods in Sabre_DAV_Server public.
- Added: Central list of defined xml namespace prefixes. This can reduce Bandwidth and improve legibility for xml bodies with user-defined namespaces.
- Changed: moved default copy and move logic from ObjectTree to Tree class.
Converting ICalendar to XML
I've started working on a CalDAV implementation, which also requires analysis of ICalendar (rfc 2554) objects.
ICalendar objects have properties, components (such as VEVENT, VTODO) and attributes. This is awfully familiar to XML. So instead of trying to come up with a complicated parser and object structure, I decided to just convert it to XML and use PHP's simplexml.
This is my current script:
<?php
function iCalendarToXML($icalendarData) {
// Detecting line endings
if (strpos($icalendarData,"\r\n")) $lb = "\r\n";
elseif (strpos($icalendarData,"\n")) $lb = "\n";
else $lb = "\r\n";
// Splitting up items per line
$lines = explode($lb,$icalendarData);
// Properties can be folded over 2 lines. In this case the second
// line will be preceeded by a space or tab.
$lines2 = array();
foreach($lines as $line) {
if ($line[0]==" " || $line[0]=="\t") {
$lines2[count($lines2)-1].=substr($line,1);
continue;
}
$lines2[]=$line;
}
$xml = '<?xml version="1.0"?>' . "\n";
$spaces = 0;
foreach($lines2 as $line) {
$matches = array();
// This matches PROPERTYNAME;ATTRIBUTES:VALUE
if (preg_match('/^([^:^;]*)(?:;([^:]*))?:(.*)$/',$line,$matches)) {
$propertyName = strtoupper($matches[1]);
$attributes = $matches[2];
$value = $matches[3];
// If the line was in the format BEGIN:COMPONENT or END:COMPONENT, we need to special case it.
if ($propertyName == 'BEGIN') {
$xml.=str_repeat(" ",$spaces);
$xml.='<' . strtoupper($value) . ">\n";
$spaces+=2;
continue;
} elseif ($propertyName == 'END') {
$spaces-=2;
$xml.=str_repeat(" ",$spaces);
$xml.='</' . strtoupper($value) . ">\n";
continue;
}
$xml.=str_repeat(" ",$spaces);
$xml.='<' . $propertyName;
if ($attributes) {
// There can be multiple attributes
$attributes = explode(';',$attributes);
foreach($attributes as $att) {
list($attName,$attValue) = explode('=',$att,2);
$xml.=' ' . $attName . '="' . htmlspecialchars($attValue) . '"';
}
}
$xml.='>'. htmlspecialchars($value) . '</' . $propertyName . ">\n";
}
}
return $xml;
}
?>
This will convert:
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Example Corp.//CalDAV Client//EN
BEGIN:VTIMEZONE
LAST-MODIFIED:20040110T032845Z
TZID:US/Eastern
BEGIN:DAYLIGHT
DTSTART:20000404T020000
RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4
TZNAME:EDT
TZOFFSETFROM:-0500
TZOFFSETTO:-0400
END:DAYLIGHT
BEGIN:STANDARD
DTSTART:20001026T020000
RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10
TZNAME:EST
TZOFFSETFROM:-0400
TZOFFSETTO:-0500
END:STANDARD
END:VTIMEZONE
BEGIN:VEVENT
DESCRIPTION:Hello Im evert
Next line also
Blabla
ATTENDEE;PARTSTAT=ACCEPTED;ROLE=CHAIR:mailto:cyrus@example.com
ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com
DTSTAMP:20060206T001220Z
DTSTART;TZID=US/Eastern:20060104T100000
DURATION:PT1H
LAST-MODIFIED:20060206T001330Z
ORGANIZER:mailto:cyrus@example.com
SEQUENCE:1
STATUS:TENTATIVE
SUMMARY:Event #3
UID:DC6C50A017428C5216A2F1CD@example.com
X-ABC-GUID:E1CX5Dr-0007ym-Hz@example.com
END:VEVENT
END:VCALENDAR
To:
<?xml version="1.0"?>
<VCALENDAR>
<VERSION>2.0</VERSION>
<PRODID>-//Example Corp.//CalDAV Client//EN</PRODID>
<VTIMEZONE>
<LAST-MODIFIED>20040110T032845Z</LAST-MODIFIED>
<TZID>US/Eastern</TZID>
<DAYLIGHT>
<DTSTART>20000404T020000</DTSTART>
<RRULE>FREQ=YEARLY;BYDAY=1SU;BYMONTH=4</RRULE>
<TZNAME>EDT</TZNAME>
<TZOFFSETFROM>-0500</TZOFFSETFROM>
<TZOFFSETTO>-0400</TZOFFSETTO>
</DAYLIGHT>
<STANDARD>
<DTSTART>20001026T020000</DTSTART>
<RRULE>FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10</RRULE>
<TZNAME>EST</TZNAME>
<TZOFFSETFROM>-0400</TZOFFSETFROM>
<TZOFFSETTO>-0500</TZOFFSETTO>
</STANDARD>
</VTIMEZONE>
<VEVENT>
<DESCRIPTION>Hello Im evertNext line also Blabla</DESCRIPTION>
<ATTENDEE PARTSTAT="ACCEPTED" ROLE="CHAIR">mailto:cyrus@example.com</ATTENDEE>
<ATTENDEE PARTSTAT="NEEDS-ACTION">mailto:lisa@example.com</ATTENDEE>
<DTSTAMP>20060206T001220Z</DTSTAMP>
<DTSTART TZID="US/Eastern">20060104T100000</DTSTART>
<DURATION>PT1H</DURATION>
<LAST-MODIFIED>20060206T001330Z</LAST-MODIFIED>
<ORGANIZER>mailto:cyrus@example.com</ORGANIZER>
<SEQUENCE>1</SEQUENCE>
<STATUS>TENTATIVE</STATUS>
<SUMMARY>Event #3</SUMMARY>
<UID>DC6C50A017428C5216A2F1CD@example.com</UID>
<X-ABC-GUID>E1CX5Dr-0007ym-Hz@example.com</X-ABC-GUID>
</VEVENT>
</VCALENDAR>
I hope this is useful to anyone else.
Goto in PHP 5.3
Via reddit: The goto documentation got an xkcd overhaul. :)
PHP feature request: 'Throwable' interface
I would love to have a 'Throwable' inteface in PHP, so I opened my very first feature request.
I realize this is mostly an OOP purist request, as it won't provide any real functionality.
If you agree, vote!
Next page








