LockableFile.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. <?php
  2. namespace Illuminate\Filesystem;
  3. use Illuminate\Contracts\Filesystem\LockTimeoutException;
  4. class LockableFile
  5. {
  6. /**
  7. * The file resource.
  8. *
  9. * @var resource
  10. */
  11. protected $handle;
  12. /**
  13. * The file path.
  14. *
  15. * @var string
  16. */
  17. protected $path;
  18. /**
  19. * Indicates if the file is locked.
  20. *
  21. * @var bool
  22. */
  23. protected $isLocked = false;
  24. /**
  25. * Create a new File instance.
  26. *
  27. * @param string $path
  28. * @param string $mode
  29. */
  30. public function __construct($path, $mode)
  31. {
  32. $this->path = $path;
  33. $this->ensureDirectoryExists($path);
  34. $this->createResource($path, $mode);
  35. }
  36. /**
  37. * Create the file's directory if necessary.
  38. *
  39. * @param string $path
  40. * @return void
  41. */
  42. protected function ensureDirectoryExists($path)
  43. {
  44. if (! file_exists(dirname($path))) {
  45. @mkdir(dirname($path), 0777, true);
  46. }
  47. }
  48. /**
  49. * Create the file resource.
  50. *
  51. * @param string $path
  52. * @param string $mode
  53. * @return void
  54. *
  55. * @throws \Exception
  56. */
  57. protected function createResource($path, $mode)
  58. {
  59. $this->handle = fopen($path, $mode);
  60. }
  61. /**
  62. * Read the file contents.
  63. *
  64. * @param int|null $length
  65. * @return string
  66. */
  67. public function read($length = null)
  68. {
  69. clearstatcache(true, $this->path);
  70. return fread($this->handle, $length ?? ($this->size() ?: 1));
  71. }
  72. /**
  73. * Get the file size.
  74. *
  75. * @return int
  76. */
  77. public function size()
  78. {
  79. return filesize($this->path);
  80. }
  81. /**
  82. * Write to the file.
  83. *
  84. * @param string $contents
  85. * @return $this
  86. */
  87. public function write($contents)
  88. {
  89. fwrite($this->handle, $contents);
  90. fflush($this->handle);
  91. return $this;
  92. }
  93. /**
  94. * Truncate the file.
  95. *
  96. * @return $this
  97. */
  98. public function truncate()
  99. {
  100. rewind($this->handle);
  101. ftruncate($this->handle, 0);
  102. return $this;
  103. }
  104. /**
  105. * Get a shared lock on the file.
  106. *
  107. * @param bool $block
  108. * @return $this
  109. *
  110. * @throws \Illuminate\Contracts\Filesystem\LockTimeoutException
  111. */
  112. public function getSharedLock($block = false)
  113. {
  114. if (! flock($this->handle, LOCK_SH | ($block ? 0 : LOCK_NB))) {
  115. throw new LockTimeoutException("Unable to acquire file lock at path [{$this->path}].");
  116. }
  117. $this->isLocked = true;
  118. return $this;
  119. }
  120. /**
  121. * Get an exclusive lock on the file.
  122. *
  123. * @param bool $block
  124. * @return $this
  125. *
  126. * @throws \Illuminate\Contracts\Filesystem\LockTimeoutException
  127. */
  128. public function getExclusiveLock($block = false)
  129. {
  130. if (! flock($this->handle, LOCK_EX | ($block ? 0 : LOCK_NB))) {
  131. throw new LockTimeoutException("Unable to acquire file lock at path [{$this->path}].");
  132. }
  133. $this->isLocked = true;
  134. return $this;
  135. }
  136. /**
  137. * Release the lock on the file.
  138. *
  139. * @return $this
  140. */
  141. public function releaseLock()
  142. {
  143. flock($this->handle, LOCK_UN);
  144. $this->isLocked = false;
  145. return $this;
  146. }
  147. /**
  148. * Close the file.
  149. *
  150. * @return bool
  151. */
  152. public function close()
  153. {
  154. if ($this->isLocked) {
  155. $this->releaseLock();
  156. }
  157. return fclose($this->handle);
  158. }
  159. }