2017-08-18 1 views
0

J'ai téléchargé un émulateur de terminal open-source de github et je l'ai modifié un peu. La classe pour l'exécution d'un processus ressemble à ceci:PHP Script se bloque lors du passage d'un paramètre à traiter

<?php 

class CProcess { 
    const PROC_OK = true; 
    const PROC_FAILED = false; 

    private static $instance = null; 

    public static function factory() { 
     if (!isset(self::$instance)) { 
      self::$instance = new CProcess(); 
     } 
     return self::$instance; 
    } 

    private $pipes; 
    private $process; 
    private $stdinref; 
    private $stdoutref; 
    private $stderref; 

    private function __construct() { 

    } 

    public function __destruct() { 
     return $this->close(); 
    } 

    public function open($command) { 
     $spec = array(
      array("pty"), // STDIN 
      array("pty"), // STDOUT 
      array("pty") // STDERR 
     ); 

     if (!$this->process = proc_open($command, $spec, $this->pipes)) { 
      return self::PROC_FAILED; 
     } 
     $this->stdinref = &$this->pipes[0]; 
     $this->stdoutref = &$this->pipes[1]; 
     $this->stderref = &$this->pipes[2]; 

     $this->setBlocking(0); 
     return self::PROC_OK; 
    } 

    public function isResource() { 
     return is_resource($this->process); 
    } 

    public function setBlocking($blocking = 1) { 
     return stream_set_blocking($this->stdoutref, $blocking); 
    } 

    public function getStatus() { 
     return proc_get_status($this->process); 
    } 

    public function get() { 
     $out = stream_get_contents($this->stdoutref); 
     return $out; 
    } 

    public function put($data) { 
     fwrite($this->stdinref, $data . "\n"); 
     sleep(1); 
     fflush($this->stdinref); 
    } 

    public function close() { 
     if (is_resource($this->process)) { 
      fclose($this->stdinref); 
      fclose($this->stdoutref); 
      fclose($this->stderref); 
      return proc_close($this->process); 
     } 
    } 

    public function metaData() { 
     return stream_get_meta_data($this->stdoutref); 
    } 

} 

Maintenant, je veux authentifier une paire login/mot de passe en utilisant la méthode suivante:

public static function autenticate($login, $password) { 
     if (true === DEBUG_MODE) { 
      error_log("authenticate(): login={$login} password={$password}",0); 
     } 
     error_log("test"); 
     self::$username = $login; 
     $process = CProcess::factory(); 
     $cmd = "su " . escapeshellarg($login); 
     if (true === DEBUG_MODE) { 
      error_log("authenticate(): cmd={$cmd}", 0); 
     } 

     $rc = $process->open($cmd); 
     usleep(100000); // 500000 
     if ($rc === CProcess::PROC_FAILED) { 
      if (true === DEBUG_MODE) { 
       error_log("authenticate(): process_open() returns {$rc}", 0); 
      } 

      return false; 
     } 
     if (true === DEBUG_MODE) { 
      error_log("authenticate(): invoking process->put() with param={$password}"); 
     } 

     $process->put($password); 
     if (true === DEBUG_MODE) { 
      error_log("authenticate(): process->put() returned its value"); 
     } 

     usleep(100000); 
     return (bool) !$process->close(); 
    } 

Le problème est que le script se bloque lorsque entrer dans $process->put($password); . Mon navigateur affiche simplement 'Waiting for localhost' et ça dure pour toujours. Dans la méthode put(); de la classe CProcess j'ai également essayé PHP_EOL au lieu de \n mais le résultat était le même. Quel est le problème avec ce code?

+0

Êtes-vous sûr que le VARIABLES 'spec' de $ est corect dans votre fonction ouverte? Le document PHP de [proc_open] (http://php.net/manual/en/function.proc-open.php) indique que le second élément est soit r pour passer l'extrémité de lecture du tube au processus, soit pour passer la fin d'écriture »et vous n'avez pas du tout utilisé un second élément, je ne pense pas que ce soit optionnel ici! – xander

+0

Oui, j'ai présenté le tableau '$ spec' tel qu'il est écrit dans mes notes de cours. –

Répondre

0

Les tubes votre devrait être plus à l'aide comme, avec lecture/options de type d'écriture ...

$spec = array(
    0 => array("pipe", "r"), 
    1 => array("pipe", "w"), 
    2 => array("file", "/tmp/error-output.log", "a")); 
+0

Cette version de '$ spec' fait en sorte que la boîte de dialogue de connexion réapparaît constamment. Je me souviens clairement que mon prof utilisait 'pty' à ses cours. Je veux dire, je suis dans mes notes de cours. –

+0

Mais avez-vous regardé le document officiel [PHP doc] (http://php.net/manual/fr/function.proc-open.php)? Chez 'descriptorspec', il est clairement indiqué que vous ne pouvez utiliser que" pipe "ou" file "et quel que soit" pty ", je ne suis pas sûr que' proc_open' supporte les pipes nommés. – xander

+0

Vous pouvez remplacer le stderr par 'array (" pipe "," w ")', cela dépend de ce que vous faites avec. –