balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-wp-filesystem-ftpsockets.php (16884B)


      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 ( ! include_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.
    372 	 *
    373 	 * @since 2.5.0
    374 	 *
    375 	 * @param string $source      Path to the source file.
    376 	 * @param string $destination Path to the destination file.
    377 	 * @param bool   $overwrite   Optional. Whether to overwrite the destination file if it exists.
    378 	 *                            Default false.
    379 	 * @return bool True on success, false on failure.
    380 	 */
    381 	public function move( $source, $destination, $overwrite = false ) {
    382 		return $this->ftp->rename( $source, $destination );
    383 	}
    384 
    385 	/**
    386 	 * Deletes a file or directory.
    387 	 *
    388 	 * @since 2.5.0
    389 	 *
    390 	 * @param string       $file      Path to the file or directory.
    391 	 * @param bool         $recursive Optional. If set to true, deletes files and folders recursively.
    392 	 *                                Default false.
    393 	 * @param string|false $type      Type of resource. 'f' for file, 'd' for directory.
    394 	 *                                Default false.
    395 	 * @return bool True on success, false on failure.
    396 	 */
    397 	public function delete( $file, $recursive = false, $type = false ) {
    398 		if ( empty( $file ) ) {
    399 			return false;
    400 		}
    401 
    402 		if ( 'f' === $type || $this->is_file( $file ) ) {
    403 			return $this->ftp->delete( $file );
    404 		}
    405 
    406 		if ( ! $recursive ) {
    407 			return $this->ftp->rmdir( $file );
    408 		}
    409 
    410 		return $this->ftp->mdel( $file );
    411 	}
    412 
    413 	/**
    414 	 * Checks if a file or directory exists.
    415 	 *
    416 	 * @since 2.5.0
    417 	 *
    418 	 * @param string $file Path to file or directory.
    419 	 * @return bool Whether $file exists or not.
    420 	 */
    421 	public function exists( $file ) {
    422 		$list = $this->ftp->nlist( $file );
    423 
    424 		if ( empty( $list ) && $this->is_dir( $file ) ) {
    425 			return true; // File is an empty directory.
    426 		}
    427 
    428 		return ! empty( $list ); // Empty list = no file, so invert.
    429 		// Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server.
    430 	}
    431 
    432 	/**
    433 	 * Checks if resource is a file.
    434 	 *
    435 	 * @since 2.5.0
    436 	 *
    437 	 * @param string $file File path.
    438 	 * @return bool Whether $file is a file.
    439 	 */
    440 	public function is_file( $file ) {
    441 		if ( $this->is_dir( $file ) ) {
    442 			return false;
    443 		}
    444 
    445 		if ( $this->exists( $file ) ) {
    446 			return true;
    447 		}
    448 
    449 		return false;
    450 	}
    451 
    452 	/**
    453 	 * Checks if resource is a directory.
    454 	 *
    455 	 * @since 2.5.0
    456 	 *
    457 	 * @param string $path Directory path.
    458 	 * @return bool Whether $path is a directory.
    459 	 */
    460 	public function is_dir( $path ) {
    461 		$cwd = $this->cwd();
    462 
    463 		if ( $this->chdir( $path ) ) {
    464 			$this->chdir( $cwd );
    465 			return true;
    466 		}
    467 
    468 		return false;
    469 	}
    470 
    471 	/**
    472 	 * Checks if a file is readable.
    473 	 *
    474 	 * @since 2.5.0
    475 	 *
    476 	 * @param string $file Path to file.
    477 	 * @return bool Whether $file is readable.
    478 	 */
    479 	public function is_readable( $file ) {
    480 		return true;
    481 	}
    482 
    483 	/**
    484 	 * Checks if a file or directory is writable.
    485 	 *
    486 	 * @since 2.5.0
    487 	 *
    488 	 * @param string $file Path to file or directory.
    489 	 * @return bool Whether $file is writable.
    490 	 */
    491 	public function is_writable( $file ) {
    492 		return true;
    493 	}
    494 
    495 	/**
    496 	 * Gets the file's last access time.
    497 	 *
    498 	 * @since 2.5.0
    499 	 *
    500 	 * @param string $file Path to file.
    501 	 * @return int|false Unix timestamp representing last access time, false on failure.
    502 	 */
    503 	public function atime( $file ) {
    504 		return false;
    505 	}
    506 
    507 	/**
    508 	 * Gets the file modification time.
    509 	 *
    510 	 * @since 2.5.0
    511 	 *
    512 	 * @param string $file Path to file.
    513 	 * @return int|false Unix timestamp representing modification time, false on failure.
    514 	 */
    515 	public function mtime( $file ) {
    516 		return $this->ftp->mdtm( $file );
    517 	}
    518 
    519 	/**
    520 	 * Gets the file size (in bytes).
    521 	 *
    522 	 * @since 2.5.0
    523 	 *
    524 	 * @param string $file Path to file.
    525 	 * @return int|false Size of the file in bytes on success, false on failure.
    526 	 */
    527 	public function size( $file ) {
    528 		return $this->ftp->filesize( $file );
    529 	}
    530 
    531 	/**
    532 	 * Sets the access and modification times of a file.
    533 	 *
    534 	 * Note: If $file doesn't exist, it will be created.
    535 	 *
    536 	 * @since 2.5.0
    537 	 *
    538 	 * @param string $file  Path to file.
    539 	 * @param int    $time  Optional. Modified time to set for file.
    540 	 *                      Default 0.
    541 	 * @param int    $atime Optional. Access time to set for file.
    542 	 *                      Default 0.
    543 	 * @return bool True on success, false on failure.
    544 	 */
    545 	public function touch( $file, $time = 0, $atime = 0 ) {
    546 		return false;
    547 	}
    548 
    549 	/**
    550 	 * Creates a directory.
    551 	 *
    552 	 * @since 2.5.0
    553 	 *
    554 	 * @param string           $path  Path for new directory.
    555 	 * @param int|false        $chmod Optional. The permissions as octal number (or false to skip chmod).
    556 	 *                                Default false.
    557 	 * @param string|int|false $chown Optional. A user name or number (or false to skip chown).
    558 	 *                                Default false.
    559 	 * @param string|int|false $chgrp Optional. A group name or number (or false to skip chgrp).
    560 	 *                                Default false.
    561 	 * @return bool True on success, false on failure.
    562 	 */
    563 	public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
    564 		$path = untrailingslashit( $path );
    565 
    566 		if ( empty( $path ) ) {
    567 			return false;
    568 		}
    569 
    570 		if ( ! $this->ftp->mkdir( $path ) ) {
    571 			return false;
    572 		}
    573 
    574 		if ( ! $chmod ) {
    575 			$chmod = FS_CHMOD_DIR;
    576 		}
    577 
    578 		$this->chmod( $path, $chmod );
    579 
    580 		return true;
    581 	}
    582 
    583 	/**
    584 	 * Deletes a directory.
    585 	 *
    586 	 * @since 2.5.0
    587 	 *
    588 	 * @param string $path      Path to directory.
    589 	 * @param bool   $recursive Optional. Whether to recursively remove files/directories.
    590 	 *                          Default false.
    591 	 * @return bool True on success, false on failure.
    592 	 */
    593 	public function rmdir( $path, $recursive = false ) {
    594 		return $this->delete( $path, $recursive );
    595 	}
    596 
    597 	/**
    598 	 * Gets details for files in a directory or a specific file.
    599 	 *
    600 	 * @since 2.5.0
    601 	 *
    602 	 * @param string $path           Path to directory or file.
    603 	 * @param bool   $include_hidden Optional. Whether to include details of hidden ("." prefixed) files.
    604 	 *                               Default true.
    605 	 * @param bool   $recursive      Optional. Whether to recursively include file details in nested directories.
    606 	 *                               Default false.
    607 	 * @return array|false {
    608 	 *     Array of files. False if unable to list directory contents.
    609 	 *
    610 	 *     @type string $name        Name of the file or directory.
    611 	 *     @type string $perms       *nix representation of permissions.
    612 	 *     @type int    $permsn      Octal representation of permissions.
    613 	 *     @type string $owner       Owner name or ID.
    614 	 *     @type int    $size        Size of file in bytes.
    615 	 *     @type int    $lastmodunix Last modified unix timestamp.
    616 	 *     @type mixed  $lastmod     Last modified month (3 letter) and day (without leading 0).
    617 	 *     @type int    $time        Last modified time.
    618 	 *     @type string $type        Type of resource. 'f' for file, 'd' for directory.
    619 	 *     @type mixed  $files       If a directory and $recursive is true, contains another array of files.
    620 	 * }
    621 	 */
    622 	public function dirlist( $path = '.', $include_hidden = true, $recursive = false ) {
    623 		if ( $this->is_file( $path ) ) {
    624 			$limit_file = basename( $path );
    625 			$path       = dirname( $path ) . '/';
    626 		} else {
    627 			$limit_file = false;
    628 		}
    629 
    630 		mbstring_binary_safe_encoding();
    631 
    632 		$list = $this->ftp->dirlist( $path );
    633 
    634 		if ( empty( $list ) && ! $this->exists( $path ) ) {
    635 
    636 			reset_mbstring_encoding();
    637 
    638 			return false;
    639 		}
    640 
    641 		$ret = array();
    642 
    643 		foreach ( $list as $struc ) {
    644 
    645 			if ( '.' === $struc['name'] || '..' === $struc['name'] ) {
    646 				continue;
    647 			}
    648 
    649 			if ( ! $include_hidden && '.' === $struc['name'][0] ) {
    650 				continue;
    651 			}
    652 
    653 			if ( $limit_file && $struc['name'] !== $limit_file ) {
    654 				continue;
    655 			}
    656 
    657 			if ( 'd' === $struc['type'] ) {
    658 				if ( $recursive ) {
    659 					$struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive );
    660 				} else {
    661 					$struc['files'] = array();
    662 				}
    663 			}
    664 
    665 			// Replace symlinks formatted as "source -> target" with just the source name.
    666 			if ( $struc['islink'] ) {
    667 				$struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
    668 			}
    669 
    670 			// Add the octal representation of the file permissions.
    671 			$struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] );
    672 
    673 			$ret[ $struc['name'] ] = $struc;
    674 		}
    675 
    676 		reset_mbstring_encoding();
    677 
    678 		return $ret;
    679 	}
    680 
    681 	/**
    682 	 * Destructor.
    683 	 *
    684 	 * @since 2.5.0
    685 	 */
    686 	public function __destruct() {
    687 		$this->ftp->quit();
    688 	}
    689 }