Security update for Core, with self-updated composer
[yaffs-website] / vendor / symfony / process / Pipes / AbstractPipes.php
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\InvalidArgumentException;
15
16 /**
17  * @author Romain Neutron <imprec@gmail.com>
18  *
19  * @internal
20  */
21 abstract class AbstractPipes implements PipesInterface
22 {
23     /** @var array */
24     public $pipes = array();
25
26     /** @var string */
27     private $inputBuffer = '';
28     /** @var resource|scalar|\Iterator|null */
29     private $input;
30     /** @var bool */
31     private $blocked = true;
32
33     public function __construct($input)
34     {
35         if (is_resource($input) || $input instanceof \Iterator) {
36             $this->input = $input;
37         } elseif (is_string($input)) {
38             $this->inputBuffer = $input;
39         } else {
40             $this->inputBuffer = (string) $input;
41         }
42     }
43
44     /**
45      * {@inheritdoc}
46      */
47     public function close()
48     {
49         foreach ($this->pipes as $pipe) {
50             fclose($pipe);
51         }
52         $this->pipes = array();
53     }
54
55     /**
56      * Returns true if a system call has been interrupted.
57      *
58      * @return bool
59      */
60     protected function hasSystemCallBeenInterrupted()
61     {
62         $lastError = error_get_last();
63
64         // stream_select returns false when the `select` system call is interrupted by an incoming signal
65         return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
66     }
67
68     /**
69      * Unblocks streams.
70      */
71     protected function unblock()
72     {
73         if (!$this->blocked) {
74             return;
75         }
76
77         foreach ($this->pipes as $pipe) {
78             stream_set_blocking($pipe, 0);
79         }
80         if (is_resource($this->input)) {
81             stream_set_blocking($this->input, 0);
82         }
83
84         $this->blocked = false;
85     }
86
87     /**
88      * Writes input to stdin.
89      *
90      * @throws InvalidArgumentException When an input iterator yields a non supported value
91      */
92     protected function write()
93     {
94         if (!isset($this->pipes[0])) {
95             return;
96         }
97         $input = $this->input;
98
99         if ($input instanceof \Iterator) {
100             if (!$input->valid()) {
101                 $input = null;
102             } elseif (is_resource($input = $input->current())) {
103                 stream_set_blocking($input, 0);
104             } elseif (!isset($this->inputBuffer[0])) {
105                 if (!is_string($input)) {
106                     if (!is_scalar($input)) {
107                         throw new InvalidArgumentException(sprintf('%s yielded a value of type "%s", but only scalars and stream resources are supported', get_class($this->input), gettype($input)));
108                     }
109                     $input = (string) $input;
110                 }
111                 $this->inputBuffer = $input;
112                 $this->input->next();
113                 $input = null;
114             } else {
115                 $input = null;
116             }
117         }
118
119         $r = $e = array();
120         $w = array($this->pipes[0]);
121
122         // let's have a look if something changed in streams
123         if (false === $n = @stream_select($r, $w, $e, 0, 0)) {
124             return;
125         }
126
127         foreach ($w as $stdin) {
128             if (isset($this->inputBuffer[0])) {
129                 $written = fwrite($stdin, $this->inputBuffer);
130                 $this->inputBuffer = substr($this->inputBuffer, $written);
131                 if (isset($this->inputBuffer[0])) {
132                     return array($this->pipes[0]);
133                 }
134             }
135
136             if ($input) {
137                 for (;;) {
138                     $data = fread($input, self::CHUNK_SIZE);
139                     if (!isset($data[0])) {
140                         break;
141                     }
142                     $written = fwrite($stdin, $data);
143                     $data = substr($data, $written);
144                     if (isset($data[0])) {
145                         $this->inputBuffer = $data;
146
147                         return array($this->pipes[0]);
148                     }
149                 }
150                 if (feof($input)) {
151                     if ($this->input instanceof \Iterator) {
152                         $this->input->next();
153                     } else {
154                         $this->input = null;
155                     }
156                 }
157             }
158         }
159
160         // no input to read on resource, buffer is empty
161         if (!isset($this->inputBuffer[0]) && !($this->input instanceof \Iterator ? $this->input->valid() : $this->input)) {
162             $this->input = null;
163             fclose($this->pipes[0]);
164             unset($this->pipes[0]);
165         } elseif (!$w) {
166             return array($this->pipes[0]);
167         }
168     }
169 }