2014-08-26 20:46:07 +04:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Copyright (c) 2014 Robin Appelman <icewind@owncloud.com>
|
|
|
|
* This file is licensed under the Licensed under the MIT license:
|
|
|
|
* http://opensource.org/licenses/MIT
|
|
|
|
*/
|
|
|
|
|
|
|
|
namespace Icewind\SMB;
|
|
|
|
|
|
|
|
use Icewind\SMB\Exception\AuthenticationException;
|
2015-08-17 17:31:29 +03:00
|
|
|
use Icewind\SMB\Exception\ConnectException;
|
2014-08-26 20:46:07 +04:00
|
|
|
use Icewind\SMB\Exception\ConnectionException;
|
|
|
|
use Icewind\SMB\Exception\InvalidHostException;
|
2015-08-17 17:31:29 +03:00
|
|
|
use Icewind\SMB\Exception\NoLoginServerException;
|
2014-08-26 20:46:07 +04:00
|
|
|
|
|
|
|
class Connection extends RawConnection {
|
|
|
|
const DELIMITER = 'smb:';
|
2016-04-26 16:43:30 +03:00
|
|
|
const DELIMITER_LENGTH = 4;
|
2014-08-26 20:46:07 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* send input to smbclient
|
|
|
|
*
|
|
|
|
* @param string $input
|
|
|
|
*/
|
|
|
|
public function write($input) {
|
|
|
|
parent::write($input . PHP_EOL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* get all unprocessed output from smbclient until the next prompt
|
|
|
|
*
|
2016-04-26 16:43:30 +03:00
|
|
|
* @param callable $callback (optional) callback to call for every line read
|
2014-08-26 20:46:07 +04:00
|
|
|
* @return string
|
2015-08-17 17:31:29 +03:00
|
|
|
* @throws AuthenticationException
|
|
|
|
* @throws ConnectException
|
|
|
|
* @throws ConnectionException
|
|
|
|
* @throws InvalidHostException
|
|
|
|
* @throws NoLoginServerException
|
2014-08-26 20:46:07 +04:00
|
|
|
*/
|
2016-04-26 16:43:30 +03:00
|
|
|
public function read(callable $callback = null) {
|
2014-08-26 20:46:07 +04:00
|
|
|
if (!$this->isValid()) {
|
2015-08-17 17:31:29 +03:00
|
|
|
throw new ConnectionException('Connection not valid');
|
2014-08-26 20:46:07 +04:00
|
|
|
}
|
2016-02-09 19:09:30 +03:00
|
|
|
$promptLine = $this->readLine(); //first line is prompt
|
|
|
|
$this->checkConnectionError($promptLine);
|
2014-08-26 20:46:07 +04:00
|
|
|
|
|
|
|
$output = array();
|
|
|
|
$line = $this->readLine();
|
2015-08-17 17:31:29 +03:00
|
|
|
if ($line === false) {
|
2016-04-26 16:43:30 +03:00
|
|
|
$this->unknownError($promptLine);
|
|
|
|
}
|
|
|
|
while (!$this->isPrompt($line)) { //next prompt functions as delimiter
|
|
|
|
if (is_callable($callback)) {
|
|
|
|
$result = $callback($line);
|
|
|
|
if ($result === false) { // allow the callback to close the connection for infinite running commands
|
|
|
|
$this->close(true);
|
2016-02-09 19:09:30 +03:00
|
|
|
}
|
2016-04-26 16:43:30 +03:00
|
|
|
} else {
|
|
|
|
$output[] .= $line;
|
2016-02-09 19:09:30 +03:00
|
|
|
}
|
2014-08-26 20:46:07 +04:00
|
|
|
$line = $this->readLine();
|
|
|
|
}
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
2016-04-26 16:43:30 +03:00
|
|
|
/**
|
|
|
|
* Check
|
|
|
|
*
|
|
|
|
* @param $line
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
private function isPrompt($line) {
|
|
|
|
return mb_substr($line, 0, self::DELIMITER_LENGTH) === self::DELIMITER || $line === false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param string $promptLine (optional) prompt line that might contain some info about the error
|
|
|
|
* @throws ConnectException
|
|
|
|
*/
|
|
|
|
private function unknownError($promptLine = '') {
|
|
|
|
if ($promptLine) { //maybe we have some error we missed on the previous line
|
|
|
|
throw new ConnectException('Unknown error (' . $promptLine . ')');
|
|
|
|
} else {
|
|
|
|
$error = $this->readError(); // maybe something on stderr
|
|
|
|
if ($error) {
|
|
|
|
throw new ConnectException('Unknown error (' . $error . ')');
|
|
|
|
} else {
|
|
|
|
throw new ConnectException('Unknown error');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-26 20:46:07 +04:00
|
|
|
/**
|
|
|
|
* check if the first line holds a connection failure
|
|
|
|
*
|
|
|
|
* @param $line
|
|
|
|
* @throws AuthenticationException
|
|
|
|
* @throws InvalidHostException
|
2015-08-17 17:31:29 +03:00
|
|
|
* @throws NoLoginServerException
|
2014-08-26 20:46:07 +04:00
|
|
|
*/
|
|
|
|
private function checkConnectionError($line) {
|
|
|
|
$line = rtrim($line, ')');
|
|
|
|
if (substr($line, -23) === ErrorCodes::LogonFailure) {
|
2015-08-17 17:31:29 +03:00
|
|
|
throw new AuthenticationException('Invalid login');
|
2014-08-26 20:46:07 +04:00
|
|
|
}
|
|
|
|
if (substr($line, -26) === ErrorCodes::BadHostName) {
|
2015-08-17 17:31:29 +03:00
|
|
|
throw new InvalidHostException('Invalid hostname');
|
2014-08-26 20:46:07 +04:00
|
|
|
}
|
|
|
|
if (substr($line, -22) === ErrorCodes::Unsuccessful) {
|
2015-08-17 17:31:29 +03:00
|
|
|
throw new InvalidHostException('Connection unsuccessful');
|
2014-08-26 20:46:07 +04:00
|
|
|
}
|
|
|
|
if (substr($line, -28) === ErrorCodes::ConnectionRefused) {
|
2015-08-17 17:31:29 +03:00
|
|
|
throw new InvalidHostException('Connection refused');
|
|
|
|
}
|
|
|
|
if (substr($line, -26) === ErrorCodes::NoLogonServers) {
|
|
|
|
throw new NoLoginServerException('No login server');
|
2014-08-26 20:46:07 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function close($terminate = true) {
|
|
|
|
if (is_resource($this->getInputStream())) {
|
|
|
|
$this->write('close' . PHP_EOL);
|
|
|
|
}
|
|
|
|
parent::close($terminate);
|
|
|
|
}
|
|
|
|
}
|