Community discussions

MikroTik App
 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 9:57 am

I'm trying the recommended PHP API:
<?php
            use PEAR2\Net\RouterOS;

            require_once 'PEAR2_Net_RouterOS-1.0.0b5.phar';

            try {
                $client = new Client('192.168.100.1', 'admin', 'password', 8728);
                
                echo 'Connected!';
                
                $responses = $client->sendSync(new RouterOS\Request('/ip/arp/print'));

                foreach ($responses as $response) {
                    if ($response->getType() === Response::TYPE_DATA) {
                        echo 'IP: ', $response->getProperty('address'),
                        ' MAC: ', $response->getProperty('mac-address'),
                        "\n";
                    }
                }
            } catch (Exception $e) {
                echo '<pre>';
                var_dump($e);
                echo '</pre>';
            }
The message from the var_dump is this error: "Class Client could not be loaded from Client.php, file does not exist (registered paths="phar:///var/www/project/PEAR2_Net_RouterOS-1.0.0b5.phar/PEAR2_Net_RouterOS-1.0.0b5/src") [PEAR2_Autoload-0.2.4]". What am I missing here?
Last edited by Beelze on Tue Mar 08, 2016 10:18 am, edited 1 time in total.
 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 10:18 am

I changed
$client = new Client('192.168.100.1', 'admin', 'password', 8728);

to

$client = new RouterOS\Client('192.168.100.1', 'admin', 'password', 8728);
and the API now connects successfully, the next thing that happens is this:

"Class Response could not be loaded from Response.php, file does not exist (registered paths="phar:///var/www/dataplace/PEAR2_Net_RouterOS-1.0.0b5.phar/PEAR2_Net_RouterOS-1.0.0b5/src") [PEAR2_Autoload-0.2.4]"

