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 ;
use Symfony\Component\Process\Process ;
use Symfony\Component\Process\Exception\RuntimeException ;
/**
* WindowsPipes implementation uses temporary files as handles .
*
* @ see https :// bugs . php . net / bug . php ? id = 51800
* @ see https :// bugs . php . net / bug . php ? id = 65650
*
* @ author Romain Neutron < imprec @ gmail . com >
*
* @ internal
*/
class WindowsPipes extends AbstractPipes
{
/** @var array */
private $files = array ();
/** @var array */
private $fileHandles = array ();
/** @var array */
private $readBytes = array (
Process :: STDOUT => 0 ,
Process :: STDERR => 0 ,
);
/** @var bool */
private $disableOutput ;
public function __construct ( $disableOutput , $input )
{
$this -> disableOutput = ( bool ) $disableOutput ;
if ( ! $this -> disableOutput ) {
// 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/bug.php?id=51800
$this -> files = array (
2015-11-17 21:42:33 +00:00
Process :: STDOUT => tempnam ( sys_get_temp_dir (), 'out_sf_proc' ),
Process :: STDERR => tempnam ( sys_get_temp_dir (), 'err_sf_proc' ),
2015-08-18 00:00:26 +00:00
);
foreach ( $this -> files as $offset => $file ) {
2016-04-20 16:56:34 +00:00
if ( false === $file || false === $this -> fileHandles [ $offset ] = @ fopen ( $file , 'rb' )) {
2015-08-18 00:00:26 +00:00
throw new RuntimeException ( 'A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable' );
}
}
}
2016-04-20 16:56:34 +00:00
parent :: __construct ( $input );
2015-08-18 00:00:26 +00:00
}
public function __destruct ()
{
$this -> close ();
$this -> removeFiles ();
}
/**
* { @ inheritdoc }
*/
public function getDescriptors ()
{
if ( $this -> disableOutput ) {
$nullstream = fopen ( 'NUL' , 'c' );
return array (
array ( 'pipe' , 'r' ),
$nullstream ,
$nullstream ,
);
}
// We're not using pipe on Windows platform as it hangs (https://bugs.php.net/bug.php?id=51800)
// We're not using file handles as it can produce corrupted output https://bugs.php.net/bug.php?id=65650
// So we redirect output within the commandline and pass the nul device to the process
return array (
array ( 'pipe' , 'r' ),
array ( 'file' , 'NUL' , 'w' ),
array ( 'file' , 'NUL' , 'w' ),
);
}
/**
* { @ inheritdoc }
*/
public function getFiles ()
{
return $this -> files ;
}
/**
* { @ inheritdoc }
*/
public function readAndWrite ( $blocking , $close = false )
{
2016-04-20 16:56:34 +00:00
$this -> unblock ();
$w = $this -> write ();
$read = $r = $e = array ();
if ( $blocking ) {
if ( $w ) {
@ stream_select ( $r , $w , $e , 0 , Process :: TIMEOUT_PRECISION * 1E6 );
} elseif ( $this -> fileHandles ) {
usleep ( Process :: TIMEOUT_PRECISION * 1E6 );
2015-08-18 00:00:26 +00:00
}
2016-04-20 16:56:34 +00:00
}
foreach ( $this -> fileHandles as $type => $fileHandle ) {
$data = stream_get_contents ( $fileHandle , - 1 , $this -> readBytes [ $type ]);
if ( isset ( $data [ 0 ])) {
$this -> readBytes [ $type ] += strlen ( $data );
2015-08-18 00:00:26 +00:00
$read [ $type ] = $data ;
}
2016-04-20 16:56:34 +00:00
if ( $close ) {
fclose ( $fileHandle );
2015-08-18 00:00:26 +00:00
unset ( $this -> fileHandles [ $type ]);
}
}
return $read ;
}
/**
* { @ inheritdoc }
*/
public function areOpen ()
{
2016-04-20 16:56:34 +00:00
return $this -> pipes && $this -> fileHandles ;
2015-08-18 00:00:26 +00:00
}
/**
* { @ inheritdoc }
*/
public function close ()
{
parent :: close ();
foreach ( $this -> fileHandles as $handle ) {
fclose ( $handle );
}
$this -> fileHandles = array ();
}
/**
* Creates a new WindowsPipes instance .
*
* @ param Process $process The process
* @ param $input
*
* @ return WindowsPipes
*/
public static function create ( Process $process , $input )
{
return new static ( $process -> isOutputDisabled (), $input );
}
/**
2015-10-08 18:40:12 +00:00
* Removes temporary files .
2015-08-18 00:00:26 +00:00
*/
private function removeFiles ()
{
foreach ( $this -> files as $filename ) {
if ( file_exists ( $filename )) {
@ unlink ( $filename );
}
}
$this -> files = array ();
}
}