get by api

Hi
I want get expired usermanager’s user by php api.

/tool user-manager user get $i credit-left=0s

Please post api command for that.
Thank you

First off - Do you want to set a certain user’s “credit-left” to 0s? Do you want to get all users that have “credit=left” equal to 0s? Or do you want to get whatever the “credit-left” is for a particular user?

Regardless…

In the user menu in particular, instead of using the number, you can use the name. With the API protocol, you must specify all argument names, including those that are unnamed on the command line. My PHP API client in particular accepts CLI-like syntax, so in it, depending on what you want to do:

  • To set the credit-left for a user with username “user1”:
$client->sendSync(new RouterOS\Request('/tool user-manager user set numbers=user1 credit-left=0s'));
  • To get whatever the credit-left is for username “user1”, and put it into $creditLeft:
$creditLeft = $client->sendSync(new RouterOS\Request('/tool user-manager user get number=user1 value-name=credit-left'))->getArgument('ret');
  • To get all users that have credit-left equal to 0s, and put them into $creditlessUsers (for later looping over them and doing whatever with them):
$creditlessUsers = $client->sendSync(new RouterOS\Request('/tool user-manager user print', RouterOS\Query::where('credit-left', '0s')))->getAllOfType(RouterOS\Response::TYPE_DATA);

Thank you boen
I want get phone number of all users with credit-left=0s for sending sms to him/her.
I can do that with mikrotik script.

