Wordpress 4.6
[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'] = (int) $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                         unlink( $temp );
126                         return false;
127                 }
128
129                 mbstring_binary_safe_encoding();
130
131                 if ( ! $this->ftp->fget($temphandle, $file) ) {
132                         fclose($temphandle);
133                         unlink($temp);
134
135                         reset_mbstring_encoding();
136
137                         return ''; // Blank document, File does exist, It's just blank.
138                 }
139
140                 reset_mbstring_encoding();
141
142                 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
143                 $contents = '';
144
145                 while ( ! feof($temphandle) )
146                         $contents .= fread($temphandle, 8192);
147
148                 fclose($temphandle);
149                 unlink($temp);
150                 return $contents;
151         }
152
153         /**
154          * @access public
155          *
156          * @param string $file
157          * @return array
158          */
159         public function get_contents_array($file) {
160                 return explode("\n", $this->get_contents($file) );
161         }
162
163         /**
164          * @access public
165          *
166          * @param string $file
167          * @param string $contents
168          * @param int|bool $mode
169          * @return bool
170          */
171         public function put_contents($file, $contents, $mode = false ) {
172                 $temp = wp_tempnam( $file );
173                 if ( ! $temphandle = @fopen($temp, 'w+') ) {
174                         unlink($temp);
175                         return false;
176                 }
177
178                 // The FTP class uses string functions internally during file download/upload
179                 mbstring_binary_safe_encoding();
180
181                 $bytes_written = fwrite( $temphandle, $contents );
182                 if ( false === $bytes_written || $bytes_written != strlen( $contents ) ) {
183                         fclose( $temphandle );
184                         unlink( $temp );
185
186                         reset_mbstring_encoding();
187
188                         return false;
189                 }
190
191                 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
192
193                 $ret = $this->ftp->fput($file, $temphandle);
194
195                 reset_mbstring_encoding();
196
197                 fclose($temphandle);
198                 unlink($temp);
199
200                 $this->chmod($file, $mode);
201
202                 return $ret;
203         }
204
205         /**
206          * @access public
207          *
208          * @return string
209          */
210         public function cwd() {
211                 $cwd = $this->ftp->pwd();
212                 if ( $cwd )
213                         $cwd = trailingslashit($cwd);
214                 return $cwd;
215         }
216
217         /**
218          * @access public
219          *
220          * @param string $file
221          * @return bool
222          */
223         public function chdir($file) {
224                 return $this->ftp->chdir($file);
225         }
226
227         /**
228          * @access public
229          *
230          * @param string $file
231          * @param int|bool $mode
232          * @param bool $recursive
233          * @return bool
234          */
235         public function chmod($file, $mode = false, $recursive = false ) {
236                 if ( ! $mode ) {
237                         if ( $this->is_file($file) )
238                                 $mode = FS_CHMOD_FILE;
239                         elseif ( $this->is_dir($file) )
240                                 $mode = FS_CHMOD_DIR;
241                         else
242                                 return false;
243                 }
244
245                 // chmod any sub-objects if recursive.
246                 if ( $recursive && $this->is_dir($file) ) {
247                         $filelist = $this->dirlist($file);
248                         foreach ( (array)$filelist as $filename => $filemeta )
249                                 $this->chmod($file . '/' . $filename, $mode, $recursive);
250                 }
251
252                 // chmod the file or directory
253                 return $this->ftp->chmod($file, $mode);
254         }
255
256         /**
257          * @access public
258          *
259          * @param string $file
260          * @return string
261          */
262         public function owner($file) {
263                 $dir = $this->dirlist($file);
264                 return $dir[$file]['owner'];
265         }
266
267         /**
268          * @access public
269          *
270          * @param string $file
271          * @return string
272          */
273         public function getchmod($file) {
274                 $dir = $this->dirlist($file);
275                 return $dir[$file]['permsn'];
276         }
277
278         /**
279          * @access public
280          *
281          * @param string $file
282          * @return string
283          */
284         public function group($file) {
285                 $dir = $this->dirlist($file);
286                 return $dir[$file]['group'];
287         }
288
289         /**
290          * @access public
291          *
292          * @param string   $source
293          * @param string   $destination
294          * @param bool     $overwrite
295          * @param int|bool $mode
296          * @return bool
297          */
298         public function copy($source, $destination, $overwrite = false, $mode = false) {
299                 if ( ! $overwrite && $this->exists($destination) )
300                         return false;
301
302                 $content = $this->get_contents($source);
303                 if ( false === $content )
304                         return false;
305
306                 return $this->put_contents($destination, $content, $mode);
307         }
308
309         /**
310          * @access public
311          *
312          * @param string $source
313          * @param string $destination
314          * @param bool   $overwrite
315          * @return bool
316          */
317         public function move($source, $destination, $overwrite = false ) {
318                 return $this->ftp->rename($source, $destination);
319         }
320
321         /**
322          * @access public
323          *
324          * @param string $file
325          * @param bool   $recursive
326          * @param string $type
327          * @return bool
328          */
329         public function delete($file, $recursive = false, $type = false) {
330                 if ( empty($file) )
331                         return false;
332                 if ( 'f' == $type || $this->is_file($file) )
333                         return $this->ftp->delete($file);
334                 if ( !$recursive )
335                         return $this->ftp->rmdir($file);
336
337                 return $this->ftp->mdel($file);
338         }
339
340         /**
341          * @access public
342          *
343          * @param string $file
344          * @return bool
345          */
346         public function exists( $file ) {
347                 $list = $this->ftp->nlist( $file );
348
349                 if ( empty( $list ) && $this->is_dir( $file ) ) {
350                         return true; // File is an empty directory.
351                 }
352
353                 return !empty( $list ); //empty list = no file, so invert.
354                 // Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server.
355         }
356
357         /**
358          * @access public
359          *
360          * @param string $file
361          * @return bool
362          */
363         public function is_file($file) {
364                 if ( $this->is_dir($file) )
365                         return false;
366                 if ( $this->exists($file) )
367                         return true;
368                 return false;
369         }
370
371         /**
372          * @access public
373          *
374          * @param string $path
375          * @return bool
376          */
377         public function is_dir($path) {
378                 $cwd = $this->cwd();
379                 if ( $this->chdir($path) ) {
380                         $this->chdir($cwd);
381                         return true;
382                 }
383                 return false;
384         }
385
386         /**
387          * @access public
388          *
389          * @param string $file
390          * @return bool
391          */
392         public function is_readable($file) {
393                 return true;
394         }
395
396         /**
397          * @access public
398          *
399          * @param string $file
400          * @return bool
401          */
402         public function is_writable($file) {
403                 return true;
404         }
405
406         /**
407          * @access public
408          *
409          * @param string $file
410          * @return bool
411          */
412         public function atime($file) {
413                 return false;
414         }
415
416         /**
417          * @access public
418          *
419          * @param string $file
420          * @return int
421          */
422         public function mtime($file) {
423                 return $this->ftp->mdtm($file);
424         }
425
426         /**
427          * @param string $file
428          * @return int
429          */
430         public function size($file) {
431                 return $this->ftp->filesize($file);
432         }
433
434         /**
435          * @access public
436          *
437          * @param string $file
438          * @param int $time
439          * @param int $atime
440          * @return bool
441          */
442         public function touch($file, $time = 0, $atime = 0 ) {
443                 return false;
444         }
445
446         /**
447          * @access public
448          *
449          * @param string $path
450          * @param mixed  $chmod
451          * @param mixed  $chown
452          * @param mixed  $chgrp
453          * @return bool
454          */
455         public function mkdir($path, $chmod = false, $chown = false, $chgrp = false ) {
456                 $path = untrailingslashit($path);
457                 if ( empty($path) )
458                         return false;
459
460                 if ( ! $this->ftp->mkdir($path) )
461                         return false;
462                 if ( ! $chmod )
463                         $chmod = FS_CHMOD_DIR;
464                 $this->chmod($path, $chmod);
465                 return true;
466         }
467
468         /**
469          * @access public
470          *
471          * @param string $path
472          * @param bool $recursive
473          */
474         public function rmdir($path, $recursive = false ) {
475                 $this->delete($path, $recursive);
476         }
477
478         /**
479          * @access public
480          *
481          * @param string $path
482          * @param bool   $include_hidden
483          * @param bool   $recursive
484          * @return bool|array
485          */
486         public function dirlist($path = '.', $include_hidden = true, $recursive = false ) {
487                 if ( $this->is_file($path) ) {
488                         $limit_file = basename($path);
489                         $path = dirname($path) . '/';
490                 } else {
491                         $limit_file = false;
492                 }
493
494                 mbstring_binary_safe_encoding();
495
496                 $list = $this->ftp->dirlist($path);
497                 if ( empty( $list ) && ! $this->exists( $path ) ) {
498
499                         reset_mbstring_encoding();
500
501                         return false;
502                 }
503
504                 $ret = array();
505                 foreach ( $list as $struc ) {
506
507                         if ( '.' == $struc['name'] || '..' == $struc['name'] )
508                                 continue;
509
510                         if ( ! $include_hidden && '.' == $struc['name'][0] )
511                                 continue;
512
513                         if ( $limit_file && $struc['name'] != $limit_file )
514                                 continue;
515
516                         if ( 'd' == $struc['type'] ) {
517                                 if ( $recursive )
518                                         $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
519                                 else
520                                         $struc['files'] = array();
521                         }
522
523                         // Replace symlinks formatted as "source -> target" with just the source name
524                         if ( $struc['islink'] )
525                                 $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
526
527                         // Add the Octal representation of the file permissions
528                         $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] );
529
530                         $ret[ $struc['name'] ] = $struc;
531                 }
532
533                 reset_mbstring_encoding();
534
535                 return $ret;
536         }
537
538         /**
539          * @access public
540          */
541         public function __destruct() {
542                 $this->ftp->quit();
543         }
544 }