PHP Notice: Undefined variable: _ in /opt/mikrotik/routeros

Hello, guys. I have this error almost every time I run my script. I load some data to mikrotik from database and If I want to upload a few rows <20 I’s ok. When Im trying to load about 200+ rows it returns this PHP Notice: Undefined variable: _ in /opt/mikrotik/routeros_api.class.php on line 300
error
Can someone help me? The day before everything was OK!

I’m guessing you’re using this client, right? It’s known to have some quirks with response buffering, apparent in larger sets of responses, combined with lower network speed, as is likely the case with your setup.

Try it with this client instead.

If you can’t/won’t do that (e.g. if you’re using PHP 5.2), at least make sure you’re having the latest version of your current client. The latest one has a fix for this that might help.

Seems like all the other API clients are flawed in some cases. Please give an honest opinion, Boenrobot, should we remove them? Or there is some value of keeping them ?

You mean the other PHP clients, or other clients in general?

If you mean the PHP clients:

  • Denis’ one - No value in keeping it at all IMHO. Not only is it buggy, but both ayfan’s client and mine can do everything it can do, and much more, both more conveniently. The only legitimate reason anyone has to use it is that it’s PHP 5.2 compatible, but so is ayufan’s client, so that’s a somewhat poor excuse too.
  • ayufan’s one - There’s some value in it. I haven’t used it, nor have I seen people in the forum use it, so I can’t comment on stability. I don’t really like most of the approaches from an “elegance” standpoint, but what constitutes “elegant” is always debatable. In fact, that client has some features* that I’ve only added in my client in the cutting edge (not yet released) version, so I guess you could sort of call it inspirational… except that my inspiration came from a forum user, and not looking at the client, but that’s beside the point - it could serve as an inspiration for authors of clients for other languages.
  • vthinkteam’s sparks framework client - as I’ve said in his topic, I don’t like the fact that this client provides only an extremely reduced subset of functionality, but in the (IMHO) unlikely event that one needs that subset specifically AND uses the sparks framework, I must admit it would be easier to use that client instead of any other**, so… I guess keep it for the few people it might be helpful to.

If we’re talking in general - of course there’s value in keeping them… for now… since it’s always better to have some client than none at all. Besides, the Perl client used to be flawed, but it got fixed. As long as there’s someone to be “in charge” of a client, it would get fixed/extended more swiftly.

  • indexing of the result by property.
    ** Other clients (mine included) could potentially be made to be as easy to use as that client for all of RouterOS’ functionality if the API protocol implements a way to tell clients about the available commands, arguments, menus and properties. Perhaps something like my proposal for a “/help” command.

Oh :slight_smile: My client is pretty stable. I were using it for a few years for syncing MT configs. You write templated configuration which is synced over bunch of devices. If you look at https://github.com/ayufan/rosapi-php there’s slightly newer version. Some people may not like it, because it’s mostly high-level approach.

Challenge accepted :wink: .

A quick inspection at your github version shows that the reading is stable (props for that BTW - your client is now the 3rd one I know of to get that right, along with the Perl one and my one), but writing can potentially fail. You need to do a similar thing to what you did for the reading - check the number of bytes written (the returned value), and resend the data from that offset.

