diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index da9f11b..671d29d 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -2105,6 +2105,25 @@ function install_check_requirements($install_state) { } } } + + // Installations on Windows can run into limitations with MAX_PATH if the + // Drupal root directory is too deep in the filesystem. Generally this shows + // up in cached Twig templates. Because of their variable length, for example + // template suggestions can arbitrarily lengthen a filename, there is no set + // limit beyond which Drupal will not function correctly on Windows. Thus we + // only warn if a Drupal is being installed more than 100 characters deep in + // the filesystem. + if (strpos(strtolower(php_uname('s')), 'win') === 0) { + $depth = strlen(realpath(DRUPAL_ROOT)); + if ($depth > 100) { + $requirements['max_path_on_windows'] = [ + 'title' => t('Windows installation'), + 'description' => t('The path length to the Drupal root directory (@depth characters) is greater than 100 characters. This may cause problems when running on a Windows server. It is recommended to install Drupal on Windows in a shorter path.', ['@depth' => $depth]), + 'severity' => REQUIREMENT_WARNING, + ]; + } + } + return $requirements; } diff --git a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php index f82b676..4ba3f9a 100644 --- a/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php +++ b/core/lib/Drupal/Component/PhpStorage/MTimeProtectedFastFileStorage.php @@ -7,6 +7,8 @@ namespace Drupal\Component\PhpStorage; +use \Drupal\Component\Utility\Crypt; + /** * Stores PHP code in files with securely hashed names. * @@ -135,7 +137,8 @@ public function getFullPath($name, &$directory = NULL, &$directory_mtime = NULL) if (!isset($directory_mtime)) { $directory_mtime = file_exists($directory) ? filemtime($directory) : 0; } - return $directory . '/' . hash_hmac('sha256', $name, $this->secret . $directory_mtime) . '.php'; + $hashed_name = Crypt::shortHash($name, $this->secret . $directory_mtime) . '.php'; + return $directory . '/' . $hashed_name; } /** diff --git a/core/lib/Drupal/Component/Utility/Crypt.php b/core/lib/Drupal/Component/Utility/Crypt.php index 66cadfa..0a530e7 100644 --- a/core/lib/Drupal/Component/Utility/Crypt.php +++ b/core/lib/Drupal/Component/Utility/Crypt.php @@ -15,6 +15,11 @@ class Crypt { /** + * Length for the shortHash() function. + */ + const SHORT_HASH_LENGTH_DEFAULT = 10; + + /** * Returns a string of highly randomized bytes (over the full 8-bit range). * * This function is better than simply calling mt_rand() or any other built-in @@ -136,4 +141,26 @@ public static function randomBytesBase64($count = 32) { return str_replace(['+', '/', '='], ['-', '_', ''], base64_encode(static::randomBytes($count))); } + /** + * Get a shortened sha256 hash. + * + * @param string $name + * Message to be hashed. + * @param string $key + * Shared secret key. + * @param int $length + * Hash length. + * + * @return string + * A sha256 base 36 encoded shortened hash. + */ + public static function shortHash($name, $key = NULL, $length = self::SHORT_HASH_LENGTH_DEFAULT) { + if ($key) { + return substr(base_convert(hash_hmac('sha256', $name, $key), 16, 36), 0, $length); + } + else { + return substr(base_convert(hash('sha256', $name), 16, 36), 0, $length); + } + } + } diff --git a/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php index d2cf918..5026ba4 100644 --- a/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php +++ b/core/lib/Drupal/Core/Template/TwigPhpStorageCache.php @@ -9,6 +9,7 @@ use Drupal\Core\Cache\CacheBackendInterface; use Drupal\Core\PhpStorage\PhpStorageFactory; +use Drupal\Component\Utility\Crypt; /** * Provides an alternate cache storage for Twig using PhpStorage. @@ -72,7 +73,7 @@ protected function storage() { * {@inheritdoc} */ public function generateKey($name, $className) { - $hash = hash('sha256', $className); + $hash = Crypt::shortHash($className); if (strpos($name, '{# inline_template_start #}') === 0) { // $name is an inline template, and can have characters that are not valid diff --git a/core/modules/system/src/Tests/Theme/TwigEnvironmentTest.php b/core/modules/system/src/Tests/Theme/TwigEnvironmentTest.php index 0bc52d0..53ac35d 100644 --- a/core/modules/system/src/Tests/Theme/TwigEnvironmentTest.php +++ b/core/modules/system/src/Tests/Theme/TwigEnvironmentTest.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\Html; use Drupal\Core\Site\Settings; use Drupal\simpletest\KernelTestBase; +use Drupal\Component\Utility\Crypt; /** * Tests the twig environment. @@ -92,7 +93,7 @@ public function testInlineTemplate() { $cache = $environment->getCache(); $class = $environment->getTemplateClass($name); - $expected = $hash . '_inline-template' . '_' . hash('sha256', $class); + $expected = $hash . '_inline-template_' . Crypt::shortHash($class); $this->assertEqual($expected, $cache->generateKey($name, $class)); } diff --git a/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php b/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php index 59944ff..3e94e60 100644 --- a/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php +++ b/core/tests/Drupal/Tests/Component/PhpStorage/MTimeProtectedFileStorageBase.php @@ -7,6 +7,8 @@ namespace Drupal\Tests\Component\PhpStorage; +use \Drupal\Component\Utility\Crypt; + /** * Base test class for MTime protected storage. */ @@ -82,7 +84,7 @@ public function testSecurity() { $expected_directory = $expected_root_directory . '/' . $name; } $directory_mtime = filemtime($expected_directory); - $expected_filename = $expected_directory . '/' . hash_hmac('sha256', $name, $this->secret . $directory_mtime) . '.php'; + $expected_filename = $expected_directory . '/' . Crypt::shortHash($name, $this->secret . $directory_mtime) . '.php'; // Ensure the file exists and that it and the containing directory have // minimal permissions. fileperms() can return high bits unrelated to diff --git a/core/tests/Drupal/Tests/Component/Utility/CryptTest.php b/core/tests/Drupal/Tests/Component/Utility/CryptTest.php index bf6ca27..4d0c4ad 100644 --- a/core/tests/Drupal/Tests/Component/Utility/CryptTest.php +++ b/core/tests/Drupal/Tests/Component/Utility/CryptTest.php @@ -85,6 +85,23 @@ public function testHmacBase64Invalid($data, $key) { } /** + * Tests shortHash function. + * + * @dataProvider providerTestShortHash + * @covers ::shortHash + * + * @param string $data + * Data to hash. + * @param string $key + * Key to use in hashing process. + * @param string $expected_hash + * The expected hash. + */ + public function testShortHash($data, $key, $expected_hash) { + $this->assertSame($expected_hash, Crypt::shortHash($data, $key)); + } + + /** * Provides data for self::testHashBase64(). * * @return array Test data. @@ -152,4 +169,30 @@ public function providerTestHmacBase64Invalid() { ); } + /** + * Provides data for self::testShortHash(). + * + * @return array + * Test data. + */ + public function providerTestShortHash() { + return [ + [ + 'data' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', + 'key' => 'secret-key', + 'expected_hash' => '3gulzih2ms', + ], + [ + 'data' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', + 'key' => NULL, + 'expected_hash' => '3js5i38cnx', + ], + [ + 'data' => 'Lorem', + 'key' => NULL, + 'expected_hash' => 'oo8723opxr', + ], + ]; + } + }