{"id":15025002,"url":"https://github.com/evilfreelancer/routeros-api-php","last_synced_at":"2025-05-14T10:08:38.644Z","repository":{"id":38205989,"uuid":"145332745","full_name":"EvilFreelancer/routeros-api-php","owner":"EvilFreelancer","description":"Mikrotik RouterOS API PHP client for your applications","archived":false,"fork":false,"pushed_at":"2025-04-02T06:40:11.000Z","size":326,"stargazers_count":436,"open_issues_count":5,"forks_count":154,"subscribers_count":32,"default_branch":"master","last_synced_at":"2025-04-03T23:08:04.826Z","etag":null,"topics":["api-client","library","mikrotik","mikrotik-api","php7","php8","psr","routeros","routeros-api"],"latest_commit_sha":null,"homepage":"https://mikrotik.com/software","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EvilFreelancer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"custom":["https://pay.cloudtips.ru/p/937f48ac","https://boosty.to/evilfreelancer"]}},"created_at":"2018-08-19T19:45:19.000Z","updated_at":"2025-04-03T03:36:26.000Z","dependencies_parsed_at":"2024-09-28T19:50:31.284Z","dependency_job_id":null,"html_url":"https://github.com/EvilFreelancer/routeros-api-php","commit_stats":{"total_commits":294,"total_committers":12,"mean_commits":24.5,"dds":"0.11904761904761907","last_synced_commit":"19d98d72f19067dacf3b7babf66192c5bc2998f4"},"previous_names":[],"tags_count":33,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvilFreelancer%2Frouteros-api-php","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvilFreelancer%2Frouteros-api-php/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvilFreelancer%2Frouteros-api-php/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EvilFreelancer%2Frouteros-api-php/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EvilFreelancer","download_url":"https://codeload.github.com/EvilFreelancer/routeros-api-php/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248441772,"owners_count":21104070,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","library","mikrotik","mikrotik-api","php7","php8","psr","routeros","routeros-api"],"created_at":"2024-09-24T20:01:20.510Z","updated_at":"2025-05-14T10:08:38.637Z","avatar_url":"https://github.com/EvilFreelancer.png","language":"PHP","readme":"[![Latest Stable Version](https://poser.pugx.org/evilfreelancer/routeros-api-php/v/stable)](https://packagist.org/packages/evilfreelancer/routeros-api-php)\n[![Total Downloads](https://poser.pugx.org/evilfreelancer/routeros-api-php/downloads)](https://packagist.org/packages/evilfreelancer/routeros-api-php)\n[![License](https://poser.pugx.org/evilfreelancer/routeros-api-php/license)](https://packagist.org/packages/evilfreelancer/routeros-api-php)\n\n⚠️ Project Maintenance Notice\n\nThis project is currently unmaintained by the original author. Due to limited time and shifting priorities, I am unable to actively develop, debug, or support this project.\n\nKey Points:\n- Community contributions are welcome! Feel free to fork the repo and submit Pull Requests for fixes, improvements, or new features.\n- I will review and merge reasonable PRs that align with the project’s scope.\n- No guarantees are provided for issue resolutions, feature requests, or direct support.\n\nFuture updates depend entirely on community involvement.\n\nThank you for your understanding and contributions!\n\n# RouterOS API Client\n\n```shell\ncomposer require evilfreelancer/routeros-api-php\n```\n\nThis library is partly based on [this old project](https://github.com/BenMenking/routeros-api), but unlike it has many\ninnovations to ease development. In addition, the project designed\nto work with PHP7/8 in accordance with the PSR standards.\n\nYou can use this library with pre-6.43 and post-6.43 versions of\nRouterOS firmware, it will be detected automatically on connection stage.\n\n## Table of Contents\n\n* [Minimum requirements](#Minimum-requirements)\n* [Laravel framework support](#Laravel-framework-support)\n  * [Laravel installation](#Laravel-installation)\n* [How to use](#How-to-use)\n* [How to configure the client](#How-to-configure-the-client)\n  * [List of available configuration parameters](#List-of-available-configuration-parameters)\n  * [How to enable support of legacy login schema (RouterOS pre-6.43)](#How-to-enable-support-of-legacy-login-schema-(RouterOS-pre-6.43))\n* [How to write queries](#How-to-write-queries)\n* [Read response as Iterator](#Read-response-as-Iterator)\n* [Short methods](#Short-methods)\n* [Known issues](#Known-issues)\n  * [Unable to establish socket session, Operation timed out](#Unable-to-establish-socket-session,-Operation-timed-out)\n  * [How to update/remove/create something via API?](#How-to-update/remove/create-something-via-API?)\n  * [Undefined character (any non-English languages)](#Undefined-character-(any-non-English-languages))\n* [Testing](#Testing)\n* [Links](#Links)\n\n## Minimum requirements\n\n* `php` \u003e= 7.2|8.0\n* `ext-sockets`\n\n## Laravel framework support\n\nRouterOS API client is optimized for usage as normal Laravel package, all functional is available via `\\RouterOS` facade,\nfor access to client object you need instead:\n\n```php\n$config = new \\RouterOS\\Config([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin',\n    'port' =\u003e 8728,\n]);\n$client = new \\RouterOS\\Client($config);\n```\n\nUse the facade and pass array of parameters to `client` method:\n\n```php\n$client = \\RouterOS::client([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin',\n    'port' =\u003e 8728,\n]);\n```\n\nYou also may get array with all configs which was obtained from `routeros-api.php` file:\n\n```php\n$config = \\RouterOS::config([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin',\n    'port' =\u003e 8728,\n]);\n\ndump($config);\n\n$client = \\RouterOS::client($config);\n```\n\n### Laravel installation\n\nBy default, the package will automatically register its service provider, but\nif you are a happy owner of Laravel version less than 5.5, then in a project, which is using the package\n(after `composer require` is done, of course), add into`providers` block of your `config/app.php`:\n\n```php\n'providers' =\u003e [\n    // ...\n    RouterOS\\Laravel\\ServiceProvider::class,\n],\n```\n\n#### Client configuration for Laravel\n\nYou could configure the Client using Environment variables. Complete list of available Environment variables you could find at the [default configuration file](https://github.com/EvilFreelancer/routeros-api-php/blob/master/configs/routeros-api.php).\n\nOptionally you could publish the configuration file:\n\n```shell\nphp artisan vendor:publish --provider=\"RouterOS\\\\Laravel\\\\ServiceProvider\"\n```\n\n## How to use\n\nBasic example, analogue via command line is `/ip hotspot ip-binding print`:\n\n```php\nuse \\RouterOS\\Client;\nuse \\RouterOS\\Query;\n\n// Initiate client with config object\n$client = new Client([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin',\n    'port' =\u003e 8728,\n]);\n\n// Create \"where\" Query object for RouterOS\n$query =\n    (new Query('/ip/hotspot/ip-binding/print'))\n        -\u003ewhere('mac-address', '00:00:00:00:40:29');\n\n// Send query and read response from RouterOS\n$response = $client-\u003equery($query)-\u003eread();\n\nvar_dump($response);\n```\n\nBasic example for update/create/delete types of queries:\n\n```php\nuse \\RouterOS\\Client;\nuse \\RouterOS\\Query;\n\n// Initiate client with config object\n$client = new Client([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin'\n]);\n\n// Send \"equal\" query with details about IP address which should be created\n$query =\n    (new Query('/ip/hotspot/ip-binding/add'))\n        -\u003eequal('mac-address', '00:00:00:00:40:29')\n        -\u003eequal('type', 'bypassed')\n        -\u003eequal('comment', 'testcomment');\n\n// Send query and read response from RouterOS (ordinary answer from update/create/delete queries has empty body)\n$response = $client-\u003equery($query)-\u003eread();\n\nvar_dump($response);\n```\n\nIf you need export all settings from router:\n\n```php\nuse \\RouterOS\\Client;\n\n// Initiate client with config object\n$client = new Client([\n    'host'        =\u003e '192.168.1.3',\n    'user'        =\u003e 'admin',\n    'pass'        =\u003e 'admin',\n    'ssh_port'    =\u003e 22222,\n    'ssh_timeout' =\u003e 60, // if not set then 30 seconds by default \n]);\n\n// Execute export command via ssh\n$response = $client-\u003equery('/export');\n// or\n$response = $client-\u003eexport();\n\nvar_dump($response);\n``` \n\nExamples with \"where\" conditions, \"operations\" and \"tag\":\n\n```php\nuse \\RouterOS\\Query;\n\n/**\n * Simple \"where\" query will be generated by default \n */\n\n$client-\u003equery('/ip/address/print')-\u003eread();\n\n/**\n * Send advanced \"where\" query with parameters to RouterOS \n */\n\n// If only one \"where\" condition\n$client-\u003equery('/queue/simple/print', ['target', '192.168.1.1/32']);\n\n// If multiple \"where\" conditions and need merge (operation \"|\") results\n$client-\u003equery('/interface/print', [\n    ['type', 'ether'],  // same as ['type', '=', 'ether']\n    ['type', 'vlan'],   // same as ['type', '=', 'vlan']\n], '|');\n\n/**\n * Or in OOP style\n */\n\n// If you need create query for \"create/update/delete\" operations\n$query = new Query('/ip/hotspot/ip-binding/add');\n$query-\u003eequal('mac-address', '00:00:00:00:40:29');\n$query-\u003eequal('type', 'bypassed');\n$query-\u003eequal('comment', 'testcomment');\n\n// If multiple \"where\" conditions and need merge (operation \"|\") results\n$query = new Query('/interface/print');\n$query-\u003ewhere('type', 'ether');\n$query-\u003ewhere('type', 'vlan');\n$query-\u003eoperations('|');\n\n// If multiple \"where\" conditions and need append tag\n$query = new Query('/interface/set');\n$query-\u003ewhere('disabled', 'no');\n$query-\u003ewhere('.id', 'ether1');\n$query-\u003etag(4);\n\n/**\n * Write Query object to RouterOS and read response from it\n */\n\n$response = $client-\u003equery($query)-\u003eread();\n```\n\n\u003e All available examples you can find [here](https://github.com/EvilFreelancer/routeros-api-php/tree/master/examples).\n\n## How to configure the client\n\nYou just need create object of Client class with required\nparameters in array format:\n\n```php\nuse \\RouterOS\\Client;\n\n$client = new Client([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin'\n]);\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003ci\u003eℹ️ Advanced examples of Config and Client classes usage\u003c/i\u003e\n\u003c/summary\u003e\n\n```php\nuse \\RouterOS\\Config;\nuse \\RouterOS\\Client;\n\n/**\n * You can create object of Config class\n */\n\n$config = new Config();\n\n// Then set parameters of config\n$config-\u003eset('host', '192.168.1.3');\n$config-\u003eset('user', 'admin');\n$config-\u003eset('pass', 'admin');\n\n// By the way, `-\u003eset()` method is support inline style of syntax\n$config\n    -\u003eset('host', '192.168.1.3')\n    -\u003eset('user', 'admin')\n    -\u003eset('pass', 'admin');\n\n/**\n * Or just create preconfigured Config object\n */\n\n$config = new Config([\n    'host' =\u003e '192.168.1.3',\n    'user' =\u003e 'admin',\n    'pass' =\u003e 'admin'\n]);\n\n/**\n * Then send Config object to Client constructor\n */\n\n$client = new Client($config);\n```\n\n\u003c/details\u003e\n\n### List of available configuration parameters\n\n| Parameter       | Type   | Default                                                                                      | Description                                                                                                 |\n|-----------------|--------|----------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------|\n| host            | string |                                                                                              | (required) Address of Mikrotik RouterOS                                                                     |\n| user            | string |                                                                                              | (required) Username                                                                                         |\n| pass            | string |                                                                                              | (required) Password                                                                                         |\n| port            | int    |                                                                                              | RouterOS API port number for access (if not set use 8728 or 8729 if SSL enabled)                            |\n| ssl             | bool   | false                                                                                        | Enable ssl support (if port is not set this parameter must change default port to ssl port)                 |\n| ssl_options     | array  | [details](https://github.com/EvilFreelancer/routeros-api-php/blob/master/src/Config.php#L46) | See https://www.php.net/manual/en/context.ssl.php                                                           |\n| legacy          | bool   | false                                                                                        | Deprecated, will be removed from 1.5.0: Support of legacy login scheme (true - pre 6.43, false - post 6.43) |\n| timeout         | int    | 10                                                                                           | Max timeout for connecting to RouterOS (in seconds)                                                         |\n| socket_timeout  | int    | 30                                                                                           | Max read timeout from RouterOS (in seconds)                                                                 |\n| socket_blocking | bool   | true                                                                                         | Set blocking mode on a socket stream                                                                        |\n| socket_options  | array  | [details](https://github.com/EvilFreelancer/routeros-api-php/blob/master/src/Config.php#L87) | See https://www.php.net/manual/en/context.socket.php                                                        |\n| attempts        | int    | 10                                                                                           | Count of attempts to establish TCP session                                                                  |\n| delay           | int    | 1                                                                                            | Delay between attempts in seconds                                                                           |\n| ssh_port        | int    | 22                                                                                           | Number of SSH port for exporting configuration                                                              |\n| ssh_timeout     | int    | 30                                                                                           | Max timeout from router via SSH (in seconds)                                                                |\n| ssh_private_key | string | ~/.ssh/id_rsa                                                                                | Full path to required private key                                                                           |\n\n### How to enable support of legacy login schema (RouterOS pre-6.43)\n\n\u003e From 0.8.1 this is not important, version of firmware will be detected automatically.\n\u003e Deprecated, will be removed from 1.5.0\n\n```php\n\u003c?php\nrequire_once __DIR__ . '/vendor/autoload.php';\n\nuse \\RouterOS\\Client;\n\n// Initiate client with config object\n$client = new Client([\n    'host'   =\u003e '192.168.1.3',\n    'user'   =\u003e 'admin',\n    'pass'   =\u003e 'admin',\n    'legacy' =\u003e true // you need set `legacy` parameter with `true` value\n]);\n\n// Your code below...\n```\n\n## How to write queries\n\nYou can write absolutely any queries to your router, for this you\nneed to create a \"Query\" object whose first argument is the\nrequired command, after this you can add the attributes of the\ncommand to \"Query\" object.\n\nMore about attributes and \"words\" from which these attributes\nshould be created [here](https://wiki.mikrotik.com/wiki/Manual:API#Command_word). \n\nMore about \"expressions\", \"where\", \"equal\" and other filters/modifications\nof your query you can find [here](https://wiki.mikrotik.com/wiki/Manual:API#Queries).\n\nSimple usage examples of Query class:\n\n```php\nuse \\RouterOS\\Query;\n\n// Get all installed packages (it may be enabled or disabled)\n$query = new Query('/system/package/getall');\n\n// Send \"equal\" query with details about IP address which should be created\n$query =\n    (new Query('/ip/hotspot/ip-binding/add'))\n        -\u003eequal('mac-address', '00:00:00:00:40:29')\n        -\u003eequal('type', 'bypassed')\n        -\u003eequal('comment', 'testcomment');\n\n// Set where interface is disabled and ID is ether1 (with tag 4)\n$query = \n    (new Query('/interface/set'))\n        -\u003ewhere('disabled', 'no')\n        -\u003ewhere('.id', 'ether1')\n        -\u003etag(4);\n\n// Get all ethernet and VLAN interfaces\n$query = \n    (new Query('/interface/print'))\n        -\u003ewhere('type', 'ether')\n        -\u003ewhere('type', 'vlan')\n        -\u003eoperations('|');\n\n// Get all routes that have non-empty comment\n$query =\n    (new Query('/ip/route/print'))\n        -\u003ewhere('comment', '\u003e', null);\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\n\u003ci\u003eℹ️ Advanced examples of Query class usage\u003c/i\u003e\n\u003c/summary\u003e\n\n```php\nuse \\RouterOS\\Query;\nuse \\RouterOS\\Client;\n\n// Initiate connection to RouterOS\n$client = new Client([\n    'host'   =\u003e '192.168.1.3',\n    'user'   =\u003e 'admin',\n    'pass'   =\u003e 'admin'\n]);\n\n/**\n * Execute query directly through \"-\u003equery()\" method of Client class \n */\n\n// If your query has no \"where\" conditions\n$client-\u003equery('/ip/arp/print');\n\n// If you have only one where condition, you may use one dimensional array as second parameter of query method\n$client-\u003equery('/queue/simple/print', ['target', '192.168.1.250/32']);\n\n// If you need set few where conditions then need use multi dimensional array\n$client-\u003equery('/interface/bridge/add', [\n    ['name', 'vlan100-bridge'],\n    ['vlan-filtering', 'no']\n]);\n\n/**\n * By some reason you may need restrict scope of RouterOS response,\n * for this need to use third attribute of \"-\u003equery()\" method\n */\n\n// Get all ethernet and VLAN interfaces\n$client-\u003equery('/interface/print', [\n    ['type', 'ether'],\n    ['type', 'vlan']\n], '|');\n\n/** \n * If you want set tag of your query then you need to use fourth \n * attribute of \"-\u003equery()\" method, but third attribute may be null\n */\n\n// Enable interface (tag is 4)\n$client-\u003equery('/interface/set', [\n    ['disabled', 'no'],\n    ['.id', 'ether1']\n], null, 4);\n\n/**\n * Or in OOP style  \n */\n\n// Get all ethernet and VLAN interfaces\n$query = new Query('/interface/print');\n$query-\u003ewhere('type', 'ether');\n$query-\u003ewhere('type', 'vlan');\n$query-\u003eoperations('|');\n\n// Enable interface (tag is 4)\n$query = new Query('/interface/set');\n$query-\u003eequal('disabled', 'no');\n$query-\u003eequal('.id', 'ether1');\n$query-\u003etag(4);\n\n// Or, RAW mode\n\n$query = new Query('/interface/set');\n$query-\u003eadd('=disabled=no');\n$query-\u003eadd('=.id=ether1');\n$query-\u003eadd('.tag=4');\n\n// Or, RAW mode in format of array\n    \n$query = new Query('/interface/set', [\n    '=disabled=no',\n    '=.id=ether1',\n    '.tag=4'\n]);\n\n// Or\n\n$query = new Query([\n    '/interface/set',\n    '=disabled=no',\n    '=.id=ether1',\n    '.tag=4'\n]);\n\n/**\n * Write Query object to RouterOS and read response from it\n */\n\n$response = $client-\u003equery($query)-\u003eread();\n```\n\n\u003c/details\u003e\n\n## Read response as Iterator\n\nBy default, original solution of this client is not optimized for\nwork with a large amount of results, only for small count of lines\nin response from RouterOS API.\n\nBut some routers may have (for example) 30000+ records in\ntheir firewall list. Specifically for such tasks, a method\n`readAsIterator` has been added that converts the results\nobtained from the router into a resource, with which it will\nlater be possible to work.\n\n\u003e You could treat response as an array except using any array_* functions\n\n```php\n$response = $client-\u003equery($query)-\u003ereadAsIterator();\nvar_dump($response);\n\n// The following for loop allows you to skip elements for which\n// $iterator-\u003ecurrent() throws an exception, rather than breaking\n// the loop.\nfor ($response-\u003erewind(); $response-\u003evalid(); $response-\u003enext()) {\n    try {\n        $value = $response-\u003ecurrent();\n    } catch (Exception $exception) {\n        continue;\n    }\n\n    # ...\n}\n```\n\n## Short methods\n\nYou can simplify your code and send then read from socket in one line:\n\n```php\n/** \n * Execute query and read response in ordinary mode \n */\n$response = $client-\u003equery($query)-\u003eread();\nvar_dump($response);\n\n// Or\n$response = $client-\u003eq($query)-\u003er();\nvar_dump($response);\n\n// Single method analog of lines above is\n$response = $client-\u003eqr($query);\nvar_dump($response);\n\n/**\n * Execute query and read response as Iterator \n */\n$response = $client-\u003equery($query)-\u003ereadAsIterator();\nvar_dump($response);\n\n// Or\n$response = $client-\u003eq($query)-\u003eri();\nvar_dump($response);\n\n// Single method analog of lines above is\n$response = $client-\u003eqri($query);\nvar_dump($response);\n\n/**\n * By the way, you can send few queries to your router without result: \n */\n$client-\u003equery($query1)-\u003equery($query2)-\u003equery($query3);\n\n// Or\n$client-\u003eq($query1)-\u003eq($query2)-\u003eq($query3);\n```\n\n## Known issues\n\n### Unable to establish socket session, Operation timed out\n\nThis error means that the library cannot connect to your router,\nit may mean router turned off (then need turn on), or the API service not enabled.\n\nGo to `Mikrotik Router OS -\u003e IP -\u003e Services` and enable `api` service.\n\nOr via command line:\n\n```shell script\n/ip service enable api \n```\n\n### How to update/remove/create something via API?\n\nInstead of `-\u003ewhere()` method of `Query` class you need to\nuse `-\u003eequal()` method:\n\n```php\n// Create query which should remove security profile\n$query = new \\RouterOS\\Query('/interface/wireless/security-profiles/remove');\n\n// It will generate queries, which stared from \"?\" symbol:\n$query-\u003ewhere('.id', '*1');\n\n/*\n// Sample with -\u003ewhere() method\nRouterOS\\Query Object\n(\n    [_attributes:RouterOS\\Query:private] =\u003e Array\n        (\n            [0] =\u003e ?.id=*1\n        )\n\n    [_operations:RouterOS\\Query:private] =\u003e \n    [_tag:RouterOS\\Query:private] =\u003e \n    [_endpoint:RouterOS\\Query:private] =\u003e /interface/wireless/security-profiles/remove\n)\n*/\n\n// So, as you can see, instead of `-\u003ewhere()` need to use `-\u003eequal()`\n// It will generate queries, which stared from \"=\" symbol:\n$query-\u003eequal('.id', '*1');\n\n/*\n// Sample with -\u003eequal() method\nRouterOS\\Query Object\n(\n    [_attributes:RouterOS\\Query:private] =\u003e Array\n        (\n            [0] =\u003e =.id=*1\n        )\n\n    [_operations:RouterOS\\Query:private] =\u003e \n    [_tag:RouterOS\\Query:private] =\u003e \n    [_endpoint:RouterOS\\Query:private] =\u003e /interface/wireless/security-profiles/remove\n)\n*/\n```\n\n### Undefined character (any non-English languages)\n\nRouterOS does not support national languages, only English (and API of RouterOS too).\n\nYou can try to reproduce it via web, for example add the comment to any\nelement of your system, then save and reload the page, you will see unreadable characters.\n\n## Testing\n\nYou can use my [other project](https://github.com/EvilFreelancer/docker-routeros)\nwith RouterOS in Docker container for running unit testing on your\ncomputer, for this you just need to have [Expect](https://wiki.debian.org/Expect),\n[Docker](https://docs.docker.com/install/) and [Docker Compose](https://docs.docker.com/compose/install/).\n\nNext clone the repo with RouterOS in Docker and exec\n`docker-compose up -d`, then you need preconfigure virtual routers\nvia [preconf.tcl](https://github.com/EvilFreelancer/routeros-api-php/blob/master/preconf.tcl)\nscript from root of routeros-api-php:\n\n```\n./preconf.tcl 12223\n./preconf.tcl 22223\n```\n\nAnd after this you can run tests:\n\n```\n./vendor/bin/phpunit\n```\n\n## Links\n\n* [Cloud Hosted Router](https://mikrotik.com/download#chr) - Virtual images of RouterOS for your hypervisor \n* [RouterOS Manual:API](https://wiki.mikrotik.com/wiki/Manual:API) - In case if you are wondering what is insane\n","funding_links":["https://pay.cloudtips.ru/p/937f48ac","https://boosty.to/evilfreelancer"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilfreelancer%2Frouteros-api-php","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fevilfreelancer%2Frouteros-api-php","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fevilfreelancer%2Frouteros-api-php/lists"}