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 
25 require_once "./Services/Object/classes/class.ilObject.php";
26 require_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
updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires)
Updates a write lock.
$result
$isDebug
Set this to true, to get debug output in the ILIAS log.
lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
Creates a write lock.
unlockWithoutCheckingDAV(&$objDAV, $token)
Discards a write lock.
global $DIC
Definition: saml.php:7
updateLockWithoutCheckingDAV(&$objDAV, $token, $expires)
Updates a write lock.
getLocksOnPathRef($refId)
Returns all locks on the specified object, specified by a reference id.
writelog($message)
Writes a message to the logfile.,.
getLocksOnObjectObj($objId, $nodeId=0)
Returns all locks on the specified object id.
static _getAllReferences($a_id)
get all reference ids of object
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...
cleanUp()
System maintenance: get rid of locks that have expired over an hour ago.
$r
Definition: example_031.php:79
catch(Exception $e) $message
$success
Definition: Utf8Test.php:86
getLocksOnPathDAV(&$pathDAV)
Returns all locks on the specified object path.
lockWithoutCheckingDAV(&$objDAV, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
Creates a write lock.
$old
$txt
Definition: error.php:11
Create styles array
The data for the language used.
global $ilDB
getLockDAV(&$objDAV, $token)
Returns the lock with the specified token on the specified DAV object.
Add data(end) time
Method that wraps PHPs time in order to allow simulations with the workflow.
isError($data, $code=null)
Tell whether a value is a PEAR error.
Definition: PEAR.php:280
getLocksOnObjectDAV(&$objDAV)
Returns all locks on the specified object.