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

/src/Nucleus/Library/FileSystem/File.php

https://bitbucket.org/jonbiard/nucleus
PHP | 233 lines | 96 code | 33 blank | 104 comment | 13 complexity | 8845c852712c8bb838e56c4d6e350290 MD5 | raw file
  1. <?php
  2. /**
  3. * Class File
  4. *
  5. * @package Nucleus\Library
  6. * @subpackage FileSystem
  7. *
  8. * @author Martin Biard <info@martinbiard.com>
  9. */
  10. namespace Nucleus\Library\FileSystem;
  11. use Nucleus\Library\Exception\IOException;
  12. /**
  13. * Class File
  14. *
  15. * @package Nucleus\Library
  16. * @subpackage FileSystem
  17. */
  18. class File
  19. {
  20. /**
  21. * File handle
  22. * @var resource
  23. */
  24. protected $fh;
  25. /**
  26. * File path
  27. * @var string
  28. */
  29. protected $path;
  30. /**
  31. * Constructor
  32. *
  33. * @param string $path The file path
  34. * @param string $mode The mode (see PHP's fopen() function)
  35. *
  36. * @throws IOException When the file path cannot be opened
  37. */
  38. public function __construct($path, $mode)
  39. {
  40. $this->path = $path;
  41. if (($this->fh = @fopen($this->path, $mode)) === false) {
  42. throw new IOException("Failed to open file: $this->path");
  43. }
  44. }
  45. /**
  46. * Closes the file
  47. *
  48. * @throws IOException When the file path cannot be closed
  49. */
  50. public function close()
  51. {
  52. if (($this->fh = @fclose($this->fh)) === false) {
  53. throw new IOException("Failed to close file: $this->path");
  54. }
  55. }
  56. /**
  57. * Gets the file's pointer offset
  58. *
  59. * @return int The position of the file pointer
  60. *
  61. * @throws IOException When the pointer offset cannot be fetched
  62. */
  63. public function getOffset()
  64. {
  65. if (($pos = @ftell($this->fh)) === false) {
  66. throw new IOException("Failed to get pointer offset in file: $this->path");
  67. }
  68. return $pos;
  69. }
  70. /**
  71. * Checks if the file pointer is at the end of the file
  72. *
  73. * @return bool True if the file pointer is pointing at the end of the file, false otherwise
  74. */
  75. public function isAtEOF()
  76. {
  77. return @feof($this->fh);
  78. }
  79. /**
  80. * Locks the file
  81. *
  82. * @param bool $exclusive Whether this should be an exclusive lock or not
  83. * @param bool $wait Whether to wait until the file gets released if another process is holding a lock on it
  84. *
  85. * @throws IOException When a lock cannot be established on the file
  86. */
  87. public function lock($exclusive = true, $wait = true)
  88. {
  89. $opts = $exclusive ? LOCK_EX : LOCK_SH;
  90. if (!$wait) {
  91. $opts |= LOCK_NB;
  92. }
  93. if (@flock($this->fh, $opts) === false) {
  94. throw new IOException("Failed to lock file: $this->path");
  95. }
  96. }
  97. /**
  98. * Reads characters from the file
  99. *
  100. * @param int $length The amount of characters to read
  101. *
  102. * @return string|bool The characters read or false on failure
  103. */
  104. public function read($length)
  105. {
  106. return @fread($this->fh, $length);
  107. }
  108. /**
  109. * Reads one character from the file
  110. *
  111. * @return string|bool The character read or false on failure
  112. */
  113. public function readChar()
  114. {
  115. return @fgetc($this->fh);
  116. }
  117. /**
  118. * Reads a line from the file
  119. *
  120. * @param null $length The amount of characters to read if a newline or EOF is not reached
  121. *
  122. * @return string The characters read
  123. */
  124. public function readLine($length = null)
  125. {
  126. if ($length === null) {
  127. return @fgets($this->fh);
  128. }
  129. return @fgets($this->fh, $length);
  130. }
  131. /**
  132. * Truncates the file to a certain size
  133. *
  134. * @param int $size The size to truncate to
  135. *
  136. * @throws IOException When the file cannot be resized
  137. */
  138. public function resize($size)
  139. {
  140. if (@ftruncate($this->fh, $size) === false) {
  141. throw new IOException("Failed to resize file: $this->path");
  142. }
  143. }
  144. /**
  145. * Seeks to a specific offset in the file
  146. *
  147. * Valid $from values are: 'start', 'current', and 'end'
  148. *
  149. * @param int $offset The offset
  150. * @param string $from Where to start the seek from
  151. *
  152. * @throws IOException When seeking an offset fails
  153. */
  154. public function seek($offset, $from = 'start')
  155. {
  156. switch (strtolower($from)) {
  157. case ('current'):
  158. $from = SEEK_CUR;
  159. break;
  160. case ('end'):
  161. $from = SEEK_END;
  162. break;
  163. default:
  164. $from = SEEK_SET;
  165. }
  166. if (@fseek($this->fh, $offset, $from) === -1) {
  167. throw new IOException("Failed to seek to offset in file: $this->path");
  168. }
  169. }
  170. /**
  171. * Unlocks the file
  172. *
  173. * @throws IOException When unlocking the file fails
  174. */
  175. public function unlock()
  176. {
  177. if (@flock($this->fh, LOCK_UN) === false) {
  178. throw new IOException("Failed to unlock file: $this->path");
  179. }
  180. }
  181. /**
  182. * Writes to the file
  183. *
  184. * @param mixed $data The data to write
  185. * @param null|int $length The amount of characters or bytes to write
  186. *
  187. * @throws IOException When writing to the file fails
  188. */
  189. public function write($data, $length = null)
  190. {
  191. if ($length === null) {
  192. $result = @fwrite($this->fh, $data);
  193. } else {
  194. $result = @fwrite($this->fh, $data, $length);
  195. }
  196. if ($result === false) {
  197. throw new IOException("Failed to write to file: $this->path");
  198. }
  199. }
  200. }