diff --git a/src/Client.php b/src/Client.php index fecdf83..cda9a1e 100644 --- a/src/Client.php +++ b/src/Client.php @@ -4,7 +4,14 @@ namespace RouterOS; use RouterOS\Exceptions\Exception; use RouterOS\Interfaces\ClientInterface; - +use RouterOS\Interfaces\ConfigInterface; +use RouterOS\Interfaces\QueryInterface; + +/** + * Class Client + * @package RouterOS + * @since 0.1 + */ class Client implements Interfaces\ClientInterface { /** @@ -33,15 +40,26 @@ class Client implements Interfaces\ClientInterface /** * Client constructor. - * @param Config $config + * @param ConfigInterface $config */ - public function __construct(Config $config) + public function __construct(ConfigInterface $config) { $this->_config = $config; $this->connect(); } /** + * Get some parameter from config + * + * @param string $parameter + * @return mixed + */ + private function config(string $parameter) + { + return $this->_config->get($parameter); + } + + /** * Convert ordinary string to hex string * * @param string $string @@ -49,7 +67,7 @@ class Client implements Interfaces\ClientInterface */ private function encodeLength(string $string): string { - // Yeah, that's insane, but was more ugly, so you need read this post if you interesting a details: + // Yeah, that's insane, but was more ugly, you need read this post if you interesting a details: // https://wiki.mikrotik.com/wiki/Manual:API#API_words switch (true) { case ($string < 0x80): @@ -88,10 +106,10 @@ class Client implements Interfaces\ClientInterface /** * Send write query to RouterOS (with or without tag) * - * @param Query $query + * @param QueryInterface $query * @return ClientInterface */ - public function write(Query $query): ClientInterface + public function write(QueryInterface $query): ClientInterface { // Send commands via loop to router foreach ($query->getQuery() as $command) { @@ -206,7 +224,7 @@ class Client implements Interfaces\ClientInterface } } elseif ($x !== '!done') { $matches = []; - if (preg_match_all('/[^=]+/i', $x, $matches)) { + if (preg_match_all('/[^=]+/', $x, $matches)) { if ($matches[0][0] === 'ret') { $single = $matches[0][1]; } @@ -229,21 +247,28 @@ class Client implements Interfaces\ClientInterface */ private function login(): bool { - // For the first we need get hash with salt - $query = new Query('/login'); - $response = $this->write($query)->read(); - - // Now need use this hash for authorization - $query = (new Query('/login')) - ->add('=name=' . $this->_config->user) - ->add('=response=00' . md5(\chr(0) . $this->_config->pass . pack('H*', $response[0]))); + // If legacy login scheme is enabled + if ($this->config('legacy')) { + // For the first we need get hash with salt + $query = new Query('/login'); + $response = $this->write($query)->read(); + + // Now need use this hash for authorization + $query = (new Query('/login')) + ->add('=name=' . $this->config('user')) + ->add('=response=00' . md5(\chr(0) . $this->config('pass') . pack('H*', $response[0]))); + } else { + // Just login with our credentials + $query = (new Query('/login')) + ->add('=name=' . $this->config('user')) + ->add('=password=' . $this->config('pass')); + } // Execute query and get response $response = $this->write($query)->read(false); // Return true if we have only one line from server and this line is !done return isset($response[0]) && $response[0] === '!done'; - } /** @@ -254,7 +279,7 @@ class Client implements Interfaces\ClientInterface public function connect(): bool { // Few attempts in loop - for ($attempt = 1; $attempt <= $this->_config->attempts; $attempt++) { + for ($attempt = 1; $attempt <= $this->config('attempts'); $attempt++) { // Initiate socket session $this->openSocket(); @@ -272,7 +297,7 @@ class Client implements Interfaces\ClientInterface } // Sleep some time between tries - sleep($this->_config->delay); + sleep($this->config('delay')); } // Return status of connection @@ -317,24 +342,30 @@ class Client implements Interfaces\ClientInterface $socket = false; // Default: Context for ssl - $context = stream_context_create(['ssl' => ['ciphers' => 'ADH:ALL', 'verify_peer' => false, 'verify_peer_name' => false]]); + $context = stream_context_create([ + 'ssl' => [ + 'ciphers' => 'ADH:ALL', + 'verify_peer' => false, + 'verify_peer_name' => false + ] + ]); // Default: Proto tcp:// but for ssl we need ssl:// - $proto = $this->_config->ssl ? 'ssl://' : ''; + $proto = $this->config('ssl') ? 'ssl://' : ''; try { // Initiate socket client $socket = stream_socket_client( - $proto . $this->_config->host . ':' . $this->_config->port, + $proto . $this->config('host') . ':' . $this->config('port'), $this->_socket_err_num, $this->_socket_err_str, - $this->_config->timeout, + $this->config('timeout'), STREAM_CLIENT_CONNECT, $context ); // Throw error is socket is not initiated if (false === $socket) { - throw new Exception('stream_socket_client() failed: reason: ' . socket_strerror(socket_last_error())); + throw new Exception('stream_socket_client() failed: code: ' . $this->_socket_err_num . ' reason:' . $this->_socket_err_str); } } catch (Exception $e) { @@ -355,5 +386,4 @@ class Client implements Interfaces\ClientInterface fclose($this->_socket); return true; } - } diff --git a/src/Interfaces/ClientInterface.php b/src/Interfaces/ClientInterface.php index 0fb4c5b..84bedad 100644 --- a/src/Interfaces/ClientInterface.php +++ b/src/Interfaces/ClientInterface.php @@ -2,11 +2,19 @@ namespace RouterOS\Interfaces; -use RouterOS\Query; - +/** + * Interface ClientInterface + * @package RouterOS\Interfaces + * @since 0.1 + */ interface ClientInterface { /** + * By default legacy login on RouterOS pre-6.43 is not supported + */ + const LEGACY = false; + + /** * Default port number */ const PORT = 8728; @@ -32,7 +40,7 @@ interface ClientInterface const ATTEMPTS = 10; /** - * Delay between attempts + * Delay between attempts in seconds */ const ATTEMPTS_DELAY = 1; @@ -61,9 +69,8 @@ interface ClientInterface /** * Send write query to RouterOS (with or without tag) * - * @param Query $query + * @param QueryInterface $query * @return ClientInterface */ - public function write(Query $query): ClientInterface; - + public function write(QueryInterface $query): ClientInterface; }