在 PHP 中通过 SSH 连接到 MySQL 服务器

Posted

技术标签:

【中文标题】在 PHP 中通过 SSH 连接到 MySQL 服务器【英文标题】:Connect to a MySQL server over SSH in PHP 【发布时间】:2010-10-02 15:13:45 【问题描述】:

我的数据库位于远程 Linux 机器上,我想使用 SSH 和 php 函数进行连接(我目前正在为此使用 ssh2 库)。我尝试使用 mysql_connect,但它使我无法访问(尽管我已授予权限) 当我尝试使用此功能时:

$connection = ssh2_connect('SERVER IP', 22);

ssh2_auth_password($connection, 'username', 'password');

$tunnel = ssh2_tunnel($connection, 'DESTINATION IP', 3307);

$db = mysqli_connect('127.0.0.1', 'DB_USERNAME', 'DB_PASSWORD', 
                         'dbname', 3307, $tunnel)
    or die ('Fail: '.mysql_error());

我收到错误“mysqli_connect() 期望参数 6 是字符串,给定资源”。我该如何解决这个问题?

【问题讨论】:

Connect to a MySQL server over SSH in PHP 的可能重复项 【参考方案1】:

SSH 隧道解决方案

为您的 MySQL 数据库服务器设置 SSH 隧道(通过 Jumpbox 代理以确保安全)。

(A) 图形用户界面工具

根据您的要求,您可以使用内置 SSH 隧道支持的 GUI MySQL 客户端,例如 Visual Studio Code Forwarding a port / creating SSH tunnel、TablePlus 或使用 PuTTY 来设置 本地端口转发。

在 macOS 上,我喜欢 Secure Pipes 或 TablePlus。

(B) 命令行

第 1 步。

ssh -fNg -L 3307:10.3.1.55:3306 username@ssh-jumpbox.com 

这里的关键是 '-L' 开关,它告诉 ssh 我们正在请求本地端口转发。

我已选择使用上面的端口 3307。我的 本地 机器上指向此端口的所有流量现在都将通过我的 ssh 客户端“端口转发”到运行在主机地址为ssh-jumpbox.com

在这种情况下,Jumpbox ssh 代理服务器将代表您(10.3.1.55:3306)解密流量并与您的 MySQL 数据库服务器建立网络连接。 MySQL 数据库服务器会看到来自 Jumpbox 内部网络地址的连接。

本地端口转发语法 语法有点棘手,但可以看作:

<local_workstation_port>:<database_server_addr_remote_end_of_tunnel>:<database_server_port_remote_end> username@ssh_proxy_host.com

如果您对其他开关感兴趣,它们是:

-f(转到后台) -N(不执行远程命令) -g(允许远程主机连接到本地转发端口)

私钥认证,上面加(-i)开关:

-i /path/to/私钥

第 2 步。

告诉您的本地 MySQL 客户端通过您机器上的本地端口 3307 (-h 127.0.0.1) 通过您的 SSH 隧道连接,该端口现在转发通过您在步骤 1 中建立的 SSH 隧道发送给它的所有流量。

mysql -h 127.0.0.1 -P 3307 -u dbuser -p passphrase

客户端和服务器之间的数据交换现在通过加密的 SSH 连接发送并且是安全的。

安全说明 不要直接通过隧道连接到您的数据库服务器。拥有可从 Internet 直接访问的数据库服务器是一项巨大的安全责任。将隧道目标地址设置为 Jumpbox/Bastion 主机的 Internet 地址(参见步骤 1 中的示例),并将数据库的目标设置为远程网络上数据库服务器的 internal IP 地址。 SSH 将完成剩下的工作。

第 3 步。

现在连接您的 PHP 应用程序:

<?php
      $smysql = mysql_connect( "127.0.0.1:3307", "dbuser", "passphrase" );
      mysql_select_db( "db", $smysql ); 
?>

感谢 Chris Snyder 的伟大的 article 详细介绍了用于 MySQL 连接的 ssh 命令行隧道。

【讨论】:

