Pear2 broken signature

Hello and merry Christmas.

I’m trying to run a code from a webpage using IIS but It always returns this error:

[25-Dec-2015 23:00:41 Europe/Belgrade] PHP Fatal error: Uncaught exception ‘PharException’ with message ‘phar “F:\webs\gestion\PEAR2_Net_RouterOS-1.0.0b5.phar” SHA1 signature could not be verified: broken signature’ in F:\webs\gestion\PEAR2_Net_RouterOS-1.0.0b5.phar:18
Stack trace:
#0 F:\webs\gestion\PEAR2_Net_RouterOS-1.0.0b5.phar(18): Phar::mapPhar()
#1 F:\webs\gestion\servicio.php(4): require_once(‘F:\webs\gestion…’)
#2 {main}
thrown in F:\webs\gestion_xaupax\PEAR2_Net_RouterOS-1.0.0b5.phar on line 18

Can anyone help me?

Best regards

Huh… That’s odd (and the first time ever I’ve seen a message like that). What PHP version are you using?

Good morning

Firstly I tried with IIS 5.4.14 and then with the newest one 5.6.0 but getting the same error.

My system is Windows 2008 r2 and IIS 7

I can’t duplicate it - tried with both TS and NTS builds of 5.4.14, and nothing. I thought maybe this has to do with the phar.require_hash directive in php.ini, but no, it works regardless.

My only guess is that your download is corrupted, and hence the error is correct.

To confirm, try to run the PHAR itself from CLI, i.e.

php "F:\webs\gestion\_xaupax\PEAR2_Net_RouterOS-1.0.0b5.phar"

The output should start off with

PEAR2_Net_RouterOS 1.0.0b5
SHA-1 hash: 57E213E9E2D3B7F745458C37B11B370DCFADCFED

If you instead get

PEAR2_Net_RouterOS 1.0.0b5

The PHAR extension is available, but was unable to read this PHAR file's hash.
Details: phar "F:\webs\gestion\_xaupax\PEAR2_Net_RouterOS-1.0.0b5.phar" SHA1 signature could not be verified: broken signature

Then that’s definetly the issue.
(Side note: I generated the above error by modifying the PHAR with by adding a comment in the stub; Even a single byte being modified in the file is enough to break its signature)

If that’s the issue, try downloading the PHAR again. If you are using any sort of proxies, try disabling them before doing so.

The above SHA-1 is of the contents (minus compression, AFAIK). The SHA-1 of the entire file (including compression) should be
FC534D8C74A9909CD1C9B4C1A9D554C0BD7E5913

Which you can verify with a tool of your choice, or just run

php -r "echo sha1_file('F:\webs\gestion\_xaupax\PEAR2_Net_RouterOS-1.0.0b5.phar');"

Hello, nothing above worked. I checked all the choices but nothing. I tried to change the working directory to c:\bin and neither.

Do you know where can I download directly the phar file? I have several copies of it from GitHub and source forge but don’t know if theses are right.

Thank you very much for your help

You mean that from cmd, you get “‘php’ is not recognized as an internal or external command, operable program or batch file.”?

cd to PHP’s folder (the one with php.exe in it), and try things from there.

Those are the right ones alright.

At
https://github.com/pear2/Net_RouterOS/releases
(which I recommend here, because “https”)
or
http://sourceforge.net/projects/netrouteros/files/PEAR2/

If all else fails, you could try the zip file. Extract it somewhere, and from your PHP file, include “/src/PEAR2/Autoload.php”.

Hello.

I have trie the sip version and add the src folder. When I have included the autoload.php file it says now:

“exception ‘Exception’ with message ‘Class Client could not be loaded from Client.php, file does not exist (registered paths=“F:\webs\gestion_xaupax\src”) [PEAR2_Autoload-0.2.4]’ in F:\webs\gestion_xaupax\src\PEAR2\Autoload.php:181 Stack trace: #0 [internal function]: PEAR2\Autoload::load(‘Client’) #1 F:\webs\gestion_xaupax\servicio.php(32): spl_autoload_call(‘Client’) #2 {main}”

The error line is this one:

$client = new Client($config[‘router’][‘hostname’], $config[‘router’][‘username’], $config[‘router’][‘password’]);

Good news is the files seem to be all right.

The fault here seems to be at your code. What is it in full? It should be something akin to

<?php
use PEAR2\Net\RouterOS;

require_once 'F:\webs\gestion\_xaupax\src\PEAR2\Autoload.php';

//Define $config here

$client = new RouterOS\Client($config['router']['hostname'], $config['router']['username'], $config['router']['password']);

