ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Sabre\DAV\Locks\Plugin Class Reference

Locking plugin. More...

+ Inheritance diagram for Sabre\DAV\Locks\Plugin:
+ Collaboration diagram for Sabre\DAV\Locks\Plugin:

Public Member Functions

 __construct (Backend\BackendInterface $locksBackend)
 __construct More...
 
 initialize (DAV\Server $server)
 Initializes the plugin. More...
 
 getPluginName ()
 Returns a plugin name. More...
 
 propFind (DAV\PropFind $propFind, DAV\INode $node)
 This method is called after most properties have been found it allows us to add in any Lock-related properties. More...
 
 getHTTPMethods ($uri)
 Use this method to tell the server this plugin defines additional HTTP methods. More...
 
 getFeatures ()
 Returns a list of features for the HTTP OPTIONS Dav: header. More...
 
 getLocks ($uri, $returnChildLocks=false)
 Returns all lock information on a particular uri. More...
 
 httpLock (RequestInterface $request, ResponseInterface $response)
 Locks an uri. More...
 
 httpUnlock (RequestInterface $request, ResponseInterface $response)
 Unlocks a uri. More...
 
 afterUnbind ($path)
 This method is called after a node is deleted. More...
 
 lockNode ($uri, LockInfo $lockInfo)
 Locks a uri. More...
 
 unlockNode ($uri, LockInfo $lockInfo)
 Unlocks a uri. More...
 
 getTimeoutHeader ()
 Returns the contents of the HTTP Timeout header. More...
 
 validateTokens (RequestInterface $request, &$conditions)
 The validateTokens event is triggered before every request. More...
 
 getPluginInfo ()
 Returns a bunch of meta-data about the plugin. More...
 
- Public Member Functions inherited from Sabre\DAV\ServerPlugin
 initialize (Server $server)
 This initializes the plugin. More...
 
 getFeatures ()
 This method should return a list of server-features. More...
 
 getHTTPMethods ($path)
 Use this method to tell the server this plugin defines additional HTTP methods. More...
 
 getPluginName ()
 Returns a plugin name. More...
 
 getSupportedReportSet ($uri)
 Returns a list of reports this plugin supports. More...
 
 getPluginInfo ()
 Returns a bunch of meta-data about the plugin. More...
 

Protected Member Functions

 generateLockResponse (LockInfo $lockInfo)
 Generates the response for successful LOCK requests. More...
 
 parseLockRequest ($body)
 Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object. More...
 

Protected Attributes

 $locksBackend
 
 $server
 

Detailed Description

Locking plugin.

This plugin provides locking support to a WebDAV server. The easiest way to get started, is by hooking it up as such:

$lockBackend = new Sabre\DAV\Locks\Backend\File('./mylockdb'); $lockPlugin = new Sabre\DAV\Locks\Plugin($lockBackend); $server->addPlugin($lockPlugin);

