ILIAS  release_5-3 Revision v5.3.23-19-g915713cf615
class.ilDAVLocks.php
Go to the documentation of this file.
1<?php
2// BEGIN WebDAV
3/*
4 +-----------------------------------------------------------------------------+
5 | ILIAS open source |
6 +-----------------------------------------------------------------------------+
7 | Copyright (c) 1998-2005 ILIAS open source, University of Cologne |
8 | |
9 | This program is free software; you can redistribute it and/or |
10 | modify it under the terms of the GNU General Public License |
11 | as published by the Free Software Foundation; either version 2 |
12 | of the License, or (at your option) any later version. |
13 | |
14 | This program is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with this program; if not, write to the Free Software |
21 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
22 +-----------------------------------------------------------------------------+
23*/
24
25require_once "./Services/Object/classes/class.ilObject.php";
26require_once "Services/WebDAV/classes/class.ilObjNull.php";
43{
44 private $table = 'dav_lock';
45
47 private $isDebug = false;
48
49 public function __construct()
50 {
51 }
52
76 public function lockRef($refId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
77 {
78 $this->writelog('lockRef(' . $refId . ',' . $iliasUserId . ',' . $davUser . ',' . $token . ',' . $expires . ',' . $depth . ',' . $scope . ')');
79 global $DIC;
80 $tree = $DIC['tree'];
81 $txt = $DIC['txt'];
82
83 $result = true;
84 $data = $tree->getNodeData($refId);
85
86 // Check whether a lock on the path to the object prevents the creation
87 // of a new lock
88 $locksOnPath = $this->getLocksOnPathRef($refId);
89
90 if ($scope == 'exclusive' && count($locksOnPath) > 0) {
91 $result = 'couldnt create exclusive lock due to existing lock on path ' . var_export($locksOnPath, true);
92 }
93
94 foreach ($locksOnPath as $lock) {
95 if ($lock['token'] == $token &&
96 $lock['obj_id'] == $data['obj_id'] &&
97 $lock['ilias_owner'] == $iliasUserId) {
98 if ($this->updateLockWithoutCheckingObj($data['obj_id'], 0, $token, $expires)) {
99 return true;
100 } else {
101 return 'couldnt update lock';
102 }
103 }
104 }
105
106 if ($result === true) {
107 foreach ($locksOnPath as $lock) {
108 if ($lock['scope'] == 'exclusive' &&
109 ($lock['depth'] == 'infinity' || $lock['obj_id'] == $data['obj_id']) &&
110 $lock['ilias_owner'] != $iliasUserId) {
111 $result = 'couldnt create lock due to exclusive lock on path ' . var_export($lock, true);
112 break;
113 }
114 }
115 }
116
117 // Check whether a lock on the children (subtree) of the object prevents
118 // the creation of a new lock
119 if ($result === true && $depth == 'infinity') {
120 // XXX - if lock has depth infinity, we must check for locks in the subtree
121 }
122
123 if ($result === true) {
125 $data['obj_id'],
126 0,
127 $iliasUserId,
128 $davUser,
129 $token,
130 $expires,
131 $depth,
132 $scope
133 );
134 }
135 return $result;
136 }
137
160 public function lockWithoutCheckingDAV(&$objDAV, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
161 {
162 $objId = $objDAV->getObjectId();
163 $nodeId = $objDAV->getNodeId();
164
165 return $this->lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope);
166 }
191 public function lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
192 {
193 global $DIC;
194 $ilDB = $DIC['ilDB'];
195
196 switch ($depth) {
197 case 'infinity': $depth = -1;
198 break;
199 case 0:
200 $depth = 0;
201 break;
202 default:
203 trigger_error('invalid depth ' . $depth, E_ERROR);
204 return;
205 }
206
207 switch ($scope) {
208 case 'exclusive': $scope = 'x'; break;
209 case 'shared': $scope = 's'; break;
210 default: trigger_error('invalid scope ' . $scope, E_ERROR); return;
211 }
212
213 $q = 'INSERT INTO ' . $this->table
214 . ' SET obj_id = ' . $ilDB->quote($objId, 'integer')
215 . ', node_id = ' . $ilDB->quote($nodeId, 'integer')
216 . ', ilias_owner = ' . $ilDB->quote($iliasUserId, 'text')
217 . ', dav_owner = ' . $ilDB->quote($davUser, 'text')
218 . ', token = ' . $ilDB->quote($token, 'text')
219 . ', expires = ' . $ilDB->quote($expires, 'integer')
220 . ', depth = ' . $ilDB->quote($depth, 'integer')
221 . ', type = \'w\''
222 . ', scope = ' . $ilDB->quote($scope, 'text')
223 ;
224 $this->writelog('lock query=' . $q);
225 $result = $ilDB->manipulate($q);
226 return !PEAR::isError($result);
227 }
239 public function updateLockWithoutCheckingDAV(&$objDAV, $token, $expires)
240 {
241 global $DIC;
242 $ilDB = $DIC['ilDB'];
243 $objId = $objDAV->getObjectId();
244 $nodeId = $objDAV->getNodeId();
245
246 return $this->updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires);
247 }
259 public function updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires)
260 {
261 global $DIC;
262 $ilDB = $DIC['ilDB'];
263
264 $q = 'UPDATE ' . $this->table
265 . ' SET expires = ' . $ilDB->quote($expires, 'integer')
266 . ' WHERE token = ' . $ilDB->quote($token, 'text')
267 . ' AND obj_id = ' . $ilDB->quote($objId, 'integer')
268 . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer')
269 ;
270 $aff = $ilDB->manipulate($q);
271 return $aff > 0;
272 }
284 public function unlockWithoutCheckingDAV(&$objDAV, $token)
285 {
286 global $DIC;
287 $ilDB = $DIC['ilDB'];
288 $this->writelog('unlock(' . $objDAV . ',' . $token . ')');
289
290 $objId = $objDAV->getObjectId();
291 $nodeId = $objDAV->getNodeId();
292
293 // Unlock object
294 // FIXME - Maybe we should delete all rows with the same token, not
295 // just the ones with the same token, obj_id and node_id.
296 $q = 'DELETE FROM ' . $this->table
297 . ' WHERE token = ' . $ilDB->quote($token, 'text')
298 . ' AND obj_id = ' . $ilDB->quote($objId, 'integer')
299 . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer')
300 ;
301 $this->writelog('unlock query=' . $q);
302 $aff = $ilDB->manipulate($q);
303 $success = $aff > 0;
304
305 // clean up expired locks in 1 out of 100 unlock requests
306 $random = new \ilRandom();
307 if ($random->int(1, 100) == 1) {
308 $this->cleanUp();
309 }
310
311 return $success;
312 }
313
328 public function getLockDAV(&$objDAV, $token)
329 {
330 global $DIC;
331 $ilDB = $DIC['ilDB'];
332 $this->writelog('getLocks(' . $objDAV . ')');
333 $objId = $objDAV->getObjectId();
334 $nodeId = $objDAV->getNodeId();
335
336 $q = 'SELECT ilias_owner, dav_owner, expires, depth, scope'
337 . ' FROM ' . $this->table
338 . ' WHERE obj_id = ' . $ilDB->quote($objId, 'integer')
339 . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer')
340 . ' AND token = ' . $ilDB->quote($token, 'text')
341 ;
342 $this->writelog('getLocks(' . $objDAV . ') query=' . $q);
343 $r = $ilDB->query($q);
344
345 $result = array();
346 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
347 if ($row['depth'] == -1) {
348 $row['depth'] = 'infinity';
349 }
350 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
351 $row['token'] = $token;
352 $result = $row;
353 }
354 return $result;
355 }
370 public function getLocksOnObjectDAV(&$objDAV)
371 {
372 $objId = $objDAV->getObjectId();
373 $nodeId = $objDAV->getNodeId();
374
375 return $this->getLocksOnObjectObj($objId, $nodeId);
376 }
393 public function getLocksOnObjectObj($objId, $nodeId = 0)
394 {
395 global $DIC;
396 $ilDB = $DIC['ilDB'];
397 $this->writelog('getLocks(' . $objDAV . ')');
398 $nodeId = 0;
399 $q = 'SELECT ilias_owner, dav_owner, token, expires, depth, scope'
400 . ' FROM ' . $this->table
401 . ' WHERE obj_id = ' . $ilDB->quote($objId, 'integer')
402 . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer')
403 . ' AND expires > ' . $ilDB->quote(time(), 'integer')
404 ;
405 $this->writelog('getLocks(' . $objDAV . ') query=' . $q);
406 $r = $ilDB->query($q);
407
408 $result = array();
409 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
410 if ($row['depth'] == -1) {
411 $row['depth'] = 'infinity';
412 }
413 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
414 $result[] = $row;
415 }
416 return $result;
417 }
433 public function getLocksOnPathDAV(&$pathDAV)
434 {
435 global $DIC;
436 $ilDB = $DIC['ilDB'];
437 $this->writelog('getLocksOnPathDAV');
438
439 $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
440 . ' FROM ' . $this->table
441 . ' WHERE expires > ' . $ilDB->quote(time(), 'integer')
442 . ' AND ('
443 ;
444 $isFirst = true;
445 foreach ($pathDAV as $objDAV) {
446 $objId = $objDAV->getObjectId();
447 $nodeId = $objDAV->getNodeId();
448 if ($isFirst) {
449 $isFirst = false;
450 } else {
451 $q .= ' OR ';
452 }
453 $q .= '(obj_id = ' . $ilDB->quote($objId, 'integer') . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer') . ')';
454 }
455 $q .= ')';
456
457 $this->writelog('getLocksOnPathDAV(' . $objDAV . ') query=' . $q);
458 $r = $ilDB->query($q);
459
460 $result = array();
461 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
462 if ($row['depth'] == -1) {
463 $row['depth'] = 'infinity';
464 }
465 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
466 $result[] = $row;
467 }
468 $this->writelog('getLocksOnPathDAV:' . var_export($result, true));
469 return $result;
470 }
486 public function getLocksOnPathRef($refId)
487 {
488 global $DIC;
489 $ilDB = $DIC['ilDB'];
490 $tree = $DIC['tree'];
491 $this->writelog('getLocksOnPathRef(' . $refId . ')');
492
493 $pathFull = $tree->getPathFull($refId);
494
495 $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
496 . ' FROM ' . $this->table
497 . ' WHERE expires > ' . $ilDB->quote(time(), 'integer')
498 . ' AND ('
499 ;
500 $isFirst = true;
501 foreach ($pathFull as $pathItem) {
502 $objId = $pathItem['obj_id'];
503 $nodeId = 0;
504 if ($isFirst) {
505 $isFirst = false;
506 } else {
507 $q .= ' OR ';
508 }
509 $q .= '(obj_id = ' . $ilDB->quote($objId, 'integer') . ' AND node_id = ' . $ilDB->quote($nodeId, 'integer') . ')';
510 }
511 $q .= ')';
512
513 $this->writelog('getLocksOnPathRef(' . $refId . ') query=' . $q);
514 $r = $ilDB->query($q);
515
516 $result = array();
517 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
518 if ($row['depth'] == -1) {
519 $row['depth'] = 'infinity';
520 }
521 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
522 $result[] = $row;
523 }
524 return $result;
525 }
531 public function cleanUp()
532 {
533 global $DIC;
534 $ilDB = $DIC['ilDB'];
535 $tree = $DIC['tree'];
536
537 // 1. Get rid of locks that have expired over an hour ago
538 $old = time() - 3600;
539 $q = 'DELETE'
540 . ' FROM ' . $this->table
541 . ' WHERE expires < ' . $ilDB->quote($old, 'integer')
542 ;
543 $ilDB->manipulate($q);
544
545 // 2. Get rid of null resources which are not associated to
546 // a lock due to step 1, or due to a database inconsistency
547 // because we are working with non-transactional tables
548 $q = 'SELECT dat.obj_id '
549 . ' FROM object_data AS dat'
550 . ' LEFT JOIN ' . $this->table . ' lck'
551 . ' ON dat.obj_id = lck.obj_id'
552 . ' WHERE dat.type = ' . $ilDB->quote('null', 'text')
553 . ' AND lck.obj_id IS NULL'
554 ;
555 /* TODO: smeyer.' FOR UPDATE' */
556
557 $r = $ilDB->query($q);
558 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) {
559 $references = ilObject::_getAllReferences($row['obj_id']);
560 $obj = new ilObjNull($row['obj_id'], false);
561 if (count($references) == 0) {
562 $obj->delete();
563 } else {
564 foreach ($references as $refId) {
565 $obj->setRefId($refId);
566 $obj->delete();
567 $nodeData = $tree->getNodeData($refId);
568 $tree->deleteTree($nodeData);
569 }
570 }
571 }
572 }
579 protected function writelog($message)
580 {
581 global $DIC;
582 $log = $DIC['log'];
583 $ilias = $DIC['ilias'];
584 if ($this->isDebug) {
585 $log->write(
586 $ilias->account->getLogin()
587 . ' DAV ilDAVLocks.' . str_replace("\n", ";", $message)
588 );
589 }
590 /*
591 if ($this->logFile)
592 {
593 $fh = fopen($this->logFile, 'a');
594 fwrite($fh, date('Y-m-d h:i:s '));
595 fwrite($fh, str_replace("\n",";",$message));
596 fwrite($fh, "\n\n");
597 fclose($fh);
598 }*/
599 }
600}
601// END WebDAV
$result
$success
Definition: Utf8Test.php:86
An exception for terminatinating execution or to throw for unit testing.
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:280
updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires)
Updates a write lock.
unlockWithoutCheckingDAV(&$objDAV, $token)
Discards a write lock.
lockWithoutCheckingDAV(&$objDAV, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
Creates a write lock.
getLocksOnObjectObj($objId, $nodeId=0)
Returns all locks on the specified object id.
lockRef($refId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
Creates a lock an object, unless there are locks on the object or its parents, which prevent the crea...
$isDebug
Set this to true, to get debug output in the ILIAS log.
getLocksOnPathRef($refId)
Returns all locks on the specified object, specified by a reference id.
lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
cleanUp()
System maintenance: get rid of locks that have expired over an hour ago.
getLocksOnPathDAV(&$pathDAV)
Returns all locks on the specified object path.
updateLockWithoutCheckingDAV(&$objDAV, $token, $expires)
Updates a write lock.
writelog($message)
Writes a message to the logfile.,.
getLocksOnObjectDAV(&$objDAV)
Returns all locks on the specified object.
getLockDAV(&$objDAV, $token)
Returns the lock with the specified token on the specified DAV object.
static _getAllReferences($a_id)
get all reference ids of object
$txt
Definition: error.php:11
$r
Definition: example_031.php:79
catch(Exception $e) $message
$old
global $DIC
Definition: saml.php:7
global $ilDB