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

This commit is contained in:
terrafrost 2015-04-16 07:45:39 -05:00
commit 36ef1c4084
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
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
*/
@ -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
* 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.
*
* 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
$callback = false;
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):
$mode = $mode & ~self::SOURCE_LOCAL_FILE;
$fp = $data;
@ -1825,6 +1840,8 @@ class SFTP extends SSH2
} else {
fseek($fp, $offset);
}
} elseif ($callback) {
$size = 0;
} else {
$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"
$sftp_packet_size-= strlen($handle) + 25;
$i = 0;
while ($sent < $size) {
$temp = isset($fp) ? fread($fp, $sftp_packet_size) : substr($data, $sent, $sftp_packet_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);
}
$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)) {

View File

@ -13,6 +13,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
static protected $scratchDir;
static protected $exampleData;
static protected $exampleDataLength;
static protected $buffer;
static public function setUpBeforeClass()
{
@ -159,6 +160,41 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
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
*/