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

/src/YapepBase/File/FileHandlerPhp.php

https://bitbucket.org/szeber/yapep_base
PHP | 547 lines | 205 code | 48 blank | 294 comment | 50 complexity | 89c1930f88ee8dad24d1645677a96343 MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of YAPEPBase.
  4. *
  5. * @package YapepBase
  6. * @subpackage File
  7. * @copyright 2011 The YAPEP Project All rights reserved.
  8. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  9. */
  10. namespace YapepBase\File;
  11. use YapepBase\Exception\File\Exception;
  12. use YapepBase\Exception\File\NotFoundException;
  13. use YapepBase\Exception\ParameterException;
  14. /**
  15. * Simple wrapper class for basic filesystem manipulations via PHP function.
  16. *
  17. * @package YapepBase
  18. * @subpackage File
  19. */
  20. class FileHandlerPhp implements IFileHandler {
  21. /**
  22. * Sets the access and modification time of a file or directory.
  23. *
  24. * @link http://php.net/manual/en/function.touch.php
  25. *
  26. * @param string $path Tha path to the file or directory.
  27. * @param int $modificationTime The modification time to set (timestamp).
  28. * @param int $accessTime The access time to set(timestamp).
  29. *
  30. * @return void
  31. *
  32. * @throws \YapepBase\Exception\File\Exception If the operation failed.
  33. */
  34. public function touch($path, $modificationTime = null, $accessTime = null) {
  35. if (!touch($path, $modificationTime, $accessTime)) {
  36. throw new Exception('Touch failed for path: ' . $path);
  37. }
  38. }
  39. /**
  40. * Makes a directory. Be aware that by default it is recursive.
  41. *
  42. * @link http://php.net/manual/en/function.mkdir.php
  43. *
  44. * @param string $path The directory or structure(in case of recursive mode) to create.
  45. * @param int $mode The mode (rights) of the created directory, use octal value.
  46. * @param bool $isRecursive If TRUE the whole structure will be created.
  47. *
  48. * @return void
  49. *
  50. * @throws \YapepBase\Exception\File\Exception If the operation failed.
  51. */
  52. public function makeDirectory($path, $mode = 0755, $isRecursive = true) {
  53. if (!mkdir($path, $mode, $isRecursive)) {
  54. throw new Exception('Failed to create directory: ' . $path);
  55. }
  56. // Since mkdir() is affected by the umask, do a chmod, so the new directory will have the correct permissions
  57. $this->changeMode($path, $mode);
  58. }
  59. /**
  60. * Writes the given content to a file.
  61. *
  62. * @link http://php.net/manual/en/function.file-put-contents.php
  63. *
  64. * @param string $path Path to the file.
  65. * @param mixed $data Can be either a string, an array or a stream resource.
  66. * @param bool $append If TRUE, the given data will appended after the already existent data.
  67. * @param bool $lock If TRUE, the file will be locked at the writing.
  68. *
  69. * @return int The byte count of the written data.
  70. *
  71. * @throws \YapepBase\Exception\File\Exception If the operation failed.
  72. */
  73. public function write($path, $data, $append = false, $lock = false) {
  74. $flag = 0;
  75. if ($append) {
  76. $flag = $flag | FILE_APPEND;
  77. }
  78. if ($lock) {
  79. $flag = $flag | LOCK_EX;
  80. }
  81. $result = file_put_contents($path, $data, $flag);
  82. if (false === $result) {
  83. throw new Exception('Failed to write data to file: ' . $path);
  84. }
  85. return $result;
  86. }
  87. /**
  88. * Changes the owner group and user of the file.
  89. *
  90. * @link http://php.net/manual/en/function.chgrp.php
  91. * @link http://php.net/manual/en/function.chown.php
  92. *
  93. * @param string $path Path to the file or directory.
  94. * @param string|int $group Name of the group, or the identifier.
  95. * @param string|int $user Name of the user, or the identifier.
  96. *
  97. * @return void
  98. *
  99. * @throws \YapepBase\Exception\File\NotFoundException If the file was not found.
  100. * @throws \YapepBase\Exception\File\Exception If it failed to set the owner.
  101. */
  102. public function changeOwner($path, $group = null, $user = null) {
  103. if (!$this->checkIsPathExists($path)) {
  104. throw new NotFoundException($path, 'Resource not found while changing owner: ' . $path);
  105. }
  106. if (!is_null($group) && !chgrp($path, $group)) {
  107. throw new Exception('Failed to set the group "' . $group . '" of the resource: ' . $path);
  108. }
  109. if (!is_null($user) && !chown($path, $user)) {
  110. throw new Exception('Failed to set the user "' . $user . '" of the resource: ' . $path);
  111. }
  112. }
  113. /**
  114. * Changes the mode of the file.
  115. *
  116. * @link http://php.net/manual/en/function.chmod.php
  117. *
  118. * @param string $path Path to the file or directory.
  119. * @param int $mode The mode to set, use octal values.
  120. *
  121. * @return void
  122. *
  123. * @throws \YapepBase\Exception\File\NotFoundException If the file was not found.
  124. * @throws \YapepBase\Exception\File\Exception If it failed to set the mode.
  125. */
  126. public function changeMode($path, $mode) {
  127. if (!$this->checkIsPathExists($path)) {
  128. throw new NotFoundException($path, 'Resource not found while changing mode: ' . $path);
  129. }
  130. if (!chmod($path, $mode)) {
  131. throw new Exception('Failed to set the mode "' . decoct($mode) . '" of the resource: ' . $path);
  132. }
  133. }
  134. /**
  135. * Copies a file.
  136. *
  137. * If the destination path already exists, it will be overwritten.
  138. *
  139. * @link http://php.net/manual/en/function.copy.php
  140. *
  141. * @param string $source Path to the source file.
  142. * @param string $destination The destination path.
  143. *
  144. * @return void
  145. *
  146. * @throws \YapepBase\Exception\File\NotFoundException If the source file was not found.
  147. * @throws \YapepBase\Exception\File\Exception If it failed to set the mode.
  148. */
  149. public function copy($source, $destination) {
  150. if (!$this->checkIsPathExists($source)) {
  151. throw new NotFoundException($source, 'Source file not found for copy: ' . $source);
  152. }
  153. if (!copy($source, $destination)) {
  154. throw new Exception('Failed to copy file from ' . $source . ' to ' . $destination);
  155. }
  156. }
  157. /**
  158. * Deletes a file.
  159. *
  160. * @link http://php.net/manual/en/function.unlink.php
  161. *
  162. * @param string $path Path to the file.
  163. *
  164. * @return void
  165. *
  166. * @throws \YapepBase\Exception\File\NotFoundException If the given path is not found.
  167. * @throws \YapepBase\Exception\File\Exception If it failed to delete the file or the given path
  168. * is not a regular file.
  169. */
  170. public function remove($path) {
  171. if ($this->checkIsDirectory($path)) {
  172. throw new Exception('The given path is not a valid file: ' . $path);
  173. }
  174. if (!unlink($path)) {
  175. throw new Exception('Failed to remove file: ' . $path);
  176. }
  177. }
  178. /**
  179. * Deletes a directory.
  180. *
  181. * @param string $path The directory to delete.
  182. * @param bool $isRecursive If TRUE the contents will be removed too.
  183. *
  184. * @throws \YapepBase\Exception\File\Exception If the given path is not empty, and recursive mode is off.
  185. * Or if the given path is not a valid directory, or deletion failed.
  186. *
  187. * @return void
  188. */
  189. public function removeDirectory($path, $isRecursive = false) {
  190. if (!$this->checkIsPathExists($path)) {
  191. return;
  192. }
  193. if (!$this->checkIsDirectory($path)) {
  194. throw new Exception('The given path is not a directory: ' . $path);
  195. }
  196. $content = $this->getList($path);
  197. // The given directory is not empty, but the deletion is not recursive
  198. if (!$isRecursive && !empty($content)) {
  199. throw new Exception('The given directory is not empty: ' . $path);
  200. }
  201. // Remove the contents one-by-one
  202. foreach ($content as $subPath) {
  203. $fullPath = rtrim($path, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $subPath;
  204. // We found a directory
  205. if ($this->checkIsDirectory($fullPath)) {
  206. $this->removeDirectory($fullPath, true);
  207. }
  208. // We found a file
  209. else {
  210. $this->remove($fullPath);
  211. }
  212. }
  213. if (!rmdir($path)) {
  214. throw new Exception('Failed to delete directory: ' . $path);
  215. }
  216. }
  217. /**
  218. * Moves the given file to the given destination.
  219. *
  220. * @link http://php.net/manual/en/function.rename.php
  221. * @link http://php.net/manual/en/function.move-uploaded-file.php
  222. *
  223. * @param string $sourcePath Path of the file to move.
  224. * @param string $destinationPath Destination of the moved file.
  225. * @param bool $checkIfIsUploaded If TRUE it will move the file only if the file was uploaded through HTTP.
  226. *
  227. * @throws \YapepBase\Exception\File\NotFoundException If the source file is not found.
  228. * @throws \YapepBase\Exception\File\Exception If the source file is not uploaded through HTTP and its checked
  229. * or the move failed.
  230. *
  231. * @return void
  232. */
  233. public function move($sourcePath, $destinationPath, $checkIfIsUploaded = false) {
  234. if (!$this->checkIsPathExists($sourcePath)) {
  235. throw new NotFoundException($sourcePath, 'The source file is not found for a file move: ' . $sourcePath);
  236. }
  237. if ($checkIfIsUploaded && !is_uploaded_file($sourcePath)) {
  238. throw new Exception('The given file is not uploaded through HTTP: ' . $sourcePath);
  239. }
  240. if (!rename($sourcePath, $destinationPath)) {
  241. throw new Exception('Failed to move file from ' . $sourcePath . ' to ' . $destinationPath);
  242. }
  243. }
  244. /**
  245. * Returns the parent directory's path.
  246. *
  247. * @link http://php.net/manual/en/function.dirname.php
  248. *
  249. * @param string $path Path of the file or directory.
  250. *
  251. * @return string
  252. */
  253. public function getParentDirectory($path) {
  254. return dirname($path);
  255. }
  256. /**
  257. * Returns the current working directory.
  258. *
  259. * @return string|bool The full path of the current directory or FALSE on failure.
  260. */
  261. public function getCurrentDirectory() {
  262. return getcwd();
  263. }
  264. /**
  265. * Reads entire file into a string.
  266. *
  267. * @link http://php.net/manual/en/function.file-get-contents.php
  268. *
  269. * @param string $path Path to the file to open
  270. * @param int $offset Offset where the reading starts on the original stream.
  271. * @param int $maxLength Maximum length of data read.
  272. *
  273. * @throws \YapepBase\Exception\File\NotFoundException If the given path does not exist.
  274. * @throws \YapepBase\Exception\File\Exception If the given path is not a file or the read failed.
  275. * @throws \YapepBase\Exception\ParameterException If the given maxLength is less then 0.
  276. *
  277. * @return string The content of the file, or FALSE on failure.
  278. */
  279. public function getAsString($path, $offset = -1, $maxLength = null) {
  280. if (!$this->checkIsFile($path)) {
  281. throw new Exception('The given path is not a file: ' . $path);
  282. }
  283. if (!is_null($maxLength) && $maxLength < 0) {
  284. throw new ParameterException('The maximum length cannot be less then 0. ' . $maxLength . ' given');
  285. }
  286. // The file_get_contents's maxlen parameter does not have a default value
  287. if (is_null($maxLength)) {
  288. $result = file_get_contents($path, null, null, $offset);
  289. }
  290. else {
  291. $result = file_get_contents($path, null, null, $offset, $maxLength);
  292. }
  293. if (false === $result) {
  294. throw new Exception('Failed to read file: ' . $path);
  295. }
  296. return $result;
  297. }
  298. /**
  299. * Returns the list of files and directories at the given path.
  300. *
  301. * @param string $path The directory that will be scanned.
  302. *
  303. * @throws \YapepBase\Exception\File\NotFoundException If the given path does not exist.
  304. * @throws \YapepBase\Exception\File\Exception If the given path is not a directory.
  305. *
  306. * @return array
  307. */
  308. public function getList($path) {
  309. if (!$this->checkIsDirectory($path)) {
  310. throw new Exception('The given path is not a valid directory: ' . $path);
  311. }
  312. $content = scandir($path);
  313. if (!empty($content[0]) && $content[0] == '.') {
  314. unset($content[0]);
  315. }
  316. if (!empty($content[1]) && $content[1] == '..') {
  317. unset($content[1]);
  318. }
  319. return $content;
  320. }
  321. /**
  322. * Lists the content of the given directory by glob.
  323. *
  324. * @link http://php.net/manual/en/function.glob.php
  325. *
  326. * @param string $path The path where the function should list.
  327. * @param string $pattern The pattern to match.
  328. * @param int $flags Flags to modify the behaviour of the search {@uses GLOB_*}.
  329. *
  330. * @throws \YapepBase\Exception\File\NotFoundException If the given path does not exist.
  331. * @throws \YapepBase\Exception\File\Exception If the given path is not a directory.
  332. *
  333. * @return array|bool The found path names, or FALSE on failure.
  334. */
  335. public function getListByGlob($path, $pattern, $flags = null) {
  336. if (!$this->checkIsDirectory($path)) {
  337. throw new Exception('The given path is not a valid directory: ' . $path);
  338. }
  339. $currentDir = $this->getCurrentDirectory();
  340. chdir($path);
  341. $result = glob($pattern, $flags);
  342. chdir($currentDir);
  343. return $result;
  344. }
  345. /**
  346. * Returns the file modification time.
  347. *
  348. * @link http://php.net/manual/en/function.filemtime.php
  349. *
  350. * @param string $path Path to the file or directory.
  351. *
  352. * @throws \YapepBase\Exception\File\NotFoundException If the given path does not exist.
  353. * @throws \YapepBase\Exception\File\Exception If we failed to get the modification time.
  354. *
  355. * @return int A unix timestamp, or FALSE on failure.
  356. */
  357. public function getModificationTime($path) {
  358. if (!$this->checkIsPathExists($path)) {
  359. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  360. }
  361. $result = filemtime($path);
  362. if (false === $result) {
  363. throw new Exception('Failed to get modification time for file: ' . $path);
  364. }
  365. return $result;
  366. }
  367. /**
  368. * Returns the size of the file.
  369. *
  370. * @link http://php.net/manual/en/function.filesize.php
  371. *
  372. * @param string $path Path to the file.
  373. *
  374. * @throws \YapepBase\Exception\File\NotFoundException If the given path does not exist.
  375. * @throws \YapepBase\Exception\File\Exception If we failed to get the file size.
  376. *
  377. * @return int|bool The size of the file in bytes, or FALSE on failure.
  378. */
  379. public function getSize($path) {
  380. if (!$this->checkIsPathExists($path)) {
  381. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  382. }
  383. $result = filesize($path);
  384. if (false === $result) {
  385. throw new Exception('Failed to get the size of file: ' . $path);
  386. }
  387. return $result;
  388. }
  389. /**
  390. * Checks if the given directory or file exists.
  391. *
  392. * @link http://php.net/manual/en/function.file-exists.php
  393. *
  394. * @param string $path Path to the file or directory.
  395. *
  396. * @return bool TRUE if it exits, FALSE if not.
  397. */
  398. public function checkIsPathExists($path) {
  399. return file_exists($path);
  400. }
  401. /**
  402. * Checks if the given path is a directory or not.
  403. *
  404. * @link http://php.net/manual/en/function.is-dir.php
  405. *
  406. * @param string $path The path to check.
  407. *
  408. * @return bool TRUE if it is a directory, FALSE if not.
  409. *
  410. * @throws \YapepBase\Exception\File\NotFoundException If the path does not exist.
  411. */
  412. public function checkIsDirectory($path) {
  413. if (!$this->checkIsPathExists($path)) {
  414. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  415. }
  416. return is_dir($path);
  417. }
  418. /**
  419. * Checks if the given path is a file or not.
  420. *
  421. * @link http://php.net/manual/en/function.is-file.php
  422. *
  423. * @param string $path The path to check.
  424. *
  425. * @return bool TRUE if it is a file, FALSE if not.
  426. *
  427. * @throws \YapepBase\Exception\File\NotFoundException If the path does not exits
  428. */
  429. public function checkIsFile($path) {
  430. if (!$this->checkIsPathExists($path)) {
  431. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  432. }
  433. return is_file($path);
  434. }
  435. /**
  436. * Checks if the given path is a symbolic link or not.
  437. *
  438. * @link http://php.net/manual/en/function.is-link.php
  439. *
  440. * @param string $path The path to check.
  441. *
  442. * @return bool TRUE if it is a symlink, FALSE if not.
  443. *
  444. * @throws \YapepBase\Exception\File\NotFoundException If the path does not exits
  445. */
  446. public function checkIsSymlink($path) {
  447. if (!$this->checkIsPathExists($path)) {
  448. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  449. }
  450. return is_link($path);
  451. }
  452. /**
  453. * Checks if the given path is readable.
  454. *
  455. * @link http://php.net/manual/en/function.is-writable.php
  456. *
  457. * @param string $path The path to check.
  458. *
  459. * @return bool TRUE if it is readable, FALSE if not.
  460. *
  461. * @throws \YapepBase\Exception\File\NotFoundException If the path does not exits
  462. */
  463. public function checkIsReadable($path) {
  464. if (!$this->checkIsPathExists($path)) {
  465. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  466. }
  467. return is_readable($path);
  468. }
  469. /**
  470. * Checks if the given path is writable.
  471. *
  472. * @link http://php.net/manual/en/function.is-writable.php
  473. *
  474. * @param string $path The path to check.
  475. *
  476. * @return bool TRUE if it is writable, FALSE if not.
  477. *
  478. * @throws \YapepBase\Exception\File\NotFoundException If the path does not exits
  479. */
  480. public function checkIsWritable($path) {
  481. if (!$this->checkIsPathExists($path)) {
  482. throw new NotFoundException($path, 'The given path does not exist: ' . $path);
  483. }
  484. return is_writable($path);
  485. }
  486. /**
  487. * Returns trailing name component of path
  488. *
  489. * @link http://php.net/manual/en/function.basename.php
  490. *
  491. * @param string $path The path.
  492. * @param string $suffix If the name component ends in suffix this will also be cut off.
  493. *
  494. * @return string
  495. */
  496. public function getBaseName($path, $suffix = null) {
  497. return basename($path, $suffix);
  498. }
  499. }