/lib/File.php

https://github.com/max-shamaev/phpdaemon · PHP · 301 lines · 272 code · 22 blank · 7 comment · 39 complexity · 4be880874a820de53c57c73e0ab97e7f MD5 · raw file

  1. <?php
  2. /**
  3. * Connection
  4. *
  5. * @package Core
  6. *
  7. * @author Zorin Vasily <kak.serpom.po.yaitsam@gmail.com>
  8. */
  9. class File extends IOStream {
  10. public $priority = 10; // low priority
  11. public $chunkSize = 4096;
  12. public $stat;
  13. public $offset;
  14. public $fdCacheKey;
  15. public static function convertFlags($mode, $text = false) {
  16. $plus = strpos($mode, '+') !== false;
  17. $sync = strpos($mode, 's') !== false;
  18. $type = strtr($mode, array('b' => '', '+' => '', 's' => '', '!' => ''));
  19. if ($text) {
  20. return $type;
  21. }
  22. $types = array(
  23. 'r' => $plus ? EIO_O_RDWR : EIO_O_RDONLY,
  24. 'w' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT | EIO_O_TRUNC,
  25. 'a' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT | EIO_O_APPEND,
  26. 'x' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_EXCL | EIO_O_CREAT,
  27. 'c' => ($plus ? EIO_O_RDWR : EIO_O_WRONLY) | EIO_O_CREAT,
  28. );
  29. $m = $types[$type];
  30. if ($sync) {
  31. $m |= EIO_O_FSYNC;
  32. }
  33. return $m;
  34. }
  35. public function truncate($offset = 0, $cb = null, $pri = EIO_PRI_DEFAULT) {
  36. if (!FS::$supported) {
  37. $fp = fopen($this->path, 'r+');
  38. $r = $fp && ftruncate($fp, $offset);
  39. if ($cb) {
  40. call_user_func($cb, $this, $r);
  41. }
  42. return;
  43. }
  44. eio_ftruncate($this->fd, $offset, $pri, $cb, $this);
  45. }
  46. public function stat($cb, $pri = EIO_PRI_DEFAULT) {
  47. if (!FS::$supported) {
  48. call_user_func($cb, $this, FS::statPrepare(fstat($this->fd)));
  49. return;
  50. }
  51. if ($this->stat) {
  52. call_user_func($cb, $this, $this->stat);
  53. } else {
  54. eio_fstat($this->fd, $pri, function ($file, $stat) use ($cb) {
  55. $stat = FS::statPrepare($stat);
  56. $file->stat = $stat;
  57. call_user_func($cb, $file, $stat);
  58. }, $this);
  59. }
  60. }
  61. public function statvfs($cb, $pri = EIO_PRI_DEFAULT) {
  62. if (!FS::$supported) {
  63. call_user_func($cb, $this, false);
  64. return;
  65. }
  66. if ($this->statvfs) {
  67. call_user_func($cb, $this, $this->statvfs);
  68. } else {
  69. eio_fstatvfs($this->fd, $pri, function ($file, $stat) use ($cb) {
  70. $file->statvfs = $stat;
  71. call_user_func($cb, $file, $stat);
  72. }, $this);
  73. }
  74. }
  75. public function sync($cb, $pri = EIO_PRI_DEFAULT) {
  76. if (!FS::$supported) {
  77. call_user_func($cb, $this, true);
  78. return;
  79. }
  80. return eio_fsync($this->fd, $pri, $cb, $this);
  81. }
  82. public function datasync($cb, $pri = EIO_PRI_DEFAULT) {
  83. if (!FS::$supported) {
  84. call_user_func($cb, $this, true);
  85. return;
  86. }
  87. return eio_fdatasync($this->fd, $pri, $cb, $this);
  88. }
  89. public function write($data, $cb = null, $offset = null, $pri = EIO_PRI_DEFAULT) {
  90. if (!FS::$supported) {
  91. if ($offset !== null) {
  92. fseek($data, $offset);
  93. }
  94. $r = fwrite($this->fd, $data);
  95. if ($cb) {
  96. call_user_func($cb, $this, $r);
  97. }
  98. return;
  99. }
  100. return eio_write($this->fd, $data, null, $offset, $pri, $cb, $this);
  101. }
  102. public function chown($uid, $gid = -1, $cb, $pri = EIO_PRI_DEFAULT) {
  103. if (!FS::$supported) {
  104. $r = chown($path, $uid);
  105. if ($gid !== -1) {
  106. $r = $r && chgrp($path, $gid);
  107. }
  108. if ($cb) {
  109. call_user_func($cb, $this, $r);
  110. }
  111. return;
  112. }
  113. return eio_fchown($this->fd, $uid, $gid, $pri, $cb, $this);
  114. }
  115. public function touch($mtime, $atime = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
  116. if (!FS::$supported) {
  117. $r = touch($this->path, $mtime, $atime);
  118. if ($cb) {
  119. call_user_func($cb, $this, $r);
  120. }
  121. return;
  122. }
  123. eio_futime($this->fd, $atime, $mtime, $pri, $cb, $this);
  124. }
  125. public function clearStatCache() {
  126. $this->stat = null;
  127. $this->statvfs = null;
  128. }
  129. public function read($length, $offset = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
  130. if (!FS::$supported) {
  131. call_user_func($cb, $this, false);
  132. return;
  133. }
  134. $this->offset += $length;
  135. $file = $this;
  136. eio_read(
  137. $this->fd,
  138. $length,
  139. $offset !== null ? $offset : $this->offset,
  140. $pri,
  141. $cb ? $cb: $this->onRead,
  142. $this
  143. );
  144. return true;
  145. }
  146. public function sendfile($outfd, $cb, $offset = 0, $length = null, $pri = EIO_PRI_DEFAULT) {
  147. if (!FS::$supported) {
  148. call_user_func($cb, $this, false);
  149. return;
  150. }
  151. static $chunkSize = 1024;
  152. $handler = function ($file, $sent) use ($outfd, $cb, &$handler, &$offset, &$length, $pri, $chunkSize) {
  153. if ($sent === -1) {
  154. $sent = 0;
  155. }
  156. $offset += $sent;
  157. $length -= $sent;
  158. if ($length <= 0) {
  159. call_user_func($cb, $file, true);
  160. return;
  161. }
  162. if (!is_resource($outfd)) {
  163. call_user_func($cb, $file, false);
  164. return;
  165. }
  166. eio_sendfile($outfd, $file->fd, $offset, min($chunkSize, $length), $pri, $handler, $file);
  167. };
  168. if ($length !== null) {
  169. $handler($this, -1);
  170. return;
  171. }
  172. $this->stat(function ($file, $stat) use ($handler, &$length) {
  173. $length = $stat['size'];
  174. $handler($file, -1);
  175. }, $pri);
  176. }
  177. public function readahead($length, $offset = null, $cb = null, $pri = EIO_PRI_DEFAULT) {
  178. if (!FS::$supported) {
  179. call_user_func($cb, $this, false);
  180. return;
  181. }
  182. $this->offset += $length;
  183. eio_readahead(
  184. $this->fd,
  185. $length,
  186. $offset !== null ? $offset : $this->pos,
  187. $pri,
  188. $cb,
  189. $this
  190. );
  191. return true;
  192. }
  193. public function readAll($cb = null, $pri = EIO_PRI_DEFAULT) {
  194. $this->stat(function ($file, $stat) use ($cb, $pri) {
  195. if (!$stat) {
  196. call_user_func($cb, $file, false);
  197. return;
  198. }
  199. $offset = 0;
  200. $buf = '';
  201. $size = $stat['size'];
  202. $handler = function ($file, $data) use ($cb, &$handler, $size, &$offset, $pri, &$buf) {
  203. $buf .= $data;
  204. $offset += strlen($data);
  205. $len = min($file->chunkSize, $size - $offset);
  206. if ($offset >= $size) {
  207. call_user_func($cb, $file, $buf);
  208. return;
  209. }
  210. eio_read($file->fd, $len, $offset, $pri, $handler, $this);
  211. };
  212. eio_read($file->fd, min($file->chunkSize, $size), 0, $pri, $handler, $file);
  213. }, $pri);
  214. }
  215. public function readAllChunked($cb = null, $chunkcb = null, $pri = EIO_PRI_DEFAULT) {
  216. $this->stat(function ($file, $stat) use ($cb, $chunkcb, $pri) {
  217. if (!$stat) {
  218. call_user_func($cb, $file, false);
  219. return;
  220. }
  221. $offset = 0;
  222. $size = $stat['size'];
  223. $handler = function ($file, $data) use ($cb, $chunkcb, &$handler, $size, &$offset, $pri) {
  224. call_user_func($chunkcb, $file, $data);
  225. $offset += strlen($data);
  226. $len = min($file->chunkSize, $size - $offset);
  227. if ($offset >= $size) {
  228. call_user_func($cb, $file, true);
  229. return;
  230. }
  231. eio_read($file->fd, $len, $offset, $pri, $handler, $file);
  232. };
  233. eio_read($file->fd, min($file->chunkSize, $size), $offset, $pri, $handler, $file);
  234. }, $pri);
  235. }
  236. public function __toString() {
  237. return $this->path;
  238. }
  239. public function setChunkSize($n) {
  240. $this->chunkSize = $n;
  241. }
  242. public function setFd($fd) {
  243. $this->fd = $fd;
  244. if (!$this->inited) {
  245. $this->inited = true;
  246. $this->init();
  247. }
  248. }
  249. public function seek($offset, $cb, $pri) {
  250. if (!EIO::$supported) {
  251. fseek($this->fd, $offset);
  252. return;
  253. }
  254. return eio_seek($this->fd, $offset, $pri, $cb, $this);
  255. }
  256. public function tell() {
  257. if (EIO::$supported) {
  258. return $this->pos;
  259. }
  260. return ftell($this->fd);
  261. }
  262. public function close() {
  263. $this->closeFd();
  264. }
  265. public function closeFd() {
  266. if ($this->fdCacheKey !== null) {
  267. FS::$fdCache->invalidate($this->fdCacheKey);
  268. }
  269. if ($this->fd === null) {
  270. return;
  271. }
  272. if (FS::$supported) {
  273. $r = eio_close($this->fd);
  274. $this->fd = null;
  275. return $r;
  276. }
  277. fclose($this->fd);
  278. }
  279. }