WebDAV updates
I’ve made a lot of progress on SabreDAV, and felt like it was time for an update.
I pretty much implemented the entire webdav protocol at one point, but I was unhappy with the end-user API. Because this is a pet project and there’s no deadlines attached to it, I felt like I could take my sweet time to absolutely nail the structure.
So, I started over.. I learned a lot about the protocol, and by having a good overview on the entire protocol I felt like I did a much better job.. So right now, we have read-only support for OS/X and DavFS and an easy to use API.
If you’re a mac or linux user, give it a shot by connection to the endpoint : http://www.rooftopsolutions.nl/dav/ . If you open it directly from the browser it won’t give you a nice response. Also, I noticed that OS/X makes a lot of unnecessary requests when its just read only, so it will be a tad slow there. In order to fix this OS/X needs a DAV class 2 server, with locking support. It doesn’t have to be able to write, it just needs the locking HTTP methods.
What you see in the shot is a combination of 2 things, A normal file system directory containing the vcard and my resume, and a virtual ‘articles’ directory, which is based entirely on articles from the database.
SabreDAV currently has some helper classes that allow you to easily integrate with the file system, Sabre_DAV_FS_File and Sabre_DAV_FS_Directory. In order to mix virtual and real files I extended Sabre_DAV_FS_Directory and injected in an extra ‘fake’ directory.
Here’s the code to get this up and running, hope it makes sense:
<?php
// This is our root directory. Its a standard FS_Directory, but we're injecting the virtual 'articles' directory.
class RooftopDAV extends Sabre_DAV_FS_Directory {
function getChildren() {
$children = parent::getChildren();
$children[] = new ArticlesDirectory();
return $children;
}
function getChild($name) {
if ($name=='articles') return new ArticlesDirectory();
return parent::getChild($name);
}
}
// This is our articles directory, its entirely virtual.. The only 2 methods we need to implement are getName and getChildren
class ArticlesDirectory extends Sabre_DAV_Directory {
function getChildren() {
// This is my database abstraction layer, you can make this work for any database (-library/-layer)
$articles = Sabre_DAL_Manager::init()->getRecordSet('blog_posts');
$children = array();
foreach($articles->select() as $article) {
$children[] = new Article($article);
}
return $children;
}
function getName() {
return 'articles';
}
}
// This is our article class.. We need to implement a couple of methods and we're ignoring all methods that change the file.
// Ideally we throw a 403 here, but for the proof of concept, we don't care
class Article implements Sabre_DAV_IFile {
private $article;
function __construct($article) {
$this->article = $article;
}
function put($data) {
// we'll just ignore this
}
function delete() {
// ignored
}
function setName($name) {
// ignored
}
function getName() {
return $this->article['title'] . '.html';
}
function get() {
return $this->article['description'];
}
function getSize() {
return strlen($this->article['description']);
}
function getLastModified() {
return strtotime($this->article['time']);
}
}
// Setting up our root object
$root = new RooftopDAV('/home/evert/dev/rooftopsolutions.nl/davfolder');
// The tree is responsible for dispatching all http methods to our file and directory objects
$tree = new Sabre_DAV_ObjectTree($root);
// The server class does the hardcore protocol work
$server = new Sabre_DAV_Server($tree);
// We need to make sure the server knows on what url its located
$server->setBaseUri('/dav/');
// And off we go
$server->exec();
?>
You can check out the latest version of the code on the project page. Don’t depend your life on the current API, as it is subject to change until there’s a 1.0.