Giter Club home page Giter Club logo

routeros-api-php's Introduction

Latest Stable Version Build Status Total Downloads License Code Climate Code Coverage Scrutinizer CQ

RouterOS API Client

composer require evilfreelancer/routeros-api-php

This library is partly based on this old project, but unlike it has many innovations to ease development. In addition, the project designed to work with PHP7/8 in accordance with the PSR standards.

You can use this library with pre-6.43 and post-6.43 versions of RouterOS firmware, it will be detected automatically on connection stage.

Table of Contents

Minimum requirements

  • php >= 7.2|8.0
  • ext-sockets

Laravel framework support

RouterOS API client is optimized for usage as normal Laravel package, all functional is available via \RouterOS facade, for access to client object you need instead:

$config = new \RouterOS\Config([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin',
    'port' => 8728,
]);
$client = new \RouterOS\Client($config);

Use the facade and pass array of parameters to client method:

$client = \RouterOS::client([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin',
    'port' => 8728,
]);

You also may get array with all configs which was obtained from routeros-api.php file:

$config = \RouterOS::config([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin',
    'port' => 8728,
]);

dump($config);

$client = \RouterOS::client($config);

Laravel installation

By default, the package will automatically register its service provider, but if you are a happy owner of Laravel version less than 5.5, then in a project, which is using the package (after composer require is done, of course), add intoproviders block of your config/app.php:

'providers' => [
    // ...
    RouterOS\Laravel\ServiceProvider::class,
],

Optionally, publish the configuration file if you want to change any defaults:

php artisan vendor:publish --provider="RouterOS\\Laravel\\ServiceProvider"

How to use

Basic example, analogue via command line is /ip hotspot ip-binding print:

use \RouterOS\Client;
use \RouterOS\Query;

// Initiate client with config object
$client = new Client([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin',
    'port' => 8728,
]);

// Create "where" Query object for RouterOS
$query =
    (new Query('/ip/hotspot/ip-binding/print'))
        ->where('mac-address', '00:00:00:00:40:29');

// Send query and read response from RouterOS
$response = $client->query($query)->read();

var_dump($response);

Basic example for update/create/delete types of queries:

use \RouterOS\Client;
use \RouterOS\Query;

// Initiate client with config object
$client = new Client([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin'
]);

// Send "equal" query with details about IP address which should be created
$query =
    (new Query('/ip/hotspot/ip-binding/add'))
        ->equal('mac-address', '00:00:00:00:40:29')
        ->equal('type', 'bypassed')
        ->equal('comment', 'testcomment');

// Send query and read response from RouterOS (ordinary answer from update/create/delete queries has empty body)
$response = $client->query($query)->read();

var_dump($response);

If you need export all settings from router:

use \RouterOS\Client;

// Initiate client with config object
$client = new Client([
    'host'        => '192.168.1.3',
    'user'        => 'admin',
    'pass'        => 'admin',
    'ssh_port'    => 22222,
    'ssh_timeout' => 60, // if not set then 30 seconds by default 
]);

// Execute export command via ssh
$response = $client->query('/export');
// or
$response = $client->export();

var_dump($response);

Examples with "where" conditions, "operations" and "tag":

use \RouterOS\Query;

/**
 * Simple "where" query will be generated by default 
 */

$client->query('/ip/address/print')->read();

/**
 * Send advanced "where" query with parameters to RouterOS 
 */

// If only one "where" condition
$client->query('/queue/simple/print', ['target', '192.168.1.1/32']);

// If multiple "where" conditions and need merge (operation "|") results
$client->query('/interface/print', [
    ['type', 'ether'],  // same as ['type', '=', 'ether']
    ['type', 'vlan'],   // same as ['type', '=', 'vlan']
], '|');

/**
 * Or in OOP style
 */

// If you need create query for "create/update/delete" operations
$query = new Query('/ip/hotspot/ip-binding/add');
$query->equal('mac-address', '00:00:00:00:40:29');
$query->equal('type', 'bypassed');
$query->equal('comment', 'testcomment');

// If multiple "where" conditions and need merge (operation "|") results
$query = new Query('/interface/print');
$query->where('type', 'ether');
$query->where('type', 'vlan');
$query->operations('|');

// If multiple "where" conditions and need append tag
$query = new Query('/interface/set');
$query->where('disabled', 'no');
$query->where('.id', 'ether1');
$query->tag(4);

/**
 * Write Query object to RouterOS and read response from it
 */

$response = $client->query($query)->read();

All available examples you can find here.

How to configure the client

You just need create object of Client class with required parameters in array format:

use \RouterOS\Client;

$client = new Client([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin'
]);
ℹ️ Advanced examples of Config and Client classes usage
use \RouterOS\Config;
use \RouterOS\Client;

/**
 * You can create object of Config class
 */

$config = new Config();

// Then set parameters of config
$config->set('host', '192.168.1.3');
$config->set('user', 'admin');
$config->set('pass', 'admin');

// By the way, `->set()` method is support inline style of syntax
$config
    ->set('host', '192.168.1.3')
    ->set('user', 'admin')
    ->set('pass', 'admin');

