ashikkaiser / microtikapi
适用于您的应用程序的现代 Mikrotik RouterOS API PHP 客户端(支持 Laravel)
Requires
- php: ^7.2|^8.0
- ext-sockets: *
- divineomega/php-ssh-connection: ^2.2
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.16
- larapack/dd: ^1.1
- limedeck/phpunit-detailed-printer: ^5.0
- orchestra/testbench: ^4.0|^5.0
- phpunit/phpunit: ^8.0
- rector/rector: ^0.7|^0.8|^0.9
- roave/security-advisories: dev-master
- squizlabs/php_codesniffer: ^3.5
This package is auto-updated.
Last update: 2024-09-29 05:56:42 UTC
README
RouterOS API 客户端
composer require ashikkaiser/microtikapi
这个库部分基于这个旧项目,但它有很多创新来简化开发。此外,该项目设计为符合 PSR 标准与 PHP7 一起工作。
您可以使用此库与 6.43 版本之前的 RouterOS 固件以及 6.43 版本之后的版本一起使用,它将在连接阶段自动检测。
最低要求
php>= 7.2ext-sockets
Laravel 框架支持
RouterOS API 客户端针对作为正常 Laravel 包的使用进行了优化,所有功能都可通过 \RouterOS 门面访问,要访问客户端对象,您需要使用
$config = new \RouterOS\Config([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin', 'port' => 8728, ]); $client = new \RouterOS\Client($config);
调用门面并将参数数组传递给 client 方法
$client = \RouterOS::client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin', 'port' => 8728, ]);
您还可以获取从 routeros-api.php 文件中获取的所有配置的数组
$config = \RouterOS::config([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin', 'port' => 8728, ]); dump($config); $client = \RouterOS::client($config);
Laravel 安装
默认情况下,该包将自动注册其服务提供程序,但如果您是低于 5.5 版本的 Laravel 的快乐所有者,那么在您的项目(当然是在完成 composer require 之后)中,将您的包添加到 config/app.php 的 providers 块中
'providers' => [ // ... RouterOS\Laravel\ServiceProvider::class, ],
可选地,如果需要更改任何默认设置,请发布配置文件
php artisan vendor:publish --provider="RouterOS\\Laravel\\ServiceProvider"
如何使用
基本示例,通过命令行的类似操作是 /ip hotspot ip-binding print
use \RouterOS\Client; use \RouterOS\Query; // Initiate client with config object $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin' ]); // Create "where" Query object for RouterOS $query = (new Query('/ip/hotspot/ip-binding/print')) ->where('mac-address', '00:00:00:00:40:29'); // Send query and read response from RouterOS $response = $client->query($query)->read(); var_dump($response);
基本示例用于更新/创建/删除类型的查询
use \RouterOS\Client; use \RouterOS\Query; // Initiate client with config object $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin' ]); // Send "equal" query with details about IP address which should be created $query = (new Query('/ip/hotspot/ip-binding/add')) ->equal('mac-address', '00:00:00:00:40:29') ->equal('type', 'bypassed') ->equal('comment', 'testcomment'); // Send query and read response from RouterOS (ordinary answer from update/create/delete queries has empty body) $response = $client->query($query)->read(); var_dump($response);
如果您需要从路由器导出所有设置
use \RouterOS\Client; // Initiate client with config object $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin', 'ssh_port' => 22222, ]); // Execute export command via ssh, because API /export method has a bug $response = $client->export(); print_r($response);
带有 "where" 条件、"操作" 和 "标签" 的示例
use \RouterOS\Query; /** * Simple "where" query will be generated by default */ $client->query('/ip/address/print')->read(); /** * Send advanced "where" query with parameters to RouterOS */ // If only one "where" condition $client->query('/queue/simple/print', ['target', '192.168.1.1/32']); // If multiple "where" conditions and need merge (operation "|") results $client->query('/interface/print', [ ['type', 'ether'], // same as ['type', '=', 'ether'] ['type', 'vlan'], // same as ['type', '=', 'vlan'] ], '|'); /** * Or in OOP style */ // If you need create query for "create/update/delete" operations $query = new Query('/ip/hotspot/ip-binding/add'); $query->equal('mac-address', '00:00:00:00:40:29'); $query->equal('type', 'bypassed'); $query->equal('comment', 'testcomment'); // If multiple "where" conditions and need merge (operation "|") results $query = new Query('/interface/print'); $query->where('type', 'ether'); $query->where('type', 'vlan'); $query->operations('|'); // If multiple "where" conditions and need append tag $query = new Query('/interface/set'); $query->where('disabled', 'no'); $query->where('.id', 'ether1'); $query->tag(4); /** * Write Query object to RouterOS and read response from it */ $response = $client->query($query)->read();
您可以在这里找到所有可用示例。
如何配置客户端
您只需创建一个 Client 类对象,其中包含以数组格式指定的所需参数
use \RouterOS\Client; $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin' ]);
ℹ️ Config 和 Client 类使用的高级示例
use \RouterOS\Config; use \RouterOS\Client; /** * You can create object of Config class */ $config = new Config(); // Then set parameters of config $config->set('host', '192.168.1.3'); $config->set('user', 'admin'); $config->set('pass', 'admin'); // By the way, `->set()` method is support inline style of syntax $config ->set('host', '192.168.1.3') ->set('user', 'admin') ->set('pass', 'admin'); /** * Or just create preconfigured Config object */ $config = new Config([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin' ]); /** * Then send Config object to Client constructor */ $client = new Client($config);
可用的配置参数列表
如何启用对旧登录方案(RouterOS pre-6.43)的支持
从 0.8.1 版本开始,这不再重要,固件版本将自动检测。
<?php require_once __DIR__ . '/vendor/autoload.php'; use \RouterOS\Client; // Initiate client with config object $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin', 'legacy' => true // you need set `legacy` parameter with `true` value ]); // Your code below...
如何编写查询
您可以为您的路由器编写任何查询,为此您需要创建一个 "Query" 对象,其第一个参数是所需的命令,然后您可以向 "Query" 对象添加命令的属性。
有关属性和创建这些属性应使用的 "单词" 的更多信息,请参阅这里。
有关 "表达式"、"where"、"equal" 以及您查询的其他过滤/修改的更多信息,请参阅这里。
Query 类的简单使用示例
use \RouterOS\Query; // Get all installed packages (it may be enabled or disabled) $query = new Query('/system/package/getall'); // Send "equal" query with details about IP address which should be created $query = (new Query('/ip/hotspot/ip-binding/add')) ->equal('mac-address', '00:00:00:00:40:29') ->equal('type', 'bypassed') ->equal('comment', 'testcomment'); // Set where interface is disabled and ID is ether1 (with tag 4) $query = (new Query('/interface/set')) ->where('disabled', 'no') ->where('.id', 'ether1') ->tag(4); // Get all ethernet and VLAN interfaces $query = (new Query('/interface/print')) ->where('type', 'ether') ->where('type', 'vlan') ->operations('|'); // Get all routes that have non-empty comment $query = (new Query('/ip/route/print')) ->where('comment', '>', null);
ℹ️ Query 类使用的高级示例
use \RouterOS\Query; use \RouterOS\Client; // Initiate connection to RouterOS $client = new Client([ 'host' => '192.168.1.3', 'user' => 'admin', 'pass' => 'admin' ]); /** * Execute query directly through "->query()" method of Client class */ // If your query has no "where" conditions $client->query('/ip/arp/print'); // If you have only one where condition, you may use one dimensional array as second parameter of query method $client->query('/queue/simple/print', ['target', '192.168.1.250/32']); // If you need set few where conditions then need use multi dimensional array $client->query('/interface/bridge/add', [ ['name', 'vlan100-bridge'], ['vlan-filtering', 'no'] ]); /** * By some reason you may need restrict scope of RouterOS response, * for this need to use third attribute of "->query()" method */ // Get all ethernet and VLAN interfaces $client->query('/interface/print', [ ['type', 'ether'], ['type', 'vlan'] ], '|'); /** * If you want set tag of your query then you need to use fourth * attribute of "->query()" method, but third attribute may be null */ // Enable interface (tag is 4) $client->query('/interface/set', [ ['disabled', 'no'], ['.id', 'ether1'] ], null, 4); /** * Or in OOP style */ // Get all ethernet and VLAN interfaces $query = new Query('/interface/print'); $query->where('type', 'ether'); $query->where('type', 'vlan'); $query->operations('|'); // Enable interface (tag is 4) $query = new Query('/interface/set'); $query->equal('disabled', 'no'); $query->equal('.id', 'ether1'); $query->tag(4); // Or $query = new Query('/interface/set'); $query->add('=disabled=no'); $query->add('=.id=ether1'); $query->add('.tag=4'); // Or $query = new Query('/interface/set', [ '=disabled=no', '=.id=ether1', '.tag=4' ]); // Or $query = new Query([ '/interface/set', '=disabled=no', '=.id=ether1', '.tag=4' ]); /** * Write Query object to RouterOS and read response from it */ $response = $client->query($query)->read();
作为迭代器读取响应
默认情况下,此客户端的原始解决方案未针对处理大量结果进行优化,仅针对来自 RouterOS API 的少量行响应。
但某些路由器可能在其防火墙列表中拥有(例如)30,000 多条记录。具体针对此类任务,已添加了一个名为 readAsIterator 的方法,该方法将路由器获取到的结果转换为资源,稍后可以进行操作。
除了使用任何 array_* 函数外,您还可以将响应视为数组
$response = $client->query($query)->readAsIterator(); var_dump($response); // The following for loop allows you to skip elements for which // $iterator->current() throws an exception, rather than breaking // the loop. for ($response->rewind(); $response->valid(); $response->next()) { try { $value = $response->current(); } catch (Exception $exception) { continue; } # ... }
简短的方法
您可以将代码简化,并在一行中发送和从套接字读取
/** * Execute query and read response in ordinary mode */ $response = $client->query($query)->read(); var_dump($response); // Or $response = $client->q($query)->r(); var_dump($response); // Single method analog of lines above is $response = $client->qr($query); var_dump($response); /** * Execute query and read response as Iterator */ $response = $client->query($query)->readAsIterator(); var_dump($response); // Or $response = $client->q($query)->ri(); var_dump($response); // Single method analog of lines above is $response = $client->qri($query); var_dump($response); /** * By the way, you can send few queries to your router without result: */ $client->query($query1)->query($query2)->query($query3); // Or $client->q($query1)->q($query2)->q($query3);
已知问题
无法建立套接字会话,操作超时
此错误表示库无法连接到您的路由器,这可能意味着路由器已关闭(然后需要打开),或API服务未启用。
转到 Mikrotik Router OS -> IP -> Services 并启用 api 服务。
或者通过命令行
/ip service enable api
如何通过API更新/删除/创建某些内容?
您需要使用 ->equal() 方法,而不是 Query 类的 ->where() 方法
// Create query which should remove security profile $query = new \RouterOS\Query('/interface/wireless/security-profiles/remove'); // It will generate queries, which stared from "?" symbol: $query->where('.id', '*1'); /* // Sample with ->where() method RouterOS\Query Object ( [_attributes:RouterOS\Query:private] => Array ( [0] => ?.id=*1 ) [_operations:RouterOS\Query:private] => [_tag:RouterOS\Query:private] => [_endpoint:RouterOS\Query:private] => /interface/wireless/security-profiles/remove ) */ // So, as you can see, instead of `->where()` need to use `->equal()` // It will generate queries, which stared from "=" symbol: $query->equal('.id', '*1'); /* // Sample with ->equal() method RouterOS\Query Object ( [_attributes:RouterOS\Query:private] => Array ( [0] => =.id=*1 ) [_operations:RouterOS\Query:private] => [_tag:RouterOS\Query:private] => [_endpoint:RouterOS\Query:private] => /interface/wireless/security-profiles/remove ) */
未定义字符(任何非英语语言)
RouterOS 不支持国家语言,只支持英语(以及 RouterOS 的 API)。
您可以通过网页尝试重现它,例如将注释添加到系统中的任何元素,然后保存并重新加载页面,您将看到不可读的字符。
测试
您可以使用我的包含 RouterOS 的 Docker 容器项目的其他项目,在您的计算机上运行单元测试,为此您只需要有 Expect, Docker 和 Docker Compose。
然后克隆包含 RouterOS 的 Docker 仓库,并执行 docker-compose up -d,然后您需要通过 preconf.tcl 脚本预配置虚拟路由器,脚本位于 routeros-api-php 的根目录。
./preconf.tcl 12223
./preconf.tcl 22223
然后您可以运行测试
./vendor/bin/phpunit
链接
- 云托管路由器 - 为您的虚拟机管理程序提供的 RouterOS 虚拟镜像
- RouterOS 手册:API - 如果您想知道什么是疯狂