(notice the "RouterOS" and the line with “use”)


or if you insist on using just “Client”, and not “RouterOS\Client”, then the top should say

use PEAR2\Net\RouterOS\Client;

but I’d not recommend this, as you’d then need to also add “use” lines for each class you use, e.g.

use PEAR2\Net\RouterOS\Client;
use PEAR2\Net\RouterOS\Query;
use PEAR2\Net\RouterOS\Request;
use PEAR2\Net\RouterOS\Util;

Hi

I could log into the router now, but now it responds that something is deprecated into the code at line 190 of the response.php file. But when you go to check that line it is a control which tell you how the code behaves. Maybe it is due to this line?

$ARRAY = $API->comm(“/ppp/active/print”);

Excuse me, this line:

$monitorRequest = new Request(‘/interface/monitor-traffic .proplist=rx-bits-per-second,tx-bits-per-second’);

The exact error is:

“PHP Deprecated: Response::getArgument() is deprecated in favor of Response::getProperty() (but note that Request::getArgument() is still valid) in F:\webs\gestion_xaupax\src\PEAR2\Net\RouterOS\Response.php on line 290”

I don’t think it’s this line causing it…

Somewhere you have something akin to

$response->getArgument('rx-bits-per-second'); 

or similar.

As the message warns, in the latest version, this changed to

$response->getProperty('rx-bits-per-second'); 

(believe me when I say it wasn’t an easy decision to change it, in part because conversations like this were to become inevitable…)

If you could link me to the original forum post where you got that from, I could save you the trouble of making it up to date :wink: .

Hello,

I extracted the code from the MikroTik forum http://forum.mikrotik.com/t/insert-pppoe-client-bandwidth-into-mysql/59856/1

Damn, I really went overboard with that one, didn’t I :laughing: .

I wrote that before realizing why using “namespace” in user code is a bad idea (and should only be done in library code instead). Also, turns out that “print” with “follow” argument is a perfectly valid command, pretty much equivalent to “listen”, except it can take queries, and includes the current ones too.

Here:

<?php
use PEAR2\Net\RouterOS;
require_once 'PEAR2_Net_RouterOS-1.0.0b5.phar';

$config = array(
    'db' => array(
        'hostname'  => '127.0.0.1',
        'username'  => 'root',
        'password'  => '',
        'charset'   => 'latin2',
        'dst-db'    => 'statsDb',
        'src-db'    => 'usersDb',
        'dst-table' => 'users',
        'src-table' => 'stats'
    ),
    'router' => array(
        'hostname'  => '192.168.0.1',
        'username'  => 'admin',
        'password'  => ''
    ),
    'misc' => array(
        'interval' => 3
    )
);

try {
    //Estabilishing connections. This is where stuff is most likely to fail.
    $mysqli = new mysqli($config['db']['hostname'], $config['db']['username'], $config['db']['password'], $config['db']['dst-db']);
    $mysqli->set_charset($config['db']['charset']);
    $client = new RouterOS\Client($config['router']['hostname'], $config['router']['username'], $config['router']['password']);
    
    //Because we'll be doing a lot of queries, we'll use a prepared statement.
    $insertStatement = array(
        $mysqli->prepare(
            "INSERET INTO {$config['db']['dst-table']}
                (username, timestamp, rxrate, txrate, nasshortname)
            VALUES (?, ?, ?, ?, '{$config['router']['hostname']}')"
        ),
        array(
            'user' => null,
            'timestamp' => null,
            'rx' => null,
            'tx' => null
        )
    );
    $insertStatement[0]->bind_param(
        'ssss',
        $insertStatement[1]['user'],
        $insertStatement[1]['timestamp'],
        $insertStatement[1]['rx'],
        $insertStatement[1]['tx']
    );

    $monitorRequest = new RouterOS\Request(
        '/interface/monitor-traffic .proplist=rx-bits-per-second,tx-bits-per-second'
    );
    $monitorRequest->setArgument('interval', $config['misc']['interval']);
    
    //This is the fun part. Upon receiving a response from the monitor,
    //the insert statement will be executed about it.
    $monitorListener = function ($response) use (&$insertStatement) {
        if ($response->getType(RouterOS\Response::TYPE_DATA)) {
            $insertStatement[1]['tiimestamp'] = date('Y-m-d H:i:s');
            
            $insertStatement[1]['user'] = substr(strstr($response->getTag(), '>', true), 7/*strlen('<pppoe-')*/); 
            $insertStatement[1]['rx'] = $response('rx-bits-per-second');
            $insertStatement[1]['tx'] = $response('tx-bits-per-second');
            
            $insertStatement[0]->execute();
        }
    };

    //Start collecting stats on existing interfaces.
    //If new users appear since we've started gathering stats, start collecting stats on them as well.
    $client->sendAsync(
        new RouterOS\Request(
            '/interface/print .proplist=.dead,name follow',
            RouterOS\Query::where('type', 'pppoe-in'),
            'listener'
        ),
        function ($response, $client) use ($monitorRequest, $monitorListener) {
            if ($response->getType(RouterOS\Response::TYPE_DATA)
                && 'yes' !== $response('.dead')
            ) {
                $client->sendAsync(
                    $monitorRequest
                        ->setArgument('interface', $name = $response('name'))
                        ->setTag($name),
                    $monitorListener
                );
            }
        }
    );
    
    //Activate event loop, i.e. the actual monitoring.
    $client->loop();
} catch (Exception $e) {
    die($e);
}

