Как я могу использовать PHP для настройки интерактивного сеанса SSH?
Я пытаюсь установить интерактивное SSH-соединение с удаленным сервером с помощью PHP через командную строку в Mac OS X 10.6. В настоящее время я использую функцию PHP proc_open для выполнения следующей команды:
ssh -t -t -p 22 [email protected]
Это почти работает. Параметры -t -t
должны принудительно использовать псевдотерминал, что они почти и делают. Я могу ввести пароль SSH и нажать enter. Однако после нажатия клавиши enter терминал, похоже, просто зависает. Никакого выхода, ничего - это как если бы Сеанс SSH не удался. Я не могу запускать команды или что-то еще, и мне приходится убивать все это с помощью Ctrl+C. Я знаю, что вход в систему прошел успешно, потому что я могу выполнить команду типа ssh -t -t -p 22 [email protected] "ls -la"
и получить правильный вывод.
Я подумал, что проблема, должно быть, связана с тем фактом, что я использовал стандартные каналы в своем вызове proc_open, поэтому я заменил их на pty. Я получаю следующую ошибку: "псевдотерминал pty не поддерживается в этой системе..."
Mac OS X просто не поддерживает pty или псевдо терминалы? (Я довольно новичок в использовании всей этой терминологии оболочки).
Вот PHP-код:
$descriptorspec = array(0 => array("pty"), 1 => array("pty"), 2 => array("pty"));
$cwd = getcwd();
$process = proc_open('ssh -t -t -p 22 [email protected]', $descriptorspec, $pipes, $cwd);
if (is_resource($process))
{
while (true)
{
echo(stream_get_contents($pipes[1]));
$status = proc_get_status($process);
if (! $status["running"])
break;
}
}
(Извините - ни за что на свете не могу разобраться в инструкциях по форматированию SO...)
Что я делаю не так? Почему я не могу использовать pty? Это просто невозможно в Mac OS X? Спасибо за вашу помощь!
6 answers
Вам следует использовать аутентификацию с открытым ключом, а не пытаться программно обойти интерактивную аутентификацию по паролю.
Предполагается, что запрос пароля должен использоваться из tty, и я считаю, что его намеренно усложнили для использования в противном случае. Кроме того, аргумент -t -t
вступает в силу только после подключения к удаленному хосту. И я не верю, что функция PHP proc_open()
может запускать команду внутри виртуального терминала.
Для настройки открытого ключа аутентификация:
# Generate keypair
ssh-keygen -t rsa
# Copy public key to server
scp ~/.ssh/id_rsa.pub example.com:.ssh/authorized_keys
# Now you shouldn't be prompted for a password when connecting to example.com
# from this host and user account.
ssh example.com
# Since the web server (and thus PHP) probably has its own user account...
# Copy the ~/.ssh/id_rsa file somewhere else
cp ~/.ssh/id_rsa /some_path/id_rsa
# Change ownership of the file to the web server account
chown www-data:www-data /some_path/id_rsa
# Fix the file permissions (ssh ignore the keyfile if it is world readable)
chown 600 /some_path/id_rsa
# Try connecting to the server through the web server account
su -c "ssh -i /some_path/id_rsa -o UserKnownHostsFile=/some_path/known_hosts example.com" www-data
# Add the host to the known hosts file when prompted
В качестве альтернативы вы можете использовать plink
(часть PuTTY для Linux) вместо OpenSSH, поскольку он может принимать пароль в командной строке plink -pw password example.com
. Но это создает угрозу безопасности, поскольку любой, кто запускает ps aux
на сервере, может видеть пароль в списке процессов.
Существует также программа под названием sshpass
, которая берет пароль из переменной среды или аргумента команды и передает его ssh
.
Похоже, что проблему лучше всего решить с помощью функции PHP passthru(). После еще многих (довольно болезненных) исследований я смог выполнить команду с помощью этой функции и мог взаимодействовать с удаленным сервером через терминал, как если бы я запустил экспорт ssh и svn вручную (для них обоих требуются пароли, поэтому были хорошие тесты). Что мне нужно будет сделать, так это создать (потенциально очень длинную) строку команд, разделенных &&
, и прикрепить их к концу команды ssh: ssh -t -t -p 22 hostname command1 && command2 ...
Вывод будет отправлен на мой терминал в Mac OS X, даже если команды выполняются на удаленном сервере. Похоже, это решение, которое я искал все это время - на самом деле довольно простое! Спасибо всем, кто помог мне в этом. Я поставил Александру "зеленую галочку", потому что он был единственным, кто продолжал отвечать и был весьма полезен в выводе окончательного ответа на проблему. Спасибо, Александр!
Это устарело, но для любых гуглеров есть реальное решение с использованием proc_open:
Дескрипторы Pty доступны в PHP, но должны быть настроены во время компиляции (см. Этот 10-летний отчет об ошибке https://bugs.php.net/bug.php?id=33147)
Но в python, однако, у нас нет этой проблемы. Поэтому вместо того, чтобы запускать команду ssh напрямую, запустите этот скрипт python:
import sys
import pty
args = " ".join(sys.argv[1:])
pty.spawn(['/usr/bin/ssh', args])
О pty.spawn из документов python:
Порождает процесс, и подключите его управляющий терминал к стандартному вводу-выводу текущего процесса. Это часто используется для того, чтобы сбивать с толку программы, которые настаивают на считывании с управляющего терминала.
Вы пробовали расширение PHP SSH2?
Вы пробовали phpseclib, чистую реализацию PHP SSH?:
<?php
include('Net/SSH2.php');
$ssh = new Net_SSH2('www.domain.tld');
if (!$ssh->login('username', 'password')) {
exit('Login Failed');
}
echo $ssh->read('username@username:~$');
$ssh->write("ls -la\n");
echo $ssh->read('username@username:~$');
?>
Я написал ssh-клиент на php с расширением ssh2, вы можете взглянуть на исходный код на странице github https://github.com/roke22/PHP-SSH2-Web-Client
Пожалуйста, отправьте несколько отзывов.