class WindowsPipes
WindowsPipes implementation uses temporary files as handles.
@author Romain Neutron <imprec@gmail.com>
@internal
Hierarchy
- class \Symfony\Component\Process\Pipes\AbstractPipes implements \Symfony\Component\Process\Pipes\PipesInterface
- class \Symfony\Component\Process\Pipes\WindowsPipes extends \Symfony\Component\Process\Pipes\AbstractPipes
Expanded class hierarchy of WindowsPipes
See also
1 file declares its use of WindowsPipes
- Process.php in vendor/
symfony/ process/ Process.php
File
-
vendor/
symfony/ process/ Pipes/ WindowsPipes.php, line 27
Namespace
Symfony\Component\Process\PipesView source
class WindowsPipes extends AbstractPipes {
private array $files = [];
private array $fileHandles = [];
private array $lockHandles = [];
private array $readBytes = [
Process::STDOUT => 0,
Process::STDERR => 0,
];
public function __construct(mixed $input, bool $haveReadSupport) {
if ($this->haveReadSupport) {
// 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/51800
$pipes = [
Process::STDOUT => Process::OUT,
Process::STDERR => Process::ERR,
];
$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 (!($h = fopen($file . '.lock', 'w'))) {
if (file_exists($file . '.lock')) {
continue 2;
}
restore_error_handler();
throw new RuntimeException('A temporary file could not be opened to write the process output: ' . $lastError);
}
if (!flock($h, \LOCK_EX | \LOCK_NB)) {
continue 2;
}
if (isset($this->lockHandles[$pipe])) {
flock($this->lockHandles[$pipe], \LOCK_UN);
fclose($this->lockHandles[$pipe]);
}
$this->lockHandles[$pipe] = $h;
if (!($h = fopen($file, 'w')) || !fclose($h) || !($h = fopen($file, 'r'))) {
flock($this->lockHandles[$pipe], \LOCK_UN);
fclose($this->lockHandles[$pipe]);
unset($this->lockHandles[$pipe]);
continue 2;
}
$this->fileHandles[$pipe] = $h;
$this->files[$pipe] = $file;
}
break;
}
restore_error_handler();
}
parent::__construct($input);
}
public function __sleep() : array {
throw new \BadMethodCallException('Cannot serialize ' . __CLASS__);
}
public function __wakeup() : void {
throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
}
public function __destruct() {
$this->close();
}
public function getDescriptors() : array {
if (!$this->haveReadSupport) {
$nullstream = fopen('NUL', 'c');
return [
[
'pipe',
'r',
],
$nullstream,
$nullstream,
];
}
// We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
// We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
// So we redirect output within the commandline and pass the nul device to the process
return [
[
'pipe',
'r',
],
[
'file',
'NUL',
'w',
],
[
'file',
'NUL',
'w',
],
];
}
public function getFiles() : array {
return $this->files;
}
public function readAndWrite(bool $blocking, bool $close = false) : array {
$this->unblock();
$w = $this->write();
$read = $r = $e = [];
if ($blocking) {
if ($w) {
@stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1000000.0);
}
elseif ($this->fileHandles) {
usleep((int) (Process::TIMEOUT_PRECISION * 1000000.0));
}
}
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) {
ftruncate($fileHandle, 0);
fclose($fileHandle);
flock($this->lockHandles[$type], \LOCK_UN);
fclose($this->lockHandles[$type]);
unset($this->fileHandles[$type], $this->lockHandles[$type]);
}
}
return $read;
}
public function haveReadSupport() : bool {
return $this->haveReadSupport;
}
public function areOpen() : bool {
return $this->pipes && $this->fileHandles;
}
public function close() : void {
parent::close();
foreach ($this->fileHandles as $type => $handle) {
ftruncate($handle, 0);
fclose($handle);
flock($this->lockHandles[$type], \LOCK_UN);
fclose($this->lockHandles[$type]);
}
$this->fileHandles = $this->lockHandles = [];
}
}
Members
Title Sort descending | Modifiers | Object type | Summary | Overriden Title |
---|---|---|---|---|
AbstractPipes::$blocked | private | property | ||
AbstractPipes::$input | private | property | @var resource|string|\Iterator | |
AbstractPipes::$inputBuffer | private | property | ||
AbstractPipes::$lastError | private | property | ||
AbstractPipes::$pipes | public | property | ||
AbstractPipes::handleError | public | function | @internal | |
AbstractPipes::hasSystemCallBeenInterrupted | protected | function | Returns true if a system call has been interrupted. | |
AbstractPipes::unblock | protected | function | Unblocks streams. | |
AbstractPipes::write | protected | function | Writes input to stdin. | |
PipesInterface::CHUNK_SIZE | public | constant | ||
WindowsPipes::$fileHandles | private | property | ||
WindowsPipes::$files | private | property | ||
WindowsPipes::$lockHandles | private | property | ||
WindowsPipes::$readBytes | private | property | ||
WindowsPipes::areOpen | public | function | Returns if the current state has open file handles or pipes. | Overrides PipesInterface::areOpen |
WindowsPipes::close | public | function | Closes file handles and pipes. | Overrides AbstractPipes::close |
WindowsPipes::getDescriptors | public | function | Returns an array of descriptors for the use of proc_open. | Overrides PipesInterface::getDescriptors |
WindowsPipes::getFiles | public | function | Returns an array of filenames indexed by their related stream in case these pipes use temporary files. | Overrides PipesInterface::getFiles |
WindowsPipes::haveReadSupport | public | function | Returns if pipes are able to read output. | Overrides PipesInterface::haveReadSupport |
WindowsPipes::readAndWrite | public | function | Reads data in file handles and pipes. | Overrides PipesInterface::readAndWrite |
WindowsPipes::__construct | public | function | Overrides AbstractPipes::__construct | |
WindowsPipes::__destruct | public | function | ||
WindowsPipes::__sleep | public | function | ||
WindowsPipes::__wakeup | public | function |