• Web-based Distributed Authoring and Versioning • • Goal: enable interoperability of tools for distributed web authoring • • Turns the web into a writable medium • • Applies to all kinds of content - not just HTML and images • • Based on extensions to HTTP • • Uses XML for properties, control, status • • RFC 2518 (Core) and RFC 3253 (DeltaV) How does it work? • • Layered on HTTP/1.1 using its extension facilities • • New methods, for example: COPY, MKCOL, PROPFIND, CHECKOUT • • New headers • • Some slight changes to existing methods semantics • • RFC 2518 ("core"): pretty straight-forward • • RFC 3253 (versioning): complex A sample request Request all metadata for a directory and its contents PROPFIND /container/ HTTP/1.1 Host: www.foo.bar Depth: 1 Content-Type: text/xml; charset="utf-8" Content-Length: <?xml version="1.0" ?> <D:propfind xmlns:D="DAV:"> <D:allprop/> </D:propfind> Shortened response HTTP/1.1 207 Multi-Status Content-Type: text/xml; charset="utf-8" Content-Length: <?xml version="1.0" encoding="utf-8" ?> <D:multistatus xmlns:D="DAV:"> <D:response> <D:href>http://www.foo.bar/container/</D:href> <D:propstat> <D:prop> <D:getcontentlength>12345</getcontentlength> </D:prop> <D:prop xmlns:R="http://www.foo.bar/boxschema/"> <R:bigbox> <R:BoxType>Box type A</R:BoxType> </R:bigbox> <R:author> Why PHP? Why PHP? Why not just use Apache mod_dav? • • no additional binaries needed, just pure PHP code • • not necessarily bound to a single server or API • • easy to extend • • all needed bits included (XML parser, HTTP header and content access ) The WebDAV base class The abstract HTTP_WebDAV_Server base class The actual PHP framework for writing a customized WebDAV server is implemented as an abstract base class. The class already takes care of most of the protocol specific stuff like: • • HTTP header parsing • • XML parsing and generation • • authentication • • type conversions • • status codes • • lock checks • • the OPTIONS reply • • partial GET and PUT requests • • known client 'issues' • • Extending the base class Extending the base class requires that you add methods to it that map to WebDAV specific request methods. These methods receive and return all relevant information in the form of PHP arrays. You do not have to deal with XML and header parsing / generation as this is already taken care of by the baseclass. Possible methods • • GET() • • PUT() • • COPY() • • MOVE() • • DELETE() • • PROPFIND() • • PROPPATCH() • • LOCK() • • UNLOCK() • • CHECKLOCK() • • CHECKAUTH() WebDAV conformance For a minimal Server you only need to implement GET(), PUT() and PROPFIND(). Such a minimal server is not at all compliant to the sepcs but may already work with some clients. For a DAV level 1 compliant server you also need COPY(), MOVE(), DELETE() and PROPPATCH(). A DAV level 2 complient server has to implement locking, so you also need LOCK(), UNLOCK() and CHECKLOCK(). A versioning server as specified in RFC 3253 is beyond the current scope of the this PHP package. Getting content with GET() A WebDAV GET request can be handled similar to a normal HTTP GET request. Just make sure that you always set appropriate Content-Length: and Last-Modified: headers before returning the actual content. The path of the requested resource is passed to GET() in the parameter element 'path': <?php function GET(&$param) { $fspath = $this->base . $param["path"]; if (file_exists($fspath)) { header("Content-Type: " . mime_content_type($fspath); header("Last-Modified: " . date("D, j M Y H:m:s ", file_mtime($fspath)) . "GMT "); header("Content-Length: ". filesize($fspath)); readfile($fspath); return true; } else { return false; } } ?> GET() (cont.) As an alternative you may just return a readable PHP stream together with size and modification time information from the GET() method. By doing so you do not have to deal with HTTP header generation yourself and get support for partial GET requests without taking further action as an additional benefit. <?php function GET(&$param) { $fspath = $this->base . $param["path"]; if (file_exists($fspath)) { $param['mimetype'] = mime_content_type($fspath); $param['mtime'] = filemtime($fspath); $param['size'] = filesize($fspath); $param['stream'] = fopen($fspath, "r"); return true; } else { return false; } } ?> Note that no further error checking is needed on calling fopen() here. The base class will take appropriate action if the returned stream is not a PHP resource or not readable. Storing content with PUT() The HTTP PUT request method is used to write data to a resource on the server. The PUT() method is called by the base class with the following elements of its parameter array filled: • • 'path': the resource the received data should be put into • • 'content_length': the number of bytes transfered • • 'content_type': the content type of the data transfered • • 'stream': a PHP stream you can read the actual data from • • 'ranges': an array of byte range specifications to be written on partial requests As with the GET() method you may either handle a PUT request yourself or just return a writable stream and have the base class write to it. PUT() (cont.) <?php function PUT(&$params) { $fspath = $this->base . $params["path"]; if(!@is_dir(dirname($fspath))) { return "409 Conflict"; } $new = ! file_exists($fspath); $fp = fopen($fspath, "w"); if(is_resource($fp) && is_resource($params["stream"])) { while(!feof($params["stream"])) { fwrite($fp, fread($params["stream"], 4096)); } fclose($fp); } return $new ? "201 Created" : "204 No Content"; } ?> PUT() (cont.) function PUT(&$params) { $fspath = $this->base . $params["path"]; if(!@is_dir(dirname($fspath))) { return false; } $options["new"] = ! file_exists($fspath); $fp = fopen($fspath, "w"); return $fp; } ?> . • Web-based Distributed Authoring and Versioning • • Goal: enable interoperability of tools for distributed web authoring • • Turns the web into a writable. need COPY(), MOVE(), DELETE() and PROPPATCH(). A DAV level 2 complient server has to implement locking, so you also need LOCK(), UNLOCK() and CHECKLOCK(). A versioning server as specified. ("core"): pretty straight-forward • • RFC 3253 (versioning) : complex A sample request Request all metadata for a directory and its contents PROPFIND /container/ HTTP/1.1 Host: www.foo.bar Depth: