|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZWebDAVServer class 00004 // 00005 // Created on: <01-Aug-2003 13:13:13 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 /*! \file ezwebdavserver.php 00032 WebDAV server base class. 00033 */ 00034 00035 /*! \defgroup eZWebDAV WebDAV system */ 00036 00037 /*! 00038 \class eZWebDAVServer ezwebdavserver.php 00039 \ingroup eZWebDAV 00040 \brief Virtual base class for implementing WebDAV servers. 00041 00042 \todo Add support for propall and propname 00043 */ 00044 00045 //include_once( "lib/ezutils/classes/ezmimetype.php" ); 00046 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00047 00048 /*! 00049 \return \c true if logging is enabled. 00050 \deprecated Use eZWebDAVServer::isLoggingEnabled() instead. 00051 */ 00052 function eZWebDavCheckLogSetting() 00053 { 00054 return eZWebDAVServer::isLoggingEnabled(); 00055 } 00056 00057 /*! 00058 Logs the string \a $logString to the logfile /tmp/webdavlog.txt 00059 if logging is enabled. 00060 \deprecated Appending to log file is now done through appendLogEntry in the webdav server class. 00061 */ 00062 function append_to_log( $logString ) 00063 { 00064 return eZWebDAVServer::appendLogEntry( $logString ); 00065 } 00066 00067 /*! 00068 Logs the string \a $logString to the logfile /tmp/webdavlog.txt 00069 if logging is enabled. 00070 \deprecated Appending to log file is now done through appendLogEntry in the webdav server class. 00071 */ 00072 function eZWebDavAppendToLog( $logString ) 00073 { 00074 return eZWebDAVServer::appendLogEntry( $logString ); 00075 } 00076 00077 class eZWebDAVServer 00078 { 00079 // General status OK return codes: 00080 const OK = 10; 00081 const OK_SILENT = 11; 00082 const OK_CREATED = 12; 00083 const OK_OVERWRITE = 13; 00084 00085 // General status FAILED return codes: 00086 const FAILED_FORBIDDEN = 30; 00087 const FAILED_NOT_FOUND = 31; 00088 const FAILED_EXISTS = 32; 00089 const FAILED_CONFLICT = 33; 00090 const FAILED_PRECONDITION = 34; 00091 const FAILED_LOCKED = 35; 00092 const FAILED_BAD_GATEWAY = 36; 00093 const FAILED_STORAGE_FULL = 37; 00094 const FAILED_UNSUPPORTED = 38; 00095 00096 // File timestamp formats (MUST be correct, or else: Won't work in MSIE...). 00097 // Yes, the two timestamps are actually in different formats. Don't touch! 00098 const CTIME_FORMAT = "Y-m-d\\TH:i:s\\Z"; 00099 const MTIME_FORMAT = "D, d M Y H:i:s"; 00100 00101 // Temporary (uploaded) file stuff: 00102 const TEMP_FILE_PREFIX = "eZWebDAVUpload_"; 00103 00104 /*! Constructor of eZWebDAVServer; 00105 disables PHP error messages. 00106 */ 00107 function eZWebDAVServer() 00108 { 00109 $this->setupXMLOutputCharset(); 00110 } 00111 00112 function setServerRoot( $rootDir ) 00113 { 00114 if ( file_exists ( $rootDir ) ) 00115 { 00116 $this->ServerRootDir = $rootDir; 00117 00118 return true; 00119 } 00120 else 00121 { 00122 return false; 00123 } 00124 } 00125 00126 /*! Server process function. 00127 Dumps a custom header, sets the path and finally 00128 checks what the clients wants. Calls the appropriate 00129 virtual function (based on the client request). 00130 */ 00131 function processClientRequest() 00132 { 00133 $this->appendLogEntry( "WebDAV server started...", 'processClientRequest' ); 00134 $this->XMLBodyRead = false; 00135 00136 // Dump some custom header/info. 00137 $this->headers(); 00138 00139 // Clear file status cache (just in case). 00140 clearstatcache(); 00141 00142 // Convert the requested URI string to non-bogus format. 00143 $target = urldecode( $_SERVER["REQUEST_URI"] ); 00144 $target = $this->processURL( $target ); 00145 00146 $this->appendLogEntry( "----------------------------------------" ); 00147 $this->appendLogEntry( "Client says: " . $_SERVER["REQUEST_METHOD"], 'processClientRequest' ); 00148 $this->appendLogEntry( "Target: " . $_SERVER["REQUEST_URI"], 'processClientRequest' ); 00149 $this->appendLogEntry( "----------------------------------------" ); 00150 00151 $status = eZWebDAVServer::FAILED_NOT_FOUND; 00152 00153 switch ( $_SERVER["REQUEST_METHOD"] ) 00154 { 00155 // OPTIONS (Server ID reply.) 00156 case "OPTIONS": 00157 { 00158 $this->appendLogEntry( "OPTIONS was issued from client.", 'processClientRequest' ); 00159 $options = $this->options( $target ); 00160 $status = $this->outputOptions( $options ); 00161 } break; 00162 00163 // PROPFIND (Show dir/collection content.) 00164 case "PROPFIND": 00165 { 00166 $this->appendLogEntry( "PROPFIND was issued from client.", 'processClientRequest' ); 00167 00168 $depth = $_SERVER['HTTP_DEPTH']; 00169 if ( $depth != 0 and $depth != 1 and $depth != "infinity" ) 00170 $depth = "infinity"; 00171 $this->appendLogEntry( "Depth: $depth.", 'processClientRequest' ); 00172 00173 $xmlBody = $this->xmlBody(); 00174 // Find which properties were requested 00175 // $this->appendLogEntry( $xmlBody, 'xmlbody' ); 00176 $dom = new DOMDocument( '1.0', 'utf-8' ); 00177 $dom->preserveWhiteSpace = false; 00178 $ok = $dom->loadXML( $xmlBody ); 00179 00180 $requestedProperties = array(); 00181 if ( $ok ) 00182 { 00183 $propfindNode = $dom->documentElement; 00184 $propNode = $propfindNode->getElementsByTagName( 'prop' )->item( 0 ); 00185 if ( $propNode ) 00186 { 00187 $propList = $propNode->childNodes; 00188 foreach ( $propList as $node ) 00189 { 00190 $name = $node->localName; 00191 $requestedProperties[] = $name; 00192 } 00193 } 00194 else 00195 { 00196 $allpropNode = $propfindNode->getElementsByTagName( 'allprop' )->item( 0 ); 00197 if ( $allpropNode ) 00198 { 00199 // The server must return all possible properties 00200 $requestedProperties = true; 00201 } 00202 else 00203 { 00204 $propnameNode = $propfindNode->getElementsByTagName( 'propname' )->item( 0 ); 00205 if ( $propnameNode ) 00206 { 00207 // The server must return only the names of all properties 00208 $requestedProperties = false; 00209 } 00210 } 00211 } 00212 } 00213 00214 $collection = $this->getCollectionContent( $target, $depth, $requestedProperties ); 00215 if ( is_array( $collection ) ) 00216 { 00217 $status = $this->outputCollectionContent( $collection, $requestedProperties ); 00218 } 00219 else 00220 { 00221 $status = $collection; 00222 } 00223 } break; 00224 00225 // HEAD (Check if file/resource exists.) 00226 case "HEAD": 00227 { 00228 $this->appendLogEntry( "HEAD was issued from client.", 'processClientRequest' ); 00229 $data = $this->get( $target ); 00230 $status = $this->outputSendDataToClient( $data, true ); 00231 } break; 00232 00233 // GET (Download a file/resource from server to client.) 00234 case "GET": 00235 { 00236 $this->appendLogEntry( "GET was issued from client.", 'processClientRequest' ); 00237 $data = $this->get( $target ); 00238 $status = $this->outputSendDataToClient( $data ); 00239 } break; 00240 00241 // PUT (Upload a file/resource from client to server.) 00242 case "PUT": 00243 { 00244 $this->appendLogEntry( "PUT was issued from client.", 'processClientRequest' ); 00245 $status = eZWebDAVServer::OK_CREATED; 00246 00247 // Attempt to get file/resource sent from client/browser. 00248 $tempFile = $this->storeUploadedFile( $target ); 00249 00250 // If there was an actual file: 00251 if ( $tempFile ) 00252 { 00253 // Attempt to do something with it (copy/whatever). 00254 $status = $this->put( $target, $tempFile ); 00255 00256 unlink( $tempFile ); 00257 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00258 eZDir::cleanupEmptyDirectories( dirname( $tempFile ) ); 00259 } 00260 // Else: something went wrong... 00261 else 00262 { 00263 $status = eZWebDAVServer::FAILED_FORBIDDEN; 00264 } 00265 00266 } break; 00267 00268 // MKCOL (Create a directory/collection.) 00269 case "MKCOL": 00270 { 00271 $this->appendLogEntry( "MKCOL was issued from client.", 'processClientRequest' ); 00272 if ( strlen( $this->xmlBody() ) > 0 ) 00273 { 00274 $this->appendLogEntry( "MKCOL body error.", 'processClientRequest' ); 00275 $status = eZWebDAVServer::FAILED_FORBIDDEN; 00276 } 00277 else 00278 { 00279 $status = $this->mkcol( $target ); 00280 } 00281 } break; 00282 00283 // COPY (Copy a resource/collection from one location to another.) 00284 case "COPY": 00285 { 00286 $this->appendLogEntry( "COPY was issued from client.", 'processClientRequest' ); 00287 00288 $source = $target; 00289 $url = parse_url( $_SERVER["HTTP_DESTINATION"] ); 00290 $destination = urldecode( $url["path"] ); 00291 $destination = $this->processURL( $destination ); 00292 $status = $this->copy( $source, $destination ); 00293 } break; 00294 00295 // MOVE (Move a resource/collection from one location to another.) 00296 case "MOVE": 00297 { 00298 $this->appendLogEntry( "MOVE was issued from client.", 'processClientRequest' ); 00299 $source = $target; 00300 $url = parse_url( $_SERVER["HTTP_DESTINATION"] ); 00301 $destination = urldecode( $url["path"] ); 00302 $destination = $this->processURL( $destination ); 00303 $status = $this->move( $source, $destination ); 00304 } break; 00305 00306 // DELETE (Remove a resource/collection.) 00307 case "DELETE": 00308 { 00309 $this->appendLogEntry( "DELETE was issued from client.", 'processClientRequest' ); 00310 $status = $this->delete( $target ); 00311 } break; 00312 00313 // Default case: unknown command from client. 00314 default: 00315 { 00316 // __FIX_ME__ 00317 } break; 00318 } 00319 // Read the XML body if it is not used yet, 00320 // PHP should discard it but it's a bug in some PHP versions 00321 if ( !$this->XMLBodyRead ) 00322 $this->flushXMLBody(); 00323 00324 // Handle the returned status code (post necessary/matching headers, etc.). 00325 $this->handle( $status ); 00326 } 00327 00328 /*! 00329 \protected 00330 Generates HTTP headers with information on what the server supports. 00331 \param $options An array with the various options the server supports 00332 - methods - An array with methods it can handle, 00333 if not supplied it will report all possible methods. 00334 - versions - An array with versions this server supports, 00335 if not supplied it will return 1,2,<http://apache.org/dav/propset/fs/1>. 00336 \return The WebDAV status code 00337 */ 00338 function outputOptions( $options ) 00339 { 00340 // Default options 00341 $methods = array( 'OPTIONS', 'GET', 'HEAD', 'POST', 'DELETE', 'TRACE', 'PROPFIND', 'PROPPATCH', 'COPY', 'MOVE', 'LOCK', 'UNLOCK' ); 00342 $versions = array( '1', '2', '<http://apache.org/dav/propset/fs/1>' ); 00343 00344 if ( isset( $options['methods'] ) ) 00345 $methods = $options['methods']; 00346 if ( isset( $options['versions'] ) ) 00347 $versions = $options['versions']; 00348 00349 header( 'Content-Length: 0' ); 00350 header( 'MS-Author-Via: DAV' ); 00351 header( 'Allow: ' . implode( ', ', $methods ) ); 00352 header( 'DAV: ' . implode( ',', $versions ) ); 00353 header( 'Content-Type: text/plain; charset=iso-8859-1' ); 00354 00355 return eZWebDAVServer::OK_SILENT; 00356 } 00357 00358 /*! 00359 \protected 00360 Generates the WebDAV XML from \a $collection and outputs using print(). 00361 \param $collection An array with elements (e.g dirs/files). 00362 Each element consists of: 00363 - ctime - The timestamp when the element was created 00364 - mtime - The timestamp when the element was last modified 00365 - mimetype - The type of element, use httpd/unix-directory for folder like entries 00366 - href - URL which points to the element 00367 - name - The name of the element 00368 - size - The size of the element in bytes, not needed for folders 00369 \return The WebDAV status code 00370 */ 00371 function outputCollectionContent( $collection, $requestedProperties ) 00372 { 00373 // Sanity check & action: if client forgot to ask, we'll still 00374 // play along revealing some basic/default properties. This is 00375 // necessary to make it work with Windows XP + SP2. 00376 if( !is_array( $requestedProperties ) || count( $requestedProperties ) == 0 ) 00377 { 00378 $requestedProperties = array( 'displayname', 00379 'creationdate', 00380 'getlastmodified', 00381 'getcontenttype', 00382 'getcontentlength', 00383 'resourcetype' ); 00384 } 00385 00386 // Fix for CaDAVer (text based linux client) -> error if not revealed. 00387 // Apparently it does not mess up for other clients so I'll just leave 00388 // it without wrapping it inside a client-specific check. 00389 if( !in_array( 'getcontenttype', $requestedProperties ) ) 00390 { 00391 $requestedProperties[] = 'getcontenttype'; 00392 } 00393 00394 $this->appendLogEntry( 'Client requested ' . 00395 count( $requestedProperties ) . 00396 ' properties.', 'outputCollectionContent' ); 00397 00398 $dataCharset = eZWebDAVServer::dataCharset(); 00399 $xmlCharset = $this->XMLOutputCharset(); 00400 00401 $xmlText = "<?xml version=\"1.0\" encoding=\"$xmlCharset\"?>\n" . 00402 "<D:multistatus xmlns:D=\"DAV:\">\n"; 00403 00404 // Maps from WebDAV property names to internal names 00405 $nameMap = array( 'displayname' => 'name', 00406 'creationdate' => 'ctime', 00407 'getlastmodified' => 'mtime', 00408 'getcontenttype' => 'mimetype', 00409 'getcontentlength' => 'size' ); 00410 00411 foreach ( $requestedProperties as $requestedProperty ) 00412 { 00413 if ( !isset( $nameMap[$requestedProperty] ) ) 00414 $nameMap[$requestedProperty] = $requestedProperty; 00415 } 00416 00417 // Misc helpful debug info (use when things go wrong..) 00418 //$this->appendLogEntry( var_dump( $requestedProperties ), 'outputCollectionContent' ); 00419 //$this->appendLogEntry( var_dump( $nameMap ), 'outputCollectionContent' ); 00420 //$this->appendLogEntry( var_dump( $collection ), 'outputCollectionContent' ); 00421 00422 // For all the entries in this dir/collection-array: 00423 foreach ( $collection as $entry ) 00424 { 00425 // Translate the various UNIX timestamps to WebDAV format: 00426 $creationTime = date( eZWebDAVServer::CTIME_FORMAT, $entry['ctime'] ); 00427 $modificationTime = date( eZWebDAVServer::MTIME_FORMAT, $entry['mtime'] ); 00428 00429 // The following lines take care of URL encoding special characters 00430 // for each element (stuff between slashes) in the path. 00431 $href = $entry['href']; 00432 $pathArray = split( '/', eZWebDAVServer::recode( "$href", $dataCharset, $xmlCharset ) ); 00433 00434 $encodedPath = '/'; 00435 00436 foreach( $pathArray as $pathElement ) 00437 { 00438 if( $pathElement != '' ) 00439 { 00440 $encodedPath .= rawurlencode( $pathElement ); 00441 $encodedPath .= '/'; 00442 } 00443 } 00444 00445 $isCollection = $entry['mimetype'] == 'httpd/unix-directory'; 00446 00447 // If this is not a collection, don't leave a trailing '/' 00448 // on the href. If you do, Goliath gets confused. 00449 if ( !$isCollection ) 00450 $encodedPath = rtrim($encodedPath, '/'); 00451 00452 $xmlText .= "<D:response>\n" . 00453 " <D:href>" . $encodedPath ."</D:href>\n" . 00454 " <D:propstat>\n" . 00455 " <D:prop>\n"; 00456 00457 $unknownProperties = array(); 00458 00459 foreach ( $requestedProperties as $requestedProperty ) 00460 { 00461 $name = $nameMap[$requestedProperty]; 00462 if ( isset( $entry[$name] ) ) 00463 { 00464 if ( $requestedProperty == 'creationdate' ) 00465 { 00466 $creationTime = date( eZWebDAVServer::CTIME_FORMAT, $entry['ctime'] ); 00467 $xmlText .= " <D:" . $requestedProperty . ">" . $creationTime . "</D:" . $requestedProperty . ">\n"; 00468 } 00469 else if ( $requestedProperty == 'getlastmodified' ) 00470 { 00471 $modificationTime = date( eZWebDAVServer::MTIME_FORMAT, $entry['mtime'] ); 00472 $xmlText .= " <D:" . $requestedProperty . ">" . $modificationTime . "</D:" . $requestedProperty . ">\n"; 00473 } 00474 else if ( $isCollection and $requestedProperty == 'getcontenttype' ) 00475 { 00476 00477 $xmlText .= ( " <D:resourcetype>\n" . 00478 " <D:collection />\n" . 00479 " </D:resourcetype>\n" ); 00480 00481 $unknownProperties[] = $requestedProperty; 00482 } 00483 else 00484 { 00485 $xmlText .= " <D:" . $requestedProperty . ">" . htmlspecialchars( eZWebDAVServer::recode( "$entry[$name]", $dataCharset, $xmlCharset ) ) . "</D:" . $requestedProperty . ">\n"; 00486 } 00487 } 00488 else if ( $requestedProperty != 'resourcetype' or !$isCollection ) 00489 { 00490 $unknownProperties[] = $requestedProperty; 00491 } 00492 } 00493 00494 $xmlText .= ( " <D:lockdiscovery/>\n" ); 00495 00496 $xmlText .= ( " </D:prop>\n" . 00497 " <D:status>HTTP/1.1 200 OK</D:status>\n" . 00498 " </D:propstat>\n" ); 00499 00500 00501 // List the non supported properties and mark with 404 00502 // This behavior (although recommended/standard) might 00503 // confuse some clients. Try commenting out if necessary... 00504 00505 $xmlText .= " <D:propstat>\n"; 00506 $xmlText .= " <D:prop>\n"; 00507 foreach ( $unknownProperties as $unknownProperty ) 00508 { 00509 $xmlText .= " <D:" . $unknownProperty . " />\n"; 00510 } 00511 $xmlText .= " </D:prop>\n"; 00512 $xmlText .= " <D:status>HTTP/1.1 404 Not Found</D:status>\n"; 00513 $xmlText .= " </D:propstat>\n"; 00514 00515 $xmlText .= "</D:response>\n"; 00516 } 00517 00518 $xmlText .= "</D:multistatus>\n"; 00519 // Send the necessary headers... 00520 header( 'HTTP/1.1 207 Multi-Status' ); 00521 header( 'Content-Type: text/xml' ); 00522 00523 // Comment out the next line if you don't 00524 // want to use chunked transfer encoding. 00525 //header( 'Content-Length: '.strlen( $xmlText ) ); 00526 00527 $text = @ob_get_contents(); 00528 if ( strlen( $text ) != 0 ) 00529 $this->appendLogEntry( $text, "DAV: PHP Output" ); 00530 while ( @ob_end_clean() ); 00531 00532 // Dump XML response (from server to client to logfile. 00533 //$this->appendLogEntry( $xmlText, 'xmlText' ); 00534 00535 // Dump the actual XML data containing collection list. 00536 print( $xmlText ); 00537 00538 $dom = new DOMDocument( '1.0', 'utf-8' ); 00539 $success = $dom->loadXML( $xmlText ); 00540 if ( $success ) 00541 $this->appendLogEntry( "XML was parsed", 'outputCollectionContent' ); 00542 else 00543 $this->appendLogEntry( "XML was NOT parsed $xmlText", 'outputCollectionContent' ); 00544 00545 // If we got this far: everything is OK. 00546 return eZWebDAVServer::OK_SILENT; 00547 } 00548 00549 /*! 00550 \protected 00551 Outputs the data \a $output using print(). 00552 \param $output Is an array which can contain: 00553 - data - String or byte data 00554 - file - The path to the file, the contents of the file will be output 00555 \return The WebDAV status code 00556 */ 00557 function outputSendDataToClient( $output, $headers_only = false ) 00558 { 00559 if ( !$output ) 00560 { 00561 $this->appendLogEntry( "outputData: no data available", 'outputSendDataToClient' ); 00562 return eZWebDAVServer::FAILED_NOT_FOUND; 00563 } 00564 00565 // Check if we are dealing with custom data. 00566 if ( $output["data"] ) 00567 { 00568 $this->appendLogEntry( "outputData: DATA is a string...", 'outputSendDataToClient' ); 00569 } 00570 // Else: we need to output a file. 00571 elseif ( $output["file"] ) 00572 { 00573 $this->appendLogEntry( "outputData: DATA is a file...", 'outputSendDataToClient' ); 00574 $realPath = $output["file"]; 00575 00576 // Check if the file/dir actually exists and is readable (permission): 00577 if ( ( file_exists( $realPath ) ) && ( is_readable( $realPath ) ) ) 00578 { 00579 $this->appendLogEntry( "outputData: file exists on server...", 'outputSendDataToClient' ); 00580 00581 // Get misc. file info. 00582 $eTag = md5_file( $realPath ); 00583 $size = filesize( $realPath ); 00584 00585 $dir = dirname( $realPath ); 00586 $file = basename( $realPath ); 00587 00588 $mimeInfo = eZMimeType::findByURL( $dir . '/' . $file ); 00589 $mimeType = $mimeInfo['name']; 00590 00591 // Send necessary headers to client. 00592 header( 'HTTP/1.1 200 OK' ); 00593 header( 'Accept-Ranges: bytes' ); 00594 header( 'Content-Length: '.$size ); 00595 header( 'Content-Type: '.$mimeType ); 00596 header( 'ETag: '.$eTag ); 00597 00598 $text = @ob_get_contents(); 00599 if ( strlen( $text ) != 0 ) 00600 $this->appendLogEntry( $text, "DAV: PHP Output" ); 00601 while ( @ob_end_clean() ); 00602 00603 if ( !$headers_only ) 00604 { 00605 // Attempt to open the file. 00606 $fp = fopen( $realPath, "rb" ); 00607 00608 // Output the actual contents of the file. 00609 $status = fpassthru( $fp ); 00610 00611 // Check if the last command succeded.. 00612 if ( $status == $size) 00613 { 00614 return eZWebDAVServer::OK_SILENT; 00615 } 00616 else 00617 { 00618 return eZWebDAVServer::FAILED_FORBIDDEN; 00619 } 00620 } 00621 else 00622 { 00623 return eZWebDAVServer::OK_SILENT; 00624 } 00625 } 00626 // Else: file/dir doesn't exist! 00627 else 00628 { 00629 $this->appendLogEntry( "outputData: file DOES NOT exists on server...", 'outputSendDataToClient' ); 00630 return eZWebDAVServer::FAILED_NOT_FOUND; 00631 } 00632 } 00633 else 00634 { 00635 $this->appendLogEntry( "outputData: No file specified", 'outputSendDataToClient' ); 00636 00637 $text = @ob_get_contents(); 00638 if ( strlen( $text ) != 0 ) 00639 $this->appendLogEntry( $text, "DAV: PHP Output" ); 00640 while ( @ob_end_clean() ); 00641 00642 return eZWebDAVServer::FAILED_NOT_FOUND; 00643 } 00644 } 00645 00646 /*! 00647 \protected 00648 Will try to store the uploaded to a temporary location using \a $target 00649 for name. 00650 \return The name of the temp file or \c false if it failed. 00651 */ 00652 function storeUploadedFile( $target ) 00653 { 00654 $dir = eZWebDAVServer::tempDirectory() . '/' . md5( microtime() . '-' . $target ); 00655 $filePath = $dir . '/' . basename( $target ); 00656 00657 if ( !file_exists( $dir ) ) 00658 { 00659 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00660 eZDir::mkdir( $dir, false, true ); 00661 } 00662 00663 $result = copy( "php://input", $filePath ); 00664 if ( !$result ) 00665 { 00666 $result = file_exists( $filePath ); 00667 } 00668 00669 if ( $result ) 00670 { 00671 header( "HTTP/1.1 201 Created" ); 00672 return $filePath; 00673 } 00674 return false; 00675 } 00676 00677 /*! 00678 \return The XML body text for the current request. 00679 */ 00680 function xmlBody() 00681 { 00682 $xmlBody = file_get_contents( "php://input" ); 00683 // $this->appendLogEntry( $xmlBody, 'xmlBody' ); 00684 $this->XMLBodyRead = true; 00685 return $xmlBody; 00686 } 00687 00688 /*! 00689 \return The XML body text for the current request. 00690 */ 00691 function flushXMLBody() 00692 { 00693 // Flush the XML body by reading it, 00694 // PHP should discard it but it's a bug in some PHP versions 00695 $xmlBody = file_get_contents( "php://input" ); 00696 } 00697 00698 /*! 00699 \protected 00700 This method will be called on all intercepted URLs and can be reimplemented 00701 to clean up the URL for further processing. 00702 A typical usage is when the server is running without rewrite rules and will 00703 have the .php file in the path. 00704 \return The new URL which can safely be passed to the operation methods. 00705 */ 00706 function processURL( $url ) 00707 { 00708 return $url; 00709 } 00710 00711 /*! 00712 \protected 00713 This is called before each each request is processed and can be used to output 00714 some common headers. 00715 */ 00716 function headers() 00717 { 00718 } 00719 00720 /*! 00721 \virtual 00722 Reports WebDAV options which information on what the server supports. 00723 \return An associative array with options, can contain: 00724 - methods - An array with methods it can handle, 00725 if not supplied it will use all possible methods. 00726 - versions - An array with versions this server supports, 00727 if not supplied it will use 1,2,<http://apache.org/dav/propset/fs/1>. 00728 */ 00729 function options( $target ) 00730 { 00731 } 00732 00733 /*! 00734 \virtual 00735 \return An array with elements that belongs to the collection \a $collection 00736 \param $depth The current depth, \c 0 for only current object, \c 1 for it's children 00737 \param $properties Which properties the client asked for, either an array with DAV 00738 property names, \c true for all properties or \c false for only property names. 00739 */ 00740 function getCollectionContent( $collection, $depth = false, $properties = false ) 00741 { 00742 } 00743 00744 /*! 00745 \virtual 00746 \return Information on a given element 00747 */ 00748 function head( $target ) 00749 { 00750 } 00751 00752 /*! 00753 \virtual 00754 Fetches the data for the element \a $target 00755 \return The contents of a given element, e.g. contents of a file. 00756 */ 00757 function get( $target ) 00758 { 00759 } 00760 00761 /*! 00762 \virtual 00763 Tries to create/overwrite an element named \a $target with contents taken from \a $tempFile. 00764 \return The WebDAV status code 00765 */ 00766 function put( $target, $tempFile ) 00767 { 00768 } 00769 00770 /*! 00771 \virtual 00772 Create a new collection (folder) named \a $target. 00773 \return The WebDAV status code 00774 */ 00775 function mkcol( $target ) 00776 { 00777 } 00778 00779 /*! 00780 \virtual 00781 Copies the element \a $source to destination \a $destination 00782 \return The WebDAV status code 00783 */ 00784 function copy( $source, $destination ) 00785 { 00786 } 00787 00788 /*! 00789 \virtual 00790 Moves the element \a $source to destination \a $destination 00791 \return The WebDAV status code 00792 */ 00793 function move( $source, $destination ) 00794 { 00795 } 00796 00797 /*! 00798 \virtual 00799 Removes the element \a $target. 00800 \return The WebDAV status code 00801 */ 00802 function delete( $target ) 00803 { 00804 } 00805 00806 /*! 00807 \protected 00808 Handles return values and sends necessary/corresponding headers. 00809 */ 00810 function handle( $status ) 00811 { 00812 $this->appendLogEntry( "handle function was called with status: $status", 'handle' ); 00813 00814 // Check and translate status to HTTP:WebDAV reply. 00815 switch ( $status ) 00816 { 00817 // OK. 00818 case eZWebDAVServer::OK: 00819 { 00820 header( "HTTP/1.1 200 OK" ); 00821 } break; 00822 00823 // OK, SILENT. 00824 case eZWebDAVServer::OK_SILENT: 00825 { 00826 // Do nothing... 00827 } break; 00828 00829 // OK, CREATED. 00830 case eZWebDAVServer::OK_CREATED: 00831 { 00832 header( "HTTP/1.1 201 Created" ); 00833 } break; 00834 00835 // OK, OVERWRITE. 00836 case eZWebDAVServer::OK_OVERWRITE: 00837 { 00838 header( "HTTP/1.1 204 No Content"); 00839 } break; 00840 00841 // FAILED, FORBIDDEN! 00842 case eZWebDAVServer::FAILED_FORBIDDEN: 00843 { 00844 header( "HTTP/1.1 403 Forbidden"); 00845 } break; 00846 00847 // FAILED, NOT FOUND! 00848 case eZWebDAVServer::FAILED_NOT_FOUND: 00849 { 00850 header( "HTTP/1.1 404 Not Found" ); 00851 } break; 00852 00853 // FAILED, ALREADY EXISTS! 00854 case eZWebDAVServer::FAILED_EXISTS: 00855 { 00856 header( "HTTP/1.1 405 Method not allowed" ); 00857 } break; 00858 00859 // FAILED, CONFLICT! 00860 case eZWebDAVServer::FAILED_CONFLICT: 00861 { 00862 header( "HTTP/1.1 409 Conflict" ); 00863 }break; 00864 00865 // FAILED, PRECONDITION. 00866 case eZWebDAVServer::FAILED_PRECONDITION: 00867 { 00868 header( "HTTP/1.1 412 Precondition Failed" ); 00869 } break; 00870 00871 // FAILED, RESOURCE IS LOCKED! 00872 case eZWebDAVServer::FAILED_LOCKED: 00873 { 00874 header( "HTTP/1.1 423 Locked" ); 00875 } break; 00876 00877 // FAILED, BAD GATEWAY! 00878 case eZWebDAVServer::FAILED_BAD_GATEWAY: 00879 { 00880 header( "HTTP/1.1 502 Bad Gateway" ); 00881 } break; 00882 00883 // FAILED, NO SPACE LEFT ON DEVICE! 00884 case eZWebDAVServer::FAILED_STORAGE_FULL: 00885 { 00886 header( "HTTP/1.1 507 Insufficient Storage" ); 00887 } break; 00888 00889 // FAILED, UNSUPPORTED REQUEST! 00890 case eZWebDAVServer::FAILED_UNSUPPORTED: 00891 { 00892 header( "HTTP/1.1 415 Unsupported Media Type" ); 00893 } break; 00894 00895 // Default case: something went wrong... 00896 default: 00897 { 00898 $this->appendLogEntry( "HTTP 500, THIS SHOULD NOT HAPPEN!", 'handle' ); 00899 header( "HTTP/1.1 500 Internal Server Error" ); 00900 } break; 00901 } 00902 00903 $text = @ob_get_contents(); 00904 if ( strlen( $text ) != 0 ) 00905 $this->appendLogEntry( $text, "DAV: PHP Output" ); 00906 while ( @ob_end_clean() ); 00907 } 00908 00909 /*! 00910 Logs the string \a $logString to the logfile webdav.log 00911 in the current log directory (usually var/log). 00912 If logging is disabled, nothing is done. 00913 */ 00914 static function appendLogEntry( $logString, $label = false ) 00915 { 00916 if ( !eZWebDAVServer::isLoggingEnabled() ) 00917 return false; 00918 00919 $varDir = eZSys::varDirectory(); 00920 00921 $logDir = 'log'; 00922 $logName = 'webdav.log'; 00923 $fileName = $varDir . '/' . $logDir . '/' . $logName; 00924 if ( !file_exists( $varDir . '/' . $logDir ) ) 00925 { 00926 //include_once( 'lib/ezfile/classes/ezdir.php' ); 00927 eZDir::mkdir( $varDir . '/' . $logDir, false, true ); 00928 } 00929 00930 $logFile = fopen( $fileName, 'a' ); 00931 $nowTime = date( "Y-m-d H:i:s : " ); 00932 $text = $nowTime . $logString; 00933 if ( $label ) 00934 $text .= ' [' . $label . ']'; 00935 fwrite( $logFile, $text . "\n" ); 00936 fclose( $logFile ); 00937 } 00938 00939 /*! 00940 \static 00941 \return \c true if WebDAV logging is enabled. 00942 */ 00943 static function isLoggingEnabled() 00944 { 00945 $useLogging =& $GLOBALS['eZWebDavLogging']; 00946 if ( !isset( $useLogging ) ) 00947 { 00948 $ini = eZINI::instance( 'webdav.ini' ); 00949 $useLogging = $ini->variable( 'GeneralSettings', 'Logging' ) == 'enabled'; 00950 } 00951 return $useLogging; 00952 } 00953 00954 /*! 00955 Sets charset for outputted xml by 'userAgent' 00956 */ 00957 function setupXMLOutputCharset() 00958 { 00959 $charset = eZWebDAVServer::dataCharset(); 00960 00961 $userAgent = isset( $_SERVER['HTTP_USER_AGENT'] ) ? $_SERVER['HTTP_USER_AGENT'] : false; 00962 $pattern = eZWebDAVServer::userAgentPattern(); 00963 $userAgentSettings = eZWebDAVServer::userAgentSettings(); 00964 00965 if ( preg_match( $pattern, $userAgent, $matches ) && isset( $userAgentSettings[$matches[0]] ) ) 00966 { 00967 $agentSettings = $userAgentSettings[$matches[0]]; 00968 if ( isset( $agentSettings['xmlCharset'] ) && $agentSettings['xmlCharset'] != '' ) 00969 $charset = $agentSettings['xmlCharset']; 00970 } 00971 00972 $this->setXMLOutputCharset( $charset ); 00973 } 00974 00975 /*! 00976 Sets charset for outputted xml. 00977 */ 00978 function setXMLOutputCharset( $charset ) 00979 { 00980 if ( $charset == '' ) 00981 { 00982 $this->appendLogEntry( "Error: unable to set empty charset for outputted xml.", 'setXMLOutputCharset' ); 00983 return false; 00984 } 00985 00986 $this->XMLOutputCharset = $charset; 00987 return true; 00988 } 00989 00990 /*! 00991 \return charset for outputted xml 00992 */ 00993 function XMLOutputCharset() 00994 { 00995 return $this->XMLOutputCharset; 00996 } 00997 00998 /*! 00999 \static 01000 \return charset of data. It's used as charset for outputted xml if 01001 other charset is not specified in 'userAgentSettings'. 01002 */ 01003 function dataCharset() 01004 { 01005 $ini = eZINI::instance( 'i18n.ini' ); 01006 $charset = $ini->variable('CharacterSettings', 'Charset' ); 01007 return $charset; 01008 } 01009 01010 /*! 01011 \static 01012 \return pattern for 'preg_match'. The pattern is built from 'userAgentSettings'. 01013 */ 01014 function userAgentPattern() 01015 { 01016 $pattern = '//'; 01017 01018 $userAgentSettings = eZWebDAVServer::userAgentSettings(); 01019 if( count( $userAgentSettings ) > 0 ) 01020 { 01021 $pattern = '/'; 01022 01023 foreach( $userAgentSettings as $agent => $settings ) 01024 $pattern .= $agent . '|'; 01025 01026 $pattern[strlen($pattern)-1] = '/'; 01027 } 01028 01029 return $pattern; 01030 } 01031 01032 /*! 01033 \static 01034 \return a list of different settings for known user-agents. 01035 */ 01036 function userAgentSettings() 01037 { 01038 return array( 'WebDrive' => array( 'xmlCharset' => 'utf-8' ), 01039 'Microsoft Data Access Internet Publishing Provider' => array( 'xmlCharset' => 'utf-8' ) 01040 ); 01041 } 01042 01043 /*! 01044 \static 01045 \return recoded \a $string form \a $fromCharset to \a $toCharset 01046 */ 01047 function recode( $string, $fromCharset, $toCharset, $stop = false ) 01048 { 01049 //include_once( 'lib/ezi18n/classes/eztextcodec.php' ); 01050 $codec = eZTextCodec::instance( $fromCharset, $toCharset, false ); 01051 if ( $codec ) 01052 $string = $codec->convertString( $string ); 01053 01054 return $string; 01055 } 01056 01057 /*! 01058 \static 01059 \return the path to the WebDAV temporary directory 01060 01061 If the directory does not exist yet, it will be created first. 01062 */ 01063 static function tempDirectory() 01064 { 01065 $tempDir = eZSys::varDirectory() . '/webdav/tmp'; 01066 if ( !file_exists( $tempDir ) ) 01067 { 01068 eZDir::mkdir( $tempDir, false, true ); 01069 } 01070 return $tempDir; 01071 } 01072 01073 /* 01074 \static 01075 \return the path to the WebDAV root directory 01076 01077 If the directory does not exist yet, it will be created first. 01078 */ 01079 static function rootDirectory() 01080 { 01081 $rootDir = eZSys::varDirectory() . '/webdav/root'; 01082 if ( !file_exists( $rootDir ) ) 01083 { 01084 eZDir::mkdir( $rootDir, false, true ); 01085 } 01086 return $rootDir; 01087 } 01088 01089 /// \privatesection 01090 public $ServerRootDir = ""; 01091 public $XMLBodyRead = false; 01092 public $XMLOutputCharset = 'utf-8'; 01093 } 01094 ?>