Connection reuse refactoring to rid of globals

This commit is contained in:
Dmitry Balabka 2015-08-27 12:45:28 +03:00
parent 815fd47162
commit 70dd67c4d9
5 changed files with 87 additions and 5 deletions

View File

@ -19,6 +19,7 @@ namespace phpseclib\Net\SFTP;
use phpseclib\Crypt\RSA; use phpseclib\Crypt\RSA;
use phpseclib\Net\SFTP; use phpseclib\Net\SFTP;
use phpseclib\Net\SSH2;
/** /**
* SFTP Stream Wrapper * SFTP Stream Wrapper
@ -166,13 +167,12 @@ class Stream
} }
} }
if ($host[0] == '$') { if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
$host = substr($host, 1); $host = SSH2::getConnectionByResourceId($host);
global $$host; if ($host === false) {
if (($$host instanceof SFTP) === false) {
return false; return false;
} }
$this->sftp = $$host; $this->sftp = $host;
} else { } else {
if (isset($this->context)) { if (isset($this->context)) {
$context = stream_context_get_options($this->context); $context = stream_context_get_options($this->context);

View File

@ -866,6 +866,14 @@ class SSH2
*/ */
var $agent; var $agent;
/**
* Connection storage to replicates ssh2 extension functionality:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
*
* @var SSH2[]
*/
static $connections;
/** /**
* Default Constructor. * Default Constructor.
* *
@ -959,6 +967,8 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY') 31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
); );
self::$connections[$this->getResourceId()] = $this;
if (is_resource($host)) { if (is_resource($host)) {
$this->fsock = $host; $this->fsock = $host;
return; return;
@ -2836,6 +2846,7 @@ class SSH2
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) { if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file); fclose($this->realtime_log_file);
} }
unset(self::$connections[$this->getResourceId()]);
} }
/** /**
@ -4152,4 +4163,47 @@ class SSH2
$this->windowColumns = $columns; $this->windowColumns = $columns;
$this->windowRows = $rows; $this->windowRows = $rows;
} }
/**
* @return string
*/
function __toString()
{
return $this->getResourceId();
}
/**
* We use {} because that symbols should not be in URL according to
* {@link http://tools.ietf.org/html/rfc3986#section-2 RFC}.
* It will safe us from any conflicts, because otherwise regexp will
* match all alphanumeric domains.
*
* @return string
*/
function getResourceId()
{
return '{' . spl_object_hash($this) . '}';
}
/**
* Return existing connection
*
* @param string $id
*
* @return bool|SSH2 will return false if no such connection
*/
static function getConnectionByResourceId($id)
{
return isset(self::$connections[$id]) ? self::$connections[$id] : false;
}
/**
* Return all excising connections
*
* @return SSH2[]
*/
static function getConnections()
{
return self::$connections;
}
} }

View File

@ -27,6 +27,19 @@ class Functional_Net_SFTPStreamTest extends Functional_Net_SFTPTestCase
$this->assertSame(0, $this->sftp->size('fooo.txt')); $this->assertSame(0, $this->sftp->size('fooo.txt'));
} }
/**
* Tests connection reuse functionality same as ssh2 extension:
* {@link http://php.net/manual/en/wrappers.ssh2.php#refsect1-wrappers.ssh2-examples}
*/
public function testConnectionReuse()
{
$originalConnectionsCount = count(\phpseclib\Net\SSH2::getConnections());
$session = $this->sftp;
$dirs = scandir("sftp://$session/");
$this->assertCount($originalConnectionsCount, \phpseclib\Net\SSH2::getConnections());
$this->assertEquals(array('.', '..'), array_slice($dirs, 0, 2));
}
protected function buildUrl($suffix) protected function buildUrl($suffix)
{ {
return sprintf( return sprintf(

View File

@ -13,6 +13,9 @@ use phpseclib\Net\SFTP;
*/ */
abstract class Functional_Net_SFTPTestCase extends PhpseclibFunctionalTestCase abstract class Functional_Net_SFTPTestCase extends PhpseclibFunctionalTestCase
{ {
/**
* @var SFTP
*/
protected $sftp; protected $sftp;
protected $scratchDir; protected $scratchDir;

View File

@ -110,6 +110,18 @@ class Unit_Net_SSH2Test extends PhpseclibTestCase
$this->assertFalse($ssh->isQuietModeEnabled()); $this->assertFalse($ssh->isQuietModeEnabled());
} }
public function testGetConnectionByResourceId()
{
$ssh = new \phpseclib\Net\SSH2('localhost');
$this->assertSame($ssh, \phpseclib\Net\SSH2::getConnectionByResourceId($ssh->getResourceId()));
}
public function testGetResourceId()
{
$ssh = new \phpseclib\Net\SSH2('localhost');
$this->assertSame('{' . spl_object_hash($ssh) . '}', $ssh->getResourceId());
}
/** /**
* @return \phpseclib\Net\SSH2 * @return \phpseclib\Net\SSH2
*/ */