ILIAS  Release_3_10_x_branch Revision 61812
 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)
218  .', node_id = '.$ilDB->quote($nodeId)
219  .', ilias_owner = '.$ilDB->quote($iliasUserId)
220  .', dav_owner = '.$ilDB->quote($davUser)
221  .', token = '.$ilDB->quote($token)
222  .', expires = '.$ilDB->quote($expires)
223  .', depth = '.$ilDB->quote($depth)
224  .', type = \'w\''
225  .', scope = '.$ilDB->quote($scope)
226  ;
227  $this->writelog('lock query='.$q);
228  $result = $ilDB->query($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)
267  .' WHERE token = '.$ilDB->quote($token)
268  .' AND obj_id = '.$ilDB->quote($objId)
269  .' AND node_id = '.$ilDB->quote($nodeId)
270  ;
271  $ilDB->query($q);
272  return mysql_affected_rows() > 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)
298  .' AND obj_id = '.$ilDB->quote($objId)
299  .' AND node_id = '.$ilDB->quote($nodeId)
300  ;
301  $this->writelog('unlock query='.$q);
302  $ilDB->query($q);
303  $success = mysql_affected_rows() > 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)
338  .' AND node_id = '.$ilDB->quote($nodeId)
339  .' AND token = '.$ilDB->quote($token)
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)
400  .' AND node_id = '.$ilDB->quote($nodeId)
401  .' AND expires > '.$ilDB->quote(time())
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('getLocksOnPath('.$pathDAV.')');
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())
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 = '.$objId.' AND node_id = '.$nodeId.')';
452  }
453  $q .= ')';
454 
455  $this->writelog('getLocksOnPath('.$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  return $result;
466  }
482  public function getLocksOnPathRef($refId)
483  {
484  global $ilDB, $tree;
485  $this->writelog('getLocksOnPathForRefId('.$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())
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 = '.$objId.' AND node_id = '.$nodeId.')';
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)
535  ;
536  $ilDB->query($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.' AS lck'
544  .' ON dat.obj_id = lck.obj_id'
545  .' WHERE dat.type = \'null\''
546  .' AND lck.obj_id IS NULL'
547  .' FOR UPDATE'
548  ;
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 ?>