/wp-content/plugins/wp-migrate-db-pro/class/wpmdb-filesystem.php

https://gitlab.com/najomie/fit-hippie · PHP · 561 lines · 288 code · 94 blank · 179 comment · 79 complexity · 439be06cd4cfa9f4eaa5a984bd31568f MD5 · raw file

  1. <?php
  2. class WPMDB_Filesystem {
  3. private $wp_filesystem;
  4. private $credentials;
  5. private $use_filesystem = false;
  6. private $chmod_dir;
  7. private $chmod_file;
  8. /**
  9. * Pass `true` when instantiating to skip using WP_Filesystem
  10. *
  11. * @param bool $force_no_fs
  12. */
  13. public function __construct( $force_no_fs = false ) {
  14. if ( ! $force_no_fs && function_exists( 'request_filesystem_credentials' ) ) {
  15. if ( ( defined( 'WPMDB_WP_FILESYSTEM' ) && WPMDB_WP_FILESYSTEM ) || ! defined( 'WPMDB_WP_FILESYSTEM' ) ) {
  16. $this->maybe_init_wp_filesystem();
  17. }
  18. }
  19. // Set default permissions
  20. if ( defined( 'FS_CHMOD_DIR' ) ) {
  21. $this->chmod_dir = FS_CHMOD_DIR;
  22. } else {
  23. $this->chmod_dir = ( fileperms( ABSPATH ) & 0777 | 0755 );
  24. }
  25. if ( defined( 'FS_CHMOD_FILE' ) ) {
  26. $this->chmod_file = FS_CHMOD_FILE;
  27. } else {
  28. $this->chmod_file = ( fileperms( ABSPATH . 'index.php' ) & 0777 | 0644 );
  29. }
  30. }
  31. /**
  32. * Getter for the instantiated WP_Filesystem
  33. *
  34. * @return WP_Filesystem|false
  35. *
  36. * This should be used carefully since $wp_filesystem won't always have a value.
  37. */
  38. public function get_wp_filesystem() {
  39. if ( $this->use_filesystem ) {
  40. return $this->wp_filesystem;
  41. } else {
  42. return false;
  43. }
  44. }
  45. /**
  46. * Is WP_Filesystem being used?
  47. *
  48. * @return bool
  49. */
  50. public function using_wp_filesystem() {
  51. return $this->use_filesystem;
  52. }
  53. /**
  54. * Attempts to use the correct path for the FS method being used
  55. *
  56. * @param string $abs_path
  57. *
  58. * @return string
  59. */
  60. public function get_sanitized_path( $abs_path ) {
  61. if ( $this->using_wp_filesystem() ) {
  62. return str_replace( ABSPATH, $this->wp_filesystem->abspath(), $abs_path );
  63. }
  64. return $abs_path;
  65. }
  66. /**
  67. * Attempt to initiate WP_Filesystem
  68. *
  69. * If this fails, $use_filesystem is set to false and all methods in this class should use native php fallbacks
  70. * Thwarts `request_filesystem_credentials()` attempt to display a form for obtaining creds from users
  71. *
  72. * TODO: provide notice and input in wp-admin for users when this fails
  73. */
  74. public function maybe_init_wp_filesystem() {
  75. ob_start();
  76. $this->credentials = request_filesystem_credentials( '', '', false, false, null );
  77. $ob_contents = ob_get_contents();
  78. ob_end_clean();
  79. if ( wp_filesystem( $this->credentials ) ) {
  80. global $wp_filesystem;
  81. $this->wp_filesystem = $wp_filesystem;
  82. $this->use_filesystem = true;
  83. }
  84. }
  85. /**
  86. * Create file if not exists then set mtime and atime on file
  87. *
  88. * @param string $abs_path
  89. * @param int $time
  90. * @param int $atime
  91. *
  92. * @return bool
  93. */
  94. public function touch( $abs_path, $time = 0, $atime = 0 ) {
  95. if ( 0 == $time ) {
  96. $time = time();
  97. }
  98. if ( 0 == $atime ) {
  99. $atime = time();
  100. }
  101. $return = @touch( $abs_path, $time, $atime );
  102. if ( ! $return && $this->use_filesystem ) {
  103. $abs_path = $this->get_sanitized_path( $abs_path );
  104. $return = $this->wp_filesystem->touch( $abs_path, $time, $atime );
  105. }
  106. return $return;
  107. }
  108. /**
  109. * file_put_contents with chmod
  110. *
  111. * @param string $abs_path
  112. * @param string $contents
  113. *
  114. * @return bool
  115. */
  116. public function put_contents( $abs_path, $contents ) {
  117. $return = @file_put_contents( $abs_path, $contents );
  118. $this->chmod( $abs_path );
  119. if ( ! $return && $this->use_filesystem ) {
  120. $abs_path = $this->get_sanitized_path( $abs_path );
  121. $return = $this->wp_filesystem->put_contents( $abs_path, $contents, $this->chmod_file );
  122. }
  123. return (bool) $return;
  124. }
  125. /**
  126. * Does the specified file or dir exist
  127. *
  128. * @param string $abs_path
  129. *
  130. * @return bool
  131. */
  132. public function file_exists( $abs_path ) {
  133. $return = file_exists( $abs_path );
  134. if ( ! $return && $this->use_filesystem ) {
  135. $abs_path = $this->get_sanitized_path( $abs_path );
  136. $return = $this->wp_filesystem->exists( $abs_path );
  137. }
  138. return (bool) $return;
  139. }
  140. /**
  141. * Get a file's size
  142. *
  143. * @param string $abs_path
  144. *
  145. * @return int
  146. */
  147. public function filesize( $abs_path ) {
  148. $return = filesize( $abs_path );
  149. if ( ! $return && $this->use_filesystem ) {
  150. $abs_path = $this->get_sanitized_path( $abs_path );
  151. $return = $this->wp_filesystem->size( $abs_path );
  152. }
  153. return $return;
  154. }
  155. /**
  156. * Get the contents of a file as a string
  157. *
  158. * @param string $abs_path
  159. *
  160. * @return string
  161. */
  162. public function get_contents( $abs_path ) {
  163. $return = @file_get_contents( $abs_path );
  164. if ( ! $return && $this->use_filesystem ) {
  165. $abs_path = $this->get_sanitized_path( $abs_path );
  166. $return = $this->wp_filesystem->get_contents( $abs_path );
  167. }
  168. return $return;
  169. }
  170. /**
  171. * Delete a file
  172. *
  173. * @param string $abs_path
  174. *
  175. * @return bool
  176. */
  177. public function unlink( $abs_path ) {
  178. $return = @unlink( $abs_path );
  179. if ( ! $return && $this->use_filesystem ) {
  180. $abs_path = $this->get_sanitized_path( $abs_path );
  181. $return = $this->wp_filesystem->delete( $abs_path, false, false );
  182. }
  183. return $return;
  184. }
  185. /**
  186. * chmod a file
  187. *
  188. * @param string $abs_path
  189. * @param int $perms
  190. *
  191. * @return bool
  192. *
  193. * Leave $perms blank to use $this->chmod_file/DIR or pass value like 0777
  194. */
  195. public function chmod( $abs_path, $perms = null ) {
  196. if ( is_null( $perms ) ) {
  197. $perms = $this->is_file( $abs_path ) ? $this->chmod_file : $this->chmod_dir;
  198. }
  199. $return = @chmod( $abs_path, $perms );
  200. if ( ! $return && $this->use_filesystem ) {
  201. $abs_path = $this->get_sanitized_path( $abs_path );
  202. $return = $this->wp_filesystem->chmod( $abs_path, $perms, false );
  203. }
  204. return $return;
  205. }
  206. /**
  207. * Is the specified pat a directory?
  208. *
  209. * @param string $abs_path
  210. *
  211. * @return bool
  212. */
  213. public function is_dir( $abs_path ) {
  214. $return = is_dir( $abs_path );
  215. if ( ! $return && $this->use_filesystem ) {
  216. $abs_path = $this->get_sanitized_path( $abs_path );
  217. $return = $this->wp_filesystem->is_dir( $abs_path );
  218. }
  219. return $return;
  220. }
  221. /**
  222. * Is the specified path a file?
  223. *
  224. * @param string $abs_path
  225. *
  226. * @return bool
  227. */
  228. public function is_file( $abs_path ) {
  229. $return = is_file( $abs_path );
  230. if ( ! $return && $this->use_filesystem ) {
  231. $abs_path = $this->get_sanitized_path( $abs_path );
  232. $return = $this->wp_filesystem->is_file( $abs_path );
  233. }
  234. return $return;
  235. }
  236. /**
  237. * Is the specified path readable
  238. *
  239. * @param string $abs_path
  240. *
  241. * @return bool
  242. */
  243. public function is_readable( $abs_path ) {
  244. $return = is_readable( $abs_path );
  245. if ( ! $return && $this->use_filesystem ) {
  246. $abs_path = $this->get_sanitized_path( $abs_path );
  247. $return = $this->wp_filesystem->is_readable( $abs_path );
  248. }
  249. return $return;
  250. }
  251. /**
  252. * Is the specified path writable
  253. *
  254. * @param string $abs_path
  255. *
  256. * @return bool
  257. */
  258. public function is_writable( $abs_path ) {
  259. $return = is_writable( $abs_path );
  260. if ( ! $return && $this->use_filesystem ) {
  261. $abs_path = $this->get_sanitized_path( $abs_path );
  262. $return = $this->wp_filesystem->is_writable( $abs_path );
  263. }
  264. return $return;
  265. }
  266. /**
  267. * Recursive mkdir
  268. *
  269. * @param string $abs_path
  270. * @param int $perms
  271. *
  272. * @return bool
  273. */
  274. public function mkdir( $abs_path, $perms = null ) {
  275. if ( is_null( $perms ) ) {
  276. $perms = $this->chmod_dir;
  277. }
  278. if ( $this->is_dir( $abs_path ) ) {
  279. $this->chmod( $perms );
  280. return true;
  281. }
  282. try {
  283. $mkdirp = wp_mkdir_p( $abs_path );
  284. } catch ( Exception $e ) {
  285. $mkdirp = false;
  286. }
  287. if ( $mkdirp ) {
  288. $this->chmod( $perms );
  289. return true;
  290. }
  291. $return = @mkdir( $abs_path, $perms, true );
  292. if ( ! $return && $this->use_filesystem ) {
  293. $abs_path = $this->get_sanitized_path( $abs_path );
  294. if ( $this->is_dir( $abs_path ) ) {
  295. return true;
  296. }
  297. // WP_Filesystem doesn't offer a recursive mkdir()
  298. $abs_path = str_replace( '//', '/', $abs_path );
  299. $abs_path = rtrim( $abs_path, '/' );
  300. if ( empty( $abs_path ) ) {
  301. $abs_path = '/';
  302. }
  303. $dirs = explode( '/', ltrim( $abs_path, '/' ) );
  304. $current_dir = '';
  305. foreach ( $dirs as $dir ) {
  306. $current_dir .= '/' . $dir;
  307. if ( ! $this->is_dir( $current_dir ) ) {
  308. $this->wp_filesystem->mkdir( $current_dir, $perms );
  309. }
  310. }
  311. $return = $this->is_dir( $abs_path );
  312. }
  313. return $return;
  314. }
  315. /**
  316. * Delete a directory
  317. *
  318. * @param string $abs_path
  319. * @param bool $recursive
  320. *
  321. * @return bool
  322. */
  323. public function rmdir( $abs_path, $recursive = false ) {
  324. if ( ! $this->is_dir( $abs_path ) ) {
  325. return false;
  326. }
  327. // taken from WP_Filesystem_Direct
  328. if ( ! $recursive ) {
  329. $return = @rmdir( $abs_path );
  330. } else {
  331. // At this point it's a folder, and we're in recursive mode
  332. $abs_path = trailingslashit( $abs_path );
  333. $filelist = $this->scandir( $abs_path );
  334. $return = true;
  335. if ( is_array( $filelist ) ) {
  336. foreach ( $filelist as $filename => $fileinfo ) {
  337. if ( 'd' === $fileinfo['type'] ) {
  338. $return = $this->rmdir( $abs_path . $filename, $recursive );
  339. } else {
  340. $return = $this->unlink( $abs_path . $filename );
  341. }
  342. }
  343. }
  344. if ( file_exists( $abs_path ) && ! @rmdir( $abs_path ) ) {
  345. $return = false;
  346. }
  347. }
  348. if ( ! $return && $this->use_filesystem ) {
  349. $abs_path = $this->get_sanitized_path( $abs_path );
  350. return $this->wp_filesystem->rmdir( $abs_path, $recursive );
  351. }
  352. return $return;
  353. }
  354. /**
  355. * Get a list of files/folders under specified directory
  356. *
  357. * @param $abs_path
  358. *
  359. * @return array|bool
  360. */
  361. public function scandir( $abs_path ) {
  362. $dirlist = @scandir( $abs_path );
  363. if ( false === $dirlist ) {
  364. if ( $this->use_filesystem ) {
  365. $abs_path = $this->get_sanitized_path( $abs_path );
  366. return $this->wp_filesystem->dirlist( $abs_path, true, false );
  367. }
  368. return false;
  369. }
  370. $return = array();
  371. // normalize return to look somewhat like the return value for WP_Filesystem::dirlist
  372. foreach ( $dirlist as $entry ) {
  373. if ( '.' === $entry || '..' === $entry ) {
  374. continue;
  375. }
  376. $return[ $entry ] = array(
  377. 'name' => $entry,
  378. 'type' => $this->is_dir( $abs_path . '/' . $entry ) ? 'd' : 'f',
  379. );
  380. }
  381. return $return;
  382. }
  383. /**
  384. * Light wrapper for move_uploaded_file with chmod
  385. *
  386. * @param string $file
  387. * @param string $destination
  388. * @param int $perms
  389. *
  390. * @return bool
  391. *
  392. * TODO: look into replicating more functionality from wp_handle_upload()
  393. */
  394. public function move_uploaded_file( $file, $destination, $perms = null ) {
  395. $return = @move_uploaded_file( $file, $destination );
  396. if ( $return ) {
  397. $this->chmod( $destination, $perms );
  398. }
  399. return $return;
  400. }
  401. /**
  402. * Copy a file
  403. *
  404. * @param string $source_abs_path
  405. * @param string $destination_abs_path
  406. * @param bool $overwrite
  407. * @param int $perms
  408. *
  409. * @return bool
  410. *
  411. * Taken from WP_Filesystem_Direct
  412. */
  413. public function copy( $source_abs_path, $destination_abs_path, $overwrite = true, $perms = false ) {
  414. // error if source file doesn't exist
  415. if ( ! $this->file_exists( $source_abs_path ) ) {
  416. return false;
  417. }
  418. if ( ! $overwrite && $this->file_exists( $destination_abs_path ) ) {
  419. return false;
  420. }
  421. $return = copy( $source_abs_path, $destination_abs_path );
  422. if ( $perms && $return ) {
  423. $this->chmod( $destination_abs_path, $perms );
  424. }
  425. if ( ! $return && $this->use_filesystem ) {
  426. $source_abs_path = $this->get_sanitized_path( $source_abs_path );
  427. $destination_abs_path = $this->get_sanitized_path( $destination_abs_path );
  428. $return = $this->wp_filesystem->copy( $source_abs_path, $destination_abs_path, $overwrite, $perms );
  429. }
  430. return $return;
  431. }
  432. /**
  433. * Move a file
  434. *
  435. * @param string $source_abs_path
  436. * @param string $destination_abs_path
  437. * @param bool $overwrite
  438. *
  439. * @return bool
  440. */
  441. public function move( $source_abs_path, $destination_abs_path, $overwrite = true ) {
  442. // error if source file doesn't exist
  443. if ( ! $this->file_exists( $source_abs_path ) ) {
  444. return false;
  445. }
  446. // Try using rename first. if that fails (for example, source is read only) try copy.
  447. // Taken in part from WP_Filesystem_Direct
  448. if ( ! $overwrite && $this->file_exists( $destination_abs_path ) ) {
  449. return false;
  450. } elseif ( @rename( $source_abs_path, $destination_abs_path ) ) {
  451. return true;
  452. } else {
  453. if ( $this->copy( $source_abs_path, $destination_abs_path, $overwrite ) && $this->file_exists( $destination_abs_path ) ) {
  454. $this->unlink( $source_abs_path );
  455. return true;
  456. } else {
  457. $return = false;
  458. }
  459. }
  460. if ( ! $return && $this->use_filesystem ) {
  461. $source_abs_path = $this->get_sanitized_path( $source_abs_path );
  462. $destination_abs_path = $this->get_sanitized_path( $destination_abs_path );
  463. $return = $this->wp_filesystem->move( $source_abs_path, $destination_abs_path, $overwrite );
  464. }
  465. return $return;
  466. }
  467. }