minor #23766 Consistently use 7 chars of sha256 for hash-based id generation (nicolas-grekas)

This PR was merged into the 3.4 branch.

Discussion
----------

Consistently use 7 chars of sha256 for hash-based id generation

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | -
| License       | MIT
| Doc PR        | -

This prevents generating over long service ids, and for filesystem-related changes, makes the Windows 258 chars limit farther.

Commits
-------

bc22cdd034 Consistently use 7 chars of sha256 for hash-based id generation
This commit is contained in:
Fabien Potencier 2017-08-03 14:04:31 +02:00
commit ce1050820f
25 changed files with 60 additions and 40 deletions

View File

@ -387,8 +387,7 @@ abstract class AbstractDoctrineExtension extends Extension
$seed = '_'.$container->getParameter('kernel.root_dir');
}
$seed .= '.'.$container->getParameter('kernel.name').'.'.$container->getParameter('kernel.environment').'.'.$container->getParameter('kernel.debug');
$hash = hash('sha256', $seed);
$namespace = 'sf_'.$this->getMappingResourceExtension().'_'.$objectManagerName.'_'.$hash;
$namespace = 'sf_'.$this->getMappingResourceExtension().'_'.$objectManagerName.'_'.ContainerBuilder::hash($seed);
$cacheDriver['namespace'] = $namespace;
}

View File

