You are on page 1of 84

1

API PHP class


http://wiki.mikrotik.com/wiki/API_PHP_class#Example_1
This is PHP class for working with RouterOS v3 API. You can take it, edit it and use it as you need. NOTE - The class as shown does not work for large replies

Contents
[hide]

o o

1 Author 2 Contributors 3 Changelog 4 Class 5 Example 1 5.1 Output 6 Example 2 6.1 Output 7 Example 3 8 Example 4 9 Example 5 10 See also

Author
Denis Basta (Denis [dot] Basta [at] gmail [dot] com)

Contributors
Nick Barnes Ben Menking (ben [at] infotechsc [dot] com) Jeremy Jefferson (http://jeremyj.com) Cristian Deluxe (djcristiandeluxe [at] gmail [dot] com)

Changelog
1.0 Denis Basta (Denis [dot] Basta [at] gmail [dot] com) First PHP Class released from author 1.1 Nick Barnes read() function altered to take into account the placing of the "!done" reply and also correct calculation of the reply length.

2
1.2 Ben Menking (ben [at] infotechsc [dot] com) read() function altered removed echo statement that dumped byte data to screen 1.3 Jeremy Jefferson (http://jeremyj.com) January 8, 2010 Fixed write function in order to allow for queries to be executed 1.4 Cristian Deluxe (djcristiandeluxe [at] gmail [dot] com) November 17, 2011 comm() function altered, added the possibility of make regular exp queries. parse_response() and parse_response4smarty() functions altered to support a "single data" responses from server Added documentation to functions following PHPDoc guidelines Added version number (1.4) for follow the changes more easy

Class

<?php /***************************** * * RouterOS PHP API class v1.4 * Author: Denis Basta * Contributors: * * * * * * http://www.mikrotik.com * http://wiki.mikrotik.com/wiki/API_PHP_class * ******************************/ Nick Barnes Ben Menking (ben [at] infotechsc [dot] com) Jeremy Jefferson (http://jeremyj.com) Cristian Deluxe (djcristiandeluxe [at] gmail [dot] com)

class routeros_api

3
{ var $debug = false; var $error_no; number, if any var $error_str; if any var $attempts = 5; var $connected = false; var $delay = 3; seconds var $port = 8728; var $timeout = 3; timeout var $socket; // Show debug information // Variable for storing connection error

// Variable for storing connection error text,

// Connection attempt count // Connection state // Delay between connection attempts in

// Port to connect to // Connection attempt timeout and data read

// Variable for storing socket resource

/** * Print text for debug purposes * * @param string * * @return void */ function debug($text) { if ($this->debug) echo $text . "\n"; } $text Text to print

/** * *

4
* @param string * * @return void */ function encode_length($length) { if ($length < 0x80) { $length = chr($length); } else if ($length < 0x4000) { $length |= 0x8000; $length = chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } else if ($length < 0x200000) { $length |= 0xC00000; $length = chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } else if ($length < 0x10000000) { $length |= 0xE0000000; $length = chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } else if ($length >= 0x10000000) $length = chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); return $length; } $length

/** * Login to RouterOS * * @param string RouterOS server $ip Hostname (IP or domain) of the

5
* @param string * @param string * * @return boolean */ function connect($ip, $login, $password) { for ($ATTEMPT = 1; $ATTEMPT <= $this->attempts; $ATTEMPT++) { $this->connected = false; $this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $ip . ':' . $this->port . '...'); if ($this->socket = @fsockopen($ip, $this->port, $this>error_no, $this->error_str, $this->timeout)) { socket_set_timeout($this->socket, $this->timeout); $this->write('/login'); $RESPONSE = $this->read(false); if ($RESPONSE[0] == '!done') { 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; } } } If we are connected or not $login $password The RouterOS username The RouterOS password

6
} fclose($this->socket); } sleep($this->delay); } if ($this->connected) $this->debug('Connected...'); else $this->debug('Error...'); return $this->connected; }

/** * Disconnect from RouterOS * * @return void */ function disconnect() { fclose($this->socket); $this->connected = false; $this->debug('Disconnected...'); }

/** * Parse response from Router OS * * @param array * $response Response data

7
* @return array */ function parse_response($response) { if (is_array($response)) { $PARSED $CURRENT = array(); = null; Array with parsed data

$singlevalue = null; $count = 0;

foreach ($response as $x) { if (in_array($x, array( '!fatal', '!re', '!trap' ))) { if ($x == '!re') { $CURRENT =& $PARSED[]; } else $CURRENT =& $PARSED[$x][]; } else if ($x != '!done') { if (preg_match_all('/[^=]+/i', $x, $MATCHES)) { if ($MATCHES[0][0] == 'ret') { $singlevalue = $MATCHES[0][1]; } $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : ''); } } } if (empty($PARSED) && !is_null($singlevalue)) { $PARSED = $singlevalue;

8
} return $PARSED; } else return array(); }

/** * Parse response from Router OS * * @param array * * @return array */ function parse_response4smarty($response) { if (is_array($response)) { $PARSED = array(); Array with parsed data $response Response data

$CURRENT = null; $singlevalue = null; foreach ($response as $x) { if (in_array($x, array( '!fatal', '!re', '!trap' ))) { if ($x == '!re') $CURRENT =& $PARSED[]; else $CURRENT =& $PARSED[$x][]; } else if ($x != '!done') {

9
if (preg_match_all('/[^=]+/i', $x, $MATCHES)) { if ($MATCHES[0][0] == 'ret') { $singlevalue = $MATCHES[0][1]; } $CURRENT[$MATCHES[0][0]] = (isset($MATCHES[0][1]) ? $MATCHES[0][1] : ''); } } } foreach ($PARSED as $key => $value) { $PARSED[$key] = $this->array_change_key_name($value); } return $PARSED; if (empty($PARSED) && !is_null($singlevalue)) { $PARSED = $singlevalue; } } else { return array(); } }

/** * Change "-" and "/" from array key to "_" * * @param array * * @return array */ function array_change_key_name(&$array) { Array with changed key names $array Input array

10
if (is_array($array)) { foreach ($array as $k => $v) { $tmp = str_replace("-", "_", $k); $tmp = str_replace("/", "_", $tmp); if ($tmp) { $array_new[$tmp] = $v; } else { $array_new[$k] = $v; } } return $array_new; } else { return $array; } }

