/src/File/FileHandlerPhp.php

https://github.com/szeber/yapep_base · PHP · 286 lines · 216 code · 65 blank · 5 comment · 41 complexity · f032e51bfc8074fc3dbf3e9ed5553500 MD5 · raw file

  1. <?php
  2. declare(strict_types=1);
  3. namespace YapepBase\File;
  4. use YapepBase\Exception\InvalidArgumentException;
  5. use YapepBase\File\Exception\Exception;
  6. use YapepBase\File\Exception\NotFoundException;
  7. class FileHandlerPhp implements IFileHandler
  8. {
  9. public function touch(string $path, int $modificationTime = 0, int $accessTime = 0): void
  10. {
  11. if (!touch($path, $modificationTime, $accessTime)) {
  12. throw new Exception('Touch failed for path: ' . $path);
  13. }
  14. }
  15. public function makeDirectory(string $path, int $mode = 0755, bool $isRecursive = true): void
  16. {
  17. if (!mkdir($path, $mode, $isRecursive)) {
  18. throw new Exception('Failed to create directory: ' . $path);
  19. }
  20. // Since mkdir() is affected by the umask, do a chmod, so the new directory will have the correct permissions
  21. $this->changeMode($path, $mode);
  22. }
  23. public function write(string $path, string $data, bool $append = false, bool $lock = false): void
  24. {
  25. $flag = 0;
  26. if ($append) {
  27. $flag = $flag | FILE_APPEND;
  28. }
  29. if ($lock) {
  30. $flag = $flag | LOCK_EX;
  31. }
  32. $result = file_put_contents($path, $data, $flag);
  33. if (false === $result) {
  34. throw new Exception('Failed to write data to file: ' . $path);
  35. }
  36. }
  37. public function changeOwner(string $path, ?string $group = null, ?string $user = null): void
  38. {
  39. $this->requirePathToExist($path);
  40. if (!is_null($group) && !chgrp($path, $group)) {
  41. throw new Exception('Failed to set the group "' . $group . '" of the resource: ' . $path);
  42. }
  43. if (!is_null($user) && !chown($path, $user)) {
  44. throw new Exception('Failed to set the user "' . $user . '" of the resource: ' . $path);
  45. }
  46. }
  47. public function changeMode(string $path, int $mode): void
  48. {
  49. $this->requirePathToExist($path);
  50. if (!chmod($path, $mode)) {
  51. throw new Exception('Failed to set the mode "' . decoct($mode) . '" of the resource: ' . $path);
  52. }
  53. }
  54. public function copy(string $sourcePath, string $destinationPath): void
  55. {
  56. $this->requirePathToExist($sourcePath);
  57. if (!copy($sourcePath, $destinationPath)) {
  58. throw new Exception('Failed to copy file from ' . $sourcePath . ' to ' . $destinationPath);
  59. }
  60. }
  61. public function remove(string $path): void
  62. {
  63. if (!$this->pathExists($path)) {
  64. return;
  65. }
  66. if ($this->isDirectory($path)) {
  67. throw new Exception('The given path is a directory: ' . $path);
  68. }
  69. if (!unlink($path)) {
  70. throw new Exception('Failed to remove file: ' . $path);
  71. }
  72. }
  73. public function removeDirectory(string $path, bool $isRecursive = false): void
  74. {
  75. if (!$this->pathExists($path)) {
  76. return;
  77. }
  78. if (!$this->isDirectory($path)) {
  79. throw new Exception('The given path is not a directory: ' . $path);
  80. }
  81. $content = $this->getList($path);
  82. if (!$isRecursive && !empty($content)) {
  83. throw new Exception('The given directory is not empty: ' . $path);
  84. }
  85. foreach ($content as $subPath) {
  86. $fullPath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $subPath;
  87. if ($this->isDirectory($fullPath)) {
  88. $this->removeDirectory($fullPath, true);
  89. }
  90. else {
  91. $this->remove($fullPath);
  92. }
  93. }
  94. if (!rmdir($path)) {
  95. throw new Exception('Failed to delete directory: ' . $path);
  96. }
  97. }
  98. public function move(string $sourcePath, string $destinationPath, bool $checkIfIsUploaded = false): void
  99. {
  100. $this->requirePathToExist($sourcePath);
  101. if ($checkIfIsUploaded && !is_uploaded_file($sourcePath)) {
  102. throw new Exception('The given file is not uploaded through HTTP: ' . $sourcePath);
  103. }
  104. if (!rename($sourcePath, $destinationPath)) {
  105. throw new Exception('Failed to move file from ' . $sourcePath . ' to ' . $destinationPath);
  106. }
  107. }
  108. public function getParentDirectory(string $path): string
  109. {
  110. return dirname($path);
  111. }
  112. public function getCurrentDirectory(): ?string
  113. {
  114. $currentDirectory = getcwd();
  115. return empty($currentDirectory) ? null : $currentDirectory;
  116. }
  117. public function getAsString(string $path, int $offset = 0, $maxLength = null): string
  118. {
  119. if (!is_null($maxLength) && $maxLength < 0) {
  120. throw new InvalidArgumentException('The maximum length cannot be less then 0. ' . $maxLength . ' given');
  121. }
  122. // The file_get_contents's maxlength parameter does not have a default value
  123. if (is_null($maxLength)) {
  124. $result = file_get_contents($path, false, null, $offset);
  125. } else {
  126. $result = file_get_contents($path, false, null, $offset, $maxLength);
  127. }
  128. if ($result === false) {
  129. throw new Exception('Failed to read file: ' . $path);
  130. }
  131. return $result;
  132. }
  133. public function getList(string $path): array
  134. {
  135. if (!$this->isDirectory($path)) {
  136. throw new Exception('The given path is not a valid directory: ' . $path);
  137. }
  138. $content = scandir($path);
  139. if (!empty($content[0]) && $content[0] == '.') {
  140. unset($content[0]);
  141. }
  142. if (!empty($content[1]) && $content[1] == '..') {
  143. unset($content[1]);
  144. }
  145. return $content;
  146. }
  147. public function getListByGlob(string $path, string $pattern, int $flags = null): array
  148. {
  149. if (!$this->isDirectory($path)) {
  150. throw new Exception('The given path is not a valid directory: ' . $path);
  151. }
  152. $currentDir = $this->getCurrentDirectory();
  153. chdir($path);
  154. $result = glob($pattern, $flags);
  155. chdir($currentDir);
  156. if ($result === false) {
  157. throw new Exception('Failed to find paths by ' . $pattern . ' in ' . $path);
  158. }
  159. return $result;
  160. }
  161. public function getModificationTime(string $path): int
  162. {
  163. $this->requirePathToExist($path);
  164. $result = filemtime($path);
  165. if ($result === false) {
  166. throw new Exception('Failed to get modification time for file: ' . $path);
  167. }
  168. return $result;
  169. }
  170. public function getSize(string $path): int
  171. {
  172. $this->requirePathToExist($path);
  173. $result = filesize($path);
  174. if ($result === false) {
  175. throw new Exception('Failed to get the size of file: ' . $path);
  176. }
  177. return $result;
  178. }
  179. public function pathExists(string $path): bool
  180. {
  181. return file_exists($path);
  182. }
  183. public function isDirectory(string $path): bool
  184. {
  185. $this->requirePathToExist($path);
  186. return is_dir($path);
  187. }
  188. public function isFile(string $path): bool
  189. {
  190. $this->requirePathToExist($path);
  191. return is_file($path);
  192. }
  193. public function isSymlink(string $path): bool
  194. {
  195. $this->requirePathToExist($path);
  196. return is_link($path);
  197. }
  198. public function isReadable(string $path): bool
  199. {
  200. $this->requirePathToExist($path);
  201. return is_readable($path);
  202. }
  203. public function isWritable(string $path): bool
  204. {
  205. $this->requirePathToExist($path);
  206. return is_writable($path);
  207. }
  208. public function getBaseName(string $path, ?string $suffix = null): string
  209. {
  210. return basename($path, $suffix);
  211. }
  212. /**
  213. * @throws NotFoundException
  214. */
  215. private function requirePathToExist(string $path)
  216. {
  217. if (!$this->pathExists($path)) {
  218. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  219. }
  220. }
  221. }