Merge branch '3.4' into 4.0
* 3.4: fix merge [Security] Fix logout Cleanup 2 tests for the HttpException classes #27250 limiting GET_LOCK key up to 64 char due to changes in MySQL 5.7.5 and later [Config] Fix tests when path contains UTF chars [DI] Shared services should not be inlined in non-shared ones [Profiler] Remove propel & event_listener_loading category identifiers [Filesystem] Fix usages of error_get_last() [Cache][Lock] Fix usages of error_get_last() [Debug] Fix populating error_get_last() for handled silent errors [DI] Display previous error messages when throwing unused bindings Suppress warnings when open_basedir is non-empty
This commit is contained in:
commit
8c430fbeb2
@ -184,14 +184,15 @@ class SecurityExtension extends Extension
|
||||
|
||||
$configId = 'security.firewall.map.config.'.$name;
|
||||
|
||||
list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
|
||||
list($matcher, $listeners, $exceptionListener, $logoutListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId);
|
||||
|
||||
$contextId = 'security.firewall.map.context.'.$name;
|
||||
$context = $container->setDefinition($contextId, new ChildDefinition('security.firewall.context'));
|
||||
$context
|
||||
->replaceArgument(0, new IteratorArgument($listeners))
|
||||
->replaceArgument(1, $exceptionListener)
|
||||
->replaceArgument(2, new Reference($configId))
|
||||
->replaceArgument(2, $logoutListener)
|
||||
->replaceArgument(3, new Reference($configId))
|
||||
;
|
||||
|
||||
$contextRefs[$contextId] = new Reference($contextId);
|
||||
@ -237,7 +238,7 @@ class SecurityExtension extends Extension
|
||||
|
||||
// Security disabled?
|
||||
if (false === $firewall['security']) {
|
||||
return array($matcher, array(), null);
|
||||
return array($matcher, array(), null, null);
|
||||
}
|
||||
|
||||
$config->replaceArgument(4, $firewall['stateless']);
|
||||
@ -276,16 +277,15 @@ class SecurityExtension extends Extension
|
||||
$config->replaceArgument(6, $contextKey);
|
||||
|
||||
// Logout listener
|
||||
$logoutListenerId = null;
|
||||
if (isset($firewall['logout'])) {
|
||||
$listenerKeys[] = 'logout';
|
||||
$listenerId = 'security.logout_listener.'.$id;
|
||||
$listener = $container->setDefinition($listenerId, new ChildDefinition('security.logout_listener'));
|
||||
$listener->replaceArgument(3, array(
|
||||
$logoutListenerId = 'security.logout_listener.'.$id;
|
||||
$logoutListener = $container->setDefinition($logoutListenerId, new ChildDefinition('security.logout_listener'));
|
||||
$logoutListener->replaceArgument(3, array(
|
||||
'csrf_parameter' => $firewall['logout']['csrf_parameter'],
|
||||
'csrf_token_id' => $firewall['logout']['csrf_token_id'],
|
||||
'logout_path' => $firewall['logout']['path'],
|
||||
));
|
||||
$listeners[] = new Reference($listenerId);
|
||||
|
||||
// add logout success handler
|
||||
if (isset($firewall['logout']['success_handler'])) {
|
||||
@ -295,16 +295,16 @@ class SecurityExtension extends Extension
|
||||
$logoutSuccessHandler = $container->setDefinition($logoutSuccessHandlerId, new ChildDefinition('security.logout.success_handler'));
|
||||
$logoutSuccessHandler->replaceArgument(1, $firewall['logout']['target']);
|
||||
}
|
||||
$listener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
||||
$logoutListener->replaceArgument(2, new Reference($logoutSuccessHandlerId));
|
||||
|
||||
// add CSRF provider
|
||||
if (isset($firewall['logout']['csrf_token_generator'])) {
|
||||
$listener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
|
||||
$logoutListener->addArgument(new Reference($firewall['logout']['csrf_token_generator']));
|
||||
}
|
||||
|
||||
// add session logout handler
|
||||
if (true === $firewall['logout']['invalidate_session'] && false === $firewall['stateless']) {
|
||||
$listener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference('security.logout.handler.session')));
|
||||
}
|
||||
|
||||
// add cookie logout handler
|
||||
@ -313,12 +313,12 @@ class SecurityExtension extends Extension
|
||||
$cookieHandler = $container->setDefinition($cookieHandlerId, new ChildDefinition('security.logout.handler.cookie_clearing'));
|
||||
$cookieHandler->addArgument($firewall['logout']['delete_cookies']);
|
||||
|
||||
$listener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference($cookieHandlerId)));
|
||||
}
|
||||
|
||||
// add custom handlers
|
||||
foreach ($firewall['logout']['handlers'] as $handlerId) {
|
||||
$listener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
||||
$logoutListener->addMethodCall('addHandler', array(new Reference($handlerId)));
|
||||
}
|
||||
|
||||
// register with LogoutUrlGenerator
|
||||
@ -378,7 +378,7 @@ class SecurityExtension extends Extension
|
||||
$config->replaceArgument(10, $listenerKeys);
|
||||
$config->replaceArgument(11, isset($firewall['switch_user']) ? $firewall['switch_user'] : null);
|
||||
|
||||
return array($matcher, $listeners, $exceptionListener);
|
||||
return array($matcher, $listeners, $exceptionListener, null !== $logoutListenerId ? new Reference($logoutListenerId) : null);
|
||||
}
|
||||
|
||||
private function createContextListener($container, $contextKey)
|
||||
|
@ -138,6 +138,7 @@
|
||||
<service id="security.firewall.context" class="Symfony\Bundle\SecurityBundle\Security\FirewallContext" abstract="true">
|
||||
<argument type="collection" />
|
||||
<argument type="service" id="security.exception_listener" />
|
||||
<argument /> <!-- LogoutListener -->
|
||||
<argument /> <!-- FirewallConfig -->
|
||||
</service>
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Bundle\SecurityBundle\Security;
|
||||
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
/**
|
||||
* This is a wrapper around the actual firewall configuration which allows us
|
||||
@ -23,13 +24,24 @@ class FirewallContext
|
||||
{
|
||||
private $listeners;
|
||||
private $exceptionListener;
|
||||
private $logoutListener;
|
||||
private $config;
|
||||
|
||||
public function __construct(iterable $listeners, ExceptionListener $exceptionListener = null, FirewallConfig $config = null)
|
||||
/**
|
||||
* @param LogoutListener|null $logoutListener
|
||||
*/
|
||||
public function __construct(iterable $listeners, ExceptionListener $exceptionListener = null, $logoutListener = null, FirewallConfig $config = null)
|
||||
{
|
||||
$this->listeners = $listeners;
|
||||
$this->exceptionListener = $exceptionListener;
|
||||
$this->config = $config;
|
||||
if ($logoutListener instanceof FirewallConfig) {
|
||||
$this->config = $logoutListener;
|
||||
} elseif (null === $logoutListener || $logoutListener instanceof LogoutListener) {
|
||||
$this->logoutListener = $logoutListener;
|
||||
$this->config = $config;
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Argument 3 passed to %s() must be instance of %s or null, %s given.', __METHOD__, LogoutListener::class, is_object($logoutListener) ? get_class($logoutListener) : gettype($logoutListener)));
|
||||
}
|
||||
}
|
||||
|
||||
public function getConfig()
|
||||
@ -46,4 +58,9 @@ class FirewallContext
|
||||
{
|
||||
return $this->exceptionListener;
|
||||
}
|
||||
|
||||
public function getLogoutListener()
|
||||
{
|
||||
return $this->logoutListener;
|
||||
}
|
||||
}
|
||||
|
@ -40,10 +40,10 @@ class FirewallMap implements FirewallMapInterface
|
||||
$context = $this->getFirewallContext($request);
|
||||
|
||||
if (null === $context) {
|
||||
return array(array(), null);
|
||||
return array(array(), null, null);
|
||||
}
|
||||
|
||||
return array($context->getListeners(), $context->getExceptionListener());
|
||||
return array($context->getListeners(), $context->getExceptionListener(), $context->getLogoutListener());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ abstract class CompleteConfigurationTest extends TestCase
|
||||
$arguments = $contextDef->getArguments();
|
||||
$listeners[] = array_map('strval', $arguments['index_0']->getValues());
|
||||
|
||||
$configDef = $container->getDefinition((string) $arguments['index_2']);
|
||||
$configDef = $container->getDefinition((string) $arguments['index_3']);
|
||||
$configs[] = array_values($configDef->getArguments());
|
||||
}
|
||||
|
||||
@ -99,7 +99,6 @@ abstract class CompleteConfigurationTest extends TestCase
|
||||
null,
|
||||
null,
|
||||
array(
|
||||
'logout',
|
||||
'switch_user',
|
||||
'x509',
|
||||
'remote_user',
|
||||
@ -171,7 +170,6 @@ abstract class CompleteConfigurationTest extends TestCase
|
||||
array(),
|
||||
array(
|
||||
'security.channel_listener',
|
||||
'security.logout_listener.secure',
|
||||
'security.authentication.listener.x509.secure',
|
||||
'security.authentication.listener.remote_user.secure',
|
||||
'security.authentication.listener.form.secure',
|
||||
|
@ -0,0 +1,34 @@
|
||||
<?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\Bundle\SecurityBundle\Tests\Functional;
|
||||
|
||||
class LogoutTest extends WebTestCase
|
||||
{
|
||||
public function testSessionLessRememberMeLogout()
|
||||
{
|
||||
$client = $this->createClient(array('test_case' => 'RememberMeLogout', 'root_config' => 'config.yml'));
|
||||
|
||||
$client->request('POST', '/login', array(
|
||||
'_username' => 'johannes',
|
||||
'_password' => 'test',
|
||||
));
|
||||
|
||||
$cookieJar = $client->getCookieJar();
|
||||
$cookieJar->expire(session_name());
|
||||
|
||||
$this->assertNotNull($cookieJar->get('REMEMBERME'));
|
||||
|
||||
$client->request('GET', '/logout');
|
||||
|
||||
$this->assertNull($cookieJar->get('REMEMBERME'));
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
<?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.
|
||||
*/
|
||||
|
||||
use Symfony\Bundle\SecurityBundle\SecurityBundle;
|
||||
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
|
||||
|
||||
return array(
|
||||
new FrameworkBundle(),
|
||||
new SecurityBundle(),
|
||||
);
|
@ -0,0 +1,25 @@
|
||||
imports:
|
||||
- { resource: ./../config/framework.yml }
|
||||
|
||||
security:
|
||||
encoders:
|
||||
Symfony\Component\Security\Core\User\User: plaintext
|
||||
|
||||
providers:
|
||||
in_memory:
|
||||
memory:
|
||||
users:
|
||||
johannes: { password: test, roles: [ROLE_USER] }
|
||||
|
||||
firewalls:
|
||||
default:
|
||||
form_login:
|
||||
check_path: login
|
||||
remember_me: true
|
||||
require_previous_session: false
|
||||
remember_me:
|
||||
always_remember_me: true
|
||||
secret: key
|
||||
logout: ~
|
||||
anonymous: ~
|
||||
stateless: true
|
@ -0,0 +1,5 @@
|
||||
login:
|
||||
path: /login
|
||||
|
||||
logout:
|
||||
path: /logout
|
@ -16,6 +16,7 @@ use Symfony\Bundle\SecurityBundle\Security\FirewallConfig;
|
||||
use Symfony\Bundle\SecurityBundle\Security\FirewallContext;
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
class FirewallContextTest extends TestCase
|
||||
{
|
||||
@ -23,6 +24,7 @@ class FirewallContextTest extends TestCase
|
||||
{
|
||||
$config = new FirewallConfig('main', 'user_checker', 'request_matcher');
|
||||
$exceptionListener = $this->getExceptionListenerMock();
|
||||
$logoutListener = $this->getLogoutListenerMock();
|
||||
$listeners = array(
|
||||
$this
|
||||
->getMockBuilder(ListenerInterface::class)
|
||||
@ -30,10 +32,11 @@ class FirewallContextTest extends TestCase
|
||||
->getMock(),
|
||||
);
|
||||
|
||||
$context = new FirewallContext($listeners, $exceptionListener, $config);
|
||||
$context = new FirewallContext($listeners, $exceptionListener, $logoutListener, $config);
|
||||
|
||||
$this->assertEquals($listeners, $context->getListeners());
|
||||
$this->assertEquals($exceptionListener, $context->getExceptionListener());
|
||||
$this->assertEquals($logoutListener, $context->getLogoutListener());
|
||||
$this->assertEquals($config, $context->getConfig());
|
||||
}
|
||||
|
||||
@ -44,4 +47,12 @@ class FirewallContextTest extends TestCase
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
|
||||
private function getLogoutListenerMock()
|
||||
{
|
||||
return $this
|
||||
->getMockBuilder(LogoutListener::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
class FirewallMapTest extends TestCase
|
||||
{
|
||||
@ -35,7 +36,7 @@ class FirewallMapTest extends TestCase
|
||||
|
||||
$firewallMap = new FirewallMap($container, $map);
|
||||
|
||||
$this->assertEquals(array(array(), null), $firewallMap->getListeners($request));
|
||||
$this->assertEquals(array(array(), null, null), $firewallMap->getListeners($request));
|
||||
$this->assertNull($firewallMap->getFirewallConfig($request));
|
||||
$this->assertFalse($request->attributes->has(self::ATTRIBUTE_FIREWALL_CONTEXT));
|
||||
}
|
||||
@ -51,7 +52,7 @@ class FirewallMapTest extends TestCase
|
||||
|
||||
$firewallMap = new FirewallMap($container, $map);
|
||||
|
||||
$this->assertEquals(array(array(), null), $firewallMap->getListeners($request));
|
||||
$this->assertEquals(array(array(), null, null), $firewallMap->getListeners($request));
|
||||
$this->assertNull($firewallMap->getFirewallConfig($request));
|
||||
$this->assertFalse($request->attributes->has(self::ATTRIBUTE_FIREWALL_CONTEXT));
|
||||
}
|
||||
@ -71,6 +72,9 @@ class FirewallMapTest extends TestCase
|
||||
$exceptionListener = $this->getMockBuilder(ExceptionListener::class)->disableOriginalConstructor()->getMock();
|
||||
$firewallContext->expects($this->once())->method('getExceptionListener')->willReturn($exceptionListener);
|
||||
|
||||
$logoutListener = $this->getMockBuilder(LogoutListener::class)->disableOriginalConstructor()->getMock();
|
||||
$firewallContext->expects($this->once())->method('getLogoutListener')->willReturn($logoutListener);
|
||||
|
||||
$matcher = $this->getMockBuilder(RequestMatcherInterface::class)->getMock();
|
||||
$matcher->expects($this->once())
|
||||
->method('matches')
|
||||
@ -82,7 +86,7 @@ class FirewallMapTest extends TestCase
|
||||
|
||||
$firewallMap = new FirewallMap($container, array('security.firewall.map.context.foo' => $matcher));
|
||||
|
||||
$this->assertEquals(array(array($listener), $exceptionListener), $firewallMap->getListeners($request));
|
||||
$this->assertEquals(array(array($listener), $exceptionListener, $logoutListener), $firewallMap->getListeners($request));
|
||||
$this->assertEquals($firewallConfig, $firewallMap->getFirewallConfig($request));
|
||||
$this->assertEquals('security.firewall.map.context.foo', $request->attributes->get(self::ATTRIBUTE_FIREWALL_CONTEXT));
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
"require": {
|
||||
"php": "^7.1.3",
|
||||
"ext-xml": "*",
|
||||
"symfony/security": "~3.4|~4.0",
|
||||
"symfony/security": "~3.4.10|^4.0.10",
|
||||
"symfony/dependency-injection": "^3.4.3|^4.0.3",
|
||||
"symfony/http-kernel": "~3.4|~4.0"
|
||||
},
|
||||
|
@ -7,10 +7,8 @@
|
||||
'default': '#999',
|
||||
'section': '#444',
|
||||
'event_listener': '#00B8F5',
|
||||
'event_listener_loading': '#00B8F5',
|
||||
'template': '#66CC00',
|
||||
'doctrine': '#FF6633',
|
||||
'propel': '#FF6633',
|
||||
} %}
|
||||
{% endif %}
|
||||
|
||||
|
@ -126,9 +126,12 @@ trait RedisTrait
|
||||
throw new InvalidArgumentException(sprintf('Redis connection failed (%s): %s', $e->getMessage(), $dsn));
|
||||
}
|
||||
|
||||
if (@!$redis->isConnected()) {
|
||||
$e = ($e = error_get_last()) && preg_match('/^Redis::p?connect\(\): (.*)/', $e['message'], $e) ? sprintf(' (%s)', $e[1]) : '';
|
||||
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $e, $dsn));
|
||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||
$isConnected = $redis->isConnected();
|
||||
restore_error_handler();
|
||||
if (!$isConnected) {
|
||||
$error = preg_match('/^Redis::p?connect\(\): (.*)/', $error, $error) ? sprintf(' (%s)', $error[1]) : '';
|
||||
throw new InvalidArgumentException(sprintf('Redis connection failed%s: %s', $error, $dsn));
|
||||
}
|
||||
|
||||
if ((null !== $auth && !$redis->auth($auth))
|
||||
|
@ -55,7 +55,7 @@ class XmlUtilsTest extends TestCase
|
||||
XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate'));
|
||||
$this->fail();
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
$this->assertRegExp('/The XML file "[\w:\/\\\.~+-]+" is not valid\./', $e->getMessage());
|
||||
$this->assertRegExp('/The XML file ".+" is not valid\./', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertInstanceOf('DOMDocument', XmlUtils::loadFile($fixtures.'valid.xml', array($mock, 'validate')));
|
||||
|
@ -218,12 +218,11 @@ class Command
|
||||
|
||||
if (null !== $this->processTitle) {
|
||||
if (function_exists('cli_set_process_title')) {
|
||||
if (false === @cli_set_process_title($this->processTitle)) {
|
||||
if (!@cli_set_process_title($this->processTitle)) {
|
||||
if ('Darwin' === PHP_OS) {
|
||||
$output->writeln('<comment>Running "cli_get_process_title" as an unprivileged user is not supported on MacOS.</comment>');
|
||||
} else {
|
||||
$error = error_get_last();
|
||||
trigger_error($error['message'], E_USER_WARNING);
|
||||
cli_set_process_title($this->processTitle);
|
||||
}
|
||||
}
|
||||
} elseif (function_exists('setproctitle')) {
|
||||
|
@ -380,14 +380,16 @@ class ErrorHandler
|
||||
public function handleError($type, $message, $file, $line)
|
||||
{
|
||||
// Level is the current error reporting level to manage silent error.
|
||||
$level = error_reporting();
|
||||
$silenced = 0 === ($level & $type);
|
||||
// Strong errors are not authorized to be silenced.
|
||||
$level = error_reporting() | E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
|
||||
$level |= E_RECOVERABLE_ERROR | E_USER_ERROR | E_DEPRECATED | E_USER_DEPRECATED;
|
||||
$log = $this->loggedErrors & $type;
|
||||
$throw = $this->thrownErrors & $type & $level;
|
||||
$type &= $level | $this->screamedErrors;
|
||||
|
||||
if (!$type || (!$log && !$throw)) {
|
||||
return $type && $log;
|
||||
return !$silenced && $type && $log;
|
||||
}
|
||||
$scope = $this->scopedErrors & $type;
|
||||
|
||||
@ -493,7 +495,7 @@ class ErrorHandler
|
||||
}
|
||||
}
|
||||
|
||||
return $type && $log;
|
||||
return !$silenced && $type && $log;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -65,6 +65,30 @@ class ErrorHandlerTest extends TestCase
|
||||
}
|
||||
}
|
||||
|
||||
public function testErrorGetLast()
|
||||
{
|
||||
$handler = ErrorHandler::register();
|
||||
$logger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock();
|
||||
$handler->setDefaultLogger($logger);
|
||||
$handler->screamAt(E_ALL);
|
||||
|
||||
try {
|
||||
@trigger_error('Hello', E_USER_WARNING);
|
||||
$expected = array(
|
||||
'type' => E_USER_WARNING,
|
||||
'message' => 'Hello',
|
||||
'file' => __FILE__,
|
||||
'line' => __LINE__ - 5,
|
||||
);
|
||||
$this->assertSame($expected, error_get_last());
|
||||
} catch (\Exception $e) {
|
||||
restore_error_handler();
|
||||
restore_exception_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
public function testNotice()
|
||||
{
|
||||
ErrorHandler::register();
|
||||
|
@ -118,8 +118,12 @@ abstract class AbstractRecursivePass implements CompilerPassInterface
|
||||
|
||||
$class = $definition->getClass();
|
||||
|
||||
if (!$r = $this->container->getReflectionClass($class)) {
|
||||
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
|
||||
try {
|
||||
if (!$r = $this->container->getReflectionClass($class)) {
|
||||
throw new RuntimeException(sprintf('Invalid service "%s": class "%s" does not exist.', $this->currentId, $class));
|
||||
}
|
||||
} catch (\ReflectionException $e) {
|
||||
throw new RuntimeException(sprintf('Invalid service "%s": %s.', $this->currentId, lcfirst(rtrim($e->getMessage(), '.'))));
|
||||
}
|
||||
if (!$r = $r->getConstructor()) {
|
||||
if ($required) {
|
||||
|
@ -120,6 +120,6 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return $this->container->getDefinition($ids[0])->isShared();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ class ResolveBindingsPass extends AbstractRecursivePass
|
||||
{
|
||||
private $usedBindings = array();
|
||||
private $unusedBindings = array();
|
||||
private $errorMessages = array();
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
@ -37,11 +38,19 @@ class ResolveBindingsPass extends AbstractRecursivePass
|
||||
parent::process($container);
|
||||
|
||||
foreach ($this->unusedBindings as list($key, $serviceId)) {
|
||||
throw new InvalidArgumentException(sprintf('Unused binding "%s" in service "%s".', $key, $serviceId));
|
||||
$message = sprintf('Unused binding "%s" in service "%s".', $key, $serviceId);
|
||||
if ($this->errorMessages) {
|
||||
$message .= sprintf("\nCould be related to%s:", 1 < \count($this->errorMessages) ? ' one of' : '');
|
||||
}
|
||||
foreach ($this->errorMessages as $m) {
|
||||
$message .= "\n - ".$m;
|
||||
}
|
||||
throw new InvalidArgumentException($message);
|
||||
}
|
||||
} finally {
|
||||
$this->usedBindings = array();
|
||||
$this->unusedBindings = array();
|
||||
$this->errorMessages = array();
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,6 +103,7 @@ class ResolveBindingsPass extends AbstractRecursivePass
|
||||
$calls[] = array($constructor, $value->getArguments());
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
$this->errorMessages[] = $e->getMessage();
|
||||
$this->container->getDefinition($this->currentId)->addError($e->getMessage());
|
||||
|
||||
return parent::processValue($value, $isRoot);
|
||||
|
@ -92,7 +92,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
|
||||
$this->assertNotSame($container->getDefinition('bar'), $arguments[2]);
|
||||
}
|
||||
|
||||
public function testProcessInlinesMixedServicesLoop()
|
||||
public function testProcessDoesNotInlineMixedServicesLoop()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
$container
|
||||
@ -108,7 +108,7 @@ class InlineServiceDefinitionsPassTest extends TestCase
|
||||
|
||||
$this->process($container);
|
||||
|
||||
$this->assertEquals($container->getDefinition('foo')->getArgument(0), $container->getDefinition('bar'));
|
||||
$this->assertEquals(new Reference('bar'), $container->getDefinition('foo')->getArgument(0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -18,6 +18,7 @@ use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass;
|
||||
use Symfony\Component\DependencyInjection\ContainerBuilder;
|
||||
use Symfony\Component\DependencyInjection\Reference;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\ParentNotExists;
|
||||
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
|
||||
use Symfony\Component\DependencyInjection\TypedReference;
|
||||
|
||||
@ -61,6 +62,21 @@ class ResolveBindingsPassTest extends TestCase
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessageRegexp Unused binding "$quz" in service [\s\S]+ Invalid service ".*\\ParentNotExists": class NotExists not found\.
|
||||
*/
|
||||
public function testMissingParent()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
||||
$definition = $container->register(ParentNotExists::class, ParentNotExists::class);
|
||||
$definition->setBindings(array('$quz' => '123'));
|
||||
|
||||
$pass = new ResolveBindingsPass();
|
||||
$pass->process($container);
|
||||
}
|
||||
|
||||
public function testTypedReferenceSupport()
|
||||
{
|
||||
$container = new ContainerBuilder();
|
||||
|
@ -22,6 +22,8 @@ use Symfony\Component\Filesystem\Exception\FileNotFoundException;
|
||||
*/
|
||||
class Filesystem
|
||||
{
|
||||
private static $lastError;
|
||||
|
||||
/**
|
||||
* Copies a file.
|
||||
*
|
||||
@ -96,12 +98,11 @@ class Filesystem
|
||||
continue;
|
||||
}
|
||||
|
||||
if (true !== @mkdir($dir, $mode, true)) {
|
||||
$error = error_get_last();
|
||||
if (!self::box('mkdir', $dir, $mode, true)) {
|
||||
if (!is_dir($dir)) {
|
||||
// The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one
|
||||
if ($error) {
|
||||
throw new IOException(sprintf('Failed to create "%s": %s.', $dir, $error['message']), 0, null, $dir);
|
||||
if (self::$lastError) {
|
||||
throw new IOException(sprintf('Failed to create "%s": %s.', $dir, self::$lastError), 0, null, $dir);
|
||||
}
|
||||
throw new IOException(sprintf('Failed to create "%s"', $dir), 0, null, $dir);
|
||||
}
|
||||
@ -170,20 +171,17 @@ class Filesystem
|
||||
foreach ($files as $file) {
|
||||
if (is_link($file)) {
|
||||
// See https://bugs.php.net/52176
|
||||
if (!@(unlink($file) || '\\' !== DIRECTORY_SEPARATOR || rmdir($file)) && file_exists($file)) {
|
||||
$error = error_get_last();
|
||||
throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, $error['message']));
|
||||
if (!(self::box('unlink', $file) || '\\' !== DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) {
|
||||
throw new IOException(sprintf('Failed to remove symlink "%s": %s.', $file, self::$lastError));
|
||||
}
|
||||
} elseif (is_dir($file)) {
|
||||
$this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS));
|
||||
|
||||
if (!@rmdir($file) && file_exists($file)) {
|
||||
$error = error_get_last();
|
||||
throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, $error['message']));
|
||||
if (!self::box('rmdir', $file) && file_exists($file)) {
|
||||
throw new IOException(sprintf('Failed to remove directory "%s": %s.', $file, self::$lastError));
|
||||
}
|
||||
} elseif (!@unlink($file) && file_exists($file)) {
|
||||
$error = error_get_last();
|
||||
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, $error['message']));
|
||||
} elseif (!self::box('unlink', $file) && file_exists($file)) {
|
||||
throw new IOException(sprintf('Failed to remove file "%s": %s.', $file, self::$lastError));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -337,16 +335,14 @@ class Filesystem
|
||||
|
||||
$this->mkdir(dirname($targetDir));
|
||||
|
||||
$ok = false;
|
||||
if (is_link($targetDir)) {
|
||||
if (readlink($targetDir) != $originDir) {
|
||||
$this->remove($targetDir);
|
||||
} else {
|
||||
$ok = true;
|
||||
if (readlink($targetDir) === $originDir) {
|
||||
return;
|
||||
}
|
||||
$this->remove($targetDir);
|
||||
}
|
||||
|
||||
if (!$ok && true !== @symlink($originDir, $targetDir)) {
|
||||
if (!self::box('symlink', $originDir, $targetDir)) {
|
||||
$this->linkException($originDir, $targetDir, 'symbolic');
|
||||
}
|
||||
}
|
||||
@ -378,7 +374,7 @@ class Filesystem
|
||||
$this->remove($targetFile);
|
||||
}
|
||||
|
||||
if (true !== @link($originFile, $targetFile)) {
|
||||
if (!self::box('link', $originFile, $targetFile)) {
|
||||
$this->linkException($originFile, $targetFile, 'hard');
|
||||
}
|
||||
}
|
||||
@ -391,9 +387,8 @@ class Filesystem
|
||||
*/
|
||||
private function linkException($origin, $target, $linkType)
|
||||
{
|
||||
$report = error_get_last();
|
||||
if (is_array($report)) {
|
||||
if ('\\' === DIRECTORY_SEPARATOR && false !== strpos($report['message'], 'error code(1314)')) {
|
||||
if (self::$lastError) {
|
||||
if ('\\' === DIRECTORY_SEPARATOR && false !== strpos(self::$lastError, 'error code(1314)')) {
|
||||
throw new IOException(sprintf('Unable to create %s link due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?', $linkType), 0, null, $target);
|
||||
}
|
||||
}
|
||||
@ -743,4 +738,29 @@ class Filesystem
|
||||
|
||||
return 2 === count($components) ? array($components[0], $components[1]) : array(null, $components[0]);
|
||||
}
|
||||
|
||||
private static function box($func)
|
||||
{
|
||||
self::$lastError = null;
|
||||
\set_error_handler(__CLASS__.'::handleError');
|
||||
try {
|
||||
$result = \call_user_func_array($func, \array_slice(\func_get_args(), 1));
|
||||
\restore_error_handler();
|
||||
|
||||
return $result;
|
||||
} catch (\Throwable $e) {
|
||||
} catch (\Exception $e) {
|
||||
}
|
||||
\restore_error_handler();
|
||||
|
||||
throw $e;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public static function handleError($type, $msg)
|
||||
{
|
||||
self::$lastError = $msg;
|
||||
}
|
||||
}
|
||||
|
@ -66,12 +66,11 @@ class SplFileInfo extends \SplFileInfo
|
||||
*/
|
||||
public function getContents()
|
||||
{
|
||||
$level = error_reporting(0);
|
||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||
$content = file_get_contents($this->getPathname());
|
||||
error_reporting($level);
|
||||
restore_error_handler();
|
||||
if (false === $content) {
|
||||
$error = error_get_last();
|
||||
throw new \RuntimeException($error['message']);
|
||||
throw new \RuntimeException($error);
|
||||
}
|
||||
|
||||
return $content;
|
||||
|
@ -93,9 +93,11 @@ class File extends \SplFileInfo
|
||||
{
|
||||
$target = $this->getTargetFile($directory, $name);
|
||||
|
||||
if (!@rename($this->getPathname(), $target)) {
|
||||
$error = error_get_last();
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
|
||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||
$renamed = rename($this->getPathname(), $target);
|
||||
restore_error_handler();
|
||||
if (!$renamed) {
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
|
||||
}
|
||||
|
||||
@chmod($target, 0666 & ~umask());
|
||||
|
@ -192,9 +192,11 @@ class UploadedFile extends File
|
||||
|
||||
$target = $this->getTargetFile($directory, $name);
|
||||
|
||||
if (!@move_uploaded_file($this->getPathname(), $target)) {
|
||||
$error = error_get_last();
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error['message'])));
|
||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||
$moved = move_uploaded_file($this->getPathname(), $target);
|
||||
restore_error_handler();
|
||||
if (!$moved) {
|
||||
throw new FileException(sprintf('Could not move the file "%s" to "%s" (%s)', $this->getPathname(), $target, strip_tags($error)));
|
||||
}
|
||||
|
||||
@chmod($target, 0666 & ~umask());
|
||||
|
@ -674,14 +674,16 @@ class PdoSessionHandler extends AbstractSessionHandler
|
||||
{
|
||||
switch ($this->driver) {
|
||||
case 'mysql':
|
||||
// MySQL 5.7.5 and later enforces a maximum length on lock names of 64 characters. Previously, no limit was enforced.
|
||||
$lockId = \substr($sessionId, 0, 64);
|
||||
// should we handle the return value? 0 on timeout, null on error
|
||||
// we use a timeout of 50 seconds which is also the default for innodb_lock_wait_timeout
|
||||
$stmt = $this->pdo->prepare('SELECT GET_LOCK(:key, 50)');
|
||||
$stmt->bindValue(':key', $sessionId, \PDO::PARAM_STR);
|
||||
$stmt->bindValue(':key', $lockId, \PDO::PARAM_STR);
|
||||
$stmt->execute();
|
||||
|
||||
$releaseStmt = $this->pdo->prepare('DO RELEASE_LOCK(:key)');
|
||||
$releaseStmt->bindValue(':key', $sessionId, \PDO::PARAM_STR);
|
||||
$releaseStmt->bindValue(':key', $lockId, \PDO::PARAM_STR);
|
||||
|
||||
return $releaseStmt;
|
||||
case 'pgsql':
|
||||
|
@ -6,21 +6,6 @@ use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
|
||||
|
||||
class UnprocessableEntityHttpExceptionTest extends HttpExceptionTest
|
||||
{
|
||||
/**
|
||||
* Test that setting the headers using the setter function
|
||||
* is working as expected.
|
||||
*
|
||||
* @param array $headers The headers to set
|
||||
*
|
||||
* @dataProvider headerDataProvider
|
||||
*/
|
||||
public function testHeadersSetter($headers)
|
||||
{
|
||||
$exception = new UnprocessableEntityHttpException(10);
|
||||
$exception->setHeaders($headers);
|
||||
$this->assertSame($headers, $exception->getHeaders());
|
||||
}
|
||||
|
||||
protected function createException()
|
||||
{
|
||||
return new UnprocessableEntityHttpException();
|
||||
|
@ -6,17 +6,7 @@ use Symfony\Component\HttpKernel\Exception\UnsupportedMediaTypeHttpException;
|
||||
|
||||
class UnsupportedMediaTypeHttpExceptionTest extends HttpExceptionTest
|
||||
{
|
||||
/**
|
||||
* @dataProvider headerDataProvider
|
||||
*/
|
||||
public function testHeadersSetter($headers)
|
||||
{
|
||||
$exception = new UnsupportedMediaTypeHttpException(10);
|
||||
$exception->setHeaders($headers);
|
||||
$this->assertSame($headers, $exception->getHeaders());
|
||||
}
|
||||
|
||||
protected function createException($headers = array())
|
||||
protected function createException()
|
||||
{
|
||||
return new UnsupportedMediaTypeHttpException();
|
||||
}
|
||||
|
@ -78,8 +78,7 @@ class FlockStore implements StoreInterface
|
||||
);
|
||||
|
||||
// Silence error reporting
|
||||
set_error_handler(function () {
|
||||
});
|
||||
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
|
||||
if (!$handle = fopen($fileName, 'r')) {
|
||||
if ($handle = fopen($fileName, 'x')) {
|
||||
chmod($fileName, 0444);
|
||||
@ -91,8 +90,7 @@ class FlockStore implements StoreInterface
|
||||
restore_error_handler();
|
||||
|
||||
if (!$handle) {
|
||||
$error = error_get_last();
|
||||
throw new LockStorageException($error['message'], 0, null);
|
||||
throw new LockStorageException($error, 0, null);
|
||||
}
|
||||
|
||||
// On Windows, even if PHP doc says the contrary, LOCK_NB works, see
|
||||
|
@ -77,7 +77,7 @@ class ExecutableFinder
|
||||
}
|
||||
foreach ($suffixes as $suffix) {
|
||||
foreach ($dirs as $dir) {
|
||||
if (@is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === DIRECTORY_SEPARATOR || is_executable($file))) {
|
||||
if (@is_file($file = $dir.DIRECTORY_SEPARATOR.$name.$suffix) && ('\\' === DIRECTORY_SEPARATOR || @is_executable($file))) {
|
||||
return $file;
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class PhpExecutableFinder
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PATH')) {
|
||||
if (!is_executable($php)) {
|
||||
if (!@is_executable($php)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -52,12 +52,12 @@ class PhpExecutableFinder
|
||||
}
|
||||
|
||||
if ($php = getenv('PHP_PEAR_PHP_BIN')) {
|
||||
if (is_executable($php)) {
|
||||
if (@is_executable($php)) {
|
||||
return $php;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_executable($php = PHP_BINDIR.('\\' === DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
|
||||
if (@is_executable($php = PHP_BINDIR.('\\' === DIRECTORY_SEPARATOR ? '\\php.exe' : '/php'))) {
|
||||
return $php;
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,7 @@ abstract class AbstractPipes implements PipesInterface
|
||||
private $inputBuffer = '';
|
||||
private $input;
|
||||
private $blocked = true;
|
||||
private $lastError;
|
||||
|
||||
/**
|
||||
* @param resource|string|int|float|bool|\Iterator|null $input
|
||||
@ -58,10 +59,11 @@ abstract class AbstractPipes implements PipesInterface
|
||||
*/
|
||||
protected function hasSystemCallBeenInterrupted()
|
||||
{
|
||||
$lastError = error_get_last();
|
||||
$lastError = $this->lastError;
|
||||
$this->lastError = null;
|
||||
|
||||
// stream_select returns false when the `select` system call is interrupted by an incoming signal
|
||||
return isset($lastError['message']) && false !== stripos($lastError['message'], 'interrupted system call');
|
||||
return null !== $lastError && false !== stripos($lastError, 'interrupted system call');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,4 +167,12 @@ abstract class AbstractPipes implements PipesInterface
|
||||
return array($this->pipes[0]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
public function handleError($type, $msg)
|
||||
{
|
||||
$this->lastError = $msg;
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,9 @@ class UnixPipes extends AbstractPipes
|
||||
unset($r[0]);
|
||||
|
||||
// let's have a look if something changed in streams
|
||||
if (($r || $w) && false === @stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
set_error_handler(array($this, 'handleError'));
|
||||
if (($r || $w) && false === stream_select($r, $w, $e, 0, $blocking ? Process::TIMEOUT_PRECISION * 1E6 : 0)) {
|
||||
restore_error_handler();
|
||||
// if a system call has been interrupted, forget about it, let's try again
|
||||
// otherwise, an error occurred, let's reset pipes
|
||||
if (!$this->hasSystemCallBeenInterrupted()) {
|
||||
@ -108,6 +110,7 @@ class UnixPipes extends AbstractPipes
|
||||
|
||||
return $read;
|
||||
}
|
||||
restore_error_handler();
|
||||
|
||||
foreach ($r as $pipe) {
|
||||
// prior PHP 5.4 the array passed to stream_select is modified and
|
||||
|
@ -47,13 +47,22 @@ class Firewall implements EventSubscriberInterface
|
||||
}
|
||||
|
||||
// register listeners for this firewall
|
||||
list($listeners, $exceptionListener) = $this->map->getListeners($event->getRequest());
|
||||
$listeners = $this->map->getListeners($event->getRequest());
|
||||
|
||||
$authenticationListeners = $listeners[0];
|
||||
$exceptionListener = $listeners[1];
|
||||
$logoutListener = isset($listeners[2]) ? $listeners[2] : null;
|
||||
|
||||
if (null !== $exceptionListener) {
|
||||
$this->exceptionListeners[$event->getRequest()] = $exceptionListener;
|
||||
$exceptionListener->register($this->dispatcher);
|
||||
}
|
||||
|
||||
return $this->handleRequest($event, $listeners);
|
||||
$this->handleRequest($event, $authenticationListeners);
|
||||
|
||||
if (null !== $logoutListener) {
|
||||
$logoutListener->handle($event);
|
||||
}
|
||||
}
|
||||
|
||||
public function onKernelFinishRequest(FinishRequestEvent $event)
|
||||
|
@ -14,6 +14,7 @@ namespace Symfony\Component\Security\Http;
|
||||
use Symfony\Component\HttpFoundation\RequestMatcherInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\Security\Http\Firewall\ExceptionListener;
|
||||
use Symfony\Component\Security\Http\Firewall\LogoutListener;
|
||||
|
||||
/**
|
||||
* FirewallMap allows configuration of different firewalls for specific parts
|
||||
@ -25,9 +26,9 @@ class FirewallMap implements FirewallMapInterface
|
||||
{
|
||||
private $map = array();
|
||||
|
||||
public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null)
|
||||
public function add(RequestMatcherInterface $requestMatcher = null, array $listeners = array(), ExceptionListener $exceptionListener = null, LogoutListener $logoutListener = null)
|
||||
{
|
||||
$this->map[] = array($requestMatcher, $listeners, $exceptionListener);
|
||||
$this->map[] = array($requestMatcher, $listeners, $exceptionListener, $logoutListener);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,10 +38,10 @@ class FirewallMap implements FirewallMapInterface
|
||||
{
|
||||
foreach ($this->map as $elements) {
|
||||
if (null === $elements[0] || $elements[0]->matches($request)) {
|
||||
return array($elements[1], $elements[2]);
|
||||
return array($elements[1], $elements[2], $elements[3]);
|
||||
}
|
||||
}
|
||||
|
||||
return array(array(), null);
|
||||
return array(array(), null, null);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user