/** * Read data from Router OS * * @param boolean * * @return array */ function read($parse = true) { $RESPONSE = array(); while (true) { // Read the first byte of input which gives us some or all of the length // of the remaining reply. Array with parsed or unparsed data $parse Parse the data? default: true

11
$BYTE = ord(fread($this->socket, 1));

$LENGTH = 0; // If the first bit is set then we need to remove the first four bits, shift left 8 // and then read another byte in. // We repeat this for the second and third bits. // If the fourth bit is set, we need to remove anything left in the first byte // and then read in yet another byte. if ($BYTE & 128) { if (($BYTE & 192) == 128) { $LENGTH = (($BYTE & 63) << 8) + ord(fread($this>socket, 1)); } else { if (($BYTE & 224) == 192) { $LENGTH = (($BYTE & 31) << 8) + ord(fread($this>socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this->socket, 1)); } else { if (($BYTE & 240) == 224) { $LENGTH = (($BYTE & 15) << 8) + ord(fread($this->socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this>socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this>socket, 1)); } else { $LENGTH = ord(fread($this->socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this>socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this>socket, 1)); $LENGTH = ($LENGTH << 8) + ord(fread($this>socket, 1));

12
} } } } else { $LENGTH = $BYTE; } // If we have got more characters to read, read them in. if ($LENGTH > 0) { $_ = "";

$retlen = 0; while ($retlen < $LENGTH) { $toread = $LENGTH - $retlen; $_ .= fread($this->socket, $toread); $retlen = strlen($_); } $RESPONSE[] = $_; $this->debug('>>> [' . $retlen . '/' . $LENGTH . '] bytes read.'); } // If we get a !done, make a note of it. if ($_ == "!done") $receiveddone = true; $STATUS = socket_get_status($this->socket); if ($LENGTH > 0) $this->debug('>>> [' . $LENGTH . ', ' . $STATUS['unread_bytes'] . ']' . $_); if ((!$this->connected && !$STATUS['unread_bytes']) || ($this>connected && !$STATUS['unread_bytes'] && $receiveddone)) break; } if ($parse)

13
$RESPONSE = $this->parse_response($RESPONSE); return $RESPONSE; }

/** * Write (send) data to Router OS * * @param string $command A string with the command to send If we set an integer, the command

* @param mixed $param2 will send this data as a "tag"

* If we set it to boolean true, the funcion will send the comand and finish * If we set it to boolean false, the funcion will send the comand and wait for next command * * * @return boolean */ function write($command, $param2 = true) { if ($command) { $data = explode("\n", $command); foreach ($data as $com) { $com = trim($com); fwrite($this->socket, $this->encode_length(strlen($com)) . $com); $this->debug('<<< [' . strlen($com) . '] ' . $com); } if (gettype($param2) == 'integer') { fwrite($this->socket, $this->encode_length(strlen('.tag=' . $param2)) . '.tag=' . $param2 . chr(0)); Return false if no command especified Default: true

14
$this->debug('<<< [' . strlen('.tag=' . $param2) . '] .tag=' . $param2); } else if (gettype($param2) == 'boolean') fwrite($this->socket, ($param2 ? chr(0) : '')); return true; } else return false; }

/** * Write (send) data to Router OS * * @param string * @param array * * @return array */ function comm($com, $arr = array()) { $count = count($arr); $this->write($com, !$arr); $i = 0; foreach ($arr as $k => $v) { switch ($k[0]) { case "?": $el = "$k=$v"; break; case "~": $el = "$k~$v"; break; Array with parsed $com $arr A string with the command to send An array with arguments or queries

15
default: $el = "=$k=$v"; break; } $last = ($i++ == $count - 1); $this->write($el, $last); } return $this->read(); } } ?>

Example 1

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = true;

