Diff: STRATO-apps/wordpress_03/app/wp-admin/includes/class-wp-filesystem-ftpsockets.php

Keine Baseline-Datei – Diff nur gegen leer.
Zur Liste
1 -
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 + *
14 + * @see WP_Filesystem_Base
15 + */
16 + class WP_Filesystem_ftpsockets extends WP_Filesystem_Base {
17 +
18 + /**
19 + * @since 2.5.0
20 + * @var ftp
21 + */
22 + public $ftp;
23 +
24 + /**
25 + * Constructor.
26 + *
27 + * @since 2.5.0
28 + *
29 + * @param array $opt
30 + */
31 + public function __construct( $opt = '' ) {
32 + $this->method = 'ftpsockets';
33 + $this->errors = new WP_Error();
34 +
35 + // Check if possible to use ftp functions.
36 + if ( ! require_once ABSPATH . 'wp-admin/includes/class-ftp.php' ) {
37 + return;
38 + }
39 +
40 + $this->ftp = new ftp();
41 +
42 + if ( empty( $opt['port'] ) ) {
43 + $this->options['port'] = 21;
44 + } else {
45 + $this->options['port'] = (int) $opt['port'];
46 + }
47 +
48 + if ( empty( $opt['hostname'] ) ) {
49 + $this->errors->add( 'empty_hostname', __( 'FTP hostname is required' ) );
50 + } else {
51 + $this->options['hostname'] = $opt['hostname'];
52 + }
53 +
54 + // Check if the options provided are OK.
55 + if ( empty( $opt['username'] ) ) {
56 + $this->errors->add( 'empty_username', __( 'FTP username is required' ) );
57 + } else {
58 + $this->options['username'] = $opt['username'];
59 + }
60 +
61 + if ( empty( $opt['password'] ) ) {
62 + $this->errors->add( 'empty_password', __( 'FTP password is required' ) );
63 + } else {
64 + $this->options['password'] = $opt['password'];
65 + }
66 + }
67 +
68 + /**
69 + * Connects filesystem.
70 + *
71 + * @since 2.5.0
72 + *
73 + * @return bool True on success, false on failure.
74 + */
75 + public function connect() {
76 + if ( ! $this->ftp ) {
77 + return false;
78 + }
79 +
80 + $this->ftp->SetTimeout( FS_CONNECT_TIMEOUT );
81 +
82 + if ( ! $this->ftp->SetServer( $this->options['hostname'], $this->options['port'] ) ) {
83 + $this->errors->add(
84 + 'connect',
85 + sprintf(
86 + /* translators: %s: hostname:port */
87 + __( 'Failed to connect to FTP Server %s' ),
88 + $this->options['hostname'] . ':' . $this->options['port']
89 + )
90 + );
91 +
92 + return false;
93 + }
94 +
95 + if ( ! $this->ftp->connect() ) {
96 + $this->errors->add(
97 + 'connect',
98 + sprintf(
99 + /* translators: %s: hostname:port */
100 + __( 'Failed to connect to FTP Server %s' ),
101 + $this->options['hostname'] . ':' . $this->options['port']
102 + )
103 + );
104 +
105 + return false;
106 + }
107 +
108 + if ( ! $this->ftp->login( $this->options['username'], $this->options['password'] ) ) {
109 + $this->errors->add(
110 + 'auth',
111 + sprintf(
112 + /* translators: %s: Username. */
113 + __( 'Username/Password incorrect for %s' ),
114 + $this->options['username']
115 + )
116 + );
117 +
118 + return false;
119 + }
120 +
121 + $this->ftp->SetType( FTP_BINARY );
122 + $this->ftp->Passive( true );
123 + $this->ftp->SetTimeout( FS_TIMEOUT );
124 +
125 + return true;
126 + }
127 +
128 + /**
129 + * Reads entire file into a string.
130 + *
131 + * @since 2.5.0
132 + *
133 + * @param string $file Name of the file to read.
134 + * @return string|false Read data on success, false if no temporary file could be opened,
135 + * or if the file couldn't be retrieved.
136 + */
137 + public function get_contents( $file ) {
138 + if ( ! $this->exists( $file ) ) {
139 + return false;
140 + }
141 +
142 + $tempfile = wp_tempnam( $file );
143 + $temphandle = fopen( $tempfile, 'w+' );
144 +
145 + if ( ! $temphandle ) {
146 + unlink( $tempfile );
147 + return false;
148 + }
149 +
150 + mbstring_binary_safe_encoding();
151 +
152 + if ( ! $this->ftp->fget( $temphandle, $file ) ) {
153 + fclose( $temphandle );
154 + unlink( $tempfile );
155 +
156 + reset_mbstring_encoding();
157 +
158 + return ''; // Blank document. File does exist, it's just blank.
159 + }
160 +
161 + reset_mbstring_encoding();
162 +
163 + fseek( $temphandle, 0 ); // Skip back to the start of the file being written to.
164 + $contents = '';
165 +
166 + while ( ! feof( $temphandle ) ) {
167 + $contents .= fread( $temphandle, 8 * KB_IN_BYTES );
168 + }
169 +
170 + fclose( $temphandle );
171 + unlink( $tempfile );
172 +
173 + return $contents;
174 + }
175 +
176 + /**
177 + * Reads entire file into an array.
178 + *
179 + * @since 2.5.0
180 + *
181 + * @param string $file Path to the file.
182 + * @return array|false File contents in an array on success, false on failure.
183 + */
184 + public function get_contents_array( $file ) {
185 + return explode( "\n", $this->get_contents( $file ) );
186 + }
187 +
188 + /**
189 + * Writes a string to a file.
190 + *
191 + * @since 2.5.0
192 + *
193 + * @param string $file Remote path to the file where to write the data.
194 + * @param string $contents The data to write.
195 + * @param int|false $mode Optional. The file permissions as octal number, usually 0644.
196 + * Default false.
197 + * @return bool True on success, false on failure.
198 + */
199 + public function put_contents( $file, $contents, $mode = false ) {
200 + $tempfile = wp_tempnam( $file );
201 + $temphandle = @fopen( $tempfile, 'w+' );
202 +
203 + if ( ! $temphandle ) {
204 + unlink( $tempfile );
205 + return false;
206 + }
207 +
208 + // The FTP class uses string functions internally during file download/upload.
209 + mbstring_binary_safe_encoding();
210 +
211 + $bytes_written = fwrite( $temphandle, $contents );
212 +
213 + if ( false === $bytes_written || strlen( $contents ) !== $bytes_written ) {
214 + fclose( $temphandle );
215 + unlink( $tempfile );
216 +
217 + reset_mbstring_encoding();
218 +
219 + return false;
220 + }
221 +
222 + fseek( $temphandle, 0 ); // Skip back to the start of the file being written to.
223 +
224 + $ret = $this->ftp->fput( $file, $temphandle );
225 +
226 + reset_mbstring_encoding();
227 +
228 + fclose( $temphandle );
229 + unlink( $tempfile );
230 +
231 + $this->chmod( $file, $mode );
232 +
233 + return $ret;
234 + }
235 +
236 + /**
237 + * Gets the current working directory.
238 + *
239 + * @since 2.5.0
240 + *
241 + * @return string|false The current working directory on success, false on failure.
242 + */
243 + public function cwd() {
244 + $cwd = $this->ftp->pwd();
245 +
246 + if ( $cwd ) {
247 + $cwd = trailingslashit( $cwd );
248 + }
249 +
250 + return $cwd;
251 + }
252 +
253 + /**
254 + * Changes current directory.
255 + *
256 + * @since 2.5.0
257 + *
258 + * @param string $dir The new current directory.
259 + * @return bool True on success, false on failure.
260 + */
261 + public function chdir( $dir ) {
262 + return $this->ftp->chdir( $dir );
263 + }
264 +
265 + /**
266 + * Changes filesystem permissions.
267 + *
268 + * @since 2.5.0
269 + *
270 + * @param string $file Path to the file.
271 + * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files,
272 + * 0755 for directories. Default false.
273 + * @param bool $recursive Optional. If set to true, changes file permissions recursively.
274 + * Default false.
275 + * @return bool True on success, false on failure.
276 + */
277 + public function chmod( $file, $mode = false, $recursive = false ) {
278 + if ( ! $mode ) {
279 + if ( $this->is_file( $file ) ) {
280 + $mode = FS_CHMOD_FILE;
281 + } elseif ( $this->is_dir( $file ) ) {
282 + $mode = FS_CHMOD_DIR;
283 + } else {
284 + return false;
285 + }
286 + }
287 +
288 + // chmod any sub-objects if recursive.
289 + if ( $recursive && $this->is_dir( $file ) ) {
290 + $filelist = $this->dirlist( $file );
291 +
292 + foreach ( (array) $filelist as $filename => $filemeta ) {
293 + $this->chmod( $file . '/' . $filename, $mode, $recursive );
294 + }
295 + }
296 +
297 + // chmod the file or directory.
298 + return $this->ftp->chmod( $file, $mode );
299 + }
300 +
301 + /**
302 + * Gets the file owner.
303 + *
304 + * @since 2.5.0
305 + *
306 + * @param string $file Path to the file.
307 + * @return string|false Username of the owner on success, false on failure.
308 + */
309 + public function owner( $file ) {
310 + $dir = $this->dirlist( $file );
311 +
312 + return $dir[ $file ]['owner'];
313 + }
314 +
315 + /**
316 + * Gets the permissions of the specified file or filepath in their octal format.
317 + *
318 + * @since 2.5.0
319 + *
320 + * @param string $file Path to the file.
321 + * @return string Mode of the file (the last 3 digits).
322 + */
323 + public function getchmod( $file ) {
324 + $dir = $this->dirlist( $file );
325 +
326 + return $dir[ $file ]['permsn'];
327 + }
328 +
329 + /**
330 + * Gets the file's group.
331 + *
332 + * @since 2.5.0
333 + *
334 + * @param string $file Path to the file.
335 + * @return string|false The group on success, false on failure.
336 + */
337 + public function group( $file ) {
338 + $dir = $this->dirlist( $file );
339 +
340 + return $dir[ $file ]['group'];
341 + }
342 +
343 + /**
344 + * Copies a file.
345 + *
346 + * @since 2.5.0
347 + *
348 + * @param string $source Path to the source file.
349 + * @param string $destination Path to the destination file.
350 + * @param bool $overwrite Optional. Whether to overwrite the destination file if it exists.
351 + * Default false.
352 + * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files,
353 + * 0755 for dirs. Default false.
354 + * @return bool True on success, false on failure.
355 + */
356 + public function copy( $source, $destination, $overwrite = false, $mode = false ) {
357 + if ( ! $overwrite && $this->exists( $destination ) ) {
358 + return false;
359 + }
360 +
361 + $content = $this->get_contents( $source );
362 +
363 + if ( false === $content ) {
364 + return false;
365 + }
366 +
367 + return $this->put_contents( $destination, $content, $mode );
368 + }
369 +
370 + /**
371 + * Moves a file or directory.
372 + *
373 + * After moving files or directories, OPcache will need to be invalidated.
374 + *
375 + * If moving a directory fails, `copy_dir()` can be used for a recursive copy.
376 + *
377 + * Use `move_dir()` for moving directories with OPcache invalidation and a
378 + * fallback to `copy_dir()`.
379 + *
380 + * @since 2.5.0
381 + *
382 + * @param string $source Path to the source file or directory.
383 + * @param string $destination Path to the destination file or directory.
384 + * @param bool $overwrite Optional. Whether to overwrite the destination if it exists.
385 + * Default false.
386 + * @return bool True on success, false on failure.
387 + */
388 + public function move( $source, $destination, $overwrite = false ) {
389 + return $this->ftp->rename( $source, $destination );
390 + }
391 +
392 + /**
393 + * Deletes a file or directory.
394 + *
395 + * @since 2.5.0
396 + *
397 + * @param string $file Path to the file or directory.
398 + * @param bool $recursive Optional. If set to true, deletes files and folders recursively.
399 + * Default false.
400 + * @param string|false $type Type of resource. 'f' for file, 'd' for directory.
401 + * Default false.
402 + * @return bool True on success, false on failure.
403 + */
404 + public function delete( $file, $recursive = false, $type = false ) {
405 + if ( empty( $file ) ) {
406 + return false;
407 + }
408 +
409 + if ( 'f' === $type || $this->is_file( $file ) ) {
410 + return $this->ftp->delete( $file );
411 + }
412 +
413 + if ( ! $recursive ) {
414 + return $this->ftp->rmdir( $file );
415 + }
416 +
417 + return $this->ftp->mdel( $file );
418 + }
419 +
420 + /**
421 + * Checks if a file or directory exists.
422 + *
423 + * @since 2.5.0
424 + * @since 6.3.0 Returns false for an empty path.
425 + *
426 + * @param string $path Path to file or directory.
427 + * @return bool Whether $path exists or not.
428 + */
429 + public function exists( $path ) {
430 + /*
431 + * Check for empty path. If ftp::nlist() receives an empty path,
432 + * it checks the current working directory and may return true.
433 + *
434 + * See https://core.trac.wordpress.org/ticket/33058.
435 + */
436 + if ( '' === $path ) {
437 + return false;
438 + }
439 +
440 + $list = $this->ftp->nlist( $path );
441 +
442 + if ( empty( $list ) && $this->is_dir( $path ) ) {
443 + return true; // File is an empty directory.
444 + }
445 +
446 + return ! empty( $list ); // Empty list = no file, so invert.
447 + // Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server.
448 + }
449 +
450 + /**
451 + * Checks if resource is a file.
452 + *
453 + * @since 2.5.0
454 + *
455 + * @param string $file File path.
456 + * @return bool Whether $file is a file.
457 + */
458 + public function is_file( $file ) {
459 + if ( $this->is_dir( $file ) ) {
460 + return false;
461 + }
462 +
463 + if ( $this->exists( $file ) ) {
464 + return true;
465 + }
466 +
467 + return false;
468 + }
469 +
470 + /**
471 + * Checks if resource is a directory.
472 + *
473 + * @since 2.5.0
474 + *
475 + * @param string $path Directory path.
476 + * @return bool Whether $path is a directory.
477 + */
478 + public function is_dir( $path ) {
479 + $cwd = $this->cwd();
480 +
481 + if ( $this->chdir( $path ) ) {
482 + $this->chdir( $cwd );
483 + return true;
484 + }
485 +
486 + return false;
487 + }
488 +
489 + /**
490 + * Checks if a file is readable.
491 + *
492 + * @since 2.5.0
493 + *
494 + * @param string $file Path to file.
495 + * @return bool Whether $file is readable.
496 + */
497 + public function is_readable( $file ) {
498 + return true;
499 + }
500 +
501 + /**
502 + * Checks if a file or directory is writable.
503 + *
504 + * @since 2.5.0
505 + *
506 + * @param string $path Path to file or directory.
507 + * @return bool Whether $path is writable.
508 + */
509 + public function is_writable( $path ) {
510 + return true;
511 + }
512 +
513 + /**
514 + * Gets the file's last access time.
515 + *
516 + * @since 2.5.0
517 + *
518 + * @param string $file Path to file.
519 + * @return int|false Unix timestamp representing last access time, false on failure.
520 + */
521 + public function atime( $file ) {
522 + return false;
523 + }
524 +
525 + /**
526 + * Gets the file modification time.
527 + *
528 + * @since 2.5.0
529 + *
530 + * @param string $file Path to file.
531 + * @return int|false Unix timestamp representing modification time, false on failure.
532 + */
533 + public function mtime( $file ) {
534 + return $this->ftp->mdtm( $file );
535 + }
536 +
537 + /**
538 + * Gets the file size (in bytes).
539 + *
540 + * @since 2.5.0
541 + *
542 + * @param string $file Path to file.
543 + * @return int|false Size of the file in bytes on success, false on failure.
544 + */
545 + public function size( $file ) {
546 + return $this->ftp->filesize( $file );
547 + }
548 +
549 + /**
550 + * Sets the access and modification times of a file.
551 + *
552 + * Note: If $file doesn't exist, it will be created.
553 + *
554 + * @since 2.5.0
555 + *
556 + * @param string $file Path to file.
557 + * @param int $time Optional. Modified time to set for file.
558 + * Default 0.
559 + * @param int $atime Optional. Access time to set for file.
560 + * Default 0.
561 + * @return bool True on success, false on failure.
562 + */
563 + public function touch( $file, $time = 0, $atime = 0 ) {
564 + return false;
565 + }
566 +
567 + /**
568 + * Creates a directory.
569 + *
570 + * @since 2.5.0
571 + *
572 + * @param string $path Path for new directory.
573 + * @param int|false $chmod Optional. The permissions as octal number (or false to skip chmod).
574 + * Default false.
575 + * @param string|int|false $chown Optional. A user name or number (or false to skip chown).
576 + * Default false.
577 + * @param string|int|false $chgrp Optional. A group name or number (or false to skip chgrp).
578 + * Default false.
579 + * @return bool True on success, false on failure.
580 + */
581 + public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
582 + $path = untrailingslashit( $path );
583 +
584 + if ( empty( $path ) ) {
585 + return false;
586 + }
587 +
588 + if ( ! $this->ftp->mkdir( $path ) ) {
589 + return false;
590 + }
591 +
592 + if ( ! $chmod ) {
593 + $chmod = FS_CHMOD_DIR;
594 + }
595 +
596 + $this->chmod( $path, $chmod );
597 +
598 + return true;
599 + }
600 +
601 + /**
602 + * Deletes a directory.
603 + *
604 + * @since 2.5.0
605 + *
606 + * @param string $path Path to directory.
607 + * @param bool $recursive Optional. Whether to recursively remove files/directories.
608 + * Default false.
609 + * @return bool True on success, false on failure.
610 + */
611 + public function rmdir( $path, $recursive = false ) {
612 + return $this->delete( $path, $recursive );
613 + }
614 +
615 + /**
616 + * Gets details for files in a directory or a specific file.
617 + *
618 + * @since 2.5.0
619 + *
620 + * @param string $path Path to directory or file.
621 + * @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files.
622 + * Default true.
623 + * @param bool $recursive Optional. Whether to recursively include file details in nested directories.
624 + * Default false.
625 + * @return array|false {
626 + * Array of arrays containing file information. False if unable to list directory contents.
627 + *
628 + * @type array ...$0 {
629 + * Array of file information. Note that some elements may not be available on all filesystems.
630 + *
631 + * @type string $name Name of the file or directory.
632 + * @type string $perms *nix representation of permissions.
633 + * @type string $permsn Octal representation of permissions.
634 + * @type int|string|false $number File number. May be a numeric string. False if not available.
635 + * @type string|false $owner Owner name or ID, or false if not available.
636 + * @type string|false $group File permissions group, or false if not available.
637 + * @type int|string|false $size Size of file in bytes. May be a numeric string.
638 + * False if not available.
639 + * @type int|string|false $lastmodunix Last modified unix timestamp. May be a numeric string.
640 + * False if not available.
641 + * @type string|false $lastmod Last modified month (3 letters) and day (without leading 0), or
642 + * false if not available.
643 + * @type string|false $time Last modified time, or false if not available.
644 + * @type string $type Type of resource. 'f' for file, 'd' for directory, 'l' for link.
645 + * @type array|false $files If a directory and `$recursive` is true, contains another array of
646 + * files. False if unable to list directory contents.
647 + * }
648 + * }
649 + */
650 + public function dirlist( $path = '.', $include_hidden = true, $recursive = false ) {
651 + if ( $this->is_file( $path ) ) {
652 + $limit_file = basename( $path );
653 + $path = dirname( $path ) . '/';
654 + } else {
655 + $limit_file = false;
656 + }
657 +
658 + mbstring_binary_safe_encoding();
659 +
660 + $list = $this->ftp->dirlist( $path );
661 +
662 + if ( empty( $list ) && ! $this->exists( $path ) ) {
663 +
664 + reset_mbstring_encoding();
665 +
666 + return false;
667 + }
668 +
669 + $path = trailingslashit( $path );
670 + $ret = array();
671 +
672 + foreach ( $list as $struc ) {
673 +
674 + if ( '.' === $struc['name'] || '..' === $struc['name'] ) {
675 + continue;
676 + }
677 +
678 + if ( ! $include_hidden && '.' === $struc['name'][0] ) {
679 + continue;
680 + }
681 +
682 + if ( $limit_file && $struc['name'] !== $limit_file ) {
683 + continue;
684 + }
685 +
686 + if ( 'd' === $struc['type'] ) {
687 + if ( $recursive ) {
688 + $struc['files'] = $this->dirlist( $path . $struc['name'], $include_hidden, $recursive );
689 + } else {
690 + $struc['files'] = array();
691 + }
692 + }
693 +
694 + // Replace symlinks formatted as "source -> target" with just the source name.
695 + if ( $struc['islink'] ) {
696 + $struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
697 + }
698 +
699 + // Add the octal representation of the file permissions.
700 + $struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] );
701 +
702 + $ret[ $struc['name'] ] = $struc;
703 + }
704 +
705 + reset_mbstring_encoding();
706 +
707 + return $ret;
708 + }
709 +
710 + /**
711 + * Destructor.
712 + *
713 + * @since 2.5.0
714 + */
715 + public function __destruct() {
716 + $this->ftp->quit();
717 + }
718 + }
719 +