/**
 * Or just create preconfigured Config object
 */

$config = new Config([
    'host' => '192.168.1.3',
    'user' => 'admin',
    'pass' => 'admin'
]);

/**
 * Then send Config object to Client constructor
 */

$client = new Client($config);

List of available configuration parameters

Parameter Type Default Description
host string (required) Address of Mikrotik RouterOS
user string (required) Username
pass string (required) Password
port int RouterOS API port number for access (if not set use 8728 or 8729 if SSL enabled)
ssl bool false Enable ssl support (if port is not set this parameter must change default port to ssl port)
ssl_options array details See https://www.php.net/manual/en/context.ssl.php
legacy bool false Deprecated, will be removed from 1.5.0: Support of legacy login scheme (true - pre 6.43, false - post 6.43)
timeout int 10 Max timeout for connecting to RouterOS (in seconds)
socket_timeout int 30 Max read timeout from RouterOS (in seconds)
socket_blocking bool true Set blocking mode on a socket stream
socket_options array details See https://www.php.net/manual/en/context.socket.php
attempts int 10 Count of attempts to establish TCP session
delay int 1 Delay between attempts in seconds
ssh_port int 22 Number of SSH port for exporting configuration
ssh_timeout int 30 Max timeout from router via SSH (in seconds)
ssh_private_key string ~/.ssh/id_rsa Full path to required private key

How to enable support of legacy login schema (RouterOS pre-6.43)

From 0.8.1 this is not important, version of firmware will be detected automatically. Deprecated, will be removed from 1.5.0

<?php
require_once __DIR__ . '/vendor/autoload.php';

use \RouterOS\Client;

// Initiate client with config object
$client = new Client([
    'host'   => '192.168.1.3',
    'user'   => 'admin',
    'pass'   => 'admin',
    'legacy' => true // you need set `legacy` parameter with `true` value
]);

// Your code below...

How to write queries

You can write absolutely any queries to your router, for this you need to create a "Query" object whose first argument is the required command, after this you can add the attributes of the command to "Query" object.

More about attributes and "words" from which these attributes should be created here.

More about "expressions", "where", "equal" and other filters/modifications of your query you can find here.

Simple usage examples of Query class:

use \RouterOS\Query;

// Get all installed packages (it may be enabled or disabled)
$query = new Query('/system/package/getall');

// Send "equal" query with details about IP address which should be created
$query =
    (new Query('/ip/hotspot/ip-binding/add'))
        ->equal('mac-address', '00:00:00:00:40:29')
        ->equal('type', 'bypassed')
        ->equal('comment', 'testcomment');

// Set where interface is disabled and ID is ether1 (with tag 4)
$query = 
    (new Query('/interface/set'))
        ->where('disabled', 'no')
        ->where('.id', 'ether1')
        ->tag(4);

// Get all ethernet and VLAN interfaces
$query = 
    (new Query('/interface/print'))
        ->where('type', 'ether')
        ->where('type', 'vlan')
        ->operations('|');

// Get all routes that have non-empty comment
$query =
    (new Query('/ip/route/print'))
        ->where('comment', '>', null);
ℹ️ Advanced examples of Query class usage
use \RouterOS\Query;
use \RouterOS\Client;

// Initiate connection to RouterOS
$client = new Client([
    'host'   => '192.168.1.3',
    'user'   => 'admin',
    'pass'   => 'admin'
]);

/**
 * Execute query directly through "->query()" method of Client class 
 */

// If your query has no "where" conditions
$client->query('/ip/arp/print');

// If you have only one where condition, you may use one dimensional array as second parameter of query method
$client->query('/queue/simple/print', ['target', '192.168.1.250/32']);

// If you need set few where conditions then need use multi dimensional array
$client->query('/interface/bridge/add', [
    ['name', 'vlan100-bridge'],
    ['vlan-filtering', 'no']
]);

/**
 * By some reason you may need restrict scope of RouterOS response,
 * for this need to use third attribute of "->query()" method
 */

// Get all ethernet and VLAN interfaces
$client->query('/interface/print', [
    ['type', 'ether'],
    ['type', 'vlan']
], '|');

/** 
 * If you want set tag of your query then you need to use fourth 
 * attribute of "->query()" method, but third attribute may be null
 */

// Enable interface (tag is 4)
$client->query('/interface/set', [
    ['disabled', 'no'],
    ['.id', 'ether1']
], null, 4);

/**
 * Or in OOP style  
 */

// Get all ethernet and VLAN interfaces
$query = new Query('/interface/print');
$query->where('type', 'ether');
$query->where('type', 'vlan');
$query->operations('|');

// Enable interface (tag is 4)
$query = new Query('/interface/set');
$query->equal('disabled', 'no');
$query->equal('.id', 'ether1');
$query->tag(4);

// Or, RAW mode

$query = new Query('/interface/set');
$query->add('=disabled=no');
$query->add('=.id=ether1');
$query->add('.tag=4');

// Or, RAW mode in format of array
    
$query = new Query('/interface/set', [
    '=disabled=no',
    '=.id=ether1',
    '.tag=4'
]);

// Or