Author
Evert Pot (http://evertpot.com/) @license http://sabre.io/license/ Modified BSD License

Definition at line 23 of file Plugin.php.

Constructor & Destructor Documentation

◆ __construct()

Sabre\DAV\Locks\Plugin::__construct ( Backend\BackendInterface  $locksBackend)

__construct

Parameters
Backend\BackendInterface$locksBackend

Definition at line 44 of file Plugin.php.

44 {
45
46 $this->locksBackend = $locksBackend;
47
48 }

References Sabre\DAV\Locks\Plugin\$locksBackend.

Member Function Documentation

◆ afterUnbind()

Sabre\DAV\Locks\Plugin::afterUnbind (   $path)

This method is called after a node is deleted.

We use this event to clean up any locks that still exist on the node.

Parameters
string$path
Returns
void

Definition at line 318 of file Plugin.php.

318 {
319
320 $locks = $this->getLocks($path, $includeChildren = true);
321 foreach ($locks as $lock) {
322 $this->unlockNode($path, $lock);
323 }
324
325 }
$path
Definition: aliased.php:25
unlockNode($uri, LockInfo $lockInfo)
Unlocks a uri.
Definition: Plugin.php:353
getLocks($uri, $returnChildLocks=false)
Returns all lock information on a particular uri.
Definition: Plugin.php:150

References $path, Sabre\DAV\Locks\Plugin\getLocks(), and Sabre\DAV\Locks\Plugin\unlockNode().

+ Here is the call graph for this function:

◆ generateLockResponse()

Sabre\DAV\Locks\Plugin::generateLockResponse ( LockInfo  $lockInfo)
protected

Generates the response for successful LOCK requests.

Parameters
LockInfo$lockInfo
Returns
string

Definition at line 394 of file Plugin.php.

394 {
395
396 return $this->server->xml->write('{DAV:}prop', [
397 '{DAV:}lockdiscovery' =>
398 new DAV\Xml\Property\LockDiscovery([$lockInfo])
399 ]);
400 }

Referenced by Sabre\DAV\Locks\Plugin\httpLock().

+ Here is the caller graph for this function:

◆ getFeatures()

Sabre\DAV\Locks\Plugin::getFeatures ( )

Returns a list of features for the HTTP OPTIONS Dav: header.

In this case this is only the number 2. The 2 in the Dav: header indicates the server supports locks.

Returns
array

Reimplemented from Sabre\DAV\ServerPlugin.

Definition at line 131 of file Plugin.php.

131 {
132
133 return [2];
134
135 }

◆ getHTTPMethods()

Sabre\DAV\Locks\Plugin::getHTTPMethods (   $uri)

Use this method to tell the server this plugin defines additional HTTP methods.

This method is passed a uri. It should only return HTTP methods that are available for the specified uri.

Parameters
string$uri
Returns
array

Reimplemented from Sabre\DAV\ServerPlugin.

Definition at line 117 of file Plugin.php.

117 {
118
119 return ['LOCK','UNLOCK'];
120
121 }

◆ getLocks()

Sabre\DAV\Locks\Plugin::getLocks (   $uri,
  $returnChildLocks = false 
)

Returns all lock information on a particular uri.

This function should return an array with Sabre\DAV\Locks\LockInfo objects. If there are no locks on a file, return an empty array.

Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree If the $returnChildLocks argument is set to true, we'll also traverse all the children of the object for any possible locks and return those as well.

Parameters
string$uri
bool$returnChildLocks
Returns
array

Definition at line 150 of file Plugin.php.

150 {
151
152 return $this->locksBackend->getLocks($uri, $returnChildLocks);
153
154 }

Referenced by Sabre\DAV\Locks\Plugin\afterUnbind(), Sabre\DAV\Locks\Plugin\httpLock(), Sabre\DAV\Locks\Plugin\httpUnlock(), Sabre\DAV\Locks\Plugin\propFind(), and Sabre\DAV\Locks\Plugin\validateTokens().

+ Here is the caller graph for this function:

◆ getPluginInfo()

Sabre\DAV\Locks\Plugin::getPluginInfo ( )

Returns a bunch of meta-data about the plugin.

Providing this information is optional, and is mainly displayed by the Browser plugin.

The description key in the returned array may contain html and will not be sanitized.

Returns
array

Reimplemented from Sabre\DAV\ServerPlugin.

Definition at line 579 of file Plugin.php.

579 {
580
581 return [
582 'name' => $this->getPluginName(),
583 'description' => 'The locks plugin turns this server into a class-2 WebDAV server and adds support for LOCK and UNLOCK',
584 'link' => 'http://sabre.io/dav/locks/',
585 ];
586
587 }
getPluginName()
Returns a plugin name.
Definition: Plugin.php:80

References Sabre\DAV\Locks\Plugin\getPluginName().

+ Here is the call graph for this function:

◆ getPluginName()

Sabre\DAV\Locks\Plugin::getPluginName ( )

Returns a plugin name.

Using this name other plugins will be able to access other plugins using Sabre\DAV\Server::getPlugin

Returns
string

Reimplemented from Sabre\DAV\ServerPlugin.

Definition at line 80 of file Plugin.php.

80 {
81
82 return 'locks';
83
84 }

Referenced by Sabre\DAV\Locks\Plugin\getPluginInfo().

+ Here is the caller graph for this function:

◆ getTimeoutHeader()

Sabre\DAV\Locks\Plugin::getTimeoutHeader ( )

Returns the contents of the HTTP Timeout header.

The method formats the header into an integer.

Returns
int

Definition at line 368 of file Plugin.php.

368 {
369
370 $header = $this->server->httpRequest->getHeader('Timeout');
371
372 if ($header) {
373
374 if (stripos($header, 'second-') === 0) $header = (int)(substr($header, 7));
375 elseif (stripos($header, 'infinite') === 0) $header = LockInfo::TIMEOUT_INFINITE;
376 else throw new DAV\Exception\BadRequest('Invalid HTTP timeout header');
377
378 } else {
379
380 $header = 0;
381
382 }
383
384 return $header;
385
386 }
if($out) else

References $header, and Sabre\DAV\Locks\LockInfo\TIMEOUT_INFINITE.

Referenced by Sabre\DAV\Locks\Plugin\httpLock().

+ Here is the caller graph for this function:

◆ httpLock()

Sabre\DAV\Locks\Plugin::httpLock ( RequestInterface  $request,
ResponseInterface  $response 
)

Locks an uri.

The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type of lock (shared or exclusive) and the owner of the lock

If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock

Additionally, a lock can be requested for a non-existent file. In these case we're obligated to create an empty file as per RFC4918:S7.3

Parameters
RequestInterface$request
ResponseInterface$response
Returns
bool

Definition at line 171 of file Plugin.php.

171 {
172
173 $uri = $request->getPath();
174
175 $existingLocks = $this->getLocks($uri);
176
177 if ($body = $request->getBodyAsString()) {
178 // This is a new lock request
179
180 $existingLock = null;
181 // Checking if there's already non-shared locks on the uri.
182 foreach ($existingLocks as $existingLock) {
183 if ($existingLock->scope === LockInfo::EXCLUSIVE) {
184 throw new DAV\Exception\ConflictingLock($existingLock);
185 }
186 }
187
188 $lockInfo = $this->parseLockRequest($body);
189 $lockInfo->depth = $this->server->getHTTPDepth();
190 $lockInfo->uri = $uri;
191 if ($existingLock && $lockInfo->scope != LockInfo::SHARED)
192 throw new DAV\Exception\ConflictingLock($existingLock);
193
194 } else {
195
196 // Gonna check if this was a lock refresh.
197 $existingLocks = $this->getLocks($uri);
198 $conditions = $this->server->getIfConditions($request);
199 $found = null;
200
201 foreach ($existingLocks as $existingLock) {
202 foreach ($conditions as $condition) {
203 foreach ($condition['tokens'] as $token) {
204 if ($token['token'] === 'opaquelocktoken:' . $existingLock->token) {
205 $found = $existingLock;
206 break 3;
207 }
208 }
209 }
210 }
211
212 // If none were found, this request is in error.
213 if (is_null($found)) {
214 if ($existingLocks) {
215 throw new DAV\Exception\Locked(reset($existingLocks));
216 } else {
217 throw new DAV\Exception\BadRequest('An xml body is required for lock requests');
218 }
219
220 }
221
222 // This must have been a lock refresh
223 $lockInfo = $found;
224
225 // The resource could have been locked through another uri.
226 if ($uri != $lockInfo->uri) $uri = $lockInfo->uri;
227
228 }
229
230 if ($timeout = $this->getTimeoutHeader()) $lockInfo->timeout = $timeout;
231
232 $newFile = false;
233
234 // If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first
235 try {
236 $this->server->tree->getNodeForPath($uri);
237
238 // We need to call the beforeWriteContent event for RFC3744
239 // Edit: looks like this is not used, and causing problems now.
240 //
241 // See Issue 222
242 // $this->server->emit('beforeWriteContent',array($uri));
243
244 } catch (DAV\Exception\NotFound $e) {
245
246 // It didn't, lets create it
247 $this->server->createFile($uri, fopen('php://memory', 'r'));
248 $newFile = true;
249
250 }
251
252 $this->lockNode($uri, $lockInfo);
253
254 $response->setHeader('Content-Type', 'application/xml; charset=utf-8');
255 $response->setHeader('Lock-Token', '<opaquelocktoken:' . $lockInfo->token . '>');
256 $response->setStatus($newFile ? 201 : 200);
257 $response->setBody($this->generateLockResponse($lockInfo));
258
259 // Returning false will interrupt the event chain and mark this method
260 // as 'handled'.
261 return false;
262
263 }
foreach($paths as $path) $request
Definition: asyncclient.php:32
const EXCLUSIVE
An exclusive lock.
Definition: LockInfo.php:25
const SHARED
A shared lock.
Definition: LockInfo.php:20
lockNode($uri, LockInfo $lockInfo)
Locks a uri.
Definition: Plugin.php:337
getTimeoutHeader()
Returns the contents of the HTTP Timeout header.
Definition: Plugin.php:368
parseLockRequest($body)
Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object.
Definition: Plugin.php:551
generateLockResponse(LockInfo $lockInfo)
Generates the response for successful LOCK requests.
Definition: Plugin.php:394
$response

References $request, $response, PHPMailer\PHPMailer\$token, Sabre\DAV\Locks\LockInfo\EXCLUSIVE, Sabre\DAV\Locks\Plugin\generateLockResponse(), Sabre\DAV\Locks\Plugin\getLocks(), Sabre\DAV\Locks\Plugin\getTimeoutHeader(), Sabre\DAV\Locks\Plugin\lockNode(), Sabre\DAV\Locks\Plugin\parseLockRequest(), and Sabre\DAV\Locks\LockInfo\SHARED.

+ Here is the call graph for this function:

◆ httpUnlock()

Sabre\DAV\Locks\Plugin::httpUnlock ( RequestInterface  $request,
ResponseInterface  $response 
)

Unlocks a uri.

This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header The server should return 204 (No content) on success

Parameters
RequestInterface$request
ResponseInterface$response
Returns
void

Definition at line 275 of file Plugin.php.

275 {
276
277 $lockToken = $request->getHeader('Lock-Token');
278
279 // If the locktoken header is not supplied, we need to throw a bad request exception
280 if (!$lockToken) throw new DAV\Exception\BadRequest('No lock token was supplied');
281
282 $path = $request->getPath();
283 $locks = $this->getLocks($path);
284
285 // Windows sometimes forgets to include < and > in the Lock-Token
286 // header
287 if ($lockToken[0] !== '<') $lockToken = '<' . $lockToken . '>';
288
289 foreach ($locks as $lock) {
290
291 if ('<opaquelocktoken:' . $lock->token . '>' == $lockToken) {
292
293 $this->unlockNode($path, $lock);
294 $response->setHeader('Content-Length', '0');
295 $response->setStatus(204);
296
297 // Returning false will break the method chain, and mark the
298 // method as 'handled'.
299 return false;
300
301 }
302
303 }
304
305 // If we got here, it means the locktoken was invalid
306 throw new DAV\Exception\LockTokenMatchesRequestUri();
307
308 }

References $path, $request, $response, Sabre\DAV\Locks\Plugin\getLocks(), and Sabre\DAV\Locks\Plugin\unlockNode().

+ Here is the call graph for this function:

◆ initialize()

Sabre\DAV\Locks\Plugin::initialize ( DAV\Server  $server)

Initializes the plugin.

This method is automatically called by the Server class after addPlugin.

Parameters
DAV\Server$server
Returns
void

Definition at line 58 of file Plugin.php.

58 {
59
60 $this->server = $server;
61
62 $this->server->xml->elementMap['{DAV:}lockinfo'] = 'Sabre\\DAV\\Xml\\Request\\Lock';
63
64 $server->on('method:LOCK', [$this, 'httpLock']);
65 $server->on('method:UNLOCK', [$this, 'httpUnlock']);
66 $server->on('validateTokens', [$this, 'validateTokens']);
67 $server->on('propFind', [$this, 'propFind']);
68 $server->on('afterUnbind', [$this, 'afterUnbind']);
69
70 }

References Sabre\DAV\Locks\Plugin\$server.

◆ lockNode()

Sabre\DAV\Locks\Plugin::lockNode (   $uri,
LockInfo  $lockInfo 
)

Locks a uri.

All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client

Parameters
string$uri
LockInfo$lockInfo
Returns
bool

Definition at line 337 of file Plugin.php.

337 {
338
339 if (!$this->server->emit('beforeLock', [$uri, $lockInfo])) return;
340 return $this->locksBackend->lock($uri, $lockInfo);
341
342 }

Referenced by Sabre\DAV\Locks\Plugin\httpLock().

+ Here is the caller graph for this function:

◆ parseLockRequest()

Sabre\DAV\Locks\Plugin::parseLockRequest (   $body)
protected

Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object.

Parameters
string$body
Returns
LockInfo

Definition at line 551 of file Plugin.php.

551 {
552
553 $result = $this->server->xml->expect(
554 '{DAV:}lockinfo',
555 $body
556 );
557
558 $lockInfo = new LockInfo();
559
560 $lockInfo->owner = $result->owner;
561 $lockInfo->token = DAV\UUIDUtil::getUUID();
562 $lockInfo->scope = $result->scope;
563
564 return $lockInfo;
565
566 }
$result
static getUUID()
Returns a pseudo-random v4 UUID.
Definition: UUIDUtil.php:26

References $result, and Sabre\DAV\UUIDUtil\getUUID().

Referenced by Sabre\DAV\Locks\Plugin\httpLock().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ propFind()

Sabre\DAV\Locks\Plugin::propFind ( DAV\PropFind  $propFind,
DAV\INode  $node 
)

This method is called after most properties have been found it allows us to add in any Lock-related properties.

Parameters
DAV\PropFind$propFind
DAV\INode$node
Returns
void

Definition at line 94 of file Plugin.php.

94 {
95
96 $propFind->handle('{DAV:}supportedlock', function() {
97 return new DAV\Xml\Property\SupportedLock();
98 });
99 $propFind->handle('{DAV:}lockdiscovery', function() use ($propFind) {
100 return new DAV\Xml\Property\LockDiscovery(
101 $this->getLocks($propFind->getPath())
102 );
103 });
104
105 }

References Sabre\DAV\Locks\Plugin\getLocks().

+ Here is the call graph for this function:

◆ unlockNode()

Sabre\DAV\Locks\Plugin::unlockNode (   $uri,
LockInfo  $lockInfo 
)

Unlocks a uri.

This method removes a lock from a uri. It is assumed all the supplied information is correct and verified

Parameters
string$uri
LockInfo$lockInfo
Returns
bool

Definition at line 353 of file Plugin.php.

353 {
354
355 if (!$this->server->emit('beforeUnlock', [$uri, $lockInfo])) return;
356 return $this->locksBackend->unlock($uri, $lockInfo);
357
358 }

Referenced by Sabre\DAV\Locks\Plugin\afterUnbind(), and Sabre\DAV\Locks\Plugin\httpUnlock().

+ Here is the caller graph for this function:

◆ validateTokens()

Sabre\DAV\Locks\Plugin::validateTokens ( RequestInterface  $request,
$conditions 
)

The validateTokens event is triggered before every request.

It's a moment where this plugin can check all the supplied lock tokens in the If: header, and check if they are valid.

In addition, it will also ensure that it checks any missing lokens that must be present in the request, and reject requests without the proper tokens.

Parameters
RequestInterface$request
mixed$conditions
Returns
void

Definition at line 416 of file Plugin.php.

416 {
417
418 // First we need to gather a list of locks that must be satisfied.
419 $mustLocks = [];
420 $method = $request->getMethod();
421
422 // Methods not in that list are operations that doesn't alter any
423 // resources, and we don't need to check the lock-states for.
424 switch ($method) {
425
426 case 'DELETE' :
427 $mustLocks = array_merge($mustLocks, $this->getLocks(
428 $request->getPath(),
429 true
430 ));
431 break;
432 case 'MKCOL' :
433 case 'MKCALENDAR' :
434 case 'PROPPATCH' :
435 case 'PUT' :
436 case 'PATCH' :
437 $mustLocks = array_merge($mustLocks, $this->getLocks(
438 $request->getPath(),
439 false
440 ));
441 break;
442 case 'MOVE' :
443 $mustLocks = array_merge($mustLocks, $this->getLocks(
444 $request->getPath(),
445 true
446 ));
447 $mustLocks = array_merge($mustLocks, $this->getLocks(
448 $this->server->calculateUri($request->getHeader('Destination')),
449 false
450 ));
451 break;
452 case 'COPY' :
453 $mustLocks = array_merge($mustLocks, $this->getLocks(
454 $this->server->calculateUri($request->getHeader('Destination')),
455 false
456 ));
457 break;
458 case 'LOCK' :
459 //Temporary measure.. figure out later why this is needed
460 // Here we basically ignore all incoming tokens...
461 foreach ($conditions as $ii => $condition) {
462 foreach ($condition['tokens'] as $jj => $token) {
463 $conditions[$ii]['tokens'][$jj]['validToken'] = true;
464 }
465 }
466 return;
467
468 }
469
470 // It's possible that there's identical locks, because of shared
471 // parents. We're removing the duplicates here.
472 $tmp = [];
473 foreach ($mustLocks as $lock) $tmp[$lock->token] = $lock;
474 $mustLocks = array_values($tmp);
475
476 foreach ($conditions as $kk => $condition) {
477
478 foreach ($condition['tokens'] as $ii => $token) {
479
480 // Lock tokens always start with opaquelocktoken:
481 if (substr($token['token'], 0, 16) !== 'opaquelocktoken:') {
482 continue;
483 }
484
485 $checkToken = substr($token['token'], 16);
486 // Looping through our list with locks.
487 foreach ($mustLocks as $jj => $mustLock) {
488
489 if ($mustLock->token == $checkToken) {
490
491 // We have a match!
492 // Removing this one from mustlocks
493 unset($mustLocks[$jj]);
494
495 // Marking the condition as valid.
496 $conditions[$kk]['tokens'][$ii]['validToken'] = true;
497
498 // Advancing to the next token
499 continue 2;
500
501 }
502
503 }
504
505 // If we got here, it means that there was a
506 // lock-token, but it was not in 'mustLocks'.
507 //
508 // This is an edge-case, as it could mean that token
509 // was specified with a url that was not 'required' to
510 // check. So we're doing one extra lookup to make sure
511 // we really don't know this token.
512 //
513 // This also gets triggered when the user specified a
514 // lock-token that was expired.
515 $oddLocks = $this->getLocks($condition['uri']);
516 foreach ($oddLocks as $oddLock) {
517
518 if ($oddLock->token === $checkToken) {
519
520 // We have a hit!
521 $conditions[$kk]['tokens'][$ii]['validToken'] = true;
522 continue 2;
523
524 }
525 }
526
527 // If we get all the way here, the lock-token was
528 // really unknown.
529
530
531 }
532
533 }
534
535 // If there's any locks left in the 'mustLocks' array, it means that
536 // the resource was locked and we must block it.
537 if ($mustLocks) {
538
539 throw new DAV\Exception\Locked(reset($mustLocks));
540
541 }
542
543 }

References $ii, $request, PHPMailer\PHPMailer\$token, Sabre\DAV\Locks\Plugin\getLocks(), and Sabre\HTTP\RequestInterface\getPath().

+ Here is the call graph for this function:

Field Documentation

◆ $locksBackend

Sabre\DAV\Locks\Plugin::$locksBackend
protected

Definition at line 30 of file Plugin.php.

Referenced by Sabre\DAV\Locks\Plugin\__construct().

◆ $server

Sabre\DAV\Locks\Plugin::$server
protected

Definition at line 37 of file Plugin.php.

Referenced by Sabre\DAV\Locks\Plugin\initialize().


The documentation for this class was generated from the following file: