mirror of
https://github.com/danog/phpseclib.git
synced 2024-11-27 04:46:26 +01:00
support for callback function for SFTP::put function - in order to pipe data directly to remote server without putting it into file or keeping in memory. This can be useful particularly for dumping big databases directly to remote server.
This commit is contained in:
parent
c0370ee91d
commit
16430d4d2e
@ -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
|
||||
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
|
||||
*/
|
||||
@ -1759,6 +1764,10 @@ class Net_SFTP extends Net_SSH2
|
||||
*
|
||||
* 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
|
||||
* care of that, yourself.
|
||||
*
|
||||
@ -1836,7 +1845,15 @@ class Net_SFTP extends Net_SSH2
|
||||
}
|
||||
|
||||
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
|
||||
$callback = false;
|
||||
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):
|
||||
$mode = $mode & ~NET_SFTP_LOCAL_FILE;
|
||||
$fp = $data;
|
||||
@ -1863,6 +1880,8 @@ class Net_SFTP extends Net_SSH2
|
||||
} else {
|
||||
fseek($fp, $offset);
|
||||
}
|
||||
} elseif ($callback) {
|
||||
$size = 0;
|
||||
} else {
|
||||
$size = strlen($data);
|
||||
}
|
||||
@ -1874,8 +1893,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"
|
||||
$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)) {
|
||||
|
@ -11,6 +11,7 @@ class Functional_Net_SFTPUserStoryTest extends PhpseclibFunctionalTestCase
|
||||
static protected $scratchDir;
|
||||
static protected $exampleData;
|
||||
static protected $exampleDataLength;
|
||||
static protected $buffer;
|
||||
|
||||
static public function setUpBeforeClass()
|
||||
{
|
||||
@ -132,6 +133,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'), 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
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user