Community discussions

MikroTik App
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 12:40 pm

Hi guys, i need a script to modify or delete one of the nat rules's list. I have 2 buttons for each nat rule (modify, delete).

The script is something like that:
<?php
use PEAR2\Net\RouterOS;
// require_once 'pear2\src\PEAR2\Autoload.php';
require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

 
$client = new RouterOS\Client('192.168.150.161', 'admin', 'admin');
 
// Tabla

echo "<table align='center' border=1 bordercolor='black'>";
echo "<tr><td align=left size=3>Src Address</td><td size=3>To Addresses</td><td size=3>Ports</td><td align=left size=3>Modificar/Eliminar</td></tr>";

// Peticion a la API 
$responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print'));


 echo "<form action='peartest.php' method='POST'>";
 
foreach ($responses as $response) {
    if ($response->getType() === RouterOS\Response::TYPE_DATA) {
        
		echo "<tr>";
		echo "<td><input type='text' name='src' value='". $response->getArgument('src-address'). "'/></td>";
        echo "<td><input type='text' name='toadd' value='". $response->getArgument('to-addresses'). "'/></td>";
		echo "<td><input type='text' name='ports' value='". $response->getArgument('to-ports'). "'/></td>";
        "\n";
		//Boton Modificar
		echo "<td><button type='submit' value='modificar' >Modificar</button>";
		//Boton Borrar
		echo "<button type='submit' name='borrar' value=''>Borrar</button>";														
			
		echo "</tr>";
    }
}
echo "</form>";
echo "</table>";

?>
I need help to create the buttons, and the script to modify and delete.
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 3:18 pm

You need to add a name to every submit button and field which is unique to the item being modified.

You'll probably want to use the item's ID as an identifier - as long as the position of the item remains the same, the ID is preserved.

Processing the button is then as easy as calling a "set"/"remove" command with the received ID as a "numbers" argument.

To make it even easier on yourself, I suggest you always name the field after the property, and use array syntax on the name, which would translate in PHP as a nested array in $_POST.

e.g.
<?php
use PEAR2\Net\RouterOS;
// require_once 'pear2\src\PEAR2\Autoload.php';
require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

 
$client = new RouterOS\Client('192.168.150.161', 'admin', 'admin');

//Action
if (isset($_POST['act'])) {
    $acts = $_POST['act'];

    foreach ($acts as $act => $itemID) {
        //Limit the action only to known ones, for security's sake
        switch ($act) {
        case 'set':
        case 'remove':
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            foreach ($_POST[$itemID] as $name => $value) {
                $actionRequest->setArgument($name, $value);
            }
            $responses = $client->sendSync($actionRequest);
            //If you want to do some error handling, do it here by inspecting $responses.
            //You can safely assume that if the table shows your old data, as opposed to the new one,
            //the action failed.
            break;
        }
    }
}

// Tabla

echo "<table align='center' border=1 bordercolor='black'>";
echo "<tr><td align=left size=3>Src Address</td><td size=3>To Addresses</td><td size=3>Ports</td><td align=left size=3>Modificar/Eliminar</td></tr>";

// Peticion a la API 
$responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print'));


 echo "<form action='peartest.php' method='POST'>";
 
foreach ($responses as $response) {
    if ($response->getType() === RouterOS\Response::TYPE_DATA) {
      $id = $response('.id');
      echo "<tr>";
      echo "<td><input type='text' name='{$id}[src-address]' value='" . $response('src-address') . "' /></td>";
      echo "<td><input type='text' name='{$id}[to-addresses]' value='" . $response('to-addresses') . "' /></td>";
      echo "<td><input type='text' name='{$id}[to-ports]' value='" . $response('to-ports') . "' /></td>";

      //Boton Modificar
      echo "<td><button type='submit' name='act[set]' value='{$id}'>Modificar</button>";
      //Boton Borrar
      echo "<button type='submit' name='act[remove]' value='{$id}'>Borrar</button></td>";
      echo "</tr>";
    }
}
echo "</form>";
echo "</table>";

?>
Last edited by boen_robot on Mon Oct 14, 2013 6:11 pm, edited 4 times in total.
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 4:29 pm