if ($API->connect('111.111.111.111', 'LOGIN', 'PASSWORD')) {

$API->write('/interface/getall');

$READ = $API->read(false); $ARRAY = $API->parse_response($READ);

16
print_r($ARRAY);

$API->disconnect();

?>

OR

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = true;

if ($API->connect('111.111.111.111', 'LOGIN', 'PASSWORD')) {

$API->write('/interface/getall'); $ARRAY = $API->read();

print_r($ARRAY);

$API->disconnect();

17
?>

OR

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = true;

if ($API->connect('111.111.111.111', 'LOGIN', 'PASSWORD')) {

$ARRAY = $API->comm('/interface/getall'); print_r($ARRAY);

$API->disconnect();

?>

Output
Array ( [0] => Array

18
( [.id] => *1 [name] => ether1 [mtu] => 1500 [type] => ether [running] => yes [dynamic] => no [slave] => no [comment] => [disabled] => no )

[1] => Array ( [.id] => *2 [name] => ether2 [mtu] => 1500 [type] => ether [running] => yes [dynamic] => no [slave] => no [comment] => [disabled] => no )

[2] => Array ( [.id] => *3 [name] => ether3 [mtu] => 1500

19
[type] => ether [running] => yes [dynamic] => no [slave] => no [comment] => ether3 [disabled] => no ) )

Example 2
Thanks a lot for this API, It help me a lot to write my php page for our support team to have access to wireless registration table.

$API->write('/interface/wireless/registration-table/print',false); $API->write('=stats=');

Output
Array ( [0] => Array ( [.id] => *147 [comment] => [interface] => AP101 [mac-address] => 00:0B:6B:37:58:33 [ap] => false [wds] => false [rx-rate] => 11Mbps [tx-rate] => 11Mbps

20
[packets] => 4043966,2669114 [bytes] => 3961713942,280551024 [frames] => 4043966,2669114 [frame-bytes] => 3937477458,264536340 [hw-frames] => 4500839,2669114 [hw-frame-bytes] => 256326637,349947988 [tx-frames-timed-out] => 0 [uptime] => 1w13:09:12 [last-activity] => 00:00:00.090 [signal-strength] => -73dBm@11Mbps [signal-to-noise] => 30 [strength-at-rates] => -73dBm@1Mbps 4m4s640ms,-73dBm@2Mbps 4m58s730ms,73dBm@5.5Mbps 42s450ms,-73dBm@11Mbps 90ms [tx-ccq] => 91 [p-throughput] => 5861 [ack-timeout] => 31 [last-ip] => 192.168.0.220 [802.1x-port-enabled] => true [wmm-enabled] => false ) [1] => Array ( ... ) ... )

Example 3
Adding vpn user

$API->comm("/ppp/secret/add", array(

21
"name" => "user",

"password" => "pass", "remote-address" => "172.16.1.10", "comment" "service" )); => "{new VPN user}", => "pptp",

Example 4
Find registration-table id for specified MAC

$ARRAY = $API->comm("/interface/wireless/registration-table/print", array( ".proplist"=> ".id", "?mac-address" => "00:0E:BB:DD:FF:FF", )); print_r($ARRAY);

Example 5
Count leases from specific IP Pool (using regexp count all IPs starting with 1.1.x.x)

$ARRAY = $API->comm("/ip/dhcp-server/lease/print", array( "count-only"=> "", "~active-address" => "1.1.", )); print_r($ARRAY);
or

$API->write('/ip/dhcp-server/lease/print', false); $API->write('=count-only=', false); $API->write('~active-address~"1.1."'); $ARRAY = $API->read();

22
print_r($ARRAY);
Returns a number with leases

See also
API PHP Telnet Class Template how to use PHP API
Category: API

Api php template


This is a php template for working with RouterOS v3 API.

Contents
[hide]

1 Requirements 2 Connected Clients (from the registration table) 3 Resources (cpu/mem/disk/version) 4 Registration Tables 5 Basic Interface List 6 Wireless Interface List 7 Hotspot Hosts List 8 See also

Requirements
1. It uses the php api Class found here : link API_PHP_class. 2. It is presented first in the forum here link Forum_link 3. overLIB popup JavaScript library is required for this and its included in the files (zip file) or can be found here:[1]

Connected Clients (from the registration table)

23
<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) { as necessery

// Change this

$API->write('/interface/wireless/registration-table/print',false); $API->write('=count-only=');

$READ = $API->read(false); $ARRAY = $API->parse_response($READ);

echo "Number of connected clients:" . substr($READ[1],5);

$API->disconnect();

?>

Resources (cpu/mem/disk/version)

24
<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) { necessery

// Change this as

$ARRAY = $API->comm("/system/resource/print");

$first = $ARRAY['0']; $memperc = ($first['free-memory']/$first['total-memory']); $hddperc = ($first['free-hdd-space']/$first['total-hdd-space']); $mem = ($memperc*100); $hdd = ($hddperc*100); echo "Mikrotik RouterOs 4.16 Resources"; echo "<br />"; echo "<table width=550 border=0 align=center>";

echo "<tr><td>Platform, board name and Ros version is:</td><td>" . $first['platform'] . " - " . $first['board-name'] . " - " . $first['version'] . " - " . $first['architecture-name'] . "</td></tr><br />"; echo "<tr><td>Cpu and available cores:</td><td>" . $first['cpu'] . " at " . $first['cpu-frequency'] . " Mhz with " . $first['cpu-count'] . " core(s) " . "</td></tr><br />"; echo "<tr><td>Uptime is:</td><td>" . $first['uptime'] . " (hh/mm/ss)" . "</td></tr><br />";

25
echo "<tr><td>Cpu Load is:</td><td>" . $first['cpu-load'] . " %" . "</td></tr><br />"; echo "<tr><td>Total,free memory and memory % is:</td><td>" . $first['totalmemory'] . "Kb - " . $first['free-memory'] . "Kb - " . number_format($mem,3) . "% </td></tr><br />"; echo "<tr><td>Total,free disk and disk % is:</td><td>" . $first['total-hddspace'] . "Kb - " . $first['free-hdd-space'] . "Kb - " . number_format($hdd,3) . "% </td></tr><br />"; echo "<tr><td>Sectors (write,since reboot,bad blocks):</td><td>" . $first['write-sect-total'] . " - " . $first['write-sect-since-reboot'] . " - " . $first['bad-blocks'] . "% </td></tr><br />";

echo "</table>";

echo "<br />"; echo "<br />"; echo "<br />"; echo "<br />Debug:"; echo "<br />";

$API->disconnect();

?>

Registration Tables

<?php function popup( $text, $popup ) { ?>

26
<a href="javascript:void(0);" onmouseover="return overlib('<?php echo($popup); ?> ');" onmouseout="return nd();"><?php echo($text); ?></a> <?php } ?>

<script type="text/javascript" src="overlib/overlib.js"><!-- overLIB (c) Erik Bosrup --> </script>

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) { necessery

// Change this as

$ARRAY = $API->comm("/interface/wireless/registration-table/print");

echo "<table width=100% border=1>";

echo "<tr><td align=left size=2>Id</td><td size=2>iface</td><td size=2>macaddress</td><td size=1>Ap</td><td size=1>wds</td><td>rx-rate</td><td>txrate</td><td>Data</td><td>uptime</td><td>Last Activity</td><td>signal strength</td><td>signal to noise</td><td>strength at rates</td><td>tx ccq</td><td>pthroughput</td><td>ack timeout</td><td>last ip</td><td>802.1x port en.</td><td>authentication type</td><td>encryption</td><td>group encryption</td><td>wmm</td></tr>";

27

echo "<tr><td align=left>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['.id'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['interface'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

28
echo "<font color=#04B404 size=2>" . $regtable['mac-address'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['ap']=="true") { echo "<font color=#04B404 size=2>" . $regtable['ap'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['ap'] ."</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['wds']=="true") { echo "<font color=#04B404 size=2>" . $regtable['wds'] . "</font><br>"; }else{

29
echo "<font color=#FF0000 size=2>". $regtable['wds'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#000099 size=2>" . $regtable['rx-rate'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['tx-rate'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

30
$regtable = $ARRAY[$i]; echo popup('Data', 'Packets ' . $regtable['packets'] . '<br/>Bytes ' . $regtable['bytes'] . '<br/>Frames ' . $regtable['frames'] . '<br/>FrameBytes ' . $regtable['frame-bytes'] . '<br/>hw-frames ' . $regtable['hwframes'] . '<br/>hw-frame-bytes ' . $regtable['hw-frame-bytes'] . '<br/>tx-frames-timed-out ' . $regtable['tx-frames-timed-out']);

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=2>" . $regtable['uptime'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=2>" . $regtable['last-activity'] . "</font><br>"; }

echo "</td><td>";

31

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#880000 size=2>" . $regtable['signal-strength'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#A00000 size=2>" . $regtable['signal-to-noise'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; $z=$regtable['wds'];

if ($z==true) { echo popup('Rates', $regtable['strength-at-rates'] ) ;

32
} if ($z==false) { echo } else { echo " "; } } popup('Rates', $regtable['strength-at-rates'] ) ;

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['tx-ccq'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['p-throughput'] . "</font><br>"; }

33

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['ack-timeout'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['last-ip'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['802.1x-port-enabled']=="true") {

34
echo "<font color=#04B404 size=2>" . $regtable['802.1x-portenabled'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['802.1x-portenabled'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#CC0000 size=2>" . $regtable['authenticationtype'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#CC0000 size=2>" . $regtable['encryption'] . "</font><br>"; }

echo "</td><td>";

35
for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#CC0000 size=2>" . $regtable['group-encryption'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['wmm-enabled']=="true") { echo "<font color=#04B404 size=2>" . $regtable['wmm-enabled'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['wmmenabled'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

36
echo "<font color=#CC0000 size=2>" . $regtable['comment'] . "</font><br>"; }

echo "</td><td>"; echo "</table>"; echo "<br />Debug:"; echo "<br />";

$API->disconnect();

?>

Basic Interface List

<?php function popup( $text, $popup ) { ?> <a href="javascript:void(0);" onmouseover="return overlib('<?php echo($popup); ?> ');" onmouseout="return nd();"><?php echo($text); ?></a> <?php } ?>

37
<script type="text/javascript" src="overlib/overlib.js"><!-- overLIB (c) Erik Bosrup --> </script>

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) {

$ARRAY = $API->comm("/interface/getall");

echo "<table width=100% border=1>";

echo "<tr><td align=left size=3>Id</td><td size=3>name</td><td size=3>type</td><td size=3>dynamic</td><td size=3>disabled</td><td>mtu</td><td>l2mtu</td><td>comment</td></tr>";

echo "<tr><td align=left>";

for ($i=0; $i<20; $i++)

{ $regtable = $ARRAY[$i];

38
echo "<font color=#04B404 size=3>" . $regtable['.id'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['name'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['type'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

39
if ($regtable['dynamic']=="true") { echo "<font color=#04B404 size=3>" . $regtable['dynamic'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=3>". $regtable['dynamic'] ."</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['disabled']=="true") { echo "<font color=#04B404 size=3>" . $regtable['disabled'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=3>". $regtable['disabled'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

40
$regtable = $ARRAY[$i];

echo "<font color=#000099 size=3>" . $regtable['mtu'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['l2mtu'] . "</font><br>"; }

echo "</td><td>";

echo "</table>"; echo "<br />Debug:"; echo "<br />"; print_r($ARRAY); $API->disconnect();

?>

Wireless Interface List

41

<?php function popup( $text, $popup ) { ?> <a href="javascript:void(0);" onmouseover="return overlib('<?php echo($popup); ?> ');" onmouseout="return nd();"><?php echo($text); ?></a> <?php } ?>

<script type="text/javascript" src="overlib/overlib.js"><!-- overLIB (c) Erik Bosrup --> </script>

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) {

$ARRAY = $API->comm("/interface/wireless/print");

echo "<table width=100% border=1>";

42
echo "<tr><td align=left size=2>Id</td><td size=2>name</td><td size=2>mtu</td><td size=1>mac-address</td><td size=1>arp</td><td width=100 size=5>interface type</td><td>mode</td><td>ssid</td><td>frequency</td><td>band</td><td>scan list</td><td>antenna mode</td><td>wds mode</td><td>wds default bridge</td><td>wds ignore ssid</td><td>default authentication</td><td>default forwarding</td><td>default ap tx limit</td><td>default client tx limit</td><td>hide ssid</td><td>security profile</td><td>compression</td></tr>";

echo "<tr><td align=left>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['.id'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['name'] . "</font><br>"; }

echo "</td><td>";

43

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['mtu'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['mac-address'] . "</font><br>";

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['arp']=="true") { echo "<font color=#04B404 size=2>" . $regtable['arp'] . "</font><br>";

44
}else{ echo "<font color=#FF0000 size=2>". $regtable['arp'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#000099 size=1>" . $regtable['interface-type'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['mode'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

45
{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=2>" . $regtable['ssid'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=2>" . $regtable['frequency'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#880000 size=2>" . $regtable['band'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

46

{ $regtable = $ARRAY[$i];

echo "<font color=#A00000 size=2>" . $regtable['scan-list'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=2>" . $regtable['antenna-mode'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; echo popup('WDS', 'WDS Mode ' . $regtable['wds-mode'] . '<br/>WDS Default Bridge ' . $regtable['wds-default-bridge'] . '<br/>WDS Ignore SSID ' . $regtable['wds-ignore-ssid']);

echo "</td><td>";

47

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['default-authentication']=="true") { echo "<font color=#04B404 size=2>" . $regtable['defaultauthentication'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['defaultauthentication'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['default-forwarding']=="true") { echo "<font color=#04B404 size=2>" . $regtable['defaultforwarding'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['defaultforwarding'] ."</font><br>"; } }

echo "</td><td>";

48

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#FF0000 size=2>". $regtable['default-ap-txlimit'] ."</font><br>";

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#FF0000 size=2>". $regtable['default-client-txlimit'] ."</font><br>";

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['hide-ssid']=="true") {

49
echo "<font color=#04B404 size=2>" . $regtable['hide-ssid'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['hidessid'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#CC0000 size=2>" . $regtable['security-profile'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['compression']=="true") { echo "<font color=#04B404 size=2>" . $regtable['compression'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['compression'] ."</font><br>";

50
} }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['running']=="true") { echo "<font color=#04B404 size=2>" . $regtable['running'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['running'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['disabled']=="true") { echo "<font color=#04B404 size=2>" . $regtable['disabled'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=2>". $regtable['disabled'] ."</font><br>";

51
} }

echo "</td><td>";

echo "</table>"; echo "<br />Debug:"; echo "<br />"; print_r($ARRAY);

$API->disconnect();

?>

Hotspot Hosts List

<?php function popup( $text, $popup ) { ?> <a href="javascript:void(0);" onmouseover="return overlib('<?php echo($popup); ?> ');" onmouseout="return nd();"><?php echo($text); ?></a> <?php } ?>

52

<script type="text/javascript" src="overlib/overlib.js"><!-- overLIB (c) Erik Bosrup --> </script>

<?php

require('routeros_api.class.php');

$API = new routeros_api();

$API->debug = false;

if ($API->connect('192.168.1.2', 'api', 'api1234')) {

$ARRAY = $API->comm("/ip/hotspot/host/print");

echo "<table width=100% border=1>";

echo "<tr><td align=left size=3>Id</td><td size=3>mac-address</td><td size=3>address</td><td size=3>toaddress</td><td>server</td><td>uptime</td><td>keepalivetimeout</td><td>foundby</td><td>DHCP</td><td>authorized</td><td>bypassed</td><td>comment</td></t r>";

echo "<tr><td align=left>";

for ($i=0; $i<250; $i++)

53
$regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['.id'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['mac-address'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['address'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

54
{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['to-address'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#000099 size=3>" . $regtable['server'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=3>" . $regtable['uptime'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

55

{ $regtable = $ARRAY[$i];

echo "<font color=#003300 size=3>" . $regtable['keepalive-timeout'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#880000 size=3>" . $regtable['found-by'] . "</font><br>"; }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['DHCP']=="true") { echo "<font color=#04B404 size=3>" . $regtable['DHCP'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=3>". $regtable['DHCP'] ."</font><br>";

56
} }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['authorized']=="true") { echo "<font color=#04B404 size=3>" . $regtable['authorized'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=3>". $regtable['authorized'] ."</font><br>"; } }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i]; if ($regtable['bypassed']=="true") { echo "<font color=#04B404 size=3>" . $regtable['bypassed'] . "</font><br>"; }else{ echo "<font color=#FF0000 size=3>". $regtable['bypassed'] ."</font><br>";

57
} }

echo "</td><td>";

for ($i=0; $i<250; $i++)

{ $regtable = $ARRAY[$i];

echo "<font color=#04B404 size=3>" . $regtable['comment'] . "</font><br>"; }

echo "</td><td>";

echo "</table>"; echo "<br />Debug:"; echo "<br />"; print_r($ARRAY);

$API->disconnect();

?>

See also
API

58
API PHP class

Manual:API
(Redirected from API)

Contents
[hide]

1 Summary 2 Protocol 2.1 API words

o o o o o o o o o

2.1.1 Command word 2.1.2 Attribute word 2.1.3 API attribute word 2.1.4 Query word 2.1.5 Reply word 2.2 API sentences

3 Initial login 4 Tags 5 Command description 5.1 Queries 5.2 OID 6 Command examples 6.1 /system/package/getall 6.2 /user/active/listen 6.3 /cancel, simultaneous commands 7 Example client 8 See also 8.1 API examples in the Wiki 8.2 API examples on the MikroTik Forum 8.3 API exmaples elsewhere

Summary
Application Programmable Interface (API) allows users to create custom software solutions to communicate with RouterOS to gather information, adjust configuration and manage router. API closely follows syntax from command line interface (CLI). It can be used to create translated or custom configuration tools to aid ease of use running and managing routers with RouterOS. To use API RouterOS version 3.x or newer is required.

59
By default API uses port #8728 and service is disabled. More on service management see in corresponding manual section. Corresponding service name is api

Protocol
Communication with router is done by sending sentences to the router and receiving one or more sentences in return. Sentence is sequence of words terminated by zero length word. Word is part of sentence encoded in certain way - encoded length and data. Communication happen by sending sentences to the router and receiving replies to sent sentences. Each sentence sent to router using API should contain command as a first word followed by words in no particular order, end of sentence is marked by zero length word. When router receives full sentence (command word, no or more attribute words and zero length word) it is evaluated and executed, then reply is formed and returned.

API words
Words are part of sentence. Each word has to be encoded in certain way - length of the world followed by word content. Length of the word should be given as count of bytes that are going to be sent. Length of the word is encoded as follows: Value of length 0 <= len <= 0x7F 0x80 <= len <= 0x3FFF 0x4000 <= len <= 0x1FFFFF 0x200000 <= len <= 0xFFFFFFF len >= 0x10000000 # of bytes 1 2 3 4 5 Encoding len, lowest byte len | 0x8000, two lower bytes len | 0xC00000, three lower bytes len | 0xE0000000 0xF0 and len as four bytes

Each word is encoded as length, followed by that many bytes of content; Words are grouped into sentences. End of sentence is terminated by zero length word; Scheme allows encoding of length up to 0x7FFFFFFFFF, only four byte length is supported; Bytes of len are sent most significant first (network order); If first byte of word is >= 0xF8, then it is a reserved control byte. After receiving unknown
control byte API client cannot proceed, because it cannot know how to interpret following bytes;

Currently control bytes are not used;


In general words can be described like this <<encoded word length><word content>>. Word content can be separated in 5 parts: command word, attribute word, API attribute word. query word and reply word

Command word
First word in sentence is has to be command followed by attribute worlds and zero length word or terminating word. Name of command word should begin with '/'. Names of commands closely follow CLI, with spaces replaced with '/'. There are commands that are specific to API;

60
Command word structure in strict order:

encoded length content prefix / CLI converted command

API specific commands:

getall login cancel


Command word concent examples:

/login /ip/address/getall /user/active/listen /interface/vlan/remove /system/reboot

Attribute word
Each command wordhave its own list of attribute words depending on content. Atribute word structure consists of 5 parts in this order:

encoded length content prefix equals sigh - = attribute name separating equals sign - = value of attribute if there is one. It is possible that attribute does not have a value

Note: Value can hold multiple equal signs in the value of attribute word since the way word is encoded

61

Note: Value can be empty

Examples without encoded length prefix:

=address=10.0.0.1 =name=iu=c3Eeg =disable-running-check=yes

Warning: Order of attribute words and API parameters is not important and should not be relied on

API attribute word


API attribute word structure is in strict order:

encoded length content prefix with dot . attribute name name postfixed with equals =sign attribute value
Currently the only such API attribute is tag.

Note: If sentence contain API attribute word tag then each returned sentence in reply from router to that tagged sentence will be tagged with same tag.

Query word
Senteces can have additional query paramteres that restrict their scope. They are explained in detail in separate section.

62
Example of sentence using query word attributes:

/interface/print ?type=ether ?type=vlan ?#|!

Query words begin with '?'. Currently only print command handles query words.

Warning: Order of query words is significant

Reply word
It is sent only by the router. It is only sent in response to full sentence send by the client.

First word of reply begins with '!'; Each sentence sent generates at least one reply (if connection does not get terminated); Last reply for every sentence is reply that has first word !done; Errors and exceptional conditions begin with !trap; Data replies begin with !re If API connection is closed, RouterOS sends !fatal with reason as reply and then closes the
connection;

API sentences
API sentence is main object of communication using API.

Empty sentences are ignored. Sentence is processed after receiving zero length word. There is a limit on number and size of sentences client can send before it has logged in. Order of attribute words should not be relied on. As order and count is changeable
by .proplist attribute.

Sentence structure is as follows:


First world should contain command word; Should contain zero length word to terminate the sentence;

63

Can contain none or several attribute words. There is no particular order at what

attribute words has to be sent in the sentence, order is not important for attribute words;

Can contain none or several query words. Order of query words in the sentence is

important.

Note: Zero length word terminates the sentence. If it is not provided router will not start to evaluate sent words and will consider all the input as part of the same sentence.

Initial login
/login !done =ret=ebddd18303a54111e2dea05a92ab46b4 /login =name=admin =response=001ea726ed53ae38520c8334f82d44c9f2 !done

First, clients sends /login command. Note that each command and response ends with an empty word. Reply contains =ret=challenge argument. Client sends second /login command, with =name=username and =response=response. In case of error, reply contains =ret=error message. In case of successful login client can start to issue commands.

Tags
It is possible to run several commands simultaneously, without waiting for previous one to
complete. If API client is doing this and needs to differentiate command responses, it can use 'tag' API parameter in command sentences.

If you include 'tag' parameter with non-empty value in command sentence, then 'tag'
parameter with exactly the same value will be included in all responses generated by this command.

If you do not include 'tag' parameter or it's value is empty, then all responses for this
command will not have 'tag' parameter.

64

Command description
/cancel
optional argument: =tag=tag of command to cancel, without it cancels all

running commands

does not cancel itself all canceled commands are interruped and in the usual case generate '!trap' and '!

done' responses

please note that /cancel is separate command and can have it's own unique '.tag'

parameter, that is not related to '=tag' argument of this command

listen listen command is avaliable where console print command is available, but it does

not have expected effect everywhere (i.e. may not work)

!re sentences are generated as something changes in particular item list


when item is deleted or dissapears in any other way, the '!re' sentence includes value

'=.dead=yes'

getall

This command does not terminate. To terminate it use /cancel command.

getall command is available where console print command is available. Since

version 3.21 getall is an alias for print.

print

replies contain =.id=Item internal number property.

API print command differs from the console counterpart in the following ways:

where argument is not supported. Items can be filtered using query words

(see below).

.proplist argument is a comma separated list of property names that

should be included for the returned items.


defined.

returned items may have additional properties. order of returned properties is not defined. if list contains duplicate entries, handling of such entries is not

if propery is present in .proplist, but absent from the item, then

that item does not have this property value (?name will evaluate to false for that item).

if .proplist is absent, all properties are included as requested by

print command, even those that have slow access time (such as file contents and

65
perfomance counters). Thus use of .proplist is encouraged. Omission of .proplist may have high perfomance penalty if =detail= argument is set.

Queries
print command accepts query words that limit set of returned sentences. This feature is available
since RouterOS 3.21.

Query words begin with '?'. Order of query words is significant. Query is evaluated starting from the first word. Query is evaluated for each item in the list. If query succeeds, item is processed, if query fails,
item is ignored.

Query is evaluated using a stack of boolean values. Initially stack contains infinite amount of
'true' values. At the end of evaluation, if stack contains at least one 'false' value, query fails.

Query words operate according to the following rules:


Query ?name ?-name ?name=x ?=name=x ?<name=x ?>name=x Desciption pushes 'true' if item has value of property name, 'false' if it does not. pushes 'true' if item does not have value of property name, 'false' otherwise. pushes 'true' if property name has value equal to x, 'false' otherwise. pushes 'true' if property name has value less than x, 'false' otherwise. pushes 'true' if property name has value greater than x, 'false' otherwise.

? applies operations to the values in the stack. #operations

operation string is evaluated left to right. sequence of decimal digits followed by any other character or end of word is
interpreted as a stack index. top value has index 0.

index that is followed by a character pushes copy of value at that index. index that is followed by the end of word replaces all values with the value at
that index.

! character replaces top value with the opposite. & pops two values and pushes result of logical 'and' operation. | pops two values and pushes result of logical 'or' operation. . after an index does nothing. . after another character pushes copy of top value.
Examples:

Get all ethernet and VLAN interfaces:

/interface/print

66
?type=ether ?type=vlan ?#|

Get all routes that have non-empty comment:

/ip/route/print ?>comment=

OID
print command can return OID values for properties that are available in SNMP. This feature
appeared in 3.23 version. In console, OID values can be seen by running 'print oid' command. In API, these properties have name that ends with ".oid", and can be retrieved by adding their name to the value of '.proplist'. An example: /system/resource/print =.proplist=uptime,cpu-load,uptime.oid,cpu-load.oid !re =uptime=01:22:53 =cpu-load=0 =uptime.oid=.1.3.6.1.2.1.1.3.0 =cpu-load.oid=.1.3.6.1.2.1.25.3.3.1.2.1 !done

Command examples
/system/package/getall
/system/package/getall !re =.id=*5802 =disabled=no =name=routeros-x86 =version=3.0beta2 =build-time=oct/18/2006 16:24:41 =scheduled= !re =.id=*5805 =disabled=no =name=system =version=3.0beta2 =build-time=oct/18/2006 17:20:46 =scheduled=

67
... more !re sentences ... !re =.id=*5902 =disabled=no =name=advanced-tools =version=3.0beta2 =build-time=oct/18/2006 17:20:49 =scheduled= !done

/user/active/listen
/user/active/listen !re =.id=*68 =radius=no =when=oct/24/2006 08:40:42 =name=admin =address=0.0.0.0 =via=console !re =.id=*68 =.dead=yes ... more !re sentences ...

/cancel,
/login

simultaneous commands

!done =ret=856780b7411eefd3abadee2058c149a3 /login =name=admin =response=005062f7a5ef124d34675bf3e81f56c556 !done -- first start listening for interface changes (tag is 2) /interface/listen .tag=2 -- disable interface (tag is 3) /interface/set =disabled=yes =.id=ether1 .tag=3 -- this is done for disable command (tag 3) !done .tag=3 -- enable interface (tag is 4)

68
/interface/set =disabled=no =.id=ether1 .tag=4 -- this update is generated by change made by first set command (tag 3) !re =.id=*1 =disabled=yes =dynamic=no =running=no =name=ether1 =mtu=1500 =type=ether .tag=2 -- this is done for enable command (tag 4) !done .tag=4 -- get interface list (tag is 5) /interface/getall .tag=5 -- this update is generated by change made by second set command (tag 4) !re =.id=*1 =disabled=no =dynamic=no =running=yes =name=ether1 =mtu=1500 =type=ether .tag=2 -- these are replies to getall command (tag 5) !re =.id=*1 =disabled=no =dynamic=no =running=yes =name=ether1 =mtu=1500 =type=ether .tag=5 !re =.id=*2 =disabled=no =dynamic=no =running=yes =name=ether2 =mtu=1500 =type=ether .tag=5 -- here interface getall ends (tag 5) !done

69
.tag=5 -- stop listening - request to cancel command with tag 2, cancel itself uses tag 7 /cancel =tag=2 .tag=7 -- listen command is interrupted (tag 2) !trap =category=2 =message=interrupted .tag=2 -- cancel command is finished (tag 7) !done .tag=7 -- listen command is finished (tag 2) !done .tag=2

Example client
this is simple API client in Python2 example for Python3 usage: api.py ip-address username password after that type words from keyboard, terminating them with newline Since empty word terminates sentence, you should press enter twice after last word before
sentence will be sent to router.

#!/usr/bin/python

import sys, posix, time, md5, binascii, socket, select

class ApiRos: "Routeros api" def __init__(self, sk): self.sk = sk self.currenttag = 0

70
def login(self, username, pwd): for repl, attrs in self.talk(["/login"]): chal = binascii.unhexlify(attrs['=ret']) md = md5.new() md.update('\x00') md.update(pwd) md.update(chal) self.talk(["/login", "=name=" + username, "=response=00" + binascii.hexlify(md.digest())])

def talk(self, words): if self.writeSentence(words) == 0: return r = [] while 1: i = self.readSentence(); if len(i) == 0: continue reply = i[0] attrs = {} for w in i[1:]: j = w.find('=', 1) if (j == -1): attrs[w] = '' else: attrs[w[:j]] = w[j+1:] r.append((reply, attrs)) if reply == '!done': return r

def writeSentence(self, words): ret = 0 for w in words:

71
self.writeWord(w) ret += 1 self.writeWord('') return ret

def readSentence(self): r = [] while 1: w = self.readWord() if w == '': return r r.append(w)

def writeWord(self, w): print "<<< " + w self.writeLen(len(w)) self.writeStr(w)

def readWord(self): ret = self.readStr(self.readLen()) print ">>> " + ret return ret

def writeLen(self, l): if l < 0x80: self.writeStr(chr(l)) elif l < 0x4000: l |= 0x8000 self.writeStr(chr((l >> 8) & 0xFF)) self.writeStr(chr(l & 0xFF)) elif l < 0x200000:

72
l |= 0xC00000 self.writeStr(chr((l >> 16) & 0xFF)) self.writeStr(chr((l >> 8) & 0xFF)) self.writeStr(chr(l & 0xFF)) elif l < 0x10000000: l |= 0xE0000000 self.writeStr(chr((l >> 24) & 0xFF)) self.writeStr(chr((l >> 16) & 0xFF)) self.writeStr(chr((l >> 8) & 0xFF)) self.writeStr(chr(l & 0xFF)) else: self.writeStr(chr(0xF0)) self.writeStr(chr((l >> 24) & 0xFF)) self.writeStr(chr((l >> 16) & 0xFF)) self.writeStr(chr((l >> 8) & 0xFF)) self.writeStr(chr(l & 0xFF))

def readLen(self): c = ord(self.readStr(1)) if (c & 0x80) == 0x00: pass elif (c & 0xC0) == 0x80: c &= ~0xC0 c <<= 8 c += ord(self.readStr(1)) elif (c & 0xE0) == 0xC0: c &= ~0xE0 c <<= 8 c += ord(self.readStr(1)) c <<= 8

73
c += ord(self.readStr(1)) elif (c & 0xF0) == 0xE0: c &= ~0xF0 c <<= 8 c += ord(self.readStr(1)) c <<= 8 c += ord(self.readStr(1)) c <<= 8 c += ord(self.readStr(1)) elif (c & 0xF8) == 0xF0: c = ord(self.readStr(1)) c <<= 8 c += ord(self.readStr(1)) c <<= 8 c += ord(self.readStr(1)) c <<= 8 c += ord(self.readStr(1)) return c

def writeStr(self, str): n = 0; while n < len(str): r = self.sk.send(str[n:]) if r == 0: raise RuntimeError, "connection closed by remote end" n += r

def readStr(self, length): ret = '' while len(ret) < length: s = self.sk.recv(length - len(ret))

74
if s == '': raise RuntimeError, "connection closed by remote end" ret += s return ret

def main(): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((sys.argv[1], 8728)) apiros = ApiRos(s); apiros.login(sys.argv[2], sys.argv[3]);

inputsentence = []

while 1: r = select.select([s, sys.stdin], [], [], None) if s in r[0]: # something to read in socket, read sentence x = apiros.readSentence()

if sys.stdin in r[0]: # read line from input and strip off newline l = sys.stdin.readline() l = l[:-1]

# if empty line, send sentence and start with new # otherwise append to input sentence if l == '': apiros.writeSentence(inputsentence) inputsentence = [] else: inputsentence.append(l)

75

if __name__ == '__main__': main()

Example run:

debian@localhost:~/api-test$ ./api.py 10.0.0.1 admin '' <<< /login <<< >>> !done >>> =ret=93b438ec9b80057c06dd9fe67d56aa9a >>> <<< /login <<< =name=admin <<< =response=00e134102a9d330dd7b1849fedfea3cb57 <<< >>> !done >>> /user/getall

<<< /user/getall <<< >>> !re >>> =.id=*1 >>> =disabled=no >>> =name=admin >>> =group=full >>> =address=0.0.0.0/0 >>> =netmask=0.0.0.0 >>> >>> !done

76
>>>

See also
API command notes

API examples in the Wiki


in PHP in Delphi #1 in Delphi #2 in C API in C++ in C# in Flash Actionscript 3 in Ruby on rails in VB .NET in java in NodeJS Python3 in C using winsock

API examples on the MikroTik Forum


in Perl by Hugh in Delphi by Rodolfo in Delphi #2 by Chupaka in NodeJS by Trakkasure in VB by lucho512 on PHP for sparks framework by vthinkteam

API exmaples elsewhere


in .NET (C#) high-level api solution by danikf C++ libraries in PHP by boen_robot
Categories: API | Manual | System | Case Studies

77

PHP Telnet Class


Class that allows you to send commands via php and telnet should possibly be able to modify for ssh but could not get ssh compiled into my PHP :)

<?php header("Content-Type: text/plain"); /* * RouterOS API * Based on the code of SpectatorCN at http://forum.mikrotik.com/viewtopic.php?f=9&t=32957 * Modified by Ali Damji http://forum.mikrotik.com/viewtopic.php?f=9&t=33690 * Modified by Tim Haak * Free to modify, distribute, do whatever. * */ class phpMikrotikTelnet { //You may be able to lower this for single commands but needs to be high when running lots of commands var $TimeOut=125000; var $fp; var $echo=true;

function phpMikrotikTelnet($host, $username, $password,$echo=true) { $this->routeros_connect($host, $username, $password); }

function routeros_connect($host, $username, $password) {

78

$header1=chr(0xFF).chr(0xFB).chr(0x1F).chr(0xFF).chr(0xFB).chr(0x20).chr(0x FF).chr(0xFB).chr(0x18).chr(0xFF).chr(0xFB).chr(0x27).chr(0xFF).chr(0xFD).c hr(0x01).chr(0xFF).chr(0xFB).chr(0x03).chr(0xFF).chr(0xFD).chr(0x03).chr(0x FF).chr(0xFC).chr(0x23).chr(0xFF).chr(0xFC).chr(0x24).chr(0xFF).chr(0xFA).c hr(0x1F).chr(0x00).chr(0x50).chr(0x00).chr(0x18).chr(0xFF).chr(0xF0).chr(0x FF).chr(0xFA).chr(0x20).chr(0x00).chr(0x33).chr(0x38).chr(0x34).chr(0x30).c hr(0x30).chr(0x2C).chr(0x33).chr(0x38).chr(0x34).chr(0x30).chr(0x30).chr(0x FF).chr(0xF0).chr(0xFF).chr(0xFA).chr(0x27).chr(0x00).chr(0xFF).chr(0xF0).c hr(0xFF).chr(0xFA).chr(0x18).chr(0x00).chr(0x41).chr(0x4E).chr(0x53).chr(0x 49).chr(0xFF).chr(0xF0);

$header2=chr(0xFF).chr(0xFC).chr(0x01).chr(0xFF).chr(0xFC).chr(0x22).chr(0x FF).chr(0xFE).chr(0x05).chr(0xFF).chr(0xFC).chr(0x21); $this->fp=fsockopen($host,23); fputs($this->fp,$header1); usleep(125000); fputs($this->fp,$header2); usleep(125000); $this->write_to_telnet($username."+ct"); $this->write_to_telnet($password); $this->read_from_telnet(); }

function routeros_cmd($command) { //$command = str_replace(";\n",';',$command); //echo $command."\n"; $commands = explode("\n",$command); reset($commands); foreach ($commands as $cmd) { if ($this->echo) echo $cmd."\n";

79
flush(); $this->write_to_telnet(trim($cmd)); $read = $this->read_from_telnet()."\n"; if ($this->echo) echo $read; flush(); } return $rez; }

# Telnet Related function write_to_telnet($text) { fputs($this->fp,$text."\r\n"); usleep($this->TimeOut); return true; }

function read_from_telnet() { $output = ""; $count = 0; $count2 = 0; do{ $char =fread($this->fp, 1); $output .= $char; if($char==">") $count++; if($count==1) break; if($char==".") $count2++; if($count2==3) break; } while(1==1);

80
$output=preg_replace("/^.*?\n(.*)\n[^\n]*$/","$1",$output); $o=explode("\n",$output); for($i=1;$i<=count($o)-2;$i++) $op.=$o[$i]."\n"; return $op; }

function close() { fclose($this->fp); }

$cmd = ' /queue type remove pfifo remove pfifo_long remove red remove sfq remove pcq_game remove pcq_rest remove pcq_default add kind=pfifo name=pfifo pfifo-limit=50 add kind=pfifo name=pfifo_long pfifo-limit=250 add kind=sfq name=sfq sfq-allot=1514 sfq-perturb=5 add kind=red name=red red-avg-packet=1000 red-burst=40 red-limit=180 redmax-threshold=100 red-min-threshold=30 #Short que better latency add kind=pcq name=pcq_game pcq-rate=0 pcq-classifier=dst-address pcqlimit=20 pcq-total-limit=500

81
add kind=pcq name=pcq_rest pcq-rate=0 pcq-classifier=dst-address pcqlimit=200 pcq-total-limit=8000 add kind=pcq name=pcq_default pcq-rate=0 pcq-classifier=dst-address pcqlimit=50 pcq-total-limit=2000

:foreach intId in=[/interface wireless find] do={ :local intname [/interface wireless get $intId name];

\ \

:local qname ("Q_" . $intname); :local subqname ("Q_SUB_" . $intname); :local maxlimit 1000000000;

/queue tree

add burst-limit=0 burst-threshold=0 burst-time=0s max-limit=$maxlimit name=$qname parent=$intname

limit-at=$maxlimit \

add burst-limit=0 burst-threshold=0 burst-time=0s max-limit=512000 name=("voip_46_" . $intname) parent=$qname priority=1 queue=pcq_game add burst-limit=0 burst-threshold=0 burst-time=0s max-limit=512000 name=("critical_7_" parent=$qname priority=1 queue=pcq_game

limit-at=512000 \ packet-mark=dscp_46

limit-at=512000 \ packet-mark=dscp_7

. $intname)

add burst-limit=0 burst-threshold=0 burst-time=0s max-limit=3000000 name=("games_6_" . $intname) parent=$qname priority=2 queue=pcq_game #pfifo

limit-at=3000000 \ packet-mark=dscp_6

add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=5000000 \

82
max-limit=$maxlimit name=("lv_hi_" . $intname) parent=$qname priority=1 queue=pcq_rest packet-mark=lvhi

add burst-limit=0 burst-threshold=0 burst-time=0s max-limit=$maxlimit name=("lv_med_" parent=$qname priority=2 queue=pcq_rest

limit-at=1000000 \ packet-mark=lvmed

. $intname)

add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=512000 \ packet-mark=dscp_5

max-limit=512000 name=("management_5_" . $intname) parent=$qname priority=3 queue=pcq_default #pfifo add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=1000000 \

max-limit=$maxlimit name=$subqname parent=$qname

add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=100000 \ packet-

max-limit=$maxlimit name=("high_4_" . $intname) mark=dscp_4 parent=$subqname priority=5 queue=pcq_rest #pfifo_long add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=100000 \ packet-

max-limit=$maxlimit name=("norm_3_" . $intname) mark=dscp_3 parent=$subqname priority=6 queue=pcq_rest #pfifo_long add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=100000 \ packet-

max-limit=$maxlimit name=("filetrans_2_" . $intname) mark=dscp_2 parent=$subqname priority=7 queue=pcq_rest #pfifo_long add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=100000 \ packet-

max-limit=$maxlimit name=("bulk_1_" . $intname) mark=dscp_1 parent=$subqname priority=8 queue=pcq_game #sfq add burst-limit=0 burst-threshold=0 burst-time=0s

limit-at=100000 \ packet-

max-limit=$maxlimit name=("unmarked_" . $intname) mark="unmarked" parent=$subqname priority=8 queue=pcq_game

83
#sfq

/system script set start_shaping source=([/system script get start_shaping source] . " \ /queue tree set games_6_$intname limit-at=5000000 max-limit=5000000; \ /queue tree set [find parent=$subqname] max-limit=5000000; \ /queue tree set $subqname max-limit=5000000\r\ \n") set stop_shaping source=([/system script get stop_shaping source] . " \ /queue tree set games_6_$intname limit-at=3000000 max-limit=3000000; \ /queue tree set [find parent=$subqname] max-limit=$maxlimit; \ /queue tree set $subqname max-limit=$maxlimit\r\ \n") }

/system clock set time-zone-name=Africa/Johannesburg

/system ntp client set enabled=yes mode=unicast primary-ntp=172.20.2.1 secondary-ntp=\ 172.20.11.34

:put "done" ';

//$ServerList [] = "172.20.16.106"; //$ServerList [] = "172.20.245.55"; //$ServerList [] = "172.20.12.81";

84
$ServerList [] = "172.20.14.177";

$Username $Pass

= 'username'; = 'password';

foreach ($ServerList as $Server) { $mk = &new phpMikrotikTelnet($Server, $Username, $Pass); $mk->routeros_cmd($cmd); $mk->close();

?>

You might also like