$query = new Query([
    '/interface/set',
    '=disabled=no',
    '=.id=ether1',
    '.tag=4'
]);

/**
 * Write Query object to RouterOS and read response from it
 */

$response = $client->query($query)->read();

Read response as Iterator

By default, original solution of this client is not optimized for work with a large amount of results, only for small count of lines in response from RouterOS API.

But some routers may have (for example) 30000+ records in their firewall list. Specifically for such tasks, a method readAsIterator has been added that converts the results obtained from the router into a resource, with which it will later be possible to work.

You could treat response as an array except using any array_* functions

$response = $client->query($query)->readAsIterator();
var_dump($response);

// The following for loop allows you to skip elements for which
// $iterator->current() throws an exception, rather than breaking
// the loop.
for ($response->rewind(); $response->valid(); $response->next()) {
    try {
        $value = $response->current();
    } catch (Exception $exception) {
        continue;
    }

    # ...
}

Short methods

You can simplify your code and send then read from socket in one line:

/** 
 * Execute query and read response in ordinary mode 
 */
$response = $client->query($query)->read();
var_dump($response);

// Or
$response = $client->q($query)->r();
var_dump($response);

// Single method analog of lines above is
$response = $client->qr($query);
var_dump($response);

/**
 * Execute query and read response as Iterator 
 */
$response = $client->query($query)->readAsIterator();
var_dump($response);

// Or
$response = $client->q($query)->ri();
var_dump($response);

// Single method analog of lines above is
$response = $client->qri($query);
var_dump($response);

/**
 * By the way, you can send few queries to your router without result: 
 */
$client->query($query1)->query($query2)->query($query3);

// Or
$client->q($query1)->q($query2)->q($query3);

Known issues

Unable to establish socket session, Operation timed out

This error means that the library cannot connect to your router, it may mean router turned off (then need turn on), or the API service not enabled.

Go to Mikrotik Router OS -> IP -> Services and enable api service.

Or via command line:

/ip service enable api 

How to update/remove/create something via API?

Instead of ->where() method of Query class you need to use ->equal() method:

// Create query which should remove security profile
$query = new \RouterOS\Query('/interface/wireless/security-profiles/remove');

// It will generate queries, which stared from "?" symbol:
$query->where('.id', '*1');

/*
// Sample with ->where() method
RouterOS\Query Object
(
    [_attributes:RouterOS\Query:private] => Array
        (
            [0] => ?.id=*1
        )

    [_operations:RouterOS\Query:private] => 
    [_tag:RouterOS\Query:private] => 
    [_endpoint:RouterOS\Query:private] => /interface/wireless/security-profiles/remove
)
*/

// So, as you can see, instead of `->where()` need to use `->equal()`
// It will generate queries, which stared from "=" symbol:
$query->equal('.id', '*1');

/*
// Sample with ->equal() method
RouterOS\Query Object
(
    [_attributes:RouterOS\Query:private] => Array
        (
            [0] => =.id=*1
        )

    [_operations:RouterOS\Query:private] => 
    [_tag:RouterOS\Query:private] => 
    [_endpoint:RouterOS\Query:private] => /interface/wireless/security-profiles/remove
)
*/

Undefined character (any non-English languages)

RouterOS does not support national languages, only English (and API of RouterOS too).

You can try to reproduce it via web, for example add the comment to any element of your system, then save and reload the page, you will see unreadable characters.

Testing

You can use my other project with RouterOS in Docker container for running unit testing on your computer, for this you just need to have Expect, Docker and Docker Compose.

Next clone the repo with RouterOS in Docker and exec docker-compose up -d, then you need preconfigure virtual routers via preconf.tcl script from root of routeros-api-php:

./preconf.tcl 12223
./preconf.tcl 22223

And after this you can run tests:

./vendor/bin/phpunit

Links

routeros-api-php's People

Contributors

ari-arimaniac avatar arily avatar billy8119 avatar compolomus avatar dbemfica avatar evilfreelancer avatar gamadoleo avatar lilleri avatar majsterkoo avatar vonsofh avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

routeros-api-php's Issues

Can't Catch Exception When Connection Couldn't Established

Hi, I'm just started using this projects.
I already could connecting my application (local) into the router intended but when I didn't set the configuration for \RouterOS\Client properly or my pc didn't have any connection to router it always throw

"message": "Unable to establish socket session, No connection could be made because the target machine actively refused it.", "exception": "RouterOS\\Exceptions\\ClientException"

even though I already wrap it inside Try and Catch like this:

public function connectToRouterByIp($ip)
    {
        $router = $this->router->whereIpAddress($ip);
        try {
            $this->client = new \RouterOS\Client([
                'host' => $router->ip_address,
                'user' => $router->username,
                'pass' => $router->password,
                'port' => $router->port ?? 8728
            ]);
            $this->message['message'] = 'Can\'t establish connection';
        } catch (\Exception $e) {
            $this->message['message'] = 'Can\'t establish connection';
            return $this;
        }

        return $this;
    }

Did I do something that must not be done ?
Anyway, thanks for this amazing projects!

No such command when activating profile

I am trying to activate a Profile for my registered user using the below function

