ILIAS  release_5-0 Revision 5.0.0-1144-gc4397b1f870
class.ilDAVServer.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
25require_once "Services/WebDAV/classes/Server.php";
26require_once "Services/WebDAV/classes/class.ilDAVLocks.php";
27require_once "Services/WebDAV/classes/class.ilDAVProperties.php";
28require_once 'Services/WebDAV/classes/class.ilObjectDAV.php';
29
30require_once "Services/User/classes/class.ilObjUser.php";
31require_once('include/Unicode/UtfNormal.php');
32require_once('Services/Tracking/classes/class.ilChangeEvent.php');
33
51{
56 private static $instance = null;
57
63
67 private $locks;
71 private $properties;
72
78 private $clientOS = 'unknown';
83 private $clientOSFlavor = 'unknown';
88 private $clientBrowser = 'unknown';
89
100 private $putObjDAV = null;
101
108 private $isHTTPS = null;
109
114 private $isDebug = false;
115
125 public function ilDAVServer()
126 {
127 $this->writelog("<constructor>");
128
129 // Initialize the WebDAV server and create
130 // locking and property support objects
131 $this->HTTP_WebDAV_Server();
132 $this->locks = new ilDAVLocks();
133 $this->properties = new ilDAVProperties();
134 //$this->locks->createTable();
135 //$this->properties->createTable();
136
137 // Guess operating system, operating system flavor and browser of the webdav client
138 //
139 // - We need to know the operating system in order to properly
140 // hide hidden resources in directory listings.
141 //
142 // - We need the operating system flavor and the browser to
143 // properly support mounting of a webdav folder.
144 //
145 $userAgent = strtolower($_SERVER['HTTP_USER_AGENT']);
146 $this->writelog('userAgent='.$userAgent);
147 if (strpos($userAgent,'windows') !== false
148 || strpos($userAgent,'microsoft') !== false)
149 {
150 $this->clientOS = 'windows';
151 if(strpos($userAgent,'nt 5.1') !== false){
152 $this->clientOSFlavor = 'xp';
153 }else{
154 $this->clientOSFlavor = 'nichtxp';
155 }
156
157 } else if (strpos($userAgent,'darwin') !== false
158 || strpos($userAgent,'macintosh') !== false
159 || strpos($userAgent,'linux') !== false
160 || strpos($userAgent,'solaris') !== false
161 || strpos($userAgent,'aix') !== false
162 || strpos($userAgent,'unix') !== false
163 || strpos($userAgent,'gvfs') !== false // nautilus browser uses this ID
164 )
165 {
166 $this->clientOS = 'unix';
167 if (strpos($userAgent,'linux') !== false)
168 {
169 $this->clientOSFlavor = 'linux';
170 }
171 else if (strpos($userAgent,'macintosh') !== false)
172 {
173 $this->clientOSFlavor = 'osx';
174 }
175 }
176 if (strpos($userAgent,'konqueror') !== false)
177 {
178 $this->clientBrowser = 'konqueror';
179 }
180 }
181
186 public static function getInstance()
187 {
188 if(self::$instance != NULL)
189 {
190 return self::$instance;
191 }
192 return self::$instance = new ilDAVServer();
193 }
194
198 public function serveRequest()
199 {
200 // die quickly if plugin is deactivated
201 if (!self::_isActive())
202 {
203 $this->writelog(__METHOD__.' WebDAV disabled. Aborting');
204 $this->http_status('403 Forbidden');
205 echo '<html><body><h1>Sorry</h1>'.
206 '<p><b>Please enable the WebDAV plugin in the ILIAS Administration panel.</b></p>'.
207 '<p>You can only access this page, if WebDAV is enabled on this server.</p>'.
208 '</body></html>';
209 return;
210 }
211
212 try {
213 $start = time();
214 $this->writelog('serveRequest():'.$_SERVER['REQUEST_METHOD'].' '.$_SERVER['PATH_INFO'].' ...');
215 parent::serveRequest();
216 $end = time();
217 $this->writelog('serveRequest():'.$_SERVER['REQUEST_METHOD'].' done status='.$this->_http_status.' elapsed='.($end - $start));
218 $this->writelog('---');
219 }
220 catch (Exception $e)
221 {
222 $this->writelog('serveRequest():'.$_SERVER['REQUEST_METHOD'].' caught exception: '.$e->getMessage().'\n'.$e->getTraceAsString());
223 }
224 }
225
260 private function davUrlEncode($path)
261 {
262 // We compose the path to Unicode Normal Form NFC
263 // This ensures that diaeresis and other special characters
264 // are treated uniformly on Windows and on Mac OS X
266
267 $c = explode('/',$path);
268 for ($i = 0; $i < count($c); $i++)
269 {
270 $c[$i] = str_replace('+','%20',urlencode($c[$i]));
271 }
272 return implode('/',$c);
273 }
274
282 public function PROPFIND(&$options, &$files)
283 {
284 // Activate tree cache
285 global $tree;
286 //$tree->useCache(true);
287
288 $this->writelog('PROPFIND(options:'.var_export($options, true).' files:'.var_export($files, true).'.)');
289 $this->writelog('PROPFIND '.$options['path']);
290
291 // get dav object for path
292 $path =& $this->davDeslashify($options['path']);
293 $objDAV =& $this->getObject($path);
294
295 // prepare property array
296 $files['files'] = array();
297
298 // sanity check
299 if (is_null($objDAV)) {
300 return false;
301 }
302 if (! $objDAV->isPermitted('visible,read')) {
303 return '403 Forbidden';
304 }
305
306 // store information for the requested path itself
307 // FIXME : create display name for object.
308 $encodedPath = $this->davUrlEncode($path);
309
310 $GLOBALS['ilLog']->write(print_r($encodedPath,true));
311
312 $files['files'][] =& $this->fileinfo($encodedPath, $encodedPath, $objDAV);
313
314 // information for contained resources requested?
315 if (!empty($options['depth'])) {
316 // The breadthFirst list holds the collections which we have not
317 // processed yet. If depth is infinity we append unprocessed collections
318 // to the end of this list, and remove processed collections from
319 // the beginning of this list.
320 $breadthFirst = array($objDAV);
321 $objDAV->encodedPath = $encodedPath;
322
323 while (count($breadthFirst) > 0) {
324 // remove a collection from the beginning of the breadthFirst list
325 $collectionDAV = array_shift($breadthFirst);
326 $childrenDAV =& $collectionDAV->childrenWithPermission('visible,read');
327 foreach ($childrenDAV as $childDAV)
328 {
329 // On duplicate names, work with the older object (the one with the
330 // smaller object id).
331 foreach ($childrenDAV as $duplChildDAV)
332 {
333 if ($duplChildDAV->getObjectId() < $childDAV->getObjectId() &&
334 $duplChildDAV->getResourceName() == $childDAV->getResourceName())
335 {
336 continue 2;
337 }
338 }
339
340 // only add visible objects to the file list
341 if (!$this->isFileHidden($childDAV))
342 {
343 $this->writelog('PROPFIND() child ref_id='.$childDAV->getRefId());
344 $files['files'][] =& $this->fileinfo(
345 $collectionDAV->encodedPath.'/'.$this->davUrlEncode($childDAV->getResourceName()),
346 $collectionDAV->encodedPath.'/'.$this->davUrlEncode($childDAV->getDisplayName()),
347 $childDAV
348 );
349 if ($options['depth']=='infinity' && $childDAV->isCollection()) {
350 // add a collection to the end of the breadthFirst list
351 $breadthFirst[] = $childDAV;
352 $childDAV->encodedPath = $collectionDAV->encodedPath.'/'.$this->davUrlEncode($childDAV->getResourceName());
353 }
354 }
355 }
356 }
357 }
358
359 // Record read event but don't catch up with write events, because
360 // with WebDAV, a user can not see all objects contained in a folder.
361 global $ilUser;
362 ilChangeEvent::_recordReadEvent($objDAV->getILIASType(), $objDAV->getRefId(),
363 $objDAV->getObjectId(), $ilUser->getId(), false);
364
365 // ok, all done
366 $this->writelog('PROPFIND():true options='.var_export($options, true).' files='.var_export($files,true));
367 return true;
368 }
369
380 private function isFileHidden(&$objDAV)
381 {
382 // Hide null resources which haven't got an active lock
383 if ($objDAV->isNullResource()) {
384 if (count($this->locks->getLocksOnObjectDAV($objDAV)) == 0) {
385 return;
386 }
387 }
388
389 $name = $objDAV->getResourceName();
390 $isFileHidden = false;
391 switch ($this->clientOS)
392 {
393 case 'unix' :
394 // Hide Windows thumbnail files, and files which start with '~$'.
395 $isFileHidden =
396 $name == 'Thumbs.db'
397 || substr($name, 0, 2) == '~$';
398 // Hide files which contain /
399 $isFileHidden |= preg_match('/\\//', $name);
400 break;
401 case 'windows' :
402 // Hide files that start with '.'.
403 $isFileHidden = substr($name, 0, 1) == '.';
404 // Hide files which contain \ / : * ? " < > |
405 $isFileHidden |= preg_match('/\\\\|\\/|:|\\*|\\?|"|<|>|\\|/', $name);
406 break;
407 default :
408 // Hide files which contain /
409 $isFileHidden |= preg_match('/\\//', $name);
410 break;
411 }
412 $this->writelog($this->clientOS.' '.$name.' isHidden:'.$isFileHidden.' clientOS:'.$this->clientOS);
413 return $isFileHidden;
414 }
415
423 private function fileinfo($resourcePath, $displayPath, &$objDAV)
424 {
425 global $ilias;
426
427 $this->writelog('fileinfo('.$resourcePath.')');
428 // create result array
429 $info = array();
430 /* Some clients, for example WebDAV-Sync, need a trailing slash at the
431 * end of a resource path to a collection.
432 * However Mac OS X does not like this!
433 */
434 if ($objDAV->isCollection() && $this->clientOSFlavor != 'osx') {
435 $info['path'] = $resourcePath.'/';
436 } else {
437 $info['path'] = $resourcePath;
438 }
439
440 $info['props'] = array();
441
442 // no special beautified displayname here ...
443 $info["props"][] =& $this->mkprop("displayname", $displayPath);
444
445 // creation and modification time
446 $info["props"][] =& $this->mkprop("creationdate", $objDAV->getCreationTimestamp());
447 $info["props"][] =& $this->mkprop("getlastmodified", $objDAV->getModificationTimestamp());
448
449 // directory (WebDAV collection)
450 $info["props"][] =& $this->mkprop("resourcetype", $objDAV->getResourceType());
451 $info["props"][] =& $this->mkprop("getcontenttype", $objDAV->getContentType());
452 $info["props"][] =& $this->mkprop("getcontentlength", $objDAV->getContentLength());
453
454 // Only show supported locks for users who have write permission
455 if ($objDAV->isPermitted('write'))
456 {
457 $info["props"][] =& $this->mkprop("supportedlock",
458 '<D:lockentry>'
459 .'<D:lockscope><D:exclusive/></D:lockscope>'
460 .'<D:locktype><D:write/></D:locktype>'
461 .'</D:lockentry>'
462 .'<D:lockentry>'
463 .'<D:lockscope><D:shared/></D:lockscope>'
464 .'<D:locktype><D:write/></D:locktype>'
465 .'</D:lockentry>'
466 );
467 }
468
469 // Maybe we should only show locks on objects for users who have write permission.
470 // But if we don't show these locks, users who have write permission in an object
471 // further down in a hierarchy can't see who is locking their object.
472 $locks = $this->locks->getLocksOnObjectDAV($objDAV);
473 $lockdiscovery = '';
474 foreach ($locks as $lock)
475 {
476 // DAV Clients expects to see their own owner name in
477 // the locks. Since these names are not unique (they may
478 // just be the name of the local user running the DAV client)
479 // we return the ILIAS user name in all other cases.
480 if ($lock['ilias_owner'] == $ilias->account->getId())
481 {
482 $owner = $lock['dav_owner'];
483 } else {
484 $owner = '<D:href>'.$this->getLogin($lock['ilias_owner']).'</D:href>';
485 }
486 $this->writelog('lockowner='.$owner.' ibi:'.$lock['ilias_owner'].' davi:'.$lock['dav_owner']);
487
488 $lockdiscovery .=
489 '<D:activelock>'
490 .'<D:lockscope><D:'.$lock['scope'].'/></D:lockscope>'
491 //.'<D:locktype><D:'.$lock['type'].'/></D:locktype>'
492 .'<D:locktype><D:write/></D:locktype>'
493 .'<D:depth>'.$lock['depth'].'</D:depth>'
494 .'<D:owner>'.$owner.'</D:owner>'
495
496 // more than a million is considered an absolute timestamp
497 // less is more likely a relative value
498 .'<D:timeout>Second-'.(($lock['expires'] > 1000000) ? $lock['expires']-time():$lock['expires']).'</D:timeout>'
499 .'<D:locktoken><D:href>'.$lock['token'].'</D:href></D:locktoken>'
500 .'</D:activelock>'
501 ;
502 }
503 if (strlen($lockdiscovery) > 0)
504 {
505 $info["props"][] =& $this->mkprop("lockdiscovery", $lockdiscovery);
506 }
507
508 // get additional properties from database
509 $properties = $this->properties->getAll($objDAV);
510 foreach ($properties as $prop)
511 {
512 $info["props"][] = $this->mkprop($prop['namespace'], $prop['name'], $prop['value']);
513 }
514
515 //$this->writelog('fileinfo():'.var_export($info, true));
516 return $info;
517 }
518
530 public function GET(&$options)
531 {
532 global $ilUser;
533
534 $this->writelog('GET('.var_export($options, true).')');
535 $this->writelog('GET('.$options['path'].')');
536
537 // get dav object for path
538 $path = $this->davDeslashify($options['path']);
539 $objDAV =& $this->getObject($path);
540
541 // sanity check
542 if (is_null($objDAV) || $objDAV->isNullResource())
543 {
544 return false;
545 }
546
547 if (! $objDAV->isPermitted('visible,read'))
548 {
549 return '403 Forbidden';
550 }
551
552 // is this a collection?
553 if ($objDAV->isCollection())
554 {
555 if (isset($_GET['mount']))
556 {
557 return $this->mountDir($objDAV, $options);
558 }
559 else if (isset($_GET['mount-instructions']))
560 {
561 return $this->showMountInstructions($objDAV, $options);
562 }
563 else
564 {
565 return $this->getDir($objDAV, $options);
566 }
567 }
568 // detect content type
569 $options['mimetype'] =& $objDAV->getContentType();
570 // detect modification time
571 // see rfc2518, section 13.7
572 // some clients seem to treat this as a reverse rule
573 // requiring a Last-Modified header if the getlastmodified header was set
574 $options['mtime'] =& $objDAV->getModificationTimestamp();
575
576 // detect content length
577 $options['size'] =& $objDAV->getContentLength();
578
579 // get content as stream or as data array
580 $options['stream'] =& $objDAV->getContentStream();
581 if (is_null($options['stream']))
582 {
583 $options['data'] =& $objDAV->getContentData();
584 }
585
586 // Record read event and catch up write events
587 ilChangeEvent::_recordReadEvent($objDAV->getILIASType(), $objDAV->getRefId(),
588 $objDAV->getObjectId(), $ilUser->getId());
589
590 $this->writelog('GET:'.var_export($options, true));
591
592 return true;
593 }
605 private function mountDir(&$objDAV, &$options)
606 {
607 $path = $this->davDeslashify($options['path']);
608
609 header('Content-Type: application/davmount+xml');
610
611 echo "<dm:mount xmlns:dm=\"http://purl.org/NET/webdav/mount\">\n";
612 echo " </dm:url>".$this->base_uri."</dm:url>\n";
613
614 $xmlPath = str_replace('&','&amp;',$path);
615 $xmlPath = str_replace('<','&lt;',$xmlPath);
616 $xmlPath = str_replace('>','&gt;',$xmlPath);
617
618 echo " </dm:open>$xmlPath</dm:open>\n";
619 echo "</dm:mount>\n";
620
621 exit;
622
623 }
630 private function showMountInstructions(&$objDAV, &$options)
631 {
632 global $lng,$ilUser;
633
634 $path = $this->davDeslashify($options['path']);
635
636 // The $path variable may contain a full or a shortened DAV path.
637 // We convert it into an object path, which we can then use to
638 // construct a new full DAV path.
639 $objectPath = $this->toObjectPath($path);
640
641 // Construct a (possibly) full DAV path from the object path.
642 $fullPath = '';
643 foreach ($objectPath as $object)
644 {
645 if ($object->getRefId() == 1 && $this->isFileHidden($object))
646 {
647 // If the repository root object is hidden, we can not
648 // create a full path, because nothing would appear in the
649 // webfolder. We resort to a shortened path instead.
650 $fullPath .= '/ref_1';
651 }
652 else
653 {
654 $fullPath .= '/'.$this->davUrlEncode($object->getResourceName());
655 }
656 }
657
658 // Construct a shortened DAV path from the object path.
659 $shortenedPath = '/ref_'.
660 $objectPath[count($objectPath) - 1]->getRefId();
661
662 if ($objDAV->isCollection())
663 {
664 $shortenedPath .= '/';
665 $fullPath .= '/';
666 }
667
668 // Prepend client id to path
669 $shortenedPath = '/'.CLIENT_ID.$shortenedPath;
670 $fullPath = '/'.CLIENT_ID.$fullPath;
671
672 // Construct webfolder URI's. The URI's are used for mounting the
673 // webfolder. Since mounting using URI's is not standardized, we have
674 // to create different URI's for different browsers.
675 $webfolderURI = $this->base_uri.$shortenedPath;
676 $webfolderURI_Konqueror = ($this->isWebDAVoverHTTPS() ? "webdavs" : "webdav").
677 substr($this->base_uri, strrpos($this->base_uri,':')).
678 $shortenedPath;
679 ;
680 $webfolderURI_Nautilus = ($this->isWebDAVoverHTTPS() ? "davs" : "dav").
681 substr($this->base_uri, strrpos($this->base_uri,':')).
682 $shortenedPath
683 ;
684 $webfolderURI_IE = $this->base_uri.$shortenedPath;
685
686 $webfolderTitle = $objectPath[count($objectPath) - 1]->getResourceName();
687
688 header('Content-Type: text/html; charset=UTF-8');
689 echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
690 echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN\"\n";
691 echo " \"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd\">\n";
692 echo "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
693 echo " <head>\n";
694 echo " <title>".sprintf($lng->txt('webfolder_instructions_titletext'), $webfolderTitle)."</title>\n";
695 echo " </head>\n";
696 echo " <body>\n";
697
699 $webfolderURI, $webfolderURI_IE, $webfolderURI_Konqueror, $webfolderURI_Nautilus,
700 $this->clientOS,$this->clientOSFlavor);
701
702 echo " </body>\n";
703 echo "</html>\n";
704
705 // Logout anonymous user to force authentication after calling mount uri
706 if($ilUser->getId() == ANONYMOUS_USER_ID)
707 {
708 $GLOBALS['ilAuth']->logout();
709 session_destroy();
710 }
711
712 exit;
713 }
723 private function getDir(&$objDAV, &$options)
724 {
725 global $ilias, $lng;
726
727 // Activate tree cache
728 global $tree;
729 //$tree->useCache(true);
730
731 $path = $this->davDeslashify($options['path']);
732
733 // The URL of a directory must end with a slash.
734 // If it does not we are redirecting the browser.
735 // The slash is required, because we are using relative links in the
736 // HTML code we are generating below.
737 if ($path.'/' != $options['path'])
738 {
739 header('Location: '.$this->base_uri.$path.'/');
740 exit;
741 }
742
743 header('Content-Type: text/html; charset=UTF-8');
744
745 // fixed width directory column format
746 $format = "%15s %-19s %-s\n";
747
748 echo "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
749 echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1 plus MathML 2.0 plus SVG 1.1//EN\"\n";
750 echo " \"http://www.w3.org/2002/04/xhtml-math-svg/xhtml-math-svg.dtd\">\n";
751 echo "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n";
752 echo "<head>\n";
753 echo "<title>".sprintf($lng->txt('webfolder_index_of'), $path)."</title>\n";
754
755 // Create "anchorClick" behavior for for Internet Explorer
756 // This allows to create a link to a webfolder
757 echo "<style type=\"text/css\">\n";
758 echo "<!--\n";
759 echo "a {\n";
760 echo " behavior:url(#default#AnchorClick);\n";
761 echo "}\n";
762 echo "-->\n";
763 echo "</style>\n";
764
765 echo "</head><body>\n";
766
767 $hrefPath = '';
768 $pathComponents = explode('/',$path);
769 $uriComponents = array();
770 foreach ($pathComponents as $component)
771 {
772 $uriComponents[] = $this->davUrlEncode($component);
773 }
774 for ($i = 0; $i < count($pathComponents); $i++)
775 {
776 $displayName = htmlspecialchars($pathComponents[$i]);
777 if ($i != 0) {
778 $hrefPath .= '/';
779 }
780 $uriPath = implode('/', array_slice($uriComponents,0,$i + 1));
781 if ($i < 2)
782 {
783 // The first two path elements consist of the webdav.php script
784 // and the client id. These elements are not part of the
785 // directory structure and thus are not represented as links.
786 $hrefPath .= $displayName;
787 }
788 else
789 {
790 $hrefPath .= '<a href="'.$this->base_uri.$uriPath.'/">'.$displayName.'</a>';
791 }
792 }
793 echo "<h3>".sprintf($lng->txt('webfolder_index_of'), $hrefPath)."</h3>\n";
794
795 // Display user id
796 if ($ilias->account->getLogin() == 'anonymous')
797 {
798 echo "<p><font size=\"-1\">".$lng->txt('not_logged_in')."</font><br>\n";
799 } else {
800 echo "<p><font size=\"-1\">".$lng->txt('login_as')." <i>"
801 .$ilias->account->getFirstname().' '
802 .$ilias->account->getLastname().' '
803 .' '.$ilias->account->getLogin().'</i> '
804 .', '.$lng->txt('client').' <i>'.$ilias->getClientId().'</i>.'
805 ."</font><p>\n";
806 }
807
808 // Create "open as webfolder" link
809 $href = $this->base_uri.$uriPath;
810 // IE can not mount long paths. If the path has more than one element, we
811 // create a relative path with a ref-id.
812 if (count($pathComponents) > 2)
813 {
814 $hrefIE = $this->base_uri.'/'.CLIENT_ID.'/ref_'.$objDAV->getRefId();
815 } else {
816 $hrefIE = $href;
817 }
818 echo "<p><font size=\"-1\">".
819 sprintf($lng->txt('webfolder_dir_info'), "$href?mount-instructions").
820 "</font></p>\n";
821 echo "<p><font size=\"-1\">".
822 sprintf($lng->txt('webfolder_mount_dir_with'),
823 "$hrefIE\" folder=\"$hrefIE", // Internet Explorer
824 'webdav'.substr($href,4), // Konqueror
825 'dav'.substr($href,4), // Nautilus
826 $href.'?mount' // RFC 4709
827 )
828 ."</font></p>\n";
829
830 echo "<pre>";
831 printf($format, $lng->txt('size'), $lng->txt('last_change'), $lng->txt('filename'));
832 echo "<hr>";
833
834 $collectionCount = 0;
835 $fileCount = 0;
836 $children =& $objDAV->childrenWithPermission('visible,read');
837 foreach ($children as $childDAV) {
838 if ($childDAV->isCollection() && !$this->isFileHidden($childDAV))
839 {
840 $collectionCount++;
841 $name = $this->davUrlEncode($childDAV->getResourceName());
842 printf($format,
843 '-',
844 strftime("%Y-%m-%d %H:%M:%S", $childDAV->getModificationTimestamp()),
845 '<a href="'.$name.'/'.'">'.$childDAV->getDisplayName()."</a>");
846 }
847 }
848 foreach ($children as $childDAV) {
849 if ($childDAV->isFile() && !$this->isFileHidden($childDAV))
850 {
851 $fileCount++;
852 $name = $this->davUrlEncode($childDAV->getResourceName());
853 printf($format,
854 number_format($childDAV->getContentLength()),
855 strftime("%Y-%m-%d %H:%M:%S", $childDAV->getModificationTimestamp()),
856 '<a href="'.$name.'">'.$childDAV->getDisplayName()."</a>");
857 }
858 }
859 foreach ($children as $childDAV) {
860 if ($childDAV->isNullResource() && !$this->isFileHidden($childDAV))
861 {
862 $name = $this->davUrlEncode($childDAV->getResourceName());
863 printf($format,
864 'Lock',
865 strftime("%Y-%m-%d %H:%M:%S", $childDAV->getModificationTimestamp()),
866 '<a href="'.$name.'">'.$childDAV->getDisplayName()."</a>");
867 }
868 }
869 echo "<hr>";
870 echo $collectionCount.' '.$lng->txt(($collectionCount == 1) ? 'folder' : 'folders').', ';
871 echo $fileCount.' '.$lng->txt(($fileCount == 1) ? 'file' : 'files').'.';
872 echo "</pre>";
873 echo "</body></html>\n";
874
875 exit;
876 }
877
878
885 public function PUT(&$options)
886 {
887 global $ilUser;
888
889 $this->writelog('PUT('.var_export($options, true).')');
890
891 $path = $this->davDeslashify($options['path']);
892 $parent = dirname($path);
893 $name = $this->davBasename($path);
894
895 // get dav object for path
896 $parentDAV =& $this->getObject($parent);
897
898 // sanity check
899 if (is_null($parentDAV) || ! $parentDAV->isCollection()) {
900 return '409 Conflict';
901 }
902
903 // Prevent putting of files which exceed upload limit
904 // FIXME: since this is an optional parameter, we should to do the
905 // same check again in function PUTfinished.
906 if ($options['content_length'] != null &&
907 $options['content_length'] > $this->getUploadMaxFilesize()) {
908
909 $this->writelog('PUT is forbidden, because content length='.
910 $options['content_length'].' is larger than upload_max_filesize='.
911 $this->getUploadMaxFilesize().'in php.ini');
912
913 return '403 Forbidden';
914 }
915
916 // determine mime type
917 include_once("./Services/Utilities/classes/class.ilMimeTypeUtil.php");
918 $mime = ilMimeTypeUtil::lookupMimeType($name);
919
920 $objDAV =& $this->getObject($path);
921 if (is_null($objDAV))
922 {
923 $ttype = $parentDAV->getILIASFileType();
924 $isperm = $parentDAV->isPermitted('create', $ttype);
925 if (! $isperm)
926 {
927 $this->writelog('PUT is forbidden, because user has no create permission');
928
929 return '403 Forbidden';
930 }
931 $options["new"] = true;
932 $objDAV =& $parentDAV->createFile($name);
933 $this->writelog('PUT obj='.$objDAV.' name='.$name.' content_type='.$options['content_type']);
934 //$objDAV->setContentType($options['content_type']);
935 $objDAV->setContentType($mime);
936 if ($options['content_length'] != null)
937 {
938 $objDAV->setContentLength($options['content_length']);
939 }
940 $objDAV->write();
941 // Record write event
942 ilChangeEvent::_recordWriteEvent($objDAV->getObjectId(), $ilUser->getId(), 'create', $parentDAV->getObjectId());
943 }
944 else if ($objDAV->isNullResource())
945 {
946 if (! $parentDAV->isPermitted('create', $parentDAV->getILIASFileType()))
947 {
948 $this->writelog('PUT is forbidden, because user has no create permission');
949 return '403 Forbidden';
950 }
951 $options["new"] = false;
952 $objDAV =& $parentDAV->createFileFromNull($name, $objDAV);
953 $this->writelog('PUT obj='.$objDAV.' name='.$name.' content_type='.$options['content_type']);
954 //$objDAV->setContentType($options['content_type']);
955 $objDAV->setContentType($mime);
956 if ($options['content_length'] != null)
957 {
958 $objDAV->setContentLength($options['content_length']);
959 }
960 $objDAV->write();
961
962 // Record write event
963 ilChangeEvent::_recordWriteEvent($objDAV->getObjectId(), $ilUser->getId(), 'create', $parentDAV->getObjectId());
964 }
965 else
966 {
967 if (! $objDAV->isPermitted('write'))
968 {
969 $this->writelog('PUT is forbidden, because user has no write permission');
970 return '403 Forbidden';
971 }
972 $options["new"] = false;
973 $this->writelog('PUT obj='.$objDAV.' name='.$name.' content_type='.$options['content_type'].' content_length='.$options['content_length']);
974
975 // Create a new version if the previous version is not empty
976 if ($objDAV->getContentLength() != 0) {
977 $objDAV->createNewVersion();
978 }
979
980 //$objDAV->setContentType($options['content_type']);
981 $objDAV->setContentType($mime);
982 if ($options['content_length'] != null)
983 {
984 $objDAV->setContentLength($options['content_length']);
985 }
986 $objDAV->write();
987
988 // Record write event
989 ilChangeEvent::_recordWriteEvent($objDAV->getObjectId(), $ilUser->getId(), 'update');
990 ilChangeEvent::_catchupWriteEvents($objDAV->getObjectId(), $ilUser->getId(), 'update');
991 }
992 // store this object, we reuse it in method PUTfinished
993 $this->putObjDAV = $objDAV;
994
995 $out =& $objDAV->getContentOutputStream();
996 $this->writelog('PUT outputstream='.$out);
997
998 return $out;
999 }
1000
1007 public function PUTfinished(&$options)
1008 {
1009 $this->writelog('PUTfinished('.var_export($options, true).')');
1010
1011 if($this->putObjDAV->getResourceType()==""){
1012 $vir = ilUtil::virusHandling($this->putObjDAV->obj->getDirectory($this->putObjDAV->obj->version).'/'.$this->putObjDAV->obj->filename, $this->putObjDAV->obj->filename);
1013 if ($vir[0] == false)
1014 {
1015 $this->writelog('PUTfinished Virus found: '.$vir[1]);
1016 //delete file
1018 return false;
1019 }
1020 }
1021
1022 // Update the content length in the file object, if the
1023 // the client did not specify a content_length
1024 if ($options['content_length'] == null || $this->putObjDAV->getContentLength() == 0)
1025 {
1026 $objDAV = $this->putObjDAV;
1027 if ($objDAV->getContentOutputStreamLength() != null) {
1028 $objDAV->setContentLength($objDAV->getContentOutputStreamLength());
1029 } else {
1030 $objDAV->write();
1031 $objDAV->setContentLength(filesize($objDAV->obj->getDirectory($objDAV->obj->version).'/'.$objDAV->obj->filename));
1032 }
1033 $objDAV->write();
1034 $this->putObjDAV = null;
1035 }
1036 return true;
1037 }
1038
1039
1046 public function MKCOL($options)
1047 {
1048 global $ilUser;
1049
1050 $this->writelog('MKCOL('.var_export($options, true).')');
1051 $this->writelog('MKCOL '.$options['path']);
1052
1053 $path =& $this->davDeslashify($options['path']);
1054 $parent =& dirname($path);
1055 $name =& $this->davBasename($path);
1056
1057 // No body parsing yet
1058 if(!empty($_SERVER["CONTENT_LENGTH"])) {
1059 return "415 Unsupported media type";
1060 }
1061
1062 // Check if an object with the path already exists.
1063 $objDAV =& $this->getObject($path);
1064 if (! is_null($objDAV))
1065 {
1066 return '405 Method not allowed';
1067 }
1068
1069 // get parent dav object for path
1070 $parentDAV =& $this->getObject($parent);
1071
1072 // sanity check
1073 if (is_null($parentDAV) || ! $parentDAV->isCollection())
1074 {
1075 return '409 Conflict';
1076 }
1077
1078 if (! $parentDAV->isPermitted('create',$parentDAV->getILIASCollectionType()))
1079 {
1080 return '403 Forbidden';
1081 }
1082
1083 // XXX Implement code that Handles null resource here
1084
1085 $objDAV = $parentDAV->createCollection($name);
1086
1087 if ($objDAV != null)
1088 {
1089 // Record write event
1090 ilChangeEvent::_recordWriteEvent((int) $objDAV->getObjectId(), $ilUser->getId(), 'create', $parentDAV->getObjectId());
1091 }
1092
1093 $result = ($objDAV != null) ? "201 Created" : "409 Conflict";
1094 return $result;
1095 }
1096
1097
1104 public function DELETE($options)
1105 {
1106 global $ilUser;
1107
1108 $this->writelog('DELETE('.var_export($options, true).')');
1109 $this->writelog('DELETE '.$options['path']);
1110
1111 // get dav object for path
1112 $path =& $this->davDeslashify($options['path']);
1113 $parentDAV =& $this->getObject(dirname($path));
1114 $objDAV =& $this->getObject($path);
1115
1116 // sanity check
1117 if (is_null($objDAV) || $objDAV->isNullResource())
1118 {
1119 return '404 Not Found';
1120 }
1121 if (! $objDAV->isPermitted('delete'))
1122 {
1123 return '403 Forbidden';
1124 }
1125
1126 $parentDAV->remove($objDAV);
1127
1128 // Record write event
1129 ilChangeEvent::_recordWriteEvent($objDAV->getObjectId(), $ilUser->getId(), 'delete', $parentDAV->getObjectId());
1130
1131 return '204 No Content';
1132 }
1133
1140 public function MOVE($options)
1141 {
1142 global $ilUser;
1143
1144 $this->writelog('MOVE('.var_export($options, true).')');
1145 $this->writelog('MOVE '.$options['path'].' '.$options['dest']);
1146
1147 // Get path names
1148 $src = $this->davDeslashify($options['path']);
1149 $srcParent = dirname($src);
1150 $srcName = $this->davBasename($src);
1151 $dst = $this->davDeslashify($options['dest']);
1152
1153 $dstParent = dirname($dst);
1154 $dstName = $this->davBasename($dst);
1155 $this->writelog('move '.$dst.' dstname='.$dstName);
1156 // Source and destination must not be the same
1157 if ($src == $dst)
1158 {
1159 return '409 Conflict (source and destination are the same)';
1160 }
1161
1162 // Destination must not be in a subtree of source
1163 if (substr($dst,strlen($src)+1) == $src.'/')
1164 {
1165 return '409 Conflict (destination is in subtree of source)';
1166 }
1167
1168 // Get dav objects for path
1169 $srcDAV =& $this->getObject($src);
1170 $dstDAV =& $this->getObject($dst);
1171 $srcParentDAV =& $this->getObject($srcParent);
1172 $dstParentDAV =& $this->getObject($dstParent);
1173
1174 // Source must exist
1175 if ($srcDAV == null)
1176 {
1177 return '409 Conflict (source does not exist)';
1178 }
1179
1180 // Overwriting is only allowed, if overwrite option is set to 'T'
1181 $isOverwritten = false;
1182 if ($dstDAV != null)
1183 {
1184 if ($options['overwrite'] == 'T')
1185 {
1186 // Delete the overwritten destination
1187 if ($dstDAV->isPermitted('delete'))
1188 {
1189 $dstParentDAV->remove($dstDAV);
1190 $dstDAV = null;
1191 $isOverwritten = true;
1192 } else {
1193 return '403 Not Permitted';
1194 }
1195 } else {
1196 return '412 Precondition Failed';
1197 }
1198 }
1199
1200 // Parents of destination must exist
1201 if ($dstParentDAV == null)
1202 {
1203 return '409 Conflict (parent of destination does not exist)';
1204 }
1205
1206 if ($srcParent == $dstParent)
1207 {
1208 // Rename source, if source and dest are in same parent
1209
1210 // Check permission
1211 if (! $srcDAV->isPermitted('write'))
1212 {
1213 return '403 Forbidden';
1214 }
1215 $this->writelog('rename dstName='.$dstName);
1216 $srcDAV->setResourceName($dstName);
1217 $srcDAV->write();
1218 } else {
1219 // Move source, if source and dest are in same parent
1220
1221
1222 if (! $srcDAV->isPermitted('delete'))
1223 {
1224 return '403 Forbidden';
1225 }
1226
1227 if (! $dstParentDAV->isPermitted('create', $srcDAV->getILIASType()))
1228 {
1229 return '403 Forbidden';
1230 }
1231 $dstParentDAV->addMove($srcDAV, $dstName);
1232 }
1233
1234 // Record write event
1235 if ($isOverwritten)
1236 {
1237 ilChangeEvent::_recordWriteEvent($srcDAV->getObjectId(), $ilUser->getId(), 'rename');
1238 }
1239 else
1240 {
1241 ilChangeEvent::_recordWriteEvent($srcDAV->getObjectId(), $ilUser->getId(), 'remove', $srcParentDAV->getObjectId());
1242 ilChangeEvent::_recordWriteEvent($srcDAV->getObjectId(), $ilUser->getId(), 'add', $dstParentDAV->getObjectId());
1243 }
1244
1245 return ($isOverwritten) ? '204 No Content' : '201 Created';
1246 }
1247
1254 public function COPY($options, $del=false)
1255 {
1256 global $ilUser;
1257 $this->writelog('COPY('.var_export($options, true).' ,del='.$del.')');
1258 $this->writelog('COPY '.$options['path'].' '.$options['dest']);
1259
1260 // no copying to different WebDAV Servers
1261 if (isset($options["dest_url"])) {
1262 return "502 bad gateway";
1263 }
1264
1265 $src = $this->davDeslashify($options['path']);
1266 $srcParent = dirname($src);
1267 $srcName = $this->davBasename($src);
1268 $dst = $this->davDeslashify($options['dest']);
1269 $dstParent = dirname($dst);
1270 $dstName = $this->davBasename($dst);
1271
1272 // sanity check
1273 if ($src == $dst)
1274 {
1275 return '409 Conflict'; // src and dst are the same
1276 }
1277
1278 if (substr($dst,strlen($src)+1) == $src.'/')
1279 {
1280 return '409 Conflict'; // dst is in subtree of src
1281 }
1282
1283 $this->writelog('COPY src='.$src.' dst='.$dst);
1284 // get dav object for path
1285 $srcDAV =& $this->getObject($src);
1286 $dstDAV =& $this->getObject($dst);
1287 $dstParentDAV =& $this->getObject($dstParent);
1288
1289 if (is_null($srcDAV) || $srcDAV->isNullResource())
1290 {
1291 return '409 Conflict'; // src does not exist
1292 }
1293 if (is_null($dstParentDAV) || $dstParentDAV->isNullResource())
1294 {
1295 return '409 Conflict'; // parent of dst does not exist
1296 }
1297 $isOverwritten = false;
1298
1299 // XXX Handle nulltype for dstDAV
1300 if (! is_null($dstDAV))
1301 {
1302 if ($options['overwrite'] == 'T')
1303 {
1304 if ($dstDAV->isPermitted('delete'))
1305 {
1306 $dstParentDAV->remove($dstDAV);
1307 ilChangeEvent::_recordWriteEvent($dstDAV->getObjectId(), $ilUser->getId(), 'delete', $dstParentDAV->getObjectId());
1308
1309 $dstDAV = null;
1310 $isOverwritten = true;
1311 } else {
1312 return '403 Forbidden';
1313 }
1314 } else {
1315 return '412 Precondition Failed';
1316 }
1317 }
1318
1319 if (! $dstParentDAV->isPermitted('create', $srcDAV->getILIASType()))
1320 {
1321 return '403 Forbidden';
1322 }
1323 $dstDAV = $dstParentDAV->addCopy($srcDAV, $dstName);
1324
1325 // Record write event
1326 ilChangeEvent::_recordReadEvent($srcDAV->getILIASType(), $srcDAV->getRefId(),
1327 $srcDAV->getObjectId(), $ilUser->getId());
1328 ilChangeEvent::_recordWriteEvent($dstDAV->getObjectId(), $ilUser->getId(), 'create', $dstParentDAV->getObjectId());
1329
1330 return ($isOverwritten) ? '204 No Content' : '201 Created';
1331 }
1332
1339 public function PROPPATCH(&$options)
1340 {
1341 $this->writelog('PROPPATCH(options='.var_export($options, true).')');
1342 $this->writelog('PROPPATCH '.$options['path']);
1343
1344 // get dav object for path
1345 $path =& $this->davDeslashify($options['path']);
1346 $objDAV =& $this->getObject($path);
1347
1348 // sanity check
1349 if (is_null($objDAV) || $objDAV->isNullResource()) return false;
1350
1351 $isPermitted = $objDAV->isPermitted('write');
1352 foreach($options['props'] as $key => $prop) {
1353 if (!$isPermitted || $prop['ns'] == 'DAV:')
1354 {
1355 $options['props'][$key]['status'] = '403 Forbidden';
1356 } else {
1357 $this->properties->put($objDAV, $prop['ns'],$prop['name'],$prop['val']);
1358 }
1359 }
1360
1361 return "";
1362 }
1363
1364
1371 public function LOCK(&$options)
1372 {
1373 global $ilias;
1374 $this->writelog('LOCK('.var_export($options, true).')');
1375 $this->writelog('LOCK '.$options['path']);
1376
1377 // Check if an object with the path exists.
1378 $path =& $this->davDeslashify($options['path']);
1379 $objDAV =& $this->getObject($path);
1380 // Handle null-object locking
1381 // --------------------------
1382 if (is_null($objDAV))
1383 {
1384 $this->writelog('LOCK handling null-object locking...');
1385
1386 // If the name does not exist, we create a null-object for it
1387 if (isset($options["update"]))
1388 {
1389 $this->writelog('LOCK lock-update failed on non-existing null-object.');
1390 return '412 Precondition Failed';
1391 }
1392
1393 $parent = dirname($path);
1394 $parentDAV =& $this->getObject($parent);
1395 if (is_null($parentDAV))
1396 {
1397 $this->writelog('LOCK lock failed on non-existing path to null-object.');
1398 return '404 Not Found';
1399 }
1400 if (! $parentDAV->isPermitted('create', $parentDAV->getILIASFileType()) &&
1401 ! $parentDAV->isPermitted('create', $parentDAV->getILIASCollectionType()))
1402 {
1403 $this->writelog('LOCK lock failed - creation of null object not permitted.');
1404 return '403 Forbidden';
1405 }
1406
1407 $objDAV =& $parentDAV->createNull($this->davBasename($path));
1408 $this->writelog('created null resource for '.$path);
1409 }
1410
1411 // ---------------------
1412 if (! $objDAV->isNullResource() && ! $objDAV->isPermitted('write'))
1413 {
1414 $this->writelog('LOCK lock failed - user has no write permission.');
1415 return '403 Forbidden';
1416 }
1417
1418 // XXX - Check if there are other locks on the resource
1419 if (!isset($options['timeout']) || is_array($options['timeout']))
1420 {
1421 $options["timeout"] = time()+360; // 6min.
1422 }
1423
1424 if(isset($options["update"])) { // Lock Update
1425 $this->writelog('LOCK update token='.var_export($options,true));
1426 $success = $this->locks->updateLockWithoutCheckingDAV(
1427 $objDAV,
1428 $options['update'],
1429 $options['timeout']
1430 );
1431 if ($success)
1432 {
1433 $data = $this->locks->getLockDAV($objDAV, $options['update']);
1434 if ($data['ilias_owner'] == $ilias->account->getId())
1435 {
1436 $owner = $data['dav_owner'];
1437 } else {
1438 $owner = '<D:href>'.$this->getLogin($data['ilias_owner']).'</D:href>';
1439 }
1440 $options['owner'] = $owner;
1441 $options['locktoken'] = $data['token'];
1442 $options['timeout'] = $data['expires'];
1443 $options['depth'] = $data['depth'];
1444 $options['scope'] = $data['scope'];
1445 $options['type'] = $data['scope'];
1446 }
1447
1448 } else {
1449 $this->writelog('LOCK create new lock');
1450
1451 // XXX - Attempting to create a recursive exclusive lock
1452 // on a collection must fail, if any of nodes in the subtree
1453 // of the collection already has a lock.
1454 // XXX - Attempting to create a recursive shared lock
1455 // on a collection must fail, if any of nodes in the subtree
1456 // of the collection already has an exclusive lock.
1457 //$owner = (strlen(trim($options['owner'])) == 0) ? $ilias->account->getLogin() : $options['owner'];
1458 $this->writelog('lock owner='.$owner);
1459 $success = $this->locks->lockWithoutCheckingDAV(
1460 $objDAV,
1461 $ilias->account->getId(),
1462 trim($options['owner']),
1463 $options['locktoken'],
1464 $options['timeout'],
1465 $options['depth'],
1466 $options['scope']
1467 );
1468 }
1469
1470 // Note: As a workaround for the Microsoft WebDAV Client, we return
1471 // true/false here (resulting in the status '200 OK') instead of
1472 // '204 No Content').
1473 //return ($success) ? '204 No Content' : false;
1474 return $success;
1475 }
1476
1483 public function UNLOCK(&$options)
1484 {
1485 global $log, $ilias;
1486 $this->writelog('UNLOCK(options='.var_export($options, true).')');
1487 $this->writelog('UNLOCK '.$options['path']);
1488
1489 // Check if an object with the path exists.
1490 $path =& $this->davDeslashify($options['path']);
1491 $objDAV =& $this->getObject($path);
1492 if (is_null($objDAV)) {
1493 return '404 Not Found';
1494 }
1495 if (! $objDAV->isPermitted('write')) {
1496 return '403 Forbidden';
1497 }
1498
1499 $success = $this->locks->unlockWithoutCheckingDAV(
1500 $objDAV,
1501 $options['token']
1502 );
1503
1504 // Delete null resource object if there are no locks associated to
1505 // it anymore
1506 if ($objDAV->isNullResource()
1507 && count($this->locks->getLocksOnObjectDAV($objDAV)) == 0)
1508 {
1509 $parent = dirname($this->davDeslashify($options['path']));
1510 $parentDAV =& $this->getObject($parent);
1511 $parentDAV->remove($objDAV);
1512 }
1513
1514 // Workaround for Mac OS X: We must return 200 here instead of
1515 // 204.
1516 //return ($success) ? '204 No Content' : '412 Precondition Failed';
1517 return ($success) ? '200 OK' : '412 Precondition Failed';
1518 }
1519
1532 protected function checkLock($path)
1533 {
1534 global $ilias;
1535
1536 $this->writelog('checkLock('.$path.')');
1537 $result = null;
1538
1539 // get dav object for path
1540 //$objDAV = $this->getObject($path);
1541
1542 // convert DAV path into ilObjectDAV path
1543 $objPath = $this->toObjectPath($path);
1544 if (! is_null($objPath))
1545 {
1546 $objDAV = $objPath[count($objPath) - 1];
1547 $locks = $this->locks->getLocksOnPathDAV($objPath);
1548 foreach ($locks as $lock)
1549 {
1550 $isLastPathComponent = $lock['obj_id'] == $objDAV->getObjectId()
1551 && $lock['node_id'] == $objDAV->getNodeId();
1552
1553 // Check all locks on last object in path,
1554 // but only locks with depth infinity on parent objects.
1555 if ($isLastPathComponent || $lock['depth'] == 'infinity')
1556 {
1557 // DAV Clients expects to see their own owner name in
1558 // the locks. Since these names are not unique (they may
1559 // just be the name of the local user running the DAV client)
1560 // we return the ILIAS user name in all other cases.
1561 if ($lock['ilias_owner'] == $ilias->account->getId())
1562 {
1563 $owner = $lock['dav_owner'];
1564 } else {
1565 $owner = $this->getLogin($lock['ilias_owner']);
1566 }
1567
1568 // FIXME - Shouldn't we collect all locks instead of
1569 // using an arbitrary one?
1570 $result = array(
1571 "type" => "write",
1572 "obj_id" => $lock['obj_id'],
1573 "node_id" => $lock['node_id'],
1574 "scope" => $lock['scope'],
1575 "depth" => $lock['depth'],
1576 "owner" => $owner,
1577 "token" => $lock['token'],
1578 "expires" => $lock['expires']
1579 );
1580 if ($lock['scope'] == 'exclusive')
1581 {
1582 // If there is an exclusive lock in the path, it
1583 // takes precedence over all non-exclusive locks in
1584 // parent nodes. Therefore we can can finish collecting
1585 // locks.
1586 break;
1587 }
1588 }
1589 }
1590 }
1591 $this->writelog('checkLock('.$path.'):'.var_export($result,true));
1592
1593 return $result;
1594 }
1595
1600 protected function getLogin($userId)
1601 {
1602 $login = ilObjUser::_lookupLogin($userId);
1603 $this->writelog('getLogin('.$userId.'):'.var_export($login,true));
1604 return $login;
1605 }
1606
1607
1614 private function getObject($davPath)
1615 {
1616 global $tree;
1617
1618
1619 // If the second path elements starts with 'file_', the following
1620 // characters of the path element directly identify the ref_id of
1621 // a file object.
1622 $davPathComponents = split('/',substr($davPath,1));
1623 if (count($davPathComponents) > 1 &&
1624 substr($davPathComponents[1],0,5) == 'file_')
1625 {
1626 $ref_id = substr($davPathComponents[1],5);
1627 $nodePath = $tree->getNodePath($ref_id, $tree->root_id);
1628
1629 // Poor IE needs this, in order to successfully display
1630 // PDF documents
1631 header('Pragma: private');
1632 }
1633 else
1634 {
1635 $nodePath = $this->toNodePath($davPath);
1636 if ($nodePath == null && count($davPathComponents) == 1)
1637 {
1638 return ilObjectDAV::createObject(-1,'mountPoint');
1639 }
1640 }
1641 if (is_null($nodePath))
1642 {
1643 return null;
1644 } else {
1645 $top = $nodePath[count($nodePath) - 1];
1646 return ilObjectDAV::createObject($top['child'],$top['type']);
1647 }
1648 }
1655 private function toObjectPath($davPath)
1656 {
1657 $this->writelog('toObjectPath('.$davPath);
1658 global $tree;
1659
1660 $nodePath = $this->toNodePath($davPath);
1661
1662 if (is_null($nodePath))
1663 {
1664 return null;
1665 } else {
1666 $objectPath = array();
1667 foreach ($nodePath as $node)
1668 {
1669 $pathElement = ilObjectDAV::createObject($node['child'],$node['type']);
1670 if (is_null($pathElement))
1671 {
1672 break;
1673 }
1674 $objectPath[] = $pathElement;
1675 }
1676 return $objectPath;
1677 }
1678 }
1679
1691 public function toNodePath($davPath)
1692 {
1693 global $tree;
1694 $this->writelog('toNodePath('.$davPath.')...');
1695
1696 // Split the davPath into path titles
1697 $titlePath = split('/',substr($davPath,1));
1698
1699 // Remove the client id from the beginning of the title path
1700 if (count($titlePath) > 0)
1701 {
1702 array_shift($titlePath);
1703 }
1704
1705 // If the last path title is empty, remove it
1706 if (count($titlePath) > 0 && $titlePath[count($titlePath) - 1] == '')
1707 {
1708 array_pop($titlePath);
1709 }
1710
1711 // If the path is empty, return null
1712 if (count($titlePath) == 0)
1713 {
1714 $this->writelog('toNodePath('.$davPath.'):null, because path is empty.');
1715 return null;
1716 }
1717
1718 // If the path is an absolute path, ref_id is null.
1719 $ref_id = null;
1720
1721 // If the path is a relative folder path, convert it into an absolute path
1722 if (count($titlePath) > 0 && substr($titlePath[0],0,4) == 'ref_')
1723 {
1724 $ref_id = substr($titlePath[0],4);
1725 array_shift($titlePath);
1726 }
1727
1728 $nodePath = $tree->getNodePathForTitlePath($titlePath, $ref_id);
1729
1730 $this->writelog('toNodePath():'.var_export($nodePath,true));
1731 return $nodePath;
1732 }
1733
1740 private function davDeslashify($path)
1741 {
1743
1744 if ($path[strlen($path)-1] == '/') {
1745 $path = substr($path,0, strlen($path) - 1);
1746 }
1747 $this->writelog('davDeslashify:'.$path);
1748 return $path;
1749 }
1750
1757 private function davBasename($path)
1758 {
1759 $components = split('/',$path);
1760 return count($components) == 0 ? '' : $components[count($components) - 1];
1761 }
1762
1769 protected function writelog($message)
1770 {
1771 // Only write log message, if we are in debug mode
1772 if ($this->isDebug)
1773 {
1774 global $ilLog, $ilias;
1775 if ($ilLog)
1776 {
1777 if ($message == '---')
1778 {
1779 $ilLog->write('');
1780 } else {
1781 $ilLog->write(
1782 $ilias->account->getLogin()
1783 .' '.$_SERVER['REMOTE_ADDR'].':'.$_SERVER['REMOTE_PORT']
1784 .' ilDAVServer.'.str_replace("\n",";",$message)
1785 );
1786 }
1787 }
1788 else
1789 {
1790 $fh = fopen('/opt/ilias/log/ilias.log', 'a');
1791 fwrite($fh, date('Y-m-d H:i:s '));
1792 fwrite($fh, str_replace("\n",";",$message));
1793 fwrite($fh, "\n\n");
1794 fclose($fh);
1795 }
1796 }
1797 }
1798
1811 function getMountURI($refId, $nodeId = 0, $ressourceName = null, $parentRefId = null, $genericURI = false)
1812 {
1813 if ($genericURI) {
1814 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:");
1815 $query = null;
1816 } else if ($this->clientOS == 'windows') {
1817 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:");
1818 $query = 'mount-instructions';
1819 } else if ($this->clientBrowser == 'konqueror') {
1820 $baseUri = ($this->isWebDAVoverHTTPS() ? "webdavs:" : "webdav:");
1821 $query = null;
1822 } else if ($this->clientBrowser == 'nautilus') {
1823 $baseUri = ($this->isWebDAVoverHTTPS() ? "davs:" : "dav:");
1824 $query = null;
1825 } else {
1826 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:");
1827 $query = 'mount-instructions';
1828 }
1829 $baseUri.= "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]";
1830 $baseUri = substr($baseUri,0,strrpos($baseUri,'/')).'/webdav.php/'.CLIENT_ID;
1831
1832 $uri = $baseUri.'/ref_'.$refId.'/';
1833 if ($query != null)
1834 {
1835 $uri .= '?'.$query;
1836 }
1837
1838 return $uri;
1839 }
1854 function getFolderURI($refId, $nodeId = 0, $ressourceName = null, $parentRefId = null)
1855 {
1856 if ($this->clientOS == 'windows') {
1857 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:");
1858 $query = null;
1859 } else if ($this->clientBrowser == 'konqueror') {
1860 $baseUri = ($this->isWebDAVoverHTTPS() ? "webdavs:" : "webdav:");
1861 $query = null;
1862 } else if ($this->clientBrowser == 'nautilus') {
1863 $baseUri = ($this->isWebDAVoverHTTPS() ? "davs:" : "dav:");
1864 $query = null;
1865 } else {
1866 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:");
1867 $query = null;
1868 }
1869 $baseUri.= "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]";
1870 $baseUri = substr($baseUri,0,strrpos($baseUri,'/')).'/webdav.php/'.CLIENT_ID;
1871
1872 $uri = $baseUri.'/ref_'.$refId.'/';
1873 if ($query != null)
1874 {
1875 $uri .= '?'.$query;
1876 }
1877
1878 return $uri;
1879 }
1891 public function getObjectURI($refId, $ressourceName = null, $parentRefId = null)
1892 {
1893 $nodeId = 0;
1894 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:").
1895 "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]";
1896 $baseUri = substr($baseUri,0,strrpos($baseUri,'/')).'/webdav.php/'.CLIENT_ID;
1897
1898 if (! is_null($ressourceName) && ! is_null($parentRefId))
1899 {
1900 // Quickly create URI from the known data without needing SQL queries
1901 $uri = $baseUri.'/ref_'.$parentRefId.'/'.$this->davUrlEncode($ressourceName);
1902 } else {
1903 // Create URI and use some SQL queries to get the missing data
1904 global $tree;
1905 $nodePath = $tree->getNodePath($refId);
1906
1907 if (is_null($nodePath) || count($nodePath) < 2)
1908 {
1909 // No object path? Return null - file is not in repository.
1910 $uri = null;
1911 } else {
1912 $uri = $baseUri.'/ref_'.$nodePath[count($nodePath) - 2]['child'].'/'.
1913 $this->davUrlEncode($nodePath[count($nodePath) - 1]['title']);
1914 }
1915 }
1916 return $uri;
1917 }
1918
1936 public function getFileURI($refId, $ressourceName = null, $parentRefId = null)
1937 {
1938 $nodeId = 0;
1939 $baseUri = ($this->isWebDAVoverHTTPS() ? "https:" : "http:").
1940 "//$_SERVER[HTTP_HOST]$_SERVER[SCRIPT_NAME]";
1941 $baseUri = substr($baseUri,0,strrpos($baseUri,'/')).'/webdav.php/'.CLIENT_ID;
1942
1943 if (! is_null($ressourceName) && ! is_null($parentRefId))
1944 {
1945 // Quickly create URI from the known data without needing SQL queries
1946 $uri = $baseUri.'/file_'.$refId.'/'.$this->davUrlEncode($ressourceName);
1947 } else {
1948 // Create URI and use some SQL queries to get the missing data
1949 global $tree;
1950 $nodePath = $tree->getNodePath($refId);
1951
1952 if (is_null($nodePath) || count($nodePath) < 2)
1953 {
1954 // No object path? Return null - file is not in repository.
1955 $uri = null;
1956 } else {
1957 $uri = $baseUri.'/file_'.$nodePath[count($nodePath) - 1]['child'].'/'.
1958 $this->davUrlEncode($nodePath[count($nodePath) - 1]['title']);
1959 }
1960 }
1961 return $uri;
1962 }
1963
1969 public function isWebDAVoverHTTPS() {
1970 if ($this->isHTTPS == null) {
1971 global $ilSetting;
1972 require_once './Services/Http/classes/class.ilHTTPS.php';
1973 $https = new ilHTTPS();
1974 $this->isHTTPS = $https->isDetected() || $ilSetting->get('https');
1975 }
1976 return $this->isHTTPS;
1977 }
1978
1987 public static function _isActive()
1988 {
1989 global $ilClientIniFile;
1990 return $ilClientIniFile->readVariable('file_access','webdav_enabled') == '1' &&
1991 @include_once("Auth/HTTP.php");
1992 }
1998 public static function _isActionsVisible()
1999 {
2000 global $ilClientIniFile;
2001 return $ilClientIniFile->readVariable('file_access','webdav_actions_visible') == '1';
2002 }
2003
2013 public static function _getDefaultWebfolderInstructions()
2014 {
2015 global $lng;
2016 return $lng->txt('webfolder_instructions_text');
2017 }
2018
2045 public static function _getWebfolderInstructionsFor($webfolderTitle,
2046 $webfolderURI, $webfolderURI_IE, $webfolderURI_Konqueror, $webfolderURI_Nautilus,
2047 $os = 'unknown', $osFlavor = 'unknown')
2048 {
2049 global $ilSetting;
2050
2051 $settings = new ilSetting('file_access');
2052 $str = $settings->get('custom_webfolder_instructions', '');
2053 if (strlen($str) == 0 || ! $settings->get('custom_webfolder_instructions_enabled'))
2054 {
2056 }
2057 if(is_file('Customizing/clients/'.CLIENT_ID.'/webdavtemplate.htm')){
2058 $str = fread(fopen('Customizing/clients/'.CLIENT_ID.'/webdavtemplate.htm', "rb"),filesize('Customizing/clients/'.CLIENT_ID.'/webdavtemplate.htm'));
2059 }
2060 $str=utf8_encode($str);
2061
2062 preg_match_all('/(\\d+)/', $webfolderURI, $matches);
2063 $refID=$matches[0][0];
2064
2065 $str = str_replace("[WEBFOLDER_ID]", $refID, $str);
2066 $str = str_replace("[WEBFOLDER_TITLE]", $webfolderTitle, $str);
2067 $str = str_replace("[WEBFOLDER_URI]", $webfolderURI, $str);
2068 $str = str_replace("[WEBFOLDER_URI_IE]", $webfolderURI_IE, $str);
2069 $str = str_replace("[WEBFOLDER_URI_KONQUEROR]", $webfolderURI_Konqueror, $str);
2070 $str = str_replace("[WEBFOLDER_URI_NAUTILUS]", $webfolderURI_Nautilus, $str);
2071 $str = str_replace("[ADMIN_MAIL]", $ilSetting->get("admin_email"), $str);
2072
2073 if(strpos($_SERVER['HTTP_USER_AGENT'],'MSIE')!==false){
2074 $str = preg_replace('/\[IF_IEXPLORE\]((?:.|\n)*)\[\/IF_IEXPLORE\]/','\1', $str);
2075 }else{
2076 $str = preg_replace('/\[IF_NOTIEXPLORE\]((?:.|\n)*)\[\/IF_NOTIEXPLORE\]/','\1', $str);
2077 }
2078
2079 switch ($os)
2080 {
2081 case 'windows' :
2082 $operatingSystem = 'WINDOWS';
2083 break;
2084 case 'unix' :
2085 switch ($osFlavor)
2086 {
2087 case 'osx' :
2088 $operatingSystem = 'MAC';
2089 break;
2090 case 'linux' :
2091 $operatingSystem = 'LINUX';
2092 break;
2093 default :
2094 $operatingSystem = 'LINUX';
2095 break;
2096 }
2097 break;
2098 default :
2099 $operatingSystem = 'UNKNOWN';
2100 break;
2101 }
2102
2103 if ($operatingSystem != 'UNKNOWN')
2104 {
2105 $str = preg_replace('/\[IF_'.$operatingSystem.'\]((?:.|\n)*)\[\/IF_'.$operatingSystem.'\]/','\1', $str);
2106 $str = preg_replace('/\[IF_([A-Z_]+)\](?:(?:.|\n)*)\[\/IF_\1\]/','', $str);
2107 }
2108 else
2109 {
2110 $str = preg_replace('/\[IF_([A-Z_]+)\]((?:.|\n)*)\[\/IF_\1\]/','\2', $str);
2111 }
2112 return $str;
2113 }
2114
2120 private function getUploadMaxFilesize() {
2121 $val = ini_get('upload_max_filesize');
2122
2123 $val = trim($val);
2124 $last = strtolower($val[strlen($val)-1]);
2125 switch($last) {
2126 // The 'G' modifier is available since PHP 5.1.0
2127 case 'g':
2128 $val *= 1024;
2129 case 'm':
2130 $val *= 1024;
2131 case 'k':
2132 $val *= 1024;
2133 }
2134
2135 return $val;
2136 }
2137}
2138// END WebDAV
2139?>
$result
$success
Definition: Utf8Test.php:87
$_GET["client_id"]
HTTP_WebDAV_Server()
Constructor.
Definition: Server.php:108
mkprop()
helper for property element creation
Definition: Server.php:1551
http_status($status)
set HTTP return status and mirror it in a private header
Definition: Server.php:1924
toNFC( $string)
Convert a UTF-8 string to normal form C, canonical composition.
Definition: UtfNormal.php:157
_recordWriteEvent($obj_id, $usr_id, $action, $parent_obj_id=null)
Records a write event.
_catchupWriteEvents($obj_id, $usr_id, $timestamp=null)
Catches up with all write events which occured before the specified timestamp.
_recordReadEvent($a_type, $a_ref_id, $obj_id, $usr_id, $isCatchupWriteEvents=true, $a_ext_rc=false, $a_ext_time=false)
Records a read event and catches up with write events.
getDir(&$objDAV, &$options)
GET method handler for directories.
$clientBrowser
The name of some well known browsers, that need special support.
LOCK(&$options)
LOCK method handler.
getMountURI($refId, $nodeId=0, $ressourceName=null, $parentRefId=null, $genericURI=false)
Returns an URI for mounting the repository object as a webfolder.
isWebDAVoverHTTPS()
Returns true, if the WebDAV server transfers data over HTTPS.
getFileURI($refId, $ressourceName=null, $parentRefId=null)
Returns an URI for getting a file object using WebDAV.
$isDebug
The WebDAVServer prints lots of log messages to the ilias log, if this variable is set to true.
davUrlEncode($path)
We do not implement this method, because authentication is done by ilias3/webdav.php.
GET(&$options)
GET method handler.
MKCOL($options)
MKCOL method handler.
davBasename($path)
Private implementation of PHP basename() function.
writelog($message)
Writes a message to the logfile.,.
static _isActionsVisible()
Static getter.
DELETE($options)
DELETE method handler.
getLogin($userId)
Returns the login for the specified user id, or null if the user does not exist.
static getInstance()
Get singelton iunstance.
PUTfinished(&$options)
PUTfinished handler.
ilDAVServer()
Constructor.
$cachedObjectDAV
Cached object handler.
davDeslashify($path)
davDeslashify - make sure path does not end in a slash
fileinfo($resourcePath, $displayPath, &$objDAV)
Creates file info properties for a single file/resource.
checkLock($path)
checkLock() helper
PUT(&$options)
PUT method handler.
$clientOS
The operating system of the WebDAV client.
showMountInstructions(&$objDAV, &$options)
Mount instructions method handler for directories.
static _isActive()
Static getter.
toObjectPath($davPath)
Converts a DAV path into an array of DAV objects.
$locks
Handler for locks.
getObjectURI($refId, $ressourceName=null, $parentRefId=null)
Returns an URI for getting a object using WebDAV by its name.
getUploadMaxFilesize()
Gets the maximum permitted upload filesize from php.ini in bytes.
PROPFIND(&$options, &$files)
PROPFIND method handler.
UNLOCK(&$options)
UNLOCK method handler.
static _getDefaultWebfolderInstructions()
Gets instructions for the usage of webfolders.
isFileHidden(&$objDAV)
Returns true, if the resource has a file name which is hidden from the user.
getObject($davPath)
Gets a DAV object for the specified path.
getFolderURI($refId, $nodeId=0, $ressourceName=null, $parentRefId=null)
Returns an URI for mounting the repository object as a webfolder using Internet Explorer and Firefox ...
static _getWebfolderInstructionsFor($webfolderTitle, $webfolderURI, $webfolderURI_IE, $webfolderURI_Konqueror, $webfolderURI_Nautilus, $os='unknown', $osFlavor='unknown')
Gets Webfolder mount instructions for the specified webfolder.
mountDir(&$objDAV, &$options)
Mount method handler for directories.
PROPPATCH(&$options)
PROPPATCH method handler.
MOVE($options)
MOVE method handler.
toNodePath($davPath)
serveRequest()
Serves a WebDAV request.
COPY($options, $del=false)
COPY method handler.
$clientOSFlavor
The flavor of the operating system of the WebDAV client.
$properties
Handler for properties.
HTTPS.
_lookupLogin($a_user_id)
lookup login
createObject($refId, $type)
Static factory method to create a DAV object for a given refId and type.
ILIAS Setting Class.
static virusHandling($a_file, $a_orig_name="", $a_clean=true)
scan file for viruses and clean files if possible
$GLOBALS['ct_recipient']
exit
Definition: login.php:54
Virtual base class for implementing WebDAV servers.
global $lng
Definition: privfeed.php:40
global $ilSetting
Definition: privfeed.php:40
$ref_id
Definition: sahs_server.php:39
if(!is_array($argv)) $options
global $ilUser
Definition: imgupload.php:15
global $https
Definition: imgupload.php:15