|
WritingPlugins
Writing Plugins
Phase-Implementation Writing Pluginsclass FOOMethod extends Sabre_DAV_ServerPlugin {
public $server;
function getFeatures() {
return array();
}
function getHTTPMethods() {
return array('FOO');
}
function initialize(Sabre_DAV_Server $server) {
$this->server = $server;
$server->subscribeEvent('unknownMethod',array($this,'unknownMethodHandler'));
}
function unknownMethodHandler($method, $uri) {
if ($method!='FOO') return;
$this->server->httpResponse->sendBody('bar');
return false;
}
}This plugin subscribes to the 'unknownMethod' event. This event is fired whenever an HTTP method was called that wasn't handles by the server or existing plugins. In this case we are implementing the 'FOO' method. The FOO method returns 'bar' in it's response body. In the body of the event handler, note that nothing is returned when the requested method wasn't foo, and 'false' if it was. Returning false from any method handler effectively stops the event chain. You must return a literal false though, and not something that would evaluate to false (null, 0, "" is not ok) We want to return 'false' for the 'FOO' event, because other plugins should not attempt to handle that HTTP method. EventsThe following events are supported in the server: reportIf an HTTP REPORT method is invoked, all subscribers to this event get the opportunity to handle a REPORT request. Example:
function myReport($reportName,DOMDocument $dom) {
// $reportName contains the report name in clark-notation.
// For example:
//
// {DAV:}expand-properties
return true;
}
$server->subscribeEvent('report','myReport');
beforeMethodbeforeMethod is called whenever any http method handler is called. this allows the event to override standard behaviour or block requests. Example:
function blockDELETE($methodName, $uri) {
if ($methodname=='DELETE') throw new Sabre_DAV_Exception_Forbidden();
return true;
}
$server->subscribeEvent('beforeMethod','blockDELETE');
Note that the $uri argument was added in version 1.3.0 unknownMethodunknownMethod can be used to add support for new HTTP verbs (e.g.: POST). An example can be seen higher up int the page. beforeCreateFileThis event is trigged before new files are created. Using this event it is possible to intercept these actions and store them in a different spot. Since 1.6 the 'parent' argument will also be sent along. Example:
function beforeCreateFile($path,$data,Sabre_DAV_ICollection $parent) {
if ($path=='somemagicpath') {
file_put_contents('/tmp/createdfile',$data);
return false;
} else {
return true;
}
}
$server->subscribeEvent('beforeCreateFile','beforeCreateFile');
afterCreateFileThis event is triggered, only if the creation of the file succeeded. This event is only available since SabreDAV 1.6. Example: function afterCreateFile($path,Sabre_DAV_ICollection $parent) {
// Do some logging here
}
$server->subscribeEvent('afterCreateFile','afterCreateFile');beforeWriteContentThis event is trigged before files are updated. Using this event it is possible to intercept these actions, validate content or block them. The 'node' and 'data' arguments are only available since version 1.6. Example:
function beforeWriteContent($path, Sabre_DAV_IFile $node, &$data) {
file_put_contents('/tmp/davlog', $path . " just got updated!\n",FILE_APPEND);
}
$server->subscribeEvent('beforeWriteContent','beforeWriteContent');
afterWriteContentThis event is triggered, only if updating of an existing file succeeded. This event is only available since SabreDAV 1.6. Example: function afterWriteContent($path,Sabre_DAV_IFile $node) {
// Do some logging here
}
$server->subscribeEvent('afterWriteContent','afterWriteContent');beforeBindThis event is triggered whenever a new node is about to be created in the tree. This is for example triggered by PUT, MKCOL, COPY and MOVE. Example:
function beforeBind($patha) {
if (permitted()) return true;
else return false;
}
$server->subscribeEvent('beforeBind','beforeBind');
beforeUnbindThis event is triggered whenever a node is about to be deleted. If an entire tree of nodes is deleted, the event will only trigger once, for the top-level node. The event is triggered by for example DELETE, and COPY and MOVE in case the target resource was being overwritten. Example:
function beforeUnbind($path) {
if (permitted()) return true;
else return false;
}
$server->subscribeEvent('beforeUnbind','beforeUnbind');
afterUnbindThis event is triggered after a node is deleted. If an entire tree of nodes is deleted, the event will only trigger once, for the top-level node. The event is triggered by for example DELETE, and COPY and MOVE in case the target resource was being overwritten. This event is only available since SabreDAV 1.6. Example:
function afterUnbind($path) {
// Some logging could go here
}
$server->subscribeEvent('afterUnbind','afterUnbind');
beforeLockThe beforeLock event is triggered right before a resource is locked. Intercepting this event allows you to block a users' lock, or change information regarding the lock, such as the lock owner or lock timeout. Example:
function beforeLock($path,Sabre_DAV_Locks_LockInfo $lock) {
if (!permitted()) return false;
}
$server->subscribeEvent('beforeLock','beforeLock');
beforeUnlockThe beforeUnlock event is triggered right before a resource is unlocked. Intercepting this event allows you to block the unlock. Example:
function beforeUnlock($path,Sabre_DAV_Locks_LockInfo $lock) {
if (!permitted()) return false;
}
$server->subscribeEvent('beforeUnlock','beforeUnlock');
beforeGetPropertiesAdded in version 1.4 This event is fired before all properties are collected. This will allow you to add in any properties early in the process. Plugins use this to handle properties, so that nodes don't have to. Example: function beforeGetProperties($path, Sabre_DAV_INode $node, &$requestedProperties, &$returnedProperties) {
if (in_array('{DAV:}displayname', $requestedProperties) && $node instanceof CompanyX_MyNode) {
$returnedProperties[200]['{DAV:}displayname'] = 'My fancy node';
unset($requestedProperties['{DAV:}displayname']);
}
}Both requested and returned properties are passed by reference. The requestedProperties is a simple array with propertynames as values. If you unset items from this list, it will ensure that subsequent lookups from other sources (the property itself, and other plugins) won't look for that property anymore. returnedProperties is also an array, which looks like the following example: $properties = array(
// 200 status code
200 => array(
'{DAV:}getcontenttype' => 'text/plain',
'{DAV:}getcontentlength' => 1000,
),
// These properties were not found
404 => array(
'{DAV:}yourmomsname' => null,
)
);Properties are grouped by a HTTP status code. In each group there's a list of properties with their values. Note that if false is returned from this method, the node will be hidden from directory listings and any further processing for properties is cancelled. afterGetPropertiesThis event is fired after all properties for a resource have been collected. This allows you to rewrite, add or remove properties. The event receives 2 arguments, the first being the url, the second an array with properties. This array can be passed by reference to allow modification. The array is a multi-dimensional array. Simply put, it's built up as such: $properties = array(
// 200 status code
200 => array(
'{DAV:}getcontenttype' => 'text/plain',
'{DAV:}getcontentlength' => 1000,
),
// These properties were not found
404 => array(
'{DAV:}yourmomsname' => null,
)
);
Example:
function afterGetProperties($uri, &$properties) {
if (isset($properties[404]['{DAV:}owner'])) {
$propeties[200]['{DAV:}owner'] = 'evert';
unset($properties[404]['{DAV:}owner']);
}
return true;
}
$server->subscribeEvent('afterGetProperties','afterGetProperties');
updatePropertiesThis event is fired when properties are about to be updated, using for example PROPPATCH. This allows plugins to handle updating certain properties, before the standard subsystems get to it. $properties - an associative array with properties that need to be updated. The keys are the properties in clark-notation. If the value is null, it means that the user requested to delete the property. Note that this argument is passed by reference. If you choose to 'handle' updating the property, you must remove the property from this array, so SabreDAV knows updating was successful. $result - Another associative array. This array must contain the statuscodes related to updating the properties. This array is indexed by a HTTP status code. Each item has a list of properties as keys, the value for every property is null. $node - An instance of Sabre_DAV_INode. This is the node that's actually being updated. This argument was added for convenience. If updating a property fails, you must return false to break the event chain. Because updating properties should be atomic, any failure should result a complete failure. Example: /**
* This example handles updating of the {DAV:}displayname property
*/
function updateProperties(&$properties, &$result, Sabre_DAV_INode $node) {
if (!array_key_exists('{DAV:}displayname', $properties)) return;
$newDisplayName = $properties['{DAV:}displayname'];
// Do something relevant with the displayname here.
// Success:
$result[200]['{DAV:}displayname'] = null;
// Unsetting the property so we don't get a double update
unset($properties['{DAV:}displayname']);
}
$server->subscribeEvent('updateProperties','updateProperties');Other examplesCheck out Sabre_DAV_Browser_Plugin. This plugin generates HTML directory indexes for GET requests to collections. This is useful if you want the contents of the directory to be viewable by a browser. PrioritySometimes it's needed to ensure your event handler is the first in the list to be fired off. This can be achieved by adding a priority number to the argument of subscribeEvent. This should be used with care. The Authentication plugin uses this for example to make sure authentication happens before any other process. The default priority number is 100. Lower numbers for priorities will be fired off earlier. Current reserved list of priorities (might be extended in the future). Please do not use any of these.
| |
Hi.
Since my webserver does not support digest auth, I had to write a PDO basic auth plugin. It works all fine. I would like to submit it so other people can benefit. How do I do this?
The best way to go about it is to either make a patch and send it to the mailing list for review, or make a mercurial clone and make your changes there.
Looking forward to it!
Hi, when I use the browser plugin to upload a file, the HttpPut? method seems not to be invoked (and beforeBind method is not fired) although the file is correctly uploaded and created. Is this normal?
Thanks in advance for your reply.
I'm using sabredav with typo3 Extension webdav, windows 7 64bit and xamp.
Davide
Please head to the mailing list for any questions.
The browser plugin does not call httpPut, but should call createFile. I'll need sample code to help you debug (but not here).
Hi,
thank for your reply. I use sabredav basically with cyberduck. And when I create,rename or move a file all the events are fired. Maybe I did something wrong with the browser...
Thank you very much for your work, Davide