Ok, i run this API http://pear2.github.io/Net_RouterOS/
I need to do this. Can you tell me right syntax?

		$API->comm("/ip/route/add 
			=dst-address=$ip_string32
			=gateway=192.168.239.98
			=distance=1 
			=scope=30 
			=target-scope=10 
			=routing-mark=19  
			=comment=RKN");

The most elegant way, if you’re not interested in checking for error messages, would be

<?php
use PEAR2\Net\RouterOS;

require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

$util = new RouterOS\Util($client = new RouterOS\Client('hostname', 'username', 'password'));

$util->changeMenu('/ip route');

$util->add(
    array(
        'dst-address' => $ip_string32,
        'gateway' => '192.168.239.98',
        'distance'=> 1,
        'scope'=> 30, 
        'target-scope' => 10, 
        'routing-mark' => 19, 
        'comment'=> 'RKN'
    )
); 

(Util::add() returns the new items’ ID, or an empty string on error)

Or if you need to check the error message, you could do it like:

<?php
use PEAR2\Net\RouterOS;

require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

$client = new RouterOS\Client('hostname', 'username', 'password');

$addRequest = new RouterOS\Request(
    '/ip route add gateway=192.168.239.98 distance=1 scope=30 target-scope=10 routing-mark=19 comment=RKN'
);
$addRequest->setArgument('dst-address', $ip_string32);

$client->sendSync($addRequest); 

(Client::sendSync() returns a collection of responses, which normally includes a !done response with the new ID, or a !trap response with error details, plus an empty !done response)

You could also duplicate Denis’ client approach (as in, “get raw”) with Communicator, but I’d advise against that, since processing becomes needlessly complicated (think if you instead used the write() and read() methods instead of the comm() method…).

Thanks. Can you pleace transform another example with query?

		$API->write("/ip/route/print",false);
        $API->write("?comment=RKN",false);
        $API->write("=.proplist=.id,dst-address");

or like this

ip route print detail where comment=RKN

The only thing different from the second approach above is the additional second argument, that’s a query object, e.g.

$printRequest = new RouterOS\Request(
    '/ip route print .proplist=.id,dst-address',
    Query::where('comment', 'RKN')
);

$result = $client->sendSync($printRequest);

//process $result here, perhaps by iterating over it with foreach or what have you. e.g.
foreach ($result->getAllOfType(RouterOS\Response::TYPE_DATA) as $item) {
    echo $item->getArgument('dst-address');
} 

thanks! it works!

 Fatal error:  Uncaught exception 'PEAR2\Net\Transmitter\SocketException' with message 'Failed while receiving initial length byte' in phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/Transmitter/TcpClient.php:199
Stack trace:
#0 phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/Transmitter/Stream.php(356): PEAR2\Net\Transmitter\TcpClient->createException('Failed while re...', 4)
#1 phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/Transmitter/TcpClient.php(348): PEAR2\Net\Transmitter\Stream->receive(1, 'initial length ...')
#2 phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/RouterOS/Communicator.php(620): PEAR2\Net\Transmitter\TcpClient->receive(1, 'initial length ...')
#3 phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/RouterOS/Communicator.php(601): PEAR2\Net\R in phar:///opt/mikrotik/new API/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b4/src/PEAR2/Net/Transmitter/TcpClient.php on line 199

Get this with your script.
Can you tell me what I did wrong?

It’s most probably a connection error… Try to catch the exception at Client creation:

try {
$client = new RouterOS\Client('hostname', 'username', 'password');
} catch (Exception $e) {
//Connection error. Handle it here, perhaps with an error message or what have you.
}

//rest of your code 

(to be more precise - it’s a failure to login. The connection is established, but the speed seems too slow for even the CHAP challenge to be received)

Also, you are not using an encrypted connection I assume? (those are still very unstable)

$client = new RouterOS\Client(‘192.168.96.***’, ‘api’, ‘Gtuyv3$trs54fdcds’);
echo “connected”;
I use this connection.
Got same error as previous using your connection approach.

The line

$client = new RouterOS\Client('192.168.96.***', 'api', 'Gtuyv3$trs54fdcds'); 

will throw an exception on failure. When an exception is thrown, all code within the block is ignored, and the script jumps to your inner most “catch” block, if there is one at all, or terminates the script with an error message if there’s no such block to jump into.

You need to actually surround the code with a try…catch to avoid the built in error message.

So using something like:

try {
    $client = new RouterOS\Client('192.168.96.***', 'api', 'Gtuyv3$trs54fdcds');
    echo 'connected';
} catch (Exception $e) {
    //Connection error. Handle it here, perhaps with an error message or what have you.
    echo "Not connected";
    exit();
}

//rest of your code   

should output either “connected” or “Not connected” - if the first line throws an exception, “echo ‘connected’” is not going to be executed.


Or are you saying that you see “connected”, and then ALSO see the “Uncaught exception” error message?

I have to reboot mikrotik. After that, the problem was solved. API works just fine. Thanks a lot.

I have the same error when trying to connect via the API, but a reboot did not fix it for me.

'Failed while receiving initial length byte' in phar:///var/www/yii/htdocs/protected/vendor/PEAR2_Net_RouterOS-1.0.0b4.phar/PEAR2_Net_RouterOS-1.0.0b5/src/PEAR2/Net/Transmitter/TcpClient.php:199

I'm running ROS 6.21.1.I am trying the following connection method.

require_once('PEAR2_Net_RouterOS-1.0.0b5.phar');

try {
    $client = new RouterOS\Client('10.128.0.6', 'admin', 'password');
        echo "Connected";
} catch (Exception $e) {
        echo $e;
    die('Unable to connect to the router.');

If I monitor the ip firewall connections I do see a connection being made, but it is closed immediately.
[admin@seaview2] > ip firewall connection print
Flags: S - seen reply, A - assured

PROTOCOL SRC-ADDRESS DST-ADDRESS TCP-STATE TIMEOUT

3 SA tcp 10.128.0.1:58242 10.128.0.6:8728 close 5s [admin@seaview2] >I am logging the info topic, but no login ( or failure) from the API is showing in the log. What else can I do to troubleshoot this issue? Any ideas why this is happening?

If you’re not seeing “Unable to connect to the router.”, then the connection and login have been made, but then the connection is dropped later on for some reason.

What command(s) are you trying to call? Could you please post your full PHP file? Which PHP version are you using? Running on a Linux or Windows PC? Any modems or other devices in between that may affect the connection (I’m thinking maybe you’re in a situation similar to this kind of problem)?

SOLVED !!!

I had previously set a public “Available from” IP address range in the /ip service for the API. Once I added the extra private IP range for the API service on the router, it worked fine.
[admin@seaview2] > /ip service set api address=10.128.0.0/21