Merge branch '3.3' into 3.4

* 3.3:
  Add application/ld+json format associated to json
  [HttpFoundation] Fix false-positive ConflictingHeadersException
  [WebServerBundle] Fix escaping of php binary with arguments
  Error handlers' $context should be optional as it's deprecated
  [Serializer] Correct typing mistake in DocBlock
  [Config] Fix closure CS
  PHP CS Fixer: use PHPUnit Migration ruleset
  Update MemcachedTrait.php
  [Bridge/PhpUnit] thank phpunit/phpunit
  [Process] Fix setting empty env vars
  [Process] Dont use getenv(), it returns arrays and can introduce subtle breaks accros PHP versions
  [WebServerBundle] fix a bug where require would not require the good file because of env
  [Console] Commands with an alias should not be recognized as ambiguous
This commit is contained in:
Nicolas Grekas 2017-12-29 21:55:26 +01:00
commit cc027a261f
20 changed files with 111 additions and 25 deletions

View File

@ -8,9 +8,10 @@ return PhpCsFixer\Config::create()
->setRules(array(
'@Symfony' => true,
'@Symfony:risky' => true,
'@PHPUnit48Migration:risky' => true,
'php_unit_no_expectation_annotation' => false, // part of `PHPUnitXYMigration:risky` ruleset, to be enabled when PHPUnit 4.x support will be dropped, as we don't want to rewrite exceptions handling twice
'array_syntax' => array('syntax' => 'long'),
'protected_to_private' => false,
'php_unit_dedicate_assert' => array('target' => '3.5'),
))
->setRiskyAllowed(true)
->setFinder(

View File

@ -41,6 +41,10 @@
"extra": {
"branch-alias": {
"dev-master": "3.4-dev"
},
"thanks": {
"name": "phpunit/phpunit",
"url": "https://github.com/sebastianbergmann/phpunit"
}
}
}

View File

