PHP APi Connection

Hi Guys,

I am using the Mikrotik API PHP (RouterOS PHP API class v1.6) to connect and read the queue types & its Rates. However, the API connect function is return false.
But works fine with WINBOX using the same login credentials.
I can able to see the connection attempt as ‘login failure for user xxxx from xxx.xxx.xxx.xx via api’ at WINBOX logs.
Enabled api with port on ‘IP services list’.

Sample code:

require(‘routeros_api.class.php’);
$API = new RouterosAPI();

if ($API->connect(‘IP’, ‘USERNAME’, ‘PASSWORD’)) {
die(‘connnect’);
}

When i run the code, it says 'invalid user name or password - Unable to connect to RouterOS ’ . But the same login credentials works fine with WINBOX

Any thoughts?

Thanks
WINBOX ERROR LOG.png
PHP API RESULT.png

https://wiki.mikrotik.com/wiki/Manual:API#Initial_login

see notes in login process post-v6.43

This is my connection function code from routeros_api.class.php

function connect($ip, $login, $password)
{
for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
$this->connected = false;
$this->debug(‘Connection attempt #’ . $ATTEMPT . ’ to ’ . $ip . ‘:’ . $this->port . ‘…’);
$this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout);
if ($this->socket) {
socket_set_timeout($this->socket, $this->timeout);
$this->write(‘/login’);
$RESPONSE = $this->read(false);
if ($RESPONSE[0] == ‘!done’) {
$MATCHES = array();
if (preg_match_all(‘/[^=]+/i’, $RESPONSE[1], $MATCHES)) {
if ($MATCHES[0][0] == ‘ret’ && strlen($MATCHES[0][1]) == 32) {
$this->write(‘/login’, false);
$this->write(‘=name=’ . $login, false);
$this->write(‘=response=00’ . md5(chr(0) . $password . pack(‘H*’, $MATCHES[0][1])));
$RESPONSE = $this->read(false);
if ($RESPONSE[0] == ‘!done’) {
$this->connected = true;
break;
}
}
}
}
fclose($this->socket);
}
sleep($this->delay);
}
if ($this->connected)
$this->debug(‘Connected…’);
else
$this->debug(‘Error…’);
return $this->connected;
}


How can i modify it to Work?

as described in the link I provided.

send /login =name= =password= in first message

Thanks for your guidance.
Modified the code like this. Still same error. Did I miss something?

function connect($ip, $login, $password)
{
for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
$this->connected = false;
$this->debug(‘Connection attempt #’ . $ATTEMPT . ’ to ’ . $ip . ‘:’ . $this->port . ‘…’);
$this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout);
if ($this->socket) {
socket_set_timeout($this->socket, $this->timeout);
$this->write(‘/login’);
$this->write(‘=name=’ . $login, false);
$this->write(‘=password=’ . $password, false);
$RESPONSE = $this->read(false);
if ($RESPONSE[0] == ‘!done’) {
$MATCHES = array();
if (preg_match_all(‘/[^=]+/i’, $RESPONSE[1], $MATCHES)) {
if ($MATCHES[0][0] == ‘ret’ && strlen($MATCHES[0][1]) == 32) {
$this->write(‘/login’, false);
$this->write(‘=name=’ . $login, false);
$this->write(‘=response=00’ . md5(chr(0) . $password . pack(‘H*’, $MATCHES[0][1])));
$RESPONSE = $this->read(false);
if ($RESPONSE[0] == ‘!done’) {
$this->connected = true;
break;
}
}
}
}
fclose($this->socket);
}
sleep($this->delay);
}
if ($this->connected)
$this->debug(‘Connected…’);
else
$this->debug(‘Error…’);
return $this->connected;
}

there is no need to send /login again with md5 hash

http://forum.mikrotik.com/t/php-api-login-method-example-help-please/137749/11

Thank you.. but Still the same error. $RESPONSE = $this->read(false) returns just an empty array. Can you please the code now

