2015-08-18 00:00:26 +00:00
< ? php
/*
* This file is part of the Symfony package .
*
* ( c ) Fabien Potencier < fabien @ symfony . com >
*
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
*/
namespace Symfony\Component\Process\Pipes ;
2018-11-23 12:29:20 +00:00
use Symfony\Component\Process\Exception\InvalidArgumentException ;
2015-08-18 00:00:26 +00:00
/**
* @ author Romain Neutron < imprec @ gmail . com >
*
* @ internal
*/
abstract class AbstractPipes implements PipesInterface
{
public $pipes = array ();
2017-02-03 00:28:38 +00:00
private $inputBuffer = '' ;
private $input ;
2015-08-18 00:00:26 +00:00
private $blocked = true ;
2018-11-23 12:29:20 +00:00
private $lastError ;
2015-08-18 00:00:26 +00:00
2018-11-23 12:29:20 +00:00
/**
* @ param resource | string | int | float | bool | \Iterator | null $input
*/
2016-04-20 16:56:34 +00:00
public function __construct ( $input )
{
2018-11-23 12:29:20 +00:00
if ( \is_resource ( $input ) || $input instanceof \Iterator ) {
2016-04-20 16:56:34 +00:00
$this -> input = $input ;
2018-11-23 12:29:20 +00:00
} elseif ( \is_string ( $input )) {
2016-04-20 16:56:34 +00:00
$this -> inputBuffer = $input ;
} else {
$this -> inputBuffer = ( string ) $input ;
}
}
2015-08-18 00:00:26 +00:00
/**
* { @ inheritdoc }
*/
public function close ()
{
foreach ( $this -> pipes as $pipe ) {
fclose ( $pipe );
}
$this -> pipes = array ();
}
/**
* Returns true if a system call has been interrupted .
*
* @ return bool
*/
protected function hasSystemCallBeenInterrupted ()
{
2018-11-23 12:29:20 +00:00
$lastError = $this -> lastError ;
$this -> lastError = null ;
2015-08-18 00:00:26 +00:00
// stream_select returns false when the `select` system call is interrupted by an incoming signal
2018-11-23 12:29:20 +00:00
return null !== $lastError && false !== stripos ( $lastError , 'interrupted system call' );
2015-08-18 00:00:26 +00:00
}
/**
2015-10-08 18:40:12 +00:00
* Unblocks streams .
2015-08-18 00:00:26 +00:00
*/
protected function unblock ()
{
if ( ! $this -> blocked ) {
return ;
}
foreach ( $this -> pipes as $pipe ) {
stream_set_blocking ( $pipe , 0 );
}
2018-11-23 12:29:20 +00:00
if ( \is_resource ( $this -> input )) {
2015-08-18 00:00:26 +00:00
stream_set_blocking ( $this -> input , 0 );
}
$this -> blocked = false ;
}
2016-04-20 16:56:34 +00:00
/**
* Writes input to stdin .
2018-11-23 12:29:20 +00:00
*
* @ throws InvalidArgumentException When an input iterator yields a non supported value
2016-04-20 16:56:34 +00:00
*/
protected function write ()
{
if ( ! isset ( $this -> pipes [ 0 ])) {
return ;
}
2017-02-03 00:28:38 +00:00
$input = $this -> input ;
2018-11-23 12:29:20 +00:00
if ( $input instanceof \Iterator ) {
if ( ! $input -> valid ()) {
$input = null ;
} elseif ( \is_resource ( $input = $input -> current ())) {
stream_set_blocking ( $input , 0 );
} elseif ( ! isset ( $this -> inputBuffer [ 0 ])) {
if ( ! \is_string ( $input )) {
if ( ! is_scalar ( $input )) {
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 )));
}
$input = ( string ) $input ;
}
$this -> inputBuffer = $input ;
$this -> input -> next ();
$input = null ;
} else {
$input = null ;
}
}
2017-02-03 00:28:38 +00:00
$r = $e = array ();
2016-04-20 16:56:34 +00:00
$w = array ( $this -> pipes [ 0 ]);
// let's have a look if something changed in streams
2018-11-23 12:29:20 +00:00
if ( false === @ stream_select ( $r , $w , $e , 0 , 0 )) {
2016-04-20 16:56:34 +00:00
return ;
}
foreach ( $w as $stdin ) {
if ( isset ( $this -> inputBuffer [ 0 ])) {
$written = fwrite ( $stdin , $this -> inputBuffer );
$this -> inputBuffer = substr ( $this -> inputBuffer , $written );
if ( isset ( $this -> inputBuffer [ 0 ])) {
return array ( $this -> pipes [ 0 ]);
}
}
2017-02-03 00:28:38 +00:00
if ( $input ) {
2016-04-20 16:56:34 +00:00
for (;;) {
$data = fread ( $input , self :: CHUNK_SIZE );
if ( ! isset ( $data [ 0 ])) {
break ;
}
$written = fwrite ( $stdin , $data );
$data = substr ( $data , $written );
if ( isset ( $data [ 0 ])) {
$this -> inputBuffer = $data ;
return array ( $this -> pipes [ 0 ]);
}
}
2017-02-03 00:28:38 +00:00
if ( feof ( $input )) {
2018-11-23 12:29:20 +00:00
if ( $this -> input instanceof \Iterator ) {
$this -> input -> next ();
} else {
$this -> input = null ;
}
2016-04-20 16:56:34 +00:00
}
}
}
// no input to read on resource, buffer is empty
2018-11-23 12:29:20 +00:00
if ( ! isset ( $this -> inputBuffer [ 0 ]) && ! ( $this -> input instanceof \Iterator ? $this -> input -> valid () : $this -> input )) {
$this -> input = null ;
2016-04-20 16:56:34 +00:00
fclose ( $this -> pipes [ 0 ]);
unset ( $this -> pipes [ 0 ]);
2017-02-03 00:28:38 +00:00
} elseif ( ! $w ) {
2016-04-20 16:56:34 +00:00
return array ( $this -> pipes [ 0 ]);
}
}
2018-11-23 12:29:20 +00:00
/**
* @ internal
*/
public function handleError ( $type , $msg )
{
$this -> lastError = $msg ;
}
2015-08-18 00:00:26 +00:00
}