Version 1
[yaffs-website] / vendor / symfony / process / Pipes / WindowsPipes.php
diff --git a/vendor/symfony/process/Pipes/WindowsPipes.php b/vendor/symfony/process/Pipes/WindowsPipes.php
new file mode 100644 (file)
index 0000000..87a781e
--- /dev/null
@@ -0,0 +1,205 @@
+<?php
+
+/*
+ * This file is part of the Symfony package.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Process\Pipes;
+
+use Symfony\Component\Process\Process;
+use Symfony\Component\Process\Exception\RuntimeException;
+
+/**
+ * WindowsPipes implementation uses temporary files as handles.
+ *
+ * @see https://bugs.php.net/bug.php?id=51800
+ * @see https://bugs.php.net/bug.php?id=65650
+ *
+ * @author Romain Neutron <imprec@gmail.com>
+ *
+ * @internal
+ */
+class WindowsPipes extends AbstractPipes
+{
+    /** @var array */
+    private $files = array();
+    /** @var array */
+    private $fileHandles = array();
+    /** @var array */
+    private $readBytes = array(
+        Process::STDOUT => 0,
+        Process::STDERR => 0,
+    );
+    /** @var bool */
+    private $disableOutput;
+
+    public function __construct($disableOutput, $input)
+    {
+        $this->disableOutput = (bool) $disableOutput;
+
+        if (!$this->disableOutput) {
+            // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
+            // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
+            //
+            // @see https://bugs.php.net/bug.php?id=51800
+            $pipes = array(
+                Process::STDOUT => Process::OUT,
+                Process::STDERR => Process::ERR,
+            );
+            $tmpCheck = false;
+            $tmpDir = sys_get_temp_dir();
+            $lastError = 'unknown reason';
+            set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; });
+            for ($i = 0;; ++$i) {
+                foreach ($pipes as $pipe => $name) {
+                    $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
+                    if (file_exists($file) && !unlink($file)) {
+                        continue 2;
+                    }
+                    $h = fopen($file, 'xb');
+                    if (!$h) {
+                        $error = $lastError;
+                        if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) {
+                            continue;
+                        }
+                        restore_error_handler();
+                        throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error));
+                    }
+                    if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) {
+                        continue 2;
+                    }
+                    if (isset($this->files[$pipe])) {
+                        unlink($this->files[$pipe]);
+                    }
+                    $this->files[$pipe] = $file;
+                }
+                break;
+            }
+            restore_error_handler();
+        }
+
+        parent::__construct($input);
+    }
+
+    public function __destruct()
+    {
+        $this->close();
+        $this->removeFiles();
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getDescriptors()
+    {
+        if ($this->disableOutput) {
+            $nullstream = fopen('NUL', 'c');
+
+            return array(
+                array('pipe', 'r'),
+                $nullstream,
+                $nullstream,
+            );
+        }
+
+        // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
+        // We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
+        // So we redirect output within the commandline and pass the nul device to the process
+        return array(
+            array('pipe', 'r'),
+            array('file', 'NUL', 'w'),
+            array('file', 'NUL', 'w'),
+        );
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getFiles()
+    {
+        return $this->files;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function readAndWrite($blocking, $close = false)
+    {
+        $this->unblock();
+        $w = $this->write();
+        $read = $r = $e = array();
+
+        if ($blocking) {
+            if ($w) {
+                @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
+            } elseif ($this->fileHandles) {
+                usleep(Process::TIMEOUT_PRECISION * 1E6);
+            }
+        }
+        foreach ($this->fileHandles as $type => $fileHandle) {
+            $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
+
+            if (isset($data[0])) {
+                $this->readBytes[$type] += strlen($data);
+                $read[$type] = $data;
+            }
+            if ($close) {
+                fclose($fileHandle);
+                unset($this->fileHandles[$type]);
+            }
+        }
+
+        return $read;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function areOpen()
+    {
+        return $this->pipes && $this->fileHandles;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function close()
+    {
+        parent::close();
+        foreach ($this->fileHandles as $handle) {
+            fclose($handle);
+        }
+        $this->fileHandles = array();
+    }
+
+    /**
+     * Creates a new WindowsPipes instance.
+     *
+     * @param Process $process The process
+     * @param $input
+     *
+     * @return static
+     */
+    public static function create(Process $process, $input)
+    {
+        return new static($process->isOutputDisabled(), $input);
+    }
+
+    /**
+     * Removes temporary files.
+     */
+    private function removeFiles()
+    {
+        foreach ($this->files as $filename) {
+            if (file_exists($filename)) {
+                @unlink($filename);
+            }
+        }
+        $this->files = array();
+    }
+}