We help IT Professionals succeed at work.

PHP Fatal error:  Uncaught Error: Call to undefined function ssh2_connect() Centos 8, PHP 7.2.1

abuhaneef
abuhaneef asked
on
I am trying to implement ssh2 on PHP 7.2. 1. I am continually getting the error below.

[10-Jan-2020 18:40:19 UTC] PHP Fatal error:  Uncaught Error: Call to undefined function ssh2_connect() in /var/www/html/sshtest2.php:3

The method I used for the install was: https://medium.com/php-7-tutorial/solution-how-to-compile-php7-with-ssh2-f23de4e9c319

After the install, I verified the presence of the module.
                    cat /etc/php.d/ssh2.ini -> extension=ssh2.so
                    php -m|grep ssh2  ->  PHP Warning:  Module 'ssh2' already loaded in Unknown on line 0
                                                            ssh2

I have also copied extension=ssh2.so to /etc/php.ini, but I continually get the function error. Any ideas?  Script is below:


<?php
        echo "SSH connection: ";
        if (!($resource=@ssh2_connect("10.10.10.62"))) {
                echo "[FAILED]<br />";
                exit(1);
        }
        echo "[OK]<br />";

        echo "Athetication: ";
        if (!@ssh2_auth_password($resource,"user","password")) {
                echo "[FAILED]<br />";
                exit(1);
        }
        echo "[OK]<br />";

        echo "Shell: ";
        if (!($stdio = @ssh2_shell($resource,"xterm"))) {
                echo "[FAILED]<br />";
                exit(1);
        }
        echo "[OK]<br />";
        $command = "ls /etc";
        fwrite($stdio,$command);

        sleep(1);

        while($line = fgets($stdio)) {
                flush();
                echo $line."<br />";
        }

        fclose($stdio);
?>
Comment
Watch Question

Commented:
1. Create a new script, /var/www/html/info.php with these contents:
<?php
phpinfo();

Open in new window


2. Access that script via the web. Search the results for references to SSH and also note down the location of the php.ini file that it uses.

3. Switch back to the shell and run it via the command line:
php /var/www/html/info.php | less

Open in new window


Look for differences in the php.ini file location and whether or not SSH is present in the outputs (e.g. is SSH missing from both, or is it missing from just one, etc).

If both outputs share the same php.ini and same PHP version / binary, then you might simply need to restart your web server (or PHP-FPM, if you're using PHP-FPM).

Author

Commented:
php /var/www/html/info.php |grep ssh2 yielded this:

PHP Warning:  Module 'ssh2' already loaded in Unknown on line 0
/etc/php.d/ssh2.ini
Registered PHP Streams => https, ftps, compress.zlib, php, file, glob, data, http, ftp, ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp, compress.bzip2, phar
ssh2
libssh2 version => 1.8.0
banner => SSH-2.0-libssh2_1.8.0
PWD => /tmp/pecl-networking-ssh2-php7
$_SERVER['PWD'] => /tmp/pecl-networking-ssh2-php7
$_ENV['PWD'] => /tmp/pecl-networking-ssh2-php7


Searching for ssh on the info.php page only gave me this "libSSH Version       libssh/0.8.5/openssl/zlib "

Commented:
So at first glance, it looks like your binary executable version of PHP (the one you run on the shell) might have the SSH2 library properly installed with the PECL extension. Notice the libssh2 version is 1.8.0.

Then your web-based version seems like it might have an old version of libSSH installed and it doesn't seem to have the PECL extension.

So either you have two different PHP installations (one for the shell and one for the web), or your web version isn't reading from the same php.ini files, or your web version just hasn't been restarted yet.

Commented:
Also, the reason you're getting the message "PHP Warning:  Module 'ssh2' already loaded in Unknown on line 0" is likely because you indicated you added the extension to both /etc/php.d/ssh2.ini and also /etc/php.ini. So it's probably trying to load it twice.

Author

Commented:
How can I efficiently reduce it to 1 version?  Yes extension=ssh2.so is in both .
David FavorFractional CTO
Distinguished Expert 2019

Commented:
Note: The ssh2 module is still flagged as alpha quality for any PHP-7+, so consider well if it's wise to base code on this module.

If you must use this module, normally you'll install the php-ssh2 module from your Distro's repositories.

You can also build this from PECL, which may give you more unstable code or additional fixes.

For this module, you'll require a lot of work to determine the best course of action to use it.

Tip: If you look at the related GitHub repository, looks like last code update was 3x years ago, so this seems to either be AbandonWare or will eventually become AbandonWare.

There are many other, supported methods of accomplishing this... rather than using code edging toward AbandonWare.

Suggestion: Open another question describing what you're actually targeting to accomplish, asking for experts to describe how they might approach your project. You may find an alternative which is easier to maintain.

Commented:
How can I efficiently reduce it to 1 version?
That's a more complex system administration question that depends on how your system is set up. You would need to identify how both versions are running and then ensure that your web server is configured to use the appropriate version. Nobody can really answer more specifically than that without knowing your setup.

If you're not familiar with how to do this yourself, several people on here are available for hourly contract work and can help you for a fee. You'd have to contact them to ask for help.

Author

Commented:
I need to execute a script on another server from a php web form.   If I uninstall the pecl version will the shell begin working with the web server.

Commented:
You could always use shell_exec() to call the local ssh binary, and implement trusted SSH keys for authentication for password-less login.

However, I personally would not do it this via SSH. It has a lot of potential for errors and problems later on. The way I would approach it would be to use individual, simple steps that are less susceptible to errors:

Option #1:
Server A: Add a "job request" record into a database table.
Server A: Call a generic web script on Server B
Server B: Generic web script checks for new job requests in the database table, executes, the job, and puts the result back into the table.
Server A: Accesses the result from the table.

Option #2:
Similar to Option #1 but if Server B doesn't have a web server, then use a cron job on server B to execute the PHP script to check for new job requests instead.

Option #3:
Implement an authenticated, internal web service on Server B that Server A calls directly.

Option #4:
Similar to Option #3 but use a custom service (non-web), using something like ReactPHP, and then you can just use sockets to make the request and get the response.

Be wary that shell access is often pretty powerful, so if you give PHP on Server A the ability to SSH into Server B, then you're introducing a lot of risk if PHP is ever compromised on Server A. The above options allow you to define a very specific job for Server B to do without opening up any further access to the system.
David FavorFractional CTO
Distinguished Expert 2019

Commented:
You asked, "How can I efficiently reduce it to 1 version?  Yes extension=ssh2.so is in both".

The code for this project lives in one monolithic .php file, so you'll have to modify this code to downgrade to SSH V1.

Things to keep in mind.

1) V1 is completely retired.

