ILIAS  Release_4_0_x_branch Revision 61816
 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 
397  $q = 'SELECT ilias_owner, dav_owner, token, expires, depth, scope'
398  .' FROM '.$this->table
399  .' WHERE obj_id = '.$ilDB->quote($objId,'integer')
400  .' AND node_id = '.$ilDB->quote($nodeId,'integer')
401  .' AND expires > '.$ilDB->quote(time(),'integer')
402  ;
403  $this->writelog('getLocks('.$objDAV.') query='.$q);
404  $r = $ilDB->query($q);
405 
406  $result = array();
407  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
408  {
409  if ($row['depth'] == -1) $row['depth'] = 'infinity';
410  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
411  $result[] = $row;
412  }
413  return $result;
414  }
430  public function getLocksOnPathDAV(&$pathDAV)
431  {
432  global $ilDB;
433  $this->writelog('getLocksOnPathDAV');
434 
435  $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
436  .' FROM '.$this->table
437  .' WHERE expires > '.$ilDB->quote(time(),'integer')
438  .' AND ('
439  ;
440  $isFirst = true;
441  foreach ($pathDAV as $objDAV)
442  {
443  $objId = $objDAV->getObjectId();
444  $nodeId = $objDAV->getNodeId();
445  if ($isFirst)
446  {
447  $isFirst = false;
448  } else {
449  $q .= ' OR ';
450  }
451  $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
452  }
453  $q .= ')';
454 
455  $this->writelog('getLocksOnPathDAV('.$objDAV.') query='.$q);
456  $r = $ilDB->query($q);
457 
458  $result = array();
459  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
460  {
461  if ($row['depth'] == -1) $row['depth'] = 'infinity';
462  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
463  $result[] = $row;
464  }
465  $this->writelog('getLocksOnPathDAV:'.var_export($result,true));
466  return $result;
467  }
483  public function getLocksOnPathRef($refId)
484  {
485  global $ilDB, $tree;
486  $this->writelog('getLocksOnPathRef('.$refId.')');
487 
488  $pathFull = $tree->getPathFull($refId);
489 
490  $q = 'SELECT obj_id, node_id, ilias_owner, dav_owner, token, expires, depth, scope'
491  .' FROM '.$this->table
492  .' WHERE expires > '.$ilDB->quote(time(),'integer')
493  .' AND ('
494  ;
495  $isFirst = true;
496  foreach ($pathFull as $pathItem)
497  {
498  $objId = $pathItem['obj_id'];
499  $nodeId = 0;
500  if ($isFirst)
501  {
502  $isFirst = false;
503  } else {
504  $q .= ' OR ';
505  }
506  $q .= '(obj_id = '.$ilDB->quote($objId,'integer').' AND node_id = '.$ilDB->quote($nodeId,'integer').')';
507  }
508  $q .= ')';
509 
510  $this->writelog('getLocksOnPathRef('.$refId.') query='.$q);
511  $r = $ilDB->query($q);
512 
513  $result = array();
514  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
515  {
516  if ($row['depth'] == -1) $row['depth'] = 'infinity';
517  $row['scope'] = ($row['scope'] == 'x') ? 'exclusive' : 'shared';
518  $result[] = $row;
519  }
520  return $result;
521  }
527  public function cleanUp()
528  {
529  global $ilDB, $tree;
530 
531  // 1. Get rid of locks that have expired over an hour ago
532  $old = time() - 3600;
533  $q = 'DELETE'
534  .' FROM '.$this->table
535  .' WHERE expires < '.$ilDB->quote($old,'integer')
536  ;
537  $ilDB->manipulate($q);
538 
539  // 2. Get rid of null resources which are not associated to
540  // a lock due to step 1, or due to a database inconsistency
541  // because we are working with non-transactional tables
542  $q = 'SELECT dat.obj_id '
543  .' FROM object_data AS dat'
544  .' LEFT JOIN '.$this->table.' lck'
545  .' ON dat.obj_id = lck.obj_id'
546  .' WHERE dat.type = '.$ilDB->quote('null','text')
547  .' AND lck.obj_id IS NULL'
548  ;
549 /* TODO: smeyer.' FOR UPDATE' */
550 
551  $r = $ilDB->query($q);
552  while ($row = $r->fetchRow(DB_FETCHMODE_ASSOC))
553  {
554  $references = ilObject::_getAllReferences($row['obj_id']);
555  $obj =& new ilObjNull($row['obj_id'], false);
556  if (count($references) == 0)
557  {
558  $obj->delete();
559  } else {
560  foreach ($references as $refId)
561  {
562  $obj->setRefId($refId);
563  $obj->delete();
564  $nodeData = $tree->getNodeData($refId);
565  $tree->deleteTree($nodeData);
566  }
567  }
568  }
569  }
576  protected function writelog($message)
577  {
578  global $log, $ilias;
579  if ($this->isDebug)
580  {
581  $log->write(
582  $ilias->account->getLogin()
583  .' DAV ilDAVLocks.'.str_replace("\n",";",$message)
584  );
585  }
586  /*
587  if ($this->logFile)
588  {
589  $fh = fopen($this->logFile, 'a');
590  fwrite($fh, date('Y-m-d h:i:s '));
591  fwrite($fh, str_replace("\n",";",$message));
592  fwrite($fh, "\n\n");
593  fclose($fh);
594  }*/
595  }
596 }
597 // END WebDAV
598 ?>