2012-03-23 21:54:38 +04:00
< ? php
/**
* Copyright ( c ) 2012 Robin Appelman < icewind @ owncloud . com >
* This file is licensed under the Affero General Public License version 3 or
* later .
* See the COPYING - README file .
*/
2012-09-07 20:30:48 +04:00
namespace OC\Files\Storage ;
2014-03-04 18:44:58 +04:00
class DAV extends \OC\Files\Storage\Common {
2012-03-23 21:54:38 +04:00
private $password ;
private $user ;
private $host ;
private $secure ;
private $root ;
2013-12-15 20:22:52 +04:00
private $certPath ;
2012-10-22 00:04:45 +04:00
private $ready ;
2012-03-23 21:54:38 +04:00
/**
2012-10-12 01:17:59 +04:00
* @ var \Sabre_DAV_Client
2012-03-23 21:54:38 +04:00
*/
private $client ;
2014-03-04 18:44:58 +04:00
private static $tempFiles = array ();
2012-08-29 10:42:49 +04:00
2013-05-25 19:10:20 +04:00
/**
* check if curl is installed
*/
public static function checkDependencies () {
if ( function_exists ( 'curl_init' )) {
return true ;
} else {
$l = new \OC_L10N ( 'files_external' );
2013-05-30 19:37:47 +04:00
return $l -> t ( '<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting of ownCloud / WebDAV is not possible. Please ask your system administrator to install it.' );
2013-05-25 19:10:20 +04:00
}
}
2012-09-07 17:22:01 +04:00
public function __construct ( $params ) {
2012-12-24 22:45:52 +04:00
if ( isset ( $params [ 'host' ]) && isset ( $params [ 'user' ]) && isset ( $params [ 'password' ])) {
$host = $params [ 'host' ];
//remove leading http[s], will be generated in createBaseUri()
if ( substr ( $host , 0 , 8 ) == " https:// " ) $host = substr ( $host , 8 );
else if ( substr ( $host , 0 , 7 ) == " http:// " ) $host = substr ( $host , 7 );
2014-03-04 18:44:58 +04:00
$this -> host = $host ;
$this -> user = $params [ 'user' ];
$this -> password = $params [ 'password' ];
2012-12-24 22:45:52 +04:00
if ( isset ( $params [ 'secure' ])) {
if ( is_string ( $params [ 'secure' ])) {
$this -> secure = ( $params [ 'secure' ] === 'true' );
} else {
$this -> secure = ( bool ) $params [ 'secure' ];
}
2012-11-30 19:27:11 +04:00
} else {
2012-12-24 22:45:52 +04:00
$this -> secure = false ;
}
2013-12-15 20:22:52 +04:00
if ( $this -> secure === true ) {
2014-03-04 18:44:58 +04:00
$certPath = \OC_User :: getHome ( \OC_User :: getUser ()) . '/files_external/rootcerts.crt' ;
2013-12-15 20:22:52 +04:00
if ( file_exists ( $certPath )) {
2014-03-04 18:44:58 +04:00
$this -> certPath = $certPath ;
2013-12-15 20:22:52 +04:00
}
}
2014-03-04 18:44:58 +04:00
$this -> root = isset ( $params [ 'root' ]) ? $params [ 'root' ] : '/' ;
if ( ! $this -> root || $this -> root [ 0 ] != '/' ) {
$this -> root = '/' . $this -> root ;
2012-12-24 22:45:52 +04:00
}
2014-03-04 18:44:58 +04:00
if ( substr ( $this -> root , - 1 , 1 ) != '/' ) {
$this -> root .= '/' ;
2012-11-05 19:39:03 +04:00
}
2012-11-30 19:27:11 +04:00
} else {
2013-02-12 05:27:05 +04:00
throw new \Exception ();
2012-03-23 21:54:38 +04:00
}
2012-10-22 00:04:45 +04:00
}
2014-03-04 18:44:58 +04:00
private function init () {
if ( $this -> ready ) {
2012-10-22 00:04:45 +04:00
return ;
}
$this -> ready = true ;
2012-08-29 10:42:49 +04:00
2013-12-17 12:38:43 +04:00
$settings = array (
'baseUri' => $this -> createBaseUri (),
'userName' => $this -> user ,
'password' => $this -> password ,
);
2012-03-23 21:54:38 +04:00
2013-01-15 17:57:23 +04:00
$this -> client = new \Sabre_DAV_Client ( $settings );
2012-08-29 10:42:49 +04:00
2013-12-17 12:38:43 +04:00
if ( $this -> secure === true && $this -> certPath ) {
2013-12-15 20:22:52 +04:00
$this -> client -> addTrustedCertificates ( $this -> certPath );
2012-07-09 12:19:19 +04:00
}
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
public function getId () {
2012-10-12 01:06:57 +04:00
return 'webdav::' . $this -> user . '@' . $this -> host . '/' . $this -> root ;
2012-03-23 21:54:38 +04:00
}
2013-10-09 18:54:36 +04:00
protected function createBaseUri () {
2014-03-04 18:44:58 +04:00
$baseUri = 'http' ;
2012-11-30 19:27:11 +04:00
if ( $this -> secure ) {
2014-03-04 18:44:58 +04:00
$baseUri .= 's' ;
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
$baseUri .= '://' . $this -> host . $this -> root ;
2012-03-23 21:54:38 +04:00
return $baseUri ;
}
2012-09-07 17:22:01 +04:00
public function mkdir ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-10-29 02:58:08 +04:00
return $this -> simpleResponse ( 'MKCOL' , $path , null , 201 );
2012-03-23 21:54:38 +04:00
}
2012-09-07 17:22:01 +04:00
public function rmdir ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path ) . '/' ;
2014-01-31 19:06:11 +04:00
// FIXME: some WebDAV impl return 403 when trying to DELETE
// a non-empty folder
2012-10-29 02:58:08 +04:00
return $this -> simpleResponse ( 'DELETE' , $path , null , 204 );
2012-03-23 21:54:38 +04:00
}
2012-09-07 17:22:01 +04:00
public function opendir ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$response = $this -> client -> propfind ( $this -> encodePath ( $path ), array (), 1 );
$id = md5 ( 'webdav' . $this -> root . $path );
2013-01-28 18:34:15 +04:00
$content = array ();
2014-03-04 18:44:58 +04:00
$files = array_keys ( $response );
array_shift ( $files ); //the first entry is the current directory
2012-11-30 19:27:11 +04:00
foreach ( $files as $file ) {
2012-06-29 21:00:41 +04:00
$file = urldecode ( basename ( $file ));
2014-03-04 18:44:58 +04:00
$content [] = $file ;
2012-03-23 21:54:38 +04:00
}
2013-01-28 18:34:15 +04:00
\OC\Files\Stream\Dir :: register ( $id , $content );
2014-03-04 18:44:58 +04:00
return opendir ( 'fakedir://' . $id );
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
2012-09-07 17:22:01 +04:00
public function filetype ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$response = $this -> client -> propfind ( $this -> encodePath ( $path ), array ( '{DAV:}resourcetype' ));
2014-01-31 19:06:11 +04:00
$responseType = array ();
if ( isset ( $response [ " { DAV:}resourcetype " ])) {
2014-03-04 18:44:58 +04:00
$responseType = $response [ " { DAV:}resourcetype " ] -> resourceType ;
2014-01-31 19:06:11 +04:00
}
2014-03-04 18:44:58 +04:00
return ( count ( $responseType ) > 0 and $responseType [ 0 ] == " { DAV:}collection " ) ? 'dir' : 'file' ;
} catch ( \Exception $e ) {
2012-07-02 19:52:51 +04:00
error_log ( $e -> getMessage ());
\OCP\Util :: writeLog ( " webdav client " , \OCP\Util :: sanitizeHTML ( $e -> getMessage ()), \OCP\Util :: ERROR );
2012-03-23 21:54:38 +04:00
return false ;
}
}
2012-09-07 17:22:01 +04:00
public function file_exists ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-01-31 19:06:11 +04:00
$this -> client -> propfind ( $this -> encodePath ( $path ), array ( '{DAV:}resourcetype' ));
2014-03-04 18:44:58 +04:00
return true ; //no 404 exception
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
2012-09-07 17:22:01 +04:00
public function unlink ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2013-02-09 20:35:47 +04:00
return $this -> simpleResponse ( 'DELETE' , $path , null , 204 );
2012-03-23 21:54:38 +04:00
}
2013-02-09 20:35:47 +04:00
public function fopen ( $path , $mode ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
switch ( $mode ) {
2012-03-23 21:54:38 +04:00
case 'r' :
case 'rb' :
2014-03-04 18:44:58 +04:00
if ( ! $this -> file_exists ( $path )) {
2012-10-11 23:13:19 +04:00
return false ;
}
2012-03-23 21:54:38 +04:00
//straight up curl instead of sabredav here, sabredav put's the entire get result in memory
$curl = curl_init ();
$fp = fopen ( 'php://temp' , 'r+' );
2014-03-04 18:44:58 +04:00
curl_setopt ( $curl , CURLOPT_USERPWD , $this -> user . ':' . $this -> password );
curl_setopt ( $curl , CURLOPT_URL , $this -> createBaseUri () . $this -> encodePath ( $path ));
2012-03-23 21:54:38 +04:00
curl_setopt ( $curl , CURLOPT_FILE , $fp );
2013-08-02 23:18:29 +04:00
curl_setopt ( $curl , CURLOPT_FOLLOWLOCATION , true );
2013-12-17 12:38:43 +04:00
if ( $this -> secure === true ) {
curl_setopt ( $curl , CURLOPT_SSL_VERIFYPEER , true );
curl_setopt ( $curl , CURLOPT_SSL_VERIFYHOST , 2 );
2014-03-04 18:44:58 +04:00
if ( $this -> certPath ) {
2013-12-17 12:38:43 +04:00
curl_setopt ( $curl , CURLOPT_CAINFO , $this -> certPath );
}
}
2014-03-04 18:44:58 +04:00
curl_exec ( $curl );
2014-01-31 19:06:11 +04:00
$statusCode = curl_getinfo ( $curl , CURLINFO_HTTP_CODE );
if ( $statusCode !== 200 ) {
\OCP\Util :: writeLog ( " webdav client " , 'curl GET ' . curl_getinfo ( $curl , CURLINFO_EFFECTIVE_URL ) . ' returned status code ' . $statusCode , \OCP\Util :: ERROR );
}
2014-03-04 18:44:58 +04:00
curl_close ( $curl );
2012-03-23 21:54:38 +04:00
rewind ( $fp );
return $fp ;
case 'w' :
case 'wb' :
case 'a' :
case 'ab' :
case 'r+' :
case 'w+' :
case 'wb+' :
case 'a+' :
case 'x' :
case 'x+' :
case 'c' :
case 'c+' :
//emulate these
2014-03-04 18:44:58 +04:00
if ( strrpos ( $path , '.' ) !== false ) {
$ext = substr ( $path , strrpos ( $path , '.' ));
2012-11-30 19:27:11 +04:00
} else {
2014-03-04 18:44:58 +04:00
$ext = '' ;
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
if ( $this -> file_exists ( $path )) {
$tmpFile = $this -> getCachedFile ( $path );
} else {
$tmpFile = \OCP\Files :: tmpFile ( $ext );
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
\OC\Files\Stream\Close :: registerCallback ( $tmpFile , array ( $this , 'writeBack' ));
self :: $tempFiles [ $tmpFile ] = $path ;
return fopen ( 'close://' . $tmpFile , $mode );
2012-03-23 21:54:38 +04:00
}
}
2012-09-07 17:22:01 +04:00
public function writeBack ( $tmpFile ) {
2012-11-30 19:27:11 +04:00
if ( isset ( self :: $tempFiles [ $tmpFile ])) {
2012-10-24 00:53:54 +04:00
$this -> uploadFile ( $tmpFile , self :: $tempFiles [ $tmpFile ]);
2012-03-23 21:54:38 +04:00
unlink ( $tmpFile );
}
}
2012-09-07 17:22:01 +04:00
public function free_space ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$response = $this -> client -> propfind ( $this -> encodePath ( $path ), array ( '{DAV:}quota-available-bytes' ));
2012-11-30 19:27:11 +04:00
if ( isset ( $response [ '{DAV:}quota-available-bytes' ])) {
2012-03-23 21:54:38 +04:00
return ( int ) $response [ '{DAV:}quota-available-bytes' ];
2012-11-30 19:27:11 +04:00
} else {
2014-01-16 13:53:58 +04:00
return \OC\Files\SPACE_UNKNOWN ;
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
} catch ( \Exception $e ) {
2013-07-25 18:14:46 +04:00
return \OC\Files\SPACE_UNKNOWN ;
2012-03-23 21:54:38 +04:00
}
}
2014-03-04 18:44:58 +04:00
public function touch ( $path , $mtime = null ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2012-11-30 19:27:11 +04:00
if ( is_null ( $mtime )) {
2014-03-04 18:44:58 +04:00
$mtime = time ();
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2013-07-12 15:25:37 +04:00
// if file exists, update the mtime, else create a new empty file
if ( $this -> file_exists ( $path )) {
2014-01-31 19:06:11 +04:00
try {
$this -> client -> proppatch ( $this -> encodePath ( $path ), array ( '{DAV:}lastmodified' => $mtime ));
2014-03-04 18:44:58 +04:00
} catch ( \Sabre_DAV_Exception_NotImplemented $e ) {
2014-01-31 19:06:11 +04:00
return false ;
}
2013-07-12 15:25:37 +04:00
} else {
$this -> file_put_contents ( $path , '' );
}
2013-11-25 15:44:27 +04:00
return true ;
2012-03-23 21:54:38 +04:00
}
2014-03-04 18:44:58 +04:00
protected function uploadFile ( $path , $target ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$source = fopen ( $path , 'r' );
2012-03-23 21:54:38 +04:00
$curl = curl_init ();
2014-03-04 18:44:58 +04:00
curl_setopt ( $curl , CURLOPT_USERPWD , $this -> user . ':' . $this -> password );
curl_setopt ( $curl , CURLOPT_URL , $this -> createBaseUri () . str_replace ( ' ' , '%20' , $target ));
2012-03-23 21:54:38 +04:00
curl_setopt ( $curl , CURLOPT_BINARYTRANSFER , true );
curl_setopt ( $curl , CURLOPT_INFILE , $source ); // file pointer
curl_setopt ( $curl , CURLOPT_INFILESIZE , filesize ( $path ));
curl_setopt ( $curl , CURLOPT_PUT , true );
2013-12-17 12:38:43 +04:00
if ( $this -> secure === true ) {
curl_setopt ( $curl , CURLOPT_SSL_VERIFYPEER , true );
curl_setopt ( $curl , CURLOPT_SSL_VERIFYHOST , 2 );
2014-03-04 18:44:58 +04:00
if ( $this -> certPath ) {
2013-12-17 12:38:43 +04:00
curl_setopt ( $curl , CURLOPT_CAINFO , $this -> certPath );
}
}
2014-03-04 18:44:58 +04:00
curl_exec ( $curl );
2014-01-31 19:06:11 +04:00
$statusCode = curl_getinfo ( $curl , CURLINFO_HTTP_CODE );
if ( $statusCode !== 200 ) {
\OCP\Util :: writeLog ( " webdav client " , 'curl GET ' . curl_getinfo ( $curl , CURLINFO_EFFECTIVE_URL ) . ' returned status code ' . $statusCode , \OCP\Util :: ERROR );
}
2014-03-04 18:44:58 +04:00
curl_close ( $curl );
$this -> removeCachedFile ( $target );
2012-03-23 21:54:38 +04:00
}
2013-02-09 20:35:47 +04:00
public function rename ( $path1 , $path2 ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-01-31 19:06:11 +04:00
$path1 = $this -> encodePath ( $this -> cleanPath ( $path1 ));
2014-03-04 18:44:58 +04:00
$path2 = $this -> createBaseUri () . $this -> encodePath ( $this -> cleanPath ( $path2 ));
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$this -> client -> request ( 'MOVE' , $path1 , null , array ( 'Destination' => $path2 ));
$this -> removeCachedFile ( $path1 );
$this -> removeCachedFile ( $path2 );
2012-03-23 21:54:38 +04:00
return true ;
2014-03-04 18:44:58 +04:00
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
2013-02-09 20:35:47 +04:00
public function copy ( $path1 , $path2 ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-01-31 19:06:11 +04:00
$path1 = $this -> encodePath ( $this -> cleanPath ( $path1 ));
2014-03-04 18:44:58 +04:00
$path2 = $this -> createBaseUri () . $this -> encodePath ( $this -> cleanPath ( $path2 ));
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$this -> client -> request ( 'COPY' , $path1 , null , array ( 'Destination' => $path2 ));
$this -> removeCachedFile ( $path2 );
2012-03-23 21:54:38 +04:00
return true ;
2014-03-04 18:44:58 +04:00
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
2012-09-07 17:22:01 +04:00
public function stat ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-01-31 19:06:11 +04:00
$response = $this -> client -> propfind ( $this -> encodePath ( $path ), array ( '{DAV:}getlastmodified' , '{DAV:}getcontentlength' ));
2012-06-29 21:00:41 +04:00
return array (
2014-03-04 18:44:58 +04:00
'mtime' => strtotime ( $response [ '{DAV:}getlastmodified' ]),
'size' => ( int ) isset ( $response [ '{DAV:}getcontentlength' ]) ? $response [ '{DAV:}getcontentlength' ] : 0 ,
2012-06-29 21:00:41 +04:00
);
2014-03-04 18:44:58 +04:00
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return array ();
}
}
2012-09-07 17:22:01 +04:00
public function getMimeType ( $path ) {
2012-10-22 00:04:45 +04:00
$this -> init ();
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$response = $this -> client -> propfind ( $this -> encodePath ( $path ), array ( '{DAV:}getcontenttype' , '{DAV:}resourcetype' ));
2014-01-31 19:06:11 +04:00
$responseType = array ();
if ( isset ( $response [ " { DAV:}resourcetype " ])) {
2014-03-04 18:44:58 +04:00
$responseType = $response [ " { DAV:}resourcetype " ] -> resourceType ;
2014-01-31 19:06:11 +04:00
}
2014-03-04 18:44:58 +04:00
$type = ( count ( $responseType ) > 0 and $responseType [ 0 ] == " { DAV:}collection " ) ? 'dir' : 'file' ;
if ( $type == 'dir' ) {
2012-03-23 21:54:38 +04:00
return 'httpd/unix-directory' ;
2012-11-30 19:27:11 +04:00
} elseif ( isset ( $response [ '{DAV:}getcontenttype' ])) {
2012-03-23 21:54:38 +04:00
return $response [ '{DAV:}getcontenttype' ];
2012-11-30 19:27:11 +04:00
} else {
2012-03-23 21:54:38 +04:00
return false ;
}
2014-03-04 18:44:58 +04:00
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
2014-02-19 12:31:54 +04:00
/**
* @ param string $path
*/
2013-02-12 14:05:12 +04:00
public function cleanPath ( $path ) {
2013-11-20 21:14:42 +04:00
$path = \OC\Files\Filesystem :: normalizePath ( $path );
// remove leading slash
return substr ( $path , 1 );
2012-03-23 21:54:38 +04:00
}
2014-01-31 19:06:11 +04:00
/**
* URL encodes the given path but keeps the slashes
2014-03-04 18:44:58 +04:00
*
2014-01-31 19:06:11 +04:00
* @ param string $path to encode
* @ return string encoded path
*/
private function encodePath ( $path ) {
// slashes need to stay
return str_replace ( '%2F' , '/' , rawurlencode ( $path ));
}
2014-02-06 19:30:58 +04:00
/**
* @ param string $method
* @ param string $path
* @ param integer $expected
*/
2013-02-09 20:35:47 +04:00
private function simpleResponse ( $method , $path , $body , $expected ) {
2014-03-04 18:44:58 +04:00
$path = $this -> cleanPath ( $path );
2012-11-30 19:27:11 +04:00
try {
2014-03-04 18:44:58 +04:00
$response = $this -> client -> request ( $method , $this -> encodePath ( $path ), $body );
return $response [ 'statusCode' ] == $expected ;
} catch ( \Exception $e ) {
2012-03-23 21:54:38 +04:00
return false ;
}
}
}
2013-12-15 20:22:52 +04:00