print ppp active connections and interface list PEAR2 PHP

Hi guys, im here again, with a new code:

<?php use PEAR2\Net\RouterOS; // require_once 'pear2\src\PEAR2\Autoload.php'; require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar'; //IP MIKROTIK //Usuario //Password $client = new RouterOS\Client('xxx.xxx.xxx.xxx, 'admin', 'admin'); //Conexion a Mikrotik // Tabla echo ""; echo ""; //Actualizar pagina echo ""; $interfaces = $client->sendSync(new RouterOS\Request('/interface/pppoe-server/print')); $ppps = $client->sendSync(new RouterOS\Request('/ppp/active/print')); if ($interfaces['name']==$ppps['name']) { foreach (array_combine($interfaces, $ppps) as $interface => $ppp) { if ($interface->getType() === RouterOS\Response::TYPE_DATA OR $ppp->getType() === RouterOS\Response::TYPE_DATA ) { $id = $interface('.id'); $id2 = $ppp ('.id'); echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } } } echo "
NombreServicioTiempo Activo DireccionReiniciar
". $interface('name') ."" . $interface('service'). "" . $interface('uptime'). "". $ppp('address') ."
" ?>This time, i need a list with ppp active connections, service, uptime, address, and a reboot connection button.

I think, i need combine 2 print arrays(pppoe-server and active ppp), but dont print nothing :S
And i don know how to reboot the active connection with API.

Thanks :slight_smile:

I’m not using PPP, so I don’t know for sure, but… doesn’t the “active” entry contain all the information you need? Why lookup the non-active interfaces’ info to begin with?

As for the combine… it doesn’t work, because the response from sendSync() is not an array, but a ResponseCollection object.

Speaking of which, you can more easily print the data responses by using its getAllOfType() method, e.g.

<?php use PEAR2\Net\RouterOS; // require_once 'pear2\src\PEAR2\Autoload.php'; require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar'; //IP MIKROTIK //Usuario //Password $client = new RouterOS\Client('xxx.xxx.xxx.xxx, 'admin', 'admin'); //Conexion a Mikrotik // Tabla echo ""; echo ""; //Actualizar pagina echo ""; $ppps = $client->sendSync(new RouterOS\Request('/ppp/active/print'))->getAllOfType(RouterOS\Response::TYPE_DATA); foreach ($ppps as $ppp) { $id = $ppp('.id'); echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; } echo "
NombreServicioTiempo Activo DireccionReiniciar
". $ppp('name') ."" . $ppp('service'). "" . $ppp('uptime'). "". $ppp('address') ."
" ?>If you're sure you want to go on your current route... the ResponseCollection also has a toArray() method, so
array_combine($interfaces->toArray(), $ppps->toArray()) 

could work… except that array_combine wants both arrays to have equal number of elements, meaning that unless all of your PPP interfaces are active, the above would return “false” (which would then trigger a fatal error if given to “foreach”).

And i don know how to reboot the active connection with API.

How do you do it from CLI and/or Winbox?

Hmmm.. I need ‘service’ from /interface/pppoe-server instead ‘service’ from /ppp/active and name (interface/ppoe-server)= name(ppp/active), and i use ‘if’ like this:

$interfaces = $client->sendSync(new RouterOS\Request('/interface/pppoe-server/print')); 
$ppps = $client->sendSync(new RouterOS\Request('/ppp/active/print'))->getAllOfType(RouterOS\Response::TYPE_DATA);

if ($interfaces['name'] == $ppps['name']){
foreach ($ppps as $ppp) {
  $id = $ppp('.id');
  echo "<tr>";
  echo "<td>". $ppp('name') ."</td>";
 echo "<td>" . $ppp('service'). "</td>";
 echo "<td>" . $ppp('uptime'). "</td>";
  echo "<td>". $ppp('address') ."</td>";
  echo "<td><input type='submit' value='Reiniciar' name='Reiniciar' /></td></tr>";
}
}

And now, how i change the service? I dont understand.. It should be $interface(‘name’) but i dont know how i put the array interfaces in the same foreach :S


How do you do it from CLI and/or Winbox?

In ppp/active connections, i remove the connection, and it restarts. So i need something like
$client->sendSync(new RouterOS\Request(‘/ppp/active/remove’)) in the button

The two “service” fields are different?!?

OK then… one way to do it is to first get a list of all active interfaces, then for each one, make a print against the full list with a query where you ask for the name to be the same. For example:

$ppps = $client->sendSync(new RouterOS\Request('/ppp/active/print'))->getAllOfType(RouterOS\Response::TYPE_DATA);

