├── .gitignore ├── composer.json ├── composer.lock ├── config └── mikrotik.php ├── phpunit.xml ├── readme.md ├── src ├── Commands │ ├── Command.php │ ├── Interfaces.php │ └── Ip.php ├── Contracts │ ├── ClientContract.php │ ├── CommandContract.php │ └── MikrotikContract.php ├── Core │ ├── Client.php │ ├── Collection.php │ ├── QueryBuilder.php │ └── Request.php ├── Entity │ ├── Address.php │ ├── Bridge.php │ ├── Entity.php │ ├── Ethernet.php │ ├── GenericEntity.php │ └── InterfaceEntity.php ├── Exceptions │ ├── CommandException.php │ ├── ConnectionException.php │ ├── InvalidCommandException.php │ └── WrongArgumentTypeException.php ├── Facades │ └── MikrotikFacade.php ├── Mikrotik.php ├── MikrotikServiceProvider.php └── Support │ ├── EntityUtils.php │ └── InterfaceEnums.php └── tests ├── AuthTest.php ├── InterfacesCommandsTest.php ├── IpCommandsTest.php ├── StaticCommandTest.php └── Traits └── CreateApplication.php /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/storage 3 | /public/hot 4 | /storage/*.key 5 | /bootstrap 6 | /vendor 7 | /.idea 8 | Homestead.json 9 | Homestead.yaml 10 | .env 11 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jjsquady/mikrotikapi", 3 | "description": "An Mikrotik Api Wrapper", 4 | "minimum-stability": "dev", 5 | "prefer-stable": true, 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Jorge 'jjsquady' Junior", 10 | "email": "jjsquady@gmail.com" 11 | } 12 | ], 13 | "autoload": { 14 | "psr-4": { 15 | "jjsquady\\MikrotikApi\\": "src/" 16 | } 17 | }, 18 | "autoload-dev": { 19 | "psr-4": { 20 | "jjsquady\\MikrotikApi\\Tests\\": "tests/" 21 | } 22 | }, 23 | 24 | "require": { 25 | "php": "^7.4", 26 | "pear2/net_routeros": "1.0.0b6", 27 | "pear2/net_transmitter": "1.0.0b2" 28 | }, 29 | "require-dev": { 30 | "laravel/framework": "^8.11", 31 | "orchestra/testbench": "^6.2", 32 | "phpunit/phpunit": "^9.4" 33 | }, 34 | "extra": { 35 | "branch-alias": { 36 | "dev-master": "1.0-dev" 37 | }, 38 | "laravel": { 39 | "providers": [ 40 | "jjsquady\\MikrotikApi\\MikrotikServiceProvider" 41 | ], 42 | "aliases": { 43 | "Mikrotik": "jjsquady\\MikrotikApi\\Facades\\MikrotikFacade" 44 | } 45 | } 46 | }, 47 | "config": { 48 | "sort-packages": true 49 | }, 50 | "scripts": { 51 | "test": "vendor/bin/phpunit" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /config/mikrotik.php: -------------------------------------------------------------------------------- 1 | [ 5 | 'host' => env('MK_API_HOST', null), 6 | 'user' => env('MK_API_USER', 'admin'), 7 | 'password' => env('MK_API_PASSWORD', ''), 8 | 'port' => env('MK_API_PORT', 8728) 9 | ], 10 | 'entities' => [ 11 | 'interface' => \jjsquady\MikrotikApi\Entity\InterfaceEntity::class 12 | ] 13 | ]; -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests 15 | 16 | 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Mikrotik Api for Laravel 8.x 2 | WIP - Work In Progress 3 | 4 | Instalation 5 | ---- 6 | 7 | Via composer: 8 | ``` 9 | composer require jjsquady/mikrotikapi 10 | ``` 11 | 12 | Or manually insert this block into your composer.json in require section: 13 | ``` 14 | "require": { 15 | "jjsquady/mikrotikapi": "dev-master", // <- this line 16 | } 17 | ``` 18 | 19 | Configuration on Laravel (< 5.4): 20 | ---- 21 | 22 | Insert into `config/app.php` in `providers` array: 23 | 24 | ``` 25 | jjsquady\MikrotikApi\MikrotikServiceProvider::class 26 | ``` 27 | 28 | #### Use the Facade: 29 | 30 | Insert into `config/app.php` in `facades` array: 31 | 32 | ``` 33 | 'Mikrotik' => jjsquady\MikrotikApi\Facades\MikrotikFacade::class 34 | ``` 35 | 36 | **Note:** for Laravel 5.4+ this package comes with Package Discovery enabled. 37 | 38 | 39 | #### Publish the configuration file: 40 | 41 | ``` 42 | php artisan vendor:publish --provider=jjsquady\MikrotikApi\MikrotikServiceProvider 43 | ``` 44 | 45 | Basic Usage: 46 | ---- 47 | 48 | Set up the host and credentials into .env file: 49 | 50 | ```$bash 51 | MK_API_HOST= 52 | MK_API_USER= 53 | MK_API_PASSWORD= 54 | MK_API_PORT= 55 | ``` 56 | 57 | ```$php 58 | 59 | // create a connection with Mikrotik Router 60 | 61 | $conn = Mikrotik::connect()->getConnection(); 62 | 63 | if($conn->isConnected()) { 64 | // you have access to Commands 65 | // and can call from here... 66 | } 67 | ``` 68 | 69 | Getting interfaces: 70 | --- 71 | ```$php 72 | $conn = Mikrotik::connect()->getConnection(); 73 | 74 | if($conn->isConnected()) { 75 | // Get all interfaces 76 | $interfaces = Interfaces::bind($conn)->get(); 77 | 78 | // get() returns a Collection and you can use all methods available 79 | 80 | // you can send it to view 81 | return view("", [ 82 | 'interfaces' => $interfaces 83 | ]); 84 | } 85 | ``` 86 | 87 | This project its a work in progress... and its in early developing phase. 88 | I really get thankful with ur contribution. 89 | 90 | ##### Created by jjsquady (Jorge Junior) 91 | ##### (cc) 2017-2019 92 | ##### License: MIT 93 | -------------------------------------------------------------------------------- /src/Commands/Command.php: -------------------------------------------------------------------------------- 1 | client = $client; 86 | 87 | $this->entityClass = $this->entityClass ?? GenericEntity::class; 88 | 89 | $this->entity = (new $this->entityClass); 90 | 91 | $this->rootPath = $this->entity->getPath(); 92 | 93 | if(!$this->rootPath) { 94 | throw new CommandException('Command not found.'); 95 | } 96 | 97 | $this->request = new Request($this->rootPath); 98 | } 99 | 100 | /** 101 | * @param $command 102 | * @param null $args 103 | * @return $this 104 | */ 105 | private function executeCommand($command, $args = null) 106 | { 107 | $this->request = new Request($command); 108 | 109 | $this->processCommandArgs($args); 110 | 111 | $this->_response = $this->processCommand(); 112 | 113 | return $this; 114 | 115 | } 116 | 117 | /** 118 | * 119 | * @return \jjsquady\MikrotikApi\Core\Collection 120 | */ 121 | public function get() 122 | { 123 | $this->executeCommand($this->rootPath . '/print'); 124 | return $this->convertArrayToEntities($this->_response); 125 | } 126 | 127 | public function remove($id) 128 | { 129 | $this->executeCommand($this->rootPath . '/remove', ['.id' => $id]); 130 | } 131 | 132 | public function find($attribute, $value = null) 133 | { 134 | // TODO: Implement find() method. 135 | } 136 | 137 | /** 138 | * @return mixed 139 | */ 140 | public function getBaseCommand() 141 | { 142 | return $this->rootPath; 143 | } 144 | 145 | /** 146 | * @param array $args 147 | * @return string 148 | */ 149 | protected function buildCommandPath(array $args) 150 | { 151 | if (!is_array($args)) { 152 | //TODO: throw exception 153 | } 154 | 155 | if (empty(array_last($args))) { 156 | return implode('', $args); 157 | } 158 | 159 | return implode("/", $args); 160 | } 161 | 162 | /** 163 | * @param $name 164 | * @param $arguments 165 | * @return QueryBuilder 166 | * @throws InvalidCommandException 167 | */ 168 | public function __call($name, $arguments) 169 | { 170 | if (array_key_exists($name, $this->commands)) { 171 | $command = array_key_exists($name, $this->commandsAlias) ? $this->commandsAlias[$name] : $name; 172 | $fullCommand = $this->buildCommandPath([$this->base_command, $command]); 173 | return $this->buildNewQuery($this->commands[$name], $fullCommand); 174 | } 175 | 176 | throw new InvalidCommandException($name); 177 | } 178 | 179 | /** 180 | * @param $entityClass 181 | * @param $command 182 | * @return QueryBuilder 183 | */ 184 | protected function buildNewQuery($entityClass, $command) 185 | { 186 | $this->query = new QueryBuilder($entityClass, $command, $this->client); 187 | return $this->query; 188 | } 189 | 190 | /** 191 | * @return \PEAR2\Net\RouterOS\ResponseCollection 192 | */ 193 | private function processCommand() 194 | { 195 | return $this->client->sendSync($this->request); 196 | } 197 | 198 | /** 199 | * @param $args 200 | */ 201 | private function processCommandArgs($args) 202 | { 203 | if (!is_array($args)) { 204 | return; 205 | } 206 | 207 | array_map(function ($arg) { 208 | $this->request->setArgument($arg); 209 | }, $args); 210 | } 211 | 212 | public static function bind(Client $client) 213 | { 214 | try { 215 | 216 | return new static($client); 217 | 218 | } catch (CommandException $e) { 219 | 220 | throw new CommandException($e); 221 | 222 | } 223 | } 224 | 225 | } -------------------------------------------------------------------------------- /src/Commands/Interfaces.php: -------------------------------------------------------------------------------- 1 | entityClass = config('mikrotik.entities.interface'); 28 | 29 | parent::__construct($client); 30 | } 31 | 32 | /** 33 | * @param $id 34 | * @throws CommandException 35 | */ 36 | public function remove($id) 37 | { 38 | throw new CommandException('Interfaces cannot be removed.'); 39 | } 40 | } -------------------------------------------------------------------------------- /src/Commands/Ip.php: -------------------------------------------------------------------------------- 1 | Address::class, 29 | 'arp' => Arp::class, 30 | 'accounting' => Accounting::class 31 | ]; 32 | 33 | public function address() 34 | { 35 | return $this->__call("address", null); 36 | } 37 | 38 | public function arp() 39 | { 40 | return $this->__call("arp", null); 41 | } 42 | 43 | } -------------------------------------------------------------------------------- /src/Contracts/ClientContract.php: -------------------------------------------------------------------------------- 1 | connected = true; 32 | 33 | }catch (\Exception $exception) { 34 | 35 | $this->connected = false; 36 | 37 | throw new ConnectionException($exception->getMessage()); 38 | } 39 | } 40 | 41 | /** 42 | * @return mixed 43 | */ 44 | public function isConnected() 45 | { 46 | return $this->connected; 47 | } 48 | } -------------------------------------------------------------------------------- /src/Core/Collection.php: -------------------------------------------------------------------------------- 1 | entityClass = $entityClassName; 28 | $this->client = $client; 29 | $this->directory = $directory; 30 | } 31 | 32 | public static function find($params) 33 | { 34 | 35 | } 36 | 37 | public static function where($property, $value = null, $operator = self::OP_EQ) 38 | { 39 | 40 | } 41 | 42 | public function all() 43 | { 44 | return $this->execute(); 45 | } 46 | 47 | public function first() 48 | { 49 | return $this->all()->first(); 50 | } 51 | 52 | public function get($args = array(), $query = null) 53 | { 54 | return $this->execute($args, $query); 55 | } 56 | 57 | private function execute($args = array(), $query = null) 58 | { 59 | $util = new Util($this->client); 60 | 61 | $util->setMenu($this->directory); 62 | 63 | $items = $util->getAll($args, $query); 64 | 65 | return $this->convertArrayToEntities($items, $this->entityClass); 66 | } 67 | 68 | 69 | } -------------------------------------------------------------------------------- /src/Core/Request.php: -------------------------------------------------------------------------------- 1 | query = $query; 31 | } 32 | } 33 | 34 | public function getPath() 35 | { 36 | return $this->directory; 37 | } 38 | 39 | public function toArray() 40 | { 41 | return get_object_vars($this); 42 | } 43 | 44 | public function getDirectory() 45 | { 46 | return $this->directory; 47 | } 48 | 49 | /** 50 | * @return string 51 | */ 52 | public function __toString() 53 | { 54 | return json_encode($this); 55 | } 56 | 57 | /** 58 | * @param $property 59 | * @return null 60 | */ 61 | public function __get($property) 62 | { 63 | $propertyClean = $this->convertToDashes($property); 64 | 65 | if (isset($this->fillable)) { 66 | return $this->getFillableProperty($propertyClean); 67 | } 68 | 69 | return property_exists($this, $propertyClean) ? $this->{$propertyClean} : null; 70 | } 71 | 72 | public function setAttributes(array $attributes) 73 | { 74 | foreach ($attributes as $attribute => $value) { 75 | in_array($attribute, $this->fillable) ? $this->{$attribute} = $value : null; 76 | } 77 | 78 | return $this; 79 | } 80 | 81 | /** 82 | * If $fillable array its set, then looks into this array for properties 83 | * @param $property 84 | * @return null 85 | */ 86 | private function getFillableProperty($property) 87 | { 88 | return in_array($property, $this->fillable) ? 89 | property_exists($this, $property) ? 90 | $this->{$property} : 91 | null : 92 | null; 93 | } 94 | 95 | /** 96 | * Convertes a camelCase property to hyphened-case (myProp -> my-prop) 97 | * @param $property 98 | * @return string 99 | */ 100 | private function convertToDashes($property) 101 | { 102 | preg_match_all('!([A-Z][A-Z0-9]*(?=$|[A-Z][a-z0-9])|[A-Za-z][a-z0-9]+)!', $property, $matches); 103 | $ret = $matches[0]; 104 | foreach ($ret as &$match) { 105 | $match = $match == strtoupper($match) ? strtolower($match) : lcfirst($match); 106 | } 107 | return implode('-', $ret); 108 | } 109 | } -------------------------------------------------------------------------------- /src/Entity/Ethernet.php: -------------------------------------------------------------------------------- 1 | credentials = [ 41 | 'host' => $host, 42 | 'username' => $username, 43 | 'password' => $password, 44 | 'port' => $port 45 | ]; 46 | } 47 | 48 | /** 49 | * Connects to a MK host 50 | * 51 | * @return Mikrotik 52 | * @throws ConnectionException 53 | */ 54 | public function connect() 55 | { 56 | $this->connection = new Client(...array_values($this->credentials)); 57 | 58 | return $this; 59 | } 60 | 61 | /** 62 | * @return Client 63 | */ 64 | public function getConnection() 65 | { 66 | return $this->connection; 67 | } 68 | 69 | /** 70 | * Get the credentials 71 | * @return array 72 | */ 73 | public function getCredentials() 74 | { 75 | return $this->credentials; 76 | } 77 | 78 | } -------------------------------------------------------------------------------- /src/MikrotikServiceProvider.php: -------------------------------------------------------------------------------- 1 | publishes([ 21 | __DIR__ . '/../config/mikrotik.php' => config_path('mikrotik.php') 22 | ]); 23 | } 24 | 25 | /** 26 | * Register the application services. 27 | * 28 | * @return void 29 | */ 30 | public function register() 31 | { 32 | $this->mergeConfigFrom(__DIR__ . '/../config/mikrotik.php', 'mikrotik'); 33 | 34 | $this->app->singleton('mikontrollib', function($app) { 35 | return new Mikrotik( 36 | config('mikrotik.auth.host'), 37 | config('mikrotik.auth.user'), 38 | config('mikrotik.auth.password'), 39 | config('mikrotik.auth.port'), 40 | ); 41 | }); 42 | } 43 | 44 | public function provides() 45 | { 46 | return [ 47 | 'mikontrollib' 48 | ]; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/Support/EntityUtils.php: -------------------------------------------------------------------------------- 1 | getType() == Response::TYPE_DATA) { 37 | $collection->add( 38 | $this->entity->setAttributes($this->getEntityProperties($item)) 39 | ); 40 | } 41 | } 42 | 43 | return $collection; 44 | } 45 | 46 | /** 47 | * @param $array 48 | * @return array 49 | */ 50 | private function getEntityProperties($array) 51 | { 52 | $attributes = []; 53 | 54 | foreach ($array as $property => $value) { 55 | $attributes[$property] = $value; 56 | } 57 | 58 | return $attributes; 59 | } 60 | } -------------------------------------------------------------------------------- /src/Support/InterfaceEnums.php: -------------------------------------------------------------------------------- 1 | mikrotik = Mikrotik::connect(); 31 | 32 | $this->client = $this->mikrotik->getClient(); 33 | } 34 | 35 | public function test_if_connection_returns_client_instance() 36 | { 37 | $this->assertInstanceOf(Client::class, $this->client); 38 | } 39 | 40 | public function test_if_throws_connection_exception() 41 | { 42 | $this->expectException(ConnectionException::class); 43 | 44 | (new \jjsquady\MikrotikApi\Mikrotik(config('mikrotik.auth.host'), 'wronguser'))->connect(); 45 | 46 | } 47 | 48 | public function test_getting_credentials() 49 | { 50 | $this->assertIsArray($this->mikrotik->getCredentials()); 51 | 52 | $this->assertTrue(in_array('admin', $this->mikrotik->getCredentials())); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /tests/InterfacesCommandsTest.php: -------------------------------------------------------------------------------- 1 | client = Mikrotik::connect()->getClient(); 28 | } 29 | 30 | public function test_execute_command_sync_response_array() 31 | { 32 | $response = Interfaces::bind($this->client) 33 | ->get() 34 | ->toArray(); 35 | $this->assertEquals(true, is_array($response)); 36 | } 37 | 38 | public function test_returns_an_interface_entity_object() 39 | { 40 | $response = Interfaces::bind($this->client)->get()->first(); 41 | $this->assertInstanceOf(InterfaceEntity::class, $response); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /tests/IpCommandsTest.php: -------------------------------------------------------------------------------- 1 | jjsquady\MikrotikApi\Facades\MikrotikFacade::class 27 | ]; 28 | } 29 | 30 | public function getConn() 31 | { 32 | $client = Mikrotik::connect(['192.168.0.20', 'admin', '']); 33 | return $client; 34 | } 35 | 36 | public function test_if_command_works() 37 | { 38 | $this->assertInstanceOf(Ip::class, new Ip($this->getConn())); 39 | } 40 | 41 | public function test_if_command_address_exists() 42 | { 43 | $ipcomm = new Ip($this->getConn()); 44 | $this->assertInstanceOf(QueryBuilder::class, $ipcomm->address()); 45 | } 46 | 47 | public function test_arp_method() 48 | { 49 | $ipcomm = new Ip($this->getConn()); 50 | $this->assertInstanceOf(QueryBuilder::class, $ipcomm->arp()); 51 | } 52 | 53 | public function test_accounting_method() 54 | { 55 | $ipcomm = new Ip($this->getConn()); 56 | $this->assertInstanceOf(Collection::class, $ipcomm->accounting()->all()); 57 | } 58 | } -------------------------------------------------------------------------------- /tests/StaticCommandTest.php: -------------------------------------------------------------------------------- 1 | assertInstanceOf(Client::class, Mikrotik::connect()->getClient()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tests/Traits/CreateApplication.php: -------------------------------------------------------------------------------- 1 | load(); 22 | $app['config']->set('mikrotik.auth.host', $env['MK_API_HOST']); 23 | $app['config']->set('mikrotik.auth.user', $env['MK_API_USER']); 24 | $app['config']->set('mikrotik.auth.password', $env['MK_API_PASSWORD']); 25 | $app['config']->set('mikrotik.auth.port', $env['MK_API_PORT']); 26 | } 27 | 28 | protected function getPackageProviders($app) 29 | { 30 | return [\jjsquady\MikrotikApi\MikrotikServiceProvider::class]; 31 | } 32 | 33 | protected function getPackageAliases($app) 34 | { 35 | return [ 36 | 'Mikrotik' => \jjsquady\MikrotikApi\Facades\MikrotikFacade::class 37 | ]; 38 | } 39 | } --------------------------------------------------------------------------------