Информация
Услуги
  • Внедрение
  • Настройка
  • Поддержка
  • Ремонт
Контакты
Новинка
Распродажа
Новости
Доставка
Оплата
Загрузки
  • Прошивки
    • WinBox
    • RouterOS
    • Мобильные приложения MikroTik
    • Архив
  • RouterOS
  • Мобильные приложения MikroTik
  • Архив
Форум
Настройка
    info@mikrotik.moscow
    +7 495 320-55-52
    Заказать звонок
    Mikrotik.moscow
    Каталог
    • Акции
      Акции
    • Маршрутизаторы
      Маршрутизаторы
    • Коммутаторы
      Коммутаторы
    • Радиомосты и уличные точки доступа
      Радиомосты и уличные точки доступа
    • Wi-Fi для дома и офиса
      Wi-Fi для дома и офиса
    • LTE/5G
      LTE/5G
    • Powerline адаптеры
      Powerline адаптеры
    • IoT устройства
      IoT устройства
    • Оборудование 60 ГГц
      Оборудование 60 ГГц
    • Материнские платы RouterBOARD
      Материнские платы RouterBOARD
    • Корпуса
      Корпуса
    • Интерфейсы
      Интерфейсы
    • SFP/QSFP трансиверы
      SFP/QSFP трансиверы
    • Аксессуары
      Аксессуары
    • Антенны
      Антенны
    • Архив
      Архив
    Войти
    0 Сравнение
    0 Избранное
    0 Корзина
    Скачать WinBox Скачать Прошивки Форум > RouterOS Форум > SwOS Форум > Железо
    Mikrotik.moscow
    Каталог
    Войти
    0 Сравнение
    0 Избранное
    0 Корзина
    Mikrotik.moscow
    Телефоны
    +7 495 320-55-52
    Заказать звонок
    0
    0
    0
    Mikrotik.moscow
    • +7 495 320-55-52
      • Назад
      • Телефоны
      • +7 495 320-55-52
      • Заказать звонок
    • info@mikrotik.moscow
    • г. Москва, ул. Бакунинская, 84
    • Пн-Пт: 09-00 до 18-00
      Сб-Вс: выходной


    • Кабинет
    • 0 Сравнение
    • 0 Избранное
    • 0 Корзина
    Главная
    Форум
    Форум
    RouterOS
    Mikrotik API с PHP

    Mikrotik API с PHP

    Форумы: RouterOS, Аппаратное обеспечение, SwOS, Обратная связь, Объявления, Сторонние инструменты
    Поиск  Пользователи  Правила  Войти
    Страницы: 1
    RSS
    Mikrotik API с PHP, RouterOS
     
    P3T3R
    Guest
    #1
    0
    03.02.2012 15:54:00
    Привет, у меня небольшая проблема с моим php-скриптом. Вот сам скрипт:  
    <?php  
    require('config.php');  
    require('routeros_api.class.php');  

    $API = new routeros_api();  
    $API->debug = true;  
    $dediny = array(  
                   array("10.30.1."),  
                   array("10.30.2."),  
                   array("10.30.31."),  
    );  
    $ip = array(  
               array("10.30.1.1", "Peter123", "xxx"),  
               array("10.30.2.1", "Peter123", "xxx"),  
               array("10.30.31.1", "Peter123", "xxx"),    
    );  

    foreach($ip as $mikrotik){  
     foreach($dediny as $dedina){  
      if ($API->connect($mikrotik[0], $mikrotik[1], $mikrotik[2])) {
         $query = mysql_query("SELECT usermac, userip, username FROM sl_internet WHERE userip like '.$dedina[0].%' and usermac IS NOT NULL");
         while($row = mysql_fetch_array($query)){    
           $usermac  = $row['usermac'];
           $username = $row['username'];
           $uzivatel = strtr($username, ' ./áäčďéěëíµňôóöŕřšťúůüýžÁÄČĎÉĚËÍĄŇÓÖÔŘŔŠŤÚŮÜÝŽ', '___aacdeeeilnooorrstuuuyzaacdeeelinooorrstuuuyz');    
           $API->write("/interface/wireless/access-list/add", false);  
           $API->write("=forwarding=no", false);  
           $API->write("=authentication=yes", false);  
           $API->write("=interface=all", false);  
           $API->write("=mac-address=". $usermac ."", false);  
           $API->write("=comment=". $uzivatel ."");  

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

           print_r($ARRAY);  

           $API->disconnect();  
         }    
       }  
     }  
    }    

    ?>  
    Моя проблема: пользователь входит в Mikrotik, но MAC-адрес не записывается в список адресов. В чём может быть проблема?  

    Вот сообщение после запуска скрипта:  

    Пытался №1 к 10.30.1.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=32a065fe9daba77f3c5131fe9294b93e <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=001474e0d360b775f9f923580ea95b6531 >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.1.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=7206547048eec1e0534e37022bb0bfde <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=00a340b63c0a50704f74e02f67a37dbfbd >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.1.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=44c48f9f023aca98e8ded349e2f1170b <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=002c5d6607a10717b1451a29e364d3631c >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.2.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=1a3eea89741b8af595f5cdd05ad9bdb8 <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=00b7ed1b0084a8444e5a05fc6740907a94 >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.2.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=90012ab87e8fdc28939546dd09d060e2 <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=00ffd2da3ec2cc85f75b61bd9814f2d654 >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.2.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=027a28f68da888643ea623c12f7f7b1a <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=00088dc34835b6b70c767ce468bdde5a39 >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.31.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=a9da030586223ef96a396d27e6dbcd3c <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=00891ba7cc96c3d64c45020fb015f2f88e >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
    Пытался №1 к 10.30.31.1:8728... Ошибка...  
    Пытался №1 к 10.30.31.1:8728... <<< [6] /login >>> [5/5] байт прочитано. >>> [5, 39]!done >>> [37/37] байт прочитано. >>> [37, 1]=ret=c5d47c20ed608b3c88512315972621bc <<< [6] /login <<< [14] =name=Peter123 <<< [44] =response=000c3912efd857b8ff542e3f86c69698ef >>> [5/5] байт прочитано. >>> [5, 1]!done Подключено...
     
     
     
    juanmesa
    Guest
    #2
    0
    20.06.2012 13:36:00
    Добрый день. Я пытаюсь работать с классом php для Mikrotik, но не удалось заставить его работать на арендованном хостинге (Godaddy). Зато с моего ноутбука (с Appserv), подключенного к Mikrotik, всё работает. Буду благодарен за помощь. У меня Routerboard RB1100.

    С хостинга:
    Попытка подключения #1 к telmovil.4dq.com:8728 …
    Попытка подключения #2 к telmovil.4dq.com:8728 …
    Попытка подключения #3 к telmovil.4dq.com:8728 …
    Попытка подключения #4 к telmovil.4dq.com:8728 …
    Попытка подключения #5 к telmovil.4dq.com:8728 …
    Ошибка…

    С моего ноутбука с Appserv:
    Попытка подключения #1 к telmovil.4dq.com:8728 …
    <<< [6] /login >>>
    [5/5] байт прочитано.
    >>> [5, 39]!done
    >>> [37/37] байт прочитано.
    >>> [37, 1]=ret=bfba4d9674433881af0c85abe446e063
    <<< [6] /login
    <<< [11] =name=xxxxx
    <<< [44] =response=006245a8313d081bd97f2679c2ab870e53
    >>> [5/5] байт прочитано.
    [5, 1]!done
    Подключено…
    <<< [18] /ip/route/rule/add
    <<< [22] =src-address=10.1.0.99
    <<< [19] =action=unreachable
    <<< [27] =comment=adicionado por api
    >>> [5/5] байт прочитано.
    >>> [5, 10]!done
    >>> [8/8] байт прочитано.
    >>> [8, 1]=ret=*49
    <<< [59] /ip route rule add src-address=10.1.0.99 action=unreachable
    Отключено…

    Спасибо.
     
     
     
    boen_robot
    Guest
    #3
    0
    21.06.2012 13:39:00
    @juanmesa Пожалуйста, пиши по-английски. Я не понимаю… Испанский, как я полагаю. В любом случае, посмотрев лог, думаю, понял в чём у тебя проблема. Наверное, у тебя в коде что-то типа: $API->comm('/ip route rule add src-address=10.1.0.99 action=unreachable'); или может быть $API->write('/ip route rule add src-address=10.1.0.99 action=unreachable', false); В любом случае, с классом Дениса так делать нельзя. Судя по логу, раньше в твоём коде ты это делаешь правильно. Удали все части кода, которые похожи на приведённые примеры, и используй тот вариант, который работал раньше.
     
     
     
    P3T3R
    Guest
    #4
    0
    22.06.2012 07:15:00
    Привет, boen_robot, у меня проблема с address list в Mikrotik.  
     

    У нас три AP с тремя IP-адресами в одном Mikrotik. У каждого AP есть свой IP:  
    AP 1 – 10.30.31.1  
    AP 2 – 10.30.32.1  
    AP 3 – 10.30.33.1  

    У нас есть база данных MySQL, где хранятся IP и MAC адреса наших клиентов.  

    Как написать PHP-скрипт, который будет:  
    - Если MAC адрес есть в MySQL и в Mikrotik → ничего не делать  
    - Если MAC адрес есть в MySQL, но нет в Mikrotik → добавить MAC адрес в address list  
    - Если MAC адреса нет в MySQL, но он есть в Mikrotik → удалить MAC адрес из address list  

    Спасибо!
     
     
     
    boen_robot
    Guest
    #5
    0
    22.06.2012 12:39:00
    @P3T3R Есть несколько способов подойти к решению, всё зависит от того, где вы хотите сосредоточить основную нагрузку — на роутере, веб-сервере или сервере базы данных? Есть ли проблемы с памятью где-то? Как выглядит таблица в БД? Мы вообще про ARP-лист говорим? Предположу, что память на веб-сервере не самый большой вопрос (хотя она всё равно ограничена, пусть даже искусственно через php.ini), и что сетевые соединения с роутером дороже, чем с сервером базы данных, как это обычно и бывает (особенно если БД работает на той же машине, что и веб-сервер). Также предполагаю следующую структуру таблицы БД:

    CREATE TABLE `arp` (
     `ip` varchar(15) NOT NULL,
     `mac` char(17) NOT NULL,
     PRIMARY KEY (`ip`,`mac`)
    ) ENGINE=InnoDB

    Сначала сделайте один запрос на вывод к роутеру, чтобы получить все записи. Затем для каждой записи из списка проверьте, есть ли она в базе, просто сделав запрос и посмотрев, есть ли результат. Если записи нет — добавьте её ID в список для удаления. Если есть — добавьте пару IP/MAC в строку, которая позже сформирует SQL-запрос. После обработки всех записей сделайте один запрос на удаление к роутеру со всеми собранными ID, выполните SQL-запрос, который вернёт все записи, кроме тех, что собраны, и отправьте запрос на добавление каждой из них.

    Если не возражаете, приведу пример на своём клиенте, но вы можете переписать это на класс Дениса, если нужно:

    <?php
    namespace PEAR2\Net\RouterOS;
    require_once 'PEAR2/Net/RouterOS/Autoload.php';

    //Подключаемся и к роутеру, и к MySQL.
    $client = new Client('10.30.99.31', 'admin', 'password');
    $mysqli = new \mysqli('127.0.0.1', 'root', '', 'db');

    //Для скорости используем подготовленные выражения.
    $selectStatement = array(
     'stmt' => $mysqli->prepare('SELECT `ip`, `mac` FROM `arp` WHERE `ip`= ? AND `mac` = ?'),
     'params' => array('ip' => null, 'mac' => null)
    );
    $selectStatement->bind_param('ss', $selectStatement['params']['ip'], $selectStatement['params']['mac']);

    //Переменные для дальнейшего использования.
    $removalIDs = '';
    $finalSelectQueryFilters = array();

    //Делаем запрос, который вернёт все записи ARP... без комментариев.
    $printRequest = new Request('/ip arp print .proplist=.id,address,mac-address');
    $printRequest->setTag('p');

    //Определяем, что делать с каждой записью. Такой подход минимизирует потребление памяти на этом этапе.
    $client->sendAsync($printRequest,
     function ($response) use ($mysqli, &$selectStatement, &$removalIDs, &$finalSelectQueryFilters) {
       if ($response->getType() === Response::TYPE_DATA) {
         $selectStatement['params']['ip'] = $response->getArgument('address');
         $selectStatement['params']['mac'] = $response->getArgument('mac-address');
         $selectStatement['stmt']->execute();
         if ($selectStatement['stmt']->get_result()->num_rows) {
           $finalSelectQueryFilters[] =
             "(`ip` = '" . $mysqli->real_escape_string($response->getArgument('address')) .
             "' AND `mac` = '" . $mysqli->real_escape_string($response->getArgument('mac-address')) .
             "')";
         } else {
           $removalIDs .= $response->getArgument('.id') . ',';
         }
       }
     }
    );
    $client->loop();

    //$removalIDs и $finalSelectQueryFilters теперь заполнены. Используем их.

    //Удаляем все записи, которых нет в базе.
    $removeRequest = new Request('/ip arp remove');
    $removeRequest->setArgument('numbers', rtrim($removalIDs, ','));
    $client->sendSync($removeRequest);

    //Получаем все записи, которые есть в базе, но отсутствуют в роутере.
    $finalSelectResult = $mysqli->query('SELECT `ip`, `mac` FROM `arp` WHERE NOT (' . implode(' OR ', $finalSelectQueryFilters) . ')');

    //Добавляем их в роутер.
    $addRequest = new Request('/ip arp add');
    for ($i = 0; $row = $finalSelectResult->fetch_assoc(); ++$i) {
     $client->sendAsync(
       $addRequest
         ->setArgument('address', $row['ip'])
         ->setArgument('mac-address', $row['mac'])
         ->setTag($i)
     );
    }
    $client->loop();

    Кстати, всё было бы гораздо проще, если вы просто добавляли записи в роутер одновременно с добавлением в базу, и удаляли из роутера при удалении из базы.
     
     
     
    P3T3R
    Guest
    #6
    0
    02.07.2012 07:37:00
    Привет, boen_robot, спасибо за ответ, но что если у меня будет больше клиентов? У нас веб-сервер и MySQL сервер на одном сервере, где около 2000 IP-клиентов и примерно 200 IP-адресов MikroTik. Твой скрипт для ARP-листа, можешь написать скрипт для Wireless - access list? Большое спасибо!
     
     
     
    boen_robot
    Guest
    #7
    0
    02.07.2012 11:16:00
    По поводу того, что у вас несколько роутеров — пример в моём втором посте: в принципе, просто создайте новый объект Client для каждого роутера. Что касается access-list… извиняюсь, я раньше не заметил, что вы хотите работать только с MAC-адресами (я отвлёкся на то, что в вашей базе данных есть ещё и IP, поэтому сначала подумал про ARP). В базе данных указано, в каком роутере находится пользователь? Эти данные отличаются для каждого роутера или пользователь может подключаться с любого? Предположу, что данные разные для каждого роутера (имена пользователей могут повторяться, если они на разных роутерах), и что база это отслеживает с помощью отдельной таблицы с данными роутеров. Тогда схема может выглядеть примерно так:

    SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
    SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
    SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='TRADITIONAL';

    -- -----------------------------------------------------
    -- Таблица `routers`
    -- -----------------------------------------------------
    CREATE TABLE IF NOT EXISTS `routers` (
     `routerID` INT(11) NOT NULL AUTO_INCREMENT,
     `ip` VARCHAR(15) NOT NULL,
     `username` VARCHAR(255) NOT NULL,
     `password` VARCHAR(255) NOT NULL,
     PRIMARY KEY (`routerID`)
    )
    ENGINE=InnoDB
    DEFAULT CHARSET=utf8;

    SHOW WARNINGS;

    -- -----------------------------------------------------
    -- Таблица `clients`
    -- -----------------------------------------------------
    CREATE TABLE IF NOT EXISTS `clients` (
     `ip` VARCHAR(15) NOT NULL,
     `mac` CHAR(17) NOT NULL,
     `routerID` INT(11) NOT NULL,
     `username` VARCHAR(255) NULL DEFAULT NULL,
     PRIMARY KEY (`ip`, `mac`, `routerID`),
     INDEX `fk_clients_routers` (`routerID` ASC),
     CONSTRAINT `fk_clients_routers`
       FOREIGN KEY (`routerID`)
       REFERENCES `router`.`routers` (`routerID`)
       ON DELETE NO ACTION
       ON UPDATE CASCADE
    )
    ENGINE=InnoDB
    DEFAULT CHARSET=utf8;

    SHOW WARNINGS;

    SET SQL_MODE=@OLD_SQL_MODE;
    SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
    SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

    Теперь, поскольку структура кода начинала сходить с ума, я выделил большую часть прежнего кода в отдельный класс. Думаю, мог бы сделать это и лучше, но сейчас главная задача — привести в порядок то, что раньше было анонимной функцией. Остальная часть кода практически не изменилась, за исключением всего, что связано с IP:

    <?php
    namespace PEAR2\Net\RouterOS;
    require_once 'PEAR2/Net/RouterOS/Autoload.php';

    // Подключение к MySQL.
    $mysqli = new \mysqli('127.0.0.1', 'root', '', 'db');

    class ResponseProcessor {
       protected $mysqli;
       protected $stmt;
       protected $params = array('routerID' => null, 'mac' => null);
       protected $removalIDs = '';
       protected $existingMACs = '';

       public function __construct(\mysqli $mysqli) {
           $this->mysqli = $mysqli;
           $this->stmt = $mysqli->prepare('SELECT `mac` FROM `clients` WHERE `routerID` = ? AND `mac` = ?');
           $this->stmt->bind_param('is', $this->params['routerID'], $this->params['mac']);
       }

       public function setRouterID($id) {
           $this->params['routerID'] = (int)$id;
           $this->removalIDs = $this->existingMACs = '';
       }

       public function process(Response $response) {
           if ($response->getType() === Response::TYPE_DATA) {
               $this->params['mac'] = $response->getArgument('mac-address');
               $this->stmt->execute();
               if ($this->stmt->get_result()->num_rows) {
                   $this->existingMACs .= "'" . $this->mysqli->real_escape_string($response->getArgument('mac-address')) . "',";
               } else {
                   $this->removalIDs .= $response->getArgument('.id') . ',';
               }
           }
       }

       public function getRemovalIDs() {
           return rtrim($this->removalIDs, ',');
       }

       public function getAllNotInRouter() {
           return $this->mysqli->query('SELECT `mac` FROM `clients` WHERE `routerID` = ' . $this->params['routerID'] . ' AND `mac` NOT IN (' . rtrim($this->existingMACs, ',') . ')');
       }
    }

    $printRequest = new Request('/interface wireless access-list print .proplist=.id,mac-address');
    $printRequest->setTag('p');

    $removeRequest = new Request('/interface wireless access-list remove');
    $addRequest = new Request('/interface wireless access-list add');

    $processor = new ResponseProcessor($mysqli);
    $routers = $mysqli->query('SELECT `routerID`, `ip`, `username`, `password` FROM `routers`');
    while ($router = $routers->fetch_assoc()) {
       $client = new Client($router['ip'], $router['username'], $router['password']);
       $processor->setRouterID($router['routerID']);

       // Определяем, что делать с каждой записью. Такой подход позволяет минимизировать потребление памяти на этом этапе.
       $client->sendAsync($printRequest, array($processor, 'process'));
       $client->loop();

       // Удаляем все записи, которых нет в базе.
       $client->sendSync($removeRequest->setArgument('numbers', $processor->getRemovalIDs()));

       // Получаем все записи, которые есть в базе, но отсутствуют в роутере.
       $finalSelectResult = $processor->getAllNotInRouter();

       // Добавляем все такие записи в роутеры.
       for ($i = 0; $row = $finalSelectResult->fetch_assoc(); ++$i) {
           $client->sendAsync(
               $addRequest
                   ->setArgument('mac-address', $row['mac'])
                   ->setTag($i)
           );
       }
       $client->loop();
    }

    Обратите внимание, что в итоге каждый MAC-адрес добавляется на “все” беспроводные интерфейсы, а не на конкретный. Если хотите назначать конкретный интерфейс, нужно либо хранить интерфейс в базе вместе с MAC-адресом, либо использовать что-то вроде функции PEAR Net_IPv4::ipInNetwork(), чтобы автоматически определить интерфейс, исходя из IP пользователя и сетевых адресов AP на текущем роутере. Первый вариант требует больше места в базе (2000 пользователей минимум по 5 байт на пользователя — это минимум 10 Кб, и рост зависит от длины имен интерфейсов), а второй — занимает некоторое время (каждую добавляемую запись нужно проверить, а перед этим сделать дополнительный запрос для получения всех сетевых адресов AP; в среднем это несколько миллисекунд накладных расходов, в худшем случае полсекунды, при условии, что сеть в порядке и количество записей умеренное). Что бы вы предпочли пожертвовать?
     
     
     
    juanmesa
    Guest
    #8
    0
    10.08.2013 13:03:00
    Хорошо. Попробую объяснить на английском. API отлично подключается с моего ноутбука в локальной сети. Хотел бы запустить код с моего сайта на GoDaddy, но получаю: Попытка подключения №1 к telmovil.4dq.com:8728… Попытка подключения №2 к telmovil.4dq.com:8728… Попытка подключения №3 к telmovil.4dq.com:8728… Попытка подключения №4 к telmovil.4dq.com:8728… Попытка подключения №5 к telmovil.4dq.com:8728… Ошибка… Не получается подключиться. Спасибо за интерес и помощь.
     
     
     
    Страницы: 1
    Читают тему
    +7 495 320-55-52
    info@mikrotik.moscow
    Электрозаводская, Бауманская
    Москва, ул. Бакунинская, 84с21
    Конфиденциальность Оферта
    © 2026 «Mikrotik.Moscow»
    Главная Каталог 0 Корзина 0 Избранные Кабинет 0 Сравнение Акции Контакты Услуги Бренды Отзывы Компания Лицензии Документы Реквизиты Поиск Блог Обзоры