add ExecCmd and Tempdir
[pharext/pharext] / src / pharext / ExecCmd.php
diff --git a/src/pharext/ExecCmd.php b/src/pharext/ExecCmd.php
new file mode 100644 (file)
index 0000000..056f0b2
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+
+namespace pharext;
+
+class ExecCmd
+{
+       /**
+        * Sudo command, if the cmd needs escalated privileges
+        * @var string
+        */
+       private $sudo;
+       
+       /**
+        * Executable of the cmd
+        * @var string
+        */
+       private $command;
+       
+       /**
+        * Passthrough cmd output
+        * @var bool
+        */
+       private $verbose;
+       
+       /**
+        * Output of cmd run
+        * @var string
+        */
+       private $output;
+       
+       /**
+        * Return code of cmd run
+        * @var int
+        */
+       private $status;
+
+       /**
+        * @param string $command
+        * @param bool verbose
+        */
+       public function __construct($command, $verbose = false) {
+               $this->command = $command;
+               $this->verbose = $verbose;
+               
+               /* interrupt output stream */
+               if ($verbose) {
+                       printf("\n");
+               }
+       }
+       
+       /**
+        * (Re-)set sudo command
+        * @param string $sudo
+        */
+       public function setSu($sudo = false) {
+               $this->sudo = $sudo;
+       }
+       
+       /**
+        * Execute a program with escalated privileges handling interactive password prompt
+        * @param string $command
+        * @param string $output
+        * @param int $status
+        */
+       private function suExec($command, &$output, &$status) {
+               if (!($proc = proc_open($command, [STDIN,["pipe","w"],["pipe","w"]], $pipes))) {
+                       $status = -1;
+                       throw new \Exception("Failed to run {$command}");
+               }
+               $stdout = $pipes[1];
+               $passwd = 0;
+               while (!feof($stdout)) {
+                       $R = [$stdout]; $W = []; $E = [];
+                       if (!stream_select($R, $W, $E, null)) {
+                               continue;
+                       }
+                       $data = fread($stdout, 0x1000);
+                       /* only check a few times */
+                       if ($passwd++ < 10) {
+                               if (stristr($data, "password")) {
+                                       printf("\n%s", $data);
+                               }
+                       }
+                       $output .= $data;
+               }
+               $status = proc_close($proc);
+       }
+
+       /**
+        * Run the command
+        * @param array $args
+        * @throws \Exception
+        */
+       public function run(array $args = null) {
+               $exec = escapeshellcmd($this->command);
+               if ($args) {
+                       $exec .= " ". implode(" ", array_map("escapeshellarg", (array) $args));
+               }
+               
+               if ($this->sudo) {
+                       $this->suExec(sprintf($this->sudo." 2>&1", $exec), $this->output, $this->status);
+               } elseif ($this->verbose) {
+                       ob_start(function($s) {
+                               $this->output .= $s;
+                               return $s;
+                       }, 1);
+                       passthru($exec, $this->status);
+                       ob_end_flush();
+               } else {
+                       exec($exec ." 2>&1", $output, $this->status);
+                       $this->output = implode("\n", $output);
+               }
+               
+               if ($this->status) {
+                       throw new \Exception("Command {$this->command} failed ({$this->status})");
+               }
+       }
+       
+       /**
+        * Retrieve exit code of cmd run
+        * @return int
+        */
+       public function getStatus() {
+               return $status;
+       }
+       
+       /**
+        * Retrieve output of cmd run
+        * @return string
+        */
+       public function getOutput() {
+               return $this->output;
+       }
+}