PageRenderTime 126ms CodeModel.GetById 40ms app.highlight 46ms RepoModel.GetById 35ms app.codeStats 0ms

/wp-admin/includes/class-wp-filesystem-ftpext.php

https://bitbucket.org/abnopanda/wordpress
PHP | 393 lines | 318 code | 50 blank | 25 comment | 81 complexity | 52540bd90cee2c4d701efcf22fd26c4c MD5 | raw file
  1<?php
  2/**
  3 * WordPress FTP Filesystem.
  4 *
  5 * @package WordPress
  6 * @subpackage Filesystem
  7 */
  8
  9/**
 10 * WordPress Filesystem Class for implementing FTP.
 11 *
 12 * @since 2.5
 13 * @package WordPress
 14 * @subpackage Filesystem
 15 * @uses WP_Filesystem_Base Extends class
 16 */
 17class WP_Filesystem_FTPext extends WP_Filesystem_Base {
 18	var $link;
 19	var $errors = null;
 20	var $options = array();
 21
 22	function __construct($opt='') {
 23		$this->method = 'ftpext';
 24		$this->errors = new WP_Error();
 25
 26		//Check if possible to use ftp functions.
 27		if ( ! extension_loaded('ftp') ) {
 28			$this->errors->add('no_ftp_ext', __('The ftp PHP extension is not available'));
 29			return false;
 30		}
 31
 32		// Set defaults:
 33		//This Class uses the timeout on a per-connection basis, Others use it on a per-action basis.
 34
 35		if ( ! defined('FS_TIMEOUT') )
 36			define('FS_TIMEOUT', 240);
 37
 38		if ( empty($opt['port']) )
 39			$this->options['port'] = 21;
 40		else
 41			$this->options['port'] = $opt['port'];
 42
 43		if ( empty($opt['hostname']) )
 44			$this->errors->add('empty_hostname', __('FTP hostname is required'));
 45		else
 46			$this->options['hostname'] = $opt['hostname'];
 47
 48		if ( ! empty($opt['base']) )
 49			$this->wp_base = $opt['base'];
 50
 51		// Check if the options provided are OK.
 52		if ( empty($opt['username']) )
 53			$this->errors->add('empty_username', __('FTP username is required'));
 54		else
 55			$this->options['username'] = $opt['username'];
 56
 57		if ( empty($opt['password']) )
 58			$this->errors->add('empty_password', __('FTP password is required'));
 59		else
 60			$this->options['password'] = $opt['password'];
 61
 62		$this->options['ssl'] = false;
 63		if ( isset($opt['connection_type']) && 'ftps' == $opt['connection_type'] )
 64			$this->options['ssl'] = true;
 65	}
 66
 67	function connect() {
 68		if ( isset($this->options['ssl']) && $this->options['ssl'] && function_exists('ftp_ssl_connect') )
 69			$this->link = @ftp_ssl_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
 70		else
 71			$this->link = @ftp_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
 72
 73		if ( ! $this->link ) {
 74			$this->errors->add('connect', sprintf(__('Failed to connect to FTP Server %1$s:%2$s'), $this->options['hostname'], $this->options['port']));
 75			return false;
 76		}
 77
 78		if ( ! @ftp_login($this->link,$this->options['username'], $this->options['password']) ) {
 79			$this->errors->add('auth', sprintf(__('Username/Password incorrect for %s'), $this->options['username']));
 80			return false;
 81		}
 82
 83		//Set the Connection to use Passive FTP
 84		@ftp_pasv( $this->link, true );
 85		if ( @ftp_get_option($this->link, FTP_TIMEOUT_SEC) < FS_TIMEOUT )
 86			@ftp_set_option($this->link, FTP_TIMEOUT_SEC, FS_TIMEOUT);
 87
 88		return true;
 89	}
 90
 91	function get_contents($file, $type = '', $resumepos = 0 ) {
 92		if ( empty($type) )
 93			$type = FTP_BINARY;
 94
 95		$tempfile = wp_tempnam($file);
 96		$temp = fopen($tempfile, 'w+');
 97
 98		if ( ! $temp )
 99			return false;
100
101		if ( ! @ftp_fget($this->link, $temp, $file, $type, $resumepos) )
102			return false;
103
104		fseek($temp, 0); //Skip back to the start of the file being written to
105		$contents = '';
106
107		while ( ! feof($temp) )
108			$contents .= fread($temp, 8192);
109
110		fclose($temp);
111		unlink($tempfile);
112		return $contents;
113	}
114	function get_contents_array($file) {
115		return explode("\n", $this->get_contents($file));
116	}
117
118	function put_contents($file, $contents, $mode = false ) {
119		$tempfile = wp_tempnam($file);
120		$temp = fopen($tempfile, 'w+');
121		if ( ! $temp )
122			return false;
123
124		fwrite($temp, $contents);
125		fseek($temp, 0); //Skip back to the start of the file being written to
126
127		$type = $this->is_binary($contents) ? FTP_BINARY : FTP_ASCII;
128		$ret = @ftp_fput($this->link, $file, $temp, $type);
129
130		fclose($temp);
131		unlink($tempfile);
132
133		$this->chmod($file, $mode);
134
135		return $ret;
136	}
137	function cwd() {
138		$cwd = @ftp_pwd($this->link);
139		if ( $cwd )
140			$cwd = trailingslashit($cwd);
141		return $cwd;
142	}
143	function chdir($dir) {
144		return @ftp_chdir($this->link, $dir);
145	}
146	function chgrp($file, $group, $recursive = false ) {
147		return false;
148	}
149	function chmod($file, $mode = false, $recursive = false) {
150		if ( ! $mode ) {
151			if ( $this->is_file($file) )
152				$mode = FS_CHMOD_FILE;
153			elseif ( $this->is_dir($file) )
154				$mode = FS_CHMOD_DIR;
155			else
156				return false;
157		}
158
159		// chmod any sub-objects if recursive.
160		if ( $recursive && $this->is_dir($file) ) {
161			$filelist = $this->dirlist($file);
162			foreach ( (array)$filelist as $filename => $filemeta )
163				$this->chmod($file . '/' . $filename, $mode, $recursive);
164		}
165
166		// chmod the file or directory
167		if ( ! function_exists('ftp_chmod') )
168			return (bool)@ftp_site($this->link, sprintf('CHMOD %o %s', $mode, $file));
169		return (bool)@ftp_chmod($this->link, $mode, $file);
170	}
171	function chown($file, $owner, $recursive = false ) {
172		return false;
173	}
174	function owner($file) {
175		$dir = $this->dirlist($file);
176		return $dir[$file]['owner'];
177	}
178	function getchmod($file) {
179		$dir = $this->dirlist($file);
180		return $dir[$file]['permsn'];
181	}
182	function group($file) {
183		$dir = $this->dirlist($file);
184		return $dir[$file]['group'];
185	}
186	function copy($source, $destination, $overwrite = false, $mode = false) {
187		if ( ! $overwrite && $this->exists($destination) )
188			return false;
189		$content = $this->get_contents($source);
190		if ( false === $content)
191			return false;
192		return $this->put_contents($destination, $content, $mode);
193	}
194	function move($source, $destination, $overwrite = false) {
195		return ftp_rename($this->link, $source, $destination);
196	}
197
198	function delete($file, $recursive = false, $type = false) {
199		if ( empty($file) )
200			return false;
201		if ( 'f' == $type || $this->is_file($file) )
202			return @ftp_delete($this->link, $file);
203		if ( !$recursive )
204			return @ftp_rmdir($this->link, $file);
205
206		$filelist = $this->dirlist( trailingslashit($file) );
207		if ( !empty($filelist) )
208			foreach ( $filelist as $delete_file )
209				$this->delete( trailingslashit($file) . $delete_file['name'], $recursive, $delete_file['type'] );
210		return @ftp_rmdir($this->link, $file);
211	}
212
213	function exists($file) {
214		$list = @ftp_nlist($this->link, $file);
215		return !empty($list); //empty list = no file, so invert.
216	}
217	function is_file($file) {
218		return $this->exists($file) && !$this->is_dir($file);
219	}
220	function is_dir($path) {
221		$cwd = $this->cwd();
222		$result = @ftp_chdir($this->link, trailingslashit($path) );
223		if ( $result && $path == $this->cwd() || $this->cwd() != $cwd ) {
224			@ftp_chdir($this->link, $cwd);
225			return true;
226		}
227		return false;
228	}
229	function is_readable($file) {
230		//Get dir list, Check if the file is readable by the current user??
231		return true;
232	}
233	function is_writable($file) {
234		//Get dir list, Check if the file is writable by the current user??
235		return true;
236	}
237	function atime($file) {
238		return false;
239	}
240	function mtime($file) {
241		return ftp_mdtm($this->link, $file);
242	}
243	function size($file) {
244		return ftp_size($this->link, $file);
245	}
246	function touch($file, $time = 0, $atime = 0) {
247		return false;
248	}
249	function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
250		$path = untrailingslashit($path);
251		if ( empty($path) )
252			return false;
253
254		if ( !@ftp_mkdir($this->link, $path) )
255			return false;
256		$this->chmod($path, $chmod);
257		if ( $chown )
258			$this->chown($path, $chown);
259		if ( $chgrp )
260			$this->chgrp($path, $chgrp);
261		return true;
262	}
263	function rmdir($path, $recursive = false) {
264		return $this->delete($path, $recursive);
265	}
266
267	function parselisting($line) {
268		static $is_windows;
269		if ( is_null($is_windows) )
270			$is_windows = stripos( ftp_systype($this->link), 'win') !== false;
271
272		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) ) {
273			$b = array();
274			if ( $lucifer[3] < 70 )
275				$lucifer[3] +=2000;
276			else
277				$lucifer[3] += 1900; // 4digit year fix
278			$b['isdir'] = ( $lucifer[7] == '<DIR>');
279			if ( $b['isdir'] )
280				$b['type'] = 'd';
281			else
282				$b['type'] = 'f';
283			$b['size'] = $lucifer[7];
284			$b['month'] = $lucifer[1];
285			$b['day'] = $lucifer[2];
286			$b['year'] = $lucifer[3];
287			$b['hour'] = $lucifer[4];
288			$b['minute'] = $lucifer[5];
289			$b['time'] = @mktime($lucifer[4] + (strcasecmp($lucifer[6], "PM") == 0 ? 12 : 0), $lucifer[5], 0, $lucifer[1], $lucifer[2], $lucifer[3]);
290			$b['am/pm'] = $lucifer[6];
291			$b['name'] = $lucifer[8];
292		} elseif ( !$is_windows && $lucifer = preg_split('/[ ]/', $line, 9, PREG_SPLIT_NO_EMPTY)) {
293			//echo $line."\n";
294			$lcount = count($lucifer);
295			if ( $lcount < 8 )
296				return '';
297			$b = array();
298			$b['isdir'] = $lucifer[0]{0} === 'd';
299			$b['islink'] = $lucifer[0]{0} === 'l';
300			if ( $b['isdir'] )
301				$b['type'] = 'd';
302			elseif ( $b['islink'] )
303				$b['type'] = 'l';
304			else
305				$b['type'] = 'f';
306			$b['perms'] = $lucifer[0];
307			$b['number'] = $lucifer[1];
308			$b['owner'] = $lucifer[2];
309			$b['group'] = $lucifer[3];
310			$b['size'] = $lucifer[4];
311			if ( $lcount == 8 ) {
312				sscanf($lucifer[5], '%d-%d-%d', $b['year'], $b['month'], $b['day']);
313				sscanf($lucifer[6], '%d:%d', $b['hour'], $b['minute']);
314				$b['time'] = @mktime($b['hour'], $b['minute'], 0, $b['month'], $b['day'], $b['year']);
315				$b['name'] = $lucifer[7];
316			} else {
317				$b['month'] = $lucifer[5];
318				$b['day'] = $lucifer[6];
319				if ( preg_match('/([0-9]{2}):([0-9]{2})/', $lucifer[7], $l2) ) {
320					$b['year'] = date("Y");
321					$b['hour'] = $l2[1];
322					$b['minute'] = $l2[2];
323				} else {
324					$b['year'] = $lucifer[7];
325					$b['hour'] = 0;
326					$b['minute'] = 0;
327				}
328				$b['time'] = strtotime( sprintf('%d %s %d %02d:%02d', $b['day'], $b['month'], $b['year'], $b['hour'], $b['minute']) );
329				$b['name'] = $lucifer[8];
330			}
331		}
332
333		// Replace symlinks formatted as "source -> target" with just the source name
334		if ( $b['islink'] )
335			$b['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $b['name'] );
336
337		return $b;
338	}
339
340	function dirlist($path = '.', $include_hidden = true, $recursive = false) {
341		if ( $this->is_file($path) ) {
342			$limit_file = basename($path);
343			$path = dirname($path) . '/';
344		} else {
345			$limit_file = false;
346		}
347
348		$pwd = @ftp_pwd($this->link);
349		if ( ! @ftp_chdir($this->link, $path) ) // Cant change to folder = folder doesn't exist
350			return false;
351		$list = @ftp_rawlist($this->link, '-a', false);
352		@ftp_chdir($this->link, $pwd);
353
354		if ( empty($list) ) // Empty array = non-existent folder (real folder will show . at least)
355			return false;
356
357		$dirlist = array();
358		foreach ( $list as $k => $v ) {
359			$entry = $this->parselisting($v);
360			if ( empty($entry) )
361				continue;
362
363			if ( '.' == $entry['name'] || '..' == $entry['name'] )
364				continue;
365
366			if ( ! $include_hidden && '.' == $entry['name'][0] )
367				continue;
368
369			if ( $limit_file && $entry['name'] != $limit_file)
370				continue;
371
372			$dirlist[ $entry['name'] ] = $entry;
373		}
374
375		$ret = array();
376		foreach ( (array)$dirlist as $struc ) {
377			if ( 'd' == $struc['type'] ) {
378				if ( $recursive )
379					$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
380				else
381					$struc['files'] = array();
382			}
383
384			$ret[ $struc['name'] ] = $struc;
385		}
386		return $ret;
387	}
388
389	function __destruct() {
390		if ( $this->link )
391			ftp_close($this->link);
392	}
393}