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

21
我想通过ssh在我的mysql服务器上建立一个ssh隧道。
理想情况下,我会像直接连接一样返回一个mysqli db指针。
我在一个没有SSH2库的共享主机上,但我可能可以使用PECL在本地安装它们。
如果有一种使用本机命令的方法,那就太好了。
我认为可以尝试这样做,但没有那些库它是行不通的。
$connection = ssh2_connect('SERVER IP', 22); 

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

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

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

有人有任何想法吗?我在liquidweb上运行共享的CentOS Linux主机。

关于如何使隧道持久化,有什么想法吗?是否可能使用另一个脚本建立它并在PHP中利用它?

谢谢。


你意识到那个共享主机上的其他人也可以连接到你的数据库,对吧? - Zoredache
它仍需要有效的用户名和密码才能连接,但这是明确的风险。如果在PHP中每次执行创建隧道,那么情况是否如此? - Eric Goodwin
我删除了之前的回答,因为在阅读文档后我发现使用mysqli使用SSL比我想象的要复杂得多。 - Powerlord
6个回答

16

我将使用autossh工具创建一个持久的SSH隧道连接到你的MySQL数据库。然后,在你的PHP代码中,你只需要将其指向本地主机。

你可以通过执行以下操作进行测试(不自动重启):

ssh -L 3306:localhost:3306 user@domain.com

设置ssh密钥以免使用密码,并调整mysql系统中的.ssh/authorized_keys文件,只允许其用于端口转发。

欲了解更多有关ssh技巧的信息,请参见Brian Hatch在SSH和端口转发方面的优秀系列文章。


这个答案让我找到了正确的方向。我最终在这里弄清楚了:https://dev59.com/h3RB5IYBdhLWcg3w7riV#hwcZoYgBc1ULPQZFSBaz - Ryan

13

在执行SQL操作期间必须保持隧道开启。以下来自RJMetrics的示例可以解释:

以下是通用的SSH命令语法:

ssh -f -L bind-ip-address:bind-port:remote-ip-address:remote-port \
username@remote-server [command] >> /path/to/logfile

以下是如何只用2行PHP代码安全地建立远程数据库连接:

shell_exec("ssh -f -L 127.0.0.1:3307:127.0.0.1:3306 user@remote.rjmetrics.com sleep 60 >> logfile");  
$db = mysqli_connect("127.0.0.1", "sqluser", "sqlpassword", "rjmadmin", 3307);
我们使用shell_exec()函数创建一个具有60秒开放窗口的隧道,然后使用mysqli_connect()函数使用转发的端口打开数据库连接。请注意,我们必须在这里使用“mysqli”库,因为mysql_connect()不允许我们指定端口,而mysql_ * 函数已经过时。 sleep 60:在隧道连接方面,我们基本上有两个选项:始终保持连接开放或根据需要打开并关闭它。我们更喜欢后者,因此在建立隧道时不指定-N选项,这将使其一直保持开放状态,直到手动停止进程(对于自动化来说是不好的)。由于没有指定-N,所以我们的隧道会在其SSH会话不被用于任何事情时关闭自身。这是理想的行为,除了我们创建隧道和通过隧道运行MySQL连接之间的几秒钟之外。为了在此期间给我们一些时间,我们在创建隧道时发出无害的sleep 60命令,这基本上为我们购买了60秒的时间,在隧道关闭之前通过隧道运行其他操作。只要在该时间段内建立了MySQL连接,我们就可以开始工作了。

1
这个问题要求输入ssh密码,该如何处理? - Vivek Sancheti

7

我尝试使用root凭据和公私钥对进行SSH,它允许我通过命令行连接,但不能通过PHP代码连接。

我还尝试通过创建隧道(使用SSH2函数)并从PHP代码运行shell命令(systemexec等),但都没有成功。

最后,我尝试使用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函数,请尝试以下方法。

3

这是可能的,但为什么要这样做呢?这会比必要的复杂,并且容易出错。

你不能在本地运行数据库吗?如果不行,你不能使用像SQLite、XML文件或其他不需要单独服务器守护程序的东西吗?

你真的不想在PHP脚本内初始化隧道。初始化SSH隧道需要很长时间(可以轻松地达到一两秒钟),这意味着每个连接到数据库的页面在加载时都会有2秒的延迟。

如果你必须这样做(我强烈建议不要这样做),最好的方法是有一个在后台维护连接的脚本。

设置SSH密钥对。然后使用autossh,或一个简单的脚本来执行所需的SSH命令,等待进程死亡并重新启动它。它可以更智能化,尝试每10-20秒运行一次命令,如果失败则重新连接。

使用SSH密钥对,您无需在脚本中硬编码远程用户密码。我建议通过使用专用隧道用户并给它一个受限制的shell来限制远程用户的操作(请参阅this问题)。
简而言之,我强烈建议首先尝试SQLite,然后查看使用XML文件存储数据的可行性,再尝试向您的Web主机请求获取本地MySQL服务器,然后考虑SSH隧道选项。

1
如果需要加密连接,您会推荐 SSL 还是 SSH? - csi
@ChristopherIckes 是的,SSL会更加合适。 - dbr

1

Eric,

我认为你这次没什么运气。你可以在 PHP 代码中使用 ssh 扩展,或者如果你有服务器访问权限,你可以尝试在命令行上创建一个 ssh 隧道。

虽然你可能需要特殊权限才能这样做。另外看起来你没有此托管账户的 ssh 权限。

--Joao


1

我认为你最好找一个不同的托管提供商;我建议使用VPS解决方案(虚拟专用服务器),它可以让您完全掌控您的Web主机。这样,如果您不喜欢默认配置,您可以自己升级。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接