Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Routeros Api Php Laravel Package

evilfreelancer/routeros-api-php

A modern PHP client for the MikroTik RouterOS API. Connect to RouterOS 6 and 7 devices, run commands, and parse responses through a clean, framework-agnostic, object-oriented interface. Install via Composer and use it in Laravel or any PHP project.

View on GitHub
Deep Wiki
Context7

Getting Started

evilfreelancer/routeros-api-php is a low-level, framework-agnostic client for the MikroTik RouterOS binary API (port 8728, or 8729 over TLS). In Laravel it is not auto-discovered — you wire it up yourself.

Minimal setup:

composer require evilfreelancer/routeros-api-php

Add credentials to config/services.php (do not hardcode them in code):

'routeros' => [
    'host'       => env('ROUTEROS_HOST', '192.168.88.1'),
    'user'       => env('ROUTEROS_USER', 'admin'),
    'pass'       => env('ROUTEROS_PASS', ''),
    'port'       => (int) env('ROUTEROS_PORT', 8728),
    'ssl'        => (bool) env('ROUTEROS_SSL', false),
    'timeout'    => 10,
    'attempts'   => 2,
],

Bind it as a singleton in AppServiceProvider:

use RouterOS\Client;

$this->app->singleton(Client::class, fn () => new Client(config('services.routeros')));

First use case — list DHCP leases:

use RouterOS\Query;

$rows = app(\RouterOS\Client::class)
    ->query((new Query('/ip/dhcp-server/lease/print'))->where('status', 'bound'))
    ->read();

Look first at the RouterOS\Client, RouterOS\Query, and RouterOS\Config classes; nearly everything is query(Query $q)->read().

Implementation Patterns

Wrap the client in a domain service. Do not inject RouterOS\Client into controllers — you will leak query strings everywhere and have no seam for tests.

class RouterOsService
{
    public function __construct(private Client $client) {}

    public function activeLeases(): array
    {
        return $this->client
            ->query((new Query('/ip/dhcp-server/lease/print'))->where('status', 'bound'))
            ->read();
    }
}

Read vs write queries. print/getall support ->where($key, $value); commands must be built as operations:

$q = new Query('/ip/hotspot/user/add');
$q->equal('name', 'guest-01')->equal('password', 'secret')->equal('profile', 'default');
$client->query($q)->read();

Named connections for multiple routers. The package's Config is a plain value object, so build clients via a factory keyed by router name rather than a single singleton:

$client = new Client(config("routeros.routers.{$name}"));

Resolve per-request or cache in a RouterRegistry service. This is the cleanest way to support a fleet without abusing the container.

Multi-command batching with tags. Use ->tag('x') when sending related queries so you can correlate responses — RouterOS does not preserve ordering guarantees across interleaved commands, and the response array contains tag keys.

Queue jobs for anything mutating. Wrap writes in a job with $tries = 1 (or explicit retry policy). RouterOS commands are not idempotent — blind framework-level retries on timeout will duplicate users/queues/rules.

Scheduled commands for polling. A daily/5-min Artisan command that pulls counters into Eloquent is the standard pattern; keep the raw read() result short-lived and map it immediately to your own DTOs, since the package returns arrays with RouterOS-specific keys (.id, and per-command field names).

PSR-3 logging. Pass 'logger' => $psr3Logger in the config array; the client emits connection/query events you can route to a routeros log channel.

Testing. The package has no fakes. Bind a stub Client subclass or a mocked RouterOsService in the container — your service wrapper is the mocking boundary.

Gotchas and Tips

  • Persistent sockets in long-lived workers. The client holds an open stream. Under Horizon/Octane, a connection reused across a sleep or long queue can be silently dead. Catch StreamException/ClientException and reconnect ($client = new Client(...)) rather than retrying on the same instance.
  • Timeouts are two different things. timeout (seconds, connection/attempt) and stream-level timeouts have separate semantics, and the 1.7.0 fix specifically corrects PHP 8.4 stream timeout handling (issue #131). If you were pinballing between "connection hangs forever on 8.4" and "premature timeout", upgrade — but still set a small timeout and treat every call as failing.
  • Empty responses are now safe. 1.7.0 (issue #136) fixes parsing of empty responses for nested script execution, e.g. :execute or scripts that call scripts. Before this, those paths could throw or return null. If your code has a defensive if (empty($response)) before 1.7.0, keep it but note it is no longer the failure mode.
  • Windows dev environments. 1.7.0 (PR #142) adds Windows compatibility; the word-splitting logic previously misbehaved with CRLF. If you develop on Laravel Herd for Windows and test against a CHR VM, upgrade before filing bugs.
  • RouterOS API-SSL is not HTTP TLS. Certificates are self-signed and there is no hostname verification; port 8729 is a raw TLS socket. Do not expect Laravel's SSL config to apply.
  • No escaping for values. Query::equal() writes the value into a length-prefixed word — the transport is safe from injection, but you must still validate untrusted input (a user-supplied address can add anything valid in RouterOS syntax). Never interpolate user input into a raw Query path such as /system/script/run arguments.
  • .id keys. Every returned record has a '.id' => '*1A' style key. Strip it before persisting or serialising to JSON.
  • Commands need read() too. query() returns the client (fluent), not a result. Forgetting ->read() yields a no-op-looking success.
  • Permissions. API users need api, read, write policies; a 401 manifests as BadCredentialsException, but an under-privileged user surfaces as an empty or error word — log the raw response when debugging.
  • Bulk reads are memory-heavy. /ip/firewall/connection/print and similar can return tens of thousands of rows into a PHP array. Filter server-side with ->where() or ->operations() and paginate with ->equal('count', N) style queries where the menu supports it.
  • Extension points are limited by design: subclass RouterOS\Client to add retry/metrics behaviour, implement PSR-3 for logging, and use RouterOS\Config for validation. There are no events or middleware — put your observability in the service wrapper.

Upgrade from 1.6.0 is non-breaking (three bug fixes, two first-time contributors); it is worth taking for the PHP 8.4 and Windows fixes alone.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings