Merge remote-tracking branch 'audrey/sftp-put-callback-for-1.0' into 1.0

This commit is contained in:
terrafrost 2015-04-16 07:45:24 -05:00
commit 1d772c3a6f
2 changed files with 64 additions and 2 deletions

View File

@ -102,6 +102,11 @@ define('NET_SFTP_LOCAL_FILE', 1);
*/ */
// this value isn't really used anymore but i'm keeping it reserved for historical reasons // this value isn't really used anymore but i'm keeping it reserved for historical reasons
define('NET_SFTP_STRING', 2); define('NET_SFTP_STRING', 2);
/**
* Reads data from callback:
* function callback($length) returns string to proceed, null for EOF
*/
define('NET_SFTP_CALLBACK', 16);
/** /**
* Resumes an upload * Resumes an upload
*/ */
@ -1759,6 +1764,10 @@ class Net_SFTP extends Net_SSH2
* *
* If $data is a resource then it'll be used as a resource instead. * If $data is a resource then it'll be used as a resource instead.
* *
*
* Setting $mode to self::SOURCE_CALLBACK will use $data as callback function, which gets only one parameter -- number
* of bytes to return, and returns a string if there is some data or null if there is no more data
*
* 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.
* *
@ -1837,7 +1846,15 @@ 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
$callback = false;
switch (true) { switch (true) {
case $mode & NET_SFTP_CALLBACK;
if (!is_callable($data)) {
user_error("\$data should be is_callable if you set NET_SFTP_CALLBACK flag");
}
$callback = $data;
// do nothing
break;
case is_resource($data): case is_resource($data):
$mode = $mode & ~NET_SFTP_LOCAL_FILE; $mode = $mode & ~NET_SFTP_LOCAL_FILE;
$fp = $data; $fp = $data;
@ -1864,6 +1881,8 @@ class Net_SFTP extends Net_SSH2
} else { } else {
fseek($fp, $offset); fseek($fp, $offset);
} }
} elseif ($callback) {
$size = 0;
} else { } else {
$size = strlen($data); $size = strlen($data);
} }
@ -1875,8 +1894,15 @@ class Net_SFTP extends Net_SSH2
// make the SFTP packet be exactly 4096 bytes by including the bytes in the NET_SFTP_WRITE packets "header" // 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; $sftp_packet_size-= strlen($handle) + 25;
$i = 0; $i = 0;
while ($sent < $size) { while ($callback || ($sent < $size)) {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_size); if ($callback) {
$temp = call_user_func($callback, $sftp_packet_size);
if (is_null($temp)) {
break;
}
} else {
$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)) {

View File

@ -11,6 +11,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
static protected $scratchDir; static protected $scratchDir;
static protected $exampleData; static protected $exampleData;
static protected $exampleDataLength; static protected $exampleDataLength;
static protected $buffer;
static public function setUpBeforeClass() static public function setUpBeforeClass()
{ {
@ -132,6 +133,41 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
return $sftp; return $sftp;
} }
static function callback($length)
{
$r = substr(self::$buffer, 0, $length);
self::$buffer = substr(self::$buffer, $length);
if (strlen($r)) return $r;
return null;
}
/**
* @depends testStatOnDir
*/
public function testPutSizeGetFileCallback($sftp)
{
self::$buffer = self::$exampleData;
$this->assertTrue(
$sftp->put('file1.txt', array(__CLASS__, 'callback'), NET_SFTP_CALLBACK),
'Failed asserting that example data could be successfully put().'
);
$this->assertSame(
self::$exampleDataLength,
$sftp->size('file1.txt'),
'Failed asserting that put example data has the expected length'
);
$this->assertSame(
self::$exampleData,
$sftp->get('file1.txt'),
'Failed asserting that get() returns expected example data.'
);
return $sftp;
}
/** /**
* @depends testStatOnDir * @depends testStatOnDir
*/ */