@ -30,7 +30,7 @@ if (is_file($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$_SERVER['SCRIPT_NAME'
return false;
}
$script = getenv('APP_FRONT_CONTROLLER') ?: 'index.php';
$script = isset($_ENV['APP_FRONT_CONTROLLER']) ? $_ENV['APP_FRONT_CONTROLLER'] : 'index.php';
$_SERVER = array_merge($_SERVER, $_ENV);
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR.$script;

View File

@ -146,11 +146,11 @@ class WebServer
private function createServerProcess(WebServerConfig $config)
{
$finder = new PhpExecutableFinder();
if (false === $binary = $finder->find()) {
if (false === $binary = $finder->find(false)) {
throw new \RuntimeException('Unable to find the PHP binary.');
}
$process = new Process(array($binary, '-S', $config->getAddress(), $config->getRouter()));
$process = new Process(array_merge(array($binary), $finder->findArguments(), array('-dvariables_order=EGPCS', '-S', $config->getAddress(), $config->getRouter())));
$process->setWorkingDirectory($config->getDocumentRoot());
$process->setTimeout(null);

View File

@ -32,7 +32,7 @@ class WebServerConfig
throw new \InvalidArgumentException(sprintf('Unable to find the front controller under "%s" (none of these files exist: %s).', $documentRoot, implode(', ', $this->getFrontControllerFileNames($env))));
}
putenv('APP_FRONT_CONTROLLER='.$file);
$_ENV['APP_FRONT_CONTROLLER'] = $file;
$this->documentRoot = $documentRoot;
$this->env = $env;

View File

@ -21,7 +21,7 @@
"symfony/console": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/http-kernel": "~3.3|~4.0",
"symfony/process": "~3.3|~4.0"
"symfony/process": "~3.3.14|^3.4.2|^4.0.2"
},
"autoload": {
"psr-4": { "Symfony\\Bundle\\WebServerBundle\\": "" },

View File

@ -71,7 +71,7 @@ trait MemcachedTrait
*
* @return \Memcached
*
* @throws \ErrorEception When invalid options or servers are provided
* @throws \ErrorException When invalid options or servers are provided
*/
public static function createConnection($servers, array $options = array())
{

View File

@ -186,7 +186,7 @@ class ExprBuilder
*/
public function thenInvalid($message)
{
$this->thenPart = function ($v) use ($message) {throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
$this->thenPart = function ($v) use ($message) { throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
return $this;
}

View File

@ -158,7 +158,7 @@ class ResourceCheckerConfigCache implements ConfigCacheInterface
$meta = false;
$signalingException = new \UnexpectedValueException();
$prevUnserializeHandler = ini_set('unserialize_callback_func', '');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context) use (&$prevErrorHandler, $signalingException) {
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) use (&$prevErrorHandler, $signalingException) {
if (E_WARNING === $type && 'Class __PHP_Incomplete_Class has no unserializer' === $msg) {
throw $signalingException;
}

View File

@ -580,6 +580,7 @@ class Application
{
$this->init();
$aliases = array();
$allCommands = $this->commandLoader ? array_merge($this->commandLoader->getNames(), array_keys($this->commands)) : array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);
@ -612,14 +613,15 @@ class Application
// filter out aliases for commands which are already on the list
if (count($commands) > 1) {
$commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands;
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands) {
$commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) {
$commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias;
$aliases[$nameOrAlias] = $commandName;
return $commandName === $nameOrAlias || !in_array($commandName, $commands);
}));
}
$exact = in_array($name, $commands, true);
$exact = in_array($name, $commands, true) || isset($aliases[$name]);
if (count($commands) > 1 && !$exact) {
$usableWidth = $this->terminal->getWidth() - 10;
$abbrevs = array_values($commands);

View File

@ -57,6 +57,8 @@ class ApplicationTest extends TestCase
require_once self::$fixturesPath.'/BarBucCommand.php';
require_once self::$fixturesPath.'/FooSubnamespaced1Command.php';
require_once self::$fixturesPath.'/FooSubnamespaced2Command.php';
require_once self::$fixturesPath.'/TestTiti.php';
require_once self::$fixturesPath.'/TestToto.php';
}
protected function normalizeLineBreaks($text)
@ -283,6 +285,14 @@ class ApplicationTest extends TestCase
$application->findNamespace('f');
}
public function testFindNonAmbiguous()
{
$application = new Application();
$application->add(new \TestTiti());
$application->add(new \TestToto());
$this->assertEquals('test-toto', $application->find('test')->getName());
}
/**
* @expectedException \Symfony\Component\Console\Exception\CommandNotFoundException
* @expectedExceptionMessage There are no commands defined in the "bar" namespace.

View File

@ -0,0 +1,21 @@
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class TestTiti extends Command
{
protected function configure()
{
$this
->setName('test-titi')
->setDescription('The test:titi command')
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->write('test-titi');
}
}

View File

@ -0,0 +1,22 @@
<?php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class TestToto extends Command
{
protected function configure()
{
$this
->setName('test-toto')
->setDescription('The test-toto command')
->setAliases(array('test'))
;
}
protected function execute(InputInterface $input, OutputInterface $output)
{
$output->write('test-toto');
}
}

View File

@ -1990,6 +1990,7 @@ class Request
'js' => array('application/javascript', 'application/x-javascript', 'text/javascript'),
'css' => array('text/css'),
'json' => array('application/json', 'application/x-json'),
'jsonld' => array('application/ld+json'),
'xml' => array('text/xml', 'application/xml', 'application/x-xml'),
'rdf' => array('application/rdf+xml'),
'atom' => array('application/atom+xml'),

View File

@ -372,6 +372,7 @@ class RequestTest extends TestCase
array('js', array('application/javascript', 'application/x-javascript', 'text/javascript')),
array('css', array('text/css')),
array('json', array('application/json', 'application/x-json')),
array('jsonld', array('application/ld+json')),
array('xml', array('text/xml', 'application/xml', 'application/x-xml')),
array('rdf', array('application/rdf+xml')),
array('atom', array('application/atom+xml')),
@ -968,6 +969,26 @@ class RequestTest extends TestCase
$request->getClientIps();
}
/**
* @dataProvider getClientIpsWithConflictingHeadersProvider
*/
public function testGetClientIpsOnlyXHttpForwardedForTrusted($httpForwarded, $httpXForwardedFor)
{
$request = new Request();
$server = array(
'REMOTE_ADDR' => '88.88.88.88',
'HTTP_FORWARDED' => $httpForwarded,
'HTTP_X_FORWARDED_FOR' => $httpXForwardedFor,
);
Request::setTrustedProxies(array('88.88.88.88'), Request::HEADER_X_FORWARDED_FOR);
$request->initialize(array(), array(), array(), array(), array(), $server);
$this->assertSame(array_reverse(explode(',', $httpXForwardedFor)), $request->getClientIps());
}
public function getClientIpsWithConflictingHeadersProvider()
{
// $httpForwarded $httpXForwardedFor

View File

@ -326,12 +326,20 @@ class Process implements \IteratorAggregate
// @see : https://bugs.php.net/69442
$ptsWorkaround = fopen(__FILE__, 'r');
}
if (defined('HHVM_VERSION')) {
$envPairs = $env;
} else {
$envPairs = array();
foreach ($env as $k => $v) {
$envPairs[] = $k.'='.$v;
}
}
if (!is_dir($this->cwd)) {
@trigger_error('The provided cwd does not exist. Command is currently ran against getcwd(). This behavior is deprecated since version 3.4 and will be removed in 4.0.', E_USER_DEPRECATED);
}
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $env, $this->options);
$this->process = proc_open($commandline, $descriptors, $this->processPipes->pipes, $this->cwd, $envPairs, $this->options);
if (!is_resource($this->process)) {
throw new RuntimeException('Unable to launch a new process.');
@ -1722,15 +1730,11 @@ class Process implements \IteratorAggregate
private function getDefaultEnv()
{
if (\PHP_VERSION_ID >= 70100) {
$env = getenv();
} else {
$env = array();
$env = array();
foreach ($_SERVER as $k => $v) {
if (is_string($v) && false !== $v = getenv($k)) {
$env[$k] = $v;
}
foreach ($_SERVER as $k => $v) {
if (is_string($v) && false !== $v = getenv($k)) {
$env[$k] = $v;
}
}

View File

@ -1441,14 +1441,14 @@ class ProcessTest extends TestCase
public function testEnvIsInherited()
{
$process = $this->getProcessForCode('echo serialize($_SERVER);', null, array('BAR' => 'BAZ'));
$process = $this->getProcessForCode('echo serialize($_SERVER);', null, array('BAR' => 'BAZ', 'EMPTY' => ''));
putenv('FOO=BAR');
$_ENV['FOO'] = 'BAR';
$process->run();
$expected = array('BAR' => 'BAZ', 'FOO' => 'BAR');
$expected = array('BAR' => 'BAZ', 'EMPTY' => '', 'FOO' => 'BAR');
$env = array_intersect_key(unserialize($process->getOutput()), $expected);
$this->assertEquals($expected, $env);

View File

@ -245,7 +245,7 @@ class PropertyAccessor implements PropertyAccessorInterface
/**
* @internal
*/
public static function handleError($type, $message, $file, $line, $context)
public static function handleError($type, $message, $file, $line, $context = array())
{
if (E_RECOVERABLE_ERROR === $type) {
self::throwInvalidArgumentException($message, debug_backtrace(false), 1);

View File

@ -57,7 +57,7 @@ class CustomNormalizer implements NormalizerInterface, DenormalizerInterface, Se
}
/**
* Checks if the given class implements the NormalizableInterface.
* Checks if the given class implements the DenormalizableInterface.
*
* @param mixed $data Data to denormalize from
* @param string $type The class to which the data should be denormalized

View File

@ -212,7 +212,7 @@ abstract class AbstractCloner implements ClonerInterface
*/
public function cloneVar($var, $filter = 0)
{
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context) {
$this->prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = array()) {
if (E_RECOVERABLE_ERROR === $type || E_USER_ERROR === $type) {
// Cloner never dies
throw new \ErrorException($msg, 0, $type, $file, $line);