Edit: I removed
if ($response->getType() === Response::TYPE_DATA) {
from the code and it seems to work now. Is this Response check necessary? If I look through the wiki on Github then it is actually used a lot. Right now this is my work-around:
if ($response->getType() != '!done') { // statements }
 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 11:12 am

I defined those constants myself:
define('TYPE_DATA', '!re');
define('TYPE_FINAL', '!done');
define('TYPE_ERROR', '!trap');
define('TYPE_FATAL', '!fatal');
 
noib
Member Candidate
Member Candidate
Posts: 291
Joined: Fri Jan 25, 2013 6:04 pm
Location: France
Contact:

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 11:32 am

I also use this package and it's working well, here is an abstract of my code
<?php>
	require_once 'PEAR2_Net_Transmitter-1.0.0a5.phar';
	require_once 'PEAR2_Net_RouterOS-1.0.0b5.phar';

      $client = new PEAR2\Net\RouterOS\Client($IP, $login, $pass);
      $requete = new PEAR2\Net\RouterOS\Request("/ip/hotspot/host/print");
      $requete->setArgument('detail', ''); 
      $listeReponses = $client->sendSync($requete);
      foreach ($listeReponses as $data) {
        if ($data->getType() === PEAR2\Net\RouterOS\Response::TYPE_DATA) {
            $mac = $data->getProperty('mac-address');
            .. etc
        }
      }


 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 11:53 am

Thanks @noib! The Net_Transmitter phar file did the job for me.

However, I got one followup question though: I'm trying to monitor my SFP1 interface to get the sfp-tx-power and sfp-rx-power properties, but I'm getting no luck with the code. This is what I have:
$monitor = new RouterOS\Request('/interface/ethernet/monitor=once=10'); 
$responses = $client->sendSync($monitor); 
            
echo '<pre>';
var_dump($responses);
echo '</pre>';
which gives me this message:
["message"]=>
        string(15) "no such command"
I have tried a lot, but I don't know how to get the rx and tx properties of my SFP interfaces...
 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Tue Mar 08, 2016 12:36 pm

UPDATE:

I finally got it working, I had to use the setArgument() method twice for this to work:
$monitor = new RouterOS\Request('/interface/ethernet/monitor'); 
$monitor->setArgument('numbers', '10');
$monitor->setArgument('once');

$responses = $client->sendSync($monitor); 

echo '<pre>';
var_dump($responses);
echo '</pre>';
Output:

array(25) {
["name"]=>
string(4) "sfp1"
["status"]=>
string(7) "link-ok"
{ .... }
["sfp-tx-power"]=>
string(6) "-2.906"
["sfp-rx-power"]=>
string(6) "-3.822"
}
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Wed Mar 09, 2016 12:41 am

Whoa, so much things to clear up... I'm so sorry for having to do this...
  require_once 'PEAR2_Net_Transmitter-1.0.0a5.phar';
   require_once 'PEAR2_Net_RouterOS-1.0.0b5.phar';
The 'PEAR2_Net_RouterOS-1.0.0b5.phar' file includes everything from PEAR2_Net_Transmitter. No need to include them both.
Edit: I removed
if ($response->getType() === Response::TYPE_DATA) {
from the code and it seems to work now. Is this Response check necessary? If I look through the wiki on Github then it is actually used a lot.
The value of Response::getType() is one of !re, !done, !trap or !fatal - whichever one the returned API sentence has. The check is done because often you don't want to actually "do" anything with the !done reply. Instead, that reply is returned merely as a "we're done here" marker, with no useful data added to it. Other times however, you do actually want to do something with a !done reply, especially if it has some data in it, rather than this data being part of a previous !re reply. Case in point is the "ret" argument on "add" commands. So to address such cases, it's up to you to check if the response is one you want to deal with for your particular case.

And if you're thinking that sounds like a pretty edge case that doesn't justify the added complexity, and that in 99% all you need is CRUD operations, with the "Read" part being over the actual data... That's what the Util class, and its getAll() method are for - to make that common case trivial to pull off.
Right now this is my work-around:
if ($response->getType() != '!done') { // statements }
This is as perfectly valid and fine as using constants.

The purpose of the constants is to better assist you when using IDEs, as it's easier for them to find instances of a constant being used than it is to find a string used in a particular type of context (e.g. the string "!done" used for a response type vs. a typo in a longer text that should've been a sentence ending with "!", and the first word of the next sentence being "done", but someone forgot the space between the two), plus it enables the PHP compilers (think Hack, not the interpreter...) to do some minor optimizations.
define('TYPE_DATA', '!re');
define('TYPE_FINAL', '!done');
define('TYPE_ERROR', '!trap');
define('TYPE_FATAL', '!fatal');
The "real" constants are part of the Response class, and these here are global constants. They're unnecessary, and only pollute your global namespace.

You can simply replace "Response::TYPE_DATA" with "RouterOS\Response::TYPE_DATA", and the rest analogously.

The root of the whole problem here is a misunderstanding of how namespaces work... When you have at the top
namespace PEAR2\Net\RouterOS;
everything else is relative to that namespace, so when you use
new Client
you're referring to the "\PEAR2\Net\RouterOS\Client" class, and similarly, when you have
if ($response->getType() === Response::TYPE_DATA) {
you're reffering to the "TYPE_DATA" constant that's inside the "\PEAR2\Net\RouterOS\Response" class.

On other hand, if at the top you have
use PEAR2\Net\RouterOS;
everything is still relative to whatever "namespace" says (or is not relative to a namespace, if "namespace" is not present at all). Everything EXCEPT the part that's last in there - RouterOS. Everything that starts with "RouterOS", followed by "\" is instead relative to "\PEAR2\Net\RouterOS". Therefore,
new RouterOS\Client
and
if ($response->getType() === RouterOS\Response::TYPE_DATA) {
would target the same classes as before, while
new Client
would be looking for a class named "Client" at the root namespace (which doesn't exist), and same with "Response".
$monitor = new RouterOS\Request('/interface/ethernet/monitor=once=10');
> sigh <

I suggest you read this particular section of the GitHub wiki, but to save you the trouble of reading more than you've already did (speaking of which, if you've read all of this post so far, thank you), you can also do it with
$monitor = new RouterOS\Request('/interface ethernet monitor numbers=ether10 once'); 
(replacing "ether10" with the actual name of the interface you want to monitor, because the API protocol doesn't support numbers, despite the argument name being "numbers")
 
Beelze
Frequent Visitor
Frequent Visitor
Topic Author
Posts: 60
Joined: Tue Mar 04, 2014 12:21 pm

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Wed Mar 09, 2016 4:42 pm

Whoa, so much things to clear up... I'm so sorry for having to do this...
Well, im not. Of course I have read the wiki, but things were still not very clear to me how things were supposed to set up. Perhaps I should have stated that I DID read the wiki.

But I must thank you for your clear explanation, I can now safely develop my application :-)
 
User avatar
boen_robot
Forum Guru
Forum Guru
Posts: 2400
Joined: Thu Aug 31, 2006 4:43 pm
Location: europe://Bulgaria/Plovdiv

Re: PHP API: "Class Client could not be loaded from Client.php, file does not exist"

Wed Mar 09, 2016 6:45 pm

Well, im not. Of course I have read the wiki, but things were still not very clear to me how things were supposed to set up.
Before making that last reply, I double checked the whole page, and noticed I actually forgot to replace "Response" with "RouterOS\Response" in two places (both now fixed, thanks), so I guess I'm not surprised you got that error (and hopefully, you'll be the last :lol: ).
Perhaps I should have stated that I DID read the wiki.
Any suggestions for improvements to it, given those experiences?

(Being the author of it, you can imagine I have a sort of blind spot for what is and isn't "obvious enough to not dwell on it, just casually mention it in the middle of the thing" vs. "make a whole section/paragraph, complete with two or three examples to clarify this potentially confusing thing"...)

But before you suggest the namespace clarification (as I did above)... I used to have that (in the "Getting started" page in fact), but that made people lose focus on the more important bits on that page (namely, firewall stuff...), so I decided to just link to the PHP manual page instead, which seems to have been the right move, as I get far fewer firewall related questions than before, while namespace related questions have stayed the same.

Who is online

Users browsing this forum: No registered users and 15 guests