From e48ee12940a702da8bc5c2887902c82094851efd Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 16 Aug 2014 12:49:55 -0500 Subject: [PATCH 1/5] SFTP: make it so files can be downloaded into resources or upload from resources --- phpseclib/Net/SFTP.php | 58 ++++++++++++++-------- tests/Functional/Net/SFTPUserStoryTest.php | 20 ++++++++ 2 files changed, 58 insertions(+), 20 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 306b75d1..6f32b9a7 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1757,6 +1757,8 @@ class Net_SFTP extends Net_SSH2 * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * + * If $data is a resource then it'll be used a resource instead. + * * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. * @@ -1834,16 +1836,25 @@ class Net_SFTP extends Net_SSH2 } // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 - if ($mode & NET_SFTP_LOCAL_FILE) { - if (!is_file($data)) { - user_error("$data is not a valid file"); - return false; - } - $fp = @fopen($data, 'rb'); - if (!$fp) { - return false; - } - $size = filesize($data); + switch (true) { + case is_resource($data): + $mode = $mode & ~NET_SFTP_LOCAL_FILE; + $fp = $data; + break; + case $mode & NET_SFTP_LOCAL_FILE: + if (!is_file($data)) { + user_error("$data is not a valid file"); + return false; + } + $fp = @fopen($data, 'rb'); + if (!$fp) { + return false; + } + } + + if (isset($fp)) { + $stat = fstat($fp); + $size = $stat['size']; if ($local_start >= 0) { fseek($fp, $local_start); @@ -2005,13 +2016,20 @@ class Net_SFTP extends Net_SSH2 return false; } - if ($local_file !== false) { - $fp = fopen($local_file, 'wb'); - if (!$fp) { - return false; - } + if (is_resource($local_file)) { + $fp = $local_file; + $stat = fstat($fp); + $res_offset = $stat['size']; } else { - $content = ''; + $res_offset = 0; + if ($local_file !== false) { + $fp = fopen($local_file, 'wb'); + if (!$fp) { + return false; + } + } else { + $content = ''; + } } $start = $offset; @@ -2019,7 +2037,7 @@ class Net_SFTP extends Net_SSH2 while (true) { $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { - if ($local_file !== false) { + if ($local_file !== false && !is_resource($local_file)) { fclose($fp); } return false; @@ -2042,7 +2060,7 @@ class Net_SFTP extends Net_SSH2 break 2; default: user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); - if ($local_file !== false) { + if ($local_file !== false && !is_resource($local_file)) { fclose($fp); } return false; @@ -2057,11 +2075,11 @@ class Net_SFTP extends Net_SSH2 if ($local_file === false) { $content = substr($content, 0, $length); } else { - ftruncate($fp, $length); + ftruncate($fp, $length + $res_offset); } } - if ($local_file !== false) { + if ($local_file !== false && !is_resource($local_file)) { fclose($fp); } diff --git a/tests/Functional/Net/SFTPUserStoryTest.php b/tests/Functional/Net/SFTPUserStoryTest.php index 974af9cb..7388e89d 100644 --- a/tests/Functional/Net/SFTPUserStoryTest.php +++ b/tests/Functional/Net/SFTPUserStoryTest.php @@ -319,6 +319,26 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase /** * @depends testSortOrder */ + public function testResourceXfer($sftp) + { + $fp = fopen('res.txt', 'w+'); + $sftp->get('file1.txt', $fp); + rewind($fp); + $sftp->put('file4.txt', $fp); + fclose($fp); + + $this->assertSame( + self::$exampleData, + $sftp->get('file4.txt'), + 'Failed asserting that a file downloaded into a resource and reuploaded from a resource has the correct data' + ); + + return $sftp; + } + + /** + * @depends testResourceXfer + */ public function testSymlink($sftp) { $this->assertTrue( From 7ed53f24282f0f32d9ae3d8805c366fd5632cf05 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 16 Aug 2014 13:56:34 -0500 Subject: [PATCH 2/5] SFTP: fix issue with uploading via a resource --- 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 6f32b9a7..2d18742e 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1875,7 +1875,7 @@ class Net_SFTP extends Net_SSH2 $sftp_packet_size-= strlen($handle) + 25; $i = 0; while ($sent < $size) { - $temp = $mode & NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); + $temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); $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)) { From 29e0143308d0d0af2265bda911f0f0f7ea70af56 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Sat, 16 Aug 2014 15:49:38 -0500 Subject: [PATCH 3/5] SFTP: grammar --- 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 2d18742e..4bdcbd9a 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1757,7 +1757,7 @@ class Net_SFTP extends Net_SSH2 * contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how * large $remote_file will be, as well. * - * If $data is a resource then it'll be used a resource instead. + * If $data is a resource then it'll be used as a resource instead. * * Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take * care of that, yourself. From cb66c561c2fa11850a931f23a6f10ccca4b97029 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 19 Aug 2014 14:05:24 -0500 Subject: [PATCH 4/5] SFTP: optimize conditional calls to fclose in get() method --- phpseclib/Net/SFTP.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/phpseclib/Net/SFTP.php b/phpseclib/Net/SFTP.php index 4bdcbd9a..dd6c4a7e 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -2032,12 +2032,14 @@ class Net_SFTP extends Net_SSH2 } } + $fclose_check = $local_file !== false && !is_resource($local_file); + $start = $offset; $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; while (true) { $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { - if ($local_file !== false && !is_resource($local_file)) { + if ($fclose_check) { fclose($fp); } return false; @@ -2060,7 +2062,7 @@ class Net_SFTP extends Net_SSH2 break 2; default: user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); - if ($local_file !== false && !is_resource($local_file)) { + if ($fclose_check) { fclose($fp); } return false; @@ -2079,7 +2081,7 @@ class Net_SFTP extends Net_SSH2 } } - if ($local_file !== false && !is_resource($local_file)) { + if ($fclose_check) { fclose($fp); } From 74feca9cf22ff9c3be3ab0290f3296aeb4080b98 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Tue, 19 Aug 2014 14:20:20 -0500 Subject: [PATCH 5/5] SFTP: cs adjustment --- 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 dd6c4a7e..5335927d 100644 --- a/phpseclib/Net/SFTP.php +++ b/phpseclib/Net/SFTP.php @@ -1780,7 +1780,7 @@ class Net_SFTP extends Net_SSH2 * Setting $local_start to > 0 or $mode | NET_SFTP_RESUME_START doesn't do anything unless $mode | NET_SFTP_LOCAL_FILE. * * @param String $remote_file - * @param String $data + * @param String|resource $data * @param optional Integer $mode * @param optional Integer $start * @param optional Integer $local_start