Write.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355
  1. <?php
  2. /**
  3. * Copyright © Magento, Inc. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Filesystem\Directory;
  7. use Magento\Framework\Exception\FileSystemException;
  8. use Magento\Framework\Exception\ValidatorException;
  9. /**
  10. * Write Interface implementation
  11. */
  12. class Write extends Read implements WriteInterface
  13. {
  14. /**
  15. * Permissions for new sub-directories
  16. *
  17. * @var int
  18. */
  19. protected $permissions = 0777;
  20. /**
  21. * Constructor
  22. *
  23. * @param \Magento\Framework\Filesystem\File\WriteFactory $fileFactory
  24. * @param \Magento\Framework\Filesystem\DriverInterface $driver
  25. * @param string $path
  26. * @param int $createPermissions
  27. * @param PathValidatorInterface|null $pathValidator
  28. */
  29. public function __construct(
  30. \Magento\Framework\Filesystem\File\WriteFactory $fileFactory,
  31. \Magento\Framework\Filesystem\DriverInterface $driver,
  32. $path,
  33. $createPermissions = null,
  34. ?PathValidatorInterface $pathValidator = null
  35. ) {
  36. parent::__construct($fileFactory, $driver, $path, $pathValidator);
  37. if (null !== $createPermissions) {
  38. $this->permissions = $createPermissions;
  39. }
  40. }
  41. /**
  42. * Check if directory or file is writable
  43. *
  44. * @param string $path
  45. * @return void
  46. * @throws \Magento\Framework\Exception\FileSystemException
  47. */
  48. protected function assertWritable($path)
  49. {
  50. if ($this->isWritable($path) === false) {
  51. $path = (!$this->driver->isFile($path))
  52. ? $this->getAbsolutePath($this->path, $path)
  53. : $this->getAbsolutePath($path);
  54. throw new FileSystemException(new \Magento\Framework\Phrase('The path "%1" is not writable.', [$path]));
  55. }
  56. }
  57. /**
  58. * Check if given path is exists and is file
  59. *
  60. * @param string $path
  61. * @return void
  62. * @throws \Magento\Framework\Exception\FileSystemException
  63. */
  64. protected function assertIsFile($path)
  65. {
  66. clearstatcache();
  67. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  68. if (!$this->driver->isFile($absolutePath)) {
  69. throw new FileSystemException(
  70. new \Magento\Framework\Phrase('The "%1" file doesn\'t exist.', [$absolutePath])
  71. );
  72. }
  73. }
  74. /**
  75. * Create directory if it does not exist
  76. *
  77. * @param string $path
  78. * @return bool
  79. * @throws FileSystemException
  80. * @throws ValidatorException
  81. */
  82. public function create($path = null)
  83. {
  84. $this->validatePath($path);
  85. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  86. if ($this->driver->isDirectory($absolutePath)) {
  87. return true;
  88. }
  89. return $this->driver->createDirectory($absolutePath, $this->permissions);
  90. }
  91. /**
  92. * Rename a file
  93. *
  94. * @param string $path
  95. * @param string $newPath
  96. * @param WriteInterface $targetDirectory
  97. * @return bool
  98. * @throws FileSystemException
  99. * @throws ValidatorException
  100. */
  101. public function renameFile($path, $newPath, WriteInterface $targetDirectory = null)
  102. {
  103. $this->validatePath($path);
  104. $this->assertIsFile($path);
  105. $targetDirectory = $targetDirectory ?: $this;
  106. if (!$targetDirectory->isExist($this->driver->getParentDirectory($newPath))) {
  107. $targetDirectory->create($this->driver->getParentDirectory($newPath));
  108. }
  109. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  110. $absoluteNewPath = $targetDirectory->getAbsolutePath($newPath);
  111. return $this->driver->rename($absolutePath, $absoluteNewPath, $targetDirectory->driver);
  112. }
  113. /**
  114. * Copy a file
  115. *
  116. * @param string $path
  117. * @param string $destination
  118. * @param WriteInterface $targetDirectory
  119. * @return bool
  120. * @throws FileSystemException
  121. * @throws ValidatorException
  122. */
  123. public function copyFile($path, $destination, WriteInterface $targetDirectory = null)
  124. {
  125. $this->validatePath($path);
  126. $this->assertIsFile($path);
  127. $targetDirectory = $targetDirectory ?: $this;
  128. if (!$targetDirectory->isExist($this->driver->getParentDirectory($destination))) {
  129. $targetDirectory->create($this->driver->getParentDirectory($destination));
  130. }
  131. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  132. $absoluteDestination = $targetDirectory->getAbsolutePath($destination);
  133. return $this->driver->copy($absolutePath, $absoluteDestination, $targetDirectory->driver);
  134. }
  135. /**
  136. * Creates symlink on a file and places it to destination
  137. *
  138. * @param string $path
  139. * @param string $destination
  140. * @param WriteInterface $targetDirectory [optional]
  141. * @return bool
  142. * @throws \Magento\Framework\Exception\FileSystemException
  143. * @throws ValidatorException
  144. */
  145. public function createSymlink($path, $destination, WriteInterface $targetDirectory = null)
  146. {
  147. $this->validatePath($path);
  148. $targetDirectory = $targetDirectory ?: $this;
  149. $parentDirectory = $this->driver->getParentDirectory($destination);
  150. if (!$targetDirectory->isExist($parentDirectory)) {
  151. $targetDirectory->create($parentDirectory);
  152. }
  153. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  154. $absoluteDestination = $targetDirectory->getAbsolutePath($destination);
  155. return $this->driver->symlink($absolutePath, $absoluteDestination, $targetDirectory->driver);
  156. }
  157. /**
  158. * Delete given path
  159. *
  160. * @param string $path
  161. * @return bool
  162. * @throws FileSystemException
  163. * @throws ValidatorException
  164. */
  165. public function delete($path = null)
  166. {
  167. $exceptionMessages = [];
  168. $this->validatePath($path);
  169. if (!$this->isExist($path)) {
  170. return true;
  171. }
  172. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  173. if ($this->driver->isFile($absolutePath)) {
  174. $this->driver->deleteFile($absolutePath);
  175. } else {
  176. try {
  177. $this->deleteFilesRecursively($absolutePath);
  178. } catch (FileSystemException $e) {
  179. $exceptionMessages[] = $e->getMessage();
  180. }
  181. try {
  182. $this->driver->deleteDirectory($absolutePath);
  183. } catch (FileSystemException $e) {
  184. $exceptionMessages[] = $e->getMessage();
  185. }
  186. if (!empty($exceptionMessages)) {
  187. throw new FileSystemException(
  188. new \Magento\Framework\Phrase(
  189. \implode(' ', $exceptionMessages)
  190. )
  191. );
  192. }
  193. }
  194. return true;
  195. }
  196. /**
  197. * Delete files recursively
  198. *
  199. * Implemented in order to delete as much files as possible and collect all exceptions
  200. *
  201. * @param string $path
  202. * @return void
  203. * @throws FileSystemException
  204. */
  205. private function deleteFilesRecursively(string $path)
  206. {
  207. $exceptionMessages = [];
  208. $entitiesList = $this->driver->readDirectoryRecursively($path);
  209. foreach ($entitiesList as $entityPath) {
  210. if ($this->driver->isFile($entityPath)) {
  211. try {
  212. $this->driver->deleteFile($entityPath);
  213. } catch (FileSystemException $e) {
  214. $exceptionMessages[] = $e->getMessage();
  215. }
  216. }
  217. }
  218. if (!empty($exceptionMessages)) {
  219. throw new FileSystemException(
  220. new \Magento\Framework\Phrase(
  221. \implode(' ', $exceptionMessages)
  222. )
  223. );
  224. }
  225. }
  226. /**
  227. * Change permissions of given path
  228. *
  229. * @param string $path
  230. * @param int $permissions
  231. * @return bool
  232. * @throws FileSystemException
  233. * @throws ValidatorException
  234. */
  235. public function changePermissions($path, $permissions)
  236. {
  237. $this->validatePath($path);
  238. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  239. return $this->driver->changePermissions($absolutePath, $permissions);
  240. }
  241. /**
  242. * Recursively change permissions of given path
  243. *
  244. * @param string $path
  245. * @param int $dirPermissions
  246. * @param int $filePermissions
  247. * @return bool
  248. * @throws FileSystemException
  249. * @throws ValidatorException
  250. */
  251. public function changePermissionsRecursively($path, $dirPermissions, $filePermissions)
  252. {
  253. $this->validatePath($path);
  254. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  255. return $this->driver->changePermissionsRecursively($absolutePath, $dirPermissions, $filePermissions);
  256. }
  257. /**
  258. * Sets modification time of file, if file does not exist - creates file
  259. *
  260. * @param string $path
  261. * @param int|null $modificationTime
  262. * @return bool
  263. * @throws FileSystemException
  264. * @throws ValidatorException
  265. */
  266. public function touch($path, $modificationTime = null)
  267. {
  268. $this->validatePath($path);
  269. $folder = $this->driver->getParentDirectory($path);
  270. $this->create($folder);
  271. $this->assertWritable($folder);
  272. return $this->driver->touch($this->driver->getAbsolutePath($this->path, $path), $modificationTime);
  273. }
  274. /**
  275. * Check if given path is writable
  276. *
  277. * @param string|null $path
  278. * @return bool
  279. * @throws \Magento\Framework\Exception\FileSystemException
  280. * @throws ValidatorException
  281. */
  282. public function isWritable($path = null)
  283. {
  284. $this->validatePath($path);
  285. return $this->driver->isWritable($this->driver->getAbsolutePath($this->path, $path));
  286. }
  287. /**
  288. * Open file in given mode
  289. *
  290. * @param string $path
  291. * @param string $mode
  292. * @return \Magento\Framework\Filesystem\File\WriteInterface
  293. * @throws \Magento\Framework\Exception\FileSystemException
  294. * @throws ValidatorException
  295. */
  296. public function openFile($path, $mode = 'w')
  297. {
  298. $this->validatePath($path);
  299. $folder = dirname($path);
  300. $this->create($folder);
  301. $this->assertWritable($this->isExist($path) ? $path : $folder);
  302. $absolutePath = $this->driver->getAbsolutePath($this->path, $path);
  303. return $this->fileFactory->create($absolutePath, $this->driver, $mode);
  304. }
  305. /**
  306. * Write contents to file in given mode
  307. *
  308. * @param string $path
  309. * @param string $content
  310. * @param string|null $mode
  311. * @return int The number of bytes that were written.
  312. * @throws FileSystemException
  313. */
  314. public function writeFile($path, $content, $mode = 'w+')
  315. {
  316. return $this->openFile($path, $mode)->write($content);
  317. }
  318. /**
  319. * Get driver
  320. *
  321. * @return \Magento\Framework\Filesystem\DriverInterface
  322. */
  323. public function getDriver()
  324. {
  325. return $this->driver;
  326. }
  327. }