Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 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\Exception\RuntimeException;
15
use Symfony\Component\Process\Process;
16
 
17
/**
18
 * WindowsPipes implementation uses temporary files as handles.
19
 *
20
 * @see https://bugs.php.net/51800
21
 * @see https://bugs.php.net/65650
22
 *
23
 * @author Romain Neutron <imprec@gmail.com>
24
 *
25
 * @internal
26
 */
27
class WindowsPipes extends AbstractPipes
28
{
29
    private $files = [];
30
    private $fileHandles = [];
31
    private $lockHandles = [];
32
    private $readBytes = [
33
        Process::STDOUT => 0,
34
        Process::STDERR => 0,
35
    ];
36
    private $haveReadSupport;
37
 
38
    public function __construct(mixed $input, bool $haveReadSupport)
39
    {
40
        $this->haveReadSupport = $haveReadSupport;
41
 
42
        if ($this->haveReadSupport) {
43
            // Fix for PHP bug #51800: reading from STDOUT pipe hangs forever on Windows if the output is too big.
44
            // Workaround for this problem is to use temporary files instead of pipes on Windows platform.
45
            //
46
            // @see https://bugs.php.net/51800
47
            $pipes = [
48
                Process::STDOUT => Process::OUT,
49
                Process::STDERR => Process::ERR,
50
            ];
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
 
58
                    if (!$h = fopen($file.'.lock', 'w')) {
59
                        if (file_exists($file.'.lock')) {
60
                            continue 2;
61
                        }
62
                        restore_error_handler();
63
                        throw new RuntimeException('A temporary file could not be opened to write the process output: '.$lastError);
64
                    }
65
                    if (!flock($h, \LOCK_EX | \LOCK_NB)) {
66
                        continue 2;
67
                    }
68
                    if (isset($this->lockHandles[$pipe])) {
69
                        flock($this->lockHandles[$pipe], \LOCK_UN);
70
                        fclose($this->lockHandles[$pipe]);
71
                    }
72
                    $this->lockHandles[$pipe] = $h;
73
 
74
                    if (!($h = fopen($file, 'w')) || !fclose($h) || !$h = fopen($file, 'r')) {
75
                        flock($this->lockHandles[$pipe], \LOCK_UN);
76
                        fclose($this->lockHandles[$pipe]);
77
                        unset($this->lockHandles[$pipe]);
78
                        continue 2;
79
                    }
80
                    $this->fileHandles[$pipe] = $h;
81
                    $this->files[$pipe] = $file;
82
                }
83
                break;
84
            }
85
            restore_error_handler();
86
        }
87
 
88
        parent::__construct($input);
89
    }
90
 
91
    public function __sleep(): array
92
    {
93
        throw new \BadMethodCallException('Cannot serialize '.__CLASS__);
94
    }
95
 
96
    public function __wakeup()
97
    {
98
        throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
99
    }
100
 
101
    public function __destruct()
102
    {
103
        $this->close();
104
    }
105
 
106
    public function getDescriptors(): array
107
    {
108
        if (!$this->haveReadSupport) {
109
            $nullstream = fopen('NUL', 'c');
110
 
111
            return [
112
                ['pipe', 'r'],
113
                $nullstream,
114
                $nullstream,
115
            ];
116
        }
117
 
118
        // We're not using pipe on Windows platform as it hangs (https://bugs.php.net/51800)
119
        // We're not using file handles as it can produce corrupted output https://bugs.php.net/65650
120
        // So we redirect output within the commandline and pass the nul device to the process
121
        return [
122
            ['pipe', 'r'],
123
            ['file', 'NUL', 'w'],
124
            ['file', 'NUL', 'w'],
125
        ];
126
    }
127
 
128
    public function getFiles(): array
129
    {
130
        return $this->files;
131
    }
132
 
133
    public function readAndWrite(bool $blocking, bool $close = false): array
134
    {
135
        $this->unblock();
136
        $w = $this->write();
137
        $read = $r = $e = [];
138
 
139
        if ($blocking) {
140
            if ($w) {
141
                @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6);
142
            } elseif ($this->fileHandles) {
143
                usleep(Process::TIMEOUT_PRECISION * 1E6);
144
            }
145
        }
146
        foreach ($this->fileHandles as $type => $fileHandle) {
147
            $data = stream_get_contents($fileHandle, -1, $this->readBytes[$type]);
148
 
149
            if (isset($data[0])) {
150
                $this->readBytes[$type] += \strlen($data);
151
                $read[$type] = $data;
152
            }
153
            if ($close) {
154
                ftruncate($fileHandle, 0);
155
                fclose($fileHandle);
156
                flock($this->lockHandles[$type], \LOCK_UN);
157
                fclose($this->lockHandles[$type]);
158
                unset($this->fileHandles[$type], $this->lockHandles[$type]);
159
            }
160
        }
161
 
162
        return $read;
163
    }
164
 
165
    public function haveReadSupport(): bool
166
    {
167
        return $this->haveReadSupport;
168
    }
169
 
170
    public function areOpen(): bool
171
    {
172
        return $this->pipes && $this->fileHandles;
173
    }
174
 
175
    public function close()
176
    {
177
        parent::close();
178
        foreach ($this->fileHandles as $type => $handle) {
179
            ftruncate($handle, 0);
180
            fclose($handle);
181
            flock($this->lockHandles[$type], \LOCK_UN);
182
            fclose($this->lockHandles[$type]);
183
        }
184
        $this->fileHandles = $this->lockHandles = [];
185
    }
186
}