Merge branch '2.4' into 2.5

* 2.4:
  [HttpKernel] added an analyze of environment parameters for built-in server.
  change command to which available under most unix systems
  add way to test command under windows
  fix shell command injection
  [Form] allowed CallbackTransformer to use callable
  [Process] Added process synchronization to the incremental output tests
This commit is contained in:
Fabien Potencier 2014-08-08 17:50:54 +02:00
commit 5ca28c0d71
6 changed files with 89 additions and 19 deletions

View File

@ -25,6 +25,7 @@ if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'
return false; return false;
} }
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app_dev.php'; $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app_dev.php';
require 'app_dev.php'; require 'app_dev.php';

View File

@ -25,6 +25,7 @@ if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'
return false; return false;
} }
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app.php'; $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.'app.php';
require 'app.php'; require 'app.php';

View File

@ -50,17 +50,19 @@ class Shell
*/ */
public function testCommand($command) public function testCommand($command)
{ {
if (self::TYPE_WINDOWS === $this->type) {
// todo: find a way to test if Windows command exists
return false;
}
if (!function_exists('exec')) { if (!function_exists('exec')) {
return false; return false;
} }
// todo: find a better way (command could not be available) // todo: find a better way (command could not be available)
exec('command -v '.$command, $output, $code); $testCommand = 'which ';
if (self::TYPE_WINDOWS === $this->type) {
$testCommand = 'where ';
}
$command = escapeshellcmd($command);
exec($testCommand.$command, $output, $code);
return 0 === $code && count($output) > 0; return 0 === $code && count($output) > 0;
} }

View File

@ -18,24 +18,33 @@ class CallbackTransformer implements DataTransformerInterface
{ {
/** /**
* The callback used for forward transform * The callback used for forward transform
* @var \Closure * @var callable
*/ */
private $transform; private $transform;
/** /**
* The callback used for reverse transform * The callback used for reverse transform
* @var \Closure * @var callable
*/ */
private $reverseTransform; private $reverseTransform;
/** /**
* Constructor. * Constructor.
* *
* @param \Closure $transform The forward transform callback * @param callable $transform The forward transform callback
* @param \Closure $reverseTransform The reverse transform callback * @param callable $reverseTransform The reverse transform callback
*
* @throws \InvalidArgumentException when the given callbacks is invalid
*/ */
public function __construct(\Closure $transform, \Closure $reverseTransform) public function __construct($transform, $reverseTransform)
{ {
if (!is_callable($transform)) {
throw new \InvalidArgumentException('Argument 1 should be a callable');
}
if (!is_callable($reverseTransform)) {
throw new \InvalidArgumentException('Argument 2 should be a callable');
}
$this->transform = $transform; $this->transform = $transform;
$this->reverseTransform = $reverseTransform; $this->reverseTransform = $reverseTransform;
} }
@ -47,7 +56,7 @@ class CallbackTransformer implements DataTransformerInterface
* *
* @return mixed The value in the transformed representation * @return mixed The value in the transformed representation
* *
* @throws UnexpectedTypeException when the argument is not a string * @throws UnexpectedTypeException when the argument is not of the expected type
* @throws TransformationFailedException when the transformation fails * @throws TransformationFailedException when the transformation fails
*/ */
public function transform($data) public function transform($data)

View File

@ -0,0 +1,37 @@
<?php
namespace Symfony\Component\Form\Tests;
use Symfony\Component\Form\CallbackTransformer;
class CallbackTransformerTest extends \PHPUnit_Framework_TestCase
{
public function testTransform()
{
$transformer = new CallbackTransformer(
function($value) { return $value.' has been transformed'; },
function($value) { return $value.' has reversely been transformed'; }
);
$this->assertEquals('foo has been transformed', $transformer->transform('foo'));
$this->assertEquals('bar has reversely been transformed', $transformer->reverseTransform('bar'));
}
/**
* @dataProvider invalidCallbacksProvider
*
* @expectedException \InvalidArgumentException
*/
public function testConstructorWithInvalidCallbacks($transformCallback, $reverseTransformCallback)
{
new CallbackTransformer($transformCallback, $reverseTransformCallback);
}
public function invalidCallbacksProvider()
{
return array(
array( null, function(){} ),
array( function(){}, null ),
);
}
}

View File

@ -260,13 +260,23 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testGetIncrementalErrorOutput() public function testGetIncrementalErrorOutput()
{ {
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { usleep(100000); file_put_contents(\'php://stderr\', \'ERROR\'); $n++; }'))); // use a lock file to toggle between writing ("W") and reading ("R") the
// error stream
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
file_put_contents($lock, 'W');
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { file_put_contents(\'php://stderr\', \'ERROR\'); $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
$p->start(); $p->start();
while ($p->isRunning()) { while ($p->isRunning()) {
$this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalErrorOutput(), $matches)); if ('R' === file_get_contents($lock)) {
usleep(20000); $this->assertLessThanOrEqual(1, preg_match_all('/ERROR/', $p->getIncrementalErrorOutput(), $matches));
file_put_contents($lock, 'W');
}
usleep(100);
} }
unlink($lock);
} }
public function testFlushErrorOutput() public function testFlushErrorOutput()
@ -280,7 +290,7 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testGetOutput() public function testGetOutput()
{ {
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) {echo \' foo \';$n++; usleep(500); }'))); $p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { echo \' foo \'; $n++; }')));
$p->run(); $p->run();
$this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches)); $this->assertEquals(3, preg_match_all('/foo/', $p->getOutput(), $matches));
@ -288,13 +298,23 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
public function testGetIncrementalOutput() public function testGetIncrementalOutput()
{ {
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n=0;while ($n<3) { echo \' foo \'; usleep(50000); $n++; }'))); // use a lock file to toggle between writing ("W") and reading ("R") the
// output stream
$lock = tempnam(sys_get_temp_dir(), get_class($this).'Lock');
file_put_contents($lock, 'W');
$p = $this->getProcess(sprintf('php -r %s', escapeshellarg('$n = 0; while ($n < 3) { if (\'W\' === file_get_contents('.var_export($lock, true).')) { echo \' foo \'; $n++; file_put_contents('.var_export($lock, true).', \'R\'); } usleep(100); }')));
$p->start(); $p->start();
while ($p->isRunning()) { while ($p->isRunning()) {
$this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches)); if ('R' === file_get_contents($lock)) {
usleep(20000); $this->assertLessThanOrEqual(1, preg_match_all('/foo/', $p->getIncrementalOutput(), $matches));
file_put_contents($lock, 'W');
}
usleep(100);
} }
unlink($lock);
} }
public function testFlushOutput() public function testFlushOutput()