Thanks so much, i really need this code for my project..I changed some syntax errors but the rest its ok
i have another problem, the buttons still dont working, i want in the input texts change my nat rules directly, but they still unchanged.
i cant understand the action part of the code..

p.d Sorry my bad english :S
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 4:50 pm

I noticed a problem myself a minute ago (sorry about that)... try the above again now.
i cant understand the action part of the code..
Do
var_dump($_POST); 
and you'll see that rather than being just name/value pairs, $_POST is now an array with other arrays nested into it. Each item's ID is a key in $_POST, along with the key "act" which will be used to tell PHP what to do with the rest of the data. The "act" key contains an array with the action name as a key, and the ID on which to apply that action as a value.

In other words, $_POST becomes the equivalent of (for example)
array(
    '*1' => array(
        'src-address' => '10.10.10.1',
        'to-address'  => '192.168.150.100',
        'to-ports'    => '80'
    ),
    '*2' => array(
        'src-address' => '10.10.10.2',
        'to-address'  => '192.168.150.101',
        'to-ports'    => '81'
    ),

    //All of your other firewall rules here.
    //Yes, all firewall rules' data is sent; always.

    'act' => array(
        'set' => '*1'
    )
); 
In the action part, the line
foreach ($acts as $act => $itemID) { 
places the action (set or remove) in the variable $act, and the corresponding ID in $itemID.

So far, given the example $_POST above, the code knows it would need to "set" the item with ID "*1". The lines
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID); 
make that into a request.

But what is the new data? To find THAT out, the lines
            foreach ($_POST[$itemID] as $name => $value) {
                $actionRequest->setArgument($name, $value);
            } 
loop over the part of the $_POST array that holds the data for that ID, and populate the requests' arguments accordingly. In the end, the resulting request is the equivalent of

ros code

/ip firewall nat set numbers="*1" src-address="10.10.10.1" to-address="192.168.150.100" to-ports="80"
Does the data actually contain any modifications (or was the button just clicked without modifications having been made)? The code doesn't care for that - it executes the above regardless.
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 5:51 pm

The buttons still dont working..When i modify the src address or ports or something in the table and then i click on Modify, the values refresh and come back to old values :S
And the delete button neither working..

Im using the updated code right now

Im so glad with ur help, thanks..I was working hard in this code, and its hard to me, being a newbie in php and mikrotik api
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 6:07 pm

Opps.

The argument is called "to-addresses", and I instead had "to-address". Change:
echo "<td><input type='text' name='{$id}[to-address]' value='" . $response('to-address'). "' /></td>"; 
to
echo "<td><input type='text' name='{$id}[to-addresses]' value='" . $response('to-addresses') . "' /></td>"; 
You had it right the first time, and somehow in my editing, I ended up screwing it up.

(The form displays non-the less because non-existing arguments are shown as NULL, which is in turn outputted as an empty string if you don't explicitly check for it; but when setting, RouterOS doesn't skip the argument, but fails with an error message instead)

I've now fixed it above too.
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 6:16 pm

I know, I changed to-addresses in ur first code, u had to-address too but its dont working..
Im using Firebug to see the code on the firefox and i have something wrong

http://gyazo.com/20b4a734b8d73217ab46a46111426976

maybe something is wrong with the name.. :S

and the button's name too:

http://gyazo.com/10484d4ed5361df9df28a39146b66ed5
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 6:23 pm

That's odd. I have Firefox too, and with that last change in place, it works as expected in both it and IE10.

Although note that there are no "OK" or "error" messages, so you may be left with the impression that nothing happened when you click the Modificar button.

Let's add some error handling to figure out what's different with your case. Change
            $responses = $client->sendSync($actionRequest); 
to
            $responses = $client->sendSync($actionRequest);
            $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR);
            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>";
            } else {
                echo '<div><ul>';
                foreach ($errors as $error) {
                    echo '<li>' . $error('message') . '</li>';
                }
                echo '</ul></div>';
            } 
Last edited by boen_robot on Mon Oct 14, 2013 6:40 pm, edited 2 times in total.
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 6:36 pm

That's odd. I have Firefox too, and with that last change in place, it works as expected in both it and IE10.

Although note that there are no "OK" or "error" messages, so you may be left with the impression that nothing happened when you click the Modificar button.