public function activateProfile($username)
  {
      $activateProfileQuery = new Query(
          "/tool/user-manager/user/create-and-activate-profile/" . $username,
          [
              '=customer=admin',
              '=profile=24hrs Unlimited'
          ]
      );
      $response = $this->query($activateProfileQuery)->read(false);
      print("Activating Profile...");
      print_r($response);
  }

But I keep getting the error message below

Activating Profile...Array ( [0] => !trap [1] => =message=no such command [2] => !done )

Please help.

Thank you for this amazing library.

Remove address list

How to remove address list at firewall using list name or ip address parameter?

is there a way to use monitor command for a duration.

Is there a way with this to use the monitor command for a time period then return the results

Eg command line command
/interface ethernet monitor ether4 duration=1

Would run for 1 second the output the last result.

Setting/Removing

Amazing package - thank you for writing it! Love your username!

Having some inconsistent results, which i am confused as to whether is my fault (probably) or limitations of the API.

I've created a security profile named 'test1' (index 1, the second one after the default profile). All works well. However, when i come to edit or remove it, all i get is a silent [] back from the API, and nothing changed in the admin. If i run the commands from the CLI (over SSH), they update instantly.

Changing the profile name:

This works in the CLI:

interface wireless security-profiles set 1 name=test1old

Neither of these work, even though they correctly find the object using print:

(new \RouterOS\Client(['host' => '192.168.0.1', 'user' => 'admin', 'pass' => 'redacted']))
->query((new \RouterOS\Query('/interface/wireless/security-profiles/set'))
    ->where('name', 'test1')
    ->equal('name', 'test1old'))
->read();
(new \RouterOS\Client(['host' => '192.168.0.1', 'user' => 'admin', 'pass' => 'redacted']))
->query((new \RouterOS\Query('/interface/wireless/security-profiles/set/1'))
    ->equal('name', 'test1old'))
->read();

Result:
[]
(Nothing changed)

Removing it entirely:

This works in the CLI:

interface wireless security-profiles remove 1

Neither of these work, even though they correctly find the object using print:

