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