And if you want the version that attempts to reconnect, wrap the above in

<?php
use PEAR2\Net\RouterOS;
use PEAR2\Net\Transmitter;
require_once 'PEAR2_Net_RouterOS-1.0.0b5.phar';

$config = array(...);

while (true) {
    try {
        ...
    } catch (RouterOS\Exception $er) {
        sleep(10);
    } catch (Transmitter\Exception $et) {
        sleep(10);
    } catch (Exception $e) {
        die($e);
    }
}

(BTW, the note abut “interval” having to be smaller than default_socket_timeout no longer applies; It may be any value now)

Hi again, I have copied your code and now it give me another error

exception ‘Exception’ with message ‘Class mysqli could not be loaded from mysqli.php, file does not exist (registered paths=“F:\webs\gestion_xaupax\src”) [PEAR2_Autoload-0.2.4]’ in F:\webs\gestion_xaupax\src\PEAR2\Autoload.php:181 Stack trace: #0 [internal function]: PEAR2\Autoload::load(‘mysqli’) #1 F:\webs\gestion_xaupax\servicio2.php(35): spl_autoload_call(‘mysqli’) #2 {main}

I have tried to load it with this sentence:

use PEAR2\Net\RouterOS\mysqli;

But the file does not exist.

Good morning

I have passed that error right now, it was for using different php versions, so I have left an unique version on my system and that error is passed out. But now, it launches another one, in the next line “charset”, I have been reading and maybe it is about my MySQL version but I doubt about it because my version is higher than the one which is being refered at the forums. Have you ever had this error previously?

“PHP Fatal error: Call to undefined method mysqli::setCharset() in F:\webs\gestion_xaupax\servicio2.php on line 37”

Opps. My bad.

It’s mysqli::set_charset(), not mysqli::setCharset().

I’ve corrected it above.


As for the previous class not found error, you can safely have multiple PHP versions, as long as you make sure each has its own php.ini. And to use mysqli, the php.ini that the “current” PHP version is using needs to have extension=php_mysqli.dll uncommented.

Chances are that the other PHP version you had did use its own php.ini, but one which didn’t have that line in it.

Good evening.

Thank you, now the page remains loading all the time, it looks that makes the connection because I see it when using Torch in the router but nothing is inserted into the database. The rest of the code is as you gave me it and any error appears nor in the page neither in the php log file.

This script is supposed to be ran from the command line, not from a web page. From there, it’s supposed to stay on indefinitely (making it look like it has hanged, except it isn’t). Just like how I previously asked you to run the PHAR file, only this time, you’re supposed to run this PHP file instead.

You need to have previously created the database and the table for it to actually get inserted there, or else all calls to

            $insertStatement[0]->execute(); 

would simply fail silently. You can create them from MySQL Workbench, or whatever MySQL management tool you’d like to use.

The table should have columns named username, timestamp, rxrate, txrate and nasshortname, as seen in the script. Because @UsRb had two databases and two tables to worry about, the script was written with those two in mind, “src-” and “dst-”. For pure stats collection, you really only need one table in one database - the “dst-table” in the “dst-db”.

You can change the names of those here:

        'dst-db'    => 'statsDb',
        'src-db'    => 'usersDb',
        'dst-table' => 'users',
        'src-table' => 'stats' 

(and feel free to remove “src-table” and “src-db”)

If you want to use different column names for the table, you can edit the part about

        $mysqli->prepare(
            "INSERET INTO {$config['db']['dst-table']}
                (username, timestamp, rxrate, txrate, nasshortname)
            VALUES (?, ?, ?, ?, '{$config['router']['hostname']}')"
        ),