attempts; $ATTEMPT++) { $this->connected = false; $this->debug('Connection attempt #' . $ATTEMPT . ' to ' . $ip . ':' . $this->port . '...'); $this->socket = @fsockopen($ip, $this->port, $this->error_no, $this->error_str, $this->timeout); if ($this->socket) { socket_set_timeout($this->socket, $this->timeout); $this->write('/login'); $RESPONSE = $this->read(false); if (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=' . $login, 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($this->delay); } if ($this->connected) { $this->debug('Connected successfully to ' . $ip . ':' . $this->port); } else { $this->debug('Error connecting to ' . $ip . ':' . $this->port); } return $this->connected; } /** * Disconnect from RouterOS */ public function disconnect() { fclose($this->socket); $this->connected = false; $this->debug('Disconnected'); } /** * Parse response from RouterOS * * @param array $response Response data * * @return array Parsed data */ public function parseResponse($response) { if (is_array($response)) { $PARSED = array(); $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][]; } } elseif ($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; } return $PARSED; } else { return array(); } } /** * Read data from RouterOS * * @param boolean $parse Parse the data? * * @return array Data array */ public function read($parse = true) { $RESPONSE = array(); $line = ''; while (true) { $BYTE = fread($this->socket, 1); $line .= $BYTE; if ($BYTE == "\0") { $RESPONSE[] = $line; if (substr($line, -5) == "!done\0") { break; } $line = ''; } } if ($parse) { return $this->parseResponse($RESPONSE); } else { return $RESPONSE; } } /** * Write (send) data to RouterOS * * @param string $command A string with the command to send * @param boolean $param2 If we are sending a command, or a parameter * * @return void */ public function write($command, $param2 = true) { if ($command) { $data = explode("\n", $command); foreach ($data as $com) { $com = trim($com); fwrite($this->socket, $this->encodeLength(strlen($com)) . $com); $this->debug('<<< ' . $com); } if (gettype($param2) == 'integer') { fwrite($this->socket, $this->encodeLength(strlen('.tag=' . $param2)) . '.tag=' . $param2 . "\0"); $this->debug('<<< .tag=' . $param2); } elseif (gettype($param2) == 'boolean') { fwrite($this->socket, ($param2 ? '' : "\0")); } } } /** * Encode length of the string * * @param integer $length Length of the string * * @return string Encoded length */ private function encodeLength($length) { if ($length < 0x80) { return chr($length); } if ($length < 0x4000) { return chr(($length >> 8) | 0x80) . chr($length & 0xFF); } if ($length < 0x200000) { return chr(($length >> 16) | 0xC0) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } if ($length < 0x10000000) { return chr(($length >> 24) | 0xE0) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } return chr(0xF0) . chr(($length >> 24) & 0xFF) . chr(($length >> 16) & 0xFF) . chr(($length >> 8) & 0xFF) . chr($length & 0xFF); } /** * Print debug information * * @param string $text Debug text * * @return void */ private function debug($text) { if ($this->debug) { echo $text . "\n"; } } }