@ -22,7 +22,7 @@
},
"require-dev": {
"symfony/stopwatch": "~2.8|~3.0|~4.0",
"symfony/dependency-injection": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/form": "^3.2.5|~4.0",
"symfony/http-kernel": "~2.8|~3.0|~4.0",
"symfony/property-access": "~2.8|~3.0|~4.0",
@ -38,7 +38,7 @@
},
"conflict": {
"phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0",
"symfony/dependency-injection": "<3.3"
"symfony/dependency-injection": "<3.4"
},
"suggest": {
"symfony/form": "",

View File

@ -111,7 +111,7 @@ class CachePoolPass implements CompilerPassInterface
if ($usedEnvs || preg_match('#^[a-z]++://#', $name)) {
$dsn = $name;
if (!$container->hasDefinition($name = md5($dsn))) {
if (!$container->hasDefinition($name = 'cache_connection.'.ContainerBuilder::hash($dsn))) {
$definition = new Definition(AbstractAdapter::class);
$definition->setPublic(false);
$definition->setFactory(array(AbstractAdapter::class, 'createConnection'));

View File

@ -937,7 +937,7 @@ abstract class FrameworkExtensionTest extends TestCase
$container = $this->createContainerFromFile('cache');
$redisUrl = 'redis://localhost';
$providerId = md5($redisUrl);
$providerId = 'cache_connection.'.ContainerBuilder::hash($redisUrl);
$this->assertTrue($container->hasDefinition($providerId));
@ -951,7 +951,7 @@ abstract class FrameworkExtensionTest extends TestCase
$container = $this->createContainerFromFile('cache_env_var');
$redisUrl = 'redis://paas.com';
$providerId = md5($redisUrl);
$providerId = 'cache_connection.'.ContainerBuilder::hash($redisUrl);
$this->assertTrue($container->hasDefinition($providerId));

View File

@ -20,7 +20,7 @@
"ext-xml": "*",
"symfony/cache": "~3.4|~4.0",
"symfony/class-loader": "~3.2",
"symfony/dependency-injection": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/config": "~3.3|~4.0",
"symfony/event-dispatcher": "^3.3.1|~4.0",
"symfony/http-foundation": "~3.3|~4.0",

View File

@ -666,7 +666,7 @@ class SecurityExtension extends Extension
private function createExpression($container, $expression)
{
if (isset($this->expressions[$id = 'security.expression.'.sha1($expression)])) {
if (isset($this->expressions[$id = 'security.expression.'.ContainerBuilder::hash($expression)])) {
return $this->expressions[$id];
}
@ -686,8 +686,7 @@ class SecurityExtension extends Extension
$methods = array_map('strtoupper', (array) $methods);
}
$serialized = serialize(array($path, $host, $methods, $ip, $attributes));
$id = 'security.request_matcher.'.md5($serialized).sha1($serialized);
$id = 'security.request_matcher.'.ContainerBuilder::hash(array($path, $host, $methods, $ip, $attributes));
if (isset($this->requestMatchers[$id])) {
return $this->requestMatchers[$id];

View File

@ -84,7 +84,7 @@ abstract class CompleteConfigurationTest extends TestCase
array(
'simple',
'security.user_checker',
'security.request_matcher.707b20193d4cb9f2718114abcbebb32af48f948484fc166a03482f49bf14f25e271f72c7',
'security.request_matcher.6tndozi',
false,
),
array(
@ -117,7 +117,7 @@ abstract class CompleteConfigurationTest extends TestCase
array(
'host',
'security.user_checker',
'security.request_matcher.dda8b565689ad8509623ee68fb2c639cd81cd4cb339d60edbaf7d67d30e6aa09bd8c63c3',
'security.request_matcher.and0kk1',
true,
false,
'security.user.provider.concrete.default',

View File

@ -19,7 +19,7 @@
"php": "^5.5.9|>=7.0.8",
"ext-xml": "*",
"symfony/security": "~3.4|~4.0",
"symfony/dependency-injection": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/http-kernel": "~3.3|~4.0",
"symfony/polyfill-php70": "~1.0"
},
@ -29,7 +29,7 @@
"symfony/console": "~3.2|~4.0",
"symfony/css-selector": "~2.8|~3.0|~4.0",
"symfony/dom-crawler": "~2.8|~3.0|~4.0",
"symfony/event-dispatcher": "~3.3|~4.0",
"symfony/event-dispatcher": "^3.3.1|~4.0",
"symfony/form": "^2.8.18|^3.2.5|~4.0",
"symfony/framework-bundle": "^3.2.8|~4.0",
"symfony/http-foundation": "~2.8|~3.0|~4.0",
@ -47,7 +47,7 @@
},
"conflict": {
"symfony/var-dumper": "<3.3",
"symfony/event-dispatcher": "<3.3"
"symfony/event-dispatcher": "<3.3.1"
},
"suggest": {
"symfony/security-acl": "For using the ACL functionality of this bundle"

View File

@ -57,7 +57,7 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
if ($public = $value->isPublic()) {
$value->setPublic(false);
}
$id = 'service_locator.'.md5(serialize($value));
$id = 'service_locator.'.ContainerBuilder::hash($value);
if ($isRoot) {
if ($id !== $this->currentId) {
@ -90,7 +90,7 @@ final class ServiceLocatorTagPass extends AbstractRecursivePass
->setPublic(false)
->addTag('container.service_locator');
if (!$container->has($id = 'service_locator.'.md5(serialize($locator)))) {
if (!$container->has($id = 'service_locator.'.ContainerBuilder::hash($locator))) {
$container->setDefinition($id, $locator);
}

View File

@ -1391,6 +1391,20 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
return $services;
}
/**
* Computes a reasonably unique hash of a value.
*
* @param mixed $value A serializable value
*
* @return string
*/
public static function hash($value)
{
$hash = substr(base64_encode(hash('sha256', serialize($value), true)), 0, 7);
return str_replace(array('/', '+'), array('.', '_'), strtolower($hash));
}
/**
* Retrieves the currently set proxy instantiator or instantiates one.
*

View File

@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@ -386,6 +387,7 @@ class XmlFileLoader extends FileLoader
{
$definitions = array();
$count = 0;
$suffix = ContainerBuilder::hash($file);
$xpath = new \DOMXPath($xml);
$xpath->registerNamespace('container', self::NS);
@ -395,7 +397,7 @@ class XmlFileLoader extends FileLoader
foreach ($nodes as $node) {
if ($services = $this->getChildren($node, 'service')) {
// give it a unique name
$id = sprintf('%d_%s', ++$count, hash('sha256', $file));
$id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $node->getAttribute('class')).$suffix);
$node->setAttribute('id', $id);
$node->setAttribute('service', $id);
@ -415,7 +417,7 @@ class XmlFileLoader extends FileLoader
@trigger_error(sprintf('Top-level anonymous services are deprecated since Symfony 3.4, the "id" attribute will be required in version 4.0 in %s at line %d.', $file, $node->getLineNo()), E_USER_DEPRECATED);
// give it a unique name
$id = sprintf('%d_%s', ++$count, hash('sha256', $file));
$id = sprintf('%d_%s', ++$count, preg_replace('/^.*\\\\/', '', $node->getAttribute('class')).$suffix);
$node->setAttribute('id', $id);
$definitions[$id] = array($node, $file, true);
}

View File

@ -15,6 +15,7 @@ use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
@ -98,6 +99,7 @@ class YamlFileLoader extends FileLoader
private $yamlParser;
private $anonymousServicesCount;
private $anonymousServicesSuffix;
/**
* {@inheritdoc}
@ -134,6 +136,7 @@ class YamlFileLoader extends FileLoader
// services
$this->anonymousServicesCount = 0;
$this->anonymousServicesSuffix = ContainerBuilder::hash($path);
$this->setCurrentDir(dirname($path));
try {
$this->parseDefinitions($content, $path);
@ -691,7 +694,7 @@ class YamlFileLoader extends FileLoader
$instanceof = $this->instanceof;
$this->instanceof = array();
$id = sprintf('%d_%s', ++$this->anonymousServicesCount, hash('sha256', $file));
$id = sprintf('%d_%s', ++$this->anonymousServicesCount, preg_replace('/^.*\\\\/', '', isset($argument['class']) ? $argument['class'] : '').$this->anonymousServicesSuffix);
$this->parseDefinition($id, $argument, $file, array());
if (!$this->container->hasDefinition($id)) {

View File

@ -534,7 +534,7 @@ class YamlFileLoaderTest extends TestCase
$this->assertCount(1, $args);
$this->assertInstanceOf(Reference::class, $args[0]);
$this->assertTrue($container->has((string) $args[0]));
$this->assertRegExp('/^\d+_[A-Za-z0-9]{64}$/', (string) $args[0]);
$this->assertRegExp('/^\d+_Bar[._A-Za-z0-9]{7}$/', (string) $args[0]);
$anonymous = $container->getDefinition((string) $args[0]);
$this->assertEquals('Bar', $anonymous->getClass());
@ -546,7 +546,7 @@ class YamlFileLoaderTest extends TestCase
$this->assertInternalType('array', $factory);
$this->assertInstanceOf(Reference::class, $factory[0]);
$this->assertTrue($container->has((string) $factory[0]));
$this->assertRegExp('/^\d+_[A-Za-z0-9]{64}$/', (string) $factory[0]);
$this->assertRegExp('/^\d+_Quz[._A-Za-z0-9]{7}$/', (string) $factory[0]);
$this->assertEquals('constructFoo', $factory[1]);
$anonymous = $container->getDefinition((string) $factory[0]);

View File

@ -59,7 +59,7 @@ class FileFormField extends FormField
$name = $info['basename'];
// copy to a tmp location
$tmp = sys_get_temp_dir().'/'.sha1(uniqid(mt_rand(), true));
$tmp = sys_get_temp_dir().'/'.strtr(substr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), 0, 7), '/', '_');
if (array_key_exists('extension', $info)) {
$tmp .= '.'.$info['extension'];
}

View File

@ -141,7 +141,7 @@ class BinaryFileResponse extends Response
*/
public function setAutoEtag()
{
$this->setEtag(sha1_file($this->file->getPathname()));
$this->setEtag(substr(base64_encode(hash_file('sha256', $this->file->getPathname(), true)), 0, 32));
return $this;
}

View File

@ -754,7 +754,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface
$dumper = new PhpDumper($container);
if (class_exists('ProxyManager\Configuration') && class_exists('Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper')) {
$dumper->setProxyDumper(new ProxyDumper(md5($cache->getPath())));
$dumper->setProxyDumper(new ProxyDumper(substr(hash('sha256', $cache->getPath()), 0, 7)));
}
$content = $dumper->dump(array('class' => $class, 'base_class' => $baseClass, 'file' => $cache->getPath(), 'debug' => $this->debug));

View File

@ -71,7 +71,7 @@ class FlockStore implements StoreInterface
$fileName = sprintf('%s/sf.%s.%s.lock',
$this->lockPath,
preg_replace('/[^a-z0-9\._-]+/i', '-', $key),
hash('sha256', $key)
strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_')
);
// Silence error reporting

View File

@ -62,8 +62,9 @@ class FlockStoreTest extends AbstractStoreTest
$key = new Key('<?php echo "% hello word ! %" ?>');
$file = sprintf(
'%s/sf.-php-echo-hello-word-.4b3d9d0d27ddef3a78a64685dda3a963e478659a9e5240feaf7b4173a8f28d5f.lock',
sys_get_temp_dir()
'%s/sf.-php-echo-hello-word-.%s.lock',
sys_get_temp_dir(),
strtr(substr(base64_encode(hash('sha256', $key, true)), 0, 7), '/', '_')
);
// ensure the file does not exist before the store
@unlink($file);

View File

@ -85,7 +85,7 @@ class XliffFileDumper extends FileDumper
foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('trans-unit');
$translation->setAttribute('id', md5($source));
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
$translation->setAttribute('resname', $source);
$s = $translation->appendChild($dom->createElement('source'));
@ -145,7 +145,7 @@ class XliffFileDumper extends FileDumper
foreach ($messages->all($domain) as $source => $target) {
$translation = $dom->createElement('unit');
$translation->setAttribute('id', md5($source));
$translation->setAttribute('id', strtr(substr(base64_encode(hash('sha256', $source, true)), 0, 7), '/+', '._'));
$segment = $translation->appendChild($dom->createElement('segment'));

View File

@ -28,6 +28,8 @@ class FileDumperTest extends TestCase
$dumper->dump($catalogue, array('path' => $tempDir));
$this->assertFileExists($tempDir.'/messages.en.concrete');
@unlink($tempDir.'/messages.en.concrete');
}
/**

View File

@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<xliff xmlns="urn:oasis:names:tc:xliff:document:2.0" version="2.0" srcLang="fr-FR" trgLang="en-US">
<file id="messages.en_US">
<unit id="acbd18db4cc2f85cedef654fccc4a4d8">
<unit id="LCa0a2j">
<segment>
<source>foo</source>
<target>bar</target>
</segment>
</unit>
<unit id="3c6e0b8a9c15224a8228b9a98ca1531d">
<unit id="LHDhK3o">
<segment>
<source>key</source>
<target order="1"></target>
</segment>
</unit>
<unit id="18e6a493872558d949b4c16ea1fa6ab6">
<unit id="2DA_bnh">
<segment>
<source>key.with.cdata</source>
<target><![CDATA[<source> & <target>]]></target>

View File

@ -5,18 +5,18 @@
<tool tool-id="symfony" tool-name="Symfony"/>
</header>
<body>
<trans-unit id="acbd18db4cc2f85cedef654fccc4a4d8" resname="foo">
<trans-unit id="LCa0a2j" resname="foo">
<source>foo</source>
<target>bar</target>
<note priority="1" from="bar">baz</note>
</trans-unit>
<trans-unit id="3c6e0b8a9c15224a8228b9a98ca1531d" resname="key">
<trans-unit id="LHDhK3o" resname="key">
<source>key</source>
<target></target>
<note>baz</note>
<note>qux</note>
</trans-unit>
<trans-unit id="18e6a493872558d949b4c16ea1fa6ab6" resname="key.with.cdata">
<trans-unit id="2DA_bnh" resname="key.with.cdata">
<source>key.with.cdata</source>
<target><![CDATA[<source> & <target>]]></target>
</trans-unit>

View File

@ -5,7 +5,7 @@
<tool tool-id="symfony" tool-name="Symfony"/>
</header>
<body>
<trans-unit id="acbd18db4cc2f85cedef654fccc4a4d8" resname="foo">
<trans-unit id="LCa0a2j" resname="foo">
<source>foo</source>
<target state="needs-translation">bar</target>
</trans-unit>

View File

@ -5,7 +5,7 @@
<tool tool-id="foo" tool-name="foo" tool-version="0.0" tool-company="Foo"/>
</header>
<body>
<trans-unit id="acbd18db4cc2f85cedef654fccc4a4d8" resname="foo">
<trans-unit id="LCa0a2j" resname="foo">
<source>foo</source>
<target>bar</target>
</trans-unit>

View File

@ -363,7 +363,7 @@ EOF
private function getCatalogueCachePath($locale)
{
return $this->cacheDir.'/catalogue.'.$locale.'.'.sha1(serialize($this->fallbackLocales)).'.php';
return $this->cacheDir.'/catalogue.'.$locale.'.'.strtr(substr(base64_encode(hash('sha256', serialize($this->fallbackLocales), true)), 0, 7), '/', '_').'.php';
}
private function doLoadCatalogue($locale)