WP_Filesystem_FTPext

WordPress Filesystem Class for implementing FTP.

Defined (1)

The class is defined in the following location(s).

/wp-admin/includes/class-wp-filesystem-ftpext.php  
  1. class WP_Filesystem_FTPext extends WP_Filesystem_Base { 
  2. public $link; 
  3.  
  4. /** 
  5. * @access public 
  6. * @param array $opt 
  7. */ 
  8. public function __construct( $opt = '' ) { 
  9. $this->method = 'ftpext'; 
  10. $this->errors = new WP_Error(); 
  11.  
  12. // Check if possible to use ftp functions. 
  13. if ( ! extension_loaded('ftp') ) { 
  14. $this->errors->add('no_ftp_ext', __('The ftp PHP extension is not available')); 
  15. return; 
  16.  
  17. // This Class uses the timeout on a per-connection basis, Others use it on a per-action basis. 
  18.  
  19. if ( ! defined('FS_TIMEOUT') ) 
  20. define('FS_TIMEOUT', 240); 
  21.  
  22. if ( empty($opt['port']) ) 
  23. $this->options['port'] = 21; 
  24. else 
  25. $this->options['port'] = $opt['port']; 
  26.  
  27. if ( empty($opt['hostname']) ) 
  28. $this->errors->add('empty_hostname', __('FTP hostname is required')); 
  29. else 
  30. $this->options['hostname'] = $opt['hostname']; 
  31.  
  32. // Check if the options provided are OK. 
  33. if ( empty($opt['username']) ) 
  34. $this->errors->add('empty_username', __('FTP username is required')); 
  35. else 
  36. $this->options['username'] = $opt['username']; 
  37.  
  38. if ( empty($opt['password']) ) 
  39. $this->errors->add('empty_password', __('FTP password is required')); 
  40. else 
  41. $this->options['password'] = $opt['password']; 
  42.  
  43. $this->options['ssl'] = false; 
  44. if ( isset($opt['connection_type']) && 'ftps' == $opt['connection_type'] ) 
  45. $this->options['ssl'] = true; 
  46.  
  47. /** 
  48. * @access public 
  49. * @return bool 
  50. */ 
  51. public function connect() { 
  52. if ( isset($this->options['ssl']) && $this->options['ssl'] && function_exists('ftp_ssl_connect') ) 
  53. $this->link = @ftp_ssl_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT); 
  54. else 
  55. $this->link = @ftp_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT); 
  56.  
  57. if ( ! $this->link ) { 
  58. $this->errors->add( 'connect',  
  59. /** translators: %s: hostname:port */ 
  60. sprintf( __( 'Failed to connect to FTP Server %s' ),  
  61. $this->options['hostname'] . ':' . $this->options['port'] 
  62. ); 
  63. return false; 
  64.  
  65. if ( ! @ftp_login( $this->link, $this->options['username'], $this->options['password'] ) ) { 
  66. $this->errors->add( 'auth',  
  67. /** translators: %s: username */ 
  68. sprintf( __( 'Username/Password incorrect for %s' ),  
  69. $this->options['username'] 
  70. ); 
  71. return false; 
  72.  
  73. // Set the Connection to use Passive FTP 
  74. @ftp_pasv( $this->link, true ); 
  75. if ( @ftp_get_option($this->link, FTP_TIMEOUT_SEC) < FS_TIMEOUT ) 
  76. @ftp_set_option($this->link, FTP_TIMEOUT_SEC, FS_TIMEOUT); 
  77.  
  78. return true; 
  79.  
  80. /** 
  81. * Retrieves the file contents. 
  82. * @since 2.5.0 
  83. * @access public 
  84. * @param string $file Filename. 
  85. * @return string|false File contents on success, false if no temp file could be opened,  
  86. * or if the file couldn't be retrieved. 
  87. */ 
  88. public function get_contents( $file ) { 
  89. $tempfile = wp_tempnam($file); 
  90. $temp = fopen($tempfile, 'w+'); 
  91.  
  92. if ( ! $temp ) { 
  93. unlink( $tempfile ); 
  94. return false; 
  95.  
  96. if ( ! @ftp_fget( $this->link, $temp, $file, FTP_BINARY ) ) { 
  97. fclose( $temp ); 
  98. unlink( $tempfile ); 
  99. return false; 
  100.  
  101. fseek( $temp, 0 ); // Skip back to the start of the file being written to 
  102. $contents = ''; 
  103.  
  104. while ( ! feof($temp) ) 
  105. $contents .= fread($temp, 8192); 
  106.  
  107. fclose($temp); 
  108. unlink($tempfile); 
  109. return $contents; 
  110.  
  111. /** 
  112. * @access public 
  113. * @param string $file 
  114. * @return array 
  115. */ 
  116. public function get_contents_array($file) { 
  117. return explode("\n", $this->get_contents($file)); 
  118.  
  119. /** 
  120. * @access public 
  121. * @param string $file 
  122. * @param string $contents 
  123. * @param bool|int $mode 
  124. * @return bool 
  125. */ 
  126. public function put_contents($file, $contents, $mode = false ) { 
  127. $tempfile = wp_tempnam($file); 
  128. $temp = fopen( $tempfile, 'wb+' ); 
  129.  
  130. if ( ! $temp ) { 
  131. unlink( $tempfile ); 
  132. return false; 
  133.  
  134. mbstring_binary_safe_encoding(); 
  135.  
  136. $data_length = strlen( $contents ); 
  137. $bytes_written = fwrite( $temp, $contents ); 
  138.  
  139. reset_mbstring_encoding(); 
  140.  
  141. if ( $data_length !== $bytes_written ) { 
  142. fclose( $temp ); 
  143. unlink( $tempfile ); 
  144. return false; 
  145.  
  146. fseek( $temp, 0 ); // Skip back to the start of the file being written to 
  147.  
  148. $ret = @ftp_fput( $this->link, $file, $temp, FTP_BINARY ); 
  149.  
  150. fclose($temp); 
  151. unlink($tempfile); 
  152.  
  153. $this->chmod($file, $mode); 
  154.  
  155. return $ret; 
  156.  
  157. /** 
  158. * @access public 
  159. * @return string 
  160. */ 
  161. public function cwd() { 
  162. $cwd = @ftp_pwd($this->link); 
  163. if ( $cwd ) 
  164. $cwd = trailingslashit($cwd); 
  165. return $cwd; 
  166.  
  167. /** 
  168. * @access public 
  169. * @param string $dir 
  170. * @return bool 
  171. */ 
  172. public function chdir($dir) { 
  173. return @ftp_chdir($this->link, $dir); 
  174.  
  175. /** 
  176. * @access public 
  177. * @param string $file 
  178. * @param int $mode 
  179. * @param bool $recursive 
  180. * @return bool 
  181. */ 
  182. public function chmod($file, $mode = false, $recursive = false) { 
  183. if ( ! $mode ) { 
  184. if ( $this->is_file($file) ) 
  185. $mode = FS_CHMOD_FILE; 
  186. elseif ( $this->is_dir($file) ) 
  187. $mode = FS_CHMOD_DIR; 
  188. else 
  189. return false; 
  190.  
  191. // chmod any sub-objects if recursive. 
  192. if ( $recursive && $this->is_dir($file) ) { 
  193. $filelist = $this->dirlist($file); 
  194. foreach ( (array)$filelist as $filename => $filemeta ) 
  195. $this->chmod($file . '/' . $filename, $mode, $recursive); 
  196.  
  197. // chmod the file or directory 
  198. if ( ! function_exists('ftp_chmod') ) 
  199. return (bool)@ftp_site($this->link, sprintf('CHMOD %o %s', $mode, $file)); 
  200. return (bool)@ftp_chmod($this->link, $mode, $file); 
  201.  
  202. /** 
  203. * @access public 
  204. * @param string $file 
  205. * @return string 
  206. */ 
  207. public function owner($file) { 
  208. $dir = $this->dirlist($file); 
  209. return $dir[$file]['owner']; 
  210. /** 
  211. * @access public 
  212. * @param string $file 
  213. * @return string 
  214. */ 
  215. public function getchmod($file) { 
  216. $dir = $this->dirlist($file); 
  217. return $dir[$file]['permsn']; 
  218.  
  219. /** 
  220. * @access public 
  221. * @param string $file 
  222. * @return string 
  223. */ 
  224. public function group($file) { 
  225. $dir = $this->dirlist($file); 
  226. return $dir[$file]['group']; 
  227.  
  228. /** 
  229. * @access public 
  230. * @param string $source 
  231. * @param string $destination 
  232. * @param bool $overwrite 
  233. * @param string|bool $mode 
  234. * @return bool 
  235. */ 
  236. public function copy($source, $destination, $overwrite = false, $mode = false) { 
  237. if ( ! $overwrite && $this->exists($destination) ) 
  238. return false; 
  239. $content = $this->get_contents($source); 
  240. if ( false === $content ) 
  241. return false; 
  242. return $this->put_contents($destination, $content, $mode); 
  243.  
  244. /** 
  245. * @access public 
  246. * @param string $source 
  247. * @param string $destination 
  248. * @param bool $overwrite 
  249. * @return bool 
  250. */ 
  251. public function move($source, $destination, $overwrite = false) { 
  252. return ftp_rename($this->link, $source, $destination); 
  253.  
  254. /** 
  255. * @access public 
  256. * @param string $file 
  257. * @param bool $recursive 
  258. * @param string $type 
  259. * @return bool 
  260. */ 
  261. public function delete($file, $recursive = false, $type = false) { 
  262. if ( empty($file) ) 
  263. return false; 
  264. if ( 'f' == $type || $this->is_file($file) ) 
  265. return @ftp_delete($this->link, $file); 
  266. if ( !$recursive ) 
  267. return @ftp_rmdir($this->link, $file); 
  268.  
  269. $filelist = $this->dirlist( trailingslashit($file) ); 
  270. if ( !empty($filelist) ) 
  271. foreach ( $filelist as $delete_file ) 
  272. $this->delete( trailingslashit($file) . $delete_file['name'], $recursive, $delete_file['type'] ); 
  273. return @ftp_rmdir($this->link, $file); 
  274.  
  275. /** 
  276. * @access public 
  277. * @param string $file 
  278. * @return bool 
  279. */ 
  280. public function exists($file) { 
  281. $list = @ftp_nlist($this->link, $file); 
  282.  
  283. if ( empty( $list ) && $this->is_dir( $file ) ) { 
  284. return true; // File is an empty directory. 
  285.  
  286. return !empty($list); //empty list = no file, so invert. 
  287.  
  288. /** 
  289. * @access public 
  290. * @param string $file 
  291. * @return bool 
  292. */ 
  293. public function is_file($file) { 
  294. return $this->exists($file) && !$this->is_dir($file); 
  295.  
  296. /** 
  297. * @access public 
  298. * @param string $path 
  299. * @return bool 
  300. */ 
  301. public function is_dir($path) { 
  302. $cwd = $this->cwd(); 
  303. $result = @ftp_chdir($this->link, trailingslashit($path) ); 
  304. if ( $result && $path == $this->cwd() || $this->cwd() != $cwd ) { 
  305. @ftp_chdir($this->link, $cwd); 
  306. return true; 
  307. return false; 
  308.  
  309. /** 
  310. * @access public 
  311. * @param string $file 
  312. * @return bool 
  313. */ 
  314. public function is_readable($file) { 
  315. return true; 
  316.  
  317. /** 
  318. * @access public 
  319. * @param string $file 
  320. * @return bool 
  321. */ 
  322. public function is_writable($file) { 
  323. return true; 
  324.  
  325. /** 
  326. * @access public 
  327. * @param string $file 
  328. * @return bool 
  329. */ 
  330. public function atime($file) { 
  331. return false; 
  332.  
  333. /** 
  334. * @access public 
  335. * @param string $file 
  336. * @return int 
  337. */ 
  338. public function mtime($file) { 
  339. return ftp_mdtm($this->link, $file); 
  340.  
  341. /** 
  342. * @access public 
  343. * @param string $file 
  344. * @return int 
  345. */ 
  346. public function size($file) { 
  347. return ftp_size($this->link, $file); 
  348.  
  349. /** 
  350. * @access public 
  351. * @param string $file 
  352. * @return bool 
  353. */ 
  354. public function touch($file, $time = 0, $atime = 0) { 
  355. return false; 
  356.  
  357. /** 
  358. * @access public 
  359. * @param string $path 
  360. * @param mixed $chmod 
  361. * @param mixed $chown 
  362. * @param mixed $chgrp 
  363. * @return bool 
  364. */ 
  365. public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) { 
  366. $path = untrailingslashit($path); 
  367. if ( empty($path) ) 
  368. return false; 
  369.  
  370. if ( !@ftp_mkdir($this->link, $path) ) 
  371. return false; 
  372. $this->chmod($path, $chmod); 
  373. return true; 
  374.  
  375. /** 
  376. * @access public 
  377. * @param string $path 
  378. * @param bool $recursive 
  379. * @return bool 
  380. */ 
  381. public function rmdir($path, $recursive = false) { 
  382. return $this->delete($path, $recursive); 
  383.  
  384. /** 
  385. * @access public 
  386. * @staticvar bool $is_windows 
  387. * @param string $line 
  388. * @return array 
  389. */ 
  390. public function parselisting($line) { 
  391. static $is_windows = null; 
  392. if ( is_null($is_windows) ) 
  393. $is_windows = stripos( ftp_systype($this->link), 'win') !== false; 
  394.  
  395. if ( $is_windows && preg_match('/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/', $line, $lucifer) ) { 
  396. $b = array(); 
  397. if ( $lucifer[3] < 70 ) 
  398. $lucifer[3] +=2000; 
  399. else 
  400. $lucifer[3] += 1900; // 4digit year fix 
  401. $b['isdir'] = ( $lucifer[7] == '<DIR>'); 
  402. if ( $b['isdir'] ) 
  403. $b['type'] = 'd'; 
  404. else 
  405. $b['type'] = 'f'; 
  406. $b['size'] = $lucifer[7]; 
  407. $b['month'] = $lucifer[1]; 
  408. $b['day'] = $lucifer[2]; 
  409. $b['year'] = $lucifer[3]; 
  410. $b['hour'] = $lucifer[4]; 
  411. $b['minute'] = $lucifer[5]; 
  412. $b['time'] = @mktime($lucifer[4] + (strcasecmp($lucifer[6], "PM") == 0 ? 12 : 0), $lucifer[5], 0, $lucifer[1], $lucifer[2], $lucifer[3]); 
  413. $b['am/pm'] = $lucifer[6]; 
  414. $b['name'] = $lucifer[8]; 
  415. } elseif ( !$is_windows && $lucifer = preg_split('/[ ]/', $line, 9, PREG_SPLIT_NO_EMPTY)) { 
  416. //echo $line."\n"; 
  417. $lcount = count($lucifer); 
  418. if ( $lcount < 8 ) 
  419. return ''; 
  420. $b = array(); 
  421. $b['isdir'] = $lucifer[0]{0} === 'd'; 
  422. $b['islink'] = $lucifer[0]{0} === 'l'; 
  423. if ( $b['isdir'] ) 
  424. $b['type'] = 'd'; 
  425. elseif ( $b['islink'] ) 
  426. $b['type'] = 'l'; 
  427. else 
  428. $b['type'] = 'f'; 
  429. $b['perms'] = $lucifer[0]; 
  430. $b['permsn'] = $this->getnumchmodfromh( $b['perms'] ); 
  431. $b['number'] = $lucifer[1]; 
  432. $b['owner'] = $lucifer[2]; 
  433. $b['group'] = $lucifer[3]; 
  434. $b['size'] = $lucifer[4]; 
  435. if ( $lcount == 8 ) { 
  436. sscanf($lucifer[5], '%d-%d-%d', $b['year'], $b['month'], $b['day']); 
  437. sscanf($lucifer[6], '%d:%d', $b['hour'], $b['minute']); 
  438. $b['time'] = @mktime($b['hour'], $b['minute'], 0, $b['month'], $b['day'], $b['year']); 
  439. $b['name'] = $lucifer[7]; 
  440. } else { 
  441. $b['month'] = $lucifer[5]; 
  442. $b['day'] = $lucifer[6]; 
  443. if ( preg_match('/([0-9]{2}):([0-9]{2})/', $lucifer[7], $l2) ) { 
  444. $b['year'] = date("Y"); 
  445. $b['hour'] = $l2[1]; 
  446. $b['minute'] = $l2[2]; 
  447. } else { 
  448. $b['year'] = $lucifer[7]; 
  449. $b['hour'] = 0; 
  450. $b['minute'] = 0; 
  451. $b['time'] = strtotime( sprintf('%d %s %d %02d:%02d', $b['day'], $b['month'], $b['year'], $b['hour'], $b['minute']) ); 
  452. $b['name'] = $lucifer[8]; 
  453.  
  454. // Replace symlinks formatted as "source -> target" with just the source name 
  455. if ( isset( $b['islink'] ) && $b['islink'] ) { 
  456. $b['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $b['name'] ); 
  457.  
  458. return $b; 
  459.  
  460. /** 
  461. * @access public 
  462. * @param string $path 
  463. * @param bool $include_hidden 
  464. * @param bool $recursive 
  465. * @return bool|array 
  466. */ 
  467. public function dirlist($path = '.', $include_hidden = true, $recursive = false) { 
  468. if ( $this->is_file($path) ) { 
  469. $limit_file = basename($path); 
  470. $path = dirname($path) . '/'; 
  471. } else { 
  472. $limit_file = false; 
  473.  
  474. $pwd = @ftp_pwd($this->link); 
  475. if ( ! @ftp_chdir($this->link, $path) ) // Cant change to folder = folder doesn't exist 
  476. return false; 
  477. $list = @ftp_rawlist($this->link, '-a', false); 
  478. @ftp_chdir($this->link, $pwd); 
  479.  
  480. if ( empty($list) ) // Empty array = non-existent folder (real folder will show . at least) 
  481. return false; 
  482.  
  483. $dirlist = array(); 
  484. foreach ( $list as $k => $v ) { 
  485. $entry = $this->parselisting($v); 
  486. if ( empty($entry) ) 
  487. continue; 
  488.  
  489. if ( '.' == $entry['name'] || '..' == $entry['name'] ) 
  490. continue; 
  491.  
  492. if ( ! $include_hidden && '.' == $entry['name'][0] ) 
  493. continue; 
  494.  
  495. if ( $limit_file && $entry['name'] != $limit_file) 
  496. continue; 
  497.  
  498. $dirlist[ $entry['name'] ] = $entry; 
  499.  
  500. $ret = array(); 
  501. foreach ( (array)$dirlist as $struc ) { 
  502. if ( 'd' == $struc['type'] ) { 
  503. if ( $recursive ) 
  504. $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive); 
  505. else 
  506. $struc['files'] = array(); 
  507.  
  508. $ret[ $struc['name'] ] = $struc; 
  509. return $ret; 
  510.  
  511. /** 
  512. * @access public 
  513. */ 
  514. public function __destruct() { 
  515. if ( $this->link ) 
  516. ftp_close($this->link);