Mercurial > hg > isophonics-drupal-site
comparison vendor/symfony/process/Pipes/WindowsPipes.php @ 0:4c8ae668cc8c
Initial import (non-working)
author | Chris Cannam |
---|---|
date | Wed, 29 Nov 2017 16:09:58 +0000 |
parents | |
children | 1fec387a4317 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:4c8ae668cc8c |
---|---|
1 <?php | |
2 | |
3 /* | |
4 * This file is part of the Symfony package. | |
5 * | |
6 * (c) Fabien Potencier <fabien@symfony.com> | |
7 * | |
8 * For the full copyright and license information, please view the LICENSE | |
9 * file that was distributed with this source code. | |
10 */ | |
11 | |
12 namespace Symfony\Component\Process\Pipes; | |
13 | |
14 use Symfony\Component\Process\Process; | |
15 use Symfony\Component\Process\Exception\RuntimeException; | |
16 | |
17 /** | |
18 * WindowsPipes implementation uses temporary files as handles. | |
19 * | |
20 * @see https://bugs.php.net/bug.php?id=51800 | |
21 * @see https://bugs.php.net/bug.php?id=65650 | |
22 * | |
23 * @author Romain Neutron <imprec@gmail.com> | |
24 * | |
25 * @internal | |
26 */ | |
27 class WindowsPipes extends AbstractPipes | |
28 { | |
29 /** @var array */ | |
30 private $files = array(); | |
31 /** @var array */ | |
32 private $fileHandles = array(); | |
33 /** @var array */ | |
34 private $readBytes = array( | |
35 Process::STDOUT => 0, | |
36 Process::STDERR => 0, | |
37 ); | |
38 /** @var bool */ | |
39 private $haveReadSupport; | |
40 | |
41 public function __construct($input, $haveReadSupport) | |
42 { | |
43 $this->haveReadSupport = (bool) $haveReadSupport; | |
44 | |
45 if ($this->haveReadSupport) { | |
46 // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big. | |
47 // Workaround for this problem is to use temporary files instead of pipes on Windows platform. | |
48 // | |
49 // @see https://bugs.php.net/bug.php?id=51800 | |
50 $pipes = array( | |
51 Process::STDOUT => Process::OUT, | |
52 Process::STDERR => Process::ERR, | |
53 ); | |
54 $tmpCheck = false; | |
55 $tmpDir = sys_get_temp_dir(); | |
56 $lastError = 'unknown reason'; | |
57 set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); | |
58 for ($i = 0;; ++$i) { | |
59 foreach ($pipes as $pipe => $name) { | |
60 $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); | |
61 if (file_exists($file) && !unlink($file)) { | |
62 continue 2; | |
63 } | |
64 $h = fopen($file, 'xb'); | |
65 if (!$h) { | |
66 $error = $lastError; | |
67 if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) { | |
68 continue; | |
69 } | |
70 restore_error_handler(); | |
71 throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error)); | |
72 } | |
73 if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) { | |
74 continue 2; | |
75 } | |
76 if (isset($this->files[$pipe])) { | |
77 unlink($this->files[$pipe]); | |
78 } | |
79 $this->files[$pipe] = $file; | |
80 } | |
81 break; | |
82 } | |
83 restore_error_handler(); | |
84 } | |
85 | |
86 parent::__construct($input); | |
87 } | |
88 | |
89 public function __destruct() | |
90 { | |
91 $this->close(); | |
92 $this->removeFiles(); | |
93 } | |
94 | |
95 /** | |
96 * {@inheritdoc} | |
97 */ | |
98 public function getDescriptors() | |
99 { | |
100 if (!$this->haveReadSupport) { | |
101 $nullstream = fopen('NUL', 'c'); | |
102 | |
103 return array( | |
104 array('pipe', 'r'), | |
105 $nullstream, | |
106 $nullstream, | |
107 ); | |
108 } | |
109 | |
110 // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800) | |
111 // We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650 | |
112 // So we redirect output within the commandline and pass the nul device to the process | |
113 return array( | |
114 array('pipe', 'r'), | |
115 array('file', 'NUL', 'w'), | |
116 array('file', 'NUL', 'w'), | |
117 ); | |
118 } | |
119 | |
120 /** | |
121 * {@inheritdoc} | |
122 */ | |
123 public function getFiles() | |
124 { | |
125 return $this->files; | |
126 } | |
127 | |
128 /** | |
129 * {@inheritdoc} | |
130 */ | |
131 public function readAndWrite($blocking, $close = false) | |
132 { | |
133 $this->unblock(); | |
134 $w = $this->write(); | |
135 $read = $r = $e = array(); | |
136 | |
137 if ($blocking) { | |
138 if ($w) { | |
139 @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); | |
140 } elseif ($this->fileHandles) { | |
141 usleep(Process::TIMEOUT_PRECISION * 1E6); | |
142 } | |
143 } | |
144 foreach ($this->fileHandles as $type => $fileHandle) { | |
145 $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]); | |
146 | |
147 if (isset($data[0])) { | |
148 $this->readBytes[$type] += strlen($data); | |
149 $read[$type] = $data; | |
150 } | |
151 if ($close) { | |
152 fclose($fileHandle); | |
153 unset($this->fileHandles[$type]); | |
154 } | |
155 } | |
156 | |
157 return $read; | |
158 } | |
159 | |
160 /** | |
161 * {@inheritdoc} | |
162 */ | |
163 public function haveReadSupport() | |
164 { | |
165 return $this->haveReadSupport; | |
166 } | |
167 | |
168 /** | |
169 * {@inheritdoc} | |
170 */ | |
171 public function areOpen() | |
172 { | |
173 return $this->pipes && $this->fileHandles; | |
174 } | |
175 | |
176 /** | |
177 * {@inheritdoc} | |
178 */ | |
179 public function close() | |
180 { | |
181 parent::close(); | |
182 foreach ($this->fileHandles as $handle) { | |
183 fclose($handle); | |
184 } | |
185 $this->fileHandles = array(); | |
186 } | |
187 | |
188 /** | |
189 * Removes temporary files. | |
190 */ | |
191 private function removeFiles() | |
192 { | |
193 foreach ($this->files as $filename) { | |
194 if (file_exists($filename)) { | |
195 @unlink($filename); | |
196 } | |
197 } | |
198 $this->files = array(); | |
199 } | |
200 } |