I solved, the problem was here:
echo "<td><input type='text' name='{$id}[to-addresses]' value='" . $response('to-addresses'). "' /></td>";
instead
      echo "<td><input type='text' name='{$id}['to-addresses']' value='" . $response('to-addresses'). "' /></td>";
But now i can remove the rules but dont update them..
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Mon Oct 14, 2013 6:47 pm

That can't be right. You're breaking off the value attribute with the first apostrophe.
But now i can remove the rules but dont update them..
EDIT: Yeah... Having apostrophes results in a DIFFERENT name. That's why you can't edit - the parameter name is again different.

BTW, to remove, you don't need the arguments. So change:
        //Limit the action only to known ones, for security's sake
        switch ($act) {
        case 'set':
        case 'remove':
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            foreach ($_POST[$itemID] as $name => $value) {
                $actionRequest->setArgument($name, $value);
            }
            $responses = $client->sendSync($actionRequest);
            //If you want to do some error handling, do it here by inspecting $responses.
            //You can safely assume that if the table shows your old data, as opposed to the new one,
            //the action failed.
            break;
        } 
to
        //Limit the action only to known ones, for security's sake
        if (in_array($act, array('set', 'remove'))) {
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            if ('set' === $act) {
                foreach ($_POST[$itemID] as $name => $value) {
                    $actionRequest->setArgument($name, $value);
                }
            }
            $responses = $client->sendSync($actionRequest);
            $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR);
            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>";
            } else {
                echo '<div><ul>';
                foreach ($errors as $error) {
                    echo '<li>' . $error('message') . '</li>';
                }
                echo '</ul></div>';
            }
        } 
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Tue Oct 15, 2013 9:54 am

That can't be right. You're breaking off the value attribute with the first apostrophe.
But now i can remove the rules but dont update them..
EDIT: Yeah... Having apostrophes results in a DIFFERENT name. That's why you can't edit - the parameter name is again different.

BTW, to remove, you don't need the arguments. So change:
        //Limit the action only to known ones, for security's sake
        switch ($act) {
        case 'set':
        case 'remove':
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            foreach ($_POST[$itemID] as $name => $value) {
                $actionRequest->setArgument($name, $value);
            }
            $responses = $client->sendSync($actionRequest);
            //If you want to do some error handling, do it here by inspecting $responses.
            //You can safely assume that if the table shows your old data, as opposed to the new one,
            //the action failed.
            break;
        }  
to
        //Limit the action only to known ones, for security's sake
        if (in_array($act, array('set', 'remove'))) {
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            if ('set' === $act) {
                foreach ($_POST[$itemID] as $name => $value) {
                    $actionRequest->setArgument($name, $value);
                }
            }
            $responses = $client->sendSync($actionRequest);
            $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR);
            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>";
            } else {
                echo '<div><ul>';
                foreach ($errors as $error) {
                    echo '<li>' . $error('message') . '</li>';
                }
                echo '</ul></div>';
            }
        }  

I did the last changes on Action, and now i cant remove too :S

I let u here again, the full code..something is wrong here..

natfinal.php

php code

<?php
use PEAR2\Net\RouterOS;
// require_once 'pear2\src\PEAR2\Autoload.php';
require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

 
$client = new RouterOS\Client('192.168.150.161', 'admin', 'admin');


//Limit the action only to known ones, for security's sake
    if (in_array($act, array('set', 'remove'))) {
        $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
        $actionRequest->setArgument('numbers', $itemID);
            if ('set' === $act) {
                foreach ($_POST[$itemID] as $name => $value) {
                    $actionRequest->setArgument($name, $value);
                }
            }
            $responses = $client->sendSync($actionRequest);
            $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR);
            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>";
            } else {
                echo '<div><ul>';
                foreach ($errors as $error) {
                    echo '<li>' . $error('message') . '</li>';
                }
                echo '</ul></div>';
        }
    } 

// Tabla

echo "<table align='center' border=1 bordercolor='black'>";
echo "<tr><td align=left size=3>Src Address</td><td size=3>To Addresses</td><td size=3>Ports</td><td align=left size=3>Modificar/Eliminar</td></tr>";

