【问题标题】:Interacting with multiple servers over SSH in PHP在 PHP 中通过 SSH 与多个服务器交互
【发布时间】:2011-01-18 23:22:13
【问题描述】:

我目前正在用 PHP 编写一个部署框架。该框架连接到服务器并通过 SSH 执行命令。我一直在寻找很长一段时间试图在 PHP 中找到一种方法来更好地做到这一点。以下是要求。该技术应该能够:

  1. 以编程方式输入 SSH 密码。我知道当您想要无密码 SSH 登录时,使用 SSH 密钥是一种方法,但请记住,这是一个部署框架。它可能一次部署到 25 台服务器。要求用户设置 SSH 密钥才能使用框架似乎不正确,谁想输入 25 次密码?我在这里使用 Capistrano 作为模型 - 它会询问您的密码一次,然后使用它来建立 SSH 连接而无需重新提示用户。我不建议将密码存储在部署脚本中,只需(静默)输入一次并在部署任务完成之前使用。

  2. 将输出发送到 PHP 脚本。我希望能够独立拦截每个 SSH 会话的终端输出,对其进行修改,然后将其发送回终端供用户查看。这样,我可以将服务器的名称添加到输出的每一行以显示正在发生的事情。

  3. 提供对终端的写入(以及读取)访问权限。重要的是用户(或脚本)能够在终端中输入除 SSH 密码之外的其他信息。

  4. 支持 SSH v2。

目前,我的框架将部署脚本中的命令“编译”成一个巨大的字符串,并使用 SSH 命令执行它们。每个最终部署命令如下所示:

ssh -t -t -p 12345 user@server.com 'command1; command2;'

这些 SSH 命令中的每一个都通过 PHP 的内置 passthru 函数执行:

<?php passthru("ssh -t -t -p 12345 user@server.com 'command1; command2;'"); ?>

我尝试使用 proc_open 和几乎所有 PHP 的其他命令执行函数都无济于事 - 它们都没有提供我上面列出的所有功能。此外,我尝试了几个纯 PHP SSH 实现,也无济于事。这些库要么不提供对终端的写访问权限,要么不支持 SSH v2。

对此的任何帮助将不胜感激 - 提前致谢!

【问题讨论】:

    标签: php deployment ssh passthru


    【解决方案1】:

    您认为以下是对终端的写访问的示例吗?:

    ssh -t -t -p 12345 user@server.com 'command1; command2;'
    

    如果是这样,那么您可以使用 phpseclib's pure PHP SSH implementation 来做到这一点。例如。

    $ssh = new Net_SSH2(...);
    $ssh->login(..., ...);
    $ssh->exec('command1; command2;');
    

    如果不是,那么(1)我会说你最好使用 phpseclib,而不是你当前的实现和(2)如果你想要 phpseclib 作者所说的“交互式”支持可能你可以尝试联系作者吗?也许愿意付给他一些钱来激励他开发这个功能。查看支持论坛,作者似乎反应足够。

    【讨论】:

    • 嗯,不错的建议。我之前尝试过使用phpseclib,发现它还不错,但是没有写权限。它支持具有写访问权限的 v1,但不支持 v2。我真的不认为你提到的第一个命令是写访问,因为它是使用passthru 执行的。我真正在寻找的是流到标准输入/标准输出。
    • 我最终能够让 phpseclib 满足我的需要。如果您使用 SSH2,它不提供写访问权限,但我认为期望用户为 subversion checkouts 等设置密钥并不是不可能的。感谢您为我指明正确的方向!
    【解决方案2】:

    我不确定 php 是否是正确的工具。为什么不使用更接近 shell 环境的东西,比如 bash 脚本?

    我可以想象您想要使用 PHP 的唯一原因是您可以通过单击页面上某处的链接来启动该过程,从而在您的系统应该具有的任何安全性上打一个大洞。但如果你真的需要,那么用更友好的 shell 语言编写脚本并简单地使用 php 作为网关来调用脚本仍然更容易。

    【讨论】:

    • 我同意你的观点,但 bash 脚本的灵活性远不如 PHP。我不打算从网络上使用部署框架,只是从命令行。该框架主要面向希望在同构环境中工作的开发人员,即仅将 PHP 用于他们的站点和部署脚本。这与最初为 Rails 应用程序开发的 Ruby 部署框架 (Capistrano) 的理念相同。
    • 我不理解同类环境的动机,我也不推荐 PHP 作为该任务的首选语言。一旦您开始对基本功能进行系统和直通调用,这应该是显而易见的,您只是委托给 shell 以弥补 PHP 库中的缺点。
    • 无论如何,您可能会通过使用输出缓冲来捕获终端输出并将其传输到您想要的位置。这可能就是 Capistrano 所做的。
    • 输出缓冲的想法很有趣,但不一定是实时的。不过,很好的建议。对于大多数企业来说,同质环境并不是真正关心的问题,但仍然允许您使用您知道的语言来完成所有任务。我发现 Capistrano 真的很令人困惑(所有的冒号是什么??),因此我希望使用 PHP。使用 passthru 实际上只是权宜之计——我也尝试过使用纯 PHP SSH 实现,但无济于事。 (顺便说一下,Capistrano 甚至不使用内置的 Ruby 函数来实现它的目标 - 它使用 SSH gem。)
    【解决方案3】:

    您可以使用 PHP 中的 PECL 扩展建立 SSH 连接。 http://php.net/manual/en/book.ssh2.php

    $connection = ssh2_connect('server.com', 22);
    ssh2_auth_password($connection, 'username', 'password');
    $stream1 = ssh2_exec($connection, $command1);
    $stream2 = ssh2_exec($connection, $command2);
    

    如果你需要更高级的东西,你也可以使用 ssh2_shell() 创建一个 ssh 交互式 shell。

    【讨论】:

    • 好主意,但是当我意识到 PECL 是必须内置到 PHP 中的东西时,我似乎记得放弃了这种方法。我想要求用户拥有它并不是什么大不了的事,但这可能会阻止他们使用我的框架。好主意,谢谢!
    • 是的,我自己尽量避免 PECL。
    • 我想这一切都取决于你对“尽可能”的定义。如果你真的需要它,因为没有其他解决方案存在,那么这是有道理的......
    猜你喜欢
    • 1970-01-01
    • 2014-04-25
    • 1970-01-01
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 2018-09-10
    • 2011-10-26
    • 2010-10-02
    相关资源
    最近更新 更多