31 public function __construct( $opt = '' ) { |
31 public function __construct( $opt = '' ) { |
32 $this->method = 'ftpsockets'; |
32 $this->method = 'ftpsockets'; |
33 $this->errors = new WP_Error(); |
33 $this->errors = new WP_Error(); |
34 |
34 |
35 // Check if possible to use ftp functions. |
35 // Check if possible to use ftp functions. |
36 if ( ! @include_once( ABSPATH . 'wp-admin/includes/class-ftp.php' ) ) { |
36 if ( ! include_once ABSPATH . 'wp-admin/includes/class-ftp.php' ) { |
37 return; |
37 return; |
38 } |
38 } |
|
39 |
39 $this->ftp = new ftp(); |
40 $this->ftp = new ftp(); |
40 |
41 |
41 if ( empty( $opt['port'] ) ) { |
42 if ( empty( $opt['port'] ) ) { |
42 $this->options['port'] = 21; |
43 $this->options['port'] = 21; |
43 } else { |
44 } else { |
79 $this->ftp->setTimeout( FS_CONNECT_TIMEOUT ); |
80 $this->ftp->setTimeout( FS_CONNECT_TIMEOUT ); |
80 |
81 |
81 if ( ! $this->ftp->SetServer( $this->options['hostname'], $this->options['port'] ) ) { |
82 if ( ! $this->ftp->SetServer( $this->options['hostname'], $this->options['port'] ) ) { |
82 $this->errors->add( |
83 $this->errors->add( |
83 'connect', |
84 'connect', |
84 /* translators: %s: hostname:port */ |
|
85 sprintf( |
85 sprintf( |
|
86 /* translators: %s: hostname:port */ |
86 __( 'Failed to connect to FTP Server %s' ), |
87 __( 'Failed to connect to FTP Server %s' ), |
87 $this->options['hostname'] . ':' . $this->options['port'] |
88 $this->options['hostname'] . ':' . $this->options['port'] |
88 ) |
89 ) |
89 ); |
90 ); |
|
91 |
90 return false; |
92 return false; |
91 } |
93 } |
92 |
94 |
93 if ( ! $this->ftp->connect() ) { |
95 if ( ! $this->ftp->connect() ) { |
94 $this->errors->add( |
96 $this->errors->add( |
95 'connect', |
97 'connect', |
96 /* translators: %s: hostname:port */ |
|
97 sprintf( |
98 sprintf( |
|
99 /* translators: %s: hostname:port */ |
98 __( 'Failed to connect to FTP Server %s' ), |
100 __( 'Failed to connect to FTP Server %s' ), |
99 $this->options['hostname'] . ':' . $this->options['port'] |
101 $this->options['hostname'] . ':' . $this->options['port'] |
100 ) |
102 ) |
101 ); |
103 ); |
|
104 |
102 return false; |
105 return false; |
103 } |
106 } |
104 |
107 |
105 if ( ! $this->ftp->login( $this->options['username'], $this->options['password'] ) ) { |
108 if ( ! $this->ftp->login( $this->options['username'], $this->options['password'] ) ) { |
106 $this->errors->add( |
109 $this->errors->add( |
107 'auth', |
110 'auth', |
108 /* translators: %s: username */ |
|
109 sprintf( |
111 sprintf( |
|
112 /* translators: %s: Username. */ |
110 __( 'Username/Password incorrect for %s' ), |
113 __( 'Username/Password incorrect for %s' ), |
111 $this->options['username'] |
114 $this->options['username'] |
112 ) |
115 ) |
113 ); |
116 ); |
|
117 |
114 return false; |
118 return false; |
115 } |
119 } |
116 |
120 |
117 $this->ftp->SetType( FTP_BINARY ); |
121 $this->ftp->SetType( FTP_BINARY ); |
118 $this->ftp->Passive( true ); |
122 $this->ftp->Passive( true ); |
119 $this->ftp->setTimeout( FS_TIMEOUT ); |
123 $this->ftp->setTimeout( FS_TIMEOUT ); |
|
124 |
120 return true; |
125 return true; |
121 } |
126 } |
122 |
127 |
123 /** |
128 /** |
124 * Reads entire file into a string. |
129 * Reads entire file into a string. |
132 public function get_contents( $file ) { |
137 public function get_contents( $file ) { |
133 if ( ! $this->exists( $file ) ) { |
138 if ( ! $this->exists( $file ) ) { |
134 return false; |
139 return false; |
135 } |
140 } |
136 |
141 |
137 $temp = wp_tempnam( $file ); |
142 $tempfile = wp_tempnam( $file ); |
138 |
143 $temphandle = fopen( $tempfile, 'w+' ); |
139 if ( ! $temphandle = fopen( $temp, 'w+' ) ) { |
144 |
140 unlink( $temp ); |
145 if ( ! $temphandle ) { |
|
146 unlink( $tempfile ); |
141 return false; |
147 return false; |
142 } |
148 } |
143 |
149 |
144 mbstring_binary_safe_encoding(); |
150 mbstring_binary_safe_encoding(); |
145 |
151 |
146 if ( ! $this->ftp->fget( $temphandle, $file ) ) { |
152 if ( ! $this->ftp->fget( $temphandle, $file ) ) { |
147 fclose( $temphandle ); |
153 fclose( $temphandle ); |
148 unlink( $temp ); |
154 unlink( $tempfile ); |
149 |
155 |
150 reset_mbstring_encoding(); |
156 reset_mbstring_encoding(); |
151 |
157 |
152 return ''; // Blank document, File does exist, It's just blank. |
158 return ''; // Blank document. File does exist, it's just blank. |
153 } |
159 } |
154 |
160 |
155 reset_mbstring_encoding(); |
161 reset_mbstring_encoding(); |
156 |
162 |
157 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to |
163 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to. |
158 $contents = ''; |
164 $contents = ''; |
159 |
165 |
160 while ( ! feof( $temphandle ) ) { |
166 while ( ! feof( $temphandle ) ) { |
161 $contents .= fread( $temphandle, 8 * KB_IN_BYTES ); |
167 $contents .= fread( $temphandle, 8 * KB_IN_BYTES ); |
162 } |
168 } |
163 |
169 |
164 fclose( $temphandle ); |
170 fclose( $temphandle ); |
165 unlink( $temp ); |
171 unlink( $tempfile ); |
|
172 |
166 return $contents; |
173 return $contents; |
167 } |
174 } |
168 |
175 |
169 /** |
176 /** |
170 * Reads entire file into an array. |
177 * Reads entire file into an array. |
188 * @param int|false $mode Optional. The file permissions as octal number, usually 0644. |
195 * @param int|false $mode Optional. The file permissions as octal number, usually 0644. |
189 * Default false. |
196 * Default false. |
190 * @return bool True on success, false on failure. |
197 * @return bool True on success, false on failure. |
191 */ |
198 */ |
192 public function put_contents( $file, $contents, $mode = false ) { |
199 public function put_contents( $file, $contents, $mode = false ) { |
193 $temp = wp_tempnam( $file ); |
200 $tempfile = wp_tempnam( $file ); |
194 if ( ! $temphandle = @fopen( $temp, 'w+' ) ) { |
201 $temphandle = @fopen( $tempfile, 'w+' ); |
195 unlink( $temp ); |
202 |
196 return false; |
203 if ( ! $temphandle ) { |
197 } |
204 unlink( $tempfile ); |
198 |
205 return false; |
199 // The FTP class uses string functions internally during file download/upload |
206 } |
|
207 |
|
208 // The FTP class uses string functions internally during file download/upload. |
200 mbstring_binary_safe_encoding(); |
209 mbstring_binary_safe_encoding(); |
201 |
210 |
202 $bytes_written = fwrite( $temphandle, $contents ); |
211 $bytes_written = fwrite( $temphandle, $contents ); |
203 if ( false === $bytes_written || $bytes_written != strlen( $contents ) ) { |
212 |
|
213 if ( false === $bytes_written || strlen( $contents ) != $bytes_written ) { |
204 fclose( $temphandle ); |
214 fclose( $temphandle ); |
205 unlink( $temp ); |
215 unlink( $tempfile ); |
206 |
216 |
207 reset_mbstring_encoding(); |
217 reset_mbstring_encoding(); |
208 |
218 |
209 return false; |
219 return false; |
210 } |
220 } |
211 |
221 |
212 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to |
222 fseek( $temphandle, 0 ); // Skip back to the start of the file being written to. |
213 |
223 |
214 $ret = $this->ftp->fput( $file, $temphandle ); |
224 $ret = $this->ftp->fput( $file, $temphandle ); |
215 |
225 |
216 reset_mbstring_encoding(); |
226 reset_mbstring_encoding(); |
217 |
227 |
218 fclose( $temphandle ); |
228 fclose( $temphandle ); |
219 unlink( $temp ); |
229 unlink( $tempfile ); |
220 |
230 |
221 $this->chmod( $file, $mode ); |
231 $this->chmod( $file, $mode ); |
222 |
232 |
223 return $ret; |
233 return $ret; |
224 } |
234 } |
230 * |
240 * |
231 * @return string|false The current working directory on success, false on failure. |
241 * @return string|false The current working directory on success, false on failure. |
232 */ |
242 */ |
233 public function cwd() { |
243 public function cwd() { |
234 $cwd = $this->ftp->pwd(); |
244 $cwd = $this->ftp->pwd(); |
|
245 |
235 if ( $cwd ) { |
246 if ( $cwd ) { |
236 $cwd = trailingslashit( $cwd ); |
247 $cwd = trailingslashit( $cwd ); |
237 } |
248 } |
|
249 |
238 return $cwd; |
250 return $cwd; |
239 } |
251 } |
240 |
252 |
241 /** |
253 /** |
242 * Changes current directory. |
254 * Changes current directory. |
256 * @since 2.5.0 |
268 * @since 2.5.0 |
257 * |
269 * |
258 * @param string $file Path to the file. |
270 * @param string $file Path to the file. |
259 * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, |
271 * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, |
260 * 0755 for directories. Default false. |
272 * 0755 for directories. Default false. |
261 * @param bool $recursive Optional. If set to true, changes file group recursively. |
273 * @param bool $recursive Optional. If set to true, changes file permissions recursively. |
262 * Default false. |
274 * Default false. |
263 * @return bool True on success, false on failure. |
275 * @return bool True on success, false on failure. |
264 */ |
276 */ |
265 public function chmod( $file, $mode = false, $recursive = false ) { |
277 public function chmod( $file, $mode = false, $recursive = false ) { |
266 if ( ! $mode ) { |
278 if ( ! $mode ) { |
274 } |
286 } |
275 |
287 |
276 // chmod any sub-objects if recursive. |
288 // chmod any sub-objects if recursive. |
277 if ( $recursive && $this->is_dir( $file ) ) { |
289 if ( $recursive && $this->is_dir( $file ) ) { |
278 $filelist = $this->dirlist( $file ); |
290 $filelist = $this->dirlist( $file ); |
|
291 |
279 foreach ( (array) $filelist as $filename => $filemeta ) { |
292 foreach ( (array) $filelist as $filename => $filemeta ) { |
280 $this->chmod( $file . '/' . $filename, $mode, $recursive ); |
293 $this->chmod( $file . '/' . $filename, $mode, $recursive ); |
281 } |
294 } |
282 } |
295 } |
283 |
296 |
284 // chmod the file or directory |
297 // chmod the file or directory. |
285 return $this->ftp->chmod( $file, $mode ); |
298 return $this->ftp->chmod( $file, $mode ); |
286 } |
299 } |
287 |
300 |
288 /** |
301 /** |
289 * Gets the file owner. |
302 * Gets the file owner. |
293 * @param string $file Path to the file. |
306 * @param string $file Path to the file. |
294 * @return string|false Username of the owner on success, false on failure. |
307 * @return string|false Username of the owner on success, false on failure. |
295 */ |
308 */ |
296 public function owner( $file ) { |
309 public function owner( $file ) { |
297 $dir = $this->dirlist( $file ); |
310 $dir = $this->dirlist( $file ); |
|
311 |
298 return $dir[ $file ]['owner']; |
312 return $dir[ $file ]['owner']; |
299 } |
313 } |
300 |
314 |
301 /** |
315 /** |
302 * Gets the permissions of the specified file or filepath in their octal format. |
316 * Gets the permissions of the specified file or filepath in their octal format. |
306 * @param string $file Path to the file. |
320 * @param string $file Path to the file. |
307 * @return string Mode of the file (the last 3 digits). |
321 * @return string Mode of the file (the last 3 digits). |
308 */ |
322 */ |
309 public function getchmod( $file ) { |
323 public function getchmod( $file ) { |
310 $dir = $this->dirlist( $file ); |
324 $dir = $this->dirlist( $file ); |
|
325 |
311 return $dir[ $file ]['permsn']; |
326 return $dir[ $file ]['permsn']; |
312 } |
327 } |
313 |
328 |
314 /** |
329 /** |
315 * Gets the file's group. |
330 * Gets the file's group. |
319 * @param string $file Path to the file. |
334 * @param string $file Path to the file. |
320 * @return string|false The group on success, false on failure. |
335 * @return string|false The group on success, false on failure. |
321 */ |
336 */ |
322 public function group( $file ) { |
337 public function group( $file ) { |
323 $dir = $this->dirlist( $file ); |
338 $dir = $this->dirlist( $file ); |
|
339 |
324 return $dir[ $file ]['group']; |
340 return $dir[ $file ]['group']; |
325 } |
341 } |
326 |
342 |
327 /** |
343 /** |
328 * Copies a file. |
344 * Copies a file. |
341 if ( ! $overwrite && $this->exists( $destination ) ) { |
357 if ( ! $overwrite && $this->exists( $destination ) ) { |
342 return false; |
358 return false; |
343 } |
359 } |
344 |
360 |
345 $content = $this->get_contents( $source ); |
361 $content = $this->get_contents( $source ); |
|
362 |
346 if ( false === $content ) { |
363 if ( false === $content ) { |
347 return false; |
364 return false; |
348 } |
365 } |
349 |
366 |
350 return $this->put_contents( $destination, $content, $mode ); |
367 return $this->put_contents( $destination, $content, $mode ); |
369 * Deletes a file or directory. |
386 * Deletes a file or directory. |
370 * |
387 * |
371 * @since 2.5.0 |
388 * @since 2.5.0 |
372 * |
389 * |
373 * @param string $file Path to the file or directory. |
390 * @param string $file Path to the file or directory. |
374 * @param bool $recursive Optional. If set to true, changes file group recursively. |
391 * @param bool $recursive Optional. If set to true, deletes files and folders recursively. |
375 * Default false. |
392 * Default false. |
376 * @param string|false $type Type of resource. 'f' for file, 'd' for directory. |
393 * @param string|false $type Type of resource. 'f' for file, 'd' for directory. |
377 * Default false. |
394 * Default false. |
378 * @return bool True on success, false on failure. |
395 * @return bool True on success, false on failure. |
379 */ |
396 */ |
380 public function delete( $file, $recursive = false, $type = false ) { |
397 public function delete( $file, $recursive = false, $type = false ) { |
381 if ( empty( $file ) ) { |
398 if ( empty( $file ) ) { |
382 return false; |
399 return false; |
383 } |
400 } |
384 if ( 'f' == $type || $this->is_file( $file ) ) { |
401 |
|
402 if ( 'f' === $type || $this->is_file( $file ) ) { |
385 return $this->ftp->delete( $file ); |
403 return $this->ftp->delete( $file ); |
386 } |
404 } |
|
405 |
387 if ( ! $recursive ) { |
406 if ( ! $recursive ) { |
388 return $this->ftp->rmdir( $file ); |
407 return $this->ftp->rmdir( $file ); |
389 } |
408 } |
390 |
409 |
391 return $this->ftp->mdel( $file ); |
410 return $this->ftp->mdel( $file ); |
404 |
423 |
405 if ( empty( $list ) && $this->is_dir( $file ) ) { |
424 if ( empty( $list ) && $this->is_dir( $file ) ) { |
406 return true; // File is an empty directory. |
425 return true; // File is an empty directory. |
407 } |
426 } |
408 |
427 |
409 return ! empty( $list ); //empty list = no file, so invert. |
428 return ! empty( $list ); // Empty list = no file, so invert. |
410 // Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server. |
429 // Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server. |
411 } |
430 } |
412 |
431 |
413 /** |
432 /** |
414 * Checks if resource is a file. |
433 * Checks if resource is a file. |
436 * @param string $path Directory path. |
457 * @param string $path Directory path. |
437 * @return bool Whether $path is a directory. |
458 * @return bool Whether $path is a directory. |
438 */ |
459 */ |
439 public function is_dir( $path ) { |
460 public function is_dir( $path ) { |
440 $cwd = $this->cwd(); |
461 $cwd = $this->cwd(); |
|
462 |
441 if ( $this->chdir( $path ) ) { |
463 if ( $this->chdir( $path ) ) { |
442 $this->chdir( $cwd ); |
464 $this->chdir( $cwd ); |
443 return true; |
465 return true; |
444 } |
466 } |
|
467 |
445 return false; |
468 return false; |
446 } |
469 } |
447 |
470 |
448 /** |
471 /** |
449 * Checks if a file is readable. |
472 * Checks if a file is readable. |
537 * Default false. |
560 * Default false. |
538 * @return bool True on success, false on failure. |
561 * @return bool True on success, false on failure. |
539 */ |
562 */ |
540 public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { |
563 public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { |
541 $path = untrailingslashit( $path ); |
564 $path = untrailingslashit( $path ); |
|
565 |
542 if ( empty( $path ) ) { |
566 if ( empty( $path ) ) { |
543 return false; |
567 return false; |
544 } |
568 } |
545 |
569 |
546 if ( ! $this->ftp->mkdir( $path ) ) { |
570 if ( ! $this->ftp->mkdir( $path ) ) { |
547 return false; |
571 return false; |
548 } |
572 } |
|
573 |
549 if ( ! $chmod ) { |
574 if ( ! $chmod ) { |
550 $chmod = FS_CHMOD_DIR; |
575 $chmod = FS_CHMOD_DIR; |
551 } |
576 } |
|
577 |
552 $this->chmod( $path, $chmod ); |
578 $this->chmod( $path, $chmod ); |
|
579 |
553 return true; |
580 return true; |
554 } |
581 } |
555 |
582 |
556 /** |
583 /** |
557 * Deletes a directory. |
584 * Deletes a directory. |
601 } |
628 } |
602 |
629 |
603 mbstring_binary_safe_encoding(); |
630 mbstring_binary_safe_encoding(); |
604 |
631 |
605 $list = $this->ftp->dirlist( $path ); |
632 $list = $this->ftp->dirlist( $path ); |
|
633 |
606 if ( empty( $list ) && ! $this->exists( $path ) ) { |
634 if ( empty( $list ) && ! $this->exists( $path ) ) { |
607 |
635 |
608 reset_mbstring_encoding(); |
636 reset_mbstring_encoding(); |
609 |
637 |
610 return false; |
638 return false; |
611 } |
639 } |
612 |
640 |
613 $ret = array(); |
641 $ret = array(); |
|
642 |
614 foreach ( $list as $struc ) { |
643 foreach ( $list as $struc ) { |
615 |
644 |
616 if ( '.' == $struc['name'] || '..' == $struc['name'] ) { |
645 if ( '.' === $struc['name'] || '..' === $struc['name'] ) { |
617 continue; |
646 continue; |
618 } |
647 } |
619 |
648 |
620 if ( ! $include_hidden && '.' == $struc['name'][0] ) { |
649 if ( ! $include_hidden && '.' === $struc['name'][0] ) { |
621 continue; |
650 continue; |
622 } |
651 } |
623 |
652 |
624 if ( $limit_file && $struc['name'] != $limit_file ) { |
653 if ( $limit_file && $struc['name'] != $limit_file ) { |
625 continue; |
654 continue; |
626 } |
655 } |
627 |
656 |
628 if ( 'd' == $struc['type'] ) { |
657 if ( 'd' === $struc['type'] ) { |
629 if ( $recursive ) { |
658 if ( $recursive ) { |
630 $struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive ); |
659 $struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive ); |
631 } else { |
660 } else { |
632 $struc['files'] = array(); |
661 $struc['files'] = array(); |
633 } |
662 } |
634 } |
663 } |
635 |
664 |
636 // Replace symlinks formatted as "source -> target" with just the source name |
665 // Replace symlinks formatted as "source -> target" with just the source name. |
637 if ( $struc['islink'] ) { |
666 if ( $struc['islink'] ) { |
638 $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] ); |
667 $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] ); |
639 } |
668 } |
640 |
669 |
641 // Add the Octal representation of the file permissions |
670 // Add the octal representation of the file permissions. |
642 $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] ); |
671 $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] ); |
643 |
672 |
644 $ret[ $struc['name'] ] = $struc; |
673 $ret[ $struc['name'] ] = $struc; |
645 } |
674 } |
646 |
675 |