ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
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 {
96 if ($lock['token'] == $token &&
97 $lock['obj_id'] == $data['obj_id'] &&
98 $lock['ilias_owner'] == $iliasUserId)
99 {
100 if ($this->updateLockWithoutCheckingObj($data['obj_id'], 0, $token, $expires))
101 {
102 return true;
103 }
104 else
105 {
106 return 'couldnt update lock';
107 }
108 }
109 }
110
111 if ($result === true)
112 {
113 foreach ($locksOnPath as $lock)
114 {
115 if ($lock['scope'] == 'exclusive' &&
116 ($lock['depth'] == 'infinity' || $lock['obj_id'] == $data['obj_id']) &&
117 $lock['ilias_owner'] != $iliasUserId)
118 {
119 $result = 'couldnt create lock due to exclusive lock on path '.var_export($lock,true);
120 break;
121 }
122 }
123 }
124
125 // Check whether a lock on the children (subtree) of the object prevents
126 // the creation of a new lock
127 if ($result === true && $depth == 'infinity')
128 {
129 // XXX - if lock has depth infinity, we must check for locks in the subtree
130 }
131
132 if ($result === true)
133 {
135 $data['obj_id'], 0,
136 $iliasUserId, $davUser, $token, $expires, $depth, $scope
137 );
138 }
139 return $result;
140 }
141
164 public function lockWithoutCheckingDAV(&$objDAV, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
165 {
166 $objId = $objDAV->getObjectId();
167 $nodeId = $objDAV->getNodeId();
168
169 return $this->lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope);
170 }
195 public function lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
196 {
197 global $DIC;
198 $ilDB = $DIC['ilDB'];
199
200 switch ($depth)
201 {
202 case 'infinity' : $depth = -1;
203 break;
204 case 0 :
205 $depth = 0;
206 break;
207 default :
208 trigger_error('invalid depth '.$depth,E_ERROR);
209 return;
210 }
211
212 switch ($scope)
213 {
214 case 'exclusive' : $scope = 'x'; break;
215 case 'shared' : $scope = 's'; break;
216 default : trigger_error('invalid scope '.$scope,E_ERROR); return;
217 }
218
219 $q = 'INSERT INTO '.$this->table
220 .' SET obj_id = '.$ilDB->quote($objId,'integer')
221 .', node_id = '.$ilDB->quote($nodeId,'integer')
222 .', ilias_owner = '.$ilDB->quote($iliasUserId,'text')
223 .', dav_owner = '.$ilDB->quote($davUser,'text')
224 .', token = '.$ilDB->quote($token,'text')
225 .', expires = '.$ilDB->quote($expires,'integer')
226 .', depth = '.$ilDB->quote($depth,'integer')
227 .', type = \'w\''
228 .', scope = '.$ilDB->quote($scope,'text')
229 ;
230 $this->writelog('lock query='.$q);
231 $result = $ilDB->manipulate($q);
232 return ! PEAR::isError($result);
233 }
245 public function updateLockWithoutCheckingDAV(&$objDAV, $token, $expires)
246 {
247 global $DIC;
248 $ilDB = $DIC['ilDB'];
249 $objId = $objDAV->getObjectId();
250 $nodeId = $objDAV->getNodeId();
251
252 return $this->updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires);
253 }
265 public function updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires)
266 {
267 global $DIC;
268 $ilDB = $DIC['ilDB'];
269
270 $q = 'UPDATE '.$this->table
271 .' SET expires = '.$ilDB->quote($expires,'integer')
272 .' WHERE token = '.$ilDB->quote($token,'text')
273 .' AND obj_id = '.$ilDB->quote($objId,'integer')
274 .' AND node_id = '.$ilDB->quote($nodeId,'integer')
275 ;
276 $aff = $ilDB->manipulate($q);
277 return $aff > 0;
278 }
290 public function unlockWithoutCheckingDAV(&$objDAV, $token)
291 {
292 global $DIC;
293 $ilDB = $DIC['ilDB'];
294 $this->writelog('unlock('.$objDAV.','.$token.')');
295
296 $objId = $objDAV->getObjectId();
297 $nodeId = $objDAV->getNodeId();
298
299 // Unlock object
300 // FIXME - Maybe we should delete all rows with the same token, not
301 // just the ones with the same token, obj_id and node_id.
302 $q = 'DELETE FROM '.$this->table
303 .' WHERE token = '.$ilDB->quote($token,'text')
304 .' AND obj_id = '.$ilDB->quote($objId,'integer')
305 .' AND node_id = '.$ilDB->quote($nodeId,'integer')
306 ;
307 $this->writelog('unlock query='.$q);
308 $aff = $ilDB->manipulate($q);
309 $success = $aff > 0;
310
311 // clean up expired locks in 1 out of 100 unlock requests
312 if (rand(1,100) == 1)
313 {
314 $this->cleanUp();
315 }
316
317 return $success;
318 }
319
334 public function getLockDAV(&$objDAV,$token)
335 {
336 global $DIC;
337 $ilDB = $DIC['ilDB'];
338 $this->writelog('getLocks('.$objDAV.')');
339 $objId = $objDAV->getObjectId();
340 $nodeId = $objDAV->getNodeId();
341
342 $q = 'SELECT ilias_owner, dav_owner, expires, depth, scope'
343 .' FROM '.$this->table
344 .' WHERE obj_id = '.$ilDB->quote($objId,'integer')
345 .' AND node_id = '.$ilDB->quote($nodeId,'integer')
346 .' AND token = '.$ilDB->quote($token,'text')
347 ;
348 $this->writelog('getLocks('.$objDAV.') query='.$q);
349 $r = $ilDB->query($q);
350
351 $result = array();
352 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC))
353 {
354 if ($row['depth'] == -1) $row['depth'] = 'infinity';
355 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
356 $row['token'] = $token;
357 $result = $row;
358 }
359 return $result;
360 }
375 public function getLocksOnObjectDAV(&$objDAV)
376 {
377 $objId = $objDAV->getObjectId();
378 $nodeId = $objDAV->getNodeId();
379
380 return $this->getLocksOnObjectObj($objId, $nodeId);
381 }
398 public function getLocksOnObjectObj($objId, $nodeId = 0)
399 {
400 global $DIC;
401 $ilDB = $DIC['ilDB'];
402 $this->writelog('getLocks('.$objDAV.')');
403 $nodeId = 0;
404 $q = 'SELECT ilias_owner, dav_owner, token, expires, depth, scope'
405 .' FROM '.$this->table
406 .' WHERE obj_id = '.$ilDB->quote($objId,'integer')
407 .' AND node_id = '.$ilDB->quote($nodeId,'integer')
408 .' AND expires > '.$ilDB->quote(time(),'integer')
409 ;
410 $this->writelog('getLocks('.$objDAV.') query='.$q);
411 $r = $ilDB->query($q);
412
413 $result = array();
414 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC))
415 {
416 if ($row['depth'] == -1) $row['depth'] = 'infinity';
417 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
418 $result[] = $row;
419 }
420 return $result;
421 }
437 public function getLocksOnPathDAV(&$pathDAV)
438 {
439 global $DIC;
440 $ilDB = $DIC['ilDB'];
441 $this->writelog('getLocksOnPathDAV');
442
443 $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
444 .' FROM '.$this->table
445 .' WHERE expires > '.$ilDB->quote(time(),'integer')
446 .' AND ('
447 ;
448 $isFirst = true;
449 foreach ($pathDAV as $objDAV)
450 {
451 $objId = $objDAV->getObjectId();
452 $nodeId = $objDAV->getNodeId();
453 if ($isFirst)
454 {
455 $isFirst = false;
456 } else {
457 $q .= ' OR ';
458 }
459 $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
460 }
461 $q .= ')';
462
463 $this->writelog('getLocksOnPathDAV('.$objDAV.') query='.$q);
464 $r = $ilDB->query($q);
465
466 $result = array();
467 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC))
468 {
469 if ($row['depth'] == -1) $row['depth'] = 'infinity';
470 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
471 $result[] = $row;
472 }
473 $this->writelog('getLocksOnPathDAV:'.var_export($result,true));
474 return $result;
475 }
491 public function getLocksOnPathRef($refId)
492 {
493 global $DIC;
494 $ilDB = $DIC['ilDB'];
495 $tree = $DIC['tree'];
496 $this->writelog('getLocksOnPathRef('.$refId.')');
497
498 $pathFull = $tree->getPathFull($refId);
499
500 $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
501 .' FROM '.$this->table
502 .' WHERE expires > '.$ilDB->quote(time(),'integer')
503 .' AND ('
504 ;
505 $isFirst = true;
506 foreach ($pathFull as $pathItem)
507 {
508 $objId = $pathItem['obj_id'];
509 $nodeId = 0;
510 if ($isFirst)
511 {
512 $isFirst = false;
513 } else {
514 $q .= ' OR ';
515 }
516 $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
517 }
518 $q .= ')';
519
520 $this->writelog('getLocksOnPathRef('.$refId.') query='.$q);
521 $r = $ilDB->query($q);
522
523 $result = array();
524 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC))
525 {
526 if ($row['depth'] == -1) $row['depth'] = 'infinity';
527 $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
528 $result[] = $row;
529 }
530 return $result;
531 }
537 public function cleanUp()
538 {
539 global $DIC;
540 $ilDB = $DIC['ilDB'];
541 $tree = $DIC['tree'];
542
543 // 1. Get rid of locks that have expired over an hour ago
544 $old = time() - 3600;
545 $q = 'DELETE'
546 .' FROM '.$this->table
547 .' WHERE expires < '.$ilDB->quote($old,'integer')
548 ;
549 $ilDB->manipulate($q);
550
551 // 2. Get rid of null resources which are not associated to
552 // a lock due to step 1, or due to a database inconsistency
553 // because we are working with non-transactional tables
554 $q = 'SELECT dat.obj_id '
555 .' FROM object_data AS dat'
556 .' LEFT JOIN '.$this->table.' lck'
557 .' ON dat.obj_id = lck.obj_id'
558 .' WHERE dat.type = '.$ilDB->quote('null','text')
559 .' AND lck.obj_id IS NULL'
560 ;
561/* TODO: smeyer.' FOR UPDATE' */
562
563 $r = $ilDB->query($q);
564 while ($row = $r->fetchRow(ilDBConstants::FETCHMODE_ASSOC))
565 {
566 $references = ilObject::_getAllReferences($row['obj_id']);
567 $obj = new ilObjNull($row['obj_id'], false);
568 if (count($references) == 0)
569 {
570 $obj->delete();
571 } else {
572 foreach ($references as $refId)
573 {
574 $obj->setRefId($refId);
575 $obj->delete();
576 $nodeData = $tree->getNodeData($refId);
577 $tree->deleteTree($nodeData);
578 }
579 }
580 }
581 }
588 protected function writelog($message)
589 {
590 global $DIC;
591 $log = $DIC['log'];
592 $ilias = $DIC['ilias'];
593 if ($this->isDebug)
594 {
595 $log->write(
596 $ilias->account->getLogin()
597 .' DAV ilDAVLocks.'.str_replace("\n",";",$message)
598 );
599 }
600 /*
601 if ($this->logFile)
602 {
603 $fh = fopen($this->logFile, 'a');
604 fwrite($fh, date('Y-m-d h:i:s '));
605 fwrite($fh, str_replace("\n",";",$message));
606 fwrite($fh, "\n\n");
607 fclose($fh);
608 }*/
609 }
610}
611// END WebDAV
612?>
$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:12
$r
Definition: example_031.php:79
$old
global $ilDB
global $DIC