Source of file api.routeros.php
Size: 12,458 Bytes - Last Modified: 2024-04-27T15:26:05+03:00
/tmp/current_snapshot/api/libs/api.routeros.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335 | <?php /** * Mikrotik API implementation */ class RouterOS { // Socket resource: private $socket; private $port; // Public variables: public $connected = false; public $debug_str = null; public $error_str = null; public $error_num = null; // Constatns of class: //const PORT = 8728; const DEBUG = false; const ATTEMPTS = 3; const TIMEOUT = 5; const DELAY = 0; /** * Fills in the `$this->debug_str` variable if self::DEBUG is enabled * * @param string $string Debug message string * @return boolean */ private function debug($string) { if ( self::DEBUG ) { $this->debug_str .= $string . '<br />' . PHP_EOL; } } /** * Establishes connection with RouterOS device via API * * @param string $hostname Device`s IP or hostname * @param string $username Username * @param string $password Password * @param bool $UseNewConnMode * @param string $apiPort * * @return boolean $this->connected */ public function connect($hostname, $username, $password, $UseNewConnMode = false, $apiPort = '8728') { // Connect to device: for ( $attempt = 1; $attempt <= self::ATTEMPTS; $attempt++ ) { $this->connected = false; $this->port = $apiPort; $this->debug('Connection attempt #' . $attempt . ' to ' . $hostname . ':' . $this->port); $this->socket = @fsockopen($hostname, $this->port, $this->error_num, $this->error_str, self::TIMEOUT); if ( $this->socket ) { socket_set_timeout($this->socket, self::TIMEOUT); if ($UseNewConnMode) { $this->write('/login', false); $this->write('=name=' . $username, false); $this->write('=password=' . $password); $response = $this->read(false); if (isset($response[0]) && $response[0] == '!done') { $this->connected = true; break; } } else { $this->write('/login'); $response = $this->read(false); if (isset($response[0]) && $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=' . $username, false); $this->write('=response=00' . md5(chr(0) . $password . pack('H*', $matches[0][1]))); $response = $this->read(false); if (isset($response[0]) && $response[0] == '!done') { $this->connected = true; break; } } } } } fclose($this->socket); } sleep(self::DELAY); } // Throw debug-message: if ( $this->connected ) { $this->debug('Connection with device is established...'); } else { $this->debug('Couldn`t establish connection with device!'); } // Return connection state: return $this->connected; } /** * Encodes length * * @param string $length Length to encode * @return string */ private function encode_length($length) { switch ( true ) { case ( $length < 0x80 ): $length = chr($length); break; case ( $length < 0x4000 ): $length |= 0x8000; $length = chr(($length >> 8) & 0xFF) . chr($length & 0xFF); break; case ( $length < 0x200000 ): $length |= 0xC00000; $length = chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); break; case ( $length < 0x10000000 ): $length |= 0xE0000000; $length = chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); break; case ( $length >= 0x10000000 ): $length = chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); break; } return $length; } /** * Parses RouterOS device`s reply to 'comfortable' array * * @param array $response RouterOS device`s reply * @return array */ private function parse_response($response) { $return = array(); if ( is_array($response) ) { $current = null; $single = null; foreach ( $response as $key ) { if ( in_array($key, array('!fatal', '!re', '!trap')) ) { if ( $key == '!re' ) { $current = & $return[]; } else $current = & $return[$key][]; } else if ( $key != '!done' ) { if ( preg_match_all('/[^=]+/i', $key, $matches) ) { if ( $matches[0][0] == 'ret' ) { $single = $matches[0][1]; } $current[$matches[0][0]] = ( isset($matches[0][1] ) ? $matches[0][1] : null); } } } if ( empty($return) && !is_null($single) ) { $return = $single; } } return $return; } /** * Reads data from RouterOS device via API * * @param boolean $parse_response * @return array */ public function read($parse_response = true) { $response = array(); $_ = ''; $_done = false; while ( true ) { $byte = ord(fread($this->socket, 1)); $length = 0; 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)); } } } } else $length = $byte; 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 ($_ == '!done') { $_done = 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'] && $_done) ) { break; } } return ( $parse_response ) ? $this->parse_response($response) : $response; } /** * Writes command to RouterOS device via API * * @param string $command Sending command's string * @param boolean $param ... * @return boolean */ public function write($command, $param = true) { if ( $command ) { $data = explode('\n', $command); foreach ( $data as $cmd ) { $cmd = trim($cmd); fwrite($this->socket, $this->encode_length(strlen($cmd)) . $cmd); $this->debug('<<< [' . strlen($cmd) . '] ' . $cmd); } $type = gettype($param); switch ( $type) { case 'integer': fwrite($this->socket, $this->encode_length(strlen('.tag=' . $param)) . '.tag=' . $param . chr(0)); $this->debug('<<< [' . strlen('.tag=' . $param) . '] .tag=' . $param); break; case 'boolean': fwrite($this->socket, ($param ? chr(0) : '')); break; } } return ( $command ) ? true : false; } /** * Use it for sending commands to RouterOS device * * @param string $string RouterOS`s command string * @param array $data Command`s parameters * @return array */ public function command($string, $data = array()) { $count = count($data); $this->write($string, !$data); $i = 0; foreach ( $data as $key => $value ) { switch ( $key[0] ) { case '?': $el = ($key[1] == '#') ? $key . $value : $key . '=' . $value; break; case '~': $el = $key . '~' . $value; break; default: $el = '=' . $key . '=' . $value; break; } $last = ($i++ == $count - 1); $this->write($el, $last); } return $this->read(); } /** * Closes up established connection with RouterOS device */ public function disconnect() { $this->debug('Closing up established connection with RouterOS device..'); $this->connected = ( !fclose($this->socket) ) ? true : false; return !$this->connected; } /** * Tries to get RouterOS version via SNMP or from login WEB page * * @param $Hostname * @param int $WEBPort * @param string $SNMPCommunity * @return float */ public function determineVersion($Hostname, $WEBPort = 80, $SNMPCommunity = 'public') { $Version = ''; // trying to get version via SNMP $SNMP = new SNMPHelper(); $SNMP->setMode('native'); $OID = '.1.3.6.1.4.1.14988.1.1.4.4.0'; $tmpSNMP = $SNMP->walk($Hostname, $SNMPCommunity, $OID, false); $Version = ( empty($tmpSNMP) || $tmpSNMP === "$OID = " ) ? '' : str_replace('"', '', trim( substr($tmpSNMP, stripos($tmpSNMP, ':') + 1) )); // if first option failed - trying to parse login WEB page if ( empty($Version) ) { $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $Hostname); curl_setopt($curl, CURLOPT_PORT, $WEBPort); curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 10); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $Result = curl_exec($curl); curl_close($curl); if ( !empty($Result) ) { preg_match('/RouterOS v(.*?)</', $Result, $Match); if ( isset($Match[1]) && !empty($Match[1]) ) { $Version = $Match[1]; } } } return floatval($Version); } } |