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