diff -r 3d4e9c994f10 -r a86126ab1dd4 wp/wp-admin/includes/class-wp-filesystem-ssh2.php --- a/wp/wp-admin/includes/class-wp-filesystem-ssh2.php Tue Oct 22 16:11:46 2019 +0200 +++ b/wp/wp-admin/includes/class-wp-filesystem-ssh2.php Tue Dec 15 13:49:49 2020 +0100 @@ -6,10 +6,10 @@ * * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes * - * Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work) + * Compile libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work) * * cd /usr/src - * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz + * wget https://www.libssh2.org/download/libssh2-0.14.tar.gz * tar -zxvf libssh2-0.14.tar.gz * cd libssh2-0.14/ * ./configure @@ -26,7 +26,7 @@ * Restart Apache! * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist. * - * Note: as of WordPress 2.8, This utilises the PHP5+ function 'stream_get_contents' + * Note: As of WordPress 2.8, this utilises the PHP5+ function `stream_get_contents()`. * * @since 2.7.0 * @@ -64,22 +64,11 @@ $this->method = 'ssh2'; $this->errors = new WP_Error(); - //Check if possible to use ssh2 functions. + // Check if possible to use ssh2 functions. if ( ! extension_loaded( 'ssh2' ) ) { $this->errors->add( 'no_ssh2_ext', __( 'The ssh2 PHP extension is not available' ) ); return; } - if ( ! function_exists( 'stream_get_contents' ) ) { - $this->errors->add( - 'ssh2_php_requirement', - sprintf( - /* translators: %s: stream_get_contents() */ - __( 'The ssh2 PHP extension is available, however, we require the PHP5 function %s' ), - 'stream_get_contents()' - ) - ); - return; - } // Set defaults: if ( empty( $opt['port'] ) ) { @@ -137,12 +126,13 @@ if ( ! $this->link ) { $this->errors->add( 'connect', - /* translators: %s: hostname:port */ sprintf( + /* translators: %s: hostname:port */ __( 'Failed to connect to SSH2 Server %s' ), $this->options['hostname'] . ':' . $this->options['port'] ) ); + return false; } @@ -150,38 +140,42 @@ if ( ! @ssh2_auth_password( $this->link, $this->options['username'], $this->options['password'] ) ) { $this->errors->add( 'auth', - /* translators: %s: username */ sprintf( + /* translators: %s: Username. */ __( 'Username/Password incorrect for %s' ), $this->options['username'] ) ); + return false; } } else { if ( ! @ssh2_auth_pubkey_file( $this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) { $this->errors->add( 'auth', - /* translators: %s: username */ sprintf( + /* translators: %s: Username. */ __( 'Public and Private keys incorrect for %s' ), $this->options['username'] ) ); + return false; } } $this->sftp_link = ssh2_sftp( $this->link ); + if ( ! $this->sftp_link ) { $this->errors->add( 'connect', - /* translators: %s: hostname:port */ sprintf( + /* translators: %s: hostname:port */ __( 'Failed to initialize a SFTP subsystem session with the SSH2 Server %s' ), $this->options['hostname'] . ':' . $this->options['port'] ) ); + return false; } @@ -205,6 +199,7 @@ if ( '/' === $path ) { $path = '/./'; } + return 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $path, '/' ); } @@ -212,7 +207,7 @@ * @since 2.7.0 * * @param string $command - * @param bool $returnbool + * @param bool $returnbool * @return bool|string True on success, false on failure. String if the command was executed, `$returnbool` * is false (default), and data from the resulting stream was retrieved. */ @@ -221,11 +216,13 @@ return false; } - if ( ! ( $stream = ssh2_exec( $this->link, $command ) ) ) { + $stream = ssh2_exec( $this->link, $command ); + + if ( ! $stream ) { $this->errors->add( 'command', - /* translators: %s: command */ sprintf( + /* translators: %s: Command. */ __( 'Unable to perform command: %s' ), $command ) @@ -237,11 +234,12 @@ fclose( $stream ); if ( $returnbool ) { - return ( $data === false ) ? false : '' != trim( $data ); + return ( false === $data ) ? false : '' !== trim( $data ); } else { return $data; } } + return false; } @@ -284,7 +282,7 @@ public function put_contents( $file, $contents, $mode = false ) { $ret = file_put_contents( $this->sftp_path( $file ), $contents ); - if ( $ret !== strlen( $contents ) ) { + if ( strlen( $contents ) !== $ret ) { return false; } @@ -302,9 +300,11 @@ */ public function cwd() { $cwd = ssh2_sftp_realpath( $this->sftp_link, '.' ); + if ( $cwd ) { $cwd = trailingslashit( trim( $cwd ) ); } + return $cwd; } @@ -335,9 +335,11 @@ if ( ! $this->exists( $file ) ) { return false; } + if ( ! $recursive || ! $this->is_dir( $file ) ) { return $this->run_command( sprintf( 'chgrp %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true ); } + return $this->run_command( sprintf( 'chgrp -R %s %s', escapeshellarg( $group ), escapeshellarg( $file ) ), true ); } @@ -349,7 +351,7 @@ * @param string $file Path to the file. * @param int|false $mode Optional. The permissions as octal number, usually 0644 for files, * 0755 for directories. Default false. - * @param bool $recursive Optional. If set to true, changes file group recursively. + * @param bool $recursive Optional. If set to true, changes file permissions recursively. * Default false. * @return bool True on success, false on failure. */ @@ -371,6 +373,7 @@ if ( ! $recursive || ! $this->is_dir( $file ) ) { return $this->run_command( sprintf( 'chmod %o %s', $mode, escapeshellarg( $file ) ), true ); } + return $this->run_command( sprintf( 'chmod -R %o %s', $mode, escapeshellarg( $file ) ), true ); } @@ -389,9 +392,11 @@ if ( ! $this->exists( $file ) ) { return false; } + if ( ! $recursive || ! $this->is_dir( $file ) ) { return $this->run_command( sprintf( 'chown %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true ); } + return $this->run_command( sprintf( 'chown -R %s %s', escapeshellarg( $owner ), escapeshellarg( $file ) ), true ); } @@ -405,13 +410,21 @@ */ public function owner( $file ) { $owneruid = @fileowner( $this->sftp_path( $file ) ); + if ( ! $owneruid ) { return false; } + if ( ! function_exists( 'posix_getpwuid' ) ) { return $owneruid; } + $ownerarray = posix_getpwuid( $owneruid ); + + if ( ! $ownerarray ) { + return false; + } + return $ownerarray['name']; } @@ -437,13 +450,21 @@ */ public function group( $file ) { $gid = @filegroup( $this->sftp_path( $file ) ); + if ( ! $gid ) { return false; } + if ( ! function_exists( 'posix_getgrgid' ) ) { return $gid; } + $grouparray = posix_getgrgid( $gid ); + + if ( ! $grouparray ) { + return false; + } + return $grouparray['name']; } @@ -464,10 +485,13 @@ if ( ! $overwrite && $this->exists( $destination ) ) { return false; } + $content = $this->get_contents( $source ); + if ( false === $content ) { return false; } + return $this->put_contents( $destination, $content, $mode ); } @@ -483,7 +507,17 @@ * @return bool True on success, false on failure. */ public function move( $source, $destination, $overwrite = false ) { - return @ssh2_sftp_rename( $this->sftp_link, $source, $destination ); + if ( $this->exists( $destination ) ) { + if ( $overwrite ) { + // We need to remove the destination file before we can rename the source. + $this->delete( $destination, false, 'f' ); + } else { + // If we're not overwriting, the rename will fail, so return early. + return false; + } + } + + return ssh2_sftp_rename( $this->sftp_link, $source, $destination ); } /** @@ -492,25 +526,29 @@ * @since 2.7.0 * * @param string $file Path to the file or directory. - * @param bool $recursive Optional. If set to true, changes file group recursively. + * @param bool $recursive Optional. If set to true, deletes files and folders recursively. * Default false. * @param string|false $type Type of resource. 'f' for file, 'd' for directory. * Default false. * @return bool True on success, false on failure. */ public function delete( $file, $recursive = false, $type = false ) { - if ( 'f' == $type || $this->is_file( $file ) ) { + if ( 'f' === $type || $this->is_file( $file ) ) { return ssh2_sftp_unlink( $this->sftp_link, $file ); } + if ( ! $recursive ) { return ssh2_sftp_rmdir( $this->sftp_link, $file ); } + $filelist = $this->dirlist( $file ); + if ( is_array( $filelist ) ) { foreach ( $filelist as $filename => $fileinfo ) { $this->delete( $file . '/' . $filename, $recursive, $fileinfo['type'] ); } } + return ssh2_sftp_rmdir( $this->sftp_link, $file ); } @@ -571,7 +609,7 @@ * @return bool Whether $file is writable. */ public function is_writable( $file ) { - // PHP will base it's writable checks on system_user === file_owner, not ssh_user === file_owner + // PHP will base its writable checks on system_user === file_owner, not ssh_user === file_owner. return true; } @@ -644,6 +682,7 @@ */ public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) { $path = untrailingslashit( $path ); + if ( empty( $path ) ) { return false; } @@ -651,15 +690,22 @@ if ( ! $chmod ) { $chmod = FS_CHMOD_DIR; } + if ( ! ssh2_sftp_mkdir( $this->sftp_link, $path, $chmod, true ) ) { return false; } + + // Set directory permissions. + ssh2_sftp_chmod( $this->sftp_link, $path, $chmod ); + if ( $chown ) { $this->chown( $path, $chown ); } + if ( $chgrp ) { $this->chgrp( $path, $chgrp ); } + return true; } @@ -710,12 +756,12 @@ $limit_file = false; } - if ( ! $this->is_dir( $path ) ) { + if ( ! $this->is_dir( $path ) || ! $this->is_readable( $path ) ) { return false; } $ret = array(); - $dir = @dir( $this->sftp_path( $path ) ); + $dir = dir( $this->sftp_path( $path ) ); if ( ! $dir ) { return false; @@ -725,11 +771,11 @@ $struc = array(); $struc['name'] = $entry; - if ( '.' == $struc['name'] || '..' == $struc['name'] ) { - continue; //Do not care about these folders. + if ( '.' === $struc['name'] || '..' === $struc['name'] ) { + continue; // Do not care about these folders. } - if ( ! $include_hidden && '.' == $struc['name'][0] ) { + if ( ! $include_hidden && '.' === $struc['name'][0] ) { continue; } @@ -744,11 +790,11 @@ $struc['group'] = $this->group( $path . '/' . $entry ); $struc['size'] = $this->size( $path . '/' . $entry ); $struc['lastmodunix'] = $this->mtime( $path . '/' . $entry ); - $struc['lastmod'] = date( 'M j', $struc['lastmodunix'] ); - $struc['time'] = date( 'h:i:s', $struc['lastmodunix'] ); + $struc['lastmod'] = gmdate( 'M j', $struc['lastmodunix'] ); + $struc['time'] = gmdate( 'h:i:s', $struc['lastmodunix'] ); $struc['type'] = $this->is_dir( $path . '/' . $entry ) ? 'd' : 'f'; - if ( 'd' == $struc['type'] ) { + if ( 'd' === $struc['type'] ) { if ( $recursive ) { $struc['files'] = $this->dirlist( $path . '/' . $struc['name'], $include_hidden, $recursive ); } else { @@ -758,8 +804,10 @@ $ret[ $struc['name'] ] = $struc; } + $dir->close(); unset( $dir ); + return $ret; } }