// Peticion a la API 
$responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print'));


 echo "<form action='natfinal.php' method='POST'>";
 
foreach ($responses as $response) {
    if ($response->getType() === RouterOS\Response::TYPE_DATA) {
      $id = $response('.id');
      echo "<tr>";
      echo "<td><input type='text' name='{$id}['src-address']' value='" . $response('src-address'). "' /></td>";
      echo "<td><input type='text' name='{$id}['to-addresses']' value='" . $response('to-addresses'). "' /></td>";
      echo "<td><input type='text' name='{$id}['to-ports']' value='" . $response('to-ports'). "' /></td>";

      //Boton Modificar
      echo "<td><button type='submit' name='act[set]' value='{$id}'>Modificar</button>";
      //Boton Borrar
      echo "<button type='submit' name='act[remove]' value='{$id}'>Borrar</button></td>";
      echo "</tr>";
    }
}
echo "</form>";
echo "</table>";

?>
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: Change or Delete NAT rules PEAR2 API PHP

Tue Oct 15, 2013 12:39 pm

You missed the isset and foreach parts at the top.

Plus, like I said, the apostrophes result in an entirely different name, so the $_POST array doesn't look as expected.

Here is the full, fixed code:

php code

<?php
use PEAR2\Net\RouterOS;
// require_once 'pear2\src\PEAR2\Autoload.php';
require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

$client = new RouterOS\Client('192.168.150.161', 'admin', 'admin');

if (isset($_POST['act'])) {
    foreach ($_POST['act'] as $act => $itemID) {
        //Limit the action only to known ones, for security's sake
        if (in_array($act, array('set', 'remove'))) {
            $actionRequest = new RouterOS\Request("/ip/firewall/nat/{$act}");
            $actionRequest->setArgument('numbers', $itemID);
            if ('set' === $act) {
                foreach ($_POST[$itemID] as $name => $value) {
                    $actionRequest->setArgument($name, $value);
                }
            }
            $responses = $client->sendSync($actionRequest);
            $errors = $responses->getAllOfType(RouterOS\Response::TYPE_ERROR);
            if (0 === count($errors)) {
                echo "<div>'{$act}' OK!</div>";
            } else {
                echo '<div><ul>';
                foreach ($errors as $error) {
                    echo '<li>' . $error('message') . '</li>';
                }
                echo '</ul></div>';
            }
        }
    }
}

// Tabla

echo "<table align='center' border=1 bordercolor='black'>";
echo "<tr><td align=left size=3>Src Address</td><td size=3>To Addresses</td><td size=3>Ports</td><td align=left size=3>Modificar/Eliminar</td></tr>";

// Peticion a la API 
$responses = $client->sendSync(new RouterOS\Request('/ip/firewall/nat/print'));


 echo "<form action='' method='POST'>";
 
foreach ($responses as $response) {
    if ($response->getType() === RouterOS\Response::TYPE_DATA) {
      $id = $response('.id');
      echo "<tr>";
      echo "<td><input type='text' name='{$id}[src-address]' value='" . $response('src-address'). "' /></td>";
      echo "<td><input type='text' name='{$id}[to-addresses]' value='" . $response('to-addresses'). "' /></td>";
      echo "<td><input type='text' name='{$id}[to-ports]' value='" . $response('to-ports'). "' /></td>";

      //Boton Modificar
      echo "<td><button type='submit' name='act[set]' value='{$id}'>Modificar</button>";
      //Boton Borrar
      echo "<button type='submit' name='act[remove]' value='{$id}'>Borrar</button></td>";
      echo "</tr>";
    }
}
echo "</form>";
echo "</table>";

?>
And this time, I have tested it (well, the modification part, but I'm pretty sure the removal works as well), and it works.

Note also that in your form's action, I changed it to
 echo "<form action='' method='POST'>"; 
to ensure that the form always submits to itself (regardless of file name), as opposed to a different file.
 
User avatar
Vyrtu
newbie
Topic Author
Posts: 45
Joined: Thu Oct 03, 2013 11:49 am
Location: Torrelavega,Spain

Re: Change or Delete NAT rules PEAR2 API PHP

Tue Oct 15, 2013 3:37 pm

It's working right now! Thanks for help :)