非常感谢!我花了几个小时在这上面,终于找到了你的答案。我正在开发一个 Laravel PHP 应用程序,我的本地机器是带有 nginx 和 Git Bash 的 Windows 10,我的数据库是远程的(在 Cloudways/DigitalOcean 上),所以我需要在 Git Bash ssh -i ~/.ssh/my_file -fNg -L 3307:127.0.0.1:3306 myUser@192.222.222.22 中运行类似的东西,并且然后我的 Laravel 应用程序被允许使用 DB_HOST=127.0.0.1DB_PORT=3307 连接到 Cloudways 数据库。 我们不能在 PHP 中使用 PDO 连接吗? ...我试过但没有用 这不是完整 php 中的解决方案,您需要在 bash 中运行 ssh 隧道,而不是在问题中询问的 php 中。 嗨杰罗姆。我不明白你指的是这里。问题明确地问,“...我想使用ssh和php连接”,这也反映在标题中。 我相信 -i 意味着提供私钥而不是公钥?【参考方案2】:

我一直在寻找同样的东西,但我更喜欢不需要外部命令和管理外部进程。所以在某些时候我想,编写一个可以在任何 PHP 流上运行的纯 PHP MySQL 客户端有多难?根据 MySQL 协议文档,我花了大约半天时间。

https://gist.github.com/UCIS/4e509915ed221660e58f5169267da004

您可以将它与 SSH2 库或任何其他流一起使用:

    $ssh = ssh2_connect('ssh.host.com');
    ssh2_auth_password($ssh, 'username', 'password');
    $stream = ssh2_tunnel($ssh, 'localhost', 3306);
    $link = new MysqlStreamDriver($stream, 'SQLusername', 'SQLpassword', 'database');
    $link->query('SELECT * FROM ...')->fetch_assoc();

它没有实现完整的 mysqli API,但它应该适用于所有纯文本查询。如果你决定使用这个请小心,我还没有彻底测试过代码,字符串转义代码也没有经过审核。

【讨论】:

我需要添加哪些依赖项?使用作曲家的答案将是首选。 @tannerburton 它在 PHP7 中工作。您需要ssh2 PHP extension。我还注意到我从原始项目中复制的代码中有一些不匹配的名称空间,我已经删除了这些名称空间。如果还是不行,你真的需要仔细看看 PHP 的错误信息。【参考方案3】:

我相信我(我想大多数人)在让它工作时遇到问题的原因是因为 mysql 服务器中的用户被设置为只允许来自“localhost”而不是 127.0.0.1,IP 地址本地主机。

我通过执行以下步骤使其工作:

第 1 步:允许目标用户使用 127.0.0.1 主机

SSH 正常进入你的服务器,并使用 mysql root 用户登录,然后发出命令:

GRANT ALL ON yourdbname.* TO yourdbuser@127.0.0.1 IDENTIFIED BY 'yourdbpassword';

关键当然是上面指定127.0.0.1。

第 2 步:启动到 MySQL 的本地 SSH 隧道

您现在可以启动到远程 MySQL 服务器的本地 SSH 隧道,如下所示:

ssh -vNg -L 33306:127.0.0.1:3306 sshuser@remotehost.com

-v 使 ssh 以详细模式运行,这有助于查看正在发生的事情。例如,当您尝试连接时,您会在终端控制台中看到如下调试输出:

debug1: client_input_global_request: rtype hostkeys-00@openssh.com want_reply 0
debug1: Connection to port 33306 forwarding to 127.0.0.1 port 3306 requested.

关闭连接时输出如下:

debug2: channel 2: is dead
debug2: channel 2: garbage collecting
debug1: channel 2: free: direct-tcpip: listening port 33306 for 127.0.0.1 port 3306, connect from 127.0.0.1 port 52112 to 127.0.0.1 port 33306, nchannels 3

-N 使 ssh 不发出任何命令,而是在建立连接后等待。

-g 允许远程主机连接到本地转发端口。不完全确定这是否有必要,但它对于通过同一 SSH 隧道多路复用多个连接可能很有用。

-L这个主要参数指定本地端口33306连接远程主机的本地IP地址127.0.0.1和远程主机的mysql端口,一般是3306

之后,您可以使用所需的任何机制/其他参数通过 SSH 连接到远程主机。就我而言,我使用在我的~/.ssh/config 中配置的密钥文件,所以我只需要指定user@host 即可进入。