2) Very few Distros enable even a fallback to V1 any more.

3) Currently sshd still contains code to support V1. If you're comfortable with must less secure connections, you can force sshd to enable V1 support.

4) Even if you do #3, you'll still have to rewrite the PHP module to support V1.
David FavorFractional CTO
Distinguished Expert 2019

Commented:
I need to execute a script on another server from a php web form.   If I uninstall the pecl version will the shell begin working with the web server.

Just run issue a shell_exec() call to run your script via ssh. No reason to much around with loading a PHP module.

Commented:
@David - I think when he said "How can I efficiently reduce it to 1 version?" , he was referring to the fact that he has two different PHP environments running. I don't think he was asking about how to downgrade to SSH v1. I could be wrong.

Also, while I also suggested shell_exec() as a possibility, any SSH-driven solution is going to likely expose far more risk than it needs to.

Author

Commented:
Thanks gr8gonzo for your response. I feel like I need to give a little more detailed explanation as to what I'm trying to do. I am trying to execute a on demand reset of a running service on Server B. For example the webpage would reside on Server A. User would open the web page click a button and reset a service on Server B. Risk is minimized because the both servers are contained on a private Network and do not have access to the internet.  Trusted SSH keys exist between the two servers
Commented:
I understand what you're trying to do. It's still a best practice architecture to implement a service that is dedicated to a specific task (e.g. a web service on Server B that resets specific services).

However, if you still want to use SSH, then shell_exec() is probably your best bet instead of the SSH2 extension anyway. It would be something like:

shell_exec("ssh username@hostname command");

Author

Commented:
Should this work?

$output = shell_exec("ssh user@10.10.0.100 ls /etc");
print_r ($output);

or

$output = shell_exec("ssh user@10.10.0.100 ls /etc");
echo "<pre>$output</pre>";

I tried both with no success.  ssh user@10.10.0.100 ls /etc produces output from the commandline.

Commented:
You might need to specify the full path to the ssh binary. If you're not sure where that is, just type "which ssh" on your command line.

If that doesn't work, it might be that you don't have the trusted key in PHP's user account's environment, or you haven't already executed an SSH connection to this host before for that user account that PHP runs under, so it's getting hung up on the host verification step. If that's the case, you can make sure that the remote host entry for server B is in PHP user account's ~/.ssh/known_hosts file. You can also disable host checking with "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no user@host command" but that's a pretty bad idea.

I also remembered there's an SSH2 implementation in phpseclib:
http://phpseclib.sourceforge.net/

...which requires no extensions or libraries at all. It is all implemented in pure PHP, which means it's slower but it should be a valid backup option for you.

I'd still recommend a non-SSH solution as the best option first.
If not that, then the second recommendation would be to get shell_exec() working without bypassing any security options.
If not that, then use phpseclib's implementation.
If not that, then finally fall back to shell_exec() with the security bypass (and that should be considered WORST case scenario - a temporary solution until you can get one of the better ones working).

Author

Commented:
I would like to give option 1 a try.  I will need details to accomplish this.  Is there an article that could explain more.

Option #1:
Server A: Add a "job request" record into a database table.
Server A: Call a generic web script on Server B
Server B: Generic web script checks for new job requests in the database table, executes, the job, and puts the result back into the table.
Server A: Accesses the result from the table.

Commented:
I don't know of one off the top of my head. Is there a part of that option that you don't know how to do?

Author

Commented:
Gr8gonzo, thanks for your suggestion. I ended up getting the exec(sudo SSH.....) to work by adding the script to the Apache user in the sudoers file. Thanks for sending me in the right direction.  I only had to run three simple commands so this was perfect.