From b95120c8083a3cf95d1b5589aab23aa160ce9737 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 11 Feb 2020 06:29:21 -0600 Subject: [PATCH 1/8] SFTP: change visibility of sortOptions for phpseclib2_compat --- phpseclib/Net/SFTP.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index cafcf32a..72d461ea 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -238,7 +238,7 @@ class SFTP extends SSH2 * @var array * @access private */ - private $sortOptions = []; + protected $sortOptions = []; /** * Canonicalization Flag From 8dac275a034edc139b8daf8fd1edf554cb024952 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 11 Feb 2020 23:01:18 -0600 Subject: [PATCH 2/8] SFTP: rm size() (we already have filesize()) --- phpseclib/Net/SFTP.php | 22 ---------------------- phpseclib/Net/SFTP/Stream.php | 2 +- tests/Functional/Net/SFTPLargeFileTest.php | 2 +- tests/Functional/Net/SFTPStreamTest.php | 2 +- tests/Functional/Net/SFTPUserStoryTest.php | 10 +++++----- 5 files changed, 8 insertions(+), 30 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 72d461ea..a148152d 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1060,28 +1060,6 @@ class SFTP extends SSH2 } } - /** - * Returns the file size, in bytes, or false, on failure - * - * Files larger than 4GB will show up as being exactly 4GB. - * - * @param string $filename - * @return mixed - * @access public - */ - public function size($filename) - { - if (!($this->bitmap & SSH2::MASK_LOGIN)) { - return false; - } - - $result = $this->stat($filename); - if ($result === false) { - return false; - } - return isset($result['size']) ? $result['size'] : -1; - } - /** * Save files / directories to cache * diff --git a/phpseclib/Net/SFTP/Stream.php b/phpseclib/Net/SFTP/Stream.php index 4136301e..a892b6f9 100644 --- a/phpseclib/Net/SFTP/Stream.php +++ b/phpseclib/Net/SFTP/Stream.php @@ -266,7 +266,7 @@ class Stream } $this->path = $path; - $this->size = $this->sftp->size($path); + $this->size = $this->sftp->filesize($path); $this->mode = preg_replace('#[bt]$#', '', $mode); $this->eof = false; diff --git a/tests/Functional/Net/SFTPLargeFileTest.php b/tests/Functional/Net/SFTPLargeFileTest.php index d661f76a..718426b0 100644 --- a/tests/Functional/Net/SFTPLargeFileTest.php +++ b/tests/Functional/Net/SFTPLargeFileTest.php @@ -36,7 +36,7 @@ class Functional_Net_SFTPLargeFileTest extends Functional_Net_SFTPTestCase $this->assertSame( 128 * 1024 * 1024, - $this->sftp->size($filename), + $this->sftp->filesize($filename), 'Failed asserting that uploaded local file has the expected length.' ); } diff --git a/tests/Functional/Net/SFTPStreamTest.php b/tests/Functional/Net/SFTPStreamTest.php index aad4189e..e24e85f5 100644 --- a/tests/Functional/Net/SFTPStreamTest.php +++ b/tests/Functional/Net/SFTPStreamTest.php @@ -24,7 +24,7 @@ class Functional_Net_SFTPStreamTest extends Functional_Net_SFTPTestCase $fp = fopen($this->buildUrl('fooo.txt'), 'wb', false, $context); $this->assertInternalType('resource', $fp); fclose($fp); - $this->assertSame(0, $this->sftp->size('fooo.txt')); + $this->assertSame(0, $this->sftp->filesize('fooo.txt')); } /** diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index 530e8a25..56c76fe5 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -148,7 +148,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $this->assertSame( self::$exampleDataLength, - $sftp->size('file1.txt'), + $sftp->filesize('file1.txt'), 'Failed asserting that put example data has the expected length' ); @@ -184,7 +184,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $this->assertSame( self::$exampleDataLength, - $sftp->size('file1.txt'), + $sftp->filesize('file1.txt'), 'Failed asserting that put example data has the expected length' ); @@ -232,7 +232,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $this->assertSame( 1024 * 1024, - $sftp->size('file3.txt'), + $sftp->filesize('file3.txt'), 'Failed asserting that truncate()\'d file has the expected length' ); @@ -352,7 +352,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $last_size = 0x7FFFFFFF; foreach ($files as $file) { if ($sftp->is_file($file)) { - $cur_size = $sftp->size($file); + $cur_size = $sftp->filesize($file); $this->assertLessThanOrEqual( $last_size, $cur_size, @@ -547,7 +547,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase $filename = 'file-large-from-truncate-4112MiB.txt'; $this->assertTrue($sftp->touch($filename)); $this->assertTrue($sftp->truncate($filename, $filesize)); - $this->assertSame($filesize, $sftp->size($filename)); + $this->assertSame($filesize, $sftp->filesize($filename)); return $sftp; } From 91eaf8a3104f014815a4d3af45d32c91283e3892 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 22 Feb 2020 17:43:33 -0600 Subject: [PATCH 3/8] CHANGELOG: 2.0.24 release --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 03c467cb..f8874fea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 2.0.24 - 2020-02-22 + +- X509: fix PHP 5.3 compatability issue +- SSH2: arcfour128 / arcfour256 were being included twice +- SSH2: make window resizing behave more consistently with PuTTY (#1421) +- SSH2: sodium_compat doesn't support memzero (#1432) +- SSH2: logging enhancements +- SFTP: don't buffer up download requests (PuTTY doesn't) (#1425) +- RSA: make PSS verification work for key length that aren't a power of 2 (#1423) + ## 2.0.23 - 2019-09-16 - SSH2: fix regression for connecting to servers with bad hostnames (#1405) From e8da444bb749d61a2ec6388f4ea39c65f16ac1c4 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 22 Feb 2020 22:21:19 -0600 Subject: [PATCH 4/8] SFTP/Stream: expand private key support to more than just RSA --- phpseclib/Net/SFTP/Stream.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/phpseclib/Net/SFTP/Stream.php b/phpseclib/Net/SFTP/Stream.php index a892b6f9..0c08266b 100644 --- a/phpseclib/Net/SFTP/Stream.php +++ b/phpseclib/Net/SFTP/Stream.php @@ -17,7 +17,7 @@ namespace phpseclib3\Net\SFTP; -use phpseclib3\Crypt\RSA; +use phpseclib3\Crypt\Common\PrivateKey; use phpseclib3\Net\SFTP; use phpseclib3\Net\SSH2; @@ -204,7 +204,7 @@ class Stream if (isset($context[$scheme]['password'])) { $pass = $context[$scheme]['password']; } - if (isset($context[$scheme]['privkey']) && $context[$scheme]['privkey'] instanceof RSA) { + if (isset($context[$scheme]['privkey']) && $context[$scheme]['privkey'] instanceof PrivateKey) { $pass = $context[$scheme]['privkey']; } From ee10846cac82856e26615be2ff00f5282f889690 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Mon, 24 Feb 2020 01:02:26 -0600 Subject: [PATCH 5/8] SSH2: more consistent exception handling --- phpseclib/Net/SSH2.php | 47 ++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 18 deletions(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index d131370b..75a17717 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -1295,6 +1295,7 @@ class SSH2 } if (version_compare($matches[3], '1.99', '<')) { + $this->bitmap = 0; throw new UnableToConnectException("Cannot connect to SSH $matches[3] servers"); } @@ -1310,6 +1311,7 @@ class SSH2 } if (!strlen($response) || ord($response[0]) != NET_SSH2_MSG_KEXINIT) { + $this->bitmap = 0; throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); } @@ -1444,11 +1446,12 @@ class SSH2 $kexinit_payload_server = $this->get_binary_packet(); if ($kexinit_payload_server === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } if (!strlen($kexinit_payload_server) || ord($kexinit_payload_server[0]) != NET_SSH2_MSG_KEXINIT) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException('Expected SSH_MSG_KEXINIT'); } } @@ -1552,12 +1555,13 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); throw new ConnectionClosedException('Connection closed by server'); } list($type, $primeBytes, $gBytes) = Strings::unpackSSH2('Css', $response); if ($type != NET_SSH2_MSG_KEXDH_GEX_GROUP) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException('Expected SSH_MSG_KEX_DH_GEX_GROUP'); } $this->updateLogHistory('NET_SSH2_MSG_KEXDH_REPLY', 'NET_SSH2_MSG_KEXDH_GEX_GROUP'); @@ -1600,7 +1604,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } if (!strlen($response)) { @@ -1615,6 +1619,7 @@ class SSH2 ) = Strings::unpackSSH2('Csss', $response); if ($type != constant($serverKexReplyMessage)) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException("Expected $serverKexReplyMessage"); } switch ($serverKexReplyMessage) { @@ -1680,7 +1685,7 @@ class SSH2 case $this->signature_format == $server_host_key_algorithm: case $server_host_key_algorithm != 'rsa-sha2-256' && $server_host_key_algorithm != 'rsa-sha2-512': case $this->signature_format != 'ssh-rsa': - $this->disconnect_helper(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED); + $this->disconnect_helper(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE); throw new \RuntimeException('Server Host Key Algorithm Mismatch'); } } @@ -1691,12 +1696,13 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } list($type) = Strings::unpackSSH2('C', $response); if ($type != NET_SSH2_MSG_NEWKEYS) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException('Expected SSH_MSG_NEWKEYS'); } @@ -2103,12 +2109,13 @@ class SSH2 } return $this->login_helper($username, $password); } - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } list($type, $service) = Strings::unpackSSH2('Cs', $response); if ($type != NET_SSH2_MSG_SERVICE_ACCEPT || $service != 'ssh-userauth') { + $this->disconnect_helper(NET_SSH2_DISCONNECT_PROTOCOL_ERROR); throw new \UnexpectedValueException('Expected SSH_MSG_SERVICE_ACCEPT'); } $this->bitmap |= self::MASK_LOGIN_REQ; @@ -2147,7 +2154,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2195,7 +2202,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2269,7 +2276,7 @@ class SSH2 } else { $orig = $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } } @@ -2455,7 +2462,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2483,7 +2490,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2596,7 +2603,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2721,7 +2728,7 @@ class SSH2 $response = $this->get_binary_packet(); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } @@ -2956,7 +2963,6 @@ class SSH2 $this->channel_status[self::CHANNEL_SUBSYSTEM] = NET_SSH2_MSG_CHANNEL_REQUEST; $response = $this->get_channel_packet(self::CHANNEL_SUBSYSTEM); - if ($response === false) { return false; } @@ -3254,7 +3260,7 @@ class SSH2 if ($this->hmac_check instanceof Hash) { $hmac = stream_get_contents($this->fsock, $this->hmac_size); if ($hmac === false || strlen($hmac) != $this->hmac_size) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR); throw new \RuntimeException('Error reading socket'); } @@ -3264,10 +3270,12 @@ class SSH2 if (($this->hmac_check->getHash() & "\xFF\xFF\xFF\xFF") == 'umac') { $this->hmac_check->setNonce("\0\0\0\0" . pack('N', $this->get_seq_no)); if ($hmac != $this->hmac_check->hash($reconstructed)) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR); throw new \RuntimeException('Invalid UMAC'); } } else { if ($hmac != $this->hmac_check->hash(pack('Na*', $this->get_seq_no, $reconstructed))) { + $this->disconnect_helper(NET_SSH2_DISCONNECT_MAC_ERROR); throw new \RuntimeException('Invalid HMAC'); } } @@ -3338,7 +3346,7 @@ class SSH2 while ($remaining_length > 0) { $temp = stream_get_contents($this->fsock, $remaining_length); if ($temp === false || feof($this->fsock)) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new \RuntimeException('Error reading from socket'); } $buffer.= $temp; @@ -3615,7 +3623,7 @@ class SSH2 $response = $this->get_binary_packet(true); if ($response === false) { - $this->bitmap = 0; + $this->disconnect_helper(NET_SSH2_DISCONNECT_CONNECTION_LOST); throw new ConnectionClosedException('Connection closed by server'); } } @@ -4086,7 +4094,10 @@ class SSH2 { if ($this->bitmap & self::MASK_CONNECTED) { $data = Strings::packSSH2('CNss', NET_SSH2_MSG_DISCONNECT, $reason, '', ''); - $this->send_binary_packet($data); + try { + $this->send_binary_packet($data); + } catch (\Exception $e) { + } } $this->bitmap = 0; From 59a7b1166b666a4e5b76313e72790700c2ffaaed Mon Sep 17 00:00:00 2001 From: terrafrost Date: Mon, 24 Feb 2020 19:20:00 -0600 Subject: [PATCH 6/8] SSH2: use RFC8332 auth even if host key algo isn't RSA --- phpseclib/Net/SSH2.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/phpseclib/Net/SSH2.php b/phpseclib/Net/SSH2.php index 75a17717..2da90962 100644 --- a/phpseclib/Net/SSH2.php +++ b/phpseclib/Net/SSH2.php @@ -2398,7 +2398,12 @@ class SSH2 if ($publickey instanceof RSA) { $privatekey = $privatekey->withPadding(RSA::SIGNATURE_PKCS1); - switch ($this->signature_format) { + $algos = ['rsa-sha2-256', 'rsa-sha2-512', 'ssh-rsa']; + if (isset($this->preferred['hostkey'])) { + $algos = array_intersect($this->preferred['hostkey'] , $algos); + } + $algo = self::array_intersect_first($algos, $this->server_host_key_algorithms); + switch ($algo) { case 'rsa-sha2-512': $hash = 'sha512'; $signatureType = 'rsa-sha2-512'; From db6ce986f3b1ba2309ac97d757c3ab5094188205 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Mon, 24 Feb 2020 22:14:28 -0600 Subject: [PATCH 7/8] Revert "SFTP: don't buffer up download requests (PuTTY doesn't)" This reverts commit 333e2e4c2bb1e50e698be57f601cb08260705654. --- phpseclib/Net/SFTP.php | 49 +++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 1fc794db..4984156b 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1701,6 +1701,13 @@ class Net_SFTP extends Net_SSH2 } $i++; + + if ($i >= NET_SFTP_QUEUE_SIZE) { + if (!$this->_read_put_responses($i)) { + return false; + } + $i = 0; + } } } @@ -1710,8 +1717,11 @@ class Net_SFTP extends Net_SSH2 $i++; - if (!$this->_read_put_responses($i)) { - return false; + if ($i >= NET_SFTP_QUEUE_SIZE) { + if (!$this->_read_put_responses($i)) { + return false; + } + $i = 0; } return true; @@ -2081,7 +2091,7 @@ class Net_SFTP extends Net_SSH2 $subtemp = $offset + $sent; $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); - if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet, $i)) { + if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { if ($mode & NET_SFTP_LOCAL_FILE) { fclose($fp); } @@ -2093,6 +2103,14 @@ class Net_SFTP extends Net_SSH2 } $i++; + + if ($i == NET_SFTP_QUEUE_SIZE) { + if (!$this->_read_put_responses($i)) { + $i = 0; + break; + } + $i = 0; + } } if (!$this->_read_put_responses($i)) { @@ -2380,8 +2398,10 @@ class Net_SFTP extends Net_SSH2 if (!$recursive) { return false; } - - return $this->_delete_recursive($path); + $i = 0; + $result = $this->_delete_recursive($path, $i); + $this->_read_put_responses($i); + return $result; } $this->_remove_from_stat_cache($path); @@ -2399,8 +2419,11 @@ class Net_SFTP extends Net_SSH2 * @return bool * @access private */ - function _delete_recursive($path) + function _delete_recursive($path, &$i) { + if (!$this->_read_put_responses($i)) { + return false; + } $i = 0; $entries = $this->_list($path, true); @@ -2428,6 +2451,13 @@ class Net_SFTP extends Net_SSH2 $this->_remove_from_stat_cache($temp); $i++; + + if ($i >= NET_SFTP_QUEUE_SIZE) { + if (!$this->_read_put_responses($i)) { + return false; + } + $i = 0; + } } } @@ -2438,8 +2468,11 @@ class Net_SFTP extends Net_SSH2 $i++; - if (!$this->_read_put_responses($i)) { - return false; + if ($i >= NET_SFTP_QUEUE_SIZE) { + if (!$this->_read_put_responses($i)) { + return false; + } + $i = 0; } return true; From 08e4096e7c1fa3b95a039e38fac82da641fd7028 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 25 Feb 2020 20:37:20 -0600 Subject: [PATCH 8/8] SFTP: speed up uploads --- phpseclib/Net/SFTP.php | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 4984156b..c9244c85 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -438,6 +438,9 @@ class Net_SFTP extends Net_SSH2 if (!defined('NET_SFTP_QUEUE_SIZE')) { define('NET_SFTP_QUEUE_SIZE', 32); } + if (!defined('NET_SFTP_UPLOAD_QUEUE_SIZE')) { + define('NET_SFTP_UPLOAD_QUEUE_SIZE', 1024); + } } /** @@ -2075,7 +2078,7 @@ class Net_SFTP extends Net_SSH2 $sftp_packet_size = 4096; // PuTTY uses 4096 // make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" $sftp_packet_size-= strlen($handle) + 25; - $i = 0; + $i = $j = 0; while ($dataCallback || ($size === 0 || $sent < $size)) { if ($dataCallback) { $temp = call_user_func($dataCallback, $sftp_packet_size); @@ -2091,7 +2094,7 @@ class Net_SFTP extends Net_SSH2 $subtemp = $offset + $sent; $packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); - if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) { + if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet, $j)) { if ($mode & NET_SFTP_LOCAL_FILE) { fclose($fp); } @@ -2103,8 +2106,9 @@ class Net_SFTP extends Net_SSH2 } $i++; + $j++; - if ($i == NET_SFTP_QUEUE_SIZE) { + if ($i == NET_SFTP_UPLOAD_QUEUE_SIZE) { if (!$this->_read_put_responses($i)) { $i = 0; break;