PageRenderTime 35ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/apps/files_external/lib/webdav.php

https://github.com/sezuan/core
PHP | 335 lines | 291 code | 32 blank | 12 comment | 33 complexity | cd9215e3a0536b5e396ea7233d7cd372 MD5 | raw file
Possible License(s): AGPL-3.0, AGPL-1.0, MPL-2.0-no-copyleft-exception
  1. <?php
  2. /**
  3. * Copyright (c) 2012 Robin Appelman <icewind@owncloud.com>
  4. * This file is licensed under the Affero General Public License version 3 or
  5. * later.
  6. * See the COPYING-README file.
  7. */
  8. namespace OC\Files\Storage;
  9. class DAV extends \OC\Files\Storage\Common{
  10. private $password;
  11. private $user;
  12. private $host;
  13. private $secure;
  14. private $root;
  15. private $ready;
  16. /**
  17. * @var \Sabre_DAV_Client
  18. */
  19. private $client;
  20. private static $tempFiles=array();
  21. public function __construct($params) {
  22. if (isset($params['host']) && isset($params['user']) && isset($params['password'])) {
  23. $host = $params['host'];
  24. //remove leading http[s], will be generated in createBaseUri()
  25. if (substr($host, 0, 8) == "https://") $host = substr($host, 8);
  26. else if (substr($host, 0, 7) == "http://") $host = substr($host, 7);
  27. $this->host=$host;
  28. $this->user=$params['user'];
  29. $this->password=$params['password'];
  30. if (isset($params['secure'])) {
  31. if (is_string($params['secure'])) {
  32. $this->secure = ($params['secure'] === 'true');
  33. } else {
  34. $this->secure = (bool)$params['secure'];
  35. }
  36. } else {
  37. $this->secure = false;
  38. }
  39. $this->root=isset($params['root'])?$params['root']:'/';
  40. if ( ! $this->root || $this->root[0]!='/') {
  41. $this->root='/'.$this->root;
  42. }
  43. if (substr($this->root, -1, 1)!='/') {
  44. $this->root.='/';
  45. }
  46. } else {
  47. throw new \Exception();
  48. }
  49. }
  50. private function init(){
  51. if($this->ready) {
  52. return;
  53. }
  54. $this->ready = true;
  55. $settings = array(
  56. 'baseUri' => $this->createBaseUri(),
  57. 'userName' => $this->user,
  58. 'password' => $this->password,
  59. );
  60. $this->client = new \Sabre_DAV_Client($settings);
  61. $caview = \OCP\Files::getStorage('files_external');
  62. if ($caview) {
  63. $certPath=\OCP\Config::getSystemValue('datadirectory').$caview->getAbsolutePath("").'rootcerts.crt';
  64. if (file_exists($certPath)) {
  65. $this->client->addTrustedCertificates($certPath);
  66. }
  67. }
  68. }
  69. public function getId(){
  70. return 'webdav::' . $this->user . '@' . $this->host . '/' . $this->root;
  71. }
  72. private function createBaseUri() {
  73. $baseUri='http';
  74. if ($this->secure) {
  75. $baseUri.='s';
  76. }
  77. $baseUri.='://'.$this->host.$this->root;
  78. return $baseUri;
  79. }
  80. public function mkdir($path) {
  81. $this->init();
  82. $path=$this->cleanPath($path);
  83. return $this->simpleResponse('MKCOL', $path, null, 201);
  84. }
  85. public function rmdir($path) {
  86. $this->init();
  87. $path=$this->cleanPath($path);
  88. return $this->simpleResponse('DELETE', $path, null, 204);
  89. }
  90. public function opendir($path) {
  91. $this->init();
  92. $path=$this->cleanPath($path);
  93. try {
  94. $response=$this->client->propfind($path, array(), 1);
  95. $id=md5('webdav'.$this->root.$path);
  96. $content = array();
  97. $files=array_keys($response);
  98. array_shift($files);//the first entry is the current directory
  99. foreach ($files as $file) {
  100. $file = urldecode(basename($file));
  101. $content[]=$file;
  102. }
  103. \OC\Files\Stream\Dir::register($id, $content);
  104. return opendir('fakedir://'.$id);
  105. } catch(\Exception $e) {
  106. return false;
  107. }
  108. }
  109. public function filetype($path) {
  110. $this->init();
  111. $path=$this->cleanPath($path);
  112. try {
  113. $response=$this->client->propfind($path, array('{DAV:}resourcetype'));
  114. $responseType=$response["{DAV:}resourcetype"]->resourceType;
  115. return (count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file';
  116. } catch(\Exception $e) {
  117. error_log($e->getMessage());
  118. \OCP\Util::writeLog("webdav client", \OCP\Util::sanitizeHTML($e->getMessage()), \OCP\Util::ERROR);
  119. return false;
  120. }
  121. }
  122. public function isReadable($path) {
  123. return true;//not properly supported
  124. }
  125. public function isUpdatable($path) {
  126. return true;//not properly supported
  127. }
  128. public function file_exists($path) {
  129. $this->init();
  130. $path=$this->cleanPath($path);
  131. try {
  132. $this->client->propfind($path, array('{DAV:}resourcetype'));
  133. return true;//no 404 exception
  134. } catch(\Exception $e) {
  135. return false;
  136. }
  137. }
  138. public function unlink($path) {
  139. $this->init();
  140. return $this->simpleResponse('DELETE', $path, null, 204);
  141. }
  142. public function fopen($path, $mode) {
  143. $this->init();
  144. $path=$this->cleanPath($path);
  145. switch($mode) {
  146. case 'r':
  147. case 'rb':
  148. if ( ! $this->file_exists($path)) {
  149. return false;
  150. }
  151. //straight up curl instead of sabredav here, sabredav put's the entire get result in memory
  152. $curl = curl_init();
  153. $fp = fopen('php://temp', 'r+');
  154. curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password);
  155. curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$path);
  156. curl_setopt($curl, CURLOPT_FILE, $fp);
  157. curl_exec ($curl);
  158. curl_close ($curl);
  159. rewind($fp);
  160. return $fp;
  161. case 'w':
  162. case 'wb':
  163. case 'a':
  164. case 'ab':
  165. case 'r+':
  166. case 'w+':
  167. case 'wb+':
  168. case 'a+':
  169. case 'x':
  170. case 'x+':
  171. case 'c':
  172. case 'c+':
  173. //emulate these
  174. if (strrpos($path, '.')!==false) {
  175. $ext=substr($path, strrpos($path, '.'));
  176. } else {
  177. $ext='';
  178. }
  179. $tmpFile = \OCP\Files::tmpFile($ext);
  180. \OC\Files\Stream\Close::registerCallback($tmpFile, array($this, 'writeBack'));
  181. if($this->file_exists($path)) {
  182. $this->getFile($path, $tmpFile);
  183. }
  184. self::$tempFiles[$tmpFile]=$path;
  185. return fopen('close://'.$tmpFile, $mode);
  186. }
  187. }
  188. public function writeBack($tmpFile) {
  189. if (isset(self::$tempFiles[$tmpFile])) {
  190. $this->uploadFile($tmpFile, self::$tempFiles[$tmpFile]);
  191. unlink($tmpFile);
  192. }
  193. }
  194. public function free_space($path) {
  195. $this->init();
  196. $path=$this->cleanPath($path);
  197. try {
  198. $response=$this->client->propfind($path, array('{DAV:}quota-available-bytes'));
  199. if (isset($response['{DAV:}quota-available-bytes'])) {
  200. return (int)$response['{DAV:}quota-available-bytes'];
  201. } else {
  202. return 0;
  203. }
  204. } catch(\Exception $e) {
  205. return \OC\Files\FREE_SPACE_UNKNOWN;
  206. }
  207. }
  208. public function touch($path, $mtime=null) {
  209. $this->init();
  210. if (is_null($mtime)) {
  211. $mtime=time();
  212. }
  213. $path=$this->cleanPath($path);
  214. $this->client->proppatch($path, array('{DAV:}lastmodified' => $mtime));
  215. }
  216. public function getFile($path, $target) {
  217. $this->init();
  218. $source=$this->fopen($path, 'r');
  219. file_put_contents($target, $source);
  220. }
  221. public function uploadFile($path, $target) {
  222. $this->init();
  223. $source=fopen($path, 'r');
  224. $curl = curl_init();
  225. curl_setopt($curl, CURLOPT_USERPWD, $this->user.':'.$this->password);
  226. curl_setopt($curl, CURLOPT_URL, $this->createBaseUri().$target);
  227. curl_setopt($curl, CURLOPT_BINARYTRANSFER, true);
  228. curl_setopt($curl, CURLOPT_INFILE, $source); // file pointer
  229. curl_setopt($curl, CURLOPT_INFILESIZE, filesize($path));
  230. curl_setopt($curl, CURLOPT_PUT, true);
  231. curl_exec ($curl);
  232. curl_close ($curl);
  233. }
  234. public function rename($path1, $path2) {
  235. $this->init();
  236. $path1=$this->cleanPath($path1);
  237. $path2=$this->root.$this->cleanPath($path2);
  238. try {
  239. $this->client->request('MOVE', $path1, null, array('Destination'=>$path2));
  240. return true;
  241. } catch(\Exception $e) {
  242. return false;
  243. }
  244. }
  245. public function copy($path1, $path2) {
  246. $this->init();
  247. $path1=$this->cleanPath($path1);
  248. $path2=$this->root.$this->cleanPath($path2);
  249. try {
  250. $this->client->request('COPY', $path1, null, array('Destination'=>$path2));
  251. return true;
  252. } catch(\Exception $e) {
  253. return false;
  254. }
  255. }
  256. public function stat($path) {
  257. $this->init();
  258. $path=$this->cleanPath($path);
  259. try {
  260. $response=$this->client->propfind($path, array('{DAV:}getlastmodified', '{DAV:}getcontentlength'));
  261. return array(
  262. 'mtime'=>strtotime($response['{DAV:}getlastmodified']),
  263. 'size'=>(int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
  264. );
  265. } catch(\Exception $e) {
  266. return array();
  267. }
  268. }
  269. public function getMimeType($path) {
  270. $this->init();
  271. $path=$this->cleanPath($path);
  272. try {
  273. $response=$this->client->propfind($path, array('{DAV:}getcontenttype', '{DAV:}resourcetype'));
  274. $responseType=$response["{DAV:}resourcetype"]->resourceType;
  275. $type=(count($responseType)>0 and $responseType[0]=="{DAV:}collection")?'dir':'file';
  276. if ($type=='dir') {
  277. return 'httpd/unix-directory';
  278. } elseif (isset($response['{DAV:}getcontenttype'])) {
  279. return $response['{DAV:}getcontenttype'];
  280. } else {
  281. return false;
  282. }
  283. } catch(\Exception $e) {
  284. return false;
  285. }
  286. }
  287. public function cleanPath($path) {
  288. if ( ! $path || $path[0]=='/') {
  289. return substr($path, 1);
  290. } else {
  291. return $path;
  292. }
  293. }
  294. private function simpleResponse($method, $path, $body, $expected) {
  295. $path=$this->cleanPath($path);
  296. try {
  297. $response=$this->client->request($method, $path, $body);
  298. return $response['statusCode']==$expected;
  299. } catch(\Exception $e) {
  300. return false;
  301. }
  302. }
  303. }