foreach ($ppps as $ppp) {
  $id = $ppp('.id');
  $service = $client->sendSync(new RouterOS\Request('/interface/pppoe-server/print', RouterOS\Query::where('name', $ppp('name')))->getArgument('service');
  echo "<tr>";
  echo "<td>". $ppp('name') ."</td>";
  echo "<td>" . $service . "</td>";
  echo "<td>" . $ppp('uptime'). "</td>";
  echo "<td>". $ppp('address') ."</td>";
  echo "<td><input type='submit' value='Reiniciar' name='Reiniciar' /></td></tr>";
} 

P.S. I’ve just realized a missing feature with my client - you could currently just get the two lists of active and all interfaces, but the two lists are not sorted or indexed in any way, so there’s not currently a quick way to use one as reference for searching through the other. There’s a possible remedy for this (in fact, I can think of several, and the real question is which one serves most use cases while being the most efficient), that I’d be sure to implement in the next version. So while the above would still work, you’d get better performance with that other method.

P.S.S. The number 1 reason I help on this forum is exactly to find out where the limits of my client are… and then break them! That question here did that, so I guess I should say “Thank you” :smiley: .

The code print a bit of data (5 or 6 rows), but then i have this error:

“Fatal error: Maximum execution time of 30 seconds exceeded in phar://C:/wamp/www/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/RouterOS/Communicator.php on line 601”

Yeah… like I said, the above is not exactly a very efficient way… I’ll implement a more efficient one this weekend or so, and perhaps you could try it out then.

In the meantime, the only workaround is that you simply increase your execution timeout to more than 30 seconds, but that’s obviously not a good idea in the long run.

Hmmm but, how i can increase the execution timeout? im using PEAR2_Net_RouterOS-1.0.0b4.phar

Using PHP’s set_time_limit() function.

Ideally, use it within the loop itself, to ensure the script would always finish, e.g.

foreach ($ppps as $ppp) {
  $id = $ppp('.id');
  $service = $client->sendSync(new RouterOS\Request('/interface/pppoe-server/print', RouterOS\Query::where('name', $ppp('name')))->getArgument('service');
  echo "<tr>";
  echo "<td>". $ppp('name') ."</td>";
  echo "<td>" . $service . "</td>";
  echo "<td>" . $ppp('uptime'). "</td>";
  echo "<td>". $ppp('address') ."</td>";
  echo "<td><input type='submit' value='Reiniciar' name='Reiniciar' /></td></tr>";
  set_time_limit(5);//Give the script additional 5 seconds for the next request
}  

After 5-10 minutes, the script finished but we have another error xD

“Fatal error: Maximum execution time of 5 seconds exceeded in phar://C:/wamp/www/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/Transmitter/NetworkStream.php on line 120”

If i dont compare the 'name’s, it should be more fast, right? How is the code?

If you don’t compare the names, you have absolutely no guarantee as to which interface you’re targeting - you could end up with the service of one interface being shown as if it is the service of a completely unrelated one.

You could get your full list at once, and then not make any further ones. In that case, you’d then have to loop over the full list for every active interface, which isn’t much more efficient than doing a mini print request. In fact, as far as memory consumption goes, it’s much worse, i.e. you’re trading a few seconds saved for lots of MBs of RAM, perhaps hundreds, depending on how large your full list is. To minimize the memory footprint, you could construct a query in advance.

So perhaps:

$ppps = $client->sendSync(new RouterOS\Request('/ppp/active/print'))->getAllOfType(RouterOS\Response::TYPE_DATA);

$interfaceQuery = RouterOS\Query::where('name', $ppps->getArgument('name'));
while ($ppp = $ppps->next()) {
    $interfaceQuery->orWhere('name', $ppp('name'));
}

$activeInterfaces = $client->sendSync(new RouterOS\Request('/interface/pppoe-server/print', $interfaceQuery))->getAllOfType(RouterOS\Response::TYPE_DATA)->toArray();

foreach ($ppps as $ppp) {
  $id = $ppp('.id');
  $service = '';
  foreach ($activeInterfaces as $index => $pppInterface) {
    if ($pppInterface('name') === $ppp('name')) {
      $service = $pppInterface('service');
      unset($activeInterfaces[$index]);
      break;
    }
  }
  echo "<tr>";
  echo "<td>". $ppp('name') ."</td>";
  echo "<td>" . $service . "</td>";
  echo "<td>" . $ppp('uptime'). "</td>";
  echo "<td>". $ppp('address') ."</td>";
  echo "<td><input type='submit' value='Reiniciar' name='Reiniciar' /></td></tr>";
}  

EDIT: Added an unset and break within the check loop - should improve performance a little.

Nice, its working, it takes about 20 seconds, but its ok.

Now i need remove the active connections with the restart button.

Something like /ppp/active/remove..

That’s exactly the command - make such a request where you set the “numbers” argument to the ID of the active connection (the one in the variable $id), after you process the $_POST, just like in your firewall form (please don’t make me write out all the code for you… I’m trying to help you learn).

(BTW: Note the edit above, for performance boost)

ok ok i will try :slight_smile:

P.D: I run the script again and.." Fatal error: Maximum execution time of 30 seconds exceeded in phar://C:/wamp/www/PEAR2_Net_RouterOS-1 … ection.php on line 218"

Fuuuuu…

OK… remove the “unset” line. Apparently, freeing memory takes more time than a loop over your full list.

(Note to self…)

I haven’t the unset line.. I just paste your last code

P.D: Yes i have sorry :S Much better now, 10-12 seconds

P.D.2: I post my last code if (isset($_POST[‘act’])) {
$acts = $_POST[‘act’];

foreach ($acts as $act => $itemID) {

$remove=new RouterOs\Request("/ppp/active/remove");

}

// Tabla
echo “

”;
echo “”;

//Actualizar pagina
//echo “”;

$ppps = $client->sendSync(new RouterOS\Request(‘/ppp/active/print’))->getAllOfType(RouterOS\Response::TYPE_DATA);

$interfaceQuery = RouterOS\Query::where(‘name’, $ppps->getArgument(‘name’));
while ($ppp = $ppps->next()) {
$interfaceQuery->orWhere(‘name’, $ppp(‘name’));
}

$activeInterfaces = $client->sendSync(new RouterOS\Request(‘/interface/pppoe-server/print’, $interfaceQuery))->getAllOfType(RouterOS\Response::TYPE_DATA)->toArray();

foreach ($ppps as $ppp) {
$id = $ppp(‘.id’);
$service = ‘’;
foreach ($activeInterfaces as $index => $pppInterface) {
if ($pppInterface(‘name’) === $ppp(‘name’)) {
$service = $pppInterface(‘service’);
break;
}
}
echo “

”;
echo “”;
echo “”;
echo “”;
echo “”;
echo “”;
}

echo “

NombreServicioTiempo ActivoDireccionReiniciar
<input type=‘text’ name=‘{$id}[name]’ value='”. $ppp(‘name’) .“’ /><input type=‘text’ name=‘{$id}[uptime]’ value='” . $ppp(‘uptime’). “’ /><input type=‘text’ name=‘{$id}[address]’ value='”. $ppp(‘address’) .“’ />Reiniciar
”;

echo “”;

?>Im not sure how to put the button working sorry :S

Like I said, just add the argument “numbers” with the item’s ID as value, i.e.

$remove=new RouterOs\Request("/ppp/active/remove");
$remove->setArgument('numbers', $itemID); 

and then just send $remove.


BTW, since you can’t alter an active connection, you may want to restore

  echo "<td><input type='text' name='{$id}[name]' value='". $ppp('name') ."' /></td>";
  echo "<td><input type='text' name='{$id}[service]' value='" . $service . "' /></td>";
  echo "<td><input type='text' name='{$id}[uptime]' value='" . $ppp('uptime'). "' /></td>";
  echo "<td><input type='text' name='{$id}[address]' value='". $ppp('address') ."' /></td>"; 

to your initial

  echo "<td>". $ppp('name') ."</td>";
  echo "<td>" . $service . "</td>";
  echo "<td>" . $ppp('uptime'). "</td>";
  echo "<td>". $ppp('address') ."</td>"; 

(you did right to modify the button though - it should indeed have the ID as value)

Its working, but now, i need print 2 mikrotik router in the same script.
i add a new connection:

$client = new RouterOS\Client('','admin','admin');
$client2 = new RouterOS\Client('xxx.xxx.xxx.xxx','admin','admin');

But now, i dont know how to continue the script..:S

Other question, how can i sort by name the table?
Im trying with ksort but doesnt work :S

ksort($ppps);
ksort($activeInterfaces);

Im trying combine the 2 arrays in one(ppps, and active connection) and print it, but it doesnt work..

ksort() sorts by key, and the response collection has the reply’s number as a key (first received has 0, second received has 1, etc.), not the name, and it’s already sorted… so while ksort() could work (as in “be called normally and achieve what it’s made to do”), it won’t do anything (because “what it’s made to do” is not what you want).

The previously mentioned solution for efficiently accessing an item by name will also let you export an array where the keys are name, though still ordered by how they were received. Calling ksort() on that array would produce what you want.

I’ve already implemented it in my develop branch, but there are a few more kinks I’d like to iron out before I release it (Notably: Tomorrow, when you decide you want to sort by a comment or whatever, where duplicates are possible - make a way to sort while preserving duplicates, ideally allowing you to sort those by a secondary criteria). If you can’t wait, get yourself Git, clone the develop branch, set up an autoloader, and register the “src” folder with it… yes, that’s not exactly trivial to do/follow, I know… dev releases are not intended to be easily usable.