ILIAS  Release_4_1_x_branch Revision 61804
 All Data Structures Namespaces Files Functions Variables Groups Pages
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 "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 ilDAVLocks()
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 $tree, $txt;
80 
81  $result = true;
82  $data = $tree->getNodeData($refId);
83 
84  // Check whether a lock on the path to the object prevents the creation
85  // of a new lock
86  $locksOnPath = $this->getLocksOnPathRef($refId);
87 
88  if ($scope == 'exclusive' && count($locksOnPath) > 0) {
89  $result = 'couldnt create exclusive lock due to existing lock on path '.var_export($locksOnPath,true);
90  }
91 
92  foreach ($locksOnPath as $lock)
93  {
94  if ($lock['token'] == $token &&
95  $lock['obj_id'] == $data['obj_id'] &&
96  $lock['ilias_owner'] == $iliasUserId)
97  {
98  if ($this->updateLockWithoutCheckingObj($data['obj_id'], 0, $token, $expires))
99  {
100  return true;
101  }
102  else
103  {
104  return 'couldnt update lock';
105  }
106  }
107  }
108 
109  if ($result === true)
110  {
111  foreach ($locksOnPath as $lock)
112  {
113  if ($lock['scope'] == 'exclusive' &&
114  ($lock['depth'] == 'infinity' || $lock['obj_id'] == $data['obj_id']) &&
115  $lock['ilias_owner'] != $iliasUserId)
116  {
117  $result = 'couldnt create lock due to exclusive lock on path '.var_export($lock,true);
118  break;
119  }
120  }
121  }
122 
123  // Check whether a lock on the children (subtree) of the object prevents
124  // the creation of a new lock
125  if ($result === true && $depth == 'infinity')
126  {
127  // XXX - if lock has depth infinity, we must check for locks in the subtree
128  }
129 
130  if ($result === true)
131  {
133  $data['obj_id'], 0,
134  $iliasUserId, $davUser, $token, $expires, $depth, $scope
135  );
136  }
137  return $result;
138  }
139 
162  public function lockWithoutCheckingDAV(&$objDAV, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
163  {
164  $objId = $objDAV->getObjectId();
165  $nodeId = $objDAV->getNodeId();
166 
167  return $this->lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope);
168  }
193  public function lockWithoutCheckingObj($objId, $nodeId, $iliasUserId, $davUser, $token, $expires, $depth, $scope)
194  {
195  global $ilDB;
196 
197  switch ($depth)
198  {
199  case 'infinity' : $depth = -1;
200  break;
201  case 0 :
202  $depth = 0;
203  break;
204  default :
205  trigger_error('invalid depth '.$depth,E_ERROR);
206  return;
207  }
208 
209  switch ($scope)
210  {
211  case 'exclusive' : $scope = 'x'; break;
212  case 'shared' : $scope = 's'; break;
213  default : trigger_error('invalid scope '.$scope,E_ERROR); return;
214  }
215 
216  $q = 'INSERT INTO '.$this->table
217  .' SET obj_id = '.$ilDB->quote($objId,'integer')
218  .', node_id = '.$ilDB->quote($nodeId,'integer')
219  .', ilias_owner = '.$ilDB->quote($iliasUserId,'text')
220  .', dav_owner = '.$ilDB->quote($davUser,'text')
221  .', token = '.$ilDB->quote($token,'text')
222  .', expires = '.$ilDB->quote($expires,'integer')
223  .', depth = '.$ilDB->quote($depth,'integer')
224  .', type = \'w\''
225  .', scope = '.$ilDB->quote($scope,'text')
226  ;
227  $this->writelog('lock query='.$q);
228  $result = $ilDB->manipulate($q);
229  return ! PEAR::isError($result);
230  }
242  public function updateLockWithoutCheckingDAV(&$objDAV, $token, $expires)
243  {
244  global $ilDB;
245  $objId = $objDAV->getObjectId();
246  $nodeId = $objDAV->getNodeId();
247 
248  return $this->updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires);
249  }
261  public function updateLockWithoutCheckingObj($objId, $nodeId, $token, $expires)
262  {
263  global $ilDB;
264 
265  $q = 'UPDATE '.$this->table
266  .' SET expires = '.$ilDB->quote($expires,'integer')
267  .' WHERE token = '.$ilDB->quote($token,'text')
268  .' AND obj_id = '.$ilDB->quote($objId,'integer')
269  .' AND node_id = '.$ilDB->quote($nodeId,'integer')
270  ;
271  $aff = $ilDB->manipulate($q);
272  return $aff > 0;
273  }
285  public function unlockWithoutCheckingDAV(&$objDAV, $token)
286  {
287  global $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  if (rand(1,100) == 1)
307  {
308  $this->cleanUp();
309  }
310 
311  return $success;
312  }
313 
328  public function getLockDAV(&$objDAV,$token)
329  {
330  global $ilDB;
331  $this->writelog('getLocks('.$objDAV.')');
332  $objId = $objDAV->getObjectId();
333  $nodeId = $objDAV->getNodeId();
334 
335  $q = 'SELECT ilias_owner, dav_owner, expires, depth, scope'
336  .' FROM '.$this->table
337  .' WHERE obj_id = '.$ilDB->quote($objId,'integer')
338  .' AND node_id = '.$ilDB->quote($nodeId,'integer')
339  .' AND token = '.$ilDB->quote($token,'text')
340  ;
341  $this->writelog('getLocks('.$objDAV.') query='.$q);
342  $r = $ilDB->query($q);
343 
344  $result = array();
345  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
346  {
347  if ($row['depth'] == -1) $row['depth'] = 'infinity';
348  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
349  $row['token'] = $token;
350  $result = $row;
351  }
352  return $result;
353  }
368  public function getLocksOnObjectDAV(&$objDAV)
369  {
370  $objId = $objDAV->getObjectId();
371  $nodeId = $objDAV->getNodeId();
372 
373  return $this->getLocksOnObjectObj($objId, $nodeId);
374  }
391  public function getLocksOnObjectObj($objId, $nodeId = 0)
392  {
393  global $ilDB;
394  $this->writelog('getLocks('.$objDAV.')');
395  $nodeId = 0;
396  $q = 'SELECT ilias_owner, dav_owner, token, expires, depth, scope'
397  .' FROM '.$this->table
398  .' WHERE obj_id = '.$ilDB->quote($objId,'integer')
399  .' AND node_id = '.$ilDB->quote($nodeId,'integer')
400  .' AND expires > '.$ilDB->quote(time(),'integer')
401  ;
402  $this->writelog('getLocks('.$objDAV.') query='.$q);
403  $r = $ilDB->query($q);
404 
405  $result = array();
406  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
407  {
408  if ($row['depth'] == -1) $row['depth'] = 'infinity';
409  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
410  $result[] = $row;
411  }
412  return $result;
413  }
429  public function getLocksOnPathDAV(&$pathDAV)
430  {
431  global $ilDB;
432  $this->writelog('getLocksOnPathDAV');
433 
434  $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
435  .' FROM '.$this->table
436  .' WHERE expires > '.$ilDB->quote(time(),'integer')
437  .' AND ('
438  ;
439  $isFirst = true;
440  foreach ($pathDAV as $objDAV)
441  {
442  $objId = $objDAV->getObjectId();
443  $nodeId = $objDAV->getNodeId();
444  if ($isFirst)
445  {
446  $isFirst = false;
447  } else {
448  $q .= ' OR ';
449  }
450  $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
451  }
452  $q .= ')';
453 
454  $this->writelog('getLocksOnPathDAV('.$objDAV.') query='.$q);
455  $r = $ilDB->query($q);
456 
457  $result = array();
458  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
459  {
460  if ($row['depth'] == -1) $row['depth'] = 'infinity';
461  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
462  $result[] = $row;
463  }
464  $this->writelog('getLocksOnPathDAV:'.var_export($result,true));
465  return $result;
466  }
482  public function getLocksOnPathRef($refId)
483  {
484  global $ilDB, $tree;
485  $this->writelog('getLocksOnPathRef('.$refId.')');
486 
487  $pathFull = $tree->getPathFull($refId);
488 
489  $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
490  .' FROM '.$this->table
491  .' WHERE expires > '.$ilDB->quote(time(),'integer')
492  .' AND ('
493  ;
494  $isFirst = true;
495  foreach ($pathFull as $pathItem)
496  {
497  $objId = $pathItem['obj_id'];
498  $nodeId = 0;
499  if ($isFirst)
500  {
501  $isFirst = false;
502  } else {
503  $q .= ' OR ';
504  }
505  $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
506  }
507  $q .= ')';
508 
509  $this->writelog('getLocksOnPathRef('.$refId.') query='.$q);
510  $r = $ilDB->query($q);
511 
512  $result = array();
513  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
514  {
515  if ($row['depth'] == -1) $row['depth'] = 'infinity';
516  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
517  $result[] = $row;
518  }
519  return $result;
520  }
526  public function cleanUp()
527  {
528  global $ilDB, $tree;
529 
530  // 1. Get rid of locks that have expired over an hour ago
531  $old = time() - 3600;
532  $q = 'DELETE'
533  .' FROM '.$this->table
534  .' WHERE expires < '.$ilDB->quote($old,'integer')
535  ;
536  $ilDB->manipulate($q);
537 
538  // 2. Get rid of null resources which are not associated to
539  // a lock due to step 1, or due to a database inconsistency
540  // because we are working with non-transactional tables
541  $q = 'SELECT dat.obj_id '
542  .' FROM object_data AS dat'
543  .' LEFT JOIN '.$this->table.' lck'
544  .' ON dat.obj_id = lck.obj_id'
545  .' WHERE dat.type = '.$ilDB->quote('null','text')
546  .' AND lck.obj_id IS NULL'
547  ;
548 /* TODO: smeyer.' FOR UPDATE' */
549 
550  $r = $ilDB->query($q);
551  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
552  {
553  $references = ilObject::_getAllReferences($row['obj_id']);
554  $obj = new ilObjNull($row['obj_id'], false);
555  if (count($references) == 0)
556  {
557  $obj->delete();
558  } else {
559  foreach ($references as $refId)
560  {
561  $obj->setRefId($refId);
562  $obj->delete();
563  $nodeData = $tree->getNodeData($refId);
564  $tree->deleteTree($nodeData);
565  }
566  }
567  }
568  }
575  protected function writelog($message)
576  {
577  global $log, $ilias;
578  if ($this->isDebug)
579  {
580  $log->write(
581  $ilias->account->getLogin()
582  .' DAV ilDAVLocks.'.str_replace("\n",";",$message)
583  );
584  }
585  /*
586  if ($this->logFile)
587  {
588  $fh = fopen($this->logFile, 'a');
589  fwrite($fh, date('Y-m-d h:i:s '));
590  fwrite($fh, str_replace("\n",";",$message));
591  fwrite($fh, "\n\n");
592  fclose($fh);
593  }*/
594  }
595 }
596 // END WebDAV
597 ?>