diff --git a/wp-admin/includes/class-wp-filesystem-ssh2.php b/wp-admin/includes/class-wp-filesystem-ssh2.php index bad0aa6f79..085664e38c 100644 --- a/wp-admin/includes/class-wp-filesystem-ssh2.php +++ b/wp-admin/includes/class-wp-filesystem-ssh2.php @@ -9,36 +9,54 @@ /** * WordPress Filesystem Class for implementing SSH2. * + * To use this class you must follow these steps for PHP 5.2.6+ + * + * @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.) + * + * cd /usr/src + * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz + * tar -zxvf libssh2-0.14.tar.gz + * cd libssh2-0.14/ + * ./configure + * make all install + * + * Note: No not leave the directory yet! + * + * Enter: pecl install -f ssh2 + * + * Copy the ssh.so file it creates to your PHP Module Directory. + * Open up your PHP.INI file and look for where extensions are placed. + * Add in your PHP.ini file: extension=ssh2.so + * + * Restart Apache! + * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist. + * + * * @since 2.7 * @package WordPress * @subpackage Filesystem * @uses WP_Filesystem_Base Extends class */ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { - - var $debugtest = true; // this is my var that will output the text when debuggin this class - - var $link; - var $timeout = 5; + + var $debugtest = false; // this is my var that will output the text when debuggin this class + + var $link = null; + var $sftp_link = null; + /* + * This is the timeout value for ssh results to comeback. + * Slower servers might need this incressed, but this number otherwise should not change. + * + * @parm $timeout int + * + */ + var $timeout = 15; var $errors = array(); var $options = array(); - var $permission = null; - - var $filetypes = array( - 'php'=>FTP_ASCII, - 'css'=>FTP_ASCII, - 'txt'=>FTP_ASCII, - 'js'=>FTP_ASCII, - 'html'=>FTP_ASCII, - 'htm'=>FTP_ASCII, - 'xml'=>FTP_ASCII, - - 'jpg'=>FTP_BINARY, - 'png'=>FTP_BINARY, - 'gif'=>FTP_BINARY, - 'bmp'=>FTP_BINARY - ); + var $permission = 0644; function WP_Filesystem_SSH2($opt='') { $this->method = 'ssh2'; @@ -71,10 +89,9 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { $this->options['username'] = $opt['username']; if ( empty ($opt['password']) ) - $this->errors->add('empty_password', __('SSH password is required')); + $this->errors->add('empty_password', __('SSH2 password is required')); else $this->options['password'] = $opt['password']; - } function connect() { @@ -91,146 +108,153 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { return false; } + $this->sftp_link = ssh2_sftp($this->link); + return true; } - + function run_command($link, $command, $returnbool = false) { - $this->debug("run_command(".$command.");"); - if(!($stream = @ssh2_exec( $link, $command ))) { - $this->errors->add('command', sprintf(__('Unable to preform command: %s'), $command)); - } else { - stream_set_blocking( $stream, true ); + //$this->debug("run_command(".$command.",".$returnbool.");"); + if(!($stream = @ssh2_exec( $link, $command . "; echo \"__COMMAND_FINISHED__\";"))) { + $this->errors->add('command', sprintf(__('Unable to perform command: %s'), $command)); + } else { + stream_set_blocking( $stream, true ); $time_start = time(); - $data = ""; + $data = null; while( true ) { - if( (time()-$time_start) > $this->timeout ){ - $this->errors->add('command', sprintf(__('Connection to the server has timeout after %s seconds.'), $this->timeout)); - break; - } - while( $buf = fread( $stream, strlen($stream) ) ){ - $data .= $buf; - } + if (strpos($data,"__COMMAND_FINISHED__") !== false){ + break; // the command has finshed! + } + if( (time()-$time_start) > $this->timeout ){ + $this->errors->add('command', sprintf(__('Connection to the server has timeout after %s seconds.'), $this->timeout)); + unset($this->link); + unset($this->sftp_link); // close connections + return false; + } + while( $buf = fread( $stream, strlen($stream) ) ) + $data .= $buf; } - fclose($stream); - if (($returnbool) && ($data)) { - $this->debug("Data: " . print_r($data, true) . " Returning: True"); - return true; - } elseif (($returnbool) && (!$data)) { - $this->debug("Data: " . print_r($data, true) . " Returning: False"); - return false; - } else { - $this->debug("Data: " . print_r($data, true)); - return $data; - } - } + fclose($stream); + $data = str_replace("__COMMAND_FINISHED__", "", $data); + //$this->debug("run_command(".$command."); --> \$data = " . $data); + if (($returnbool) && ( (int) $data )) { + $this->debug("Data. Returning: True"); + return true; + } elseif (($returnbool) && (! (int) $data )) { + $this->debug("Data. Returning: False"); + return false; + } else { + $this->debug("Data Only."); + return $data; + } + } + return false; } function debug($text) { if ($this->debugtest) { - echo $text . "
"; + echo "
" . $text . "
"; } } function setDefaultPermissions($perm) { - $this->permission = $perm; + $this->debug("setDefaultPermissions();"); + if ( $perm ) + $this->permission = $perm; } - function get_contents($file, $type = '', $resumepos = 0 ){ - if( empty($type) ){ - $extension = substr(strrchr($file, "."), 1); - $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII; - } - $temp = tmpfile(); - if ( ! $temp ) + function get_contents($file, $type = '', $resumepos = 0 ) { + $tempfile = wp_tempnam( $file ); + if ( ! $tempfile ) return false; - if( ! @ssh2_scp_recv($this->link, $temp, $file) ) + if( ! ssh2_scp_recv($this->link, $file, $tempfile) ) return false; - fseek($temp, 0); //Skip back to the start of the file being written to - $contents = ''; - while (!feof($temp)) { - $contents .= fread($temp, 8192); - } - fclose($temp); + $contents = file_get_contents($tempfile); + unlink($tempfile); return $contents; } - + function get_contents_array($file) { + $this->debug("get_contents_array();"); return explode("\n", $this->get_contents($file)); } - + function put_contents($file, $contents, $type = '' ) { - if( empty($type) ) { - $extension = substr(strrchr($file, "."), 1); - $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII; - } - $temp = tmpfile(); + $tempfile = wp_tempnam( $file ); + $temp = fopen($tempfile, 'w'); if ( ! $temp ) return false; fwrite($temp, $contents); - fseek($temp, 0); //Skip back to the start of the file being written to - $ret = @ssh2_scp_send($this->link, $file, $temp, $type); fclose($temp); + $ret = ssh2_scp_send($this->link, $tempfile, $file, $this->permission); + unlink($tempfile); return $ret; } - + function cwd() { - $cwd = $this->run_command($this->link, "pwd"); + $cwd = $this->run_command($this->link, 'pwd'); if( $cwd ) $cwd = trailingslashit($cwd); return $cwd; } - + function chdir($dir) { - if ($this->run_command($this->link, "cd " . $dir, true)) { - return true; - } - return false; + return $this->run_command($this->link, 'cd ' . $dir, true); } - + function chgrp($file, $group, $recursive = false ) { - return false; + $this->debug("chgrp();"); + if ( ! $this->exists($file) ) + return false; + if ( ! $recursive || ! $this->is_dir($file) ) + return $this->run_command($this->link, sprintf('chgrp %o %s', $mode, $file), true); + return $this->run_command($this->link, sprintf('chgrp -R %o %s', $mode, $file), true); } - + function chmod($file, $mode = false, $recursive = false) { + $this->debug("chmod();"); if( ! $mode ) $mode = $this->permission; if( ! $mode ) return false; if ( ! $this->exists($file) ) return false; - if ( ! $recursive || ! $this->is_dir($file) ) { - return $this->run_command($this->link, sprintf('CHMOD %o %s', $mode, $file), true); - } - //Is a directory, and we want recursive - $filelist = $this->dirlist($file); - foreach($filelist as $filename){ - $this->chmod($file . '/' . $filename, $mode, $recursive); - } - return true; + if ( ! $recursive || ! $this->is_dir($file) ) + return $this->run_command($this->link, sprintf('chmod %o %s', $mode, $file), true); + return $this->run_command($this->link, sprintf('chmod -R %o %s', $mode, $file), true); } - + function chown($file, $owner, $recursive = false ) { - return false; + $this->debug("chown();"); + if ( ! $this->exists($file) ) + return false; + if ( ! $recursive || ! $this->is_dir($file) ) + return $this->run_command($this->link, sprintf('chown %o %s', $mode, $file), true); + return $this->run_command($this->link, sprintf('chown -R %o %s', $mode, $file), true); } - + function owner($file) { + $this->debug("owner();"); $dir = $this->dirlist($file); return $dir[$file]['owner']; } - + function getchmod($file) { + $this->debug("getchmod();"); $dir = $this->dirlist($file); return $dir[$file]['permsn']; } - + function group($file) { + $this->debug("group();"); $dir = $this->dirlist($file); return $dir[$file]['group']; } - + function copy($source, $destination, $overwrite = false ) { + $this->debug("copy();"); if( ! $overwrite && $this->exists($destination) ) return false; $content = $this->get_contents($source); @@ -238,96 +262,90 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { return false; return $this->put_contents($destination, $content); } - + function move($source, $destination, $overwrite = false) { + $this->debug("move();"); return @ssh2_sftp_rename($this->link, $source, $destination); } - function delete($file, $recursive=false) { + function delete($file, $recursive = false) { if ( $this->is_file($file) ) - return @ssh2_sftp_unlink($this->link, $file); - if ( !$recursive ) - return @ssh2_sftp_rmdir($this->link, $file); + return ssh2_sftp_unlink($this->sftp_link, $file); + if ( ! $recursive ) + return ssh2_sftp_rmdir($this->sftp_link, $file); $filelist = $this->dirlist($file); - foreach ((array) $filelist as $filename => $fileinfo) { - $this->delete($file . '/' . $filename, $recursive); + if ( is_array($filelist) ) { + foreach ( $filelist as $filename => $fileinfo) { + $this->delete($file . '/' . $filename, $recursive); + } } - return @ssh2_sftp_rmdir($this->link, $file); + return ssh2_sftp_rmdir($this->sftp_link, $file); } function exists($file) { - $list = $this->run_command($this->link, sprintf('ls -la %s', $file)); - if( ! $list ) - return false; - return count($list) == 1 ? true : false; + $list = $this->run_command($this->link, sprintf('ls -lad %s', $file)); + return (bool) $list; } - + function is_file($file) { - return $this->is_dir($file) ? false : true; - } - - function is_dir($path) { - $cwd = $this->cwd(); - $result = $this->run_command($this->link, sprintf('cd %s', $path), true); - if( $result && $path == $this->cwd() || $this->cwd() != $cwd ) { - // @todo: use ssh2_exec - @ftp_chdir($this->link, $cwd); - return true; - } - return false; - } - - function is_readable($file) { - //Get dir list, Check if the file is writable by the current user?? - return true; - } - - function is_writable($file) { - //Get dir list, Check if the file is writable by the current user?? - return true; - } - - function atime($file) { - return false; - } - - function mtime($file) { - return; // i have to look up to see if there is a way in SSH2 to look the modifed date - // return ftp_mdtm($this->link, $file); - } - - function size($file) { - return; // i have to look up to see if there is a way in SSH2 to get the file size - // return ftp_size($this->link, $file); - } - - function touch($file, $time = 0, $atime = 0) { - return false; - } - - function mkdir($path, $chmod = false, $chown = false, $chgrp = false) { - if( !@ssh2_sftp_mkdir($this->link, $path) ) + //DO NOT RELY ON dirlist()! + $list = $this->run_command($this->link, sprintf('ls -lad %s', $file)); + $list = $this->parselisting($list); + if ( ! $list ) + return false; + else + return ( !$list['isdir'] && !$list['islink'] ); //ie. not a file or link, yet exists, must be file. + } + + function is_dir($path) { + //DO NOT RELY ON dirlist()! + $list = $this->parselisting($this->run_command($this->link, sprintf('ls -lad %s', rtrim($path, '/')))); + if ( ! $list ) + return false; + else + return $list['isdir']; + } + + function is_readable($file) { + //Not implmented. + } + + function is_writable($file) { + //Not implmented. + } + + function atime($file) { + //Not implmented. + } + + function mtime($file) { + //Not implmented. + } + + function size($file) { + //Not implmented. + } + + function touch($file, $time = 0, $atime = 0) { + //Not implmented. + } + + function mkdir($path, $chmod = null, $chown = false, $chgrp = false) { + if( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) ) return false; - if( $chmod ) - $this->chmod($path, $chmod); if( $chown ) $this->chown($path, $chown); if( $chgrp ) $this->chgrp($path, $chgrp); return true; } - + function rmdir($path, $recursive = false) { - if( ! $recursive ) - return @ssh2_sftp_rmdir($this->link, $path); - - //TODO: Recursive Directory delete, Have to delete files from the folder first. - //$dir = $this->dirlist($path); - //foreach($dir as $file) - + return $this->delete($path, $recursive); } function parselisting($line) { + $this->debug("parselisting();"); $is_windows = ($this->OS_remote == FTP_OS_Windows); if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|) +(.+)/", $line, $lucifer)) { $b = array(); @@ -390,25 +408,28 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { } function dirlist($path = '.', $incdot = false, $recursive = false) { + $this->debug("dirlist();"); if( $this->is_file($path) ) { $limitFile = basename($path); - $path = dirname($path) . '/'; + $path = trailingslashit(dirname($path)); } else { $limitFile = false; } - - $list = $this->run_command($this->link, sprintf('ls -a %s', $path)); + + $list = $this->run_command($this->link, sprintf('ls -la %s', $path)); if ( $list === false ) return false; + $list = explode("\n", $list); + $dirlist = array(); - foreach ( $list as $k => $v ) { + foreach ( (array)$list as $k => $v ) { $entry = $this->parselisting($v); if ( empty($entry) ) continue; - if ( '.' == $entry["name"] || '..' == $entry["name"] ) + if ( '.' == $entry['name'] || '..' == $entry['name'] ) continue; $dirlist[ $entry['name'] ] = $entry; @@ -416,6 +437,7 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { if ( ! $dirlist ) return false; + if ( empty($dirlist) ) return array(); @@ -432,7 +454,7 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive); } } else { //No dots - if ($recursive) + if ( $recursive ) $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive); } } @@ -443,9 +465,11 @@ class WP_Filesystem_SSH2 extends WP_Filesystem_Base { } function __destruct(){ - if( $this->link ) + if ( $this->link ) unset($this->link); + if ( $this->sftp_link ) + unset($this->sftp_link); } } -?> \ No newline at end of file +?> diff --git a/wp-admin/includes/file.php b/wp-admin/includes/file.php index c57e3d0f2c..3694f8c414 100644 --- a/wp-admin/includes/file.php +++ b/wp-admin/includes/file.php @@ -386,25 +386,32 @@ function unzip_file($file, $to) { if ( 0 == count($archive_files) ) return new WP_Error('empty_archive', __('Empty archive')); - $to = trailingslashit($to); $path = explode('/', $to); - $tmppath = ''; - for ( $j = 0; $j < count($path) - 1; $j++ ) { - $tmppath .= $path[$j] . '/'; - if ( ! $fs->is_dir($tmppath) ) - $fs->mkdir($tmppath, 0755); + for ( $i = count($path); $i > 0; $i-- ) { //>0 = first element is empty allways for paths starting with '/' + $tmppath = implode('/', array_slice($path, 0, $i) ); + if ( $fs->is_dir($tmppath) ) { //Found the highest folder that exists, Create from here(ie +1) + for ( $i = $i + 1; $i <= count($path); $i++ ) { + $tmppath = implode('/', array_slice($path, 0, $i) ); + if ( ! $fs->mkdir($tmppath, 0755) ) + return new WP_Error('mkdir_failed', __('Could not create directory'), $tmppath); + } + break; //Exit main for loop + } } + $to = trailingslashit($to); foreach ($archive_files as $file) { $path = explode('/', $file['filename']); - $tmppath = ''; - - // Loop through each of the items and check that the folder exists. - for ( $j = 0; $j < count($path) - 1; $j++ ) { - $tmppath .= $path[$j] . '/'; - if ( ! $fs->is_dir($to . $tmppath) ) - if ( !$fs->mkdir($to . $tmppath, 0755) ) - return new WP_Error('mkdir_failed', __('Could not create directory'), $to . $tmppath); + for ( $i = count($path) - 1; $i >= 0; $i-- ) { //>=0 as the first element contains data, count()-1, as we do not want the file component + $tmppath = $to . implode('/', array_slice($path, 0, $i) ); + if ( $fs->is_dir($tmppath) ) {//Found the highest folder that exists, Create from here + for ( $i = $i + 1; $i < count($path); $i++ ) { //< count() no file component please. + $tmppath = $to . implode('/', array_slice($path, 0, $i) ); + if ( ! $fs->mkdir($tmppath, 0755) ) + return new WP_Error('mkdir_failed', __('Could not create directory'), $tmppath); + } + break; //Exit main for loop + } } // We've made sure the folders are there, so let's extract the file now: @@ -414,7 +421,6 @@ function unzip_file($file, $to) { $fs->chmod($to . $file['filename'], 0644); } } - return true; } @@ -453,7 +459,7 @@ function WP_Filesystem( $args = false ) { if ( ! $method ) return false; - $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-'.$method.'.php', $method); + $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method); if( ! file_exists($abstraction_file) ) return; @@ -480,11 +486,7 @@ function get_filesystem_method($args = array()) { unlink($temp_file); } - if ( isset($args['connection_type']) && 'ssh' == $args['connection_type'] ) { - $method = 'SSH2'; - return apply_filters('filesystem_method', $method); - } - + if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') ) $method = 'ssh2'; if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext'; if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread return apply_filters('filesystem_method', $method); @@ -507,9 +509,13 @@ function request_filesystem_credentials($form_post, $type = '', $error = false) $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? $_POST['hostname'] : $credentials['hostname']); $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? $_POST['username'] : $credentials['username']); $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? $_POST['password'] : $credentials['password']); - if ( defined('FTP_SSH') || 'ssh' == $_POST['connection_type'] ) + + if ( strpos($credentials['hostname'], ':') ) + list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2); + + if ( defined('FTP_SSH') || (isset($_POST['connection_type']) && 'ssh' == $_POST['connection_type']) ) $credentials['connection_type'] = 'ssh'; - else if ( defined('FTP_SSL') || 'ftps' == $_POST['connection_type'] ) + else if ( defined('FTP_SSL') || (isset($_POST['connection_type']) && 'ftps' == $_POST['connection_type']) ) $credentials['connection_type'] = 'ftps'; else $credentials['connection_type'] = 'ftp'; @@ -523,7 +529,7 @@ function request_filesystem_credentials($form_post, $type = '', $error = false) $hostname = ''; $username = ''; $password = ''; - $ssl = ''; + $connection_type = ''; if ( !empty($credentials) ) extract($credentials, EXTR_OVERWRITE); if ( $error ) { @@ -540,7 +546,7 @@ function request_filesystem_credentials($form_post, $type = '', $error = false) - + @@ -556,7 +562,7 @@ function request_filesystem_credentials($form_post, $type = '', $error = false)



-

+

diff --git a/wp-admin/includes/update.php b/wp-admin/includes/update.php index 05551aaf0a..169e9acb1c 100644 --- a/wp-admin/includes/update.php +++ b/wp-admin/includes/update.php @@ -238,23 +238,22 @@ function wp_update_core($feedback = '') { return new WP_Error('download_failed', __('Download failed.'), $download_file->get_error_message()); $working_dir = $content_dir . 'upgrade/core'; - // Clean up working directory - if ( $wp_filesystem->is_dir($working_dir) ) + if ( $wp_filesystem->is_dir($working_dir) ) { $wp_filesystem->delete($working_dir, true); + } - apply_filters('update_feedback', __('Unpacking the update')); + apply_filters('update_feedback', __('Unpacking the core update')); // Unzip package to working directory $result = unzip_file($download_file, $working_dir); - // Once extracted, delete the package unlink($download_file); - + if ( is_wp_error($result) ) { $wp_filesystem->delete($working_dir, true); return $result; } - + // Copy update-core.php from the new version into place. if ( !$wp_filesystem->copy($working_dir . '/wordpress/wp-admin/includes/update-core.php', $wp_dir . 'wp-admin/includes/update-core.php', true) ) { $wp_filesystem->delete($working_dir, true);
size="40" />" size="40" />