Merge remote-tracking branch 'audrey/sftp-put-callback'

This commit is contained in:
terrafrost 2015-04-16 07:45:51 -05:00
commit 1b22d523dc
2 changed files with 62 additions and 2 deletions

View File

@ -72,6 +72,11 @@ class SFTP extends SSH2
*/ */
// 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
const SOURCE_STRING = 2; const SOURCE_STRING = 2;
/**
* Reads data from callback:
* function callback($length) returns string to proceed, null for EOF
*/
const SOURCE_CALLBACK = 16;
/** /**
* Resumes an upload * Resumes an upload
*/ */
@ -1718,6 +1723,8 @@ class SFTP extends 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.
* *
* 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
*
* 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.
* *
* 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
@ -1798,7 +1805,15 @@ class SFTP extends 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 & self::SOURCE_CALLBACK;
if (!is_callable($data)) {
user_error("\$data should be is_callable() if you specify SOURCE_CALLBACK flag");
}
$callback = $data;
// do nothing
break;
case is_resource($data): case is_resource($data):
$mode = $mode & ~self::SOURCE_LOCAL_FILE; $mode = $mode & ~self::SOURCE_LOCAL_FILE;
$fp = $data; $fp = $data;
@ -1825,6 +1840,8 @@ class SFTP extends SSH2
} else { } else {
fseek($fp, $offset); fseek($fp, $offset);
} }
} elseif ($callback) {
$size = 0;
} else { } else {
$size = strlen($data); $size = strlen($data);
} }
@ -1836,8 +1853,15 @@ class SFTP extends 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) {
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); $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

@ -13,6 +13,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()
{ {
@ -159,6 +160,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'), $sftp::SOURCE_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 testPutSizeGetFile * @depends testPutSizeGetFile
*/ */