function connect($ip, $login, $password)
{
for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
$this->connected = false;
$this->debug(‘Connection attempt #’ . $ATTEMPT . ’ to ’ . $ip . ‘:’ . $this->port . ‘…’);
$this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout);
if ($this->socket) {
socket_set_timeout($this->socket, $this->timeout);
$this->write(‘/login’);
$this->write(‘=name=’ . $login, false);
$this->write(‘=password=’ . $password, false);
$RESPONSE = $this->read(false);

if ($RESPONSE[0] == ‘!done’) {
$MATCHES = array();
if (preg_match_all(‘/[^=]+/i’, $RESPONSE[1], $MATCHES)) {
if ($MATCHES[0][0] == ‘ret’ && strlen($MATCHES[0][1]) == 32) {
$RESPONSE = $this->read(false);
if ($RESPONSE[0] == ‘!done’) {
$this->connected = true;
break;
}
}
}
}
fclose($this->socket);
}
sleep($this->delay);
}
if ($this->connected)
$this->debug(‘Connected…’);
else
$this->debug(‘Error…’);
return $this->connected;
}

Thanks for the class file. But still the same issue.. I think the prob is not from class file. Look like something else

Issue maybe from any ip blocking or any firewall settings? Why my connection is refusing by server?
Any ideas?

If you can see connection attempt in router’s log, then it clearly passed through firewall, otherwise it wouldn’t be there at all.

Yes you are right! I don’t know whats the exact issue.. Can you please help me to check it?

The class I linked to works fine for me, so I don’t know what can be wrong. Add some more debug output in connect(), just simple “echo” is fine, to see what exactly fails. Dumping $RESPONSE is good start.

Ok sure.
Result of : $RESPONSE = $this->read(false) :

Array
(
[0] => !trap
[1] => =message=std failure: not allowed (9)
[2] => !done
)

I don’t know what that is, but maybe some problem with permissions for used username?

Ohh ok.. I will check and get back to you.

For anyone coming to this topic looking for a solution, this solution worked for me. Modify connect() function within RouterosAPI class thus:

public function connect($ip, $login, $password, $porta)
    {
        for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) {
            $this->connected = false;
            $PROTOCOL = ($this->ssl ? 'ssl://' : '' );
            $context = stream_context_create(array('ssl' => array('ciphers' => 'ADH:ALL', 'verify_peer' => false, 'verify_peer_name' => false)));
            $this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $PROTOCOL . $ip . ':' . $porta . '...');
            $this->socket = @stream_socket_client($PROTOCOL . $ip.':'. $porta, $this->error_no, $this->error_str, $this->timeout, STREAM_CLIENT_CONNECT);
            
			if ($this->socket) {
                socket_set_timeout($this->socket, $this->timeout);
                $this->write('/login');
				$this->write('=name=' . $login, false);
				$this->write('=password=' . $password, false);
                $RESPONSE = $this->read(false);
				
				/if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
                    $this->connected = true;
					/*
					// see notes at https://wiki.mikrotik.com/wiki/Manual:API#Initial_login
					$MATCHES = array();
                    if (preg_match_all('/[^=]+/i', $RESPONSE[1], $MATCHES)) {
                        if ($MATCHES[0][0] == 'ret' && strlen($MATCHES[0][1]) == 32) {
                            $this->write('/login', false);
                            $this->write('=name=' . $login, false);
							$this->write('=response=00' . md5(chr(0) . $password . pack('H*', $MATCHES[0][1])));
							mostra_array($this, 'api 116');
                            $RESPONSE = $this->read(false);mostra_array($RESPONSE, 'api 117 RESPONSE');
                            if (isset($RESPONSE[0]) && $RESPONSE[0] == '!done') {
                                $this->connected = true;
                                break;
                            }
                        }
                    }
					*/
										
                }
                fclose($this->socket);
            }
            sleep($this->delay);
        }

This is $RESPONSE object:

Connection attempt #1 to xx.xx.xx.197:21... <<< [6] /login <<< [14] =name=myLogin<<< [23] =password=myPassword >>> [5/5] bytes read. >>> [5, 39]!done >>> [37/37] bytes read. >>> [37, 1]=ret=2a26f0033901135c0c685bdbc6ffb5de Connected... Disconnected...