ILIAS  release_5-2 Revision v5.2.25-18-g3f80b828510
WindowsPipes.php
Go to the documentation of this file.
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
13
16
28{
30 private $files = array();
32 private $fileHandles = array();
34 private $readBytes = array(
35 Process::STDOUT => 0,
36 Process::STDERR => 0,
37 );
40
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(
53 );
54 $tmpDir = sys_get_temp_dir();
55 $error = 'unknown reason';
56 set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
57 for ($i = 0;; ++$i) {
58 foreach ($pipes as $pipe => $name) {
59 $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name);
60 if (file_exists($file) && !unlink($file)) {
61 continue 2;
62 }
63 $h = fopen($file, 'xb');
64 if (!$h && false === strpos($error, 'File exists')) {
65 restore_error_handler();
66 throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error));
67 }
68 if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) {
69 continue 2;
70 }
71 if (isset($this->files[$pipe])) {
72 unlink($this->files[$pipe]);
73 }
74 $this->files[$pipe] = $file;
75 }
76 break;
77 }
78 restore_error_handler();
79 }
80
81 parent::__construct($input);
82 }
83
84 public function __destruct()
85 {
86 $this->close();
87 $this->removeFiles();
88 }
89
93 public function getDescriptors()
94 {
95 if (!$this->haveReadSupport) {
96 $nullstream = fopen('NUL', 'c');
97
98 return array(
99 array('pipe', 'r'),
100 $nullstream,
101 $nullstream,
102 );
103 }
104
105 // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
106 // We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
107 // So we redirect output within the commandline and pass the nul device to the process
108 return array(
109 array('pipe', 'r'),
110 array('file', 'NUL', 'w'),
111 array('file', 'NUL', 'w'),
112 );
113 }
114
118 public function getFiles()
119 {
120 return $this->files;
121 }
122
126 public function readAndWrite($blocking, $close = false)
127 {
128 $this->unblock();
129 $w = $this->write();
130 $read = $r = $e = array();
131
132 if ($blocking) {
133 if ($w) {
134 @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
135 } elseif ($this->fileHandles) {
136 usleep(Process::TIMEOUT_PRECISION * 1E6);
137 }
138 }
139 foreach ($this->fileHandles as $type => $fileHandle) {
140 $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
141
142 if (isset($data[0])) {
143 $this->readBytes[$type] += strlen($data);
144 $read[$type] = $data;
145 }
146 if ($close) {
147 fclose($fileHandle);
148 unset($this->fileHandles[$type]);
149 }
150 }
151
152 return $read;
153 }
154
158 public function haveReadSupport()
159 {
161 }
162
166 public function areOpen()
167 {
168 return $this->pipes && $this->fileHandles;
169 }
170
174 public function close()
175 {
176 parent::close();
177 foreach ($this->fileHandles as $handle) {
178 fclose($handle);
179 }
180 $this->fileHandles = array();
181 }
182
186 private function removeFiles()
187 {
188 foreach ($this->files as $filename) {
189 if (file_exists($filename)) {
190 @unlink($filename);
191 }
192 }
193 $this->files = array();
194 }
195}
sprintf('%.4f', $callTime)
$error
Definition: Error.php:17
An exception for terminatinating execution or to throw for unit testing.
RuntimeException for the Process Component.
WindowsPipes implementation uses temporary files as handles.
haveReadSupport()
{Returns if pipes are able to read output.bool}
areOpen()
{Returns if the current state has open file handles or pipes.bool}
getFiles()
{Returns an array of filenames indexed by their related stream in case these pipes use temporary file...
readAndWrite($blocking, $close=false)
{Reads data in file handles and pipes.string[] An array of read data indexed by their fd}
getDescriptors()
{Returns an array of descriptors for the use of proc_open.array}
close()
{{Closes file handles and pipes.}}
Process is a thin wrapper around proc_* functions to easily start independent PHP processes.
Definition: Process.php:31
$h
$w
$r
Definition: example_031.php:79
if(!file_exists("$old.txt")) if( $old===$new) if(file_exists("$new.txt")) $file