mirror of
https://codeberg.org/icewind/SMB.git
synced 2026-06-03 17:24:07 +02:00
use a persistent connection instead of running a new smbclient for each command
This commit is contained in:
parent
e324e70050
commit
e76f9974d1
10 changed files with 104 additions and 52 deletions
|
|
@ -9,18 +9,16 @@
|
||||||
namespace SMB\Command;
|
namespace SMB\Command;
|
||||||
|
|
||||||
abstract class Command {
|
abstract class Command {
|
||||||
const CLIENT = 'smbclient';
|
/**
|
||||||
|
* @var \SMB\Share $connection
|
||||||
|
*/
|
||||||
|
protected $share;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \SMB\Connection $connection
|
* @param \SMB\Share $connection
|
||||||
*/
|
*/
|
||||||
protected $connection;
|
public function __construct($share) {
|
||||||
|
$this->share = $share;
|
||||||
/**
|
|
||||||
* @param \SMB\Connection $connection
|
|
||||||
*/
|
|
||||||
public function __construct($connection) {
|
|
||||||
$this->connection = $connection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -28,9 +26,8 @@ abstract class Command {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function execute($command) {
|
protected function execute($command) {
|
||||||
$auth = $this->escape($this->connection->getAuthString());
|
$this->share->write($command . PHP_EOL);
|
||||||
$command = self::CLIENT . ' -N -U ' . $auth . ' ' . $command . ' 2> /dev/null';
|
$output = $this->share->read();
|
||||||
exec($command, $output);
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,4 +55,12 @@ abstract class Command {
|
||||||
$path = str_replace('/', '\\', $path);
|
$path = str_replace('/', '\\', $path);
|
||||||
return '"' . trim(escapeshellarg($path), "'") . '"';
|
return '"' . trim(escapeshellarg($path), "'") . '"';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $path
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function escapeLocalPath($path) {
|
||||||
|
return '"' . trim(escapeshellarg($path), "'") . '"';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,15 +8,17 @@
|
||||||
|
|
||||||
namespace SMB\Command;
|
namespace SMB\Command;
|
||||||
|
|
||||||
class Dir extends Simple {
|
class Dir extends Command {
|
||||||
public function __construct($connection) {
|
public function __construct($connection) {
|
||||||
parent::__construct($connection);
|
parent::__construct($connection);
|
||||||
$this->command = 'cd';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$arguments['postfix']=' ; dir';
|
$path = $this->escapePath($arguments['path']);
|
||||||
return parent::run($arguments);
|
$this->execute('cd ' . $path);
|
||||||
|
$output = $this->execute('dir');
|
||||||
|
$this->execute('cd /');
|
||||||
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,7 @@ abstract class Double extends Command {
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$path1 = $this->escapePath($arguments['path1']);
|
$path1 = $this->escapePath($arguments['path1']);
|
||||||
$path2 = $this->escapePath($arguments['path2']);
|
$path2 = $this->escapePath($arguments['path2']);
|
||||||
$share = $arguments['share'];
|
$cmd = $this->command . ' ' . $path1 . ' ' . $path2;
|
||||||
$postFix = (isset($arguments['postfix'])) ? $arguments['postfix'] : '';
|
|
||||||
$cmd = $this->escape('//' . $this->connection->getHost() . '/' . $share);
|
|
||||||
$cmd .= " -c '" . $this->command . ' ' . $path1 . ' ' . $path2 . $postFix . "'";
|
|
||||||
$output = $this->execute($cmd);
|
$output = $this->execute($cmd);
|
||||||
return $this->parseOutput($output);
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,10 @@
|
||||||
namespace SMB\Command;
|
namespace SMB\Command;
|
||||||
|
|
||||||
class Get extends Command {
|
class Get extends Command {
|
||||||
public function __construct($connection) {
|
|
||||||
parent::__construct($connection);
|
|
||||||
$this->command = 'get';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$path1 = $this->escapePath($arguments['path1']);
|
$path1 = $this->escapePath($arguments['path1']);
|
||||||
$path2 = $this->escape($arguments['path2']); //seccond path is local, needs different escaping
|
$path2 = $this->escapeLocalPath($arguments['path2']); //second path is local, needs different escaping
|
||||||
$share = $arguments['share'];
|
$output = $this->execute('get ' . $path1 . ' ' . $path2);
|
||||||
$postFix = (isset($arguments['postfix'])) ? $arguments['postfix'] : '';
|
|
||||||
$cmd = $this->escape('//' . $this->connection->getHost() . '/' . $share);
|
|
||||||
$cmd .= " -c '" . $this->command . ' ' . $path1 . ' ' . $path2 . $postFix . "'";
|
|
||||||
$output = $this->execute($cmd);
|
|
||||||
return $this->parseOutput($output);
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ namespace SMB\Command;
|
||||||
|
|
||||||
class ListShares extends Command {
|
class ListShares extends Command {
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$output = $this->execute('-gL ' . $this->escape($this->connection->getHost()));
|
$auth = $this->escape($this->connection->getAuthString());
|
||||||
|
$command = self::CLIENT . ' -N -U ' . $auth . ' ' . '-gL ' . $this->escape($this->connection->getHost()) . ' 2> /dev/null';
|
||||||
|
exec($command, $output);
|
||||||
return $this->parseOutput($output);
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,10 @@
|
||||||
namespace SMB\Command;
|
namespace SMB\Command;
|
||||||
|
|
||||||
class Put extends Command {
|
class Put extends Command {
|
||||||
public function __construct($connection) {
|
|
||||||
parent::__construct($connection);
|
|
||||||
$this->command = 'put';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$path1 = $this->escape($arguments['path1']); //first path is local, needs different escaping
|
$path1 = $this->escapeLocalPath($arguments['path1']); //first path is local, needs different escaping
|
||||||
$path2 = $this->escapePath($arguments['path2']);
|
$path2 = $this->escapePath($arguments['path2']);
|
||||||
$share = $arguments['share'];
|
$output = $this->execute('put ' . $path1 . ' ' . $path2);
|
||||||
$postFix = (isset($arguments['postfix'])) ? $arguments['postfix'] : '';
|
|
||||||
$cmd = $this->escape('//' . $this->connection->getHost() . '/' . $share);
|
|
||||||
$cmd .= " -c '" . $this->command . ' ' . $path1 . ' ' . $path2 . $postFix . "'";
|
|
||||||
$output = $this->execute($cmd);
|
|
||||||
return $this->parseOutput($output);
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,7 @@ abstract class Simple extends Command {
|
||||||
|
|
||||||
public function run($arguments) {
|
public function run($arguments) {
|
||||||
$path = $this->escapePath($arguments['path']);
|
$path = $this->escapePath($arguments['path']);
|
||||||
$share = $arguments['share'];
|
$cmd = $this->command . ' ' . $path;
|
||||||
$postFix = (isset($arguments['postfix'])) ? $arguments['postfix'] : '';
|
|
||||||
$cmd = $this->escape('//' . $this->connection->getHost() . '/' . $share);
|
|
||||||
$cmd .= " -c '" . $this->command . ' ' . $path . $postFix . "'";
|
|
||||||
$output = $this->execute($cmd);
|
$output = $this->execute($cmd);
|
||||||
return $this->parseOutput($output);
|
return $this->parseOutput($output);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
namespace SMB;
|
namespace SMB;
|
||||||
|
|
||||||
class Connection {
|
class Connection {
|
||||||
|
const CLIENT = 'smbclient';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string $host
|
* @var string $host
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,6 @@ class AlreadyExistsException extends \Exception {
|
||||||
|
|
||||||
class NotEmptyException extends \Exception {
|
class NotEmptyException extends \Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ConnectionError extends \Exception {
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,19 @@ class Share {
|
||||||
*/
|
*/
|
||||||
private $connection;
|
private $connection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource $process
|
||||||
|
*/
|
||||||
|
private $process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var resource[] $pipes
|
||||||
|
*
|
||||||
|
* $pipes[0] holds STDIN for smbclient
|
||||||
|
* $pipes[1] holds STDOUT for smbclient
|
||||||
|
*/
|
||||||
|
private $pipes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string $name
|
* @var string $name
|
||||||
*/
|
*/
|
||||||
|
|
@ -26,6 +39,27 @@ class Share {
|
||||||
public function __construct($connection, $name) {
|
public function __construct($connection, $name) {
|
||||||
$this->connection = $connection;
|
$this->connection = $connection;
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
|
|
||||||
|
$descriptorSpec = array(
|
||||||
|
0 => array("pipe", "r"),
|
||||||
|
1 => array("pipe", "w"),
|
||||||
|
// 1 => array("file", "/tmp/smbout", 'a'),
|
||||||
|
2 => array("file", "/tmp/smberror", "a")
|
||||||
|
);
|
||||||
|
|
||||||
|
$command = Connection::CLIENT . ' -N -U ' . $this->connection->getAuthString() .
|
||||||
|
' //' . $this->connection->getHost() . '/' . $this->name;
|
||||||
|
$this->process = proc_open($command, $descriptorSpec, $this->pipes, null, array(
|
||||||
|
'CLI_FORCE_INTERACTIVE' => 'y' // Needed or the prompt isn't displayed!!
|
||||||
|
));
|
||||||
|
if (!is_resource($this->process)) {
|
||||||
|
throw new ConnectionError();
|
||||||
|
}
|
||||||
|
// stream_set_blocking($this->pipes[1], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct() {
|
||||||
|
proc_close($this->process);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -35,7 +69,7 @@ class Share {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function dir($path) {
|
public function dir($path) {
|
||||||
return (new Command\Dir($this->connection))->run(array('path' => $path, 'share' => $this->name));
|
return (new Command\Dir($this))->run(array('path' => $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -45,7 +79,7 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function mkdir($path) {
|
public function mkdir($path) {
|
||||||
return (new Command\Mkdir($this->connection))->run(array('path' => $path, 'share' => $this->name));
|
return (new Command\Mkdir($this))->run(array('path' => $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -55,7 +89,7 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function rmdir($path) {
|
public function rmdir($path) {
|
||||||
return (new Command\Rmdir($this->connection))->run(array('path' => $path, 'share' => $this->name));
|
return (new Command\Rmdir($this))->run(array('path' => $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -65,7 +99,7 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function del($path) {
|
public function del($path) {
|
||||||
return (new Command\Del($this->connection))->run(array('path' => $path, 'share' => $this->name));
|
return (new Command\Del($this))->run(array('path' => $path));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -76,7 +110,7 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function rename($from, $to) {
|
public function rename($from, $to) {
|
||||||
return (new Command\Rename($this->connection))->run(array('path1' => $from, 'path2' => $to, 'share' => $this->name));
|
return (new Command\Rename($this))->run(array('path1' => $from, 'path2' => $to));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,7 +121,7 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function put($source, $target) {
|
public function put($source, $target) {
|
||||||
return (new Command\Put($this->connection))->run(array('path1' => $source, 'path2' => $target, 'share' => $this->name));
|
return (new Command\Put($this))->run(array('path1' => $source, 'path2' => $target));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -98,6 +132,34 @@ class Share {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function get($source, $target) {
|
public function get($source, $target) {
|
||||||
return (new Command\Get($this->connection))->run(array('path1' => $source, 'path2' => $target, 'share' => $this->name));
|
return (new Command\Get($this))->run(array('path1' => $source, 'path2' => $target));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send input to smbclient
|
||||||
|
*
|
||||||
|
* @param string $input
|
||||||
|
*/
|
||||||
|
public function write($input) {
|
||||||
|
fwrite($this->pipes[0], $input);
|
||||||
|
fwrite($this->pipes[0], PHP_EOL); //make sure we have a recognizable delimiter
|
||||||
|
fflush($this->pipes[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get all unprocessed output from smbclient
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function read() {
|
||||||
|
fgets($this->pipes[1]);//first line is promt
|
||||||
|
$output = array();
|
||||||
|
$line = fgets($this->pipes[1]);
|
||||||
|
while (substr($line, 0, 4) !== 'smb:') { //next prompt functions as delimiter
|
||||||
|
$output[] .= $line;
|
||||||
|
$line = fgets($this->pipes[1]);
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
// return explode(PHP_EOL, stream_get_contents($this->pipes[1]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue