Merge pull request #456 from terrafrost/sftp-resources

SFTP: make it so files can be downloaded into resources or upload from resources

* terrafrost/sftp-resources:
  SFTP: cs adjustment
  SFTP: optimize conditional calls to fclose in get() method
  SFTP: grammar
  SFTP: fix issue with uploading via a resource
  SFTP: make it so files can be downloaded into resources or upload   from resources
This commit is contained in:
Andreas Fischer 2014-08-19 22:25:02 +02:00
commit 7696cbf826
2 changed files with 62 additions and 22 deletions

View File

@ -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 * 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. * large $remote_file will be, as well.
* *
* 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 * 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. * care of that, yourself.
* *
@ -1778,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. * 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 $remote_file
* @param String $data * @param String|resource $data
* @param optional Integer $mode * @param optional Integer $mode
* @param optional Integer $start * @param optional Integer $start
* @param optional Integer $local_start * @param optional Integer $local_start
@ -1834,7 +1836,12 @@ class Net_SFTP extends Net_SSH2
} }
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3 // http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
if ($mode & NET_SFTP_LOCAL_FILE) { 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)) { if (!is_file($data)) {
user_error("$data is not a valid file"); user_error("$data is not a valid file");
return false; return false;
@ -1843,7 +1850,11 @@ class Net_SFTP extends Net_SSH2
if (!$fp) { if (!$fp) {
return false; return false;
} }
$size = filesize($data); }
if (isset($fp)) {
$stat = fstat($fp);
$size = $stat['size'];
if ($local_start >= 0) { if ($local_start >= 0) {
fseek($fp, $local_start); fseek($fp, $local_start);
@ -1864,7 +1875,7 @@ class Net_SFTP extends Net_SSH2
$sftp_packet_size-= strlen($handle) + 25; $sftp_packet_size-= strlen($handle) + 25;
$i = 0; $i = 0;
while ($sent < $size) { 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; $subtemp = $offset + $sent;
$packet = pack('Na*N3a*', strlen($handle), $handle, $subtemp / 4294967296, $subtemp, strlen($temp), $temp); $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)) {
@ -2005,6 +2016,12 @@ class Net_SFTP extends Net_SSH2
return false; return false;
} }
if (is_resource($local_file)) {
$fp = $local_file;
$stat = fstat($fp);
$res_offset = $stat['size'];
} else {
$res_offset = 0;
if ($local_file !== false) { if ($local_file !== false) {
$fp = fopen($local_file, 'wb'); $fp = fopen($local_file, 'wb');
if (!$fp) { if (!$fp) {
@ -2013,13 +2030,16 @@ class Net_SFTP extends Net_SSH2
} else { } else {
$content = ''; $content = '';
} }
}
$fclose_check = $local_file !== false && !is_resource($local_file);
$start = $offset; $start = $offset;
$size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length; $size = $this->max_sftp_packet < $length || $length < 0 ? $this->max_sftp_packet : $length;
while (true) { while (true) {
$packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size); $packet = pack('Na*N3', strlen($handle), $handle, $offset / 4294967296, $offset, $size);
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) { if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
return false; return false;
@ -2042,7 +2062,7 @@ class Net_SFTP extends Net_SSH2
break 2; break 2;
default: default:
user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS'); user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS');
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }
return false; return false;
@ -2057,11 +2077,11 @@ class Net_SFTP extends Net_SSH2
if ($local_file === false) { if ($local_file === false) {
$content = substr($content, 0, $length); $content = substr($content, 0, $length);
} else { } else {
ftruncate($fp, $length); ftruncate($fp, $length + $res_offset);
} }
} }
if ($local_file !== false) { if ($fclose_check) {
fclose($fp); fclose($fp);
} }

View File

@ -319,6 +319,26 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
/** /**
* @depends testSortOrder * @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) public function testSymlink($sftp)
{ {
$this->assertTrue( $this->assertTrue(