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 
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  {
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 ?>
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.
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
$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:12
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.
global $DIC
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.