_command = $command; $this->_pipes = []; $this->_out = new stdClass(); $this->_out->out = ''; $this->_out->err = ''; } /** * Reads from the process pipes. * * @return void */ private function _readFromPipes() { $read = [ $this->_pipes[1], $this->_pipes[2] ]; $write = null; $except = null; $n = @stream_select( $read, $write, $except, 0, 500 ); if ( $n > 0 ) { foreach ( $read as $pipe ) { while ( $data = fread( $pipe, 8092 ) ) { if ( $pipe === $this->_pipes[1] ) { $this->_out->out .= $data; } elseif ( $pipe === $this->_pipes[2] ) { $this->_out->err .= $data; } } } } } /** * Executes the command and reads the output and result code. * * @param array|null $output Reference to store command output. * @param int|null $resultCode Reference to store command result code. * * @return mixed Returns the last line of the output, or false on failure. */ public function execute( ?array &$output = null, ?int &$resultCode = null ) { $process = proc_open( $this->_command, [ 0 => [ "pipe", "r" ], 1 => [ "pipe", "w" ], 2 => [ "pipe", "w" ] ], $this->_pipes, getcwd(), [ 'PATH' => implode( ":", self::PATH ) ] ); if ( $process === false ) { $output[] = "Can't open process using `proc_open`"; $resultCode = 1; return false; } fclose( $this->_pipes[0] ); // Close stdin stream_set_blocking( $this->_pipes[1], false ); stream_set_blocking( $this->_pipes[2], false ); while ( true ) { $status = proc_get_status( $process ); if ( $status === false || $status['running'] === false ) { fclose( $this->_pipes[1] ); fclose( $this->_pipes[2] ); proc_close( $process ); if ( $status === false ) { $output[] = "Can't read status from process"; $resultCode = 1; return false; } $resultCode = $status['exitcode']; $out = trim( $this->_out->out ); if ( $resultCode && trim( $this->_out->err ) ) { $out = trim( $this->_out->err ); } $output = $out ? preg_split( "/\r?\n/", $out ) : []; break; } $this->_readFromPipes(); } return ! empty( $output ) ? end( $output ) : ''; } /** * Static method to execute a shell command. * * @param string $command Command to execute. * @param array|null $output Reference to store command output. * @param int|null $resultCode Reference to store command result code. * * @return mixed Returns the last line of the output, or false on failure. */ public static function exec( string $command, ?array &$output = null, ?int &$resultCode = null ) { $process = new self( $command ); //echo $command; return $process->execute( $output, $resultCode ); } }