Make WordPress Core

Ticket #7690: 7690.7.diff

File 7690.7.diff, 19.9 KB (added by DD32, 17 years ago)
  • wp-admin/includes/class-wp-filesystem-ssh2.php

     
    99/**
    1010 * WordPress Filesystem Class for implementing SSH2.
    1111 *
     12 * To use this class you must follow these steps for PHP 5.2.6+
     13 *
     14 * @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes
     15 *
     16 * Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now.)
     17 *
     18 * cd /usr/src
     19 * wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
     20 * tar -zxvf libssh2-0.14.tar.gz
     21 * cd libssh2-0.14/
     22 * ./configure
     23 * make all install
     24 *
     25 * Note: No not leave the directory yet!
     26 *
     27 * Enter: pecl install -f ssh2
     28 *
     29 * Copy the ssh.so file it creates to your PHP Module Directory.
     30 * Open up your PHP.INI file and look for where extensions are placed.
     31 * Add in your PHP.ini file: extension=ssh2.so
     32 *
     33 * Restart Apache!
     34 * Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp  exist.
     35 *
     36 *
    1237 * @since 2.7
    1338 * @package WordPress
    1439 * @subpackage Filesystem
     
    1641 */
    1742class WP_Filesystem_SSH2 extends WP_Filesystem_Base {
    1843       
    19         var $debugtest = true;  //      this is my var that will output the text when debuggin this class
     44        var $debugtest = false; //      this is my var that will output the text when debuggin this class
    2045       
    21         var $link;
    22         var $timeout = 5;
     46        var $link = null;
     47        var $sftp_link = null;
     48        /*
     49         * This is the timeout value for ssh results to comeback.
     50         * Slower servers might need this incressed, but this number otherwise should not change.
     51         *
     52         * @parm $timeout int
     53         *
     54         */
     55        var $timeout = 15;
    2356        var $errors = array();
    2457        var $options = array();
    2558
    26         var $permission = null;
     59        var $permission = 0644;
    2760
    28         var $filetypes = array(
    29                                                         'php'=>FTP_ASCII,
    30                                                         'css'=>FTP_ASCII,
    31                                                         'txt'=>FTP_ASCII,
    32                                                         'js'=>FTP_ASCII,
    33                                                         'html'=>FTP_ASCII,
    34                                                         'htm'=>FTP_ASCII,
    35                                                         'xml'=>FTP_ASCII,
    36 
    37                                                         'jpg'=>FTP_BINARY,
    38                                                         'png'=>FTP_BINARY,
    39                                                         'gif'=>FTP_BINARY,
    40                                                         'bmp'=>FTP_BINARY
    41                                                         );
    42 
    4361        function WP_Filesystem_SSH2($opt='') {
    4462                $this->method = 'ssh2';
    4563                $this->errors = new WP_Error();
     
    7189                        $this->options['username'] = $opt['username'];
    7290
    7391                if ( empty ($opt['password']) )
    74                         $this->errors->add('empty_password', __('SSH password is required'));
     92                        $this->errors->add('empty_password', __('SSH2 password is required'));
    7593                else
    7694                        $this->options['password'] = $opt['password'];
    77 
    7895        }
    7996
    8097        function connect() {
     
    91108                        return false;
    92109                }
    93110
     111                $this->sftp_link = ssh2_sftp($this->link);
     112
    94113                return true;
    95114        }
    96115       
    97116        function run_command($link, $command, $returnbool = false) {
    98                 $this->debug("run_command(".$command.");");
    99                 if(!($stream = @ssh2_exec( $link, $command ))) {
    100             $this->errors->add('command', sprintf(__('Unable to preform command: %s'), $command));
     117                //$this->debug("run_command(".$command.",".$returnbool.");");
     118                if(!($stream = @ssh2_exec( $link, $command . "; echo \"__COMMAND_FINISHED__\";"))) {
     119            $this->errors->add('command', sprintf(__('Unable to perform command: %s'), $command));
    101120        } else {
    102121            stream_set_blocking( $stream, true );
    103122                        $time_start = time();
    104             $data = "";
     123            $data = null;
    105124                        while( true ) {
     125                            if (strpos($data,"__COMMAND_FINISHED__") !== false){
     126                                break;  //      the command has finshed!
     127                            }
    106128                            if( (time()-$time_start) > $this->timeout ){
    107129                                $this->errors->add('command', sprintf(__('Connection to the server has timeout after %s seconds.'), $this->timeout));
    108                                 break;
     130                                        unset($this->link);
     131                                        unset($this->sftp_link); //     close connections
     132                                return false;
    109133                            }
    110                     while( $buf = fread( $stream, strlen($stream) ) ){
     134                    while( $buf = fread( $stream, strlen($stream) ) )
    111135                        $data .= $buf;
    112                     }
    113136                        }
    114137            fclose($stream);
    115             if (($returnbool) && ($data)) {
    116                 $this->debug("Data: " . print_r($data, true) . " Returning: True");
     138                        $data = str_replace("__COMMAND_FINISHED__", "", $data);
     139                        //$this->debug("run_command(".$command."); --> \$data = " . $data);
     140            if (($returnbool) && ( (int) $data )) {
     141                $this->debug("Data. Returning: True");
    117142                return true;
    118             } elseif (($returnbool) && (!$data)) {
    119                 $this->debug("Data: " . print_r($data, true) . " Returning: False");
     143            } elseif (($returnbool) && (! (int) $data )) {
     144                $this->debug("Data. Returning: False");
    120145                return false;
    121146            } else {
    122                 $this->debug("Data: " . print_r($data, true));
     147                $this->debug("Data Only.");
    123148                return $data;
    124149            }
    125150        }
     151                return false;
    126152        }
    127153
    128154        function debug($text)
    129155        {
    130156                if ($this->debugtest)
    131157                {
    132                         echo $text . "<br/>";
     158                        echo "<br/>" . $text . "<br/>";
    133159                }
    134160        }
    135161
    136162        function setDefaultPermissions($perm) {
    137                 $this->permission = $perm;
     163                $this->debug("setDefaultPermissions();");
     164                if ( $perm )
     165                        $this->permission = $perm;
    138166        }
    139167
    140         function get_contents($file, $type = '', $resumepos = 0 ){
    141                 if( empty($type) ){
    142                         $extension = substr(strrchr($file, "."), 1);
    143                         $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII;
    144                 }
    145                 $temp = tmpfile();
    146                 if ( ! $temp )
     168        function get_contents($file, $type = '', $resumepos = 0 ) {
     169                $tempfile = wp_tempnam( $file );
     170                if ( ! $tempfile )
    147171                        return false;
    148                 if( ! @ssh2_scp_recv($this->link, $temp, $file) )
     172                if( ! ssh2_scp_recv($this->link, $file, $tempfile) )
    149173                        return false;
    150                 fseek($temp, 0); //Skip back to the start of the file being written to
    151                 $contents = '';
    152                 while (!feof($temp)) {
    153                         $contents .= fread($temp, 8192);
    154                 }
    155                 fclose($temp);
     174                $contents = file_get_contents($tempfile);
     175                unlink($tempfile);
    156176                return $contents;
    157177        }
    158178       
    159179        function get_contents_array($file) {
     180                $this->debug("get_contents_array();");
    160181                return explode("\n", $this->get_contents($file));
    161182        }
    162183       
    163184        function put_contents($file, $contents, $type = '' ) {
    164                 if( empty($type) ) {
    165                         $extension = substr(strrchr($file, "."), 1);
    166                         $type = isset($this->filetypes[ $extension ]) ? $this->filetypes[ $extension ] : FTP_ASCII;
    167                 }
    168                 $temp = tmpfile();
     185                $tempfile = wp_tempnam( $file );
     186                $temp = fopen($tempfile, 'w');
    169187                if ( ! $temp )
    170188                        return false;
    171189                fwrite($temp, $contents);
    172                 fseek($temp, 0); //Skip back to the start of the file being written to
    173                 $ret = @ssh2_scp_send($this->link, $file, $temp, $type);
    174190                fclose($temp);
     191                $ret = ssh2_scp_send($this->link, $tempfile, $file, $this->permission);
     192                unlink($tempfile);
    175193                return $ret;
    176194        }
    177195       
    178196        function cwd() {
    179                 $cwd = $this->run_command($this->link, "pwd");
     197                $cwd = $this->run_command($this->link, 'pwd');
    180198                if( $cwd )
    181199                        $cwd = trailingslashit($cwd);
    182200                return $cwd;
    183201        }
    184202       
    185203        function chdir($dir) {
    186                 if ($this->run_command($this->link, "cd " . $dir, true)) {
    187                         return true;
    188                 }
    189                 return false;
     204                return $this->run_command($this->link, 'cd ' . $dir, true);
    190205        }
    191206       
    192207        function chgrp($file, $group, $recursive = false ) {
    193                 return false;
     208                $this->debug("chgrp();");
     209                if ( ! $this->exists($file) )
     210                        return false;
     211                if ( ! $recursive || ! $this->is_dir($file) )
     212                        return $this->run_command($this->link, sprintf('chgrp %o %s', $mode, $file), true);
     213                return $this->run_command($this->link, sprintf('chgrp -R %o %s', $mode, $file), true);
    194214        }
    195215       
    196216        function chmod($file, $mode = false, $recursive = false) {
     217                $this->debug("chmod();");
    197218                if( ! $mode )
    198219                        $mode = $this->permission;
    199220                if( ! $mode )
    200221                        return false;
    201222                if ( ! $this->exists($file) )
    202223                        return false;
    203                 if ( ! $recursive || ! $this->is_dir($file) ) {
    204                         return $this->run_command($this->link, sprintf('CHMOD %o %s', $mode, $file), true);
    205                 }
    206                 //Is a directory, and we want recursive
    207                 $filelist = $this->dirlist($file);
    208                 foreach($filelist as $filename){
    209                         $this->chmod($file . '/' . $filename, $mode, $recursive);
    210                 }
    211                 return true;
     224                if ( ! $recursive || ! $this->is_dir($file) )
     225                        return $this->run_command($this->link, sprintf('chmod %o %s', $mode, $file), true);
     226                return $this->run_command($this->link, sprintf('chmod -R %o %s', $mode, $file), true);
    212227        }
    213228       
    214229        function chown($file, $owner, $recursive = false ) {
    215                 return false;
     230                $this->debug("chown();");
     231                if ( ! $this->exists($file) )
     232                        return false;
     233                if ( ! $recursive || ! $this->is_dir($file) )
     234                        return $this->run_command($this->link, sprintf('chown %o %s', $mode, $file), true);
     235                return $this->run_command($this->link, sprintf('chown -R %o %s', $mode, $file), true);
    216236        }
    217237       
    218238        function owner($file) {
     239                $this->debug("owner();");
    219240                $dir = $this->dirlist($file);
    220241                return $dir[$file]['owner'];
    221242        }
    222243       
    223244        function getchmod($file) {
     245                $this->debug("getchmod();");
    224246                $dir = $this->dirlist($file);
    225247                return $dir[$file]['permsn'];
    226248        }
    227249       
    228250        function group($file) {
     251                $this->debug("group();");
    229252                $dir = $this->dirlist($file);
    230253                return $dir[$file]['group'];
    231254        }
    232255       
    233256        function copy($source, $destination, $overwrite = false ) {
     257                $this->debug("copy();");
    234258                if( ! $overwrite && $this->exists($destination) )
    235259                        return false;
    236260                $content = $this->get_contents($source);
     
    240264        }
    241265       
    242266        function move($source, $destination, $overwrite = false) {
     267                $this->debug("move();");
    243268                return @ssh2_sftp_rename($this->link, $source, $destination);
    244269        }
    245270
    246         function delete($file, $recursive=false) {
     271        function delete($file, $recursive = false) {
    247272                if ( $this->is_file($file) )
    248                         return @ssh2_sftp_unlink($this->link, $file);
    249                 if ( !$recursive )
    250                         return @ssh2_sftp_rmdir($this->link, $file);
     273                        return ssh2_sftp_unlink($this->sftp_link, $file);
     274                if ( ! $recursive )
     275                         return ssh2_sftp_rmdir($this->sftp_link, $file);
    251276                $filelist = $this->dirlist($file);
    252                 foreach ((array) $filelist as $filename => $fileinfo) {
    253                         $this->delete($file . '/' . $filename, $recursive);
     277                if ( is_array($filelist) ) {
     278                        foreach ( $filelist as $filename => $fileinfo) {
     279                                $this->delete($file . '/' . $filename, $recursive);
     280                        }
    254281                }
    255                 return @ssh2_sftp_rmdir($this->link, $file);
     282                return ssh2_sftp_rmdir($this->sftp_link, $file);
    256283        }
    257284
    258285        function exists($file) {
    259                 $list = $this->run_command($this->link, sprintf('ls -la %s', $file));
    260                 if( ! $list )
    261                         return false;
    262                 return count($list) == 1 ? true : false;
     286                $list = $this->run_command($this->link, sprintf('ls -lad %s', $file));
     287                return (bool) $list;
    263288        }
    264289       
    265290        function is_file($file) {
    266                 return $this->is_dir($file) ? false : true;
     291                //DO NOT RELY ON dirlist()!
     292                $list = $this->run_command($this->link, sprintf('ls -lad %s', $file));
     293                $list = $this->parselisting($list);
     294                if ( ! $list )
     295                        return false;
     296                else
     297                        return ( !$list['isdir'] && !$list['islink'] ); //ie. not a file or link, yet exists, must be file.
    267298        }
    268299       
    269300        function is_dir($path) {
    270                 $cwd = $this->cwd();
    271                 $result = $this->run_command($this->link, sprintf('cd %s', $path), true);
    272                 if( $result && $path == $this->cwd() || $this->cwd() != $cwd ) {
    273                         // @todo: use ssh2_exec
    274                         @ftp_chdir($this->link, $cwd);
    275                         return true;
    276                 }
    277                 return false;
     301                //DO NOT RELY ON dirlist()!
     302                $list = $this->parselisting($this->run_command($this->link, sprintf('ls -lad %s', rtrim($path, '/'))));
     303                if ( ! $list )
     304                        return false;
     305                else
     306                        return $list['isdir'];
    278307        }
    279        
     308
    280309        function is_readable($file) {
    281                 //Get dir list, Check if the file is writable by the current user??
    282                 return true;
     310                //Not implmented.
    283311        }
    284312       
    285313        function is_writable($file) {
    286                 //Get dir list, Check if the file is writable by the current user??
    287                 return true;
     314                //Not implmented.
    288315        }
    289316       
    290317        function atime($file) {
    291                 return false;
     318                //Not implmented.
    292319        }
    293320       
    294321        function mtime($file) {
    295                 return; //      i have to look up to see if there is a way in SSH2 to look the modifed date
    296                 //      return ftp_mdtm($this->link, $file);
     322                //Not implmented.
    297323        }
    298324       
    299325        function size($file) {
    300                 return; //      i have to look up to see if there is a way in SSH2 to get the file size
    301                 //      return ftp_size($this->link, $file);
     326                //Not implmented.
    302327        }
    303328       
    304329        function touch($file, $time = 0, $atime = 0) {
    305                 return false;
     330                //Not implmented.
    306331        }
    307332       
    308         function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
    309                 if( !@ssh2_sftp_mkdir($this->link, $path) )
     333        function mkdir($path, $chmod = null, $chown = false, $chgrp = false) {
     334                if( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) )
    310335                        return false;
    311                 if( $chmod )
    312                         $this->chmod($path, $chmod);
    313336                if( $chown )
    314337                        $this->chown($path, $chown);
    315338                if( $chgrp )
     
    318341        }
    319342       
    320343        function rmdir($path, $recursive = false) {
    321                 if( ! $recursive )
    322                         return @ssh2_sftp_rmdir($this->link, $path);
    323 
    324                 //TODO: Recursive Directory delete, Have to delete files from the folder first.
    325                 //$dir = $this->dirlist($path);
    326                 //foreach($dir as $file)
    327 
     344                return $this->delete($path, $recursive);
    328345        }
    329346
    330347        function parselisting($line) {
     348        $this->debug("parselisting();");
    331349                $is_windows = ($this->OS_remote == FTP_OS_Windows);
    332350                if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/", $line, $lucifer)) {
    333351                        $b = array();
     
    390408        }
    391409
    392410        function dirlist($path = '.', $incdot = false, $recursive = false) {
     411                $this->debug("dirlist();");
    393412                if( $this->is_file($path) ) {
    394413                        $limitFile = basename($path);
    395                         $path = dirname($path) . '/';
     414                        $path = trailingslashit(dirname($path));
    396415                } else {
    397416                        $limitFile = false;
    398417                }
    399                
    400                 $list = $this->run_command($this->link, sprintf('ls -a %s', $path));
    401418
     419                $list = $this->run_command($this->link, sprintf('ls -la %s', $path));
     420
    402421                if ( $list === false )
    403422                        return false;
    404423
     424                $list = explode("\n", $list);
     425
    405426                $dirlist = array();
    406                 foreach ( $list as $k => $v ) {
     427                foreach ( (array)$list as $k => $v ) {
    407428                        $entry = $this->parselisting($v);
    408429                        if ( empty($entry) )
    409430                                continue;
    410431
    411                         if ( '.' == $entry["name"] || '..' == $entry["name"] )
     432                        if ( '.' == $entry['name'] || '..' == $entry['name'] )
    412433                                continue;
    413434
    414435                        $dirlist[ $entry['name'] ] = $entry;
     
    416437
    417438                if ( ! $dirlist )
    418439                        return false;
     440
    419441                if ( empty($dirlist) )
    420442                        return array();
    421443
     
    432454                                                        $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive);
    433455                                        }
    434456                                } else { //No dots
    435                                         if ($recursive)
     457                                        if ( $recursive )
    436458                                                $struc['files'] = $this->dirlist($path . '/' . $struc['name'], $incdot, $recursive);
    437459                                }
    438460                        }
     
    441463                }
    442464                return $ret;
    443465        }
    444 
    445466        function __destruct(){
    446                 if( $this->link )
     467                if ( $this->link )
    447468                        unset($this->link);
     469                if ( $this->sftp_link )
     470                        unset($this->sftp_link);
    448471        }
    449472}
    450473
    451 ?>
    452  No newline at end of file
     474?>
  • wp-admin/includes/file.php

     
    386386        if ( 0 == count($archive_files) )
    387387                return new WP_Error('empty_archive', __('Empty archive'));
    388388
    389         $to = trailingslashit($to);
    390389        $path = explode('/', $to);
    391         $tmppath = '';
    392         for ( $j = 0; $j < count($path) - 1; $j++ ) {
    393                 $tmppath .= $path[$j] . '/';
    394                 if ( ! $fs->is_dir($tmppath) )
    395                         $fs->mkdir($tmppath, 0755);
     390        for ( $i = count($path); $i > 0; $i-- ) { //>0 = first element is empty allways for paths starting with '/'
     391                $tmppath = implode('/', array_slice($path, 0, $i) );
     392                if ( $fs->is_dir($tmppath) ) { //Found the highest folder that exists, Create from here(ie +1)
     393                        for ( $i = $i + 1; $i <= count($path); $i++ ) {
     394                                $tmppath = implode('/', array_slice($path, 0, $i) );
     395                                if ( ! $fs->mkdir($tmppath, 0755) )
     396                                        return new WP_Error('mkdir_failed', __('ACould not create directory'), $tmppath);
     397                        }
     398                        break; //Exit main for loop
     399                }
    396400        }
    397401
     402        $to = trailingslashit($to);
    398403        foreach ($archive_files as $file) {
    399404                $path = explode('/', $file['filename']);
    400                 $tmppath = '';
    401 
    402                 // Loop through each of the items and check that the folder exists.
    403                 for ( $j = 0; $j < count($path) - 1; $j++ ) {
    404                         $tmppath .= $path[$j] . '/';
    405                         if ( ! $fs->is_dir($to . $tmppath) )
    406                                 if ( !$fs->mkdir($to . $tmppath, 0755) )
    407                                         return new WP_Error('mkdir_failed', __('Could not create directory'), $to . $tmppath);
     405                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
     406                        $tmppath = $to . implode('/', array_slice($path, 0, $i) );
     407                        if ( $fs->is_dir($tmppath) ) {//Found the highest folder that exists, Create from here
     408                                for ( $i = $i + 1; $i < count($path); $i++ ) { //< count() no file component please.
     409                                        $tmppath = $to . implode('/', array_slice($path, 0, $i) );
     410                                        if ( ! $fs->mkdir($tmppath, 0755) )
     411                                                return new WP_Error('mkdir_failed', __('BCould not create directory'), $tmppath);
     412                                }
     413                                break; //Exit main for loop
     414                        }
    408415                }
    409416
    410417                // We've made sure the folders are there, so let's extract the file now:
     
    414421                        $fs->chmod($to . $file['filename'], 0644);
    415422                }
    416423        }
    417 
    418424        return true;
    419425}
    420426
     
    453459        if ( ! $method )
    454460                return false;
    455461
    456         $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-'.$method.'.php', $method);
     462        $abstraction_file = apply_filters('filesystem_method_file', ABSPATH . 'wp-admin/includes/class-wp-filesystem-' . $method . '.php', $method);
    457463        if( ! file_exists($abstraction_file) )
    458464                return;
    459465
     
    480486                unlink($temp_file);
    481487        }
    482488
    483         if ( isset($args['connection_type']) && 'ssh' == $args['connection_type'] ) {
    484                 $method = 'SSH2';
    485                 return apply_filters('filesystem_method', $method);
    486         }
     489        if ( ! $method && isset($args['connection_type']) && 'ssh' == $args['connection_type'] && extension_loaded('ssh2') ) $method = 'ssh2';
    487490
    488491        if ( ! $method && extension_loaded('ftp') ) $method = 'ftpext';
    489492        if ( ! $method && ( extension_loaded('sockets') || function_exists('fsockopen') ) ) $method = 'ftpsockets'; //Sockets: Socket extension; PHP Mode: FSockopen / fwrite / fread
     
    507510        $credentials['hostname'] = defined('FTP_HOST') ? FTP_HOST : (!empty($_POST['hostname']) ? $_POST['hostname'] : $credentials['hostname']);
    508511        $credentials['username'] = defined('FTP_USER') ? FTP_USER : (!empty($_POST['username']) ? $_POST['username'] : $credentials['username']);
    509512        $credentials['password'] = defined('FTP_PASS') ? FTP_PASS : (!empty($_POST['password']) ? $_POST['password'] : $credentials['password']);
    510         if ( defined('FTP_SSH') || 'ssh' == $_POST['connection_type'] )
     513       
     514        if ( strpos($credentials['hostname'], ':') )
     515                list( $credentials['hostname'], $credentials['port'] ) = explode(':', $credentials['hostname'], 2);
     516
     517        if ( defined('FTP_SSH') || (isset($_POST['connection_type']) && 'ssh' == $_POST['connection_type']) )
    511518                $credentials['connection_type'] = 'ssh';
    512         else if ( defined('FTP_SSL') || 'ftps' == $_POST['connection_type'] )
     519        else if ( defined('FTP_SSL') || (isset($_POST['connection_type']) && 'ftps' == $_POST['connection_type']) )
    513520                $credentials['connection_type'] = 'ftps';
    514521        else
    515522                $credentials['connection_type'] = 'ftp';
     
    523530        $hostname = '';
    524531        $username = '';
    525532        $password = '';
    526         $ssl = '';
     533        $connection_type = '';
    527534        if ( !empty($credentials) )
    528535                extract($credentials, EXTR_OVERWRITE);
    529536        if ( $error ) {
     
    540547<table class="form-table">
    541548<tr valign="top">
    542549<th scope="row"><label for="hostname"><?php _e('Hostname') ?></label></th>
    543 <td><input name="hostname" type="text" id="hostname" value="<?php echo attribute_escape($hostname) ?>"<?php if( defined('FTP_HOST') ) echo ' disabled="disabled"' ?> size="40" /></td>
     550<td><input name="hostname" type="text" id="hostname" value="<?php echo attribute_escape($hostname); if ( !empty($port) ) echo ":$port"; ?>"<?php if( defined('FTP_HOST') ) echo ' disabled="disabled"' ?> size="40" /></td>
    544551</tr>
    545552<tr valign="top">
    546553<th scope="row"><label for="username"><?php _e('Username') ?></label></th>