eZ Publish  [4.0]
ezwebdavcontentserver.php
Go to the documentation of this file.
00001 <?php
00002 //
00003 // This is the eZWebDAVContentServer class. Manages WebDAV sessions.
00004 //
00005 // Created on: <15-Aug-2003 15:15:15 bh>
00006 //
00007 // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00008 // SOFTWARE NAME: eZ Publish
00009 // SOFTWARE RELEASE: 4.0.x
00010 // COPYRIGHT NOTICE: Copyright (C) 1999-2008 eZ Systems AS
00011 // SOFTWARE LICENSE: GNU General Public License v2.0
00012 // NOTICE: >
00013 //   This program is free software; you can redistribute it and/or
00014 //   modify it under the terms of version 2.0  of the GNU General
00015 //   Public License as published by the Free Software Foundation.
00016 //
00017 //   This program is distributed in the hope that it will be useful,
00018 //   but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 //   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 //   GNU General Public License for more details.
00021 //
00022 //   You should have received a copy of version 2.0 of the GNU General
00023 //   Public License along with this program; if not, write to the Free
00024 //   Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
00025 //   MA 02110-1301, USA.
00026 //
00027 //
00028 // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
00029 //
00030 
00031 /*!
00032   \class eZWebDAVContentServer ezwebdavcontentserver.php
00033   \ingroup eZWebDAV
00034   \brief Provides access to eZ Publish kernel using WebDAV
00035 
00036 */
00037 
00038 //include_once( 'lib/ezwebdav/classes/ezwebdavserver.php' );
00039 //include_once( 'kernel/classes/ezcontentobjecttreenode.php' );
00040 //include_once( "kernel/classes/datatypes/ezbinaryfile/ezbinaryfile.php" );
00041 //include_once( "lib/ezutils/classes/ezmimetype.php" );
00042 //include_once( 'lib/ezfile/classes/ezdir.php' );
00043 //include_once( "kernel/classes/ezurlaliasml.php" );
00044 //include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' );
00045 require_once( 'access.php' );
00046 
00047 class eZWebDAVContentServer extends eZWebDAVServer
00048 {
00049     const WEBDAV_INI_FILE = "webdav.ini";
00050     const WEBDAV_AUTH_REALM = "eZ Publish WebDAV interface";
00051     const WEBDAV_AUTH_FAILED = "Invalid username or password!";
00052     const WEBDAV_INVALID_SITE = "Invalid site name specified!";
00053     const WEBDAV_DISABLED = "WebDAV functionality is disabled!";
00054 
00055     /*!
00056      Initializes the eZWebDAVServer
00057     */
00058     function eZWebDAVContentServer()
00059     {
00060         $this->eZWebDAVServer();
00061         $this->User = eZUser::currentUser();
00062         $this->FolderClasses = null;
00063     }
00064 
00065     /*!
00066      \reimp
00067      Makes sure $this->User is reinitialized with the current user,
00068      then calls the $super->processClientRequest().
00069     */
00070     function processClientRequest()
00071     {
00072         $this->User = eZUser::currentUser();
00073         eZWebDAVServer::processClientRequest();
00074     }
00075 
00076     /*!
00077       @{
00078     */
00079 
00080     /*!
00081       \reimp
00082       Fetch the file from eZCluster if needed before send.
00083     */
00084     function outputSendDataToClient( $output, $headers_only = false )
00085     {
00086         if ( $output["file"] )
00087         {
00088             $realPath = $output["file"];
00089             require_once( 'kernel/classes/ezclusterfilehandler.php' );
00090             $file = eZClusterFileHandler::instance( $realPath );
00091             $file->fetch();
00092         }
00093         $result = eZWebDAVServer::outputSendDataToClient($output,$headers_only);
00094         if ( $output["file"] && is_object( $file ) )
00095             $file->deleteLocal();
00096         return $result;
00097     }
00098 
00099     /*!
00100       \reimp
00101       Restricts the allowed methods to only the subset that this server supports.
00102     */
00103     function options( $target )
00104     {
00105         // Only a few WebDAV operations are allowed for now.
00106         $options = array();
00107         $options['methods'] = array( 'OPTIONS', 'PROPFIND', 'HEAD', 'GET', 'PUT', 'MKCOL', 'MOVE' );
00108 //         $options['versions'] = array( '1' );
00109 
00110         return $options;
00111     }
00112 
00113     /*!
00114       \reimp
00115       Produces the collection content. Builds either the virtual start folder
00116       with the virtual content folder in it (and additional files). OR: if
00117       we're browsing within the content folder: it gets the content of the
00118       target/given folder.
00119     */
00120     function getCollectionContent( $collection, $depth = false, $properties = false )
00121     {
00122         $fullPath = $collection;
00123         $collection = $this->splitFirstPathElement( $collection, $currentSite );
00124 
00125         if ( !$currentSite )
00126         {
00127             // Display the root which contains a list of sites
00128             $this->appendLogEntry( "Root: Fethcing site list", 'CS:getCollectionContent' );
00129             $entries = $this->fetchSiteListContent( $depth, $properties );
00130             return $entries;
00131         }
00132 
00133         if ( !$this->userHasSiteAccess( $currentSite ) )
00134         {
00135             $this->appendLogEntry( "No access to site '$currentSite'", 'CS:getCollectionContent' );
00136             return eZWebDAVServer::FAILED_FORBIDDEN;
00137         }
00138 
00139         return $this->getVirtualFolderCollection( $currentSite, $collection, $fullPath, $depth, $properties );
00140     }
00141 
00142     /*!
00143      \private
00144      Handles collections on the virtual folder level, if no virtual folder
00145      elements are accessed it lists the virtual folders.
00146     */
00147     function getVirtualFolderCollection( $currentSite, $collection, $fullPath, $depth, $properties )
00148     {
00149         $this->appendLogEntry( "Check virtual folder: site '$currentSite' in '$collection' ", 'CS:getVirtualFolderCollection' );
00150         $this->setCurrentSite( $currentSite );
00151 
00152         if ( !$collection )
00153         {
00154             // We are inside a site so we display the virtual folder for the site
00155             $this->appendLogEntry( "Virtual folder for '$currentSite'", 'CS:getVirtualFolderCollection' );
00156             $entries = $this->fetchVirtualSiteContent( $currentSite, $depth, $properties );
00157             return $entries;
00158         }
00159 
00160         $collection = $this->splitFirstPathElement( $collection, $virtualFolder );
00161 
00162         if ( !in_array( $virtualFolder, $this->virtualFolderList() ) )
00163         {
00164             $this->appendLogEntry( "Unknown virtual folder: '$virtualFolder' in site '$currentSite'", 'CS:getVirtualFolderCollection' );
00165             return eZWebDAVServer::FAILED_NOT_FOUND;
00166         }
00167 
00168         if ( !$this->userHasVirtualAccess( $currentSite, $virtualFolder ) )
00169         {
00170             $this->appendLogEntry( "No access to virtual folder '$virtualFolder' in site '$currentSite'", 'CS:getVirtualFolderCollection' );
00171             return eZWebDAVServer::FAILED_FORBIDDEN;
00172         }
00173 
00174         return $this->getContentTreeCollection( $currentSite, $virtualFolder, $collection, $fullPath, $depth, $properties );
00175     }
00176 
00177     /*!
00178      \private
00179      Handles collections on the content tree level.
00180      Depending on the virtual folder we will generate a node path url and fetch
00181      the nodes for that path.
00182     */
00183     function getContentTreeCollection( $currentSite, $virtualFolder, $collection, $fullPath, $depth, $properties )
00184     {
00185         $this->appendLogEntry( "Content collection: from site '$currentSite' in '$virtualFolder' using path '$collection'", 'CS:getContentTreeCollection' );
00186         $nodePath = $this->internalNodePath( $virtualFolder, $collection );
00187         $node = $this->fetchNodeByTranslation( $nodePath );
00188 
00189         if ( !$node )
00190         {
00191             $this->appendLogEntry( "Unknown node: $nodePath", 'CS:getContentTreeCollection' );
00192             return eZWebDAVServer::FAILED_NOT_FOUND;
00193         }
00194 
00195         // Can we list the children of the node?
00196         if ( !$node->canRead() )
00197         {
00198             $this->appendLogEntry( "No access to content '$nodePath' in site '$currentSite'", 'CS:getContentTreeCollection' );
00199             return eZWebDAVServer::FAILED_FORBIDDEN;
00200         }
00201 
00202         $entries = $this->fetchContentList( $node, $nodePath, $depth, $properties );
00203         return $entries;
00204     }
00205 
00206     /*!
00207      \reimp
00208      Tries to figure out the filepath of the object being shown,
00209      if not we will pass the virtual url as the filepath.
00210     */
00211     function get( $target )
00212     {
00213         $result         = array();
00214         $result["data"] = false;
00215         $result["file"] = false;
00216 
00217         $fullPath = $target;
00218         $target = $this->splitFirstPathElement( $target, $currentSite );
00219 
00220         if ( !$currentSite )
00221         {
00222             // Sites are folders and have no data
00223             return eZWebDAVServer::FAILED_FORBIDDEN;
00224         }
00225 
00226         if ( !$this->userHasSiteAccess( $currentSite ) )
00227         {
00228             $this->appendLogEntry( "No access to site '$currentSite'", 'CS:get' );
00229             return eZWebDAVServer::FAILED_FORBIDDEN;
00230         }
00231 
00232         return $this->getVirtualFolderData( $result, $currentSite, $target, $fullPath );
00233     }
00234 
00235     /*!
00236      \private
00237      Handles data retrival on the virtual folder level.
00238     */
00239     function getVirtualFolderData( $result, $currentSite, $target, $fullPath )
00240     {
00241         $this->appendLogEntry( "current site: $currentSite", 'CS:get' );
00242         $this->setCurrentSite( $currentSite );
00243 
00244         $target = $this->splitFirstPathElement( $target, $virtualFolder );
00245 
00246         if ( !$target )
00247         {
00248             if ( !in_array( $virtualFolder, $this->virtualFileList() ) )
00249             {
00250                 return eZWebDAVServer::FAILED_NOT_FOUND;
00251             }
00252 
00253             // We have reached the end of the path
00254             if ( $virtualFolder == basename( eZWebDAVContentServer::virtualInfoFileName() ) )
00255             {
00256                 $result["file"] = eZWebDAVContentServer::virtualInfoFileName();
00257 
00258                 return $result;
00259             }
00260 
00261             // The rest in the virtual folder does not have any data
00262             return eZWebDAVServer::FAILED_NOT_FOUND;
00263         }
00264 
00265         if ( !$this->userHasVirtualAccess( $currentSite, $virtualFolder ) )
00266         {
00267             $this->appendLogEntry( "No access to virtual folder '$virtualFolder' in site '$currentSite'", 'CS:get' );
00268             return eZWebDAVServer::FAILED_FORBIDDEN;
00269         }
00270 
00271         if ( !in_array( $virtualFolder, $this->virtualFolderList() ) )
00272         {
00273             $this->appendLogEntry( "Unknown virtual folder: '$virtualFolder' in site '$currentSite'", 'CS:get' );
00274             return eZWebDAVServer::FAILED_NOT_FOUND;
00275         }
00276 
00277         if ( $virtualFolder == eZWebDAVContentServer::virtualContentFolderName() or
00278              $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
00279         {
00280             return $this->getContentNodeData( $result, $currentSite, $virtualFolder, $target, $fullPath );
00281         }
00282         return eZWebDAVServer::FAILED_NOT_FOUND;
00283     }
00284 
00285     /*!
00286      \private
00287      Handles data retrival on the content tree level.
00288     */
00289     function getContentNodeData( $result, $currentSite, $virtualFolder, $target, $fullPath )
00290     {
00291         $this->appendLogEntry( "attempting to fetch node, target is: $target", 'CS:get' );
00292 
00293         // Attempt to fetch the node the client wants to get.
00294         $nodePath = $this->internalNodePath( $virtualFolder, $target );
00295         $node = $this->fetchNodeByTranslation( $nodePath );
00296 
00297         // Proceed only if the node is valid:
00298         if ( $node == null )
00299         {
00300             $this->appendLogEntry( "No node for: $nodePath", 'CS:get' );
00301             return $result;
00302         }
00303 
00304         // Can we fetch the contents of the node
00305         if ( !$node->canRead() )
00306         {
00307             $this->appendLogEntry( "No access to get '$nodePath' in site '$currentSite'", 'CS:get' );
00308             return eZWebDAVServer::FAILED_FORBIDDEN;
00309         }
00310 
00311         $object = $node->attribute( 'object' );
00312 
00313         //include_once( 'kernel/classes/ezcontentupload.php' );
00314         $upload = new eZContentUpload();
00315         $info = $upload->objectFileInfo( $object );
00316         if ( $info )
00317         {
00318             $result['file'] = $info['filepath'];
00319         }
00320 
00321         return $result;
00322     }
00323 
00324     /*!
00325      \note Not implemented yet
00326     */
00327     function head( $target )
00328     {
00329         return eZWebDAVServer::FAILED_NOT_FOUND;
00330     }
00331 
00332     /*!
00333      \reimp
00334      Tries to create/update an object at location \a $target with the file \a $tempFile.
00335     */
00336     function put( $target, $tempFile )
00337     {
00338         $fullPath = $target;
00339         $target = $this->splitFirstPathElement( $target, $currentSite );
00340 
00341         if ( !$currentSite )
00342         {
00343             return eZWebDAVServer::FAILED_FORBIDDEN;
00344         }
00345 
00346         if ( !$this->userHasSiteAccess( $currentSite ) )
00347         {
00348             $this->appendLogEntry( "No access to site '$currentSite'", 'CS:put' );
00349             return eZWebDAVServer::FAILED_FORBIDDEN;
00350         }
00351 
00352         return $this->putVirtualFolderData( $currentSite, $target, $tempFile, $fullPath );
00353     }
00354 
00355     /*!
00356      \private
00357      Handles data storage on the content tree level.
00358      It will check if the target is below a content folder in which it calls putContentData().
00359     */
00360     function putVirtualFolderData( $currentSite, $target, $tempFile, $fullPath )
00361     {
00362         $this->appendLogEntry( "current site is: $currentSite", 'CS:put' );
00363         $this->setCurrentSite( $currentSite );
00364 
00365         $target = $this->splitFirstPathElement( $target, $virtualFolder );
00366 
00367         if ( !$target )
00368         {
00369             // We have reached the end of the path
00370             // We do not allow 'put' operations for the virtual folder.
00371             return eZWebDAVServer::FAILED_FORBIDDEN;
00372         }
00373 
00374         if ( !in_array( $virtualFolder, $this->virtualFolderList() ) )
00375         {
00376             $this->appendLogEntry( "Unknown virtual folder: '$virtualFolder' in site '$currentSite'", 'CS:put' );
00377             return eZWebDAVServer::FAILED_CONFLICT;
00378         }
00379 
00380         if ( !$this->userHasVirtualAccess( $currentSite, $virtualFolder ) )
00381         {
00382             $this->appendLogEntry( "No access to virtual folder '$virtualFolder' in site '$currentSite'", 'CS:put' );
00383             return eZWebDAVServer::FAILED_FORBIDDEN;
00384         }
00385 
00386         if ( $virtualFolder == eZWebDAVContentServer::virtualContentFolderName() or
00387              $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
00388         {
00389             return $this->putContentData( $currentSite, $virtualFolder, $target, $tempFile, $fullPath );
00390         }
00391 
00392         return eZWebDAVServer::FAILED_FORBIDDEN;
00393     }
00394 
00395     /*!
00396      \private
00397      Handles data storage on the content tree level.
00398      It will try to find the parent node of the wanted placement and
00399      create a new object with data from \a $tempFile.
00400     */
00401     function putContentData( $currentSite, $virtualFolder, $target, $tempFile, $fullPath )
00402     {
00403         $nodePath = $this->internalNodePath( $virtualFolder, $target );
00404 
00405         $this->appendLogEntry( "Inside virtual content folder", 'CS:put' );
00406 
00407         $parentNode = $this->fetchParentNodeByTranslation( $nodePath );
00408         if ( $parentNode == null )
00409         {
00410             // The node does not exist, so we cannot put the file
00411             $this->appendLogEntry( "Cannot put file $nodePath, not parent found", 'CS:put' );
00412             return eZWebDAVServer::FAILED_CONFLICT;
00413         }
00414 
00415         // Can we put content in the parent node
00416         if ( !$parentNode->canRead() )
00417         {
00418             $this->appendLogEntry( "No access to put '$nodePath' in site '$currentSite'", 'CS:put' );
00419             return eZWebDAVServer::FAILED_FORBIDDEN;
00420         }
00421 
00422         $parentNodeID = $parentNode->attribute( 'node_id' );
00423 
00424         // We need the MIME-Type to figure out which content-class we will use
00425         $mimeInfo = eZMimeType::findByURL( $nodePath );
00426         $mime = $mimeInfo['name'];
00427 
00428         $webdavINI = eZINI::instance( eZWebDAVContentServer::WEBDAV_INI_FILE );
00429         $defaultObjectType = $webdavINI->variable( 'PutSettings', 'DefaultClass' );
00430 
00431         $existingNode = $this->fetchNodeByTranslation( $nodePath );
00432         //include_once( 'kernel/classes/ezcontentupload.php' );
00433 
00434         $upload = new eZContentUpload();
00435         if ( !$upload->handleLocalFile( $result, $tempFile, $parentNodeID, $existingNode ) )
00436         {
00437             foreach ( $result['errors'] as $error )
00438             {
00439                 $this->appendLogEntry( "Error: " . $error['description'], 'CS: put' );
00440             }
00441             foreach ( $result['notices'] as $notice )
00442             {
00443                 $this->appendLogEntry( "Notice: " . $notice['description'], 'CS: put' );
00444             }
00445             if ( $result['status'] == eZContentUpload::STATUS_PERMISSION_DENIED )
00446             {
00447                 return eZWebDAVServer::FAILED_FORBIDDEN;
00448             }
00449             else
00450                 return eZWebDAVServer::FAILED_UNSUPPORTED;
00451         }
00452 
00453         return eZWebDAVServer::OK_CREATED;
00454     }
00455 
00456     /*!
00457       \reimp
00458       Tries to create a collection at \a $target. In our case this is a content-class
00459       of a given type (most likely a folder).
00460     */
00461     function mkcol( $target )
00462     {
00463         $fullPath = $target;
00464         $target = $this->splitFirstPathElement( $target, $currentSite );
00465 
00466         if ( !$currentSite )
00467         {
00468             // Site list cannot get new entries
00469             return eZWebDAVServer::FAILED_FORBIDDEN;
00470         }
00471 
00472         if ( !$this->userHasSiteAccess( $currentSite ) )
00473         {
00474             $this->appendLogEntry( "No access to site '$currentSite'", 'CS:mkcol' );
00475             return eZWebDAVServer::FAILED_FORBIDDEN;
00476         }
00477 
00478         return $this->mkcolVirtualFolder( $currentSite, $target, $fullPath );
00479     }
00480 
00481     /*!
00482      \private
00483      Handles collection creation on the virtual folder level.
00484      It will check if the target is below a content folder in which it calls mkcolContent().
00485     */
00486     function mkcolVirtualFolder( $currentSite, $target, $fullPath )
00487     {
00488         $this->setCurrentSite( $currentSite );
00489 
00490         $target = $this->splitFirstPathElement( $target, $virtualFolder );
00491 
00492         if ( !in_array( $virtualFolder, $this->virtualList() ) )
00493         {
00494             $this->appendLogEntry( "Unknown virtual element: '$virtualFolder' in site '$currentSite'", 'CS:mkcol' );
00495             return eZWebDAVServer::FAILED_NOT_FOUND;
00496         }
00497 
00498         if ( !$target )
00499         {
00500             // We have reached the end of the path
00501             // We do not allow 'mkcol' operations for the virtual folder.
00502             return eZWebDAVServer::FAILED_FORBIDDEN;
00503         }
00504 
00505         if ( !$this->userHasVirtualAccess( $currentSite, $virtualFolder ) )
00506         {
00507             $this->appendLogEntry( "No access to virtual folder '$virtualFolder' in site '$currentSite'", 'CS:mkcol' );
00508             return eZWebDAVServer::FAILED_FORBIDDEN;
00509         }
00510 
00511         if ( $virtualFolder == eZWebDAVContentServer::virtualContentFolderName() or
00512              $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
00513         {
00514             return $this->mkcolContent( $currentSite, $virtualFolder, $target, $fullPath );
00515         }
00516 
00517         return eZWebDAVServer::FAILED_FORBIDDEN;
00518     }
00519 
00520     /*!
00521      \private
00522      Handles collection creation on the content tree level.
00523      It will try to find the parent node of the wanted placement and
00524      create a new collection (folder etc.) as a child.
00525     */
00526     function mkcolContent( $currentSite, $virtualFolder, $target, $fullPath )
00527     {
00528         $nodePath = $this->internalNodePath( $virtualFolder, $target );
00529         $node = $this->fetchNodeByTranslation( $nodePath );
00530         if ( $node )
00531         {
00532             return eZWebDAVServer::FAILED_EXISTS;
00533         }
00534 
00535         $parentNode = $this->fetchParentNodeByTranslation( $nodePath );
00536         $this->appendLogEntry( "Target is: $target", 'CS:mkcolContent' );
00537 
00538         if ( !$parentNode )
00539         {
00540             return eZWebDAVServer::FAILED_NOT_FOUND;
00541         }
00542 
00543         // Can we create a collection in the parent node
00544         if ( !$parentNode->canRead() )
00545         {
00546             $this->appendLogEntry( "No access to mkcol '$nodePath' in site '$currentSite'", 'CS:mkcolContent' );
00547             return eZWebDAVServer::FAILED_FORBIDDEN;
00548         }
00549 
00550         return $this->createFolder( $parentNode, $nodePath );
00551     }
00552 
00553     /*!
00554       \reimp
00555       Removes the object from the node tree and leaves it in the trash.
00556     */
00557     function delete( $target )
00558     {
00559         $fullPath = $target;
00560         $target = $this->splitFirstPathElement( $target, $currentSite );
00561 
00562         if ( !$currentSite )
00563         {
00564             // Cannot delete entries in site list
00565             return eZWebDAVServer::FAILED_FORBIDDEN;
00566         }
00567 
00568         if ( !$this->userHasSiteAccess( $currentSite ) )
00569         {
00570             $this->appendLogEntry( "No access to site '$currentSite'", 'CS:delete' );
00571             return eZWebDAVServer::FAILED_FORBIDDEN;
00572         }
00573 
00574         return $this->deleteVirtualFolder( $currentSite, $target, $fullPath );
00575     }
00576 
00577     /*!
00578      \private
00579      Handles deletion on the virtual folder level.
00580      It will check if the target is below a content folder in which it calls deleteContent().
00581     */
00582     function deleteVirtualFolder( $currentSite, $target, $fullPath )
00583     {
00584         $this->appendLogEntry( "Target is: $target", 'CS:delete' );
00585         $this->setCurrentSite( $currentSite );
00586 
00587         $target = $this->splitFirstPathElement( $target, $virtualFolder );
00588 
00589         if ( !in_array( $virtualFolder, $this->virtualList() ) )
00590         {
00591             $this->appendLogEntry( "Unknown virtual element: '$virtualFolder' in site '$currentSite'", 'CS:deleteVirtualFolder' );
00592             return eZWebDAVServer::FAILED_NOT_FOUND;
00593         }
00594 
00595         if ( !$target )
00596         {
00597             // We have reached the end of the path
00598             // We do not allow 'delete' operations for the virtual folder.
00599             return eZWebDAVServer::FAILED_FORBIDDEN;
00600         }
00601 
00602         if ( !$this->userHasVirtualAccess( $currentSite, $virtualFolder ) )
00603         {
00604             $this->appendLogEntry( "No access to virtual folder '$virtualFolder' in site '$currentSite'", 'CS:deleteVirtualFolder' );
00605             return eZWebDAVServer::FAILED_FORBIDDEN;
00606         }
00607 
00608         if ( $virtualFolder == eZWebDAVContentServer::virtualContentFolderName() or
00609              $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
00610         {
00611             return $this->deleteContent( $currentSite, $virtualFolder, $target, $fullPath );
00612         }
00613 
00614         return eZWebDAVServer::FAILED_FORBIDDEN;
00615     }
00616 
00617     /*!
00618      \private
00619      Handles deletion on the content tree level.
00620      It will try to find the node of the target \a $target
00621      and then try to remove it (ie. move to trash) if the user is allowed.
00622     */
00623     function deleteContent( $currentSite, $virtualFolder, $target, $fullPath )
00624     {
00625         $nodePath = $this->internalNodePath( $virtualFolder, $target );
00626         $node = $this->fetchNodeByTranslation( $nodePath );
00627 
00628         if ( $node == null )
00629         {
00630             $this->appendLogEntry( "Cannot delete node/object $nodePath, it does not exist", 'CS:deleteContent' );
00631             return eZWebDAVServer::FAILED_NOT_FOUND;
00632         }
00633 
00634         // Can we delete the node?
00635         if ( !$node->canRead() or
00636              !$node->canRemove() )
00637         {
00638             $this->appendLogEntry( "No access to delete '$nodePath' in site '$currentSite'", 'CS:deleteContent' );
00639             return eZWebDAVServer::FAILED_FORBIDDEN;
00640         }
00641 
00642         $this->appendLogEntry( "Removing node: $nodePath", 'CS:deleteContent' );
00643         $node->removeNodeFromTree( true );
00644         return eZWebDAVServer::OK;
00645     }
00646 
00647     /*!
00648       \reimp
00649       Moves the object \a $source to destination \a $destination.
00650     */
00651     function move( $source, $destination )
00652     {
00653         $fullSource = $source;
00654         $fullDestination = $destination;
00655         $source = $this->splitFirstPathElement( $source, $sourceSite );
00656         $destination = $this->splitFirstPathElement( $destination, $destinationSite );
00657         if ( $sourceSite != $destinationSite )
00658         {
00659             // We do not support moving from one site to another yet
00660             // TODO: Check if the sites are using the same db,
00661             //       if so allow the move as a simple object move
00662             //       If not we will have to do an object export from
00663             //       $sourceSite and import it in $destinationSite
00664             return eZWebDAVServer::FAILED_FORBIDDEN;
00665         }
00666 
00667         if ( !$sourceSite or
00668              !$destinationSite )
00669         {
00670             // Cannot move entries in site list
00671             return eZWebDAVServer::FAILED_FORBIDDEN;
00672         }
00673 
00674         if ( !$this->userHasSiteAccess( $sourceSite ) )
00675         {
00676             $this->appendLogEntry( "No access to site '$sourceSite'", 'CS:move' );
00677             return eZWebDAVServer::FAILED_FORBIDDEN;
00678         }
00679         if ( !$this->userHasSiteAccess( $destinationSite ) )
00680         {
00681             $this->appendLogEntry( "No access to site '$destinationSite'", 'CS:move' );
00682             return eZWebDAVServer::FAILED_FORBIDDEN;
00683         }
00684 
00685         return $this->moveVirtualFolder( $sourceSite, $destinationSite,
00686                                          $source, $destination,
00687                                          $fullSource, $fullDestination );
00688     }
00689 
00690     /*!
00691      \private
00692      Handles moving on the virtual folder level.
00693      It will check if the target is below a content folder in which it calls moveContent().
00694     */
00695     function moveVirtualFolder( $sourceSite, $destinationSite,
00696                                 $source, $destination,
00697                                 $fullSource, $fullDestination )
00698     {
00699         $this->setCurrentSite( $sourceSite );
00700 
00701         $source = $this->splitFirstPathElement( $source, $sourceVFolder );
00702         $destination = $this->splitFirstPathElement( $destination, $destinationVFolder );
00703 
00704         if ( !in_array( $sourceVFolder, $this->virtualList() ) )
00705         {
00706             $this->appendLogEntry( "Unknown virtual element: '$sourceVFolder' in site '$sourceSite'", 'CS:moveVirtualFolder' );
00707             return eZWebDAVServer::FAILED_NOT_FOUND;
00708         }
00709 
00710         if ( !in_array( $destinationVFolder, $this->virtualList() ) )
00711         {
00712             $this->appendLogEntry( "Unknown virtual element: '$destinationVFolder' in site '$destinationSite'", 'CS:moveVirtualFolder' );
00713             return eZWebDAVServer::FAILED_NOT_FOUND;
00714         }
00715 
00716         if ( !$source or
00717              !$destination )
00718         {
00719             // We have reached the end of the path for source or destination
00720             // We do not allow 'move' operations for the virtual folder (from or to)
00721             return eZWebDAVServer::FAILED_FORBIDDEN;
00722         }
00723 
00724         if ( !$this->userHasVirtualAccess( $sourceSite, $sourceVFolder ) )
00725         {
00726             $this->appendLogEntry( "No access to virtual folder '$sourceVFolder' in site '$sourceSite'", 'CS:moveVirtualFolder' );
00727             return eZWebDAVServer::FAILED_FORBIDDEN;
00728         }
00729         if ( !$this->userHasVirtualAccess( $destinationSite, $destinationVFolder ) )
00730         {
00731             $this->appendLogEntry( "No access to virtual folder '$destinationVFolder' in site '$destinationSite'", 'CS:moveVirtualFolder' );
00732             return eZWebDAVServer::FAILED_FORBIDDEN;
00733         }
00734 
00735         if ( ( $sourceVFolder == eZWebDAVContentServer::virtualContentFolderName() or
00736                $sourceVFolder == eZWebDAVContentServer::virtualMediaFolderName() ) and
00737              ( $destinationVFolder == eZWebDAVContentServer::virtualContentFolderName() or
00738                $destinationVFolder == eZWebDAVContentServer::virtualMediaFolderName() ) )
00739         {
00740             return $this->moveContent( $sourceSite, $destinationSite,
00741                                        $sourceVFolder, $destinationVFolder,
00742                                        $source, $destination,
00743                                        $fullSource, $fullDestination );
00744         }
00745 
00746         return eZWebDAVServer::FAILED_FORBIDDEN;
00747     }
00748 
00749     /*!
00750      \private
00751      Handles moving on the content tree level.
00752      It will try to find the node of the target \a $source
00753      and then try to move it to \a $destination.
00754     */
00755     function moveContent( $sourceSite, $destinationSite,
00756                           $sourceVFolder, $destinationVFolder,
00757                           $source, $destination,
00758                           $fullSource, $fullDestination )
00759     {
00760         $nodePath = $this->internalNodePath( $sourceVFolder, $source );
00761         $destinationNodePath = $this->internalNodePath( $destinationVFolder, $destination );
00762 
00763         // Get rid of possible extensions, remove .jpeg .txt .html etc..
00764         $source = $this->fileBasename( $source );
00765 
00766         $sourceNode = $this->fetchNodeByTranslation( $nodePath );
00767 
00768         if ( !$sourceNode )
00769         {
00770             return eZWebDAVServer::FAILED_NOT_FOUND;
00771         }
00772 
00773         // Can we move the node from $sourceNode
00774         if ( !$sourceNode->canMoveFrom() )
00775         {
00776             $this->appendLogEntry( "No access to move the node '$sourceSite':'$nodePath'", 'CS:moveContent' );
00777             return eZWebDAVServer::FAILED_FORBIDDEN;
00778         }
00779 
00780         $object = $sourceNode->attribute( 'object' );
00781         $classID = $object->attribute( 'contentclass_id' );
00782 
00783         // Get rid of possible extensions, remove .jpeg .txt .html etc..
00784         $destination = $this->fileBasename( $destination );
00785 
00786         $destinationNode = $this->fetchNodeByTranslation( $destinationNodePath );
00787         $this->appendLogEntry( "Destination: $destinationNodePath", 'CS:moveContent' );
00788 
00789         if ( $destinationNode )
00790         {
00791             return eZWebDAVServer::FAILED_EXISTS;
00792         }
00793 
00794         $destinationNode = $this->fetchParentNodeByTranslation( $destinationNodePath );
00795 
00796         if ( !$destinationNode )
00797         {
00798             return eZWebDAVServer::FAILED_NOT_FOUND;
00799         }
00800 
00801         // Can we move the node to $destinationNode
00802         if ( !$destinationNode->canMoveTo( $classID ) )
00803         {
00804             $this->appendLogEntry( "No access to move the node '$sourceSite':'$nodePath' to '$destinationSite':'$destinationNodePath'", 'CS:moveContent' );
00805             return eZWebDAVServer::FAILED_FORBIDDEN;
00806         }
00807 
00808         $srcParentPath = $this->splitLastPathElement( $nodePath, $srcNodeName );
00809         $dstParentPath = $this->splitLastPathElement( $destinationNodePath, $dstNodeName );
00810         if ( $srcParentPath == $dstParentPath )
00811         {
00812             if( !$object->rename( $dstNodeName ) )
00813             {
00814                 $this->appendLogEntry( "Unable to rename the node '$sourceSite':'$nodePath' to '$destinationSite':'$destinationNodePath'", 'CS:moveContent' );
00815                 return eZWebDAVServer::FAILED_FORBIDDEN;
00816             }
00817         }
00818         else
00819         {
00820             //include_once( 'kernel/classes/ezcontentobjecttreenodeoperations.php' );
00821             if( !eZContentObjectTreeNodeOperations::move( $sourceNode->attribute( 'node_id' ), $destinationNode->attribute( 'node_id' ) ) )
00822             {
00823                 $this->appendLogEntry( "Unable to move the node '$sourceSite':'$nodePath' to '$destinationSite':'$destinationNodePath'", 'CS:moveContent' );
00824                 return eZWebDAVServer::FAILED_FORBIDDEN;
00825             }
00826         }
00827 
00828         /*
00829 
00830         // Todo: add lookup of the name setting for the current object
00831                     $contentObjectID = $object->attribute( 'id' );
00832                     $contentObjectAttributes =& $object->contentObjectAttributes();
00833                     $contentObjectAttributes[0]->setAttribute( 'data_text', basename( $destination ) );
00834                     $contentObjectAttributes[0]->store();
00835 
00836                     //include_once( 'lib/ezutils/classes/ezoperationhandler.php' );
00837                     $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID, 'version' => 1 ) );
00838                     $object->store();
00839         */
00840 
00841         return eZWebDAVServer::OK_CREATED;
00842     }
00843 
00844     /*!
00845      @}
00846     */
00847 
00848     /*!
00849       Sets/changes the current site(access) to a \a $site.
00850     */
00851     function setCurrentSite( $site )
00852     {
00853         $access = array( 'name' => $site,
00854                          'type' => EZ_ACCESS_TYPE_STATIC );
00855 
00856         $access = changeAccess( $access );
00857         eZDebugSetting::writeDebug( 'kernel-siteaccess', $access, 'current siteaccess' );
00858 
00859         // Clear/flush global database instance.
00860         $nullVar = null;
00861         eZDB::setInstance( $nullVar );
00862     }
00863 
00864     /*!
00865       Checks if the current user has access rights to site \a $site.
00866       \return \c true if the user proper access.
00867     */
00868     function userHasSiteAccess( $site )
00869     {
00870         $result = $this->User->hasAccessTo( 'user', 'login' );
00871         $accessWord = $result['accessWord'];
00872 
00873         if ( $accessWord == 'limited' )
00874         {
00875             //include_once( 'lib/ezutils/classes/ezsys.php' );
00876 
00877             $hasAccess = false;
00878             $policyChecked = false;
00879             foreach ( array_keys( $result['policies'] ) as $key )
00880             {
00881                 $policy =& $result['policies'][$key];
00882                 if ( isset( $policy['SiteAccess'] ) )
00883                 {
00884                     $policyChecked = true;
00885                     if ( in_array( eZSys::ezcrc32( $site ), $policy['SiteAccess'] ) )
00886                     {
00887                         $hasAccess = true;
00888                         break;
00889                     }
00890                 }
00891                 if ( $hasAccess )
00892                     break;
00893             }
00894             if ( !$policyChecked )
00895                 $hasAccess = true;
00896         }
00897         else if ( $accessWord == 'yes' )
00898         {
00899             $hasAccess = true;
00900         }
00901         else if ( $accessWord == 'no' )
00902         {
00903             $hasAccess = false;
00904         }
00905         return $hasAccess;
00906     }
00907 
00908     /*!
00909       Checks if the current user has access rights to virtual element \a virtual
00910       on site \a $site.
00911       \return \c true if the user proper access.
00912     */
00913     function userHasVirtualAccess( $site, $virtual )
00914     {
00915         $this->appendLogEntry( "Can access '$site' and '$virtual'", 'CS:userHasVirtualAccess' );
00916         return true;
00917     }
00918 
00919     /*!
00920       Detects a possible/valid site-name in start of a path.
00921       \return The name of the site that was detected or \c false if not site could be detected
00922     */
00923     function currentSiteFromPath( $path )
00924     {
00925         $this->appendLogEntry( "start path: $path", 'CS:currentSiteFromPath' );
00926 
00927         $indexDir = eZSys::indexDir();
00928 
00929         // Remove indexDir if used in non-virtualhost mode.
00930         if ( preg_match( "#^" . preg_quote( $indexDir ) . "(.+)$#", $path, $matches ) )
00931         {
00932             $path = $matches[1];
00933         }
00934 
00935         $this->appendLogEntry( "indexdir: $path", 'CS:currentSiteFromPath' );
00936 
00937         // Get the list of available sites.
00938         $sites = $this->availableSites();
00939 
00940         foreach ( $sites as $site )
00941         {
00942             // Check if given path starts with this site-name, if so: return it.
00943             if ( preg_match( "#^/" . preg_quote( $site ) . "(.*)$#", $path, $matches ) )
00944             {
00945                 $this->appendLogEntry( "site $site: $path", 'CS:currentSiteFromPath' );
00946                 return $site ;
00947             }
00948         }
00949 
00950         $this->appendLogEntry( "no valid site was found..", 'CS:currentSiteFromPath' );
00951         return false ;
00952     }
00953 
00954     /*!
00955       \reimp
00956       Removes the www-dir and indexfile from the URL.
00957     */
00958     function processURL( $url )
00959     {
00960         $this->appendLogEntry( "start url: $url", 'CS:processURL' );
00961         $indexDir = eZSys::indexDir();
00962         $len = strlen( $indexDir );
00963 
00964         if ( $indexDir == substr( $url, 0, $len ) )
00965         {
00966             $url = substr( $url, $len );
00967         }
00968 
00969         // Remove the starting / if there is one
00970         // the rest of the operation code expects this to not be present
00971         if ( strlen( $url ) > 0 and $url[0] == '/' )
00972             $url = substr( $url, 1 );
00973 
00974         $this->appendLogEntry( "indexdir url: $url", 'CS:processURL' );
00975         return $url;
00976     }
00977 
00978     /*!
00979      \reimp
00980     */
00981     function headers()
00982     {
00983         header( "WebDAV-Powered-By: eZ Publish" );
00984     }
00985 
00986     /*!
00987       Takes the first path element from \a $path and removes it from
00988       the path, the extracted part will be placed in \a $name.
00989       \return A string containing the rest of the path,
00990               the path will not contain a starting slash.
00991       \param $path A string defining a path of elements delimited by a slash,
00992                    if the path starts with a slash it will be removed.
00993       \param[out] $element The name of the first path element without any slashes.
00994 
00995       \code
00996       $path = '/path/to/item/';
00997       $newPath = eZWebDAVContentServer::splitFirstPathElement( $path, $root );
00998       print( $root ); // prints 'path', $newPath is now 'to/item/'
00999       $newPath = eZWebDAVContentServer::splitFirstPathElement( $newPath, $second );
01000       print( $second ); // prints 'to', $newPath is now 'item/'
01001       $newPath = eZWebDAVContentServer::splitFirstPathElement( $newPath, $third );
01002       print( $third ); // prints 'item', $newPath is now ''
01003       \endcode
01004     */
01005     function splitFirstPathElement( $path, &$element )
01006     {
01007         if ( $path[0] == '/' )
01008             $path = substr( $path, 1 );
01009         $pos = strpos( $path, '/' );
01010         if ( $pos === false )
01011         {
01012             $element = $path;
01013             $path = '';
01014         }
01015         else
01016         {
01017             $element = substr( $path, 0, $pos );
01018             $path = substr( $path, $pos + 1 );
01019         }
01020         return $path;
01021     }
01022 
01023     /*!
01024       Takes the last path element from \a $path and removes it from
01025       the path, the extracted part will be placed in \a $name.
01026       \return A string containing the rest of the path,
01027               the path will not contain the ending slash.
01028       \param $path A string defining a path of elements delimited by a slash,
01029                    if the path ends with a slash it will be removed.
01030       \param[out] $element The name of the first path element without any slashes.
01031 
01032       \code
01033       $path = '/path/to/item/';
01034       $newPath = eZWebDAVContentServer::splitLastPathElement( $path, $root );
01035       print( $root ); // prints 'item', $newPath is now '/path/to'
01036       $newPath = eZWebDAVContentServer::splitLastPathElement( $newPath, $second );
01037       print( $second ); // prints 'to', $newPath is now '/path'
01038       $newPath = eZWebDAVContentServer::splitLastPathElement( $newPath, $third );
01039       print( $third ); // prints 'path', $newPath is now ''
01040       \endcode
01041     */
01042     function splitLastPathElement( $path, &$element )
01043     {
01044         $len = strlen( $path );
01045         if ( $len > 0 and $path[$len - 1] == '/' )
01046             $path = substr( $path, 0, $len - 1 );
01047         $pos = strrpos( $path, '/' );
01048         if ( $pos === false )
01049         {
01050             $element = $path;
01051             $path = '';
01052         }
01053         else
01054         {
01055             $element = substr( $path, $pos + 1 );
01056             $path = substr( $path, 0, $pos );
01057         }
01058         return $path;
01059     }
01060 
01061     /*!
01062      \private
01063      \return A path that corresponds to the internal path of nodes.
01064     */
01065     function internalNodePath( $virtualFolder, $collection )
01066     {
01067         // All root nodes needs to prepend their name to get the correct path
01068         // except for the content root which uses the path directly.
01069         if ( $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
01070         {
01071             $nodePath = 'media';
01072             if ( strlen( $collection ) > 0 )
01073                 $nodePath .= '/' . $collection;
01074         }
01075         else
01076         {
01077             $nodePath = $collection;
01078         }
01079         return $nodePath;
01080     }
01081 
01082     /*!
01083       Attempts to fetch a possible/existing node by translating
01084       the inputted string/path to a node-number.
01085     */
01086     function fetchNodeByTranslation( $nodePathString )
01087     {
01088         // Get rid of possible extensions, remove .jpeg .txt .html etc..
01089         $nodePathString = $this->fileBasename( $nodePathString );
01090 
01091         // Strip away last slash
01092         if ( strlen( $nodePathString ) > 0 and
01093              $nodePathString[strlen( $nodePathString ) - 1] == '/' )
01094         {
01095             $nodePathString = substr( $nodePathString, 0, strlen( $nodePathString ) - 1 );
01096         }
01097 
01098         if ( strlen( $nodePathString ) > 0 )
01099         {
01100             $nodePathString = eZURLAliasML::convertPathToAlias( $nodePathString );
01101         }
01102 
01103         // Attempt to get nodeID from the URL.
01104         $nodeID = eZURLAliasML::fetchNodeIDByPath( $nodePathString );
01105         if ( $nodeID )
01106         {
01107             $this->appendLogEntry( "NodeID: $nodeID", 'CS:fetchNodeByTranslation' );
01108         }
01109         else
01110         {
01111             $this->appendLogEntry( "No nodeID", 'CS:fetchNodeByTranslation' );
01112             return false;
01113         }
01114 
01115         // Attempt to fetch the node.
01116         $node = eZContentObjectTreeNode::fetch( $nodeID );
01117 
01118         // Return the node.
01119         return $node;
01120     }
01121 
01122     /*!
01123       \return The string \a $name without the final suffix (.jpg, .gif etc.)
01124     */
01125     function fileBasename( $name )
01126     {
01127         $pos = strrpos( $name, '.' );
01128         if ( $pos !== false )
01129         {
01130             $name = substr( $name, 0, $pos );
01131         }
01132         return $name;
01133     }
01134 
01135     /*!
01136       Attempts to fetch a possible node by translating
01137       the inputted string/path to a node-number. The last
01138       section of the path is removed before the actual
01139       translation: hence, the PARENT node is returned.
01140     */
01141     function fetchParentNodeByTranslation( $nodePathString )
01142     {
01143         // Strip extensions. E.g. .jpg
01144         $nodePathString = $this->fileBasename( $nodePathString );
01145 
01146         // Strip away last slash
01147         if ( strlen( $nodePathString ) > 0 and
01148              $nodePathString[strlen( $nodePathString ) - 1] == '/' )
01149         {
01150             $nodePathString = substr( $nodePathString, 0, strlen( $nodePathString ) - 1 );
01151         }
01152 
01153         $nodePathString = $this->splitLastPathElement( $nodePathString, $element );
01154 
01155         if ( strlen( $nodePathString ) == 0 )
01156             $nodePathString = '/';
01157 
01158         $nodePathString = eZURLAliasML::convertPathToAlias( $nodePathString );
01159 
01160         // Attempt to translate the URL to something like "/content/view/full/84".
01161         $translateResult = eZURLAliasML::translate( $nodePathString );
01162 
01163         // handle redirects
01164         while ( $nodePathString == 'error/301' )
01165         {
01166             $nodePathString = $translateResult;
01167 
01168             $translateResult = eZURLAliasML::translate( $nodePathString );
01169         }
01170 
01171         // Get the ID of the node (which is the last part of the translated path).
01172         if ( preg_match( "#^content/view/full/([0-9]+)$#", $nodePathString, $matches ) )
01173         {
01174             $nodeID = $matches[1];
01175             $this->appendLogEntry( "NodeID: $nodeID", 'CS:fetchParentNodeByTranslation' );
01176         }
01177         else
01178         {
01179             $this->appendLogEntry( "Root node", 'CS:fetchParentNodeByTranslation' );
01180             $nodeID = 2;
01181         }
01182 
01183         // Attempt to fetch the node.
01184         $node = eZContentObjectTreeNode::fetch( $nodeID );
01185 
01186         // Return the node.
01187         return $node;
01188     }
01189 
01190     /*!
01191      \return An array containing the names of all folders in the virtual root.
01192     */
01193     function virtualFolderList()
01194     {
01195         return array( eZWebDAVContentServer::virtualContentFolderName(), eZWebDAVContentServer::virtualMediaFolderName() );
01196     }
01197 
01198     /*!
01199      \return An array containing the names of all folders in the virtual root.
01200     */
01201     function virtualFolderInfoList()
01202     {
01203         return array( array( 'name' => eZWebDAVContentServer::virtualContentFolderName() ),
01204                       array( 'name' => eZWebDAVContentServer::virtualMediaFolderName() ) );
01205     }
01206 
01207     /*!
01208      \return An array containing the names of all files in the virtual root.
01209     */
01210     function virtualFileList()
01211     {
01212         return array( basename( eZWebDAVContentServer::virtualInfoFileName() ) );
01213     }
01214 
01215     /*!
01216      \return An array containing the names of all files in the virtual root.
01217     */
01218     function virtualFileInfoList()
01219     {
01220         return array( array( 'name' => basename( eZWebDAVContentServer::virtualInfoFileName() ),
01221                              'filepath' => eZWebDAVContentServer::virtualInfoFileName() ) );
01222     }
01223 
01224     /*!
01225      \return An array containing the names of all elements in the virtual root.
01226     */
01227     function virtualList()
01228     {
01229         return array_merge( eZWebDAVContentServer::virtualFolderList(),
01230                             eZWebDAVContentServer::virtualFileList() );
01231     }
01232 
01233     /*!
01234      \return An array containing the names of all elements in the virtual root.
01235     */
01236     function virtualInfoList()
01237     {
01238         return array_merge( eZWebDAVContentServer::virtualFolderInfoList(),
01239                             eZWebDAVContentServer::virtualFileInfoList() );
01240     }
01241 
01242     /*!
01243      Functions related to creation collections
01244      @{
01245     */
01246 
01247     /*!
01248       Builds and returns the content of the virtual start fodler
01249       for a site. The virtual startfolder is an intermediate step
01250       between the site-list and actual content. This directory
01251       contains the "content" folder which leads to the site's
01252       actual content.
01253     */
01254     function fetchVirtualSiteContent( $site, $depth, $properties )
01255     {
01256         $this->appendLogEntry( "Script URL.." . eZSys::instance()->RequestURI, 'CS:fetchVirtualSiteContent' );
01257         // Location of the info file.
01258         $infoFile = $_SERVER['DOCUMENT_ROOT'] . '/' . eZWebDAVContentServer::virtualInfoFileName();
01259 
01260         // Always add the current collection
01261         $contentEntry = array();
01262         $contentEntry["name"]     = eZSys::instance()->RequestURI;
01263         $contentEntry["size"]     = 0;
01264         $contentEntry["mimetype"] = 'httpd/unix-directory';
01265         $contentEntry["ctime"]    = filectime( 'settings/siteaccess/' . $site );
01266         $contentEntry["mtime"]    = filemtime( 'settings/siteaccess/' . $site );
01267         $contentEntry["href"]     = eZSys::instance()->RequestURI;
01268         $entries[] = $contentEntry;
01269 
01270         $defctime = $contentEntry['ctime'];
01271         $defmtime = $contentEntry['mtime'];
01272 
01273         if ( $depth > 0 )
01274         {
01275             $scriptURL = eZSys::instance()->RequestURI;
01276             if ( $scriptURL{strlen($scriptURL) - 1} != "/" )
01277                 $scriptURL .= "/";
01278 
01279             // Set up attributes for the virtual content folder:
01280             foreach ( $this->virtualInfoList() as $info )
01281             {
01282                 $name = $info['name'];
01283                 $filepath = false;
01284                 if ( isset( $info['filepath'] ) )
01285                     $filepath = $info['filepath'];
01286                 $size = 0;
01287                 if ( $filepath === false or file_exists( $filepath ) )
01288                 {
01289                     $mimeType = 'httpd/unix-directory';
01290                     if ( $filepath !== false )
01291                     {
01292                         $mimeInfo = eZMimeType::findByFileContents( $filepath );
01293                         $mimeType = $mimeInfo['name'];
01294                         $ctime = filectime( $filepath );
01295                         $mtime = filemtime( $filepath );
01296                         $size  = filesize( $filepath );
01297                     }
01298                     else
01299                     {
01300                         $ctime = $defctime;
01301                         $mtime = $defmtime;
01302                     }
01303 
01304                     $entry             = array();
01305                     $entry["name"]     = $name;
01306                     $entry["size"]     = $size;
01307                     $entry["mimetype"] = $mimeType;
01308                     $entry["ctime"]    = $ctime;
01309                     $entry["mtime"]    = $mtime;
01310                     $entry["href"]     = $scriptURL . $name;
01311                     $entries[]         = $entry;
01312                 }
01313             }
01314         }
01315 
01316         return $entries;
01317     }
01318 
01319     /*!
01320       Builds a content-list of available sites and returns it.
01321     */
01322     function fetchSiteListContent( $depth, $properties )
01323     {
01324         // At the end: we'll return an array of entry-arrays.
01325         $entries = array();
01326 
01327         // An entry consists of several attributes (name, size, etc).
01328         $contentEntry = array();
01329         $entries = array();
01330 
01331         // Set up attributes for the virtual site-list folder:
01332         $contentEntry["name"]     = '/';
01333         $contentEntry["href"]     = eZSys::instance()->RequestURI;
01334         $contentEntry["size"]     = 0;
01335         $contentEntry["mimetype"] = 'httpd/unix-directory';
01336         $contentEntry["ctime"]    = filectime( 'var' );
01337         $contentEntry["mtime"]    = filemtime( 'var' );
01338 
01339         $entries[] = $contentEntry;
01340 
01341         if ( $depth > 0 )
01342         {
01343             // Get list of available sites.
01344             $sites = $this->availableSites();
01345 
01346             // For all available sites:
01347             foreach ( $sites as $site )
01348             {
01349                 // Set up attributes for the virtual site-list folder:
01350                 $contentEntry["name"]     = eZSys::instance()->RequestURI . $site;
01351                 $contentEntry["size"]     = 0;
01352                 $contentEntry["mimetype"] = 'httpd/unix-directory';
01353                 $contentEntry["ctime"]    = filectime( 'settings/siteaccess/' . $site );
01354                 $contentEntry["mtime"]    = filemtime( 'settings/siteaccess/' . $site );
01355 
01356                 if ( eZSys::instance()->RequestURI == '/' )
01357                 {
01358                     $contentEntry["href"] = $contentEntry["name"];
01359                 }
01360                 else
01361                 {
01362                     $contentEntry["href"] = eZSys::instance()->RequestURI . $contentEntry["name"];
01363                 }
01364 
01365                 $entries[] = $contentEntry;
01366             }
01367         }
01368 
01369         return $entries;
01370     }
01371 
01372     /*!
01373       Gets and returns the content of an actual node.
01374       List of other nodes belonging to the target node
01375       (one level below it) will be returned.
01376     */
01377     function fetchContentList( &$node, $target, $depth, $properties )
01378     {
01379         // We'll return an array of entries (which is an array of attributes).
01380         $entries = array();
01381 
01382         if ( $depth == 1 )
01383         {
01384             // Get all the children of the target node.
01385             $subTree = $node->subTree( array ( 'Depth' => 1 ) );
01386 
01387             // Build the entries array by going through all the
01388             // nodes in the subtree and getting their attributes:
01389             foreach ( $subTree as $someNode )
01390             {
01391                 $entries[] = $this->fetchNodeInfo( $someNode );
01392             }
01393         }
01394 
01395         // Always include the information about the current level node
01396         $thisNodeInfo = array();
01397         $thisNodeInfo = $this->fetchNodeInfo( $node );
01398         $thisNodeInfo["href"] = eZSys::instance()->RequestURI;
01399         $entries[] = $thisNodeInfo;
01400 
01401         // Return the content of the target.
01402         return $entries;
01403     }
01404 
01405     /*!
01406       \return \c true if the object \a $object should always be considered a folder.
01407     */
01408     function isObjectFolder( $object, &$class )
01409     {
01410         $classIdentifier = $class->attribute( 'identifier' );
01411         if ( $this->FolderClasses === null )
01412         {
01413             $webdavINI = eZINI::instance( eZWebDAVContentServer::WEBDAV_INI_FILE );
01414             $folderClasses = array();
01415             if ( $webdavINI->hasGroup( 'GeneralSettings' ) and
01416                  $webdavINI->hasVariable( 'GeneralSettings', 'FolderClasses' ) )
01417             {
01418                 $folderClasses = $webdavINI->variable( 'GeneralSettings', 'FolderClasses' );
01419             }
01420             $this->FolderClasses = $folderClasses;
01421         }
01422         return in_array( $classIdentifier, $this->FolderClasses );
01423     }
01424 
01425     /*!
01426       Gathers information about a given node (specified as parameter).
01427     */
01428     function fetchNodeInfo( &$node )
01429     {
01430         // When finished, we'll return an array of attributes/properties.
01431         $entry = array();
01432 
01433         // Grab settings from the ini file:
01434         $webdavINI = eZINI::instance( eZWebDAVContentServer::WEBDAV_INI_FILE );
01435         $iniSettings = $webdavINI->variable( 'DisplaySettings', 'FileAttribute' );
01436 
01437         $classIdentifier = $node->attribute( 'class_identifier' );
01438 
01439         $object = $node->attribute( 'object' );
01440 
01441         // By default, everything is displayed as a folder:
01442         // Trim the name of the node, it is in some cases whitespace in eZ Publish
01443         $entry["name"] = trim( $node->attribute( 'name' ) );
01444         $entry["size"] = 0;
01445         $entry["mimetype"] = 'httpd/unix-directory';
01446         $entry["ctime"] = $object->attribute( 'published' );
01447         $entry["mtime"] = $object->attribute( 'modified' );
01448 
01449         //include_once( 'kernel/classes/ezcontentupload.php' );
01450         $upload = new eZContentUpload();
01451         $info = $upload->objectFileInfo( $object );
01452         $suffix = '';
01453         $class = $object->contentClass();
01454         $isObjectFolder = $this->isObjectFolder( $object, $class );
01455 
01456         if ( $isObjectFolder )
01457         {
01458             // We do nothing, the default is to see it as a folder
01459         }
01460         else if ( $info )
01461         {
01462             $filePath = $info['filepath'];
01463             $entry["mimetype"] = false;
01464             $entry["size"] = false;
01465             if ( isset( $info['filesize'] ) )
01466                 $entry['size'] = $info['filesize'];
01467             if ( isset( $info['mime_type'] ) )
01468                 $entry['mimetype'] = $info['mime_type'];
01469 
01470             // Fill in information from the actual file if they are missing.
01471             $file = eZClusterFileHandler::instance( $filePath );
01472             if ( !$entry['size'] and $file->exists() )
01473             {
01474                 $entry["size"] = $file->size();
01475             }
01476             if ( !$entry['mimetype']  )
01477             {
01478                 $mimeInfo = eZMimeType::findByURL( $filePath );
01479                 $entry["mimetype"] = $mimeInfo['name'];
01480                 $suffix = $mimeInfo['suffix'];
01481                 if ( strlen( $suffix ) > 0 )
01482                     $entry["name"] .= '.' . $suffix;
01483             }
01484             else
01485             {
01486                 // eZMimeType returns first suffix in its list
01487                 // this could be another one than the original file extension
01488                 // so let's try to get the suffix from the file path first
01489                 $suffix = eZFile::suffix( $filePath );
01490                 if ( !$suffix )
01491                 {
01492                     $mimeInfo = eZMimeType::findByName( $entry['mimetype'] );
01493                     $suffix = $mimeInfo['suffix'];
01494                 }
01495                 if ( strlen( $suffix ) > 0 )
01496                     $entry["name"] .= '.' . $suffix;
01497             }
01498 
01499             if ( $file->exists() )
01500             {
01501                 $entry["ctime"] = $file->mtime();
01502                 $entry["mtime"] = $file->mtime();
01503             }
01504         }
01505         else
01506         {
01507             // Here we only show items as folders if they have
01508             // is_container set to true, otherwise it's an unknown binary file
01509             if ( !$class->attribute( 'is_container' ) )
01510             {
01511                 $entry['mimetype'] = 'application/octet-stream';
01512             }
01513         }
01514 
01515         $scriptURL = eZSys::instance()->RequestURI;
01516         if ( strlen( $scriptURL ) > 0 and $scriptURL[ strlen( $scriptURL ) - 1 ] != "/" )
01517             $scriptURL .= "/";
01518 
01519         $trimmedScriptURL = trim( $scriptURL, '/' );
01520         $scriptURLParts = explode( '/', $trimmedScriptURL );
01521 
01522         $siteAccess = $scriptURLParts[0];
01523         $virtualFolder = $scriptURLParts[1];
01524 
01525         $startURL = '/' . $siteAccess . '/' . $virtualFolder . '/';
01526 
01527         // Set the href attribute (note that it doesn't just equal the name).
01528         if ( !isset( $entry['href'] ) )
01529         {
01530             if ( strlen( $suffix ) > 0 )
01531                 $suffix = '.' . $suffix;
01532 
01533             $alias = $node->urlAlias();
01534             if ( $virtualFolder == eZWebDAVContentServer::virtualMediaFolderName() )
01535             {
01536                 // remove the real media node url alias, the virtual media folder is already in $startURL
01537                 $aliasParts = explode( '/', $alias );
01538                 array_shift( $aliasParts );
01539                 $alias = implode( '/', $aliasParts );
01540             }
01541             $entry["href"] = $startURL . $alias . $suffix;
01542         }
01543         // Return array of attributes/properties (name, size, mime, times, etc.).
01544         return $entry;
01545     }
01546 
01547     /*!
01548      @}
01549     */
01550 
01551     /*!
01552       Creates a new folder under the given target node.
01553     */
01554     function createFolder( $parentNode, $target )
01555     {
01556         // Grab settings from the ini file:
01557         $webdavINI = eZINI::instance( eZWebDAVContentServer::WEBDAV_INI_FILE );
01558         $folderClassID = $webdavINI->variable( 'FolderSettings', 'FolderClass' );
01559         $languageCode = eZContentObject::defaultLanguage();
01560 
01561         $contentObject = eZContentObject::createWithNodeAssignment( $parentNode, $folderClassID, $languageCode );
01562         if ( $contentObject )
01563         {
01564             $db = eZDB::instance();
01565             $db->begin();
01566             $version = $contentObject->version( 1 );
01567             $version->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
01568             $version->store();
01569 
01570             $contentObjectID = $contentObject->attribute( 'id' );
01571             $contentObjectAttributes = $version->contentObjectAttributes();
01572 
01573             $contentObjectAttributes[0]->setAttribute( 'data_text', basename( $target ) );
01574             $contentObjectAttributes[0]->store();
01575             $db->commit();
01576 
01577             //include_once( 'lib/ezutils/classes/ezoperationhandler.php' );
01578             $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObjectID,
01579                                                                                          'version' => 1 ) );
01580             return eZWebDAVServer::OK_CREATED;
01581         }
01582         else
01583         {
01584             $this->appendLogEntry( "Not allowed", 'CS:createFolder' );
01585             return eZWebDAVServer::FAILED_FORBIDDEN;
01586         }
01587     }
01588 
01589     /*!
01590       Gets and returns a list of the available sites (from site.ini).
01591     */
01592     function availableSites()
01593     {
01594         // The site list is an array of strings.
01595         $siteList = array();
01596 
01597         // Grab the sitelist from the ini file.
01598         $webdavINI = eZINI::instance();
01599         $siteList = $webdavINI->variable( 'SiteSettings', 'SiteList' );
01600 
01601         // Return the site list.
01602         return $siteList ;
01603     }
01604 
01605     static function virtualContentFolderName()
01606     {
01607         return ezi18n( 'kernel/content', "Content" );
01608     }
01609 
01610     static function virtualMediaFolderName()
01611     {
01612         return ezi18n( 'kernel/content', "Media" );
01613     }
01614 
01615     static function virtualInfoFileName()
01616     {
01617         $infoFile = eZSys::varDirectory() . '/webdav/root/info.txt';
01618         return $infoFile;
01619     }
01620 
01621     /// \privatesection
01622     /// Contains an array with classes that are considered folder
01623     public $FolderClasses;
01624 }
01625 ?>