PageRenderTime 51ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php

https://gitlab.com/mohamed_hussein/prodt
PHP | 432 lines | 201 code | 50 blank | 181 comment | 27 complexity | 25a681d5d44cf68bbb5f24b1aa3d3192 MD5 | raw file
  1. <?php
  2. namespace Drupal\Core\StreamWrapper;
  3. /**
  4. * Defines a Drupal stream wrapper base class for local files.
  5. *
  6. * This class provides a complete stream wrapper implementation. URIs such as
  7. * "public://example.txt" are expanded to a normal filesystem path such as
  8. * "sites/default/files/example.txt" and then PHP filesystem functions are
  9. * invoked.
  10. *
  11. * Drupal\Core\StreamWrapper\LocalStream implementations need to implement at least the
  12. * getDirectoryPath() and getExternalUrl() methods.
  13. */
  14. abstract class LocalStream implements StreamWrapperInterface {
  15. /**
  16. * Stream context resource.
  17. *
  18. * @var resource
  19. */
  20. public $context;
  21. /**
  22. * A generic resource handle.
  23. *
  24. * @var resource
  25. */
  26. public $handle = NULL;
  27. /**
  28. * Instance URI (stream).
  29. *
  30. * A stream is referenced as "scheme://target".
  31. *
  32. * @var string
  33. */
  34. protected $uri;
  35. /**
  36. * {@inheritdoc}
  37. */
  38. public static function getType() {
  39. return StreamWrapperInterface::NORMAL;
  40. }
  41. /**
  42. * Gets the path that the wrapper is responsible for.
  43. *
  44. * @return string
  45. * String specifying the path.
  46. */
  47. abstract public function getDirectoryPath();
  48. /**
  49. * {@inheritdoc}
  50. */
  51. public function setUri($uri) {
  52. $this->uri = $uri;
  53. }
  54. /**
  55. * {@inheritdoc}
  56. */
  57. public function getUri() {
  58. return $this->uri;
  59. }
  60. /**
  61. * Returns the local writable target of the resource within the stream.
  62. *
  63. * This function should be used in place of calls to realpath() or similar
  64. * functions when attempting to determine the location of a file. While
  65. * functions like realpath() may return the location of a read-only file, this
  66. * method may return a URI or path suitable for writing that is completely
  67. * separate from the URI used for reading.
  68. *
  69. * @param string $uri
  70. * Optional URI.
  71. *
  72. * @return string|bool
  73. * Returns a string representing a location suitable for writing of a file,
  74. * or FALSE if unable to write to the file such as with read-only streams.
  75. */
  76. protected function getTarget($uri = NULL) {
  77. if (!isset($uri)) {
  78. $uri = $this->uri;
  79. }
  80. [, $target] = explode('://', $uri, 2);
  81. // Remove erroneous leading or trailing, forward-slashes and backslashes.
  82. return trim($target, '\/');
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. public function realpath() {
  88. return $this->getLocalPath();
  89. }
  90. /**
  91. * Returns the canonical absolute path of the URI, if possible.
  92. *
  93. * @param string $uri
  94. * (optional) The stream wrapper URI to be converted to a canonical
  95. * absolute path. This may point to a directory or another type of file.
  96. *
  97. * @return string|bool
  98. * If $uri is not set, returns the canonical absolute path of the URI
  99. * previously set by the
  100. * Drupal\Core\StreamWrapper\StreamWrapperInterface::setUri() function.
  101. * If $uri is set and valid for this class, returns its canonical absolute
  102. * path, as determined by the realpath() function. If $uri is set but not
  103. * valid, returns FALSE.
  104. */
  105. protected function getLocalPath($uri = NULL) {
  106. if (!isset($uri)) {
  107. $uri = $this->uri;
  108. }
  109. $path = $this->getDirectoryPath() . '/' . $this->getTarget($uri);
  110. // In PHPUnit tests, the base path for local streams may be a virtual
  111. // filesystem stream wrapper URI, in which case this local stream acts like
  112. // a proxy. realpath() is not supported by vfsStream, because a virtual
  113. // file system does not have a real filepath.
  114. if (strpos($path, 'vfs://') === 0) {
  115. return $path;
  116. }
  117. $realpath = realpath($path);
  118. if (!$realpath) {
  119. // This file does not yet exist.
  120. $realpath = realpath(dirname($path)) . '/' . \Drupal::service('file_system')->basename($path);
  121. }
  122. $directory = realpath($this->getDirectoryPath());
  123. if (!$realpath || !$directory || strpos($realpath, $directory) !== 0) {
  124. return FALSE;
  125. }
  126. return $realpath;
  127. }
  128. /**
  129. * {@inheritdoc}
  130. */
  131. public function stream_open($uri, $mode, $options, &$opened_path) {
  132. $this->uri = $uri;
  133. $path = $this->getLocalPath();
  134. if ($path === FALSE) {
  135. if ($options & STREAM_REPORT_ERRORS) {
  136. trigger_error('stream_open() filename cannot be empty', E_USER_WARNING);
  137. }
  138. return FALSE;
  139. }
  140. $this->handle = ($options & STREAM_REPORT_ERRORS) ? fopen($path, $mode) : @fopen($path, $mode);
  141. if ((bool) $this->handle && $options & STREAM_USE_PATH) {
  142. $opened_path = $path;
  143. }
  144. return (bool) $this->handle;
  145. }
  146. /**
  147. * {@inheritdoc}
  148. */
  149. public function stream_lock($operation) {
  150. if (in_array($operation, [LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB])) {
  151. return flock($this->handle, $operation);
  152. }
  153. return TRUE;
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function stream_read($count) {
  159. return fread($this->handle, $count);
  160. }
  161. /**
  162. * {@inheritdoc}
  163. */
  164. public function stream_write($data) {
  165. return fwrite($this->handle, $data);
  166. }
  167. /**
  168. * {@inheritdoc}
  169. */
  170. public function stream_eof() {
  171. return feof($this->handle);
  172. }
  173. /**
  174. * {@inheritdoc}
  175. */
  176. public function stream_seek($offset, $whence = SEEK_SET) {
  177. // fseek returns 0 on success and -1 on a failure.
  178. // stream_seek 1 on success and 0 on a failure.
  179. return !fseek($this->handle, $offset, $whence);
  180. }
  181. /**
  182. * {@inheritdoc}
  183. */
  184. public function stream_flush() {
  185. return fflush($this->handle);
  186. }
  187. /**
  188. * {@inheritdoc}
  189. */
  190. public function stream_tell() {
  191. return ftell($this->handle);
  192. }
  193. /**
  194. * {@inheritdoc}
  195. */
  196. public function stream_stat() {
  197. return fstat($this->handle);
  198. }
  199. /**
  200. * {@inheritdoc}
  201. */
  202. public function stream_close() {
  203. return fclose($this->handle);
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function stream_cast($cast_as) {
  209. return $this->handle ? $this->handle : FALSE;
  210. }
  211. /**
  212. * {@inheritdoc}
  213. */
  214. public function stream_metadata($uri, $option, $value) {
  215. $target = $this->getLocalPath($uri);
  216. $return = FALSE;
  217. switch ($option) {
  218. case STREAM_META_TOUCH:
  219. if (!empty($value)) {
  220. $return = touch($target, $value[0], $value[1]);
  221. }
  222. else {
  223. $return = touch($target);
  224. }
  225. break;
  226. case STREAM_META_OWNER_NAME:
  227. case STREAM_META_OWNER:
  228. $return = chown($target, $value);
  229. break;
  230. case STREAM_META_GROUP_NAME:
  231. case STREAM_META_GROUP:
  232. $return = chgrp($target, $value);
  233. break;
  234. case STREAM_META_ACCESS:
  235. $return = chmod($target, $value);
  236. break;
  237. }
  238. if ($return) {
  239. // For convenience clear the file status cache of the underlying file,
  240. // since metadata operations are often followed by file status checks.
  241. clearstatcache(TRUE, $target);
  242. }
  243. return $return;
  244. }
  245. /**
  246. * {@inheritdoc}
  247. *
  248. * Since Windows systems do not allow it and it is not needed for most use
  249. * cases anyway, this method is not supported on local files and will trigger
  250. * an error and return false. If needed, custom subclasses can provide
  251. * OS-specific implementations for advanced use cases.
  252. */
  253. public function stream_set_option($option, $arg1, $arg2) {
  254. trigger_error('stream_set_option() not supported for local file based stream wrappers', E_USER_WARNING);
  255. return FALSE;
  256. }
  257. /**
  258. * {@inheritdoc}
  259. */
  260. public function stream_truncate($new_size) {
  261. return ftruncate($this->handle, $new_size);
  262. }
  263. /**
  264. * {@inheritdoc}
  265. */
  266. public function unlink($uri) {
  267. $this->uri = $uri;
  268. return $this->getFileSystem()->unlink($this->getLocalPath());
  269. }
  270. /**
  271. * {@inheritdoc}
  272. */
  273. public function rename($from_uri, $to_uri) {
  274. return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
  275. }
  276. /**
  277. * {@inheritdoc}
  278. */
  279. public function dirname($uri = NULL) {
  280. [$scheme] = explode('://', $uri, 2);
  281. $target = $this->getTarget($uri);
  282. $dirname = dirname($target);
  283. if ($dirname == '.') {
  284. $dirname = '';
  285. }
  286. return $scheme . '://' . $dirname;
  287. }
  288. /**
  289. * {@inheritdoc}
  290. */
  291. public function mkdir($uri, $mode, $options) {
  292. $this->uri = $uri;
  293. $recursive = (bool) ($options & STREAM_MKDIR_RECURSIVE);
  294. if ($recursive) {
  295. // $this->getLocalPath() fails if $uri has multiple levels of directories
  296. // that do not yet exist.
  297. $localpath = $this->getDirectoryPath() . '/' . $this->getTarget($uri);
  298. }
  299. else {
  300. $localpath = $this->getLocalPath($uri);
  301. }
  302. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  303. $file_system = \Drupal::service('file_system');
  304. if ($options & STREAM_REPORT_ERRORS) {
  305. return $file_system->mkdir($localpath, $mode, $recursive);
  306. }
  307. else {
  308. return @$file_system->mkdir($localpath, $mode, $recursive);
  309. }
  310. }
  311. /**
  312. * {@inheritdoc}
  313. */
  314. public function rmdir($uri, $options) {
  315. $this->uri = $uri;
  316. /** @var \Drupal\Core\File\FileSystemInterface $file_system */
  317. $file_system = \Drupal::service('file_system');
  318. if ($options & STREAM_REPORT_ERRORS) {
  319. return $file_system->rmdir($this->getLocalPath());
  320. }
  321. else {
  322. return @$file_system->rmdir($this->getLocalPath());
  323. }
  324. }
  325. /**
  326. * {@inheritdoc}
  327. */
  328. public function url_stat($uri, $flags) {
  329. $this->uri = $uri;
  330. $path = $this->getLocalPath();
  331. // Suppress warnings if requested or if the file or directory does not
  332. // exist. This is consistent with PHP's plain filesystem stream wrapper.
  333. if ($flags & STREAM_URL_STAT_QUIET || !file_exists($path)) {
  334. return @stat($path);
  335. }
  336. else {
  337. return stat($path);
  338. }
  339. }
  340. /**
  341. * {@inheritdoc}
  342. */
  343. public function dir_opendir($uri, $options) {
  344. $this->uri = $uri;
  345. $this->handle = opendir($this->getLocalPath());
  346. return (bool) $this->handle;
  347. }
  348. /**
  349. * {@inheritdoc}
  350. */
  351. public function dir_readdir() {
  352. return readdir($this->handle);
  353. }
  354. /**
  355. * {@inheritdoc}
  356. */
  357. public function dir_rewinddir() {
  358. rewinddir($this->handle);
  359. // We do not really have a way to signal a failure as rewinddir() does not
  360. // have a return value and there is no way to read a directory handler
  361. // without advancing to the next file.
  362. return TRUE;
  363. }
  364. /**
  365. * {@inheritdoc}
  366. */
  367. public function dir_closedir() {
  368. closedir($this->handle);
  369. // We do not really have a way to signal a failure as closedir() does not
  370. // have a return value.
  371. return TRUE;
  372. }
  373. /**
  374. * Returns file system service.
  375. *
  376. * @return \Drupal\Core\File\FileSystemInterface
  377. * The file system service.
  378. */
  379. private function getFileSystem() {
  380. return \Drupal::service('file_system');
  381. }
  382. }