Merge pull request #787 from torinaki/remove-global-and-earn-25$

Connection reuse refactoring to rid of globals

* torinaki/remove-global-and-earn-25$:
  Connection reuse refactoring to rid of globals
This commit is contained in:
Andreas Fischer 2015-09-02 15:04:52 +02:00
commit 6433a10fa5
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\Net\SFTP;
use phpseclib\Net\SSH2;
/**
* SFTP Stream Wrapper
@ -166,13 +167,12 @@ class Stream
}
}
if ($host[0] == '$') {
$host = substr($host, 1);
global $$host;
if (($$host instanceof SFTP) === false) {
if (preg_match('/^{[a-z0-9]+}$/i', $host)) {
$host = SSH2::getConnectionByResourceId($host);
if ($host === false) {
return false;
}
$this->sftp = $$host;
$this->sftp = $host;
} else {
if (isset($this->context)) {
$context = stream_context_get_options($this->context);

View File

@ -867,6 +867,14 @@ class SSH2
*/
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.
*
@ -960,6 +968,8 @@ class SSH2
31 => 'NET_SSH2_MSG_KEX_ECDH_REPLY')
);
self::$connections[$this->getResourceId()] = $this;
if (is_resource($host)) {
$this->fsock = $host;
return;
@ -2829,6 +2839,7 @@ class SSH2
if (isset($this->realtime_log_file) && is_resource($this->realtime_log_file)) {
fclose($this->realtime_log_file);
}
unset(self::$connections[$this->getResourceId()]);
}
/**
@ -4141,4 +4152,47 @@ class SSH2
$this->windowColumns = $columns;
$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'));
}
/**
* 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)
{
return sprintf(

View File

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

View File

@ -110,6 +110,18 @@ class Unit_Net_SSH2Test extends PhpseclibTestCase
$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
*/