发出这样的命令会在前台运行 SSH,因此我可以使用 Ctrl + C 轻松关闭它。如果您想在后台进程中运行此隧道,您可以添加 -f 来执行此操作。

第 3 步:从 PHP/其他 mysql 兼容方法连接

在您的 localhost 上从上面运行的 SSH 隧道的行为与您的 mysql 在 127.0.0.1 上运行的行为完全相同。我使用端口33306(注意三个3),它让我可以在其正常端口上运行我的本地sql 服务器。您现在可以像往常一样连接。终端上的mysql 命令如下所示:

mysql -h 127.0.0.1 -P 33306 -u yourmysqluser -p

-P(大写 P)指定 SSH 隧道的本地端接受连接的端口。使用127.0.0.1 IP 地址而不是localhost 很重要,因为 mysql cli 将尝试可能使用 linux 套接字进行连接。

对于 PHP 连接字符串,我的数据源名称字符串(对于我的 Yii2 配置)如下所示:

'dsn' => 'mysql:host=127.0.0.1;dbname=yourdbname;port=33306',

密码和用户名按正常方式指定。

【讨论】:

【参考方案4】:

不幸的是,php 提供的 ssh2 隧道似乎无法处理远程 mysql 连接,因为您无法指定要隧道的本地端口(它仅适用于端口 22 或远程服务器正在运行的任何 ssh 端口)。我对此的解决方案是通过exec() 运营商打开隧道并从那里照常连接:

exec('ssh -f -L 3307:127.0.0.1:3306 user@example.com sleep 10 > /dev/null');
$mysqli = new mysqli('127.0.0.1', 'user', 'password', 'database', '3307');

【讨论】:

@YingStyle - 密钥认证 我用什么代替user@example.com 可以使用 -i 标志设置密钥授权文件。 user@example.com 将是您要通过隧道连接的主机的登录名。 user 是用户名,example.com 是主机或 IP。【参考方案5】:

确保您连接的用户名和密码具有正确的主机名权限。我相信你可以使用 '%' 作为通配符。此外,如果您要连接到不在本地网络上的远程计算机(如果您尝试 ssh 进入它,我会假设您是),您将不得不转发路由器上的端口,服务器所在的服务器用于外部流量能够连接到它。

http://www.lanexa.net/2011/08/create-a-mysql-database-username-password-and-permissions-from-the-command-line/

【讨论】:

【参考方案6】:

即使我尝试通过 root 凭据和公钥对执行 ssh,但它允许我通过命令行而不是通过 php 代码连接。我也尝试通过创建隧道(通过使用 ssh2 函数),从 php 代码(系统、执行等)运行 shell 命令,但没有任何效果。最后我尝试了 ssh2 函数来执行 shell 命令,它终于工作了:) 这是代码,如果它对你有帮助的话:----

$connection = ssh2_connect($remotehost, '22');
if (ssh2_auth_password($connection, $user,$pass))  
    echo "Authentication Successful!\n";
 else 
    die('Authentication Failed...');


$stream=ssh2_exec($connection,'echo "select * from zingaya.users where id=\"1606\";" | mysql');
stream_set_blocking($stream, true);
while($line = fgets($stream))  
    flush();
    echo $line."\n";

如果想专门使用 php 函数,我可以试试这个。

【讨论】:

【参考方案7】:

根据the docs,最后一个参数应该是套接字或管道名称,例如“/var/run/mysql/mysql.sock”。由于您没有使用 UNIX 套接字进行连接,因此这不适用于您……所以请尝试将其排除在外。

【讨论】:

以上是关于在 PHP 中通过 SSH 连接到 MySQL 服务器的主要内容,如果未能解决你的问题,请参考以下文章

在 Netbeans 中通过 SSH 连接到 MySql db

在 Java 中通过 SSH 隧道连接到 Mongo 数据库

在 Linux 中通过 SSH 连接到 Amazon EC2

用于从该框中通过 SSH 连接到 jumphost 和 sftp 的 Python 脚本

在 Android 中通过 XAMPP 连接到 MYSQL

在IIS7中通过PHP连接到SQL SERVER 2008(使用Windows身份验证)?