class-wp-filesystem-direct.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. <?php
  2. /**
  3. * WordPress Direct Filesystem.
  4. *
  5. * @package WordPress
  6. * @subpackage Filesystem
  7. */
  8. /**
  9. * WordPress Filesystem Class for direct PHP file and folder manipulation.
  10. *
  11. * @since 2.5.0
  12. *
  13. * @see WP_Filesystem_Base
  14. */
  15. class WP_Filesystem_Direct extends WP_Filesystem_Base {
  16. /**
  17. * constructor
  18. *
  19. *
  20. * @param mixed $arg ignored argument
  21. */
  22. public function __construct($arg) {
  23. $this->method = 'direct';
  24. $this->errors = new WP_Error();
  25. }
  26. /**
  27. * Reads entire file into a string
  28. *
  29. *
  30. * @param string $file Name of the file to read.
  31. * @return string|bool The function returns the read data or false on failure.
  32. */
  33. public function get_contents($file) {
  34. return @file_get_contents($file);
  35. }
  36. /**
  37. * Reads entire file into an array
  38. *
  39. *
  40. * @param string $file Path to the file.
  41. * @return array|bool the file contents in an array or false on failure.
  42. */
  43. public function get_contents_array($file) {
  44. return @file($file);
  45. }
  46. /**
  47. * Write a string to a file
  48. *
  49. *
  50. * @param string $file Remote path to the file where to write the data.
  51. * @param string $contents The data to write.
  52. * @param int $mode Optional. The file permissions as octal number, usually 0644.
  53. * Default false.
  54. * @return bool False upon failure, true otherwise.
  55. */
  56. public function put_contents( $file, $contents, $mode = false ) {
  57. $fp = @fopen( $file, 'wb' );
  58. if ( ! $fp )
  59. return false;
  60. mbstring_binary_safe_encoding();
  61. $data_length = strlen( $contents );
  62. $bytes_written = fwrite( $fp, $contents );
  63. reset_mbstring_encoding();
  64. fclose( $fp );
  65. if ( $data_length !== $bytes_written )
  66. return false;
  67. $this->chmod( $file, $mode );
  68. return true;
  69. }
  70. /**
  71. * Gets the current working directory
  72. *
  73. *
  74. * @return string|bool the current working directory on success, or false on failure.
  75. */
  76. public function cwd() {
  77. return @getcwd();
  78. }
  79. /**
  80. * Change directory
  81. *
  82. *
  83. * @param string $dir The new current directory.
  84. * @return bool Returns true on success or false on failure.
  85. */
  86. public function chdir($dir) {
  87. return @chdir($dir);
  88. }
  89. /**
  90. * Changes file group
  91. *
  92. *
  93. * @param string $file Path to the file.
  94. * @param mixed $group A group name or number.
  95. * @param bool $recursive Optional. If set True changes file group recursively. Default false.
  96. * @return bool Returns true on success or false on failure.
  97. */
  98. public function chgrp($file, $group, $recursive = false) {
  99. if ( ! $this->exists($file) )
  100. return false;
  101. if ( ! $recursive )
  102. return @chgrp($file, $group);
  103. if ( ! $this->is_dir($file) )
  104. return @chgrp($file, $group);
  105. // Is a directory, and we want recursive
  106. $file = trailingslashit($file);
  107. $filelist = $this->dirlist($file);
  108. foreach ($filelist as $filename)
  109. $this->chgrp($file . $filename, $group, $recursive);
  110. return true;
  111. }
  112. /**
  113. * Changes filesystem permissions
  114. *
  115. *
  116. * @param string $file Path to the file.
  117. * @param int $mode Optional. The permissions as octal number, usually 0644 for files,
  118. * 0755 for dirs. Default false.
  119. * @param bool $recursive Optional. If set True changes file group recursively. Default false.
  120. * @return bool Returns true on success or false on failure.
  121. */
  122. public function chmod($file, $mode = false, $recursive = false) {
  123. if ( ! $mode ) {
  124. if ( $this->is_file($file) )
  125. $mode = FS_CHMOD_FILE;
  126. elseif ( $this->is_dir($file) )
  127. $mode = FS_CHMOD_DIR;
  128. else
  129. return false;
  130. }
  131. if ( ! $recursive || ! $this->is_dir($file) )
  132. return @chmod($file, $mode);
  133. // Is a directory, and we want recursive
  134. $file = trailingslashit($file);
  135. $filelist = $this->dirlist($file);
  136. foreach ( (array)$filelist as $filename => $filemeta)
  137. $this->chmod($file . $filename, $mode, $recursive);
  138. return true;
  139. }
  140. /**
  141. * Changes file owner
  142. *
  143. *
  144. * @param string $file Path to the file.
  145. * @param mixed $owner A user name or number.
  146. * @param bool $recursive Optional. If set True changes file owner recursively.
  147. * Default false.
  148. * @return bool Returns true on success or false on failure.
  149. */
  150. public function chown($file, $owner, $recursive = false) {
  151. if ( ! $this->exists($file) )
  152. return false;
  153. if ( ! $recursive )
  154. return @chown($file, $owner);
  155. if ( ! $this->is_dir($file) )
  156. return @chown($file, $owner);
  157. // Is a directory, and we want recursive
  158. $filelist = $this->dirlist($file);
  159. foreach ($filelist as $filename) {
  160. $this->chown($file . '/' . $filename, $owner, $recursive);
  161. }
  162. return true;
  163. }
  164. /**
  165. * Gets file owner
  166. *
  167. *
  168. * @param string $file Path to the file.
  169. * @return string|bool Username of the user or false on error.
  170. */
  171. public function owner($file) {
  172. $owneruid = @fileowner($file);
  173. if ( ! $owneruid )
  174. return false;
  175. if ( ! function_exists('posix_getpwuid') )
  176. return $owneruid;
  177. $ownerarray = posix_getpwuid($owneruid);
  178. return $ownerarray['name'];
  179. }
  180. /**
  181. * Gets file permissions
  182. *
  183. * FIXME does not handle errors in fileperms()
  184. *
  185. *
  186. * @param string $file Path to the file.
  187. * @return string Mode of the file (last 3 digits).
  188. */
  189. public function getchmod($file) {
  190. return substr( decoct( @fileperms( $file ) ), -3 );
  191. }
  192. /**
  193. *
  194. * @param string $file
  195. * @return string|false
  196. */
  197. public function group($file) {
  198. $gid = @filegroup($file);
  199. if ( ! $gid )
  200. return false;
  201. if ( ! function_exists('posix_getgrgid') )
  202. return $gid;
  203. $grouparray = posix_getgrgid($gid);
  204. return $grouparray['name'];
  205. }
  206. /**
  207. *
  208. * @param string $source
  209. * @param string $destination
  210. * @param bool $overwrite
  211. * @param int $mode
  212. * @return bool
  213. */
  214. public function copy($source, $destination, $overwrite = false, $mode = false) {
  215. if ( ! $overwrite && $this->exists($destination) )
  216. return false;
  217. $rtval = copy($source, $destination);
  218. if ( $mode )
  219. $this->chmod($destination, $mode);
  220. return $rtval;
  221. }
  222. /**
  223. *
  224. * @param string $source
  225. * @param string $destination
  226. * @param bool $overwrite
  227. * @return bool
  228. */
  229. public function move($source, $destination, $overwrite = false) {
  230. if ( ! $overwrite && $this->exists($destination) )
  231. return false;
  232. // Try using rename first. if that fails (for example, source is read only) try copy.
  233. if ( @rename($source, $destination) )
  234. return true;
  235. if ( $this->copy($source, $destination, $overwrite) && $this->exists($destination) ) {
  236. $this->delete($source);
  237. return true;
  238. } else {
  239. return false;
  240. }
  241. }
  242. /**
  243. *
  244. * @param string $file
  245. * @param bool $recursive
  246. * @param string $type
  247. * @return bool
  248. */
  249. public function delete($file, $recursive = false, $type = false) {
  250. if ( empty( $file ) ) // Some filesystems report this as /, which can cause non-expected recursive deletion of all files in the filesystem.
  251. return false;
  252. $file = str_replace( '\\', '/', $file ); // for win32, occasional problems deleting files otherwise
  253. if ( 'f' == $type || $this->is_file($file) )
  254. return @unlink($file);
  255. if ( ! $recursive && $this->is_dir($file) )
  256. return @rmdir($file);
  257. // At this point it's a folder, and we're in recursive mode
  258. $file = trailingslashit($file);
  259. $filelist = $this->dirlist($file, true);
  260. $retval = true;
  261. if ( is_array( $filelist ) ) {
  262. foreach ( $filelist as $filename => $fileinfo ) {
  263. if ( ! $this->delete($file . $filename, $recursive, $fileinfo['type']) )
  264. $retval = false;
  265. }
  266. }
  267. if ( file_exists($file) && ! @rmdir($file) )
  268. $retval = false;
  269. return $retval;
  270. }
  271. /**
  272. *
  273. * @param string $file
  274. * @return bool
  275. */
  276. public function exists($file) {
  277. return @file_exists($file);
  278. }
  279. /**
  280. *
  281. * @param string $file
  282. * @return bool
  283. */
  284. public function is_file($file) {
  285. return @is_file($file);
  286. }
  287. /**
  288. *
  289. * @param string $path
  290. * @return bool
  291. */
  292. public function is_dir($path) {
  293. return @is_dir($path);
  294. }
  295. /**
  296. *
  297. * @param string $file
  298. * @return bool
  299. */
  300. public function is_readable($file) {
  301. return @is_readable($file);
  302. }
  303. /**
  304. *
  305. * @param string $file
  306. * @return bool
  307. */
  308. public function is_writable($file) {
  309. return @is_writable($file);
  310. }
  311. /**
  312. *
  313. * @param string $file
  314. * @return int
  315. */
  316. public function atime($file) {
  317. return @fileatime($file);
  318. }
  319. /**
  320. *
  321. * @param string $file
  322. * @return int
  323. */
  324. public function mtime($file) {
  325. return @filemtime($file);
  326. }
  327. /**
  328. *
  329. * @param string $file
  330. * @return int
  331. */
  332. public function size($file) {
  333. return @filesize($file);
  334. }
  335. /**
  336. *
  337. * @param string $file
  338. * @param int $time
  339. * @param int $atime
  340. * @return bool
  341. */
  342. public function touch($file, $time = 0, $atime = 0) {
  343. if ($time == 0)
  344. $time = time();
  345. if ($atime == 0)
  346. $atime = time();
  347. return @touch($file, $time, $atime);
  348. }
  349. /**
  350. *
  351. * @param string $path
  352. * @param mixed $chmod
  353. * @param mixed $chown
  354. * @param mixed $chgrp
  355. * @return bool
  356. */
  357. public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
  358. // Safe mode fails with a trailing slash under certain PHP versions.
  359. $path = untrailingslashit($path);
  360. if ( empty($path) )
  361. return false;
  362. if ( ! $chmod )
  363. $chmod = FS_CHMOD_DIR;
  364. if ( ! @mkdir($path) )
  365. return false;
  366. $this->chmod($path, $chmod);
  367. if ( $chown )
  368. $this->chown($path, $chown);
  369. if ( $chgrp )
  370. $this->chgrp($path, $chgrp);
  371. return true;
  372. }
  373. /**
  374. *
  375. * @param string $path
  376. * @param bool $recursive
  377. * @return bool
  378. */
  379. public function rmdir($path, $recursive = false) {
  380. return $this->delete($path, $recursive);
  381. }
  382. /**
  383. *
  384. * @param string $path
  385. * @param bool $include_hidden
  386. * @param bool $recursive
  387. * @return bool|array
  388. */
  389. public function dirlist($path, $include_hidden = true, $recursive = false) {
  390. if ( $this->is_file($path) ) {
  391. $limit_file = basename($path);
  392. $path = dirname($path);
  393. } else {
  394. $limit_file = false;
  395. }
  396. if ( ! $this->is_dir($path) )
  397. return false;
  398. $dir = @dir($path);
  399. if ( ! $dir )
  400. return false;
  401. $ret = array();
  402. while (false !== ($entry = $dir->read()) ) {
  403. $struc = array();
  404. $struc['name'] = $entry;
  405. if ( '.' == $struc['name'] || '..' == $struc['name'] )
  406. continue;
  407. if ( ! $include_hidden && '.' == $struc['name'][0] )
  408. continue;
  409. if ( $limit_file && $struc['name'] != $limit_file)
  410. continue;
  411. $struc['perms'] = $this->gethchmod($path.'/'.$entry);
  412. $struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
  413. $struc['number'] = false;
  414. $struc['owner'] = $this->owner($path.'/'.$entry);
  415. $struc['group'] = $this->group($path.'/'.$entry);
  416. $struc['size'] = $this->size($path.'/'.$entry);
  417. $struc['lastmodunix']= $this->mtime($path.'/'.$entry);
  418. $struc['lastmod'] = date('M j',$struc['lastmodunix']);
  419. $struc['time'] = date('h:i:s',$struc['lastmodunix']);
  420. $struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
  421. if ( 'd' == $struc['type'] ) {
  422. if ( $recursive )
  423. $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
  424. else
  425. $struc['files'] = array();
  426. }
  427. $ret[ $struc['name'] ] = $struc;
  428. }
  429. $dir->close();
  430. unset($dir);
  431. return $ret;
  432. }
  433. }