WordPress 4.4.1
[autoinstalls/wordpress.git] / wp-admin / includes / class-wp-filesystem-ftpsockets.php
1 <?php
2 /**
3  * WordPress FTP Sockets Filesystem.
4  *
5  * @package WordPress
6  * @subpackage Filesystem
7  */
8
9 /**
10  * WordPress Filesystem Class for implementing FTP Sockets.
11  *
12  * @since 2.5.0
13  * @package WordPress
14  * @subpackage Filesystem
15  * @uses WP_Filesystem_Base Extends class
16  */
17 class WP_Filesystem_ftpsockets extends WP_Filesystem_Base {
18         /**
19          * @access public
20          * @var ftp
21          */
22         public $ftp;
23
24         /**
25          * @access public
26          *
27          * @param array $opt
28          */
29         public function __construct( $opt  = '' ) {
30                 $this->method = 'ftpsockets';
31                 $this->errors = new WP_Error();
32
33                 // Check if possible to use ftp functions.
34                 if ( ! @include_once( ABSPATH . 'wp-admin/includes/class-ftp.php' ) ) {
35                         return;
36                 }
37                 $this->ftp = new ftp();
38
39                 if ( empty($opt['port']) )
40                         $this->options['port'] = 21;
41                 else
42                         $this->options['port'] = $opt['port'];
43
44                 if ( empty($opt['hostname']) )
45                         $this->errors->add('empty_hostname', __('FTP hostname is required'));
46                 else
47                         $this->options['hostname'] = $opt['hostname'];
48
49                 // Check if the options provided are OK.
50                 if ( empty ($opt['username']) )
51                         $this->errors->add('empty_username', __('FTP username is required'));
52                 else
53                         $this->options['username'] = $opt['username'];
54
55                 if ( empty ($opt['password']) )
56                         $this->errors->add('empty_password', __('FTP password is required'));
57                 else
58                         $this->options['password'] = $opt['password'];
59         }
60
61         /**
62          * @access public
63          *
64          * @return bool
65          */
66         public function connect() {
67                 if ( ! $this->ftp )
68                         return false;
69
70                 $this->ftp->setTimeout(FS_CONNECT_TIMEOUT);
71
72                 if ( ! $this->ftp->SetServer( $this->options['hostname'], $this->options['port'] ) ) {
73                         $this->errors->add( 'connect',
74                                 /* translators: %s: hostname:port */
75                                 sprintf( __( 'Failed to connect to FTP Server %s' ),
76                                         $this->options['hostname'] . ':' . $this->options['port']
77                                 )
78                         );
79                         return false;
80                 }
81
82                 if ( ! $this->ftp->connect() ) {
83                         $this->errors->add( 'connect',
84                                 /* translators: %s: hostname:port */
85                                 sprintf( __( 'Failed to connect to FTP Server %s' ),
86                                         $this->options['hostname'] . ':' . $this->options['port']
87                                 )
88                         );
89                         return false;
90                 }
91
92                 if ( ! $this->ftp->login( $this->options['username'], $this->options['password'] ) ) {
93                         $this->errors->add( 'auth',
94                                 /* translators: %s: username */
95                                 sprintf( __( 'Username/Password incorrect for %s' ),
96                                         $this->options['username']
97                                 )
98                         );
99                         return false;
100                 }
101
102                 $this->ftp->SetType( FTP_BINARY );
103                 $this->ftp->Passive( true );
104                 $this->ftp->setTimeout( FS_TIMEOUT );
105                 return true;
106         }
107
108         /**
109          * Retrieves the file contents.
110          *
111          * @since 2.5.0
112          * @access public
113          *
114          * @param string $file Filename.
115          * @return string|false File contents on success, false if no temp file could be opened,
116          *                      or if the file doesn't exist.
117          */
118         public function get_contents( $file ) {
119                 if ( ! $this->exists($file) )
120                         return false;
121
122                 $temp = wp_tempnam( $file );
123
124                 if ( ! $temphandle = fopen($temp, 'w+') )
125                         return false;
126
127                 mbstring_binary_safe_encoding();
128
129                 if ( ! $this->ftp->fget($temphandle, $file) ) {
130                         fclose($temphandle);
131                         unlink($temp);
132
133                         reset_mbstring_encoding();
134
135                         return ''; // Blank document, File does exist, It's just blank.
136                 }
137
138                 reset_mbstring_encoding();
139
140                 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
141                 $contents = '';
142
143                 while ( ! feof($temphandle) )
144                         $contents .= fread($temphandle, 8192);
145
146                 fclose($temphandle);
147                 unlink($temp);
148                 return $contents;
149         }
150
151         /**
152          * @access public
153          *
154          * @param string $file
155          * @return array
156          */
157         public function get_contents_array($file) {
158                 return explode("\n", $this->get_contents($file) );
159         }
160
161         /**
162          * @access public
163          *
164          * @param string $file
165          * @param string $contents
166          * @param int|bool $mode
167          * @return bool
168          */
169         public function put_contents($file, $contents, $mode = false ) {
170                 $temp = wp_tempnam( $file );
171                 if ( ! $temphandle = @fopen($temp, 'w+') ) {
172                         unlink($temp);
173                         return false;
174                 }
175
176                 // The FTP class uses string functions internally during file download/upload
177                 mbstring_binary_safe_encoding();
178
179                 $bytes_written = fwrite( $temphandle, $contents );
180                 if ( false === $bytes_written || $bytes_written != strlen( $contents ) ) {
181                         fclose( $temphandle );
182                         unlink( $temp );
183
184                         reset_mbstring_encoding();
185
186                         return false;
187                 }
188
189                 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
190
191                 $ret = $this->ftp->fput($file, $temphandle);
192
193                 reset_mbstring_encoding();
194
195                 fclose($temphandle);
196                 unlink($temp);
197
198                 $this->chmod($file, $mode);
199
200                 return $ret;
201         }
202
203         /**
204          * @access public
205          *
206          * @return string
207          */
208         public function cwd() {
209                 $cwd = $this->ftp->pwd();
210                 if ( $cwd )
211                         $cwd = trailingslashit($cwd);
212                 return $cwd;
213         }
214
215         /**
216          * @access public
217          *
218          * @param string $file
219          * @return bool
220          */
221         public function chdir($file) {
222                 return $this->ftp->chdir($file);
223         }
224
225         /**
226          * @access public
227          *
228          * @param string $file
229          * @param int|bool $mode
230          * @param bool $recursive
231          * @return bool
232          */
233         public function chmod($file, $mode = false, $recursive = false ) {
234                 if ( ! $mode ) {
235                         if ( $this->is_file($file) )
236                                 $mode = FS_CHMOD_FILE;
237                         elseif ( $this->is_dir($file) )
238                                 $mode = FS_CHMOD_DIR;
239                         else
240                                 return false;
241                 }
242
243                 // chmod any sub-objects if recursive.
244                 if ( $recursive && $this->is_dir($file) ) {
245                         $filelist = $this->dirlist($file);
246                         foreach ( (array)$filelist as $filename => $filemeta )
247                                 $this->chmod($file . '/' . $filename, $mode, $recursive);
248                 }
249
250                 // chmod the file or directory
251                 return $this->ftp->chmod($file, $mode);
252         }
253
254         /**
255          * @access public
256          *
257          * @param string $file
258          * @return string
259          */
260         public function owner($file) {
261                 $dir = $this->dirlist($file);
262                 return $dir[$file]['owner'];
263         }
264
265         /**
266          * @access public
267          *
268          * @param string $file
269          * @return string
270          */
271         public function getchmod($file) {
272                 $dir = $this->dirlist($file);
273                 return $dir[$file]['permsn'];
274         }
275
276         /**
277          * @access public
278          *
279          * @param string $file
280          * @return string
281          */
282         public function group($file) {
283                 $dir = $this->dirlist($file);
284                 return $dir[$file]['group'];
285         }
286
287         /**
288          * @access public
289          *
290          * @param string   $source
291          * @param string   $destination
292          * @param bool     $overwrite
293          * @param int|bool $mode
294          * @return bool
295          */
296         public function copy($source, $destination, $overwrite = false, $mode = false) {
297                 if ( ! $overwrite && $this->exists($destination) )
298                         return false;
299
300                 $content = $this->get_contents($source);
301                 if ( false === $content )
302                         return false;
303
304                 return $this->put_contents($destination, $content, $mode);
305         }
306
307         /**
308          * @access public
309          *
310          * @param string $source
311          * @param string $destination
312          * @param bool   $overwrite
313          * @return bool
314          */
315         public function move($source, $destination, $overwrite = false ) {
316                 return $this->ftp->rename($source, $destination);
317         }
318
319         /**
320          * @access public
321          *
322          * @param string $file
323          * @param bool   $recursive
324          * @param string $type
325          * @return bool
326          */
327         public function delete($file, $recursive = false, $type = false) {
328                 if ( empty($file) )
329                         return false;
330                 if ( 'f' == $type || $this->is_file($file) )
331                         return $this->ftp->delete($file);
332                 if ( !$recursive )
333                         return $this->ftp->rmdir($file);
334
335                 return $this->ftp->mdel($file);
336         }
337
338         /**
339          * @access public
340          *
341          * @param string $file
342          * @return bool
343          */
344         public function exists( $file ) {
345                 $list = $this->ftp->nlist( $file );
346
347                 if ( empty( $list ) && $this->is_dir( $file ) ) {
348                         return true; // File is an empty directory.
349                 }
350
351                 return !empty( $list ); //empty list = no file, so invert.
352                 // Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server.
353         }
354
355         /**
356          * @access public
357          *
358          * @param string $file
359          * @return bool
360          */
361         public function is_file($file) {
362                 if ( $this->is_dir($file) )
363                         return false;
364                 if ( $this->exists($file) )
365                         return true;
366                 return false;
367         }
368
369         /**
370          * @access public
371          *
372          * @param string $path
373          * @return bool
374          */
375         public function is_dir($path) {
376                 $cwd = $this->cwd();
377                 if ( $this->chdir($path) ) {
378                         $this->chdir($cwd);
379                         return true;
380                 }
381                 return false;
382         }
383
384         /**
385          * @access public
386          *
387          * @param string $file
388          * @return bool
389          */
390         public function is_readable($file) {
391                 return true;
392         }
393
394         /**
395          * @access public
396          *
397          * @param string $file
398          * @return bool
399          */
400         public function is_writable($file) {
401                 return true;
402         }
403
404         /**
405          * @access public
406          *
407          * @param string $file
408          * @return bool
409          */
410         public function atime($file) {
411                 return false;
412         }
413
414         /**
415          * @access public
416          *
417          * @param string $file
418          * @return int
419          */
420         public function mtime($file) {
421                 return $this->ftp->mdtm($file);
422         }
423
424         /**
425          * @param string $file
426          * @return int
427          */
428         public function size($file) {
429                 return $this->ftp->filesize($file);
430         }
431
432         /**
433          * @access public
434          *
435          * @param string $file
436          * @param int $time
437          * @param int $atime
438          * @return bool
439          */
440         public function touch($file, $time = 0, $atime = 0 ) {
441                 return false;
442         }
443
444         /**
445          * @access public
446          *
447          * @param string $path
448          * @param mixed  $chmod
449          * @param mixed  $chown
450          * @param mixed  $chgrp
451          * @return bool
452          */
453         public function mkdir($path, $chmod = false, $chown = false, $chgrp = false ) {
454                 $path = untrailingslashit($path);
455                 if ( empty($path) )
456                         return false;
457
458                 if ( ! $this->ftp->mkdir($path) )
459                         return false;
460                 if ( ! $chmod )
461                         $chmod = FS_CHMOD_DIR;
462                 $this->chmod($path, $chmod);
463                 return true;
464         }
465
466         /**
467          * @access public
468          *
469          * @param string $path
470          * @param bool $recursive
471          */
472         public function rmdir($path, $recursive = false ) {
473                 $this->delete($path, $recursive);
474         }
475
476         /**
477          * @access public
478          *
479          * @param string $path
480          * @param bool   $include_hidden
481          * @param bool   $recursive
482          * @return bool|array
483          */
484         public function dirlist($path = '.', $include_hidden = true, $recursive = false ) {
485                 if ( $this->is_file($path) ) {
486                         $limit_file = basename($path);
487                         $path = dirname($path) . '/';
488                 } else {
489                         $limit_file = false;
490                 }
491
492                 mbstring_binary_safe_encoding();
493
494                 $list = $this->ftp->dirlist($path);
495                 if ( empty( $list ) && ! $this->exists( $path ) ) {
496
497                         reset_mbstring_encoding();
498
499                         return false;
500                 }
501
502                 $ret = array();
503                 foreach ( $list as $struc ) {
504
505                         if ( '.' == $struc['name'] || '..' == $struc['name'] )
506                                 continue;
507
508                         if ( ! $include_hidden && '.' == $struc['name'][0] )
509                                 continue;
510
511                         if ( $limit_file && $struc['name'] != $limit_file )
512                                 continue;
513
514                         if ( 'd' == $struc['type'] ) {
515                                 if ( $recursive )
516                                         $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
517                                 else
518                                         $struc['files'] = array();
519                         }
520
521                         // Replace symlinks formatted as "source -> target" with just the source name
522                         if ( $struc['islink'] )
523                                 $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
524
525                         // Add the Octal representation of the file permissions
526                         $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] );
527
528                         $ret[ $struc['name'] ] = $struc;
529                 }
530
531                 reset_mbstring_encoding();
532
533                 return $ret;
534         }
535
536         /**
537          * @access public
538          */
539         public function __destruct() {
540                 $this->ftp->quit();
541         }
542 }