2012-02-27 21 views
6

php istnieje kilka sposobów wykonania polecenia powłoki:Wykonanie program php - wyświetlacz i zwróci wyniku

  • system()
  • posredni()
  • shell_exec()
  • exec ()

Pierwsze dwa wyświetla dane wyjściowe, ale ich nie zwraca. Ostatnie dwa zwraca dane wyjściowe, ale ich nie wyświetla.

Chcę uruchomić polecenie powłoki, które wymaga dużo czasu, ale wyświetla niektóre wyniki, więc wiem, że nie zawiesić. Jednak na końcu chcę przetworzyć to wyjście w php. Jeśli wybiorę jedną z pierwszych dwóch, nie otrzymam danych wyjściowych, więc nie będę mógł ich przetworzyć w php. Jeśli uruchomię jedną z dwóch ostatnich, będę w stanie przetworzyć dane wyjściowe, ale mój program zawiesi się bardzo długo, bez wysyłania czegokolwiek.

Czy istnieje sposób uruchomienia polecenia powłoki, które natychmiast wyświetli wynik i zwróci go?

+0

Czy drugi argument do systemu() call nie pomoże? – KTastrophy

+0

Drugi argument to status powrotu wykonanej komendy, np. 0, jeśli wszystko było w porządku, a 1, jeśli wystąpił błąd. Powinienem wspomnieć, że też tego potrzebuję - shell_exec() to taki, który tego nie obsługuje. –

+0

Nie sądzę, że istnieje jakieś polecenie PHP, które wykona kod powłoki i wydrukuje dane wyjściowe na ekranie przed zakończeniem wykonywania. – Travesty3

Odpowiedz

2

Może ten będzie Cię interesuje? proc_open() - http://www.php.net/manual/en/function.proc-open.php

I tu jest przydatny fragment, który może pracować dla Ciebie (nie jest to skopiowane z uwagami na stronie dałem Ci link do niego):

<?php 
/* 
* Execute and display the output in real time (stdout + stderr). 
* 
* Please note this snippet is prepended with an appropriate shebang for the 
* CLI. You can re-use only the function. 
* 
* Usage example: 
* chmod u+x proc_open.php 
* ./proc_open.php "ping -c 5 google.fr"; echo RetVal=$? 
*/ 
define(BUF_SIZ, 1024);  # max buffer size 
define(FD_WRITE, 0);  # stdin 
define(FD_READ, 1);  # stdout 
define(FD_ERR, 2);  # stderr 

/* 
* Wrapper for proc_*() functions. 
* The first parameter $cmd is the command line to execute. 
* Return the exit code of the process. 
*/ 
function proc_exec($cmd) 
{ 
    $descriptorspec = array(
     0 => array("pipe", "r"), 
     1 => array("pipe", "w"), 
     2 => array("pipe", "w") 
    ); 

    $ptr = proc_open($cmd, $descriptorspec, $pipes, NULL, $_ENV); 
    if (!is_resource($ptr)) 
     return false; 

    while (($buffer = fgets($pipes[FD_READ], BUF_SIZ)) != NULL 
      || ($errbuf = fgets($pipes[FD_ERR], BUF_SIZ)) != NULL) { 
     if (!isset($flag)) { 
      $pstatus = proc_get_status($ptr); 
      $first_exitcode = $pstatus["exitcode"]; 
      $flag = true; 
     } 
     if (strlen($buffer)) 
      echo $buffer; 
     if (strlen($errbuf)) 
      echo "ERR: " . $errbuf; 
    } 

    foreach ($pipes as $pipe) 
     fclose($pipe); 

    /* Get the expected *exit* code to return the value */ 
    $pstatus = proc_get_status($ptr); 
    if (!strlen($pstatus["exitcode"]) || $pstatus["running"]) { 
     /* we can trust the retval of proc_close() */ 
     if ($pstatus["running"]) 
      proc_terminate($ptr); 
     $ret = proc_close($ptr); 
    } else { 
     if ((($first_exitcode + 256) % 256) == 255 
       && (($pstatus["exitcode"] + 256) % 256) != 255) 
      $ret = $pstatus["exitcode"]; 
     elseif (!strlen($first_exitcode)) 
      $ret = $pstatus["exitcode"]; 
     elseif ((($first_exitcode + 256) % 256) != 255) 
      $ret = $first_exitcode; 
     else 
      $ret = 0; /* we "deduce" an EXIT_SUCCESS ;) */ 
     proc_close($ptr); 
    } 

    return ($ret + 256) % 256; 
} 

/* __init__ */ 
if (isset($argv) && count($argv) > 1 && !empty($argv[1])) { 
    if (($ret = proc_exec($argv[1])) === false) 
     die("Error: not enough FD or out of memory.\n"); 
    elseif ($ret == 127) 
     die("Command not found (returned by sh).\n"); 
    else 
     exit($ret); 
} 
?> 
+0

Dzięki! Nie ma sposobu, bym kiedykolwiek wydedukował, jak uzyskać kod statusu powrotu :) –

+0

Nie ma sprawy, Kamil. :) – Pateman

2

Być może używać popen(), który wykonuje program i odczytuje jego wyjście poprzez plik uchwytem, ​​tak:

$handle = popen('/bin/ls', 'r'); 
while ($line = fread($handle, 100)){ 
    echo $line; 
} 
pclose($handle); 
+0

Dzięki! To zadziała, ale zapomniałem wspomnieć, że potrzebuję również zwrócić status wykonanego polecenia, więc prawdopodobnie proc_open (który jest podobny) pozwoli mi to zrobić - i tak dziękuję! –

+0

Nie ma za co. Cieszę się, że to rozwiązałeś! – elias