(new \RouterOS\Client(['host' => '192.168.0.1', 'user' => 'admin', 'pass' => 'redacted']))
->query((new \RouterOS\Query('/interface/wireless/security-profiles/remove'))
    ->where('name', 'test1')
->read();
(new \RouterOS\Client(['host' => '192.168.0.1', 'user' => 'admin', 'pass' => 'redacted']))
->query((new \RouterOS\Query('/interface/wireless/security-profiles/remove/1'))
->read();

Result:
[]
(Nothing changed)

Changing the where() to .id to find the internal index - at either the ID from the object or the internal index from the CLI gives the same result. Have i got this wrong, or is the API prohibited from making changes once they've been written?

Thanks in advance!

Are this library can use from outside Router network?

i'm new in mikrotik, please help

when the device (Phone/Laptop) connected to router, after get IP & Mac Address it will redirected to laravel application in cloud server. and then, i need send query for setting that IP & Mac Address can connect to internet

so, what query should i use?
or maybe any option for what i need

thank you, sorry for bad english

How to get full source from system script print?

i'm try this:

$scriptQue = (new Query('/system/script/print'));
$scriptReq = $lynx->write($scriptQue);
$script = $lynx->read();

and result:
Array
(
[0] => Array
(
[.id] => *3
[.nextid] => *5
[name] => script1
[owner] => admin
[policy] => ftp,reboot,read,write,policy,test,winbox,password,sniff,sensitive,api
[last-started] => oct/19/2019 09:36:44
[run-count] => 8992
[source] => :local monitor [/interface monitor-traffic ether2 as-value once]
[invalid] => false
)
)

why thi [source] => :local monitor [/interface monitor-traffic ether2 as-value once] can't get full source ? and last, you have solution for this case ?

thanks.

Class 'RouterOS\Laravel\ClientServiceProvide' not found

Version of RouterOS
Ubuntu 18.4

To Reproduce
When we use latest version 1.2.0 then this error occurred in laravel installation 'Class 'RouterOS\Laravel\ClientServiceProvide' not found'

Expected behavior
Older version 1.1.1 is working fine with laravel but the new version is throwing error 'Class 'RouterOS\Laravel\ClientServiceProvide' not found'

use for monitor traffic

hi EvilFreelancer,
I hope you can give me instructions, how to run the command "/interface/monitor-traffic interface=ether1 once", with this library/package

thanks

Undefined offset: 0 in .../src/Client.php on line 244

Hi,

First of all, I really like this package.

I use this package to mostly interface with queues. When creating an invalid queue (eg. queue type doesn't exist or queue name is already used), I get the notice:

PHP Notice: Undefined offset: 0 in .../evilfreelancer/routeros-api-php/src/Client.php on line 244

Here's line 244: https://github.com/EvilFreelancer/routeros-api-php/blob/master/src/Client.php#L244

When creating a queue with a name that already exists, dumping $matches after line 242 of Client.php prints these two arrays after calling $client->read():

array:3 [
  0 => array:1 [
    0 => "=message=failure: already have such name"
  ]
  1 => array:1 [
    0 => "message"
  ]
  2 => array:1 [
    0 => "failure: already have such name"
  ]
]
array:3 [
  0 => []
  1 => []
  2 => []
]

Then two notices about the undefined offset. I think it is failing on the second array where the response would be '!done'. $match[1][0] and $match[2][0] are not defined.

Should an exception be thrown instead?

I'm using Laravel and it throws an exception on notices by default.

Access via non Real IP builtin VPN Access

Can we achieve this API access via mikrotik provided vpn ID e.g. 999999d229c.sn.mynetname.net

Please provide sample of such communication which is necessary for routers without any real IP..

Thanks in advance.

More detail exceptions

Hi,
ClientException is used for

  • unable to connect...
  • invalid user name or password
  • From 1 to 3 parameters of "where" condition is allowed

In my script, when unable to connect to device, then I try ssh connection instead (sometimes api port is disabled). In this exceptions case, there is not a good way (?), how I can recognize between "unable to connect" versus "invalid user name").
Can you add more exceptions or other improvement... or did I miss something?

Thanks.

Users created via User Manager unable to log In to hotspot

Hello, thanks for this amazing library.

I have a weird issue though.

I was able to create some users and activate their profiles using the code below

 public function authenticateAndActivateUser($customer = 'admin', $username, $phone, $password, $amount = null)
    {
        $createUserQuery = new Query(
            "/tool/user-manager/user/add",
            [
                '=customer=' . $customer,
                '=username=' . strtoupper($username),
                '=phone=' . $phone,
                '=password=' . $password,
                '=disabled=no',
                '=shared-users=1',
                '=caller-id-bind-on-first-use=yes'
            ]
        );
        $existingUser = $this->findUserByUserName($username, $password);
        $userPassword = "";
        if (!empty($existingUser)) {
            foreach ($existingUser as $key => $value) {
                if (strpos($value, "=password=") !== false) {
                    $password = str_replace("=password=", "", $value);
                    $userPassword = $password;
                    break;
                }
            }
        }
        if ($userPassword !== "") {
            $this->activateProfile($username, $amount);
        } else {
            $response = $this->query($createUserQuery)->read(false);
            foreach ($response as $key => $value) {
                if ($value === '!done') {
                    $this->activateProfile($username, $amount);
                }
            }
        }
    }

Here is the activateProfile function

    public function activateProfile($username, $amount)
    {
        $activationQuery = new Query(
            '/tool/user-manager/user/create-and-activate-profile',
            [
                '=numbers=' . strtoupper($username),
                '=customer=admin',
                '=profile=24hrs Unlimited',
            ]
        );
        $response = $this->query($activationQuery)->read(false);
        print("Activating Profile for " . $username . "...");
        print_r($response);
    }

Now when I tried to log into the hotspot and make use of it with one of the users that have been created via user manager I am constantly getting the error message
invalid username or password

What do I do? Please help.

Thanks so much in advance.

Query PPP Set

Hi,
I would like change profile PPP with API but I have trouble the script didn't run. This is my code :

  // Create "where" Query object for RouterOS
     $query =
         (new Query('/ppp/secret/set/name/profile=Block'));


     // Send query and read response from RouterOS

     $response = $client->query($query)->read();
     return response()->json($response);     

Could you please share how to edit or set PPP Secret?

Thank you

Unable to establish socket session, Operation timed out

I don't know why but I am unable to establish a connection. It seems I am doing everything right but can't figure out what's exactly causing the issue. If you shed some light on this, I'd really appreciate it.

File: example.php

<?php

require __DIR__ . '/vendor/autoload.php';

use RouterOS\Client;
use RouterOS\Query;

try {
    new Client([
        'host' => '192.168.1.1',
        'user' => 'john',
        'pass' => 'doe',
    ]);
} catch (\Throwable $th) {
    var_dump($th);
}

Here's the log:

object(RouterOS\Exceptions\ClientException)#4 (7) {
  ["message":protected]=>
  string(55) "Unable to establish socket session, Operation timed out"
  ["string":"Exception":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(92) "/Desktop/mikrotiktest/vendor/evilfreelancer/routeros-api-php/src/SocketTrait.php"
  ["line":protected]=>
  int(63)
  ["trace":"Exception":private]=>
  array(3) {
    [0]=>
    array(6) {
      ["file"]=>
      string(87) "/Desktop/mikrotiktest/vendor/evilfreelancer/routeros-api-php/src/Client.php"
      ["line"]=>
      int(493)
      ["function"]=>
      string(10) "openSocket"
      ["class"]=>
      string(15) "RouterOS\Client"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
    [1]=>
    array(6) {
      ["file"]=>
      string(87) "/Desktop/mikrotiktest/vendor/evilfreelancer/routeros-api-php/src/Client.php"
      ["line"]=>
      int(73)
      ["function"]=>
      string(7) "connect"
      ["class"]=>
      string(15) "RouterOS\Client"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(0) {
      }
    }
    [2]=>
    array(6) {
      ["file"]=>
      string(43) "/Desktop/mikrotiktest/index.php"
      ["line"]=>
      int(10)
      ["function"]=>
      string(11) "__construct"
      ["class"]=>
      string(15) "RouterOS\Client"
      ["type"]=>
      string(2) "->"
      ["args"]=>
      array(1) {
        [0]=>
        object(RouterOS\Config)#2 (1) {
          ["_parameters":"RouterOS\Config":private]=>
          array(8) {
            ["legacy"]=>
            bool(false)
            ["ssl"]=>
            bool(false)
            ["timeout"]=>
            int(20)
            ["attempts"]=>
            int(10)
            ["delay"]=>
            int(1)
            ["host"]=>
            string(14) "192.168.1.1"
            ["user"]=>
            string(12) "john"
            ["pass"]=>
            string(10) "doe"
          }
        }
      }
    }
  }
  ["previous":"Exception":private]=>
  NULL
}

I am using the host IP address is the one that shows the Mikrotik Router OS when visiting it from the browser and I believe this is the right one. Is there anything else I need to do from somewhere else to make sure the connection can establish?

Incomplete responses

Version of RouterOS
I'm using RB2011UiAS with 7.1beta5 (development) version.

To Reproduce

    $client= new Client([
        'host' => $access->DireccionIP,
        'user' => $access->Usuario,
        'pass' => $access->Password,
        'port' => $access->Puerto,
        'ssh_port' => 8722
    ]);

    $query = (new Query('/ip/hotspot/user/profile/print'));

    $response = $client->query($query)->read();

    return response()->json([
        'response' => $response,
        'mensaje' => 'Información de Acceso encontrada',
        'exito' => true
    ]);

Expected behavior
I have a PHP function to print all the User Profiles into Ip/Hotspot called with ReactJS as API but the response is always incomplete because I have 23 items (checked it with Winbox) and I receive sometimes 7 objects or 9 objects but never all the objects.

responsewinbox

responsejson

What could be?
Another question that I don't understand: why do I have to use /ip/hotspot/user/profile/print instead /ip/hotspot/user-profile/print? Does this relation with "No such command prefix" error?

Unable to update simple queue

Thank you @EvilFreelancer for this wonderful package. Am testing your package but I cannot update a simple queue max-limit or any other parameter. Here's my code:

$query = new \RouterOS\Query('/queue/simple/set');
	$query->equal('name', "TestQueue");
	$query->equal('max-limit', "10000/10000");

$response = $client->query($query)->read(); // dd($response); gives !done

$response = $client->query('/queue/simple/print', ['name', 'TestQueue'])->read(); 
dd($response); // no change to the queue

What's the issue?

remove ip-binding not work

don't work

$user = $client->query('/ip/hotspot/ip-binding/print', ['mac-address', '00:00:00:00:00:A9'])->read();
if (isset($user[0]['.id'])) {
$userId = $user[0]['.id'];
$removeUser = $client->query('/ip/hotspot/ip-binding/remove', ['.id', $userId])->read();
print_r($removeUser);
}

Result:
Array ( )
Don't remove

where clause

Hello, I tried in many ways but I can not create a query using where, does your class support this?

Ex:

$query = new Query('/queue/simple/print/where', ['name=123123']); or $query = new Query('/queue/simple/print', ['where', 'name=123123']);

reading response as a stream?

it's a little extreme but when I trying to print my address list which has about 80k ip/cidr, PHP runs out of memory.
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 20480 bytes) in /~~~/vendor/evilfreelancer/routeros-api-php/src/Client.php on line 252.

Troubles with foreach

In

foreach ($arr as $ip){
 if (filter_var($ip, FILTER_VALIDATE_IP)) {
  $query=new Query('/queue/simple/print');
  $query->add('?target='.$ip.'/32');
  $responses=$ros->write($query)->read();
  print_r($responses);
  echo "<hr>";
 }

as result have answers like Array ( [after] => Array ( [] => ) )
So new query was exec so fast as I understand...
For now I move $ros=new Client($con); inside foreach and it work, but it's not good, of course, and so slow...

Attempting to set Interface to disable

So I am attempting to set an interface to disable via query. Here is what I have but doesn't seem to be working.

$query = new Query('/interface/set');
$query->where('name', 'ether5');
$query->equal('disabled', 'yes');

$response = $client->query($query)->read();

The response is null and no changes on the router. I can do prints, and other queries without any issues just haven't gotten the set to work

Export bug ?

Version of RouterOS
+100 routers tested. 6.43.x to 6.45.X

To Reproduce
examples/export.php

Expected behavior
I have only this response:

Array
(
    [0] => !done
)

Best regads,
Mickael

Running Script

How can i run "system script run Test" ?
i've tried where('name', 'Test') but it return script not found
i've tried equal('name', 'Test') but it give me unknown parameter

Is there any option to do that?

Changing parameter value with set command

Hi, I have been trying to change parameter value (e.g. change ppp secret password) but its returning empty array. I have tried differnt combination with equal, add etc. Nothing works. Here is an example how I have been trying:

$query = new Query('/ppp/secret/set');
$query->where('numbers', 1);
$query->equal('password', 'test');

Can't login after update from 6.43.8 to 6.45.8

Version of RouterOS
6.45.8 (long-term)

To Reproduce
Just login
$conn = (new Config()) -> set('timeout', 10) -> set('host', '192.168.1.1') -> set('user', 'user') -> set('pass', 'pass') -> set('delay', 10) -> set('legacy', false); $ros = new Client($conn);

Expected behavior

Fatal error: Uncaught RouterOS\Exceptions\ClientException: Invalid user name or password in /var/www/localhost/htdocs/composer/vendor/evilfreelancer/routeros-api-php/src/Client.php:438 Stack trace: #0 /var/www/localhost/htdocs/composer/vendor/evilfreelancer/routeros-api-php/src/Client.php(481): RouterOS\Client->login() #1 /var/www/localhost/htdocs/composer/vendor/evilfreelancer/routeros-api-php/src/Client.php(60): RouterOS\Client->connect() #2 /var/www/localhost/htdocs/config.php(31): RouterOS\Client->__construct(Object(RouterOS\Config)) #3 /var/www/localhost/htdocs/inc_head.php(2): require('/var/www/localh...') #4 /var/www/localhost/htdocs/user.php(318): require('/var/www/localh...') #5 {main} thrown in /var/www/localhost/htdocs/composer/vendor/evilfreelancer/routeros-api-php/src/Client.php on line 438

RouterOS reboot command terminates the API connection without response resulting in PHP timeout

When sending the /system/reboot command with the read() function it waits on a response despite setting the timout and attempts.

Would be good if I could just send the command to the router singularly.

I have already tried the write() function, which passes and allows laravel to continue but doesn't actually execute on the router.

Version of RouterOS
6.44.5

To Reproduce
$this->client = new Client([
'host' => $router->ip->address,
'user' => %%,
'pass' =>%%,
'timeout' => 5,
'attempts' => 1,
'legacy' => ($router->legacy == 0 ? false : true)
]);
$this->client->write('/system/reboot')->read();

Expected behavior
Not wait on responce and return.

Error reading 1 bytes

i tried to read my mikrotik profile, yesterday was fine but today return error: Error reading 1 bytes. Code below:

public function init()
{
	$config =
	    (new Config())
	        ->set('host', env('MIKROTIK_IP'))
	        ->set('user', env('MIKROTIK_USERNAME'))
	        ->set('pass', env('MIKROTIK_PASSWORD'))
	        ->set('timeout', 5)
	        ->set('attempts', 1);

	return $config;
}
public function getPpoe($data)
{
	$config = $this->init();
	$client = new Client($config);
	$query  = new Query('/ppp/secret/print');
	$query->where('name', $data['name']);
	$secrets = $client->query($query)->read();
	return $secrets;
}

help me

help me with instalation please, recording video teaching, thanks

Script have problems with looping.

Ex. I have 5 devices, written a loop using the script.
` $config =
(new Config())
->set('timeout', 1)
->set('host', $data_tik['tikDDNS'])
->set('user', $data_tik['tikUser'])
->set('pass', $data_tik['tikPass']);

                  $client = new Client($config);
                  $query = new Query('/system/resource/print');
                  $response = $client->write($query)->read();`

If the connection to the second device cannot be connected
The script will stop working immediately.

Can I suggest a code?
If any device connection has a problem, report back and continue working all devices are complete.

Cant change ppp secrets information

hi there, did i miss something here? because I cant change the value of secrets profile (disabled status). Here is my code:

$config =
    (new Config())
        ->set('host', env('MIKROTIK_IP'))
        ->set('user', env('MIKROTIK_USERNAME'))
        ->set('pass', env('MIKROTIK_PASSWORD'));

// Initiate client with config object
$client = new Client($config);

// Get list of all available profiles with name Block
$query = new Query('/ppp/secret/set');
$query->where('name', 'HOUSE');
$query->equal('disabled', 'yes');
$secrets = $client->query($query)->read();
return $secrets;

undefined character (Spanish language)

Hello, I am creating a simple interface for an ISP in the country of Colombia in which the Spanish language is spoken and the api does not detect the character (ñ - Ñ)

Can you solve this problem?

I appreciate your response

login() always return true regardless of legacy

Hello,
first thanks for this great job!

I've got a lot of routers with versions pre 6.43 and post 6.43.

When connecting to ROS pre 6.43 and setting legacy: false (wich is wrong, but I want to determine the router version), login() method returns true.

Here is the code :

        // Return true if we have only one line from server and this line is !done
        return isset($response[0]) && $response[0] === '!done';

I think the point is that you don't test if there is only one line in the response.

        // Return true if we have only one line from server and this line is !done
        return (1 === count($response)) &&  isset($response[0]) && ($response[0] === '!done');

Works for me...

Unable to establish socket connection "no route to host"

Hello, thanks for this amazing library.

Everything worked really well until I deployed the php script to an online server and I then I started getting the error message
Unable to establish socket connection "no route to host" whenever I try to openSocket.

Do you have any idea on how to resolve this?

Thanks.

Query /ip/firewall/nat/print won't return all results

Using with with legacy firmware, when executing query /ip/firewall/nat/print I get back only a part of what's actually on the device.
When I tried using a different library I got back all of results.
Tried resolving this issue by myself but I failed.

VPN host support

I have a mikrotik router which is setup for online remote.
I can connect anywhere as long as there is internet.
Does this support VPN host connection ?

$config = new \RouterOS\Config([
    'host' => 'http://example.com:12',
    'user' => 'admin',
    'pass' => 'admin'
]);

Currently using this package https://www.npmjs.com/package/routeros-client with a NodeJS server and they dont support VPN connection.
Then found this package that uses PHP and just want to ask if it the same with NodeJS package.

UPDATE

The problem was solved in my NodeJS application.
Turns out I blocked the port in the firewall.
Thats why I cannot established connection.

cant display full script if the script contain new line

hi,
i got issue like this #20, but for me is not solved.

fyi, mikrotik version 6.44.6 (long term)

i create script manualy on mikrotik, like this
image

then i create php file with this data :

<?php
require_once 'vendor/autoload.php';
error_reporting(E_ALL);
use RouterOS\Client;
use RouterOS\Query;
$client = new Client([
    'timeout' => 1,
    'host'    => 'my host',
    'user'    => 'my user',
    'pass'    => 'my pass',
    'port'    => my port,
]);

$query = (new Query('/system/script/print'))
            ->where('name','test_script');
$response = $client->query($query)->read();
print_r($response);

and this is the result :

image

the results can not display the full script, this method only display the first 1 line of code.

can i get full script (3 lines code) without changing my source script?

previously I apologize if the English I use is not good

Bug with `/ppp/active/print`

Version of RouterOS
Need to know version

To Reproduce

// Initiate client with config object
$client = new Client([
'host' => '138.185.236.230',
'user' => 'api_mk',
'pass' => 'senha_aqui',
'timeout' => 5,
'attempts' => 1
]);

//lembrar de verificar se a variavel $cliente foi gerada e se não gerar exception
print_r($client);
//the connection it runs smoothly	

///the problem is here
// Send query and read response from RouterOS
$response = $client->wr('/ppp/active/print',false);
var_dump($response);

exit;

Expected behavior
From @gamadoleo:

but as I said this looping problem when executing want only occurs if l2m3u is set wrong, for example l2m3u = 1500
But the question is as follows, even with the wrong m3u would not be able to download the data or display an exception, because the situation is as follows when I get no error I get lost without knowing which one is really the error

Can't get on-login parameter

Hi, i am using RouterOS 6.45.8. Trying to get list of hotspot user profile

Code

$query = (new Query('/ip/hotspot/user/profile/print'));
$response = $this->client->query($query)->read();
print_r($response);

But i can't find on-login parameter on the response

Result

photo_2020-07-04_11-07-24

User Profile from Winbox

Screenshot from 2020-07-04 11-08-14

how to send write qury

i need to send the below using this library but doesnt seem to work, if i type it from winbox terminal it works:
radius remove [find]

i tried using
$out = $client->write('/radius/remove [find]')->read();

A problem in queries with operators > and <.

Hello!
I have got a problem in working with queries to firewall connections which have operators > and <.
I use function qr on client with all three params.

$endpoint = '/ip/firewall/connection/print';
$where = [['protocol','tcp'],['reply-src-address','>','172.20.41.183:3388'],['reply-src-address','<','172.20.41.188:3390']];
$operations='&&';
$data = $client->qr($endpoint,$where,$operations);

I have analyzed my problem with the list of where filters.
I've noticed, that the code of Query.php build string with operators like:

?protocol=tcp
>?reply-src-address=172.20.41.183:3388
<?reply-src-address=172.20.41.188:3390

But according to the Wiki the lines should be:

?protocol=tcp
?>reply-src-address=172.20.41.183:3388
?>reply-src-address=172.20.41.188:3390

More, if I just use where filter ['protocol','=','tcp'] then I receive message from my router:
message=unknown parameter
The string was sent:
=?protocol=tcp
But should be either "?=protocol=tcp" or "?protocol=tcp"

Maybe there is another function in your library to use queries with certain operators?

remove user

don't work user

$out = $client->write(['/ip/hotspot/user/remove', '[find name=34342]'])->read();

Queries support

Need to add support of basic queries with methods like where, whereNot etc.
This objects should be as first argument of write method of client.

[FR] Add support for PHP 8

Version of RouterOS
N/A

To Reproduce
Package is not installable under PHP 8.

Expected behavior
Package should be compatible with the current stable release, i.e. 8

I did some work in #51 to see how badly Travis explodes.

Unable to establish socket session

Getting error on live server
Fatal error: Uncaught RouterOS\Exceptions\ClientException: Unable to establish socket session, Connection timed out RouterOS\Client->openSocket() #1 /home3/apptific/public_html/b2b_mikrotik/vendor/evilfreelancer/routeros-api-php/src/Client.php(60): RouterOS\Client->connect() #2 /home3/apptific/public_html/b2b_mikrotik/test.php(16): RouterOS\Client->__construct(Object(RouterOS\Config)) #3 {main} thrown in /home3/apptific/public_html/b2b_mikrotik/vendor/evilfreelancer/routeros-api-php/src/SocketTrait.php on line 63

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.