PluginProbe
ManageWP Worker / 4.9.25
ManageWP Worker v4.9.25
4.9.38 4.9.37 4.9.36 4.9.35 4.9.34 3.8.7 3.8.8 3.9.0 3.9.1 3.9.10 3.9.11 3.9.12 3.9.13 3.9.14 3.9.15 3.9.16 3.9.17 3.9.18 3.9.19 3.9.2 3.9.20 3.9.21 3.9.22 3.9.23 3.9.24 All 73 releases
worker / src / Symfony / Process / Pipes / WindowsPipes.php

WindowsPipes.php in ManageWP Worker 4.9.25, at src/Symfony/Process/Pipes/WindowsPipes.php

250 lines 7.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 /**
13 * WindowsPipes implementation uses temporary files as handles.
14 *
15 * @see https://bugs.php.net/bug.php?id=51800
16 * @see https://bugs.php.net/bug.php?id=65650
17 *
18 * @author Romain Neutron <imprec@gmail.com>
19 *
20 * @internal
21 */
22 class Symfony_Process_Pipes_WindowsPipes extends Symfony_Process_Pipes_AbstractPipes
23 {
24 /** @var array */
25 private $files = array();
26 /** @var array */
27 private $fileHandles = array();
28 /** @var array */
29 private $readBytes = array(
30 Symfony_Process_Process::STDOUT => 0,
31 Symfony_Process_Process::STDERR => 0,
32 );
33 /** @var bool */
34 private $disableOutput;
35
36 public function __construct($disableOutput, $input)
37 {
38 $this->disableOutput = (bool) $disableOutput;
39
40 if (!$this->disableOutput) {
41 // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
42 // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
43 //
44 // @see https://bugs.php.net/bug.php?id=51800
45 $this->files = array(
46 Symfony_Process_Process::STDOUT => tempnam(sys_get_temp_dir(), 'sf_proc_stdout'),
47 Symfony_Process_Process::STDERR => tempnam(sys_get_temp_dir(), 'sf_proc_stderr'),
48 );
49 foreach ($this->files as $offset => $file) {
50 $this->fileHandles[$offset] = fopen($this->files[$offset], 'rb');
51 if (false === $this->fileHandles[$offset]) {
52 throw new Symfony_Process_Exception_RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable');
53 }
54 }
55 }
56
57 if (is_resource($input)) {
58 $this->input = $input;
59 } else {
60 $this->inputBuffer = $input;
61 }
62 }
63
64 public function __destruct()
65 {
66 $this->close();
67 $this->removeFiles();
68 }
69
70 /**
71 * {@inheritdoc}
72 */
73 public function getDescriptors()
74 {
75 if ($this->disableOutput) {
76 $nullstream = fopen('NUL', 'c');
77
78 return array(
79 array('pipe', 'r'),
80 $nullstream,
81 $nullstream,
82 );
83 }
84
85 // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
86 // We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
87 // So we redirect output within the commandline and pass the nul device to the process
88 return array(
89 array('pipe', 'r'),
90 array('file', 'NUL', 'w'),
91 array('file', 'NUL', 'w'),
92 );
93 }
94
95 /**
96 * {@inheritdoc}
97 */
98 public function getFiles()
99 {
100 return $this->files;
101 }
102
103 /**
104 * {@inheritdoc}
105 */
106 public function readAndWrite($blocking, $close = false)
107 {
108 $this->write($blocking, $close);
109
110 $read = array();
111 $fh = $this->fileHandles;
112 foreach ($fh as $type => $fileHandle) {
113 if (0 !== fseek($fileHandle, $this->readBytes[$type])) {
114 continue;
115 }
116 $data = '';
117 $dataread = null;
118 while (!feof($fileHandle)) {
119 if (false !== $dataread = fread($fileHandle, self::CHUNK_SIZE)) {
120 $data .= $dataread;
121 }
122 }
123 if (0 < $length = strlen($data)) {
124 $this->readBytes[$type] += $length;
125 $read[$type] = $data;
126 }
127
128 if (false === $dataread || (true === $close && feof($fileHandle) && '' === $data)) {
129 fclose($this->fileHandles[$type]);
130 unset($this->fileHandles[$type]);
131 }
132 }
133
134 return $read;
135 }
136
137 /**
138 * {@inheritdoc}
139 */
140 public function areOpen()
141 {
142 return (bool) $this->pipes && (bool) $this->fileHandles;
143 }
144
145 /**
146 * {@inheritdoc}
147 */
148 public function close()
149 {
150 parent::close();
151 foreach ($this->fileHandles as $handle) {
152 fclose($handle);
153 }
154 $this->fileHandles = array();
155 }
156
157 /**
158 * Creates a new WindowsPipes instance.
159 *
160 * @param Symfony_Process_Process $process The process
161 * @param $input
162 *
163 * @return Symfony_Process_Pipes_WindowsPipes
164 */
165 public static function create(Symfony_Process_Process $process, $input)
166 {
167 return new self($process->isOutputDisabled(), $input);
168 }
169
170 /**
171 * Removes temporary files
172 */
173 private function removeFiles()
174 {
175 foreach ($this->files as $filename) {
176 if (file_exists($filename)) {
177 @unlink($filename);
178 }
179 }
180 $this->files = array();
181 }
182
183 /**
184 * Writes input to stdin
185 *
186 * @param bool $blocking
187 * @param bool $close
188 */
189 private function write($blocking, $close)
190 {
191 if (empty($this->pipes)) {
192 return;
193 }
194
195 $this->unblock();
196
197 $r = null !== $this->input ? array('input' => $this->input) : null;
198 $w = isset($this->pipes[0]) ? array($this->pipes[0]) : null;
199 $e = null;
200
201 // let's have a look if something changed in streams
202 if (false === $n = @stream_select($r, $w, $e, 0, $blocking ? Symfony_Process_Process::TIMEOUT_PRECISION * 1E6 : 0)) {
203 // if a system call has been interrupted, forget about it, let's try again
204 // otherwise, an error occurred, let's reset pipes
205 if (!$this->hasSystemCallBeenInterrupted()) {
206 $this->pipes = array();
207 }
208
209 return;
210 }
211
212 // nothing has changed
213 if (0 === $n) {
214 return;
215 }
216
217 if (null !== $w && 0 < count($r)) {
218 $data = '';
219 while ($dataread = fread($r['input'], self::CHUNK_SIZE)) {
220 $data .= $dataread;
221 }
222
223 $this->inputBuffer .= $data;
224
225 if (false === $data || (true === $close && feof($r['input']) && '' === $data)) {
226 // no more data to read on input resource
227 // use an empty buffer in the next reads
228 $this->input = null;
229 }
230 }
231
232 if (null !== $w && 0 < count($w)) {
233 while (strlen($this->inputBuffer)) {
234 $written = fwrite($w[0], $this->inputBuffer, 2 << 18);
235 if ($written > 0) {
236 $this->inputBuffer = (string) substr($this->inputBuffer, $written);
237 } else {
238 break;
239 }
240 }
241 }
242
243 // no input to read on resource, buffer is empty and stdin still open
244 if ('' === $this->inputBuffer && null === $this->input && isset($this->pipes[0])) {
245 fclose($this->pipes[0]);
246 unset($this->pipes[0]);
247 }
248 }
249 }
250