My favorites | Sign in
Project Home Downloads Wiki Issues Source
Search
for
WritingPlugins  
Writing Plugins
Phase-Implementation
Updated Feb 7, 2012 by evert...@gmail.com

Writing Plugins

class 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.

Events

The following events are supported in the server:

report

If 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');

beforeMethod

beforeMethod 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

unknownMethod

unknownMethod can be used to add support for new HTTP verbs (e.g.: POST). An example can be seen higher up int the page.

beforeCreateFile

This 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');

afterCreateFile

This 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');

beforeWriteContent

This 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');

afterWriteContent

This 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');

beforeBind

This 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');

beforeUnbind

This 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');

afterUnbind

This 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');

beforeLock

The 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');

beforeUnlock

The 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');

beforeGetProperties

Added 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.

afterGetProperties

This 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');

updateProperties

This 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 examples

Check 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.

Priority

Sometimes 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.

  • priority 10, set by the Auth plugin
  • priority 20 and 220, set by the ACL plugin (future)
  • priority 50, set by the Lock plugin
Comment by tatj...@envirology.co.nz, Jul 30, 2010

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?

Comment by project member evert...@gmail.com, Jul 30, 2010

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!

Comment by davide.c...@gmail.com, Dec 10, 2011

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

Comment by project member evert...@gmail.com, Dec 10, 2011

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).

Comment by davide.c...@gmail.com, Dec 11, 2011

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


Sign in to add a comment
Powered by Google Project Hosting