2016-12-09 4 views
3

Я новичок в PHP и phpseclib implementation of SSH.PHP скрипт зависает после команды exec

У меня есть следующий код:

$ssh = new Net_SSH2($_SESSION['targetAddress']); 
if (!$ssh->login(SSH_USER, SSH_PASSWORD)) { 
    exit('Login Failed'); 
} 

$ssh->setTimeout(400); 
$a = 0; 

while(isset($file[$a])) { 
    $ssh->exec('cd '.$_SESSION['path'].'; find -L '.$file[$a].' > /tmp/ligacoes; for i in `cat /tmp/ligacoes`; do cp $i /var/tmp/; done'); 
    $a++; 
} 

То, что я пытаюсь сделать здесь, чтобы скопировать файлы, выбранные пользователем на удаленном сервере в новый каталог на том же сервере. При выполнении сценария он успешно находит и копирует первый файл в новый каталог, но после этого сценарий просто останавливается. Даже если пользователь выбирает только один элемент, скрипт зависает и не продолжается. Он еще не прирастает $a

Любые мысли о том, что может произойти?

UPDATE:

Real Time NET_SSH2 Log

Я побежал команду непосредственно на сервере, и она прекрасно работает. Я предполагаю, что проблема ограничена $ssh->exec();

UPDATE 2:

Я изменил мой $ssh->exec('cd '.$_SESSION['path'].'; find -L '.$file[$a].' > /tmp/ligacoes; for i in 'cat /tmp/ligacoes'; do cp $i /var/tmp/; done'); к $ssh->exec('cd '.$_SESSION['path'].'; cp '.$file[$a].' /var/tmp;'); и решить часть проблемы. Теперь я могу скопировать один выбранный файл в новый каталог, и скрипт не зависает. Проблема сохраняется, когда выбраны два или более файлов.

+0

[Эффективно просто посмотреть на выход] (http://phpseclib.sourceforge.net/documentation/net.html) '$ ssh-> getLastError()' (который возвращает строку) и '$ ssh-> getErrors() '(который возвращает массив). Опубликуйте этот вывод, если он есть, в вашем вопросе. – WEBjuju

+0

Это можно сделать, используя PHP с меньшим количеством ресурсов. См. Http://stackoverflow.com/questions/19139434/php-move-a-file-into-a-different-folder-on-the-server#19139524 – Kitson88

+0

@WEBjuju Нет выхода ошибки. Использование '$ ssh-> getLog();' единственный доступный мне журнал - это соединение успешно. –

ответ

0

Вот как тайм-аут работает w.r.t. Exec().

Таким образом, первая строка в методе Exec() заключается в следующем:

$this->curTimeout = $this->timeout; 

Позже есть while (true) цикл, который имеет в нем строку:

$temp = $this->_get_channel_packet(self::CHANNEL_EXEC); 

_get_channel_packet имеет while (true) петлю, а также , Он перемещается до тех пор, пока не истечет время ожидания или пока он не получит данные по соответствующему каналу. Вот код тайм-аут:

 if ($this->curTimeout) { 
      if ($this->curTimeout < 0) { 
       $this->is_timeout = true; 
       return true; 
      } 
      $read = array($this->fsock); 
      $write = $except = null; 
      $start = microtime(true); 
      $sec = floor($this->curTimeout); 
      $usec = 1000000 * ($this->curTimeout - $sec); 
      // on windows this returns a "Warning: Invalid CRT parameters detected" error 
      if ([email protected]_select($read, $write, $except, $sec, $usec) && !count($read)) { 
       $this->is_timeout = true; 
       return true; 
      } 
      $elapsed = microtime(true) - $start; 
      $this->curTimeout-= $elapsed; 
     } 

stream_select блоки, пока данные не доступны для чтения. В зависимости от поведения вашего SSH-сервера он вполне может блокироваться на 400 секунд. И кто знает ... может быть, в вашей системе stream_select потерпит крах, прежде чем он доберется до 400-х.

Сказанное: функция предупреждения включена для этой функции, как указано в комментарии выше вызова stream_select. Вы можете удалить подавление ошибок. Это может дать некоторую информацию.

Кроме того, имейте в виду, что тайм-аут отслеживает только время, необходимое для предоставления данных. Например, время, затрачиваемое на дешифрование, не учитывает тайм-аут.

Например ...

$ssh->write("cat /dev/urandom\n"); 

$ssh->setTimeout(10); 
$start = microtime(true); 
echo $ssh->exec('ping google.com'); 
$elapsed = microtime(true) - $start; 

echo "took $elapsed seconds\n"; 

Я делаю это и $ssh->exec() принимает 20s (несмотря на тайм-аут). Если я прокомментирую $ssh->write(), это займет 10 секунд. cat /dev/urandom\n просто наводняет клиента. Вы можете видеть это более четко при ведении журнала в реальном времени (define('NET_SSH2_LOGGING', 3);). Проблема в том, что узким местом является не время блокировки, а время, затрачиваемое на получение данных/их дешифрование.

3

вещи, которые могут помочь:

  1. $ssh->exec вторит как stdout и stderr. Проверьте их.
  2. Попробуйте просто echo $ssh->exec('echo hello');
  3. Подключиться вручную, чтобы убедиться, что «Подлинность хоста ... Вы действительно хотите продолжить соединение?» был принят.
  4. Оставьте определенному, чтобы ** проверить каждую из своих команд вручную, чтобы убедиться, что они работают, прежде чем передавать их через ваш скрипт.
  5. Поместите один пример ваших команд в файл bash и попробуйте выполнить только файл bash. Если это работает, вы можете отправить переменные через exec() в файл bash для обработки. Что-то вроде:

mybash.sh

cd /example/path/; 
find -L example_file > /tmp/ligacoes; 
for i in `cat /tmp/ligacoes`; 
do cp $i /var/tmp/; 
done 

и в РНР

$ssh->exec('mybash.sh'); 

Если это работает, то вы можете расширить его для отправки переменных

cd $1; 
find -L $2 > /tmp/ligacoes; 
for i in `cat /tmp/ligacoes`; 
do cp $i /var/tmp/; 
done 

называть его, как это, где $_SESSION['path'] будет $1:

$ssh->exec('mybash.sh '.$_SESSION['path'].' '.$file[$a]); 
+0

Я создал файл bash, как вы sugested. Я могу выполнить его, но получаю те же результаты: мой PHP-скрипт останавливается. Я не получаю вывод в 'echo $ ssh-> exec ('grava1.sh');', даже первый файл, который копируется успешно. –

+0

Попробуйте просто 'echo $ ssh-> exec ('echo hello');' – WEBjuju

+0

также убедитесь, что вы приняли предупреждение man-in-the-middle, которое вы получаете, когда вы впервые подключаетесь через ssh (см. Мой новый № 3 выше) – WEBjuju