:foreach i in=[/tool user-manager user find] do={
:if ([/tool user-manager user get $i credit-left]=0s) do={
:log info [/tool user-manager user get $i value-name=phone]

But i want send sms to phone number’s by php sms api out of routeros.

$optionss = array(
'login' => 'login',
'password' => 'password'
);
$client = new SoapClient('http://sms.host.com/webservice/?WSDL', $optionss);
try
{$messageId = $client->send($phone_number, "$sms_text");}
catch (SoapFault $sf){}

Well, in that case, you need the 3rd option above.

Or, as a more complete piece of code:

<?php
use PEAR2\Net\RouterOS;

require_once 'PEAR2_Net_RouterOS-1.0.0b4.phar';

try {
    $rosClient = new RouterOS\Client(
        '192.168.0.1',
        'admin',
        'password'
    );
    $smsClient = new SoapClient(
        'http://sms.host.com/webservice/?WSDL',
        array(
            'login' => 'login',
            'password' => 'password'
        )
    );
} catch (RouterOS\Exception $e) {
    die('Failed to connect/login to RouterOS.');
} catch (SoapFault $e) {
    die('Failed to connect/login to SMS service.');
}

try {
    $creditlessUsers = $rosClient->sendSync(
        new RouterOS\Request(
            '/tool user-manager user print .proplist=name,phone',
            RouterOS\Query::where('credit-left', '0s')
        )
    )->getAllOfType(RouterOS\Response::TYPE_DATA);
} catch (RouterOS\Exception $e) {
    die('Failed to get users with no credit out of RouterOS.');
}

foreach ($creditlessUsers as $user) {
    try {
        $messageId = $smsClient->send(
            $user('phone'),
            'Your account "' . $user('name') . '" does not have any more credit.'
        );
        //SMS message sent. Do something with $messageId if you must.
    } catch (SoapFault $sf) {
        echo 'Failed to send SMS for user "' . $user('name') . '" (phone number "' . $user('phone') . '").';
    }
}

Thank you again boen.
What about for “credit-left<1d” or “credit-left<1d && credit-left!=0s” ?

:if ([/tool user-manager user get $i credit-left]<1d && [/tool user-manager user get $i credit-left]!=0s) do={

Can i do that?

Sure. Just modify the query accordingly, i.e. instead of

RouterOS\Query::where('credit-left', '0s') 

make that

RouterOS\Query::where('credit-left', '1d', '<') 

or

RouterOS\Query::where('credit-left', '1d', '<')->andWhere('credit-left', '0s', '>') 

or perhaps even

RouterOS\Query::where('credit-left', '0s')->not()->andWhere('credit-left', '1d', '<') 

The only operation that API doesn’t support (which CLI does) is regex matches. You can do that on the PHP side though.

Solved. thank you.
Is it work for not command?

RouterOS\Query::where('credit-left', '1d', '<')->andWhere('credit-left', '0s', '!=')

In RouterOS 4.17 API disconnect command does not worked and sessiones still active in system/user untill reboot router.
Is it problem or not important?

Is it work for not command?

Not in this fashion. There’s the “-” operator, which tests for non-existence of a property… But I’m not sure whether it works as “not equals” when paired with a value.

i.e.

RouterOS\Query::where('credit-left', null, '-')

will check if there’s no “credit-left” property set on the item… but I don’t know if

RouterOS\Query::where('credit-left', '1d', '-')

will give all items where the value is different from “1d”, or if it’s going to give all items where there’s no “credit-left” property (ignoring the value).

In RouterOS 4.17 API disconnect command does not worked and sessiones still active in system/user untill reboot router.
Is it problem or not important?

Yeah, it’s a known RouterOS bug… Unfortunatly, there’s no work around, short of upgrading to at least 5.*. It can quickly start to become a problem as more and more connections are made and left hanging.

If you make an application that runs continuously (ala a server), rather than terminate (ala PHP request), you can minimize that impact, since there will be just one connection that will just to happen to always be on. The only times where an extra connection will be created is if you terminate the program for some reason (e.g. software updates or hardware maintenance), and put it back on again.

Thank you boen.
One of my hosts runnig with php version 5.2.17 and the PEAR2 not working on this version.
Can i do that with routeros_api.class? (only for this host)

Yes, but you’d need to do it using the API syntax, which you can check out at the manual page.

I’d highly recommend you instead ask your host if they can provide at least 5.3.0 though… 5.2 is - in internet terms - ancient.

In fact, if they provide a cPanel for you, maybe there’s a “choose PHP version” option in there? If there is, you can choose 5.3 from it without even contacting them.

That is backup host. The main host runnig with php version 5.3.28 and working by PEAR2.
Could you please convert this project to the API syntax too?

$creditlessUsers = array_slice(
    $API->comm(
        '/tool/user-manager/user/print',
        array(
            '.proplist' => 'name,phone',
            '?credit-left' => '0s',
            '?#!' => null,
            '?<credit-left' => '1d'
        )
    ),
    0,
    -1
); 

(I hope you find the above code as ugly as I do)

And then to actually get the name and phone, instead of

$user('name')

you’d use

$user['name']

(and accordingly for “phone”)

Is this true?

<?php
require('routeros_api.class.php');

try {
$API = new routeros_api();

if ($API->connect('ip', 'username', 'password')
    );
    $smsClient = new SoapClient(
        'http://sms.host.com/webservice/?WSDL',
        array(
            'login' => 'login',
            'password' => 'password'
        )
    );
} catch (RouterOS\Exception $e) {
    die('Failed to connect/login to RouterOS.');
} catch (SoapFault $e) {
    die('Failed to connect/login to SMS service.');
}

try {

$creditlessUsers = array_slice(
    $API->comm(
        '/tool/user-manager/user/print',
        array(
            '.proplist' => 'name,phone',
            '?credit-left' => '0s',
            '?#!' => null,
            '?<credit-left' => '1d'
        )
    ),
    0,
    -1
); 

} catch (RouterOS\Exception $e) {
    die('Failed to get users with no credit out of RouterOS.');
}

foreach ($creditlessUsers as $user) {
    try {
        $messageId = $smsClient->send(
            $user('phone'),
			'Your account "' . $user('name') . '" does not have any more credit.'
        );
        //SMS message sent. Do something with $messageId if you must.
    } catch (SoapFault $sf) {
        echo 'Failed to send SMS for user "' . $user('name') . '" (phone number "' . $user('phone') . '").';
    }
}
?>

AFAIK, that API class doesn’t throw any sort of exceptions, so error checking is more in procedural style…

Also, as mentioned, the change from “(” to “[”, so:

<?php
require 'routeros_api.class.php';

$API = new routeros_api();

if (!$API->connect('ip', 'username', 'password')) {
    die('Failed to connect/login to RouterOS.');
}

try {
    $smsClient = new SoapClient(
        'http://sms.host.com/webservice/?WSDL',
        array(
            'login' => 'login',
            'password' => 'password'
        )
    );
} catch (SoapFault $e) {
    die('Failed to connect/login to SMS service.');
}

$creditlessUsers = array_slice(
    $API->comm(
        '/tool/user-manager/user/print',
        array(
            '.proplist' => 'name,phone',
            '?credit-left' => '0s',
            '?#!' => null,
            '?<credit-left' => '1d'
        )
    ),
    0,
    -1
);

foreach ($creditlessUsers as $user) {
    try {
        $messageId = $smsClient->send(
            $user['phone'],
         'Your account "' . $user['name'] . '" does not have any more credit.'
        );
        //SMS message sent. Do something with $messageId if you must.
    } catch (SoapFault $sf) {
        echo 'Failed to send SMS for user "' . $user['name'] . '" (phone number "' . $user['phone'] . '").';
    }
}
?>

(Detecting failure of retrieval - e.g. a sudden connection loss - as we did before? Not possible with this client…)

Dear Boen,
The project worked successful.
But sms does not send to last phone number. (if sort names by alpabet)
I removed “-1” and problem solved.

$creditlessUsers = array_slice(
    $API->comm(
        '/tool/user-manager/user/print',
        array(
            '.proplist' => 'name,phone',
            '?credit-left' => '0s',
            '?#!' => null,
            '?<credit-left' => '1d'
        )
    ),
    0,
    -1
);

What is problem?

Apparently, this client doesn’t include the !done response, which is IMO silly, but… whatever… Just remove the array_slice bit then:

$creditlessUsers = $API->comm(
    '/tool/user-manager/user/print',
    array(
        '.proplist' => 'name,phone',
        '?credit-left' => '0s',
        '?#!' => null,
        '?<credit-left' => '1d'
    )
); 

can you check if by any change if you send in /cancel, that should stop every command that is running, it stops?

Every API command should end with !done, unless it is !fatal.

It might be that command just runs in the background.

In RouterOS 4.17 disconnect command not worked.
I try every possible commands like:
/quit
/cancel
disconnect
..

hmrka139 initially used my client, and with it, I’m certain sendSync() won’t return until a !done reply is present AND it will be included in the result (that we then filtered out to include only the data replies). Seems most likely that the other client also receives a !done reply, but merely doesn’t include it in the returned result - it makes the assumption that if there are data replies, that’s what you’re interested in… which again, I think is silly, mostly because it doesn’t have to be so - spec wise - but whatever.

In RouterOS 4.17 disconnect command not worked.
I try every possible commands like:
/quit
/cancel
disconnect

Like I said, there’s no workaround for 4.17. The connection is left hanging, even if you explicitly issue a “/quit” command. The only things you can do are to either reboot your router periodically, or upgrade to at least 5.. With 5., at least an explicit “/quit” works (which is done automatically with my client upon disconnect; on this one you can issue it explicitly at the end). With 6.*, you don’t even need to do a “/quit”.

Unless there’s